/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1989-1999 Microsoft Corporation Module Name: procana.cxx Abstract: This file provides analysis routines for a procedure code generation class. Notes: History: Aug-31-1993 VibhasC Created. ----------------------------------------------------------------------------*/ /**************************************************************************** * include files ***************************************************************************/ #include "allana.hxx" #pragma hdrstop #pragma warning ( disable : 4701 ) /**************************************************************************** Implementation of the proc code generator class. ****************************************************************************/ CG_STATUS CG_PROC::C_BindingAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform the binding analysis for the client side. Arguments: Return Value: Notes: If it is an auto handle procedure, make sure the global auto handle is registered as a global resource. ----------------------------------------------------------------------------*/ { node_id * pID; if( IsAutoHandle() ) { pAna->AddStandardResource( ST_RES_AUTO_BH_VARIABLE ); } else { SetBindingResource( pAna->AddStandardResource( ST_RES_BH_VARIABLE ) ); // Initialize the binding resource to 0, so it gets printed out. pID = (node_id *)GetBindingResource()->GetType(); pID->SetExpr( new expr_constant( 0L ) ); } return CG_OK; } CG_STATUS CG_PROC::MarshallAnalysis( ANALYSIS_INFO * pAna ) { ITERATOR I; CG_PARAM * pCG = 0; CG_PARAM * pS; CG_RETURN * pRT; SIDE Side = pAna->GetCurrentSide(); expr_node * pSE = 0; BOOL fReturnNeedsMarshall = FALSE; if( Side == C_SIDE ) GetInParamList( I ); else GetOutParamList( I ); pRT = GetReturnType(); if ( Side == S_SIDE && pRT != 0 ) fReturnNeedsMarshall = TRUE; if( ITERATOR_GETCOUNT( I ) ) { ITERATOR_INIT( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { // The "invisible" fault or comm status param doesn't marshal. pS = (CG_PARAM *)ITERATOR_PEEKTHIS( I ); if ( pCG->IsExtraStatusParam() ) continue; pCG->MarshallAnalysis( pAna ); // Add to the sizing expression. if( pSE ) pSE = new expr_b_arithmetic( OP_PLUS, pSE, pCG->GetSizeExpression() ); else pSE = pCG->GetSizeExpression(); } } if(fReturnNeedsMarshall) { pRT->MarshallAnalysis( pAna ); if( pSE ) pSE = new expr_b_arithmetic( OP_PLUS, pSE, pRT->GetSizeExpression() ); else pSE = pRT->GetSizeExpression(); } if( pSE ) SetSizeExpression( pSE ); else SetSizeExpression( new expr_constant( 0L,VALUE_TYPE_NUMERIC_U )); if ( HasExtraStatusParam() ) { GetMembers(I); while ( ITERATOR_GETNEXT( I, pCG ) ) if ( pCG->IsExtraStatusParam() ) break; node_skl *pType = pCG->GetType(); pCG->SetResource( new RESOURCE( pType->GetSymName(), pType ) ); } return CG_OK; } CG_STATUS CG_PROC::UnMarshallAnalysis( ANALYSIS_INFO * pAna ) { ITERATOR I; CG_PARAM * pCG = 0; CG_PARAM * pS; CG_RETURN * pRT = 0; SIDE Side = pAna->GetCurrentSide(); BOOL fReturnNeedsUnMarshall = FALSE; if( Side == C_SIDE ) GetOutParamList( I ); else GetInParamList( I ); if( (Side == C_SIDE ) && (pRT = GetReturnType() ) != 0 ) fReturnNeedsUnMarshall = TRUE; if( ITERATOR_GETCOUNT(I) ) { while( ITERATOR_GETNEXT( I, pCG ) ) { // The "invisible" fault/comm status param doesn't unmarshal. pS = (CG_PARAM *)ITERATOR_PEEKTHIS( I ); if ( pCG->IsExtraStatusParam() ) continue; pCG->UnMarshallAnalysis( pAna ); } } if( fReturnNeedsUnMarshall ) { pRT->UnMarshallAnalysis( pAna ); } return CG_OK; } CG_STATUS CG_PROC::S_OutLocalAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform analysis for all params which may be allocated as locals for the server side stubs. Arguments: pAna - The analysis block. Return Value: CG_OK if all is well, error otherwise. Notes: ----------------------------------------------------------------------------*/ { ITERATOR I; CG_PARAM * pParam = 0; GetOutParamList( I ); while( ITERATOR_GETNEXT( I, pParam ) ) { pParam->S_OutLocalAnalysis( pAna ); } return CG_OK; } void CG_PROC::RpcSsPackageAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform analysis for the need to invoke RpcSsm package at server. Arguments: pAna - The analysis block. Return Value: Notes: Note that we perform both sides analysis at once as the format string is generated usually at the client pass. ----------------------------------------------------------------------------*/ { // // In ms_ext mode: // only if Enable allocate is specified // In osf mode: // if( RpcSS is recommended by analysis || enable allocate specified ) // SetMustInvokeRpcSSAllocate( 0 ); if ( IsRpcSSSpecified() ) SetMustInvokeRpcSSAllocate( 1 ); if ( MustInvokeRpcSSAllocate() || pAna->GetMode() != 0 ) return; // We analyze parameters in osf to boost performance by skipping // unnecessary enable and disable operations. // ITERATOR ParamList; CG_PARAM * pParam = 0; GetMembers( ParamList ); if( ITERATOR_GETCOUNT( ParamList ) ) { ITERATOR_INIT( ParamList ); while( ITERATOR_GETNEXT( ParamList, pParam ) ) { pParam->RpcSsPackageAnalysis( pAna ); } } CG_RETURN * pReturn = GetReturnType(); if ( pReturn ) { if ( (pAna->GetOptimOption() & OPTIMIZE_INTERPRETER) || (pReturn->GetChild() && ( ((CG_NDR *)pReturn->GetChild())->IsPointer() || ((CG_NDR *)pReturn->GetChild())->HasPointer() || ((CG_NDR *)pReturn->GetChild())->GetCGID() == ID_CG_ENCAP_STRUCT ) ) ) { // We could do a better job for Oi2 if we watched its stack. // Encapsulated union is there as it was a hassle to make it // know about its pointers. pAna->SetRpcSSAllocateRecommended( 1 ); } } if ( pAna->IsRpcSSAllocateRecommended() ) SetMustInvokeRpcSSAllocate( 1 ); } CG_STATUS CG_PROC::RefCheckAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform ref pointer check analysis. Arguments: pAna - The analysis info block. Return Value: CG_OK Notes: ----------------------------------------------------------------------------*/ { ITERATOR I; CG_PARAM * pCG = 0; CG_RETURN * pRT = 0; SIDE Side = pAna->GetCurrentSide(); BOOL fReturnNeedsMarshall = FALSE; // generate ref check resources for both in and out params. GetMembers( I ); if( (Side == S_SIDE ) && (pRT = GetReturnType() ) != 0 ) fReturnNeedsMarshall = TRUE; if( ITERATOR_GETCOUNT( I ) ) { ITERATOR_INIT( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { pCG->RefCheckAnalysis( pAna ); } } if(fReturnNeedsMarshall) { pRT->RefCheckAnalysis( pAna ); } return CG_OK; } CG_STATUS CG_PROC::InLocalAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform analysis for [in] params allocated as locals on server. Arguments: pAna - The analysis info block. Return Value: CG_OK Notes: ----------------------------------------------------------------------------*/ { ITERATOR I; CG_PARAM * pCG = 0; GetInParamList( I ); if( ITERATOR_GETCOUNT( I ) ) { ITERATOR_INIT( I ); while( ITERATOR_GETNEXT( I, pCG ) ) { pCG->InLocalAnalysis( pAna ); } } return CG_OK; } /**************************************************************************** Implementation of the parameter code generator class. ****************************************************************************/ CG_STATUS CG_PARAM::MarshallAnalysis( ANALYSIS_INFO * pAna ) { CG_STATUS Status; // // Initialize the analysis block and the parameter for the current side // and analysis phase. // InitParamMarshallAnalysis( pAna ); // Send the message to the lower cg nodes. Status = ((CG_NDR *)GetChild())->MarshallAnalysis( pAna ); if( pAna->HasAtLeastOneDeferredPointee() ) { pAna->ResetDeferPointee(); ((CG_NDR *)GetChild())->FollowerMarshallAnalysis( pAna ); } ConsolidateParamMarshallAnalysis( pAna ); // The analysis block will now have properties which are a combo of the // properties before this param and the properties of this param. return CG_OK; } CG_STATUS CG_PARAM::UnMarshallAnalysis( ANALYSIS_INFO * pAna ) { InitParamUnMarshallAnalysis( pAna ); // Send the message to the child to perform the same analysis for us // and then consolidate the results on return. ((CG_NDR *)GetChild())->UnMarshallAnalysis( pAna ); if( pAna->HasAtLeastOneDeferredPointee() ) { pAna->ResetDeferPointee(); ((CG_NDR *)GetChild())->FollowerUnMarshallAnalysis( pAna ); } // Consolidate the results of analysis from the lower nodes. ConsolidateParamUnMarshallAnalysis( pAna ); return CG_OK; } void CG_PARAM::InitParamMarshallAnalysis( ANALYSIS_INFO * pAna ) { node_skl * pType = GetType(); PNAME pName = pType->GetSymName(); CG_NDR * pC = (CG_NDR *)GetChild(); // For all cases of generic handles, where the CG_GENERIC_HANDLE will // sit below the param, we want to bypass the generic handle class during // marshall analysis. if( pC->GetCGID() == ID_CG_GENERIC_HDL ) { pC = (CG_NDR *)pC->GetChild(); } // // Allocate the resource for this parameter. On the client side, this // parameter is a param resource, while on the server, this param is a local // resource. One the client side, the param has already been added to the // resource dictionary. if( pAna->GetCurrentSide() == C_SIDE ) { if( (pC->IsArray()) && (pAna->GetOptimOption() & OPTIMIZE_INTERPRETER ) ) { pType = MakePtrIDNode( pName, pType->GetChild() ); } SetResource( new RESOURCE( pName, pType) ); } else { node_skl * pActualType = pType->GetChild(); if( (pC->GetCGID() == ID_CG_CONTEXT_HDL ) || (pC->GetChild() && (pC->GetChild()->GetCGID() == ID_CG_CONTEXT_HDL))) { pActualType = MakeIDNode( pName, new node_def ("NDR_SCONTEXT" ) ); } else if( pC->IsArray() ) pActualType = MakePtrIDNode( pName, pActualType); else pActualType = MakeIDNode( pName, pActualType ); SetResource( pAna->AddLocalResource( pName, pActualType )); } SetSizeResource( 0 ); SetLengthResource( 0 ); SetFirstResource( 0 ); pAna->SetMemoryAllocDone(); pAna->ResetRefAllocDone(); pAna->ResetEmbeddingLevel(); pAna->ResetIndirectionLevel(); pAna->SetRefChainIntact(); pAna->ResetDeferPointee(); pAna->ResetHasAtLeastOneDeferredPointee(); pAna->SetLastPlaceholderClass( (CG_NDR *)this ); } void CG_PARAM::ConsolidateParamMarshallAnalysis( ANALYSIS_INFO * pAna ) { expr_node * pSE = 0; // Consolidate the result of the analysis from lower nodes, first into // this node, and then into the analysis block. pSE = new expr_constant( (long)0U, VALUE_TYPE_NUMERIC_U ); SetSizeExpression( pSE ); if( pAna->GetOptimOption() & OPTIMIZE_SIZE ) { pAna->ClearTransientResourceDict(); } } void CG_PARAM::InitParamUnMarshallAnalysis( ANALYSIS_INFO * pAna ) { node_skl * pType = GetType(); node_skl * pActualType = pType->GetBasicType(); PNAME pName = pType->GetSymName(); CG_NDR * pC = (CG_NDR *)GetChild(); // For all cases of generic handles, where the CG_GENERIC_HANDLE will // sit below the param, we want to bypass the generic handle class during // marshall analysis. if( pC->GetCGID() == ID_CG_GENERIC_HDL ) { pC = (CG_NDR *)pC->GetChild(); } // // Allocate resources. On the client side, a parameter resource is allocated // and on the server, a local resource is allocated. // SetSubstitutePtrResource( 0 ); if( pAna->GetCurrentSide() == C_SIDE ) { pAna->SetDontReUseBuffer(); if( (pC->IsArray()) && (pAna->GetOptimOption() & OPTIMIZE_INTERPRETER ) ) { pType = MakePtrIDNode( pName, pType->GetChild() /* GetBasicType() ????????? */ ); } SetResource( new RESOURCE( pName, pType) ) ; } else if ( ! IsOmittedParam() ) { pC->SetAllocatedOnStack( 1 ); if( (pC->GetCGID() == ID_CG_CONTEXT_HDL ) || (pC->GetChild() && (pC->GetChild()->GetCGID() == ID_CG_CONTEXT_HDL))) { pActualType = MakeIDNode( pName, new node_def ("NDR_SCONTEXT" ) ); } else if( pC->IsArray() ) { pActualType = MakePtrIDNode( pName, pType->GetChild() ); } else pActualType = MakeIDNode( pName, pType->GetChild() ); pAna->ResetDontReUseBuffer(); SetResource( pAna->AddLocalResource( pName, pActualType ) ); } SetSizeResource( 0 ); SetLengthResource( 0 ); SetFirstResource( 0 ); // Reset for analysis. pAna->SetMemoryAllocDone(); pAna->ResetRefAllocDone(); pAna->ResetEmbeddingLevel(); pAna->ResetIndirectionLevel(); pAna->SetRefChainIntact(); pAna->ResetDeferPointee(); pAna->ResetHasAtLeastOneDeferredPointee(); pAna->SetLastPlaceholderClass( (CG_NDR *)this ); } void CG_PARAM::ConsolidateParamUnMarshallAnalysis( ANALYSIS_INFO * pAna ) { // Consolidate the result of the analysis from lower nodes, first into // this node, and then into the analysis block. if( pAna->GetOptimOption() & OPTIMIZE_SIZE ) { pAna->ClearTransientResourceDict(); } } CG_STATUS CG_PARAM::S_OutLocalAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform analysis for all params which may be allocated as locals for server stub Arguments: pAna - A pointer to the analysis block. Return Value: Notes: Ignore [in, out], since that would be done by the Unmarshall analysis. ----------------------------------------------------------------------------*/ { // If the param is [out] only, determine if there is a need for local // variables and if they need to be inited. if( IsParamOut() && !IsParamIn() ) { InitParamMarshallAnalysis( pAna ); ((CG_NDR *)GetChild())->S_OutLocalAnalysis( pAna ); } return CG_OK; } void CG_PARAM::RpcSsPackageAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform analysis for rpcss package enabling. Arguments: pAna - A pointer to the analysis block. Return Value: Notes: This routine should be called only in the osf mode. ----------------------------------------------------------------------------*/ { // // Package needs to be enabled (only is OSF mode) when the NDR engine // is going to do any allocations whatsoever at the server side. // // In Os this may happen on // - anything other than simple type or pointer to simple type // - with simple type, if this happens to be enum16 // In Oi this may happen on // - anything [out] // - [in] like Os // In Oi2 this may happen on // - anything [out] when lack of space on -Oi2 stack // - [in] like Os // (simple types and pointers to simple types are usually on // the interpreter stack, if there is space there). // However, this cannot be guaranteed. if( IsParamOut() && ( pAna->GetOptimOption() & OPTIMIZE_INTERPRETER) ) { // We could do a better job for Oi2 if we watched the its stack. pAna->SetRpcSSAllocateRecommended( 1 ); return; } // We are here with // [in] or [in,out] for Oi? // any for Os // See if this is one of the simple cases mentioned above. // This is really a check for the buffer reusage. CG_NDR * pChild = (CG_NDR *)GetChild(); if ( pChild->IsSimpleType() && ( pChild->GetCGID() != ID_CG_ENUM || pChild->GetCGID() == ID_CG_ENUM && ((CG_ENUM*)pChild)->IsEnumLong() ) && pChild->GetCGID() != ID_CG_INT3264 ) { // An [in] arg in the buffer. return; } // Note that we don't have to check for allocate(allnodes) etc. // as this is not an osf attribute. // Also note that we handle top level pointers here. if ( pChild->IsPointer() && ((CG_POINTER *)pChild)->IsRef() ) { // In args would stay in the buffer, // out args would be on the Os stack. CG_NDR * pPointee = (CG_NDR *)pChild->GetChild(); if ( ( pChild->GetCGID() == ID_CG_PTR || pChild->GetCGID() == ID_CG_STRING_PTR || pChild->GetCGID() == ID_CG_SIZE_PTR ) && pPointee->IsSimpleType() && ( pPointee->GetCGID() != ID_CG_ENUM || pPointee->GetCGID() == ID_CG_ENUM && ((CG_ENUM*)pPointee)->IsEnumLong() ) && pPointee->GetCGID() != ID_CG_INT3264 ) return; } pAna->SetRpcSSAllocateRecommended( 1 ); } /**************************************************************************** Implementation of the return type node. ****************************************************************************/ CG_STATUS CG_RETURN::MarshallAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform the size analysis for the return type. Arguments: pAna - A pointer to the analysis block. Return Value: Notes: For the return type, the size analysis contributes nothing on the client side, yet we must declare a local variable for the return. ----------------------------------------------------------------------------*/ { node_skl * pType = GetType(); PNAME pName = RETURN_VALUE_VAR_NAME; CG_STATUS Status; CG_NDR * pC = (CG_NDR *)GetChild(); // // Always allocate a local resource for the return type. // if( (pC->GetCGID() == ID_CG_CONTEXT_HDL ) || (pC->GetChild() && (pC->GetChild()->GetCGID() == ID_CG_CONTEXT_HDL))) { node_skl * pActualType = pType->GetBasicType(); pActualType = MakeIDNode( pName, new node_def ("NDR_SCONTEXT" ) ); SetResource( pAna->AddLocalResource( pName, pActualType )); } else { pType = MakeIDNode( pName, pType ); SetResource( pAna->AddLocalResource( pName, pType )); } SetSizeResource( 0 ); // Reset the analysis block for marshalling. pAna->SetMemoryAllocDone(); pAna->ResetRefAllocDone(); pAna->ResetEmbeddingLevel(); pAna->SetRefChainIntact(); pAna->SetDontReUseBuffer(); pAna->SetReturnContext(); pAna->SetLastPlaceholderClass( (CG_NDR *)this ); // Send the analysis message to the child nodes. Status = ((CG_NDR *)GetChild())->MarshallAnalysis( pAna ); SetSizeExpression( new expr_constant( 0L, VALUE_TYPE_NUMERIC_U ) ); pAna->ResetReturnContext(); if( pAna->GetOptimOption() & OPTIMIZE_SIZE ) { pAna->ClearTransientResourceDict(); } return Status; } CG_STATUS CG_RETURN::UnMarshallAnalysis( ANALYSIS_INFO * pAna ) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Routine Description: Perform the buffer analysis for the return type. Arguments: pAna - A pointer to the analysis block. Return Value: Notes: For the return type, the size analysis contributes nothing on the client side, yet we must declare a local variable for the return. ----------------------------------------------------------------------------*/ { node_skl * pType = GetType(); PNAME pName = RETURN_VALUE_VAR_NAME; CG_STATUS Status; // // Always allocate a local resource for the return type. // pType = MakeIDNode( pName, pType ); SetResource( pAna->AddLocalResource( pName, pType )); pAna->SetMemoryAllocDone(); pAna->ResetRefAllocDone(); pAna->ResetEmbeddingLevel(); pAna->SetRefChainIntact(); pAna->SetDontReUseBuffer(); pAna->SetReturnContext(); pAna->SetLastPlaceholderClass( (CG_NDR *)this ); Status = ((CG_NDR *)GetChild())->UnMarshallAnalysis( pAna ); pAna->ResetReturnContext(); if( pAna->GetOptimOption() & OPTIMIZE_SIZE ) { pAna->ClearTransientResourceDict(); } return Status; }