/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 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 } #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