// ==++==
//
//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
//
// ==--==
/*============================================================
**
** Header: Assembly.hpp
**
** Purpose: Implements assembly (loader domain) architecture
**
** Date: Oct 26, 1998
**
===========================================================*/
#ifndef _ASSEMBLY_H
#define _ASSEMBLY_H
#include "ceeload.h"
#include "exceptmacros.h"
#include "clsload.hpp"
#include "fusion.h"
#include "eehash.h"
#include "listlock.h"
#include "iceefilegen.h"
#include "fusionbind.h"
#include "cordbpriv.h"
#include "assemblyspec.hpp"
// A helper macro for the assembly's module hash (m_pAllowedFiles).
#define UTF8_TO_LOWER_CASE(str, qb) \
{ \
WRAPPER_CONTRACT; \
GCX_COOP(); \
INT32 allocBytes = InternalCasingHelper::InvariantToLower(NULL, 0, str); \
qb.AllocThrows(allocBytes); \
InternalCasingHelper::InvariantToLower((LPUTF8) qb.Ptr(), allocBytes, str); \
}
class BaseDomain;
class AppDomain;
class DomainAssembly;
class DomainModule;
class SystemDomain;
class ClassLoader;
class ComDynamicWrite;
class AssemblySink;
class AssemblyNative;
class AssemblySpec;
class COMHash;
class SharedSecurityDescriptor;
class Pending;
class AllocMemTracker;
// Bits in m_dwDynamicAssemblyAccess (see System.Reflection.Emit.AssemblyBuilderAccess.cs)
#define ASSEMBLY_ACCESS_RUN 0x01
#define ASSEMBLY_ACCESS_SAVE 0x02
#define ASSEMBLY_ACCESS_REFLECTION_ONLY 0x04
struct AssemblySharingContext
{
IAssemblyBindingClosure* pContext;
volatile LONG shareCount;
};
struct CreateDynamicAssemblyArgsGC
{
APPDOMAINREF refThis;
OBJECTREF refusedPset;
OBJECTREF optionalPset;
OBJECTREF requiredPset;
OBJECTREF identity;
ASSEMBLYNAMEREF assemblyName;
};
struct CreateDynamicAssemblyArgs : CreateDynamicAssemblyArgsGC
{
INT32 access;
StackCrawlMark* stackMark;
};
class Assembly
{
friend class BaseDomain;
friend class SystemDomain;
friend class ClassLoader;
friend class AssemblyNative;
friend class AssemblySpec;
friend class COMHash;
friend class NDirect;
friend class AssemblyNameNative;
friend class ClrDataAccess;
public:
Assembly(BaseDomain *pDomain, PEAssembly *pFile, DebuggerAssemblyControlFlags debuggerFlags);
void Init(AllocMemTracker *pamTracker);
void StartUnload();
void Terminate( BOOL signalProfiler = TRUE );
static Assembly *Create(BaseDomain *pDomain, PEAssembly *pFile, DebuggerAssemblyControlFlags debuggerFlags, AllocMemTracker *pamTracker);
BOOL IsSystem() { WRAPPER_CONTRACT; return m_pManifestFile->IsSystem(); }
static Assembly *CreateDynamic(BaseDomain *pDomain, CreateDynamicAssemblyArgs *args);
ReflectionModule *CreateDynamicModule(LPCWSTR name);
MethodDesc *GetEntryPoint();
//****************************************************************************************
//
// Additional init tasks for Modules. This should probably be part of Module::Initialize()
// but there's at least one call to ReflectionModule::Create that is *not* followed by a
// PrepareModule call.
void PrepareModuleForAssembly(Module* module, AllocMemTracker *pamTracker);
// This is the final step of publishing a Module into an Assembly. This step cannot fail.
void PublishModuleIntoAssembly(Module *module);
#ifndef DACCESS_COMPILE
void SetIsTenured()
{
WRAPPER_CONTRACT;
m_pManifest->SetIsTenured();
}
// CAUTION: This should only be used as backout code if an assembly is unsuccessfully
// added to the shared domain assembly map.
void UnsetIsTenured()
{
WRAPPER_CONTRACT;
m_pManifest->UnsetIsTenured();
}
#endif // DACCESS_COMPILE
//****************************************************************************************
//
// Returns the class loader associated with the assembly.
ClassLoader* GetLoader()
{
LEAF_CONTRACT;
return m_pClassLoader;
}
// ------------------------------------------------------------
// Modules
// ------------------------------------------------------------
class ModuleIterator
{
Module* m_pManifest;
DWORD m_i;
public:
#ifdef DACCESS_COMPILE
ModuleIterator()
{
// This ctor is only useful for creating placeholder
// iterator that are later copied over.
m_pManifest = NULL;
}
#endif
ModuleIterator(Assembly *pAssembly)
: m_pManifest(pAssembly->GetManifestModule()),
m_i((DWORD) -1)
{
WRAPPER_CONTRACT;
}
BOOL Next()
{
WRAPPER_CONTRACT;
while (++m_i <= m_pManifest->GetFileMax())
{
if (GetModule() != NULL)
return TRUE;
}
return FALSE;
}
Module *GetModule()
{
WRAPPER_CONTRACT;
return m_pManifest->LookupFile(TokenFromRid(m_i, mdtFile));
}
};
ModuleIterator IterateModules()
{
WRAPPER_CONTRACT;
return ModuleIterator(this);
}
//****************************************************************************************
//
// Find the module
Module* FindModule(PEFile *pFile, BOOL includeLoading = FALSE);
// Finds loading modules as well
DomainFile* FindIJWDomainFile(HMODULE hMod, const SString &path);
//****************************************************************************************
//
// Get the domain the assembly lives in.
BaseDomain* Parent()
{
LEAF_CONTRACT;
return m_pDomain;
}
// Sets the assemblies domain.
void SetParent(BaseDomain* pParent);
//-----------------------------------------------------------------------------------------
// If true, this assembly is loaded only for introspection. We can load modules, types, etc,
// but no code execution or object instantiation is permitted.
//-----------------------------------------------------------------------------------------
BOOL IsIntrospectionOnly();
//-----------------------------------------------------------------------------------------
// If true, strings only need to be interned at a per module basis, instead of at a
// per appdomain basis, which is the default. Use the module accessor so you don't need
// to touch the metadata in the ngen case
//-----------------------------------------------------------------------------------------
BOOL IsNoStringInterning();
//-----------------------------------------------------------------------------------------
// If true, any non-CLSCompliant exceptions (i.e. ones which derive from something other
// than System.Exception) are wrapped in a RuntimeWrappedException instance. In other
// words, they become compliant
//-----------------------------------------------------------------------------------------
BOOL IsRuntimeWrapExceptions();
//-----------------------------------------------------------------------------------------
// EnsureActive ensures that the assembly is properly prepped in the current app domain
// for active uses like code execution, static field access, and instance allocation
//-----------------------------------------------------------------------------------------
VOID EnsureActive();
//-----------------------------------------------------------------------------------------
// CheckActivated is a check predicate which should be used in active use paths like code
// execution, static field access, and instance allocation
//-----------------------------------------------------------------------------------------
CHECK CheckActivated();
// Returns the parent domain if it is not the system area. Returns NULL if it is the
// system domain
BaseDomain* GetDomain();
BOOL GetModuleZapFile(LPCWSTR name, SString &path);
BOOL AllowUntrustedCaller();
#ifdef LOGGING
LPCWSTR GetDebugName()
{
WRAPPER_CONTRACT;
return GetManifestFile()->GetDebugName();
}
#endif
LPCUTF8 GetSimpleName()
{
WRAPPER_CONTRACT;
return GetManifestFile()->GetSimpleName();
}
BOOL IsStrongNamed()
{
WRAPPER_CONTRACT;
return GetManifestFile()->IsStrongNamed();
}
const void *GetPublicKey(DWORD *pcbPK)
{
WRAPPER_CONTRACT;
return GetManifestFile()->GetPublicKey(pcbPK);
}
ULONG GetHashAlgId()
{
WRAPPER_CONTRACT;
return GetManifestFile()->GetHashAlgId();
}
void GetVersion(USHORT *pMajor, USHORT *pMinor, USHORT *pBuild, USHORT *pRevision)
{
WRAPPER_CONTRACT;
return GetManifestFile()->GetVersion(pMajor, pMinor, pBuild, pRevision);
}
LPCUTF8 GetLocale()
{
WRAPPER_CONTRACT;
return GetManifestFile()->GetLocale();
}
DWORD GetFlags()
{
WRAPPER_CONTRACT;
return GetManifestFile()->GetFlags();
}
// Level of strong name support (dynamic assemblies only).
enum StrongNameLevel {
SN_NONE = 0,
SN_PUBLIC_KEY = 1,
SN_FULL_KEYPAIR_IN_ARRAY = 2,
SN_FULL_KEYPAIR_IN_CONTAINER = 3
};
StrongNameLevel GetStrongNameLevel()
{
LEAF_CONTRACT;
return m_eStrongNameLevel;
}
void SetStrongNameLevel(StrongNameLevel eLevel)
{
LEAF_CONTRACT;
m_eStrongNameLevel = eLevel;
}
// returns whether CAS policy needs to be resolved for this assembly
// or whether it's safe to skip that step.
BOOL ShouldSkipPolicyResolution ()
{
WRAPPER_CONTRACT;
return IsSystem() || IsIntrospectionOnly() || (m_isDynamic && !(m_dwDynamicAssemblyAccess & ASSEMBLY_ACCESS_RUN));
}
// Cached assembly level reliability contract info, see ConstrainedExecutionRegion.cpp for details.
inline DWORD GetReliabilityContract()
{
LEAF_CONTRACT;
return m_dwReliabilityContract;
}
inline void SetReliabilityContract(DWORD dwValue)
{
LEAF_CONTRACT;
m_dwReliabilityContract = dwValue;
}
LoaderHeap* GetLowFrequencyHeap();
LoaderHeap* GetHighFrequencyHeap();
LoaderHeap* GetStubHeap();
Module* GetManifestModule()
{
LEAF_CONTRACT;
return m_pManifest;
}
ReflectionModule* GetOnDiskManifestModule()
{
LEAF_CONTRACT;
return m_pOnDiskManifest;
}
BOOL NeedsToHideManifestForEmit()
{
return m_needsToHideManifestForEmit;
}
PEAssembly* GetManifestFile()
{
LEAF_CONTRACT;
return m_pManifestFile;
}
IMDInternalImport* GetManifestImport()
{
WRAPPER_CONTRACT;
return m_pManifestFile->GetPersistentMDImport();
}
#ifndef DACCESS_COMPILE
IMetaDataImport* GetManifestImporter()
{
WRAPPER_CONTRACT;
return m_pManifestFile->GetRWImporter();
}
IMetaDataAssemblyImport* GetManifestAssemblyImporter()
{
WRAPPER_CONTRACT;
return m_pManifestFile->GetAssemblyImporter();
}
#endif // DACCESS_COMPILE
mdAssembly GetManifestToken()
{
LEAF_CONTRACT;
return TokenFromRid(1, mdtAssembly);
}
#ifndef DACCESS_COMPILE
void GetDisplayName(SString &result, DWORD flags = 0)
{
WRAPPER_CONTRACT;
return m_pManifestFile->GetDisplayName(result, flags);
}
#endif // DACCESS_COMPILE
void GetCodeBase(SString &result)
{
WRAPPER_CONTRACT;
return m_pManifestFile->GetCodeBase(result);
}
// Initialize an AssemblySpec from an Assembly.
void GetAssemblySpec(Assembl