/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 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__