windows-nt/Source/XPSP1/NT/com/rpc/midl/codegen/frmtstr.hxx
2020-09-26 16:20:57 +08:00

836 lines
27 KiB
C++

/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Copyright (c) 1993-2000 Microsoft Corporation
Module Name:
frmtstr.hxx
Abstract:
Notes:
History:
DKays Oct-1993 Created.
----------------------------------------------------------------------------*/
#ifndef __FRMTSTR_HXX__
#define __FRMTSTR_HXX__
extern "C"
{
#include <memory.h>
}
#include "ndrtypes.h"
#include "stream.hxx"
#include "cgcommon.hxx"
#include "dict.hxx"
// #define RKK_FRAG_OPT 1
class RepAsPadExprDict;
class RepAsSizeDict;
class CG_NDR;
#if defined(_AMD64_) || defined(_IA64_) // winnt
#define UNALIGNED __unaligned // winnt
#else // winnt
#define UNALIGNED // winnt
#endif // winnt
// Global defined in frmtstr.cxx
extern char * pNdrRoutineNames[];
// This has to be an even number.
#define DEFAULT_FORMAT_STRING_SIZE 1024
// Format string entry type
// If you add anything here, be sure that it works not only when outputting,
// but also when optimizing out fragments via FRMTREG::Compare.
//
typedef enum
{
FS_FORMAT_CHARACTER,
FS_POINTER_FORMAT_CHARACTER,
FS_SMALL,
FS_SHORT,
FS_LONG,
FS_SHORT_OFFSET,
FS_SHORT_TYPE_OFFSET,
FS_SHORT_STACK_OFFSET,
FS_SMALL_STACK_SIZE,
FS_PAD_MACRO,
FS_SIZE_MACRO,
FS_UNKNOWN_STACK_SIZE,
FS_OLD_PROC_FLAG_BYTE,
FS_Oi2_PROC_FLAG_BYTE,
FS_EXT_PROC_FLAG_BYTE,
FS_PARAM_FLAG_SHORT,
FS_MAGIC_UNION_SHORT,
FS_CORR_TYPE_BYTE,
FS_CORR_FLAG_SHORT,
FS_CONTEXT_HANDLE_FLAG_BYTE
} FORMAT_STRING_ENTRY_TYPE;
// (Stack) Offset Dictionary
//---------------------------
//
// It keeps track of stack or field offsets for parallel win32 platforms.
// The x86 stack offset is stored both directly in the format string itself (as
// a short for 32b implementation) and in the dictionary as a long.
// The true long value is used when optimizing.
// Other offsets are kept in the dictionary under the key which is the position
// of the x86 stack offset in the format string
//
// Note that field offsets may be negative, as for some objects like open structs,
// the correlation descriptor's offset is relative to the position of the
// array field in the struct.
// The format string offset (the position) on the other hand is always absolute,
// we use long only for convenience in dictionary comparisons.
//
typedef struct
{
long FormatStringOffset; // Note, this is not an x86 offset.
// This is the key for this dictionary.
long X86Offset;
} OffsetDictElem;
class OffsetDictionary : Dictionary
{
public :
OffsetDictionary() : Dictionary()
{
}
OffsetDictElem * LookupOffset( long Position )
{
OffsetDictElem DictElem;
OffsetDictElem * pDictElem;
Dict_Status DictStatus;
DictElem.FormatStringOffset = Position;
DictStatus = Dict_Find( &DictElem );
#if defined(RKK_FRAG_OPT)
if (DictStatus != SUCCESS )
{
printf("LookupOffset Offset=%d\n", Position );
}
#endif
MIDL_ASSERT( DictStatus == SUCCESS );
pDictElem = (OffsetDictElem *) Dict_Item();
return pDictElem;
}
virtual
SSIZE_T Compare( pUserType p1, pUserType p2 )
{
return ((OffsetDictElem *)p1)->FormatStringOffset -
((OffsetDictElem *)p2)->FormatStringOffset;
}
void Insert( long Position,
long X86Offset)
{
OffsetDictElem * pElem;
OffsetDictElem * pElemSave;
#if defined(RKK_FRAG_OPT)
if ( Position < 0 )
printf("Insert negative offset %d\n", Position );
#endif
pElemSave = pElem = new OffsetDictElem;
pElem->FormatStringOffset = Position;
pElem->X86Offset = X86Offset;
//
// Delete any entries which currently match, that is
// entries with the same FormatStringOffset key. This
// can happen because of format string compression.
//
while ( Dict_Delete( (pUserType *) &pElem ) == SUCCESS )
;
Dict_Insert( pElemSave );
}
};
// Type Offset Dictionary
//---------------------------
//
// It keeps track of type offsets, both absolute and relative.
// The reason we use a dictionary is to allow proper fragment optimization for
// for 32b implementation where a type offset has to be in short32 range while
// keeping it as a long permits the best optimization possible.
// Note that for 32b there is only one type offset regardless of the platform.
//
// The format string offset (the position) on the other hand is always absolute,
// we use long only for convenience in dictionary comparisons.
//
typedef struct
{
long Position; // FormatStringOffset is the key for this dictionary.
long TypeOffset;
} TypeOffsetDictElem;
class TypeOffsetDictionary : Dictionary
{
public :
TypeOffsetDictionary() : Dictionary()
{
}
TypeOffsetDictElem *LookupOffset( long Position )
{
TypeOffsetDictElem DictElem;
TypeOffsetDictElem * pDictElem;
Dict_Status DictStatus;
DictElem.Position = Position;
DictStatus = Dict_Find( &DictElem );
#if defined(RKK_FRAG_OPT)
if (DictStatus != SUCCESS )
{
printf("LookupOffset Position=%d\n", Position );
}
#endif
MIDL_ASSERT( DictStatus == SUCCESS );
pDictElem = (TypeOffsetDictElem *) Dict_Item();
return pDictElem;
}
virtual
SSIZE_T Compare( pUserType p1, pUserType p2 )
{
return ((TypeOffsetDictElem *)p1)->Position -
((TypeOffsetDictElem *)p2)->Position;
}
void Insert( long Position, long TypeOffset )
{
TypeOffsetDictElem * pElem;
TypeOffsetDictElem * pElemSave;
#if defined(RKK_FRAG_OPT)
if ( Position < 0 )
printf("Insert negative offset %d\n", Position );
#endif
pElemSave = pElem = new TypeOffsetDictElem;
pElem->Position = Position;
pElem->TypeOffset = TypeOffset;
//
// Delete any entries which currently match, that is
// entries with the same FormatStringOffset key. This
// can happen because of format string compression.
//
while ( Dict_Delete( (pUserType *) &pElem ) == SUCCESS )
;
Dict_Insert( pElemSave );
}
};
// (Unknown) StackSize Dictionary
//-------------------------------
//
// It keeps track of unknown stack sizes related to unknown represent_as() types.
// At the place where we have to generate the stack size in the output file,
// we use the type name to generate a size_of() expression.
//
// The format string offset (the position) is always absolute,
// we use longs only for convenience in dictionary comparisons.
typedef struct
{
long FormatStringOffset; // used as the key
char * pTypeName;
} StackSizeDictElem;
class StackSizeDictionary : Dictionary
{
public :
StackSizeDictionary() : Dictionary()
{
}
virtual
SSIZE_T Compare( pUserType p1, pUserType p2 )
{
return ((StackSizeDictElem *)p1)->FormatStringOffset -
((StackSizeDictElem *)p2)->FormatStringOffset;
}
char * LookupTypeName( long Offset )
{
StackSizeDictElem DictElem;
StackSizeDictElem * pDictElem;
Dict_Status DictStatus;
DictElem.FormatStringOffset = Offset;
DictStatus = Dict_Find( &DictElem );
MIDL_ASSERT( DictStatus == SUCCESS );
pDictElem = (StackSizeDictElem *) Dict_Item();
return pDictElem->pTypeName;
}
void Insert( long FormatStringOffset, char * pTypeName )
{
StackSizeDictElem * pElem;
StackSizeDictElem * pElemSave;
pElem = pElemSave = new StackSizeDictElem;
pElem->FormatStringOffset = FormatStringOffset;
pElem->pTypeName = pTypeName;
//
// Delete any entries which currently match, this
// can happen because of format string compression.
//
while ( Dict_Delete( (pUserType *) &pElem ) == SUCCESS )
;
Dict_Insert( pElemSave );
}
};
// CommentDictionary
//-------------------------------
//
// It keeps track of comments that can be attached to a given format string
// position.
// Note that for any offset position, we may have several comments.
//
// The format string offset (the position) is always absolute,
// we use longs only for convenience in dictionary comparisons.
typedef struct _CommentDictElem
{
struct _CommentDictElem * Next;
long FormatStringOffset; // used as the key
char * Comment;
} CommentDictElem;
class CommentDictionary : Dictionary
{
public :
CommentDictionary() : Dictionary()
{
}
virtual
SSIZE_T Compare( pUserType p1, pUserType p2 )
{
return ((CommentDictElem *)p1)->FormatStringOffset -
((CommentDictElem *)p2)->FormatStringOffset;
}
char * GetComments( long Offset );
void Insert( long FormatStringOffset, char * Comment );
};
//---------------------------------------
// FormatReg Dictionary is used to keep track of format string fragments
// that can be collapsed (optimized out).
class FRMTREG_DICT;
//---------------------------------------
// Format string
//---------------------------------------
class FORMAT_STRING
{
unsigned char * pBuffer; // Format string buffer.
unsigned char * pBufferType; // Entry type for each position.
// - indicates the meaning
unsigned long BufferSize; // Total current allocated buffer size.
unsigned long CurrentOffset; // Current offset in the format string buffer.
unsigned long LastOffset; // The last valid format string buffer index.
OffsetDictionary OffsetDict; // Stack offsets at a position
TypeOffsetDictionary TypeOffsetDict; // Type offsets at a position
StackSizeDictionary UnknownStackSizeDict; // Unknown type at a position
CommentDictionary CommentDict; // Comments at a position
FRMTREG_DICT * pReuseDict; // Fragment optimization dictionary.
//
// This class is a friend as its Compare method accesses pBuffer, pBufferType
// as well as OffsetDictionary in order to optimize fragments.
//
friend class FRMTREG_DICT;
//
// Increment CurrentOffset and update LastOffset if needed.
//
void
IncrementOffset( long increment )
{
CurrentOffset += increment;
if ( CurrentOffset > LastOffset )
LastOffset = CurrentOffset;
}
public:
FORMAT_STRING();
~FORMAT_STRING()
{
delete pBuffer;
delete pBufferType;
}
//
// Align the buffer correctly. If the current offset is odd then
// insert a pad format character.
//
void
Align()
{
if ( CurrentOffset % 2 )
PushFormatChar( FC_PAD );
}
void AddComment( long FormatOffset, char * Comment )
{
CommentDict.Insert( FormatOffset, Comment );
}
//
// Add a format char at the current offset.
//
void
PushFormatChar( FORMAT_CHARACTER fc )
{
CheckSize();
pBufferType[CurrentOffset] = FS_FORMAT_CHARACTER;
pBuffer[CurrentOffset] = (unsigned char)fc;
IncrementOffset(1);
}
//
// Add a pointer format char at the current offset.
//
void
PushPointerFormatChar( unsigned char fc )
{
CheckSize();
pBufferType[CurrentOffset] = FS_POINTER_FORMAT_CHARACTER;
pBuffer[CurrentOffset] = fc;
IncrementOffset(1);
}
//
// Push a byte at the current offset.
//
void
PushByte( long b )
{
CheckSize();
pBufferType[CurrentOffset] = FS_SMALL;
pBuffer[CurrentOffset] = (unsigned char) b;
IncrementOffset(1);
}
//
// Push a byte with old proc attributes at the current offset
//
void PushOldProcFlagsByte( long b )
{
CheckSize();
pBufferType[CurrentOffset] = FS_OLD_PROC_FLAG_BYTE;
pBuffer[CurrentOffset] = (unsigned char) b;
IncrementOffset(1);
}
//
// Push a byte with old proc attributes at the current offset
//
void PushOi2ProcFlagsByte( long b )
{
CheckSize();
pBufferType[CurrentOffset] = FS_Oi2_PROC_FLAG_BYTE;
pBuffer[CurrentOffset] = (unsigned char) b;
IncrementOffset(1);
}
//
// Push a byte with NT5 extended proc attributes at the current offset
//
void PushExtProcFlagsByte( long b )
{
CheckSize();
pBufferType[CurrentOffset] = FS_EXT_PROC_FLAG_BYTE;
pBuffer[CurrentOffset] = (unsigned char) b;
IncrementOffset(1);
}
//
// Push a context handle flags byte
//
void PushContextHandleFlagsByte( long b )
{
CheckSize();
pBufferType[CurrentOffset] = FS_CONTEXT_HANDLE_FLAG_BYTE;
pBuffer[CurrentOffset] = (unsigned char) b;
IncrementOffset(1);
}
//
// Push a byte with a correlation type (first byte of a correlation desc).
//
void PushCorrelationTypeByte( long b )
{
CheckSize();
pBufferType[CurrentOffset] = FS_CORR_TYPE_BYTE;
pBuffer[CurrentOffset] = (unsigned char) b;
IncrementOffset(1);
}
//
// Push a short at the current offset.
//
void
PushShort( short s )
{
CheckSize();
pBufferType[CurrentOffset] = FS_SHORT;
pBufferType[CurrentOffset+1] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + CurrentOffset)) = s;
IncrementOffset(2);
}
//
// Push a short with parameter attributes at the current offset.
//
void PushParamFlagsShort( short s )
{
CheckSize();
pBufferType[CurrentOffset] = FS_PARAM_FLAG_SHORT;
pBufferType[CurrentOffset+1] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + CurrentOffset)) = s;
IncrementOffset(2);
}
//
// Push a short with the new, robust related, correlation flags.
//
void PushCorrelationFlagsShort( short s )
{
CheckSize();
pBufferType[CurrentOffset] = FS_CORR_FLAG_SHORT;
pBufferType[CurrentOffset+1] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + CurrentOffset)) = s;
IncrementOffset(2);
}
//
// Push a short at the current offset.
//
void
PushShort( long s )
{
CheckSize();
pBufferType[CurrentOffset] = FS_SHORT;
pBufferType[CurrentOffset+1] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + CurrentOffset)) = (short) s;
IncrementOffset(2);
}
//
// Push a long at the current offset.
//
void
PushLong( long l )
{
CheckSize();
pBufferType[CurrentOffset] = FS_LONG;
pBufferType[CurrentOffset+1] = FS_SMALL;
pBufferType[CurrentOffset+2] = FS_SMALL;
pBufferType[CurrentOffset+3] = FS_SMALL;
*((long UNALIGNED *)(pBuffer + CurrentOffset)) = l;
IncrementOffset(4);
}
//
// Push a pad macro marker at the current offset.
//
void
PushByteWithPadMacro()
{
CheckSize();
pBufferType[ CurrentOffset ] = FS_PAD_MACRO;
pBuffer[ CurrentOffset ] = 0;
IncrementOffset(1);
}
//
// Push a size macro marker at the current offset.
//
void
PushShortWithSizeMacro()
{
CheckSize();
pBufferType[ CurrentOffset ] = FS_SIZE_MACRO;
pBufferType[CurrentOffset+1] = FS_SMALL;
pBuffer[ CurrentOffset ] = 0;
IncrementOffset(2);
}
//
// Push a format char at the specified offset.
//
void
PushFormatChar( FORMAT_CHARACTER fc, long offset )
{
pBufferType[offset] = FS_FORMAT_CHARACTER;
pBuffer[offset] = (unsigned char)fc;
}
//
// Push a short at the specified offset.
// Used only in unions to emit magic byte followed by simple type or
// to emit -1 as a marker for no default arm.
//
void PushMagicUnionShort( short s, long offset )
{
pBufferType[ offset ] = FS_MAGIC_UNION_SHORT;
pBufferType[ offset+1] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + offset)) = s;
}
//
// Push a short at the specified offset.
// Used primarily to push offsets internal to a type descriptor, for example
// an offset to pointer layout. These are treated as plain shorts as they
// never change and should not be mistaken for a relative type offset.
//
void PushShort( long s, long offset )
{
pBufferType[ offset ] = FS_SHORT;
pBufferType[ offset+1] = FS_SMALL;
*((short UNALIGNED *)(pBuffer + offset)) = (short) s;
}
//
// Push a long at the specified offset. Used only for union case values.
//
void PushLong( long l, long offset )
{
pBufferType[ offset ] = FS_LONG;
pBufferType[ offset+1] = FS_SMALL;
pBufferType[ offset+2] = FS_SMALL;
pBufferType[ offset+3] = FS_SMALL;
*((long UNALIGNED *)(pBuffer + offset)) = l;
}
//
// Push a short offset at the current offset.
// This is the relative type offset within the type string.
// For 32b code, this needs to be a value within a signed short.
//
void PushShortOffset( long s );
void PushShortOffset( long s, long offset );
//
// Push a short type-fmt-string offset at the current offset.
// This is used as the offset from a parameter into type format string.
// For 32b code, this needs to be a value within an unsigned short.
//
void PushShortTypeOffset( long s );
//
// Push a stack offset.
// Needs to be relative for non-top level objects.
//
void PushShortStackOffset( long X86Offset );
//
// Push a stack size or an unsigned stack offset. This is absolute value.
// Used for proc stack size and parameter offsets.
//
void PushUShortStackOffsetOrSize( long X86Offset );
//
// Push a parameter stack size expressed as the number of ints required
// for the parameter on the stack.
//
// The old -Oi parameter descriptor is the only place where this is used.
//
void
PushSmallStackSize( char StackSize )
{
CheckSize();
pBufferType[CurrentOffset] = FS_SMALL_STACK_SIZE;
pBuffer[CurrentOffset] = StackSize;
IncrementOffset(1);
}
//
// Push an unknown rep as stack size. We need the type name so we can
// spit out a 'sizeof' in the format string.
//
// The old -Oi parameter descriptor is the only place where this is used.
//
void
PushUnknownStackSize( char * pTypeName )
{
CheckSize();
pBufferType[CurrentOffset] = FS_UNKNOWN_STACK_SIZE;
UnknownStackSizeDict.Insert( (long) CurrentOffset, pTypeName );
IncrementOffset(1);
}
//
// Get a FORMAT_CHARACTER at a specific offset in the format string.
//
FORMAT_CHARACTER
GetFormatChar( long offset )
{
return (FORMAT_CHARACTER) pBuffer[offset];
}
//
// Get a short at a specific offset in the format string.
//
short
GetFormatShort( long offset )
{
return *(short UNALIGNED *)(pBuffer + offset);
}
//
// Get the current format string offset.
//
long
GetCurrentOffset()
{
return (long)CurrentOffset;
}
//
// Set the current format string offset. This discards
// everything after (and including) the new offset from the format string
//
void SetCurrentOffset( long NewOffset )
{
LastOffset = (unsigned long)NewOffset;
CurrentOffset = (unsigned long)NewOffset;
}
//
// Output the format string structure to the given stream.
//
void Output( ISTREAM * pStream,
char * pTypeName,
char * pName,
RepAsPadExprDict * pPadDict,
RepAsSizeDict * pSizeDict );
void OutputExprEvalFormatString(ISTREAM *pStream);
//
// Get the fragment re-use dictionary
//
FRMTREG_DICT * GetReuseDict()
{
return pReuseDict;
}
//
// Optimize a fragment away
//
long OptimizeFragment( CG_NDR * pNode );
//
// Register a fragment, but don't delete it
//
unsigned short RegisterFragment( CG_NDR * pNode );
private :
//
// Check if a bigger buffer needs to be allocated.
//
void CheckSize();
};
#endif