windows-nt/Source/XPSP1/NT/com/rpc/midl/analysis/procana.cxx

904 lines
21 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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;
}