/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1989 Microsoft Corporation Module Name: stcls.cxx Abstract: Implementation of offline methods for the structure code generation classes. Notes: History: Oct-1993 DKays Created. ----------------------------------------------------------------------------*/ #include "becls.hxx" #pragma hdrstop CG_ARRAY * CG_CONFORMANT_STRUCT::GetConformantArray() /*++ Routine Description : Gets the conformant (varying/string) class pointer for a conformant structure. Arguments : None. --*/ { CG_NDR * pConf; if ( ! pConfFld ) return 0; pConf = (CG_NDR *) pConfFld->GetChild(); for (;;) { if ( pConf->GetCGID() == ID_CG_CONF_ARRAY || pConf->GetCGID() == ID_CG_CONF_VAR_ARRAY || pConf->GetCGID() == ID_CG_CONF_STRING_ARRAY ) break; if ( pConf->IsXmitRepOrUserMarshal() ) { pConf = (CG_NDR *)pConf->GetChild(); continue; } // else pConf = (CG_NDR *) ((CG_CONFORMANT_STRUCT *)pConf)->GetConformantField(); pConf = (CG_NDR *) pConf->GetChild(); } return (CG_ARRAY *) pConf; } CG_FIELD * CG_STRUCT::GetFinalField() { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pNdr; GetMembers( Iterator ); // // Get the last field. // while ( ITERATOR_GETNEXT( Iterator, pField ) ) ; pNdr = (CG_NDR *) pField->GetChild(); if ( pNdr->IsStruct() ) pField = ((CG_STRUCT *)pNdr)->GetFinalField(); return pField; } CG_FIELD * CG_STRUCT::GetArrayField( CG_ARRAY * pArray ) { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pNdr; GetMembers( Iterator ); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pNdr = (CG_NDR *) pField->GetChild(); if ( pNdr == pArray ) return pField; // // Search inside of other structs only. // if ( pNdr->IsStruct() ) { if ( (pField = ((CG_STRUCT *)pNdr)->GetArrayField(pArray)) != 0 ) return pField; } } // Didn't find it. return 0; } BOOL CG_STRUCT::IsHardStruct() { // Always return FALSE until after PPC Update. return FALSE; } BOOL CG_STRUCT::IsHardStructOld() { CG_ITERATOR Iterator; CG_FIELD * pField; CG_FIELD * pPrevField; // // Cannot have a conformant array of any kind. // if ( (GetCGID() == ID_CG_CONF_STRUCT) || (GetCGID() == ID_CG_CONF_VAR_STRUCT) ) return FALSE; // // Cannot have pointers. // if ( HasPointer() ) return FALSE; // // Can't have more than one enum16. // if ( GetNumberOfEnum16s() > 1 ) return FALSE; // // Can't have padding in the middle of the struct that differs in // memory and on the wire. // GetMembers( Iterator ); pPrevField = 0; // // Get the last field. // while ( ITERATOR_GETNEXT( Iterator, pField ) ) { if ( pField->GetSibling() ) pPrevField = pField; } // // Check if the last field in the struct has a different memory and wire // offset. However, if there is a single union as the last field then // we have to check the second to last fields's mem and wire offsets // instead since a union's field's wire offsets are not accurate. // if ( pField->GetChild()->IsUnion() && pPrevField ) pField = pPrevField; // This is complex. if ( pField->GetMemOffset() != pField->GetWireOffset() ) return FALSE; // // Can have at most one union as the last field only. // switch ( GetNumberOfUnions() ) { case 0 : break; case 1 : // // The last field must be the union. // if ( ! GetFinalField()->GetChild()->IsUnion() ) return FALSE; else return TRUE; break; default : return FALSE; } // // Now check again if we have just one enum16. // if ( GetNumberOfEnum16s() == 1 ) return TRUE; // // Check for end padding, which is ok for a hard struct. // if ( GetMemorySize() > GetWireSize() ) return TRUE; // // It must be a nice struct. // return FALSE; } BOOL CG_STRUCT::HasAFixedBufferSize() { CG_ITERATOR Iterator; CG_FIELD * pField; GetMembers( Iterator ); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { if ( !pField->HasAFixedBufferSize() ) return FALSE; } return TRUE; } BOOL CG_STRUCT::IsComplexStruct() { CG_ITERATOR Iterator; CG_FIELD * pField; CG_FIELD * pPrevField; CG_NDR * pNdr; BOOL IsConformant; IsConformant = (GetCGID() == ID_CG_CONF_STRUCT) || (GetCGID() == ID_CG_CONF_VAR_STRUCT); switch ( GetNumberOfEnum16s() ) { case 0 : break; case 1 : if ( HasPointer() || IsConformant ) return TRUE; break; default : return TRUE; } switch ( GetNumberOfUnions() ) { case 0 : break; case 1 : if ( ! GetFinalField()->GetChild()->IsUnion() || HasPointer() || IsConformant ) return TRUE; break; default : return TRUE; } if ( (GetMemorySize() > GetWireSize()) && (HasPointer() || IsConformant) ) return TRUE; GetMembers( Iterator ); pPrevField = 0; // // Check if there are any embedded structs or arrays which are // complex. // while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pNdr = (CG_NDR *) pField->GetChild(); if ( pNdr->IsArray() && ((CG_ARRAY *)pNdr)->IsComplex() ) return TRUE; if ( pNdr->IsStruct() && ((CG_STRUCT *)pNdr)->IsComplexStruct() ) return TRUE; if ( pField->GetSibling() ) pPrevField = pField; } // // If the last field in the structure has a memory offset not equal // to the buffer offset then the struct's memory alignment is different // then the natural buffer alignment and we must make it complex. // // However, if there is a single union as the last field then we have to // check the second to last fields's mem and wire offsets instead since // a union's field's wire offsets are not accurate. // // Otherwise, if that is not true at this point then the structure is // not complex. // if ( pField->GetChild()->IsUnion() && pPrevField ) pField = pPrevField; return (pField->GetMemOffset() != pField->GetWireOffset()) || IsHardStructOld(); } long CG_STRUCT::GetNumberOfPointers() { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pMember; long Count; Count = 0; GetMembers(Iterator); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pMember = (CG_NDR *) pField->GetChild(); if ( pMember->IsPointer() && (pMember->GetCGID() != ID_CG_INTERFACE_PTR) ) Count++; if ( pMember->IsStruct() ) Count += ((CG_STRUCT *)pMember)->GetNumberOfPointers(); } return Count; } long CG_STRUCT::GetNumberOfEnum16s() { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pNdr; long Count; long Weight; Count = 0; GetMembers(Iterator); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pNdr = (CG_NDR *) pField->GetChild(); // // If an array contains a enum16 we count it as 100 enum16s, since // this routine is only interested in small enum16 counts. // if ( pNdr->IsArray() ) { pNdr = (CG_NDR *) pNdr->GetChild(); while ( pNdr->IsArray() ) pNdr = (CG_NDR *) pNdr->GetChild(); Weight = 100; } else Weight = 1; if ( pNdr->IsSimpleType() && (((CG_BASETYPE *)pNdr)->GetFormatChar() == FC_ENUM16) ) Count += Weight; if ( pNdr->IsStruct() ) Count += Weight * ((CG_STRUCT *)pNdr)->GetNumberOfEnum16s(); } return Count; } long CG_STRUCT::GetNumberOfUnions() { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pNdr; long Count; long Weight; Count = 0; GetMembers(Iterator); while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pNdr = (CG_NDR *) pField->GetChild(); // // If an array contains a union we count it as 100 unions, since // this routine is only interested in small union counts. // if ( pNdr->IsArray() ) { pNdr = (CG_NDR *) pNdr->GetChild(); while ( pNdr->IsArray() ) pNdr = (CG_NDR *) pNdr->GetChild(); Weight = 100; } else Weight = 1; if ( (pNdr->GetCGID() == ID_CG_UNION) || (pNdr->GetCGID() == ID_CG_ENCAP_STRUCT) ) Count += Weight; if ( pNdr->IsStruct() ) Count += Weight * ((CG_STRUCT *)pNdr)->GetNumberOfUnions(); } return Count; } long CG_STRUCT::GetEnum16Offset() { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pNdr; assert( GetNumberOfEnum16s() == 1 ); GetMembers( Iterator ); // // Search for the enum. // while ( ITERATOR_GETNEXT( Iterator, pField ) ) { pNdr = (CG_NDR *) pField->GetChild(); if ( pNdr->IsSimpleType() && (((CG_BASETYPE *)pNdr)->GetFormatChar() == FC_ENUM16) ) return pField->GetMemOffset(); if ( pNdr->IsStruct() && (((CG_STRUCT *)pNdr)->GetNumberOfEnum16s() == 1) ) return pField->GetMemOffset() + ((CG_STRUCT *)pNdr)->GetEnum16Offset(); } // Never get here. return 0; } void CloneForUnrolling( CG_NDR * pParent, CG_NDR * pNdr ) /* This routine will clone pNdr and overwrite the original child at the parent if needed. It is assumed the parent has been cloned, too. */ { CG_POINTER * pNewPointer; pNewPointer = 0; if ( pNdr->IsPointer() ) { switch ( pNdr->GetCGID() ) { case ID_CG_PTR : pNewPointer = new CG_POINTER( (CG_POINTER *) pNdr ); break; case ID_CG_BC_PTR : pNewPointer = new CG_BYTE_COUNT_POINTER( (CG_BYTE_COUNT_POINTER *) pNdr ); break; case ID_CG_STRING_PTR : case ID_CG_STRUCT_STRING_PTR : pNewPointer = new CG_STRING_POINTER( (CG_STRING_POINTER *) pNdr ); break; case ID_CG_SIZE_PTR : pNewPointer = new CG_SIZE_POINTER( (CG_SIZE_POINTER *) pNdr ); break; case ID_CG_LENGTH_PTR : pNewPointer = new CG_LENGTH_POINTER( (CG_LENGTH_POINTER *) pNdr ); break; case ID_CG_SIZE_LENGTH_PTR : pNewPointer = new CG_SIZE_LENGTH_POINTER( (CG_SIZE_LENGTH_POINTER *) pNdr ); break; case ID_CG_SIZE_STRING_PTR : pNewPointer = new CG_SIZE_STRING_POINTER( (CG_SIZE_STRING_POINTER *) pNdr ); break; case ID_CG_INTERFACE_PTR : pNewPointer = new CG_INTERFACE_POINTER( (CG_INTERFACE_POINTER *) pNdr ); break; default : break; } if ( pNewPointer ) { // // We have to re-set the new pointer's format string offset and // pointee format string offset to -1 so that we get a new // description!!! // if ( pNewPointer ) pNewPointer->SetFormatStringOffset( -1 ); pNewPointer->SetPointeeFormatStringOffset( -1 ); pParent->SetChild( pNewPointer ); if ( pNdr->GetChild() ) CloneForUnrolling( pNewPointer, (CG_NDR*) pNdr->GetChild() ); } } } void CG_STRUCT::Unroll() { ITERATOR Iterator; CG_FIELD * pPrevField; CG_FIELD * pField; CG_NDR * pNdr; CG_STRUCT * pStruct; GetMembers( Iterator ); pPrevField = 0; while ( ITERATOR_GETNEXT(Iterator,pField) ) { pNdr = (CG_NDR *) pField->GetChild(); if ( pNdr->IsStruct() && ((CG_STRUCT *)pNdr)->HasSizedPointer() ) pStruct = (CG_STRUCT *) pNdr; else { pPrevField = pField; continue; } // // First force the embeded struct to unroll if needed. // pStruct->Unroll(); ITERATOR IteratorEmbeded; CG_FIELD * pFieldNew; CG_FIELD * pFieldEmbeded; CG_FIELD * pFieldList; long MemOffsetStart; long WireOffsetStart; pStruct->GetMembers( IteratorEmbeded ); MemOffsetStart = pField->GetMemOffset(); WireOffsetStart = pField->GetWireOffset(); // Get previous field node. pFieldList = pPrevField; // Remove current struct field node from the list. if ( pFieldList ) pFieldList->SetSibling( pField->GetSibling() ); else this->SetChild( pField->GetSibling() ); // To be safe. pField->SetSibling( 0 ); while ( ITERATOR_GETNEXT(IteratorEmbeded,pFieldEmbeded) ) { pFieldNew = pFieldEmbeded->Clone(); pNdr = (CG_NDR *) pFieldEmbeded->GetChild(); CloneForUnrolling( pFieldNew, pNdr ); // // Set the new field's memory and wire offset. // pFieldNew->SetMemOffset( pFieldEmbeded->GetMemOffset() + MemOffsetStart ); pFieldNew->SetWireOffset( pFieldEmbeded->GetWireOffset() + WireOffsetStart ); // // Now add the imbeded struct's field name to the PrintPrefix of // the new unrolled field. We ask the imbeded struct's field // for it's name. // pFieldNew->AddPrintPrefix( pField->GetType()->GetSymName() ); if ( pFieldList ) { pFieldNew->SetSibling( pFieldList->GetSibling() ); pFieldList->SetSibling( pFieldNew ); } else { pFieldNew->SetSibling( this->GetChild() ); this->SetChild( pFieldNew ); } pFieldList = pFieldNew; } // // Set pPrevField equal to the last field node that we entered into // the list. The outermost Iterator only knows about fields that // started in the struct's field list, so the last field node we // added will have a sibling equal to the next field node we'll get // from the outer iterator. // pPrevField = pFieldNew; } } BOOL CG_STRUCT::HasSizedPointer() { CG_ITERATOR Iterator; CG_FIELD * pField; CG_NDR * pNdr; GetMembers( Iterator ); while ( ITERATOR_GETNEXT(Iterator,pField) ) { pNdr = (CG_NDR *) pField->GetChild(); if ( pNdr->IsStruct() && ((CG_STRUCT *)pNdr)->HasSizedPointer() ) return TRUE; if ( (pNdr->GetCGID() == ID_CG_SIZE_PTR) || (pNdr->GetCGID() == ID_CG_SIZE_LENGTH_PTR) || (pNdr->GetCGID() == ID_CG_SIZE_STRING_PTR) ) return TRUE; } return FALSE; } BOOL CG_ENCAPSULATED_STRUCT::ShouldFreeOffline() { CG_UNION * pUnion; pUnion = (CG_UNION *) GetChild()->GetSibling()->GetChild(); return pUnion->HasPointer(); }