INT32 QCALLTYPE COMDynamicWrite::DefineMethod(QCall::ModuleHandle pModule, INT32 tkParent, LPCWSTR wszName, LPCBYTE pSignature, INT32 sigLength, INT32 attributes) { QCALL_CONTRACT; mdMethodDef memberE = mdTokenNil; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Define the Method IfFailThrow( pRCW->GetEmitter()->DefineMethod(tkParent, //ParentTypeDef wszName, //Name of Member attributes, //Member Attributes (public, etc); (PCCOR_SIGNATURE)pSignature, //Blob value of a COM+ signature sigLength, //Size of the signature blob 0, //Code RVA miIL | miManaged, //Implementation Flags is default to managed IL &memberE) ); //[OUT]methodToken END_QCALL; return (INT32) memberE; }
/*============================DefineProperty============================ **Action: **Returns: **Arguments: **Exceptions: ==============================================================================*/ INT32 QCALLTYPE COMDynamicWrite::DefineProperty(QCall::ModuleHandle pModule, INT32 tkParent, LPCWSTR wszName, INT32 attr, LPCBYTE pSignature, INT32 sigLength) { QCALL_CONTRACT; mdProperty pr = mdTokenNil; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Define the Property IfFailThrow(pRCW->GetEmitter()->DefineProperty( tkParent, // ParentTypeDef wszName, // Name of Member attr, // property Attributes (prDefaultProperty, etc); (PCCOR_SIGNATURE)pSignature, // Blob value of a COM+ signature sigLength, // Size of the signature blob ELEMENT_TYPE_VOID, // don't specify the default value 0, // no default value (ULONG) -1, // optional length mdMethodDefNil, // no setter mdMethodDefNil, // no getter NULL, // no other methods &pr)); END_QCALL; return (INT32)pr; }
/*============================SetParamInfo============================ **Action: Helper to set parameter information **Returns: **Arguments: **Exceptions: ==============================================================================*/ INT32 QCALLTYPE COMDynamicWrite::SetParamInfo(QCall::ModuleHandle pModule, UINT32 tkMethod, UINT32 iSequence, UINT32 iAttributes, LPCWSTR wszParamName) { QCALL_CONTRACT; mdParamDef retVal = 0; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Set the methodimpl flags IfFailThrow(pRCW->GetEmitter()->DefineParam( tkMethod, iSequence, // sequence of the parameter wszParamName, iAttributes, // change the impl flags ELEMENT_TYPE_VOID, 0, (ULONG) -1, &retVal)); END_QCALL; return (INT32)retVal; }
/*=============================GetArrayMethodToken============================== **Action: **Returns: **Arguments: REFLECTMODULEBASEREF refThis ** U1ARRAYREF sig ** STRINGREF methodName ** int tkTypeSpec **Exceptions: ==============================================================================*/ INT32 QCALLTYPE COMModule::GetArrayMethodToken(QCall::ModuleHandle pModule, INT32 tkTypeSpec, LPCWSTR wszMethodName, LPCBYTE pSignature, INT32 sigLength) { QCALL_CONTRACT; mdMemberRef memberRefE = mdTokenNil; BEGIN_QCALL; if (!wszMethodName) COMPlusThrow(kArgumentNullException, W("ArgumentNull_String")); if (!tkTypeSpec) COMPlusThrow(kArgumentNullException, W("ArgumentNull_Type")); RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); HRESULT hr = pRCW->GetEmitter()->DefineMemberRef(tkTypeSpec, wszMethodName, (PCCOR_SIGNATURE)pSignature, sigLength, &memberRefE); if (FAILED(hr)) { _ASSERTE(!"Failed on DefineMemberRef"); COMPlusThrowHR(hr); } END_QCALL; return (INT32)memberRefE; }
INT32 QCALLTYPE COMDynamicWrite::DefineType(QCall::ModuleHandle pModule, LPCWSTR wszFullName, INT32 tkParent, INT32 attributes, INT32 tkEnclosingType, INT32 * pInterfaceTokens) { QCALL_CONTRACT; mdTypeDef classE = mdTokenNil; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); HRESULT hr; if (RidFromToken(tkEnclosingType)) { // defining nested type hr = pRCW->GetEmitter()->DefineNestedType(wszFullName, attributes, tkParent == 0 ? mdTypeRefNil : tkParent, (mdToken *)pInterfaceTokens, tkEnclosingType, &classE); } else { // top level type hr = pRCW->GetEmitter()->DefineTypeDef(wszFullName, attributes, tkParent == 0 ? mdTypeRefNil : tkParent, (mdToken *)pInterfaceTokens, &classE); } if (hr == META_S_DUPLICATE) { COMPlusThrow(kArgumentException, W("Argument_DuplicateTypeName")); } if (FAILED(hr)) { _ASSERTE(hr == E_OUTOFMEMORY || !"DefineTypeDef Failed"); COMPlusThrowHR(hr); } AllocMemTracker amTracker; pModule->GetClassLoader()->AddAvailableClassDontHaveLock(pModule, classE, &amTracker); amTracker.SuppressRelease(); END_QCALL; return (INT32)classE; }
// This function will add another interface impl void QCALLTYPE COMDynamicWrite::AddInterfaceImpl(QCall::ModuleHandle pModule, INT32 tdType, INT32 tkInterface) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); IfFailThrow( pRCW->GetEmitHelper()->AddInterfaceImpl(tdType, tkInterface) ); END_QCALL; }
// This function will reset the parent class in metadata void QCALLTYPE COMDynamicWrite::SetParentType(QCall::ModuleHandle pModule, INT32 tdType, INT32 tkParent) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); IfFailThrow( pRCW->GetEmitHelper()->SetTypeParent(tdType, tkParent) ); END_QCALL; }
/*============================SetConstantValue============================ **Action: Helper to set constant value to field or parameter **Returns: **Arguments: **Exceptions: ==============================================================================*/ void QCALLTYPE COMDynamicWrite::SetConstantValue(QCall::ModuleHandle pModule, UINT32 tk, DWORD valueCorType, LPVOID pValue) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); HRESULT hr; if (TypeFromToken(tk) == mdtFieldDef) { hr = pRCW->GetEmitter()->SetFieldProps( tk, // [IN] The FieldDef. ULONG_MAX, // [IN] Field attributes. valueCorType, // [IN] Flag for the value type, selected ELEMENT_TYPE_* pValue, // [IN] Constant value. (ULONG) -1); // [IN] Optional length. } else if (TypeFromToken(tk) == mdtProperty) { hr = pRCW->GetEmitter()->SetPropertyProps( tk, // [IN] The PropertyDef. ULONG_MAX, // [IN] Property attributes. valueCorType, // [IN] Flag for the value type, selected ELEMENT_TYPE_* pValue, // [IN] Constant value. (ULONG) -1, // [IN] Optional length. mdMethodDefNil, // [IN] Getter method. mdMethodDefNil, // [IN] Setter method. NULL); // [IN] Other methods. } else { hr = pRCW->GetEmitter()->SetParamProps( tk, // [IN] The ParamDef. NULL, ULONG_MAX, // [IN] Parameter attributes. valueCorType, // [IN] Flag for the value type, selected ELEMENT_TYPE_* pValue, // [IN] Constant value. (ULONG) -1); // [IN] Optional length. } if (FAILED(hr)) { _ASSERTE(!"Set default value is failing"); COMPlusThrow(kArgumentException, W("Argument_BadConstantValue")); } END_QCALL; }
FCIMPLEND //************************************************** // LoadInMemoryTypeByName // Explicitly loading an in memory type // <TODO>@todo: this function is not dealing with nested type correctly yet. // We will need to parse the full name by finding "+" for enclosing type, etc.</TODO> //************************************************** void QCALLTYPE COMModule::LoadInMemoryTypeByName(QCall::ModuleHandle pModule, LPCWSTR wszFullName) { QCALL_CONTRACT; TypeHandle typeHnd; BEGIN_QCALL; if (!pModule->IsReflection()) COMPlusThrow(kNotSupportedException, W("NotSupported_NonReflectedType")); RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // it is ok to use public import API because this is a dynamic module anyway. We are also receiving Unicode full name as // parameter. IMetaDataImport * pImport = pRCW->GetRWImporter(); if (wszFullName == NULL) IfFailThrow( E_FAIL ); // look up the handle mdTypeDef td; HRESULT hr = pImport->FindTypeDefByName(wszFullName, mdTokenNil, &td); if (FAILED(hr)) { if (hr != CLDB_E_RECORD_NOTFOUND) COMPlusThrowHR(hr); // Get the UTF8 version of strFullName MAKE_UTF8PTR_FROMWIDE(szFullName, wszFullName); pModule->GetAssembly()->ThrowTypeLoadException(szFullName, IDS_CLASSLOAD_GENERAL); } TypeKey typeKey(pModule, td); typeHnd = pModule->GetClassLoader()->LoadTypeHandleForTypeKey(&typeKey, TypeHandle()); END_QCALL; return; }
/*============================SetMethodImpl============================ ** To set a Method's Implementation flags ==============================================================================*/ void QCALLTYPE COMDynamicWrite::SetMethodImpl(QCall::ModuleHandle pModule, INT32 tkMethod, INT32 attr) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Set the methodimpl flags IfFailThrow(pRCW->GetEmitter()->SetMethodImplFlags( tkMethod, attr)); // change the impl flags END_QCALL; }
/*============================SetFieldLayoutOffset============================ **Action: set fieldlayout of a field **Returns: **Arguments: **Exceptions: ==============================================================================*/ void QCALLTYPE COMDynamicWrite::SetFieldLayoutOffset(QCall::ModuleHandle pModule, INT32 tkField, INT32 iOffset) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Set the field layout IfFailThrow(pRCW->GetEmitHelper()->SetFieldLayoutHelper( tkField, // field iOffset)); // layout offset END_QCALL; }
/*============================DefineMethodImpl============================ ** Define a MethodImpl record ==============================================================================*/ void QCALLTYPE COMDynamicWrite::DefineMethodImpl(QCall::ModuleHandle pModule, UINT32 tkType, UINT32 tkBody, UINT32 tkDecl) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Set the methodimpl flags IfFailThrow(pRCW->GetEmitter()->DefineMethodImpl( tkType, tkBody, tkDecl)); // change the impl flags END_QCALL; }
/*============================DefineMethodSemantics============================ **Action: **Returns: **Arguments: **Exceptions: ==============================================================================*/ void QCALLTYPE COMDynamicWrite::DefineMethodSemantics(QCall::ModuleHandle pModule, INT32 tkAssociation, INT32 attr, INT32 tkMethod) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Define the MethodSemantics IfFailThrow(pRCW->GetEmitHelper()->DefineMethodSemanticsHelper( tkAssociation, attr, tkMethod)); END_QCALL; }
/*============================SetClassLayout============================ **Action: **Returns: **Arguments: **Exceptions: ==============================================================================*/ void QCALLTYPE COMDynamicWrite::SetClassLayout(QCall::ModuleHandle pModule, INT32 tk, INT32 iPackSize, UINT32 iTotalSize) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter* pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Define the packing size and total size of a class IfFailThrow(pRCW->GetEmitter()->SetClassLayout( tk, // Typedef iPackSize, // packing size NULL, // no field layout iTotalSize)); // total size for the type END_QCALL; }
// This function will create a method within the class INT32 QCALLTYPE COMDynamicWrite::DefineMethodSpec(QCall::ModuleHandle pModule, INT32 tkParent, LPCBYTE pSignature, INT32 sigLength) { QCALL_CONTRACT; mdMethodDef memberE = mdTokenNil; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Define the Method IfFailThrow( pRCW->GetEmitter()->DefineMethodSpec(tkParent, //ParentTypeDef (PCCOR_SIGNATURE)pSignature, //Blob value of a COM+ signature sigLength, //Size of the signature blob &memberE) ); //[OUT]methodToken END_QCALL; return (INT32) memberE; }
/*============================SetPInvokeData============================ **Action: **Returns: **Arguments: **Exceptions: ==============================================================================*/ void QCALLTYPE COMDynamicWrite::SetPInvokeData(QCall::ModuleHandle pModule, LPCWSTR wszDllName, LPCWSTR wszFunctionName, INT32 token, INT32 linkFlags) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); mdModuleRef mrImportDll = mdTokenNil; IfFailThrow(pRCW->GetEmitter()->DefineModuleRef(wszDllName, &mrImportDll)); IfFailThrow(pRCW->GetEmitter()->DefinePinvokeMap( token, // the method token linkFlags, // the mapping flags wszFunctionName, // function name mrImportDll)); IfFailThrow(pRCW->GetEmitter()->SetMethodProps(token, (DWORD) -1, 0x0, miIL)); END_QCALL; }
/*================================DefineField================================= **Action: **Returns: **Arguments: **Exceptions: ==============================================================================*/ mdFieldDef QCALLTYPE COMDynamicWrite::DefineField(QCall::ModuleHandle pModule, INT32 tkParent, LPCWSTR wszName, LPCBYTE pSignature, INT32 sigLength, INT32 attr) { QCALL_CONTRACT; mdFieldDef retVal = mdTokenNil; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); //Emit the field. IfFailThrow( pRCW->GetEmitter()->DefineField(tkParent, wszName, attr, (PCCOR_SIGNATURE)pSignature, sigLength, ELEMENT_TYPE_VOID, NULL, (ULONG) -1, &retVal) ); END_QCALL; return retVal; }
//************************************************************* // // Defining a type into metadata of this dynamic module // //************************************************************* INT32 QCALLTYPE COMDynamicWrite::DefineGenericParam(QCall::ModuleHandle pModule, LPCWSTR wszFullName, INT32 tkParent, INT32 attributes, INT32 position, INT32 * pConstraintTokens) { QCALL_CONTRACT; mdTypeDef classE = mdTokenNil; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); IfFailThrow(pRCW->GetEmitter()->DefineGenericParam( tkParent, position, attributes, wszFullName, 0, (mdToken *)pConstraintTokens, &classE)); END_QCALL; return (INT32)classE; }
/*============================GetTokenFromSig============================ **Action: **Returns: **Arguments: **Exceptions: ==============================================================================*/ INT32 QCALLTYPE COMDynamicWrite::GetTokenFromSig(QCall::ModuleHandle pModule, LPCBYTE pSignature, INT32 sigLength) { QCALL_CONTRACT; mdSignature retVal = 0; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); _ASSERTE(pSignature); // Define the signature IfFailThrow(pRCW->GetEmitter()->GetTokenFromSig( pSignature, // Signature blob sigLength, // blob length &retVal)); // returned token END_QCALL; return (INT32)retVal; }
/*============================DefineEvent============================ **Action: **Returns: **Arguments: **Exceptions: ==============================================================================*/ INT32 QCALLTYPE COMDynamicWrite::DefineEvent(QCall::ModuleHandle pModule, INT32 tkParent, LPCWSTR wszName, INT32 attr, INT32 tkEventType) { QCALL_CONTRACT; mdProperty ev = mdTokenNil; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); // Define the Event IfFailThrow(pRCW->GetEmitHelper()->DefineEventHelper( tkParent, // ParentTypeDef wszName, // Name of Member attr, // property Attributes (prDefaultProperty, etc); tkEventType, // the event type. Can be TypeDef or TypeRef &ev)); END_QCALL; return (INT32)ev; }
//****************************************************************************** // // GetMemberRefToken // This function will return a MemberRef token given a MethodDef token and the module where the MethodDef/FieldDef is defined. // //****************************************************************************** INT32 QCALLTYPE COMModule::GetMemberRef(QCall::ModuleHandle pModule, QCall::ModuleHandle pRefedModule, INT32 tr, INT32 token) { QCALL_CONTRACT; mdMemberRef memberRefE = 0; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE( pRCW ); LPCUTF8 szName; ULONG cbComSig; PCCOR_SIGNATURE pvComSig; if (TypeFromToken(token) == mdtMethodDef) { IfFailThrow(pRefedModule->GetMDImport()->GetNameOfMethodDef(token, &szName)); IfFailThrow(pRefedModule->GetMDImport()->GetSigOfMethodDef(token, &cbComSig, &pvComSig)); } else { IfFailThrow(pRefedModule->GetMDImport()->GetNameOfFieldDef(token, &szName)); IfFailThrow(pRefedModule->GetMDImport()->GetSigOfFieldDef(token, &cbComSig, &pvComSig)); } MAKE_WIDEPTR_FROMUTF8(wzName, szName); // Translate the method sig into this scope // Assembly * pRefedAssembly = pRefedModule->GetAssembly(); Assembly * pRefingAssembly = pModule->GetAssembly(); if (pRefedAssembly->IsCollectible() && pRefedAssembly != pRefingAssembly) { if (pRefingAssembly->IsCollectible()) pRefingAssembly->GetLoaderAllocator()->EnsureReference(pRefedAssembly->GetLoaderAllocator()); else COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible")); } SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit; IfFailThrow( pRefingAssembly->GetManifestModule()->GetEmitter()->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) ); CQuickBytes qbNewSig; ULONG cbNewSig; IfFailThrow( pRefedModule->GetMDImport()->TranslateSigWithScope( pRefedAssembly->GetManifestImport(), NULL, 0, // hash value pvComSig, cbComSig, pAssemblyEmit, // Emit assembly scope. pRCW->GetEmitter(), &qbNewSig, &cbNewSig) ); mdTypeRef tref; if (TypeFromToken(tr) == mdtTypeDef) { // define a TypeRef using the TypeDef DefineTypeRefHelper(pRCW->GetEmitter(), tr, &tref); } else tref = tr; // Define the memberRef IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tref, wzName, (PCCOR_SIGNATURE) qbNewSig.Ptr(), cbNewSig, &memberRefE) ); END_QCALL; // assign output parameter return (INT32)memberRefE; }
//************************************************** // GetTypeRef // This function will return the type token given full qual name. If the type // is defined locally, we will return the TypeDef token. Or we will return a TypeRef token // with proper resolution scope calculated. // wszFullName is escaped (TYPE_NAME_RESERVED_CHAR). It should not be byref or contain enclosing type name, // assembly name, and generic argument list. //************************************************** mdTypeRef QCALLTYPE COMModule::GetTypeRef(QCall::ModuleHandle pModule, LPCWSTR wszFullName, QCall::ModuleHandle pRefedModule, LPCWSTR wszRefedModuleFileName, INT32 tkResolutionArg) { QCALL_CONTRACT; mdTypeRef tr = 0; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); IMetaDataEmit * pEmit = pRCW->GetEmitter(); IMetaDataImport * pImport = pRCW->GetRWImporter(); if (wszFullName == NULL) { COMPlusThrow(kArgumentNullException, W("ArgumentNull_String")); } InlineSString<128> ssNameUnescaped; LPCWSTR wszTemp = wszFullName; WCHAR c; while(0 != (c = *wszTemp++)) { if ( c == W('\\') && IsTypeNameReservedChar(*wszTemp) ) { ssNameUnescaped.Append(*wszTemp++); } else { _ASSERTE( ! IsTypeNameReservedChar(c) ); ssNameUnescaped.Append(c); } } LPCWSTR wszFullNameUnescaped = ssNameUnescaped.GetUnicode(); Assembly * pThisAssembly = pModule->GetClassLoader()->GetAssembly(); Assembly * pRefedAssembly = pRefedModule->GetClassLoader()->GetAssembly(); if (pModule == pRefedModule) { // referenced type is from the same module so we must be able to find a TypeDef. IfFailThrow(pImport->FindTypeDefByName( wszFullNameUnescaped, RidFromToken(tkResolutionArg) ? tkResolutionArg : mdTypeDefNil, &tr)); } else { mdToken tkResolution = mdTokenNil; if (RidFromToken(tkResolutionArg)) { // reference to nested type tkResolution = tkResolutionArg; } else { // reference to top level type if ( pThisAssembly != pRefedAssembly ) { SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit; // Generate AssemblyRef IfFailThrow( pEmit->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) ); tkResolution = pThisAssembly->AddAssemblyRef(pRefedAssembly, pAssemblyEmit); // Add the assembly ref token and the manifest module it is referring to this module's rid map. // This is needed regardless of whether the dynamic assembly has run access. Even in Save-only // or Refleciton-only mode, CreateType() of the referencing type may still need the referenced // type to be resolved and loaded, e.g. if the referencing type is a subclass of the referenced type. // // Don't cache if there is assembly associated with the token already. The assembly ref resolution // can be ambiguous because of reflection emit does not require unique assembly names. // We always let the first association win. Ideally, we would disallow this situation by throwing // exception, but that would be a breaking change. if(pModule->LookupAssemblyRef(tkResolution) == NULL) { pModule->ForceStoreAssemblyRef(tkResolution, pRefedAssembly); } } else { _ASSERTE(pModule != pRefedModule); _ASSERTE(wszRefedModuleFileName != NULL); // Generate ModuleRef IfFailThrow(pEmit->DefineModuleRef(wszRefedModuleFileName, &tkResolution)); } } IfFailThrow( pEmit->DefineTypeRefByName(tkResolution, wszFullNameUnescaped, &tr) ); } END_QCALL; return tr; }
// SetMethodIL -- This function will create a method within the class void QCALLTYPE COMDynamicWrite::SetMethodIL(QCall::ModuleHandle pModule, INT32 tk, BOOL fIsInitLocal, LPCBYTE pBody, INT32 cbBody, LPCBYTE pLocalSig, INT32 sigLength, UINT16 maxStackSize, ExceptionInstance * pExceptions, INT32 numExceptions, INT32 * pTokenFixups, INT32 numTokenFixups) { QCALL_CONTRACT; BEGIN_QCALL; RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter(); _ASSERTE(pRCW); _ASSERTE(pLocalSig); PCCOR_SIGNATURE pcSig = (PCCOR_SIGNATURE)pLocalSig; _ASSERTE(*pcSig == IMAGE_CEE_CS_CALLCONV_LOCAL_SIG); mdSignature pmLocalSigToken; if (sigLength==2 && pcSig[0]==0 && pcSig[1]==0) { //This is an empty local variable sig pmLocalSigToken=0; } else { IfFailThrow(pRCW->GetEmitter()->GetTokenFromSig( pcSig, sigLength, &pmLocalSigToken)); } COR_ILMETHOD_FAT fatHeader; // set fatHeader.Flags to CorILMethod_InitLocals if user wants to zero init the stack frame. // fatHeader.SetFlags(fIsInitLocal ? CorILMethod_InitLocals : 0); fatHeader.SetMaxStack(maxStackSize); fatHeader.SetLocalVarSigTok(pmLocalSigToken); fatHeader.SetCodeSize(cbBody); bool moreSections = (numExceptions != 0); unsigned codeSizeAligned = fatHeader.GetCodeSize(); if (moreSections) codeSizeAligned = AlignUp(codeSizeAligned, 4); // to insure EH section aligned unsigned headerSize = COR_ILMETHOD::Size(&fatHeader, numExceptions != 0); //Create the exception handlers. CQuickArray<COR_ILMETHOD_SECT_EH_CLAUSE_FAT> clauses; if (numExceptions > 0) { clauses.AllocThrows(numExceptions); for (int i = 0; i < numExceptions; i++) { clauses[i].SetFlags((CorExceptionFlag)(pExceptions[i].m_type)); clauses[i].SetTryOffset(pExceptions[i].m_start); clauses[i].SetTryLength(pExceptions[i].m_end - pExceptions[i].m_start); clauses[i].SetHandlerOffset(pExceptions[i].m_handle); clauses[i].SetHandlerLength(pExceptions[i].m_handleEnd - pExceptions[i].m_handle); if (pExceptions[i].m_type == COR_ILEXCEPTION_CLAUSE_FILTER) { clauses[i].SetFilterOffset(pExceptions[i].m_filterOffset); } else if (pExceptions[i].m_type!=COR_ILEXCEPTION_CLAUSE_FINALLY) { clauses[i].SetClassToken(pExceptions[i].m_exceptionType); } else { clauses[i].SetClassToken(mdTypeRefNil); } } } unsigned ehSize = ExceptionHandlingSize(numExceptions, clauses.Ptr()); S_UINT32 totalSizeSafe = S_UINT32(headerSize) + S_UINT32(codeSizeAligned) + S_UINT32(ehSize); if (totalSizeSafe.IsOverflow()) COMPlusThrowOM(); UINT32 totalSize = totalSizeSafe.Value(); ICeeGen* pGen = pRCW->GetCeeGen(); BYTE* buf = NULL; ULONG methodRVA; pGen->AllocateMethodBuffer(totalSize, &buf, &methodRVA); if (buf == NULL) COMPlusThrowOM(); _ASSERTE(buf != NULL); _ASSERTE((((size_t) buf) & 3) == 0); // header is dword aligned #ifdef _DEBUG BYTE* endbuf = &buf[totalSize]; #endif BYTE * startBuf = buf; // Emit the header buf += COR_ILMETHOD::Emit(headerSize, &fatHeader, moreSections, buf); //Emit the code //The fatHeader.CodeSize is a workaround to see if we have an interface or an //abstract method. Force enough verification in native to ensure that //this is true. if (fatHeader.GetCodeSize()!=0) { memcpy(buf, pBody, fatHeader.GetCodeSize()); } buf += codeSizeAligned; // Emit the eh CQuickArray<ULONG> ehTypeOffsets; if (numExceptions > 0) { // Allocate space for the the offsets to the TypeTokens in the Exception headers // in the IL stream. ehTypeOffsets.AllocThrows(numExceptions); // Emit the eh. This will update the array ehTypeOffsets with offsets // to Exception type tokens. The offsets are with reference to the // beginning of eh section. buf += COR_ILMETHOD_SECT_EH::Emit(ehSize, numExceptions, clauses.Ptr(), false, buf, ehTypeOffsets.Ptr()); } _ASSERTE(buf == endbuf); //Get the IL Section. HCEESECTION ilSection; IfFailThrow(pGen->GetIlSection(&ilSection)); // Token Fixup data... ULONG ilOffset = methodRVA + headerSize; //Add all of the relocs based on the info which I saved from ILGenerator. //Add the Token Fixups for (int iTokenFixup=0; iTokenFixup<numTokenFixups; iTokenFixup++) { IfFailThrow(pGen->AddSectionReloc(ilSection, pTokenFixups[iTokenFixup] + ilOffset, ilSection, srRelocMapToken)); } // Add token fixups for exception type tokens. for (int iException=0; iException < numExceptions; iException++) { if (ehTypeOffsets[iException] != (ULONG) -1) { IfFailThrow(pGen->AddSectionReloc( ilSection, ehTypeOffsets[iException] + codeSizeAligned + ilOffset, ilSection, srRelocMapToken)); } } //nasty interface workaround. What does this mean for abstract methods? if (fatHeader.GetCodeSize() != 0) { // add the starting address of the il blob to the il blob hash table // we need to find this information from out of process for debugger inspection // APIs so we have to store this information where we can get it later pModule->SetDynamicIL(mdToken(tk), TADDR(startBuf), FALSE); DWORD dwImplFlags; //Set the RVA of the method. IfFailThrow(pRCW->GetMDImport()->GetMethodImplProps(tk, NULL, &dwImplFlags)); dwImplFlags |= (miManaged | miIL); IfFailThrow(pRCW->GetEmitter()->SetMethodProps(tk, (DWORD) -1, methodRVA, dwImplFlags)); } END_QCALL; }