summaryrefslogtreecommitdiff
path: root/src/vm/commodule.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/commodule.cpp')
-rw-r--r--src/vm/commodule.cpp1289
1 files changed, 1289 insertions, 0 deletions
diff --git a/src/vm/commodule.cpp b/src/vm/commodule.cpp
new file mode 100644
index 0000000000..44a96d36ab
--- /dev/null
+++ b/src/vm/commodule.cpp
@@ -0,0 +1,1289 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+#include "common.h"
+#include "commodule.h"
+#include "comdynamic.h"
+#include "reflectclasswriter.h"
+#include "class.h"
+#include "corpolicy.h"
+#include "security.h"
+#include "ceesectionstring.h"
+#include <cor.h>
+#include "typeparse.h"
+#include "typekey.h"
+#include "ildbsymlib.h"
+
+
+//===============================================================================================
+// CreateISymWriterforDynamicModule:
+// Helper to create a ISymUnmanagedWriter instance and hook it up to a newly created dynamic
+// module. This object is used to capture debugging information (source line info, etc.)
+// for the dynamic module. This function determines the appropriate symbol format type
+// (ILDB or PDB), and in the case of PDB (Windows desktop only) loads diasymreader.dll.
+//
+// Arguments:
+// mod - The ReflectionModule for the new dynamic module
+// filenameTemp - the filename at which the module may be saved (ignored if no save access)
+//
+// Return value:
+// The address where the new writer instance has been stored
+//===============================================================================================
+static ISymUnmanagedWriter **CreateISymWriterForDynamicModule(ReflectionModule *mod, const WCHAR *wszFilename)
+{
+ STANDARD_VM_CONTRACT;
+
+ _ASSERTE(mod->IsReflection());
+
+ // Determine which symbol format to use. For Silverlight 2.0 RTM we use ILDB mode to address security
+ // and portability issues with diasymreader.
+ //
+ // For desktop builds we'll eventually want to make ILDB is the default, but we need to emit PDB format if
+ // the symbols can be saved to disk to preserve back compat.
+ //
+ ESymbolFormat symFormatToUse = eSymbolFormatILDB;
+
+#ifndef FEATURE_CORECLR // On desktop only we still use PDB format if the symbols are savable to disk
+ if(mod->GetAssembly()->HasSaveAccess())
+ {
+ symFormatToUse = eSymbolFormatPDB;
+ }
+#endif
+
+ static ConfigDWORD dbgForcePDBSymbols;
+ if(dbgForcePDBSymbols.val_DontUse_(W("DbgForcePDBSymbols"), 0) == 1)
+ {
+ symFormatToUse = eSymbolFormatPDB;
+ }
+
+ // Create a stream for the symbols to be emitted into. This
+ // lives on the Module for the life of the Module.
+ SafeComHolder<CGrowableStream> pStream(new CGrowableStream());
+
+ mod->SetInMemorySymbolStream(pStream, symFormatToUse);
+
+ // Create an ISymUnmanagedWriter and initialize it with the
+ // stream and the proper file name. This symbol writer will be
+ // replaced with new ones periodically as the symbols get
+ // retrieved by the debugger.
+ SafeComHolder<ISymUnmanagedWriter> pWriter;
+
+ HRESULT hr;
+ if (symFormatToUse == eSymbolFormatILDB)
+ {
+ // Create an ILDB symbol writer from the ildbsymbols library statically linked in
+ hr = IldbSymbolsCreateInstance(CLSID_CorSymWriter_SxS,
+ IID_ISymUnmanagedWriter,
+ (void**)&pWriter);
+ }
+ else
+ {
+ _ASSERTE(symFormatToUse == eSymbolFormatPDB);
+ hr = FakeCoCreateInstanceEx(CLSID_CorSymWriter_SxS,
+ GetInternalSystemDirectory(),
+ IID_ISymUnmanagedWriter,
+ (void**)&pWriter,
+ NULL);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ {
+ GCX_PREEMP();
+
+ // The other reference is given to the Sym Writer
+ // But, the writer takes it's own reference.
+ hr = pWriter->Initialize(mod->GetEmitter(),
+ wszFilename,
+ (IStream*)pStream,
+ TRUE);
+ }
+ if (SUCCEEDED(hr))
+ {
+ mod->GetReflectionModule()->SetISymUnmanagedWriter(pWriter.Extract());
+
+ // Return the address of where we've got our
+ // ISymUnmanagedWriter stored so we can pass it over
+ // to the managed symbol writer object that most of
+ // reflection emit will use to write symbols.
+ return mod->GetISymUnmanagedWriterAddr();
+ }
+ else
+ {
+ COMPlusThrowHR(hr);
+ }
+ }
+ else
+ {
+ COMPlusThrowHR(hr);
+ }
+}
+
+#ifdef FEATURE_MULTIMODULE_ASSEMBLIES
+//****************************************
+// This function creates a dynamic module underneath the current assembly.
+//****************************************
+void QCALLTYPE COMModule::DefineDynamicModule(QCall::AssemblyHandle pContainingAssembly, BOOL emitSymbolInfo, LPCWSTR pModuleName, LPCWSTR pFilename, QCall::StackCrawlMarkHandle stackMark, LPVOID* ppInternalSymWriter, QCall::ObjectHandleOnStack retModule, BOOL fIsTransient, INT32* ptkFile)
+{
+ QCALL_CONTRACT;
+
+ ReflectionModule * mod = NULL;
+
+ BEGIN_QCALL;
+
+ Assembly * pAssembly = pContainingAssembly->GetAssembly();
+ _ASSERTE(pAssembly);
+
+ // always create a dynamic module. Note that the name conflict
+ // checking is done in managed side.
+
+ mod = pAssembly->CreateDynamicModule(pModuleName, pFilename, fIsTransient, ptkFile);
+
+ mod->SetCreatingAssembly( SystemDomain::GetCallersAssembly( stackMark ) );
+
+ // If we need to emit symbol info, we setup the proper symbol
+ // writer for this module now.
+ if (emitSymbolInfo)
+ {
+ ISymUnmanagedWriter **pWriter = CreateISymWriterForDynamicModule(mod, pFilename);
+ if (ppInternalSymWriter)
+ {
+ *ppInternalSymWriter = pWriter;
+ }
+ }
+
+ GCX_COOP();
+ retModule.Set(mod->GetExposedObject());
+ END_QCALL;
+
+ return;
+}
+#endif //FEATURE_MULTIMODULE_ASSEMBLIES
+//===============================================================================================
+// Attaches an unmanaged symwriter to a newly created dynamic module.
+//===============================================================================================
+FCIMPL2(LPVOID, COMModule::nCreateISymWriterForDynamicModule, ReflectModuleBaseObject* reflectionModuleUNSAFE, StringObject* filenameUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(reflectionModuleUNSAFE);
+
+ ReflectionModule *mod = (ReflectionModule*)refModule->GetModule();
+ STRINGREF filename = (STRINGREF)filenameUNSAFE;
+
+ LPVOID pInternalSymWriter = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_2(filename, refModule);
+
+ SString name;
+ if (filename != NULL)
+ {
+ filename->GetSString(name);
+ }
+
+ GCX_PREEMP();
+ pInternalSymWriter = CreateISymWriterForDynamicModule(mod, name.GetUnicode());
+
+ HELPER_METHOD_FRAME_END();
+
+ return pInternalSymWriter;
+
+} // COMModule::nCreateISymWriterForDynamicModule
+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;
+}
+
+//**************************************************
+// 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;
+}
+
+
+/*=============================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;
+}
+
+
+//******************************************************************************
+//
+// 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;
+}
+
+
+//******************************************************************************
+//
+// Return a TypeRef token given a TypeDef token from the same emit scope
+//
+//******************************************************************************
+void COMModule::DefineTypeRefHelper(
+ IMetaDataEmit *pEmit, // given emit scope
+ mdTypeDef td, // given typedef in the emit scope
+ mdTypeRef *ptr) // return typeref
+{
+ CONTRACTL {
+ STANDARD_VM_CHECK;
+
+ PRECONDITION(CheckPointer(pEmit));
+ PRECONDITION(CheckPointer(ptr));
+ }
+ CONTRACTL_END;
+
+ CQuickBytes qb;
+ WCHAR* szTypeDef = (WCHAR*) qb.AllocThrows((MAX_CLASSNAME_LENGTH+1) * sizeof(WCHAR));
+ mdToken rs; // resolution scope
+ DWORD dwFlags;
+
+ SafeComHolder<IMetaDataImport> pImport;
+ IfFailThrow( pEmit->QueryInterface(IID_IMetaDataImport, (void **)&pImport) );
+ IfFailThrow( pImport->GetTypeDefProps(td, szTypeDef, MAX_CLASSNAME_LENGTH, NULL, &dwFlags, NULL) );
+ if ( IsTdNested(dwFlags) )
+ {
+ mdToken tdNested;
+ IfFailThrow( pImport->GetNestedClassProps(td, &tdNested) );
+ DefineTypeRefHelper( pEmit, tdNested, &rs);
+ }
+ else
+ rs = TokenFromRid( 1, mdtModule );
+
+ IfFailThrow( pEmit->DefineTypeRefByName( rs, szTypeDef, ptr) );
+} // DefineTypeRefHelper
+
+
+//******************************************************************************
+//
+// Return a MemberRef token given a RuntimeMethodInfo
+//
+//******************************************************************************
+INT32 QCALLTYPE COMModule::GetMemberRefOfMethodInfo(QCall::ModuleHandle pModule, INT32 tr, MethodDesc * pMeth)
+{
+ QCALL_CONTRACT;
+
+ mdMemberRef memberRefE = 0;
+
+ BEGIN_QCALL;
+
+ if (!pMeth)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_Obj"));
+
+ // Otherwise, we want to return memberref token.
+ if (pMeth->IsArray())
+ {
+ _ASSERTE(!"Should not have come here!");
+ COMPlusThrow(kNotSupportedException);
+ }
+
+ if (pMeth->GetMethodTable()->GetModule() == pModule)
+ {
+ // If the passed in method is defined in the same module, just return the MethodDef token
+ memberRefE = pMeth->GetMemberDef();
+ }
+ else
+ {
+ RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
+ _ASSERTE(pRCW);
+
+ LPCUTF8 szName;
+ IfFailThrow(pMeth->GetMDImport()->GetNameOfMethodDef(pMeth->GetMemberDef(), &szName));
+
+ ULONG cbComSig;
+ PCCOR_SIGNATURE pvComSig;
+ IfFailThrow(pMeth->GetMDImport()->GetSigOfMethodDef(pMeth->GetMemberDef(), &cbComSig, &pvComSig));
+
+ // Translate the method sig into this scope
+ Assembly * pRefedAssembly = pMeth->GetModule()->GetAssembly();
+ Assembly * pRefingAssembly = pModule->GetAssembly();
+
+ SafeComHolderPreemp<IMetaDataAssemblyEmit> pAssemblyEmit;
+ IfFailThrow( pRefingAssembly->GetManifestModule()->GetEmitter()->QueryInterface(IID_IMetaDataAssemblyEmit, (void **) &pAssemblyEmit) );
+
+ CQuickBytes qbNewSig;
+ ULONG cbNewSig;
+
+ if (pRefedAssembly->IsCollectible() && pRefedAssembly != pRefingAssembly)
+ {
+ if (pRefingAssembly->IsCollectible())
+ pRefingAssembly->GetLoaderAllocator()->EnsureReference(pRefedAssembly->GetLoaderAllocator());
+ else
+ COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
+ }
+
+ IfFailThrow( pMeth->GetMDImport()->TranslateSigWithScope(
+ pRefedAssembly->GetManifestImport(),
+ NULL, 0, // hash blob value
+ pvComSig,
+ cbComSig,
+ pAssemblyEmit, // Emit assembly scope.
+ pRCW->GetEmitter(),
+ &qbNewSig,
+ &cbNewSig) );
+
+ // translate the name to unicode string
+ MAKE_WIDEPTR_FROMUTF8(wszName, szName);
+
+ // Define the memberRef
+ IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tr, wszName, (PCCOR_SIGNATURE) qbNewSig.Ptr(), cbNewSig, &memberRefE) );
+ }
+
+ END_QCALL;
+
+ return memberRefE;
+}
+
+
+//******************************************************************************
+//
+// Return a MemberRef token given a RuntimeFieldInfo
+//
+//******************************************************************************
+mdMemberRef QCALLTYPE COMModule::GetMemberRefOfFieldInfo(QCall::ModuleHandle pModule, mdTypeDef tr, void * th, mdFieldDef tkField)
+{
+ QCALL_CONTRACT;
+
+ mdMemberRef memberRefE = 0;
+
+ BEGIN_QCALL;
+
+ if (TypeFromToken(tr) == mdtTypeDef)
+ {
+ // If the passed in method is defined in the same module, just return the FieldDef token
+ memberRefE = tkField;
+ }
+ else
+ {
+ TypeHandle typeHandle = TypeHandle::FromPtr(th);
+
+ RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
+ _ASSERTE(pRCW);
+
+ // get the field name and sig
+ Module * pRefedModule = typeHandle.GetModule();
+ IMDInternalImport * pRefedMDImport = pRefedModule->GetMDImport();
+
+ LPCUTF8 szName;
+ IfFailThrow(pRefedMDImport->GetNameOfFieldDef(tkField, &szName));
+
+ ULONG cbComSig;
+ PCCOR_SIGNATURE pvComSig;
+ IfFailThrow(pRefedMDImport->GetSigOfFieldDef(tkField, &cbComSig, &pvComSig));
+
+ // translate the name to unicode string
+ MAKE_WIDEPTR_FROMUTF8(wszName, szName);
+
+ 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) );
+
+ // Translate the field signature this scope
+ CQuickBytes qbNewSig;
+ ULONG cbNewSig;
+
+ IfFailThrow( pRefedMDImport->TranslateSigWithScope(
+ pRefedAssembly->GetManifestImport(),
+ NULL, 0, // hash value
+ pvComSig,
+ cbComSig,
+ pAssemblyEmit, // Emit assembly scope.
+ pRCW->GetEmitter(),
+ &qbNewSig,
+ &cbNewSig) );
+
+ IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tr, wszName, (PCCOR_SIGNATURE) qbNewSig.Ptr(), cbNewSig, &memberRefE) );
+ }
+
+ END_QCALL;
+
+ return memberRefE;
+}
+
+//******************************************************************************
+//
+// Return a MemberRef token given a Signature
+//
+//******************************************************************************
+INT32 QCALLTYPE COMModule::GetMemberRefFromSignature(QCall::ModuleHandle pModule,
+ INT32 tr,
+ LPCWSTR wszMemberName,
+ LPCBYTE pSignature,
+ INT32 sigLength)
+{
+ QCALL_CONTRACT;
+
+ mdMemberRef memberRefE = mdTokenNil;
+
+ BEGIN_QCALL;
+
+ RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
+ _ASSERTE(pRCW);
+
+ IfFailThrow( pRCW->GetEmitter()->DefineMemberRef(tr,
+ wszMemberName,
+ pSignature,
+ sigLength,
+ &memberRefE) );
+
+ END_QCALL;
+
+ return memberRefE;
+}
+
+//******************************************************************************
+//
+// SetFieldRVAContent
+// This function is used to set the FieldRVA with the content data
+//
+//******************************************************************************
+void QCALLTYPE COMModule::SetFieldRVAContent(QCall::ModuleHandle pModule, INT32 tkField, LPCBYTE pContent, INT32 length)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
+ _ASSERTE(pRCW);
+
+ ICeeGen * pGen = pRCW->GetCeeGen();
+
+ ReflectionModule * pReflectionModule = pModule->GetReflectionModule();
+
+ // Create the .sdata section if not created
+ if (pReflectionModule->m_sdataSection == 0)
+ IfFailThrow( pGen->GetSectionCreate (".sdata", sdReadWrite, &pReflectionModule->m_sdataSection) );
+
+ // Get the size of current .sdata section. This will be the RVA for this field within the section
+ DWORD dwRVA = 0;
+ IfFailThrow( pGen->GetSectionDataLen(pReflectionModule->m_sdataSection, &dwRVA) );
+ dwRVA = (dwRVA + sizeof(DWORD)-1) & ~(sizeof(DWORD)-1);
+
+ // allocate the space in .sdata section
+ void * pvBlob;
+ IfFailThrow( pGen->GetSectionBlock(pReflectionModule->m_sdataSection, length, sizeof(DWORD), (void**) &pvBlob) );
+
+ // copy over the initialized data if specified
+ if (pContent != NULL)
+ memcpy(pvBlob, pContent, length);
+
+ // set FieldRVA into metadata. Note that this is not final RVA in the image if save to disk. We will do another round of fix up upon save.
+ IfFailThrow( pRCW->GetEmitter()->SetFieldRVA(tkField, dwRVA) );
+
+ END_QCALL;
+}
+
+
+//******************************************************************************
+//
+// GetStringConstant
+// If this is a dynamic module, this routine will define a new
+// string constant or return the token of an existing constant.
+//
+//******************************************************************************
+mdString QCALLTYPE COMModule::GetStringConstant(QCall::ModuleHandle pModule, LPCWSTR pwzValue, INT32 iLength)
+{
+ QCALL_CONTRACT;
+
+ mdString strRef = mdTokenNil;
+
+ BEGIN_QCALL;
+
+ RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
+ _ASSERTE(pRCW);
+
+ _ASSERTE(pwzValue != NULL);
+
+ HRESULT hr = pRCW->GetEmitter()->DefineUserString(pwzValue, iLength, &strRef);
+ if (FAILED(hr)) {
+ _ASSERTE(hr == E_OUTOFMEMORY || !"Unknown failure in DefineUserString");
+ COMPlusThrowHR(hr);
+ }
+
+ END_QCALL;
+
+ return strRef;
+}
+
+
+/*=============================SetModuleName====================================
+// SetModuleName
+==============================================================================*/
+void QCALLTYPE COMModule::SetModuleName(QCall::ModuleHandle pModule, LPCWSTR wszModuleName)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
+ _ASSERTE(pRCW);
+
+ IfFailThrow( pRCW->GetEmitter()->SetModuleProps(wszModuleName) );
+
+ END_QCALL;
+}
+
+//******************************************************************************
+//
+// Return a type spec token given a byte array
+//
+//******************************************************************************
+BOOL QCALLTYPE COMModule::IsTransient(QCall::ModuleHandle pModule)
+{
+ QCALL_CONTRACT;
+
+ BOOL fIsTransient = FALSE;
+
+ BEGIN_QCALL;
+
+ /* Only reflection modules can be transient */
+ if (pModule->IsReflection())
+ fIsTransient = pModule->GetReflectionModule()->IsTransient();
+
+ END_QCALL;
+
+ return fIsTransient;
+}
+
+//******************************************************************************
+//
+// Return a type spec token given a byte array
+//
+//******************************************************************************
+mdTypeSpec QCALLTYPE COMModule::GetTokenFromTypeSpec(QCall::ModuleHandle pModule, LPCBYTE pSignature, INT32 sigLength)
+{
+ QCALL_CONTRACT;
+
+ mdTypeSpec ts = mdTokenNil;
+
+ BEGIN_QCALL;
+
+ RefClassWriter * pRCW = pModule->GetReflectionModule()->GetClassWriter();
+ _ASSERTE(pRCW);
+
+ IfFailThrow(pRCW->GetEmitter()->GetTokenFromTypeSpec((PCCOR_SIGNATURE)pSignature, sigLength, &ts));
+
+ END_QCALL;
+
+ return ts;
+}
+
+
+// GetType
+// Given a class name, this method will look for that class
+// with in the module.
+void QCALLTYPE COMModule::GetType(QCall::ModuleHandle pModule, LPCWSTR wszName, BOOL bThrowOnError, BOOL bIgnoreCase, QCall::ObjectHandleOnStack retType, QCall::ObjectHandleOnStack keepAlive)
+{
+ CONTRACTL
+ {
+ QCALL_CHECK;
+ PRECONDITION(CheckPointer(wszName));
+ }
+ CONTRACTL_END;
+
+ TypeHandle retTypeHandle;
+
+ BEGIN_QCALL;
+
+ DomainAssembly *pAssembly = pModule->GetDomainAssembly();
+ _ASSERTE(pAssembly);
+
+ BOOL prohibitAsmQualifiedName = TRUE;
+
+ // Load the class from this assembly (fail if it is in a different one).
+ retTypeHandle = TypeName::GetTypeManaged(wszName, pAssembly, bThrowOnError, bIgnoreCase, pAssembly->IsIntrospectionOnly(), prohibitAsmQualifiedName, NULL, FALSE, (OBJECTREF*)keepAlive.m_ppObject);
+
+ // Verify that it's in 'this' module
+ // But, if it's in a different assembly than expected, that's okay, because
+ // it just means that it's been type forwarded.
+ if (!retTypeHandle.IsNull())
+ {
+ if ( (retTypeHandle.GetModule() != pModule) &&
+ (retTypeHandle.GetModule()->GetAssembly() == pModule->GetAssembly()) )
+ retTypeHandle = TypeHandle();
+ }
+
+ if (!retTypeHandle.IsNull())
+ {
+ GCX_COOP();
+ retType.Set(retTypeHandle.GetManagedClassObject());
+ }
+
+ END_QCALL;
+
+ return;
+}
+
+
+// GetName
+// This routine will return the name of the module as a String
+void QCALLTYPE COMModule::GetScopeName(QCall::ModuleHandle pModule, QCall::StringHandleOnStack retString)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ LPCSTR szName = NULL;
+
+ if (pModule->IsResource())
+ {
+ IfFailThrow(pModule->GetAssembly()->GetManifestImport()->GetFileProps(
+ pModule->GetModuleRef(),
+ &szName,
+ NULL,
+ NULL,
+ NULL));
+ }
+ else
+ {
+ if (!pModule->GetMDImport()->IsValidToken(pModule->GetMDImport()->GetModuleFromScope()))
+ {
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+ }
+ IfFailThrow(pModule->GetMDImport()->GetScopeProps(&szName, 0));
+ }
+
+ retString.Set(szName);
+
+ END_QCALL;
+}
+
+static void ReplaceNiExtension(SString& fileName, PCWSTR pwzOldSuffix, PCWSTR pwzNewSuffix)
+{
+ STANDARD_VM_CONTRACT;
+
+ if (fileName.EndsWithCaseInsensitive(pwzOldSuffix))
+ {
+ COUNT_T oldSuffixLen = (COUNT_T)wcslen(pwzOldSuffix);
+ fileName.Replace(fileName.End() - oldSuffixLen, oldSuffixLen, pwzNewSuffix);
+ }
+}
+
+/*============================GetFullyQualifiedName=============================
+**Action:
+**Returns:
+**Arguments:
+**Exceptions:
+==============================================================================*/
+void QCALLTYPE COMModule::GetFullyQualifiedName(QCall::ModuleHandle pModule, QCall::StringHandleOnStack retString)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ HRESULT hr = S_OK;
+
+ WCHAR wszBuffer[64];
+
+ if (pModule->IsPEFile())
+ {
+ LPCWSTR fileName = pModule->GetPath();
+ if (*fileName != 0) {
+#ifndef FEATURE_CORECLR
+ // workaround - lie about where mscorlib is. Mscorlib is now loaded out of the GAC,
+ // but some apps query its location to find the system directory. (Notably CodeDOM)
+ if (pModule->IsSystem())
+ retString.Set(SystemDomain::System()->BaseLibrary());
+ else
+#endif // !FEATURE_CORECLR
+ {
+#ifdef FEATURE_WINDOWSPHONE
+ //
+ // On Phone we use only native images without any concept of the matching IL image
+ // To stop native image filenames leaking through to apps, fudge Reflection::get_Name
+ // so apps see Foo.dll instead of Foo.ni.dll
+ //
+ if (pModule->GetFile()->GetAssembly()->GetILimage()->IsTrustedNativeImage())
+ {
+ SString fileNameWithoutNi(fileName);
+
+ ReplaceNiExtension(fileNameWithoutNi, W(".ni.dll"), W(".dll"));
+ ReplaceNiExtension(fileNameWithoutNi, W(".ni.exe"), W(".exe"));
+ ReplaceNiExtension(fileNameWithoutNi, W(".ni.winmd"), W(".winmd"));
+
+ retString.Set(fileNameWithoutNi);
+ }
+ else
+#endif
+ retString.Set(fileName);
+ }
+ } else {
+ hr = UtilLoadStringRC(IDS_EE_NAME_UNKNOWN, wszBuffer, sizeof( wszBuffer ) / sizeof( WCHAR ), true );
+ if (FAILED(hr))
+ COMPlusThrowHR(hr);
+ retString.Set(wszBuffer);
+ }
+ }
+ else
+ {
+ hr = UtilLoadStringRC(IDS_EE_NAME_INMEMORYMODULE, wszBuffer, sizeof( wszBuffer ) / sizeof( WCHAR ), true );
+ if (FAILED(hr))
+ COMPlusThrowHR(hr);
+ retString.Set(wszBuffer);
+ }
+
+ END_QCALL;
+}
+
+/*===================================GetHINSTANCE===============================
+**Action: Returns the hinst for this module.
+**Returns:
+**Arguments: refThis
+**Exceptions: None.
+==============================================================================*/
+HINSTANCE QCALLTYPE COMModule::GetHINSTANCE(QCall::ModuleHandle pModule)
+{
+ QCALL_CONTRACT;
+
+ HMODULE hMod = (HMODULE)0;
+
+ BEGIN_QCALL;
+
+ // This returns the base address - this will work for either HMODULE or HCORMODULES
+ // Other modules should have zero base
+ PEFile *pPEFile = pModule->GetFile();
+ if (!pPEFile->IsDynamic() && !pPEFile->IsResource())
+ {
+ hMod = (HMODULE) pModule->GetFile()->GetManagedFileContents();
+ }
+
+ //If we don't have an hMod, set it to -1 so that they know that there's none
+ //available
+ if (!hMod) {
+ hMod = (HMODULE)-1;
+ }
+
+ END_QCALL;
+
+ return (HINSTANCE)hMod;
+}
+
+static Object* GetTypesInner(Module* pModule);
+
+// Get class will return an array contain all of the classes
+// that are defined within this Module.
+FCIMPL1(Object*, COMModule::GetTypes, ReflectModuleBaseObject* pModuleUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ OBJECTREF refRetVal = NULL;
+ REFLECTMODULEBASEREF refModule = (REFLECTMODULEBASEREF)ObjectToOBJECTREF(pModuleUNSAFE);
+ if (refModule == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ Module *pModule = refModule->GetModule();
+
+ HELPER_METHOD_FRAME_BEGIN_RET_2(refRetVal, refModule);
+
+ refRetVal = (OBJECTREF) GetTypesInner(pModule);
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(refRetVal);
+}
+FCIMPLEND
+
+Object* GetTypesInner(Module* pModule)
+{
+ CONTRACT(Object*) {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+
+ PRECONDITION(CheckPointer(pModule));
+
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ DWORD dwNumTypeDefs = 0;
+ DWORD i;
+ IMDInternalImport *pInternalImport;
+ PTRARRAYREF refArrClasses = NULL;
+ PTRARRAYREF xcept = NULL;
+ DWORD cXcept = 0;
+ HENUMInternal hEnum;
+ bool bSystemAssembly; // Don't expose transparent proxy
+ int AllocSize = 0;
+ MethodTable* pMT = NULL;
+
+ if (pModule->IsResource())
+ {
+ refArrClasses = (PTRARRAYREF) AllocateObjectArray(0, MscorlibBinder::GetClass(CLASS__CLASS));
+ RETURN(OBJECTREFToObject(refArrClasses));
+ }
+
+ GCPROTECT_BEGIN(refArrClasses);
+ GCPROTECT_BEGIN(xcept);
+
+ pInternalImport = pModule->GetMDImport();
+
+ HENUMTypeDefInternalHolder hEnum(pInternalImport);
+ // Get the count of typedefs
+ hEnum.EnumTypeDefInit();
+
+ dwNumTypeDefs = pInternalImport->EnumTypeDefGetCount(&hEnum);
+
+ // Allocate the COM+ array
+ bSystemAssembly = (pModule->GetAssembly() == SystemDomain::SystemAssembly());
+#ifdef FEATURE_REMOTING
+ // we skip the TransparentProxy type if this is mscorlib, so we can make the array one element smaller
+ AllocSize = !bSystemAssembly ? dwNumTypeDefs : dwNumTypeDefs - 1;
+#else
+ AllocSize = dwNumTypeDefs;
+#endif
+ refArrClasses = (PTRARRAYREF) AllocateObjectArray(AllocSize, MscorlibBinder::GetClass(CLASS__CLASS));
+
+ int curPos = 0;
+ OBJECTREF throwable = 0;
+ mdTypeDef tdCur = mdTypeDefNil;
+
+ GCPROTECT_BEGIN(throwable);
+ // Now create each COM+ Method object and insert it into the array.
+ while (pInternalImport->EnumTypeDefNext(&hEnum, &tdCur))
+ {
+ // Get the VM class for the current class token
+ TypeHandle curClass;
+
+ EX_TRY {
+ curClass = ClassLoader::LoadTypeDefOrRefThrowing(pModule, tdCur,
+ ClassLoader::ThrowIfNotFound,
+ ClassLoader::PermitUninstDefOrRef);
+ }
+ EX_CATCH_THROWABLE(&throwable);
+
+ if (throwable != 0) {
+ // Lazily allocate an array to store the exceptions in
+ if (xcept == NULL)
+ xcept = (PTRARRAYREF) AllocateObjectArray(dwNumTypeDefs,g_pExceptionClass);
+
+ _ASSERTE(cXcept < dwNumTypeDefs);
+ xcept->SetAt(cXcept++, throwable);
+ throwable = 0;
+ continue;
+ }
+
+ _ASSERTE("LoadClass failed." && !curClass.IsNull());
+
+ pMT = curClass.GetMethodTable();
+ PREFIX_ASSUME(pMT != NULL);
+
+ if (pMT->IsTransparentProxy())
+ {
+ // Don't expose transparent proxy
+ _ASSERTE(bSystemAssembly);
+ continue;
+ }
+
+ // Get the COM+ Class object
+ OBJECTREF refCurClass = pMT->GetManagedClassObject();
+ _ASSERTE("GetManagedClassObject failed." && refCurClass != NULL);
+
+ _ASSERTE(curPos < AllocSize);
+ refArrClasses->SetAt(curPos++, refCurClass);
+ }
+ GCPROTECT_END(); //throwable
+
+ // check if there were exceptions thrown
+ if (cXcept > 0) {
+ PTRARRAYREF xceptRet = NULL;
+ GCPROTECT_BEGIN(xceptRet);
+
+ xceptRet = (PTRARRAYREF) AllocateObjectArray(cXcept,g_pExceptionClass);
+ for (i=0;i<cXcept;i++) {
+ xceptRet->SetAt(i, xcept->GetAt(i));
+ }
+ OBJECTREF except = InvokeUtil::CreateClassLoadExcept((OBJECTREF*) &refArrClasses,(OBJECTREF*) &xceptRet);
+ COMPlusThrow(except);
+
+ GCPROTECT_END();
+ }
+
+ // We should have filled the array exactly.
+ _ASSERTE(curPos == AllocSize);
+
+ // Assign the return value to the COM+ array
+ GCPROTECT_END();
+ GCPROTECT_END();
+
+ RETURN(OBJECTREFToObject(refArrClasses));
+}
+
+#if defined(FEATURE_X509) && defined(FEATURE_CAS_POLICY)
+//+--------------------------------------------------------------------------
+//
+// Member: COMModule::GetSignerCertificate()
+//
+// Synopsis: Gets the certificate with which the module was signed.
+//
+// Effects: Creates an X509Certificate and returns it.
+//
+// Arguments: None.
+//
+// Returns: OBJECTREF to an X509Certificate object containing the
+// signer certificate.
+//
+//---------------------------------------------------------------------------
+
+void QCALLTYPE COMModule::GetSignerCertificate(QCall::ModuleHandle pModule, QCall::ObjectHandleOnStack retData)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ PCOR_TRUST pCorTrust = NULL;
+ IAssemblySecurityDescriptor* pSecDesc = NULL;
+ PBYTE pbSigner = NULL;
+ DWORD cbSigner = 0;
+
+ // ******** Get the security descriptor ********
+
+ // Get a pointer to the module security descriptor
+ pSecDesc = pModule->GetSecurityDescriptor();
+ _ASSERTE(pSecDesc);
+
+ // ******** Get COR_TRUST info from module security descriptor ********
+ if (FAILED(pSecDesc->LoadSignature(&pCorTrust)))
+ {
+ COMPlusThrow(kArgumentNullException, W("InvalidOperation_MetaDataError"));
+ }
+
+ if( pCorTrust )
+ {
+ // Get a pointer to the signer certificate information in the COR_TRUST
+ pbSigner = pCorTrust->pbSigner;
+ cbSigner = pCorTrust->cbSigner;
+
+ if( pbSigner && cbSigner )
+ {
+ retData.SetByteArray(pbSigner, cbSigner);
+ }
+ }
+
+ END_QCALL;
+}
+#endif // #if defined(FEATURE_X509) && defined(FEATURE_CAS_POLICY)
+
+FCIMPL1(FC_BOOL_RET, COMModule::IsResource, ReflectModuleBaseObject* pModuleUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ if (pModuleUNSAFE == NULL)
+ FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ FC_RETURN_BOOL(pModuleUNSAFE->GetModule()->IsResource());
+}
+FCIMPLEND
+
+#ifdef FEATURE_CORECLR
+
+//---------------------------------------------------------------------
+// Helper code for PunkSafeHandle class. This does the Release in the
+// safehandle's critical finalizer.
+//---------------------------------------------------------------------
+static VOID __stdcall DReleaseTarget(IUnknown *punk)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ if (punk)
+ {
+ punk->Release();
+ }
+}
+
+
+//---------------------------------------------------------------------
+// Helper code for PunkSafeHandle class. This returns the function that performs
+// the Release() for the safehandle's critical finalizer.
+//---------------------------------------------------------------------
+FCIMPL0(void*, COMPunkSafeHandle::nGetDReleaseTarget)
+{
+ FCALL_CONTRACT;
+
+ return (void*)DReleaseTarget;
+}
+FCIMPLEND
+#endif //FEATURE_CORECLR
+
+