804 lines
18 KiB
C++
804 lines
18 KiB
C++
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
Copyright (c) 1989-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
analysis.hxx
|
|
|
|
Abstract:
|
|
|
|
Defines the control block class used during optimsation/codegen analysis.
|
|
|
|
Notes:
|
|
|
|
This class keeps code gen analysis information while the analysis is in
|
|
progress.
|
|
|
|
Author:
|
|
|
|
VibhasC Jul-25-1993 Created
|
|
|
|
Notes:
|
|
|
|
----------------------------------------------------------------------------*/
|
|
#ifndef __ANAINFO_HXX__
|
|
#define __ANAINFO_HXX__
|
|
|
|
/****************************************************************************
|
|
* include files
|
|
***************************************************************************/
|
|
#include "nulldefs.h"
|
|
|
|
extern "C"
|
|
{
|
|
#include <stdio.h>
|
|
}
|
|
|
|
#include "common.hxx"
|
|
#include "cgcommon.hxx"
|
|
// #include "optprop.hxx"
|
|
#include "opinfo.hxx"
|
|
#include "resdict.hxx"
|
|
#include "uact.hxx"
|
|
|
|
|
|
/****************************************************************************
|
|
* local definitions
|
|
***************************************************************************/
|
|
|
|
extern short TempResourceCounter;
|
|
|
|
/****************************************************************************
|
|
Notes
|
|
|
|
The analysis phase is the first phase of the code generation process.
|
|
This phase figures out:
|
|
|
|
1. data offsets in the buffer,
|
|
2. local variable allocations,
|
|
3. alignment needs, actions,
|
|
4. Total or worst case buffer size requirements,
|
|
5. ability of the parameter to be marshalled by the engine,
|
|
6. need for auxillary routines and what auxillary routines, etc
|
|
|
|
This consists of 1 pass and information is set up during descent and the
|
|
subsequent ascent. Pointees are deferred in the ndr and the analysis phase
|
|
mimics that.
|
|
|
|
In short, the analysis phase does what the code generator would do, except
|
|
emit the code. The walk is determined by the ndr representation for a type.
|
|
|
|
A pointer to one analysis block instance is passed during the analysis walk.
|
|
Each cg class knows what to do with information in the analysis block.
|
|
|
|
|
|
A word about resources. Local variables are treated by the code generator
|
|
as local resources. These are special expression-derived classes which have
|
|
names and usually locations associated with them. A resource may be a
|
|
parameter resource in which case it will appear as a parameter, a local
|
|
resource, in which case it appears as a local variable.
|
|
|
|
The analyser may decide to allocate local resources based on need as a
|
|
result of the analysis. Some resources are pre-known to the code generator
|
|
and they are known as standard resources. The names and locations of these
|
|
are fixed. For example the buffer pointer variable is _always_ a local
|
|
resource. Similarly the rpc message pointer is _always_ a param resource
|
|
for the server stub.
|
|
***************************************************************************/
|
|
|
|
//
|
|
// Enumerations of the analysis phase. Names are self-explanatory.
|
|
//
|
|
|
|
typedef enum _anaphase
|
|
{
|
|
ANA_PHASE_CLIENT_MARSHALL
|
|
, ANA_PHASE_CLIENT_UNMARSHALL
|
|
, ANA_PHASE_SERVER_UNMARSHALL
|
|
, ANA_PHASE_SERVER_MARSHALL
|
|
|
|
//
|
|
// This last enum actually defines a count of the number of phases
|
|
// defined for the purposes of allocation of arrays for analysis info
|
|
// if necessary.
|
|
//
|
|
|
|
, ANA_PHASE_COUNT
|
|
|
|
} ANAPHASE;
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// The big guy ! This is the analysis information manager.
|
|
//
|
|
// An implementation note: Try to keep bit fields together. All bit fields
|
|
// so far have been defined as unsigned longs, so keeping them together will
|
|
// enable the compiler to coalesce them into a long. Different compiler
|
|
// implementations may do a good or bad job.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
class CG_NDR;
|
|
class ANALYSIS_INFO
|
|
{
|
|
private:
|
|
|
|
//
|
|
// Miscellaneous properties like checking for ref parameters etc are
|
|
// kept here. The presence of at least one such property indicates that
|
|
// the stub must check for the validity of such parameters.
|
|
//
|
|
|
|
MISC_PROPERTY fMiscProperties : 1;
|
|
|
|
|
|
//
|
|
// Inherited property specifies that the child node must assume memory
|
|
// allocation done for it. The lower nodes use this info to figure out if
|
|
// they need to allocate memory and local variable pointers to this memory
|
|
// if necessary.
|
|
//
|
|
|
|
unsigned long fMemoryAllocDone: 1;
|
|
|
|
// Is a reference allocated for the lower types ?
|
|
|
|
unsigned long fRefAllocDone : 1;
|
|
|
|
// Is the ref chain from top-level params intact ?
|
|
|
|
unsigned long fRefChainIntact : 1;
|
|
|
|
// Flag indicating a return context.
|
|
|
|
unsigned long fReturnContext : 1;
|
|
|
|
// Flag indicating if pointees need to be deferred.
|
|
|
|
unsigned long fDeferPointee : 1;
|
|
|
|
// Flag indicating presence of at least one deferred pointee.
|
|
|
|
unsigned long fAtLeastOneDeferredPointee: 1;
|
|
|
|
//
|
|
// Inherited property that specifies if lower nodes must assume rpc buffer
|
|
// re-use. Rpc buffer re-use is not possible for dont_free params/types.
|
|
//
|
|
|
|
unsigned long fDontReUseBuffer: 1;
|
|
|
|
|
|
unsigned long fArrayContext : 1;
|
|
|
|
// The compiler mode.
|
|
|
|
unsigned long Mode : 2;
|
|
|
|
// Rpc ss allocate recommendation.
|
|
|
|
unsigned long fRpcSSAllocateRecommended : 1;
|
|
|
|
unsigned long fRpcSSSwitchSet : 1;
|
|
|
|
//
|
|
// These fields specify the allocation info for server side parameters.
|
|
// S_AllocLocation specifies if the allocation is on the stack or heap
|
|
// or the allocation is not needed (if buffer is being re-used). The
|
|
// S_AllocType specifies what the allocation would be: a pointer to the
|
|
// type in question or the type itself. The S_InitNeed specifies if the
|
|
// param needs to be inited by the server stub on entry. These are
|
|
// inherited properties.
|
|
//
|
|
|
|
S_STUB_ALLOC_LOCATION S_AllocLocation : 2;
|
|
|
|
S_STUB_ALLOC_TYPE S_AllocType : 2;
|
|
|
|
S_STUB_INIT_NEED S_InitNeed : 2;
|
|
|
|
|
|
//
|
|
// The current analysis phase.
|
|
//
|
|
|
|
ANAPHASE Phase;
|
|
|
|
|
|
// The current side.
|
|
|
|
SIDE Side;
|
|
|
|
|
|
//
|
|
// The current set of optimisation switches. This is a transformed form of
|
|
// optimisation options that the user specified. This helps decide what
|
|
// code generation actions to take. For example an option may specify that
|
|
// a procedure needs to be interpreted, so we dont need to call the normal
|
|
// code generator.
|
|
//
|
|
|
|
OPTIM_OPTION OptimOptions;
|
|
|
|
//
|
|
// The Resource dictionaries are maitained in a resource dictionary
|
|
// data base.
|
|
//
|
|
|
|
RESOURCE_DICT_DATABASE * pResDictDatabase;
|
|
|
|
// The current embedding context. We increment this to indicate if we are
|
|
// in a top level or embedded context.
|
|
|
|
short EmbeddingLevel;
|
|
|
|
// This indicates the ptr indirection level. Each pointer must note its
|
|
// indirection level and then bump this field to indicate to the next
|
|
// pointer its (that pointer's) level.
|
|
|
|
short IndirectionLevel;
|
|
|
|
|
|
// Set unmarshalling action code.
|
|
|
|
U_ACTION UAction;
|
|
|
|
// Last placeholder class (like param / field / return etc)
|
|
|
|
CG_NDR * pLastPlaceholderClass;
|
|
|
|
public:
|
|
|
|
ANALYSIS_INFO();
|
|
|
|
|
|
~ANALYSIS_INFO()
|
|
{
|
|
}
|
|
|
|
//
|
|
// Init the state of this analysis block. This call resets the
|
|
// alignment state machine, buffer size properties etc. This is called
|
|
// ONCE per procedure per stub side.
|
|
//
|
|
|
|
void Reset();
|
|
|
|
//
|
|
// Simple set and get functions.
|
|
//
|
|
|
|
void SetRpcSSSwitchSet( BOOL f)
|
|
{
|
|
fRpcSSSwitchSet = f;
|
|
}
|
|
|
|
BOOL IsRpcSSSwitchSet()
|
|
{
|
|
return fRpcSSSwitchSet;
|
|
}
|
|
|
|
void SetRpcSSAllocateRecommended( unsigned long f )
|
|
{
|
|
fRpcSSAllocateRecommended = f;
|
|
}
|
|
|
|
BOOL IsRpcSSAllocateRecommended()
|
|
{
|
|
return (BOOL)(fRpcSSAllocateRecommended == 1);
|
|
}
|
|
|
|
void SetMode( unsigned long M )
|
|
{
|
|
Mode = M;
|
|
}
|
|
unsigned long GetMode()
|
|
{
|
|
return Mode;
|
|
}
|
|
|
|
CG_NDR * SetLastPlaceholderClass( CG_NDR * pLP )
|
|
{
|
|
return pLastPlaceholderClass = pLP;
|
|
}
|
|
CG_NDR * GetLastPlaceholderClass()
|
|
{
|
|
return pLastPlaceholderClass;
|
|
}
|
|
|
|
unsigned long SetHasAtLeastOneDeferredPointee()
|
|
{
|
|
return (fAtLeastOneDeferredPointee = 1);
|
|
}
|
|
|
|
unsigned long ResetHasAtLeastOneDeferredPointee()
|
|
{
|
|
return (fAtLeastOneDeferredPointee = 0);
|
|
}
|
|
|
|
unsigned long SetDeferPointee()
|
|
{
|
|
return (fDeferPointee = 1);
|
|
}
|
|
|
|
unsigned long ResetDeferPointee()
|
|
{
|
|
return (fDeferPointee = 0);
|
|
}
|
|
|
|
unsigned long SetReturnContext()
|
|
{
|
|
return (fReturnContext = 1);
|
|
}
|
|
unsigned long ResetReturnContext()
|
|
{
|
|
return (fReturnContext = 0);
|
|
}
|
|
|
|
unsigned long SetRefChainIntact()
|
|
{
|
|
return (fRefChainIntact = 1);
|
|
}
|
|
unsigned long ResetRefChainIntact()
|
|
{
|
|
return (fRefChainIntact = 0);
|
|
}
|
|
|
|
short ResetEmbeddingLevel()
|
|
{
|
|
return (EmbeddingLevel = 0);
|
|
}
|
|
|
|
// bumps up embedding level, but returns the old one.
|
|
|
|
short PushEmbeddingLevel()
|
|
{
|
|
return EmbeddingLevel++;
|
|
}
|
|
|
|
// pops embedding level but returns the current one.
|
|
|
|
short PopEmbeddingLevel()
|
|
{
|
|
if( IndirectionLevel > 0 )
|
|
return IndirectionLevel--;
|
|
else
|
|
return IndirectionLevel;
|
|
}
|
|
|
|
short GetCurrentEmbeddingLevel()
|
|
{
|
|
return EmbeddingLevel;
|
|
}
|
|
|
|
short SetCurrentEmbeddingLevel( short E)
|
|
{
|
|
return (EmbeddingLevel = E);
|
|
}
|
|
|
|
short ResetIndirectionLevel()
|
|
{
|
|
return (IndirectionLevel = 0);
|
|
}
|
|
|
|
// This pushes the indirection level, but returns the current one.
|
|
|
|
short PushIndirectionLevel()
|
|
{
|
|
return IndirectionLevel++;
|
|
}
|
|
|
|
// This pops the indirection Level but returns the current one.
|
|
|
|
short PopIndirectionLevel()
|
|
{
|
|
if( IndirectionLevel > 0 )
|
|
return IndirectionLevel--;
|
|
else
|
|
return IndirectionLevel;
|
|
}
|
|
|
|
short GetCurrentIndirectionLevel()
|
|
{
|
|
return IndirectionLevel;
|
|
}
|
|
|
|
S_STUB_ALLOC_LOCATION SetSStubAllocLocation( S_STUB_ALLOC_LOCATION L )
|
|
{
|
|
return (S_AllocLocation = L);
|
|
}
|
|
|
|
S_STUB_ALLOC_LOCATION GetSStubAllocLocation()
|
|
{
|
|
return S_AllocLocation;
|
|
}
|
|
|
|
S_STUB_ALLOC_TYPE SetSStubAllocType( S_STUB_ALLOC_TYPE T )
|
|
{
|
|
return (S_AllocType = T);
|
|
}
|
|
|
|
S_STUB_ALLOC_TYPE GetSStubAllocType()
|
|
{
|
|
return S_AllocType;
|
|
}
|
|
|
|
S_STUB_INIT_NEED SetSStubInitNeed( S_STUB_INIT_NEED N )
|
|
{
|
|
return (S_InitNeed = N);
|
|
}
|
|
|
|
S_STUB_INIT_NEED GetSStubInitNeed()
|
|
{
|
|
return S_InitNeed;
|
|
}
|
|
|
|
short ResetTempResourceCounter()
|
|
{
|
|
return (TempResourceCounter = 0);
|
|
}
|
|
|
|
short GetTempResourceCounter()
|
|
{
|
|
return TempResourceCounter;
|
|
}
|
|
|
|
short BumpTempResourceCounter()
|
|
{
|
|
return (++TempResourceCounter);
|
|
}
|
|
|
|
void SetDontReUseBuffer()
|
|
{
|
|
fDontReUseBuffer = 1;
|
|
}
|
|
|
|
void ResetDontReUseBuffer()
|
|
{
|
|
fDontReUseBuffer = 0;
|
|
}
|
|
|
|
void SetMemoryAllocDone()
|
|
{
|
|
fMemoryAllocDone = 1;
|
|
}
|
|
|
|
void ResetMemoryAllocDone()
|
|
{
|
|
fMemoryAllocDone = 0;
|
|
}
|
|
|
|
void SetRefAllocDone()
|
|
{
|
|
fRefAllocDone = 1;
|
|
}
|
|
|
|
void ResetRefAllocDone()
|
|
{
|
|
fRefAllocDone = 0;
|
|
}
|
|
|
|
ANAPHASE SetCurrentPhase( ANAPHASE P )
|
|
{
|
|
return (Phase = P);
|
|
}
|
|
|
|
ANAPHASE GetCurrentPhase()
|
|
{
|
|
return Phase;
|
|
}
|
|
|
|
SIDE SetCurrentSide( SIDE P )
|
|
{
|
|
return (Side = P);
|
|
}
|
|
|
|
SIDE GetCurrentSide()
|
|
{
|
|
return Side;
|
|
}
|
|
|
|
OPTIM_OPTION SetOptimOption( OPTIM_OPTION Op )
|
|
{
|
|
return (OptimOptions |= Op);
|
|
}
|
|
OPTIM_OPTION GetOptimOption()
|
|
{
|
|
return OptimOptions;
|
|
}
|
|
|
|
void ClearOptimOptions()
|
|
{
|
|
OptimOptions = OPTIMIZE_NONE;
|
|
}
|
|
|
|
MISC_PROPERTY SetMiscProperties( MISC_PROPERTY M )
|
|
{
|
|
return (fMiscProperties = M);
|
|
}
|
|
|
|
MISC_PROPERTY GetMiscProperties()
|
|
{
|
|
return fMiscProperties;
|
|
}
|
|
|
|
void SetArrayContext()
|
|
{
|
|
fArrayContext = 1;
|
|
}
|
|
void ResetArrayContext()
|
|
{
|
|
fArrayContext = 0;
|
|
}
|
|
BOOL IsArrayContext()
|
|
{
|
|
return (BOOL)(fArrayContext == 1);
|
|
}
|
|
|
|
RESOURCE_DICT_DATABASE * SetResDictDatabase( RESOURCE_DICT_DATABASE * p )
|
|
{
|
|
return ( pResDictDatabase = p );
|
|
}
|
|
|
|
RESOURCE_DICT_DATABASE * GetResDictDatabase()
|
|
{
|
|
return pResDictDatabase;
|
|
}
|
|
|
|
//
|
|
// Set the analysis block ready for the next parameter on server side.
|
|
//
|
|
|
|
void S_ResetForNextParam( )
|
|
{
|
|
ResetMemoryAllocDone();
|
|
ResetRefAllocDone();
|
|
ResetDontReUseBuffer();
|
|
ResetEmbeddingLevel();
|
|
ResetIndirectionLevel();
|
|
}
|
|
|
|
//
|
|
// Queries.
|
|
//
|
|
|
|
BOOL ShouldNotReUseBuffer()
|
|
{
|
|
return (BOOL)(fDontReUseBuffer == 1);
|
|
}
|
|
|
|
BOOL IsMemoryAllocDone()
|
|
{
|
|
return (BOOL)(fMemoryAllocDone == 1);
|
|
}
|
|
|
|
BOOL IsRefAllocDone()
|
|
{
|
|
return (fRefAllocDone == 1);
|
|
}
|
|
|
|
BOOL IsRefChainIntact()
|
|
{
|
|
return (fRefChainIntact == 1);
|
|
}
|
|
|
|
BOOL IsReturnContext()
|
|
{
|
|
return (fReturnContext == 1);
|
|
}
|
|
|
|
BOOL HasAtLeastOneDeferredPointee()
|
|
{
|
|
return (fAtLeastOneDeferredPointee == 1);
|
|
}
|
|
|
|
BOOL IsPointeeDeferred()
|
|
{
|
|
return (fDeferPointee == 1);
|
|
}
|
|
|
|
//
|
|
// Should we optimize for size ?
|
|
//
|
|
|
|
|
|
BOOL ShouldOptimizeSize()
|
|
{
|
|
return (BOOL)
|
|
((OptimOptions & OPTIMIZE_SIZE) ==
|
|
OPTIMIZE_SIZE );
|
|
}
|
|
|
|
BOOL ShouldOptimizeInterpreter()
|
|
{
|
|
return (BOOL)
|
|
((OptimOptions & OPTIMIZE_INTERPRETER) ==
|
|
OPTIMIZE_INTERPRETER );
|
|
}
|
|
|
|
//
|
|
// Should we generate code to check for a null ref pointer in the client
|
|
// stubs ?
|
|
//
|
|
|
|
BOOL ShouldCheckRef()
|
|
{
|
|
return (BOOL)
|
|
((OptimOptions & OPTIMIZE_NO_REF_CHECK) ==
|
|
0 );
|
|
}
|
|
|
|
//
|
|
// Should we generate code to check for array bound attributes like
|
|
// size_is, length_is etc in the stubs ?
|
|
//
|
|
|
|
BOOL ShouldCheckBounds()
|
|
{
|
|
return (BOOL)
|
|
((OptimOptions & OPTIMIZE_NO_BOUNDS_CHECK)==
|
|
0 );
|
|
}
|
|
|
|
//
|
|
// miscellaneous methods.
|
|
//
|
|
|
|
RESOURCE * AddParamResource( PNAME pResName, node_skl *pT )
|
|
{
|
|
return DoAddResource( pResDictDatabase->
|
|
GetParamResourceDict(),
|
|
pResName,
|
|
pT
|
|
);
|
|
}
|
|
|
|
RESOURCE * GetParamResource( PNAME pResName )
|
|
{
|
|
return
|
|
pResDictDatabase->
|
|
GetLocalResourceDict()->Search(
|
|
pResName );
|
|
}
|
|
|
|
RESOURCE * AddLocalResource( PNAME pResName, node_skl *pT )
|
|
{
|
|
return DoAddResource( pResDictDatabase->
|
|
GetLocalResourceDict(),
|
|
pResName,
|
|
pT
|
|
);
|
|
}
|
|
|
|
RESOURCE * GetLocalResource( PNAME pResName )
|
|
{
|
|
return
|
|
pResDictDatabase->
|
|
GetLocalResourceDict()->Search(
|
|
pResName );
|
|
}
|
|
|
|
RESOURCE * AddGlobalResource( PNAME pResName, node_skl *pT )
|
|
{
|
|
return DoAddResource( pResDictDatabase->
|
|
GetGlobalResourceDict(),
|
|
pResName,
|
|
pT
|
|
);
|
|
}
|
|
|
|
RESOURCE * GetGlobalResource( PNAME pResName )
|
|
{
|
|
return
|
|
pResDictDatabase->
|
|
GetGlobalResourceDict()->Search(
|
|
pResName );
|
|
}
|
|
|
|
|
|
RESOURCE * AddTransientResource( PNAME pResName, node_skl *pT )
|
|
{
|
|
return DoAddResource( pResDictDatabase->
|
|
GetTransientResourceDict(),
|
|
pResName,
|
|
pT
|
|
);
|
|
}
|
|
|
|
RESOURCE * GetTransientResource( PNAME pResName )
|
|
{
|
|
return
|
|
pResDictDatabase->
|
|
GetTransientResourceDict()->Search(
|
|
pResName );
|
|
}
|
|
|
|
void ClearTransientResourceDict()
|
|
{
|
|
pResDictDatabase->
|
|
GetTransientResourceDict()->Clear();
|
|
}
|
|
//
|
|
// This method does the actual insertion into the resource dictionary.
|
|
// This method will also check for a resource of the same name already
|
|
// present and in that case will not add.
|
|
//
|
|
|
|
RESOURCE * DoAddResource( RESOURCE_DICT * pResDict,
|
|
PNAME pName,
|
|
node_skl * pType
|
|
);
|
|
|
|
//
|
|
// This method makes it slightly easier to add standard resources whose
|
|
// types are known. This is to save various portions of the back end
|
|
// not having to bother about the type part of the standard resources,
|
|
// and this knowledge makes the need to know about the type to one
|
|
// implementation module.
|
|
//
|
|
|
|
RESOURCE * AddStandardResource( STANDARD_RES_ID ResID );
|
|
|
|
|
|
//
|
|
// Generate the name for a temporary resource.
|
|
//
|
|
|
|
PNAME GenTempResourceName( char * pPrefix );
|
|
|
|
PNAME GenTRNameOffLastParam( char * pPrefix );
|
|
|
|
// Set the unmarshalling action recommendation stuff.
|
|
|
|
unsigned short SetAllocNeed( unsigned short A )
|
|
{
|
|
return UAction.SetAllocNeed( A );
|
|
}
|
|
unsigned short GetAllocNeed()
|
|
{
|
|
return UAction.GetAllocNeed();
|
|
}
|
|
unsigned short SetRefAction( unsigned short R )
|
|
{
|
|
return UAction.SetRefAction( R );
|
|
}
|
|
unsigned short GetRefAction()
|
|
{
|
|
return UAction.GetRefAction();
|
|
}
|
|
unsigned short SetUnMarAction( unsigned short U )
|
|
{
|
|
return UAction.SetUnMarAction( U );
|
|
}
|
|
unsigned short GetUnMarAction()
|
|
{
|
|
return UAction.GetUnMarAction();
|
|
}
|
|
unsigned short SetPresentedExprAction( unsigned short P )
|
|
{
|
|
return UAction.SetPresentedExprAction( P );
|
|
}
|
|
unsigned short GetPresentedExprAction()
|
|
{
|
|
return UAction.GetPresentedExprAction();
|
|
}
|
|
void SetUAction( unsigned short A,
|
|
unsigned short R,
|
|
unsigned short U,
|
|
unsigned short P
|
|
)
|
|
{
|
|
UAction.SetUAction( A, R, U, P );
|
|
}
|
|
|
|
U_ACTION SetUAction( U_ACTION UA )
|
|
{
|
|
return UAction.SetUAction( UA );
|
|
}
|
|
|
|
#ifdef MIDL_INTERNAL
|
|
void Dump( ANAPHASE );
|
|
#endif // MIDL_INTERNAL
|
|
};
|
|
|
|
#endif // __ANAINFO_HXX__
|