summaryrefslogtreecommitdiff
path: root/src/zap/zapimage.h
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/zap/zapimage.h
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/zap/zapimage.h')
-rw-r--r--src/zap/zapimage.h1334
1 files changed, 1334 insertions, 0 deletions
diff --git a/src/zap/zapimage.h b/src/zap/zapimage.h
new file mode 100644
index 0000000000..4ff0c41e5c
--- /dev/null
+++ b/src/zap/zapimage.h
@@ -0,0 +1,1334 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+//
+// ZapImage.h
+//
+
+//
+// NGEN-specific infrastructure for writing PE files.
+//
+// ======================================================================================
+
+#ifndef __ZAPIMAGE_H__
+#define __ZAPIMAGE_H__
+
+
+#ifdef CLR_STANDALONE_BINDER
+#include "nativedata.h"
+#endif
+
+class ZapMetaData;
+class ZapILMetaData;
+class ZapCorHeader;
+class ZapNativeHeader;
+class ZapVersionInfo;
+class ZapDependencies;
+class ZapCodeManagerEntry;
+
+class ZapReadyToRunHeader;
+
+class ZapInnerPtrTable;
+class ZapMethodEntryPointTable;
+class ZapWrapperTable;
+
+class ZapBaseRelocs;
+
+class ZapBlobWithRelocs;
+
+//class ZapGCInfoTable;
+#ifdef WIN64EXCEPTIONS
+class ZapUnwindDataTable;
+#endif
+
+class ZapImportTable;
+class ZapImportSectionsTable;
+class ZapImportSectionSignatures;
+
+class ZapVirtualSectionsTable;
+class DataImage;
+
+class ZapperStats;
+
+#undef SAFERELEASE
+#define SAFERELEASE(p) if ((p) != NULL) { IUnknown * _ = (p); (p) = NULL; _->Release(); };
+
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+#define DEFAULT_CODE_BUFFER_INIT 0xcc // breakpoint
+#else
+#define DEFAULT_CODE_BUFFER_INIT 0
+#endif
+
+#ifdef _WIN64
+// Optimize for speed
+#define DEFAULT_CODE_ALIGN 16
+#else
+// Optimize for size.
+#define DEFAULT_CODE_ALIGN 4
+#endif
+
+#ifdef _TARGET_ARM_
+#define MINIMUM_CODE_ALIGN 2
+#else
+#define MINIMUM_CODE_ALIGN 1
+#endif
+
+// Various zapper hashtables are preallocated based on the size of IL image to reduce amount of
+// rehashing we have to do. Turn ZAP_HASHTABLE_TUNING on to collect data for the tuning of initial hashtable sizes.
+// #define ZAP_HASHTABLE_TUNING
+
+#ifdef ZAP_HASHTABLE_TUNING
+
+#define PREALLOCATE_HASHTABLE(table, quotient, cbILImage) \
+ PREALLOCATE_HASHTABLE_NOT_NEEDED(table, cbILImage)
+
+#define PREALLOCATE_HASHTABLE_NOT_NEEDED(table, cbILImage) \
+ do { \
+ GetSvcLogger()->Printf(W("HashTable:\t%S\t%d\t%f\n"), #table, table.GetCount(), (double)table.GetCount() / (double)cbILImage); \
+ } while (0)
+
+#define PREALLOCATE_ARRAY(array, quotient, cbILImage) \
+ do { \
+ GetSvcLogger()->Printf(W("Array:\t%S\t%d\t%f\n"), #array, array.GetCount(), (double)array.GetCount() / (double)cbILImage); \
+ } while (0)
+
+#else // ZAP_HASHTABLE_TUNING
+
+#define PREALLOCATE_HASHTABLE(table, quotient, cbILImage) \
+ do { \
+ COUNT_T nSize = (COUNT_T)(quotient * \
+ ((double)table.s_density_factor_denominator / (double)table.s_density_factor_numerator) * \
+ cbILImage); \
+ if (nSize > table.s_minimum_allocation) \
+ table.Reallocate(nSize); \
+ } while (0)
+
+#define PREALLOCATE_HASHTABLE_NOT_NEEDED(table, cbILImage)
+
+#define PREALLOCATE_ARRAY(array, quotient, cbILImage) \
+ do { \
+ COUNT_T nSize = (COUNT_T)(quotient * \
+ cbILImage); \
+ array.Preallocate(nSize); \
+ } while (0)
+
+#endif // ZAP_HASHTABLE_TUNING
+
+//---------------------------------------------------------------------------------------
+//
+// ZapImportSectionType is enum describing import sections allocated in the image
+//
+enum ZapImportSectionType
+{
+ ZapImportSectionType_Handle, // Unspecified handle
+ ZapImportSectionType_TypeHandle, // Type and method handles have to have their own section so we can restore them correctly
+ ZapImportSectionType_MethodHandle,
+#ifdef _TARGET_ARM_
+ ZapImportSectionType_PCode, // Code pointers have to be in a own section on ARM because of they are tagged differently
+#endif
+ ZapImportSectionType_StringHandle, // String handles require special handling for interning
+ ZapImportSectionType_Count,
+
+ ZapImportSectionType_Hot = 0, // We have two sets of the section - hot and cold
+ ZapImportSectionType_Cold = ZapImportSectionType_Count,
+
+ ZapImportSectionType_Eager = 2 * ZapImportSectionType_Count, // And one section for eager loaded handles
+
+ ZapImportSectionType_Total = 2 * ZapImportSectionType_Count + 1,
+};
+
+#include "zaprelocs.h"
+#include "zapinfo.h"
+#include "zapcode.h"
+
+#ifdef MDIL
+class ICompactLayoutWriter;
+#endif
+
+class ZapImage
+ : public ZapWriter
+ , public ICorCompileDataStore
+{
+ friend class Zapper;
+ friend class ZapInfo;
+ friend class ZapILMetaData;
+ friend class ZapImportTable;
+ friend class ZapCodeMethodDescs;
+ friend class ZapColdCodeMap;
+ friend class ZapReadyToRunHeader;
+
+ private:
+
+ Zapper *m_zapper;
+
+ //
+ // Output module
+ //
+
+ LPWSTR m_pOutputFileFullName; // Name of the temp ngen file to generate (including the path)
+
+ //
+ // Make all virtual section pointers public for now. It should be cleaned up as we get more sophisticated layout
+ // algorithm in place.
+ //
+public:
+ ZapPhysicalSection * m_pTextSection;
+
+ //
+ // All virtual sections of the native image in alphabetical order
+ //
+
+ ZapVirtualSection * m_pBaseRelocsSection;
+ ZapVirtualSection * m_pCodeSection;
+ ZapVirtualSection * m_pColdCodeSection;
+ ZapVirtualSection * m_pDebugSection;
+ ZapVirtualSection * m_pDelayLoadInfoDelayListSectionEager;
+ ZapVirtualSection * m_pDelayLoadInfoDelayListSectionCold;
+ ZapVirtualSection * m_pDelayLoadInfoDelayListSectionHot;
+ ZapVirtualSection * m_pDelayLoadInfoTableSection[ZapImportSectionType_Total];
+ ZapVirtualSection * m_pStubsSection;
+ ZapVirtualSection * m_pEETableSection;
+ ZapVirtualSection * m_pExceptionSection;
+ ZapVirtualSection * m_pGCSection;
+ ZapVirtualSection * m_pHeaderSection;
+ ZapVirtualSection * m_pHelperTableSection;
+ ZapVirtualSection * m_pLazyHelperSection;
+ ZapVirtualSection * m_pLazyMethodCallHelperSection;
+ ZapVirtualSection * m_pHotCodeSection;
+ ZapVirtualSection * m_pHotGCSection;
+ ZapVirtualSection * m_pHotTouchedGCSection;
+ ZapVirtualSection * m_pILMetaDataSection;
+ ZapVirtualSection * m_pILSection;
+ ZapVirtualSection * m_pImportTableSection;
+ ZapVirtualSection * m_pInstrumentSection;
+ ZapVirtualSection * m_pMetaDataSection;
+ ZapVirtualSection * m_pReadOnlyDataSection;
+ ZapVirtualSection * m_pResourcesSection;
+ ZapVirtualSection * m_pWin32ResourceSection;
+ ZapVirtualSection * m_pStubDispatchCellSection;
+ ZapVirtualSection * m_pStubDispatchDataSection;
+ ZapVirtualSection * m_pDynamicHelperCellSection;
+ ZapVirtualSection * m_pDynamicHelperDataSection;
+ ZapVirtualSection * m_pVirtualImportThunkSection;
+ ZapVirtualSection * m_pExternalMethodThunkSection;
+ ZapVirtualSection * m_pExternalMethodCellSection;
+ ZapVirtualSection * m_pExternalMethodDataSection;
+ ZapVirtualSection * m_pHotRuntimeFunctionSection;
+ ZapVirtualSection * m_pRuntimeFunctionSection;
+ ZapVirtualSection * m_pColdRuntimeFunctionSection;
+ ZapVirtualSection * m_pHotCodeMethodDescsSection;
+ ZapVirtualSection * m_pCodeMethodDescsSection;
+ ZapVirtualSection * m_pHotRuntimeFunctionLookupSection;
+ ZapVirtualSection * m_pRuntimeFunctionLookupSection;
+ ZapVirtualSection * m_pColdCodeMapSection;
+#if defined(WIN64EXCEPTIONS)
+ ZapVirtualSection * m_pHotUnwindDataSection;
+ ZapVirtualSection * m_pUnwindDataSection;
+ ZapVirtualSection * m_pColdUnwindDataSection;
+#endif // defined(WIN64EXCEPTIONS)
+
+#ifdef MDIL
+ ZapVirtualSection * m_pMDILSection;
+#endif
+ // Preloader sections
+ ZapVirtualSection * m_pPreloadSections[CORCOMPILE_SECTION_COUNT];
+
+ ZapExceptionInfoLookupTable* m_pExceptionInfoLookupTable;
+public:
+ // TODO: Remove once all EE datastructures are converted to ZapNodes
+ ICorCompilePreloader * m_pPreloader;
+ DataImage * m_pDataImage;
+
+public:
+ // TODO: The stats should be removed once we have all information available in nidump
+ ZapperStats *m_stats;
+
+private:
+ IMetaDataAssemblyEmit *m_pAssemblyEmit; // native image manifest
+ ZapMetaData * m_pAssemblyMetaData;
+#ifdef CLR_STANDALONE_BINDER
+ SArray<NativeManifestData> m_pNativeManifestData;
+public:
+#ifdef BINDER
+ static const ULONG m_selfIndex = 0; // position of "self dependency" in m_pNativeManifestData
+#else
+ ULONG m_selfIndex; // position of "self dependency" in m_pNativeManifestData
+#endif // BINDER
+
+private:
+#endif
+
+ ZapVersionInfo * m_pVersionInfo;
+ ZapDependencies * m_pDependencies;
+
+ SString m_pdbFileName;
+
+ ZapCodeManagerEntry * m_pCodeManagerEntry;
+
+ ZapBlob * m_pEEInfoTable;
+
+ //
+ // Auxiliary tables
+ //
+ ZapImportTable * m_pImportTable;
+
+ ZapImportSectionsTable * m_pImportSectionsTable;
+
+ ZapInnerPtrTable * m_pInnerPtrs;
+
+ ZapMethodEntryPointTable * m_pMethodEntryPoints;
+
+ ZapWrapperTable * m_pWrappers;
+
+ ZapBaseRelocs * m_pBaseRelocs;
+
+ ULONGLONG m_NativeBaseAddress;
+
+ ULONGLONG GetNativeBaseAddress()
+ {
+ return m_NativeBaseAddress;
+ }
+
+ void CalculateZapBaseAddress();
+
+ // Preallocate hashtables to avoid rehashing
+ void Preallocate();
+
+ ZapGCInfoTable * m_pGCInfoTable;
+
+#ifdef WIN64EXCEPTIONS
+ ZapUnwindDataTable * m_pUnwindDataTable;
+#endif
+
+ ZapImportSectionSignatures * m_pDelayLoadInfoDataTable[ZapImportSectionType_Total];
+ ZapImportSectionSignatures * m_pStubDispatchDataTable;
+ ZapImportSectionSignatures * m_pExternalMethodDataTable;
+ ZapImportSectionSignatures * m_pDynamicHelperDataTable;
+
+ ZapVirtualSectionsTable * m_pVirtualSectionsTable;
+
+ ZapDebugInfoTable * m_pDebugInfoTable;
+#ifdef MDIL
+ MdilDebugInfoTable * m_pMdilDebugInfoTable;
+#endif
+
+ ZapILMetaData * m_pILMetaData;
+
+ ZapCorHeader * m_pCorHeader;
+
+ ZapNode * m_pResources;
+
+ ZapNode * m_pNativeHeader;
+
+ ZapBlob * m_pNGenPdbDebugData;
+
+ ULONG m_totalHotCodeSize;
+ ULONG m_totalColdCodeSize;
+
+ ULONG m_totalCodeSizeInProfiledMethods;
+ ULONG m_totalColdCodeSizeInProfiledMethods;
+
+ //information to track the boundaries of the different subsections within
+ //the hot section.
+ COUNT_T m_iIBCMethod;
+ COUNT_T m_iGenericsMethod;
+ COUNT_T m_iUntrainedMethod;
+
+ //
+ // Input module
+ //
+
+ LPWSTR m_pModuleFileName; // file name of the module being compiled, including path
+ CORINFO_MODULE_HANDLE m_hModule; // Module being compiled
+ PEDecoder m_ModuleDecoder;
+ IMDInternalImport * m_pMDImport;
+ bool m_fManifestModule; // Is this the assembly-manifest-module
+ bool m_fHaveProfileData;
+
+ ZapNode ** m_pHelperThunks; // Array of on demand allocated JIT helper thunks
+
+ //
+ // Profile source
+ //
+
+ BYTE * m_profileDataFile;
+ BYTE * m_pRawProfileData;
+ COUNT_T m_cRawProfileData;
+ CorProfileData * m_pCorProfileData;
+
+ // ProfileData hash table
+ struct ProfileDataHashEntry
+ {
+ mdMethodDef md; // A copy of the method.token of the profile data
+ DWORD size; // A copy of the size of the profile data
+ ULONG pos;
+ };
+
+ class ProfileDataHashTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ProfileDataHashEntry> >
+ {
+ public:
+ typedef const mdMethodDef key_t;
+
+ static key_t GetKey(element_t e)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return e.md;
+ }
+ static BOOL Equals(key_t k1, key_t k2)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return k1 == k2;
+ }
+ static count_t Hash(key_t k)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (count_t)k;
+ }
+
+ static const element_t Null() { LIMITED_METHOD_CONTRACT; ProfileDataHashEntry e; e.pos = 0; e.size = 0; e.md = 0; return e; } // Assuming method profile data cannot start from position 0.
+ static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.pos == 0; }
+ };
+ typedef SHash<ProfileDataHashTraits> ProfileDataHashTable;
+
+ ProfileDataHashTable profileDataHashTable;
+
+#ifndef BINDER
+ SArray<SString, FALSE> fileNotFoundErrorsTable;
+ void FileNotFoundError(LPCWSTR pszMessage);
+#endif // BINDER
+
+public:
+ struct ProfileDataSection
+ {
+ BYTE *pData;
+ DWORD dataSize;
+ DWORD tableSize;
+ CORBBTPROF_TOKEN_INFO *pTable;
+ };
+
+private:
+ ProfileDataSection m_profileDataSections[SectionFormatCount];
+
+ DWORD m_profileDataNumRuns;
+
+ CorInfoRegionKind m_currentRegionKind;
+
+ BOOL IsAssemblyBeingCompiled(CORINFO_MODULE_HANDLE module) {
+ return ((module == m_hModule) ||
+ (m_zapper->m_pEECompileInfo->GetModuleAssembly(module) == m_zapper->m_hAssembly));
+ }
+
+ class ZapMethodTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ZapMethodHeader *> >
+ {
+ public:
+ typedef CORINFO_METHOD_HANDLE key_t;
+
+ static key_t GetKey(element_t e)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return e->GetHandle();
+ }
+ static BOOL Equals(key_t k1, key_t k2)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return k1 == k2;
+ }
+ static count_t Hash(key_t k)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (count_t)(size_t)k;
+ }
+ };
+
+ typedef SHash<ZapMethodTraits> ZapMethodHashTable;
+
+ ZapMethodHashTable m_CompiledMethods;
+
+ SArray<ZapMethodHeader *> m_MethodCompilationOrder;
+
+ SArray<ZapGCInfo *> m_PrioritizedGCInfo;
+
+#ifndef FEATURE_FULL_NGEN
+ class MethodCodeTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ZapMethodHeader *> >
+ {
+ public:
+ typedef ZapMethodHeader * key_t;
+
+ static FORCEINLINE key_t GetKey(element_t e)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return e;
+ }
+
+ static BOOL Equals(key_t k1, key_t k2);
+ static COUNT_T Hash(key_t k);
+
+ static const element_t Null() { LIMITED_METHOD_CONTRACT; return NULL; }
+ static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e == NULL; }
+ };
+
+ typedef SHash <MethodCodeTraits> ZapMethodCodeHashTable;
+
+ ZapMethodCodeHashTable m_CodeDeduplicator;
+#endif // FEATURE_FULL_NGEN
+
+ struct ClassLayoutOrderEntry
+ {
+ CORINFO_CLASS_HANDLE m_cls;
+ unsigned m_order;
+
+ ClassLayoutOrderEntry()
+ : m_cls(0), m_order(0)
+ {
+ }
+
+ ClassLayoutOrderEntry(CORINFO_CLASS_HANDLE cls, unsigned order)
+ : m_cls(cls), m_order(order)
+ {
+ }
+ };
+
+ class ClassLayoutOrderTraits : public NoRemoveSHashTraits< DefaultSHashTraits<ClassLayoutOrderEntry> >
+ {
+ public:
+ typedef CORINFO_CLASS_HANDLE key_t;
+
+ static key_t GetKey(element_t e)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return e.m_cls;
+ }
+ static BOOL Equals(key_t k1, key_t k2)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return k1 == k2;
+ }
+ static count_t Hash(key_t k)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (count_t)(size_t)k;
+ }
+ static const element_t Null() { LIMITED_METHOD_CONTRACT; return element_t(0,0); }
+ static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return e.m_cls == 0; }
+ };
+
+ typedef SHash<ClassLayoutOrderTraits> ClassLayoutOrderHashTable;
+
+ ClassLayoutOrderHashTable m_ClassLayoutOrder;
+
+ // See ComputeClassLayoutOrder for an explanation of these flags
+ #define UNSEEN_CLASS_FLAG (0x80000000)
+ #define METHOD_INDEX_FLAG (0x40000000)
+
+ // The class layout order needs to be initialized with the first index
+ // in m_MethodCompilationOrder of a method in the given class.
+ inline void InitializeClassLayoutOrder(CORINFO_CLASS_HANDLE cls, unsigned order)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ if (!m_ClassLayoutOrder.LookupPtr(cls))
+ {
+ ClassLayoutOrderEntry entry(cls, order | UNSEEN_CLASS_FLAG | METHOD_INDEX_FLAG);
+ m_ClassLayoutOrder.Add(entry);
+ }
+ }
+
+public:
+ inline unsigned LookupClassLayoutOrder(CORINFO_CLASS_HANDLE cls)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ const ClassLayoutOrderEntry *pEntry = m_ClassLayoutOrder.LookupPtr(cls);
+ _ASSERTE(!pEntry || pEntry->m_order != 0);
+
+ return pEntry ? pEntry->m_order : 0;
+ }
+
+private:
+
+ //
+ // The image layout algorithm
+ //
+
+ enum CodeType
+ {
+ ProfiledHot,
+ ProfiledCold,
+ Unprofiled
+ };
+
+ ZapVirtualSection * GetCodeSection(CodeType codeType);
+ ZapVirtualSection * GetRuntimeFunctionSection(CodeType codeType);
+ ZapVirtualSection * GetCodeMethodDescSection(CodeType codeType);
+ ZapVirtualSection * GetUnwindInfoLookupSection(CodeType codeType);
+
+#if defined(WIN64EXCEPTIONS)
+ ZapVirtualSection * GetUnwindDataSection(CodeType codeType);
+#endif
+
+ void GetCodeCompilationRange(CodeType codeType, COUNT_T * start, COUNT_T * end);
+
+ void OutputCode(CodeType codeType);
+ void OutputCodeInfo(CodeType codeType);
+
+ void OutputGCInfo();
+
+ void OutputDebugInfo();
+ void OutputProfileData();
+
+ void OutputEntrypointsTableForReadyToRun();
+ void OutputDebugInfoForReadyToRun();
+
+ void CopyDebugDirEntry();
+ void CopyWin32VersionResource();
+
+ void OutputManifestMetadata();
+ void OutputTables();
+
+ // Assign RVAs to all ZapNodes
+ void ComputeRVAs();
+
+ HANDLE GenerateFile(LPCWSTR wszOutputFileName, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig);
+
+ void PrintStats(LPCWSTR wszOutputFileName);
+
+ bool m_fHasClassLayoutOrder;
+
+ void ComputeClassLayoutOrder();
+ void SortUnprofiledMethodsByClassLayoutOrder();
+
+ HRESULT GetPdbFileNameFromModuleFilePath(__in_z const wchar_t *pwszModuleFilePath,
+ __out_ecount(dwPdbFileNameBufferSize) char * pwszPdbFileName,
+ DWORD dwPdbFileNameBufferSize);
+
+#ifdef MDIL
+ void LoadMDILSection();
+
+ void MethodCompileComplete_MDIL(BYTE *pCode, ULONG cCode);
+
+ void Output_MDIL();
+public:
+ DWORD Write_MDIL(FILE *outputFile);
+private:
+ void EncodeGenericInstances_MDIL();
+
+ void UnifyGenericInstances_MDIL(ZapInfo::MDILGenericMethodDesc *pMD);
+
+ COUNT_T EncodeGenericInstance_MDIL(ZapInfo::MDILGenericMethodDesc *pMD);
+
+ enum CodeKind
+ {
+ GENERIC_CODE,
+ NON_GENERIC_CODE,
+ CODE_KIND_COUNT,
+ };
+
+ SArray<BYTE> m_codeBuffer[CODE_KIND_COUNT]; // the buffer holding the finished MDIL code
+ // for all compiled methods, including a method header
+ // indicating the length, and the exception tables
+ // the first four bytes are a magic DWORD, so offset 0 is invalid
+ // we wish to keep MDIL code possibly referenced from dependencies
+ // (currently only generic code) separate from MDIL code only used
+ // during translation of the module itself
+ ULONG m_codeOffs[CODE_KIND_COUNT]; // code offset of the header of the current method
+
+ SArray<ULONG> m_mapMethodRidToOffs; // offset in code buffer for each method def rid.
+ // 0 means no MDIL code available.
+ static const ULONG GENERIC_METHOD_REF = 0x80000000; // hi bit on means this is a reference to a generic method descriptor
+ // that in turn points to the method bodies
+
+ ULONG m_methodRidCount; // number of valid entries in the m_mapMethodRidToOffs table
+
+ ULONG m_mergedGenericSize;
+ ULONG m_unmergedGenericSize;
+ ULONG m_mergedGenericCount;
+ ULONG m_unmergedGenericCount;
+
+ ULONG m_stubMethodCount;
+
+ ULONG m_assemblyName;
+ ULONG m_locale;
+ AssemblyMetaDataInternal m_assemblyData;
+ ULONG m_neutralResourceCultureNameLen;
+ DWORD m_cultureName;
+ USHORT m_neutralResourceFallbackLocation;
+
+ SArray<ZapInfo::MDILGenericMethodDesc *> m_mapGenericMethodToDesc; // maps a method rid to a list of instances
+
+ SArray<BYTE> m_genericInstPool; // where the flavor -> mdil body maps are stored
+
+ BYTE * m_pMdilPESectionData;
+ DWORD m_cbMdilPESectionData;
+ struct ModuleZapImage
+ {
+ CORINFO_MODULE_HANDLE m_module;
+ ZapImage *m_zapImage;
+ };
+
+ SArray<ModuleZapImage> m_mdilImages;
+
+ int CheckForUnmerged(ZapInfo::MDILGenericMethodDesc tab[], int last, ZapInfo::FlavorSet flavorsToMatch, __in_z WCHAR *message);
+
+ ICompactLayoutWriter *m_pICLW;
+
+ SArray<BYTE> m_stubBuffer; // the buffer holding all IL stub descriptions
+ SArray<BYTE> m_stubAssocBuffer; // the buffer with method -> IL stub associations
+
+ SArray<BYTE> m_debugInfoBuffer[CODE_KIND_COUNT]; // the buffer holding the debug info for all compiled methods
+ // the first four bytes are a magic DWORD, so offset 0 is invalid
+ // as for code, we want to keep information possibly referenced from dependencies
+ // (currently only generic code) separate from information used only
+ // during translation of the module itself so we keep two buffers
+ SArray<ULONG> m_mapMethodRidToDebug; // offset in debug info buffer for each method def rid.
+ // before adjusting the offsets to account for the generic code buffer:
+ // 0xFFFFFFFF indicates no debug data and 0 is a valid offset
+ // after adjusting the offsets, aka what is written to file:
+ // 0xFFFFFFFF is valid (albeit never generated) and 0 indicates no debug data
+
+public:
+
+ Zapper *GetZapper()
+ {
+ return m_zapper;
+ }
+
+ // remember the assembly data
+ void SetAssemblyNameAndLocale(ULONG assembly, ULONG locale, AssemblyMetaDataInternal *assemblyData) {
+ m_assemblyName = assembly;
+ m_locale = locale;
+ m_assemblyData = *assemblyData;
+ }
+
+ // Set neutral resource culture information
+ void SetNeutralResourceInfo(ULONG neutralResourceCultureNameLen, DWORD cultureName, USHORT neutralResourceFallbackLocation)
+ {
+ m_neutralResourceCultureNameLen = neutralResourceCultureNameLen;
+ m_cultureName = cultureName;
+ m_neutralResourceFallbackLocation = neutralResourceFallbackLocation;
+ }
+
+ // Should compact layout info be generated?
+ bool DoCompactLayout()
+ {
+ return (m_zapper->m_pOpt->m_compilerFlags & CORJIT_FLG_MDIL) != 0;
+ }
+
+ // Flush a serialized representation of a type
+ void FlushCompactLayoutData(mdToken typeToken, BYTE *pData, ULONG cData);
+
+ // Flush the IL stub data
+ void FlushStubData(BYTE *pStubSize, ULONG cStubSize,
+ BYTE *pStubData, ULONG cStubData,
+ BYTE *pStubAssocData, ULONG cStubAssocData);
+
+ // Flush the user string pool
+ void FlushUserStringPool(BYTE *pData, ULONG cData);
+
+ // Flush the well known types table
+ void FlushWellKnownTypes(DWORD *wellKnownTypesTable, SIZE_T count);
+
+ struct ExtModRef
+ {
+ enum ExtModRefFlags
+ {
+ NO_FLAGS = 0x0000,
+ IS_FROM_IL_METADATA = 0x0001,
+ IS_EAGERLY_BOUND = 0x0002,
+ IS_MODULE_REF = 0x0004,
+ IS_LOCAL_MODULE = 0x0008,
+ };
+
+ ULONG name; // offset of name in name pool
+ ExtModRefFlags flags;
+ };
+
+ SArray<ExtModRef> m_extModRef;
+
+ SArray<char> m_namePool;
+
+ struct ExtTypeRef
+ {
+ ULONG module : 14; // 16383 max modules to import from
+ ULONG ordinal : 18; // 262143 max types within a module
+ // Just like metadata does today, I'm planning to use
+ // wider tables when necessary
+ };
+
+#ifndef BINDER
+ SArray<ExtTypeRef> m_extTypeRef;
+
+ struct ExtTypeRefExtend
+ {
+ ULONG resolutionScope; // Rid in ExtTypeRef table of containing type (currently only used for nested types, all other type have a 0)
+ ULONG name_space; // offset of namespace in name pool
+ ULONG name; // offset of name in name pool
+ };
+
+ SArray<ExtTypeRefExtend> m_extTypeRefExtend;
+#endif // !BINDER
+
+ struct ExtMemberRef
+ {
+ ULONG typeRid : 15; // 32767 max types to import
+ ULONG isTypeSpec : 1;
+ ULONG isField : 1; // is this a field or a method?
+ ULONG ordinal : 15; // 32767 max fields or methods in a type
+ // Just like metadata does today, I'm planning to use
+ // wider tables when necessary
+ };
+
+ SArray<ExtMemberRef> m_extMemberRef;
+
+#ifndef BINDER
+ struct ExtMemberRefExtend
+ {
+ ULONG name; // offset of name in name pool
+ ULONG signature; // offset of signature.
+ };
+
+ SArray<ExtMemberRefExtend> m_extMemberRefExtend;
+#endif // !BINDER
+
+ SArray<ULONG> m_typeSpecToOffs;
+ SArray<ULONG> m_methodSpecToOffs;
+ SArray<ULONG> m_signatureToOffs;
+ SArray<BYTE> m_compactLayoutBuffer; // the buffer holding the finished compact layout data
+ // the first four bytes are a magic DWORD, so offset 0 is invalid
+
+ void SetCompactLayoutWriter(ICompactLayoutWriter *pICLW)
+ {
+ m_pICLW = pICLW;
+ }
+
+ ICompactLayoutWriter *GetCompactLayoutWriter()
+ {
+ return m_pICLW;
+ }
+
+#ifdef BINDER
+ void Output()
+ {
+ OutputCode(ProfiledHot);
+ OutputCode(Unprofiled);
+ OutputCode(ProfiledCold);
+
+ OutputCodeInfo(ProfiledHot);
+ OutputCodeInfo(ProfiledCold); // actually both Unprofiled and ProfiledCold
+
+ OutputGCInfo();
+ OutputDebugInfo();
+ OutputProfileData();
+ }
+#ifdef CLR_STANDALONE_BINDER
+ void EmitMethodIL(mdToken methodDefToken);
+ void EmitFieldRVA(mdToken fieldDefToken, RVA fieldRVA);
+#endif
+#endif
+
+private:
+
+ SArray<ULONG> m_mapTypeRidToOffs; // offset in compact layout buffer for each typedef rid
+ ULONG m_compactLayoutOffs; // offset of the current type in the compact layout data
+ ULONG m_typeRidCount; // number of valid entries in the m_mapTypeRidToOffs table
+ SArray<BYTE> m_userStringPool; // this is the user string pool exactly like it is in meta data
+ SArray<DWORD> m_wellKnownTypesTable; // this is an array of type def tokens for the well known types
+#endif
+
+public:
+ ZapImage(Zapper *zapper);
+ ~ZapImage();
+
+ // ----------------------------------------------------------------------------------------------------------
+ //
+ // Utility function for converting ZapWriter * to ZapImage *. This cast should not be done directly by the code
+ // so that the relationship between ZapWriter and ZapImage is abstracted away.
+ //
+ static ZapImage * GetImage(ZapWriter * pZapWriter)
+ {
+ return (ZapImage *)pZapWriter;
+ }
+
+ // ----------------------------------------------------------------------------------------------------------
+ //
+ // Add relocation record. This method is meant to be called from the Save method of custom ZapNodes right
+ // before the given datastructure is written into the native image.
+ //
+ // Arguments:
+ // pSrc - the datastructure being written
+ // offset - offset of the relocation within the datastructure
+ // pTarget - target of the relocation
+ // targetOffset - adjusment of the target (usually 0)
+ // type - relocation type (IMAGE_REL_BASED_XXX enum, note that we have private additions to this enum:
+ // IMAGE_REL_BASED_PTR - architecture specific reloc of virtual address
+ // IMAGE_REL_BASED_ABSOLUTE_TAGGED - absolute stored in the middle 30-bits, used for fixups.
+ // IMAGE_REL_BASED_RELPTR - pointer stored as address relative delta
+ // IMAGE_REL_BASED_RELPTR32 - pointer stored as address relative 32-bit delta
+ //
+ void WriteReloc(PVOID pSrc, int offset, ZapNode * pTarget, int targetOffset, ZapRelocationType type);
+
+ void Open(CORINFO_MODULE_HANDLE hModule, IMetaDataAssemblyEmit *pEmit);
+
+ void InitializeSections();
+ void InitializeSectionsForReadyToRun();
+
+ // Wrapper of ZapWriter::NewVirtualSection that sets sectionType
+ ZapVirtualSection * NewVirtualSection(ZapPhysicalSection * pPhysicalSection, DWORD sectionType /* ZapVirtualSectionType */, DWORD dwAlignment = 16, ZapVirtualSection * pInsertAfter = NULL)
+ {
+ ZapVirtualSection * pSection = ZapWriter::NewVirtualSection(pPhysicalSection, dwAlignment, pInsertAfter);
+ pSection->SetSectionType(sectionType);
+ return pSection;
+ }
+
+ void AllocateVirtualSections();
+
+ HANDLE SaveImage(LPCWSTR wszOutputFileName, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig);
+
+ void Preload();
+ void LinkPreload();
+
+#ifdef BINDER
+ void SetNativeVersionResource(PVOID pvVersionResourceBlob, SIZE_T cbVersionResource);
+#endif
+ void SetVersionInfo(CORCOMPILE_VERSION_INFO * pVersionInfo);
+ void SetDependencies(CORCOMPILE_DEPENDENCY *pDependencies, DWORD cDependencies);
+ void SetPdbFileName(const SString &strFileName);
+
+#ifdef CLR_STANDALONE_BINDER
+ void AddNativeDependency (NativeManifestData * pNativeManifestData) {
+ m_pNativeManifestData.Append(*pNativeManifestData);
+ }
+#endif
+
+#ifdef WIN64EXCEPTIONS
+ void SetRuntimeFunctionsDirectoryEntry();
+#endif
+
+ void SaveCorHeader();
+ void SaveNativeHeader();
+ void SaveCodeManagerEntry();
+
+ void Compile();
+
+ ZapMethodHeader * GetCompiledMethod(CORINFO_METHOD_HANDLE handle)
+ {
+ return m_CompiledMethods.Lookup(handle);
+ }
+
+
+ enum CompileStatus { LOOKUP_FAILED = -2, COMPILE_FAILED = -1, // Failure
+ NOT_COMPILED = 0, COMPILE_EXCLUDED = 1, // Info
+ COMPILE_SUCCEED = 10, ALREADY_COMPILED = 11}; // Success
+
+ static void __stdcall TryCompileMethodStub(LPVOID pContext, CORINFO_METHOD_HANDLE hStub, DWORD dwJitFlags);
+
+ BOOL IsVTableGapMethod(mdMethodDef md);
+
+ CompileStatus TryCompileMethodDef(mdMethodDef md, unsigned methodProfilingDataFlags);
+ CompileStatus TryCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle, unsigned methodProfilingDataFlags);
+ CompileStatus TryCompileMethodWorker(CORINFO_METHOD_HANDLE handle, mdMethodDef md, unsigned methodProfilingDataFlags);
+
+ BOOL ShouldCompileMethodDef(mdMethodDef md);
+ BOOL ShouldCompileInstantiatedMethod(CORINFO_METHOD_HANDLE handle);
+
+ bool canIntraModuleDirectCall(CORINFO_METHOD_HANDLE callerFtn,
+ CORINFO_METHOD_HANDLE targetFtn,
+ CorInfoIndirectCallReason *pReason = NULL,
+ CORINFO_ACCESS_FLAGS accessFlags = CORINFO_ACCESS_ANY);
+
+ CORINFO_MODULE_HANDLE GetModuleHandle()
+ {
+ return m_hModule;
+ }
+
+ IMetaDataAssemblyEmit * GetAssemblyEmit()
+ {
+ return m_pAssemblyEmit;
+ }
+
+ ZapWrapperTable * GetWrappers()
+ {
+ return m_pWrappers;
+ }
+
+ ZapImportTable * GetImportTable()
+ {
+ return m_pImportTable;
+ }
+
+ ZapImportSectionsTable * GetImportSectionsTable()
+ {
+ return m_pImportSectionsTable;
+ }
+
+ ZapNode * GetEEInfoTable()
+ {
+ return m_pEEInfoTable;
+ }
+
+ ZapReadyToRunHeader * GetReadyToRunHeader()
+ {
+ _ASSERTE(IsReadyToRunCompilation());
+ return (ZapReadyToRunHeader *)m_pNativeHeader;
+ }
+
+ ZapNode * GetInnerPtr(ZapNode * pNode, SSIZE_T offset);
+
+ CorInfoRegionKind GetCurrentRegionKind()
+ {
+ return m_currentRegionKind;
+ }
+
+ //
+ // Called from ZapImportTable::PlaceBlob
+ // to determine wheather to place the new signature Blob
+ // into the HotImports or the ColdImports section.
+ //
+ // The Assert will fire if BeginRegion was not called
+ // to setup the region
+ //
+ bool IsCurrentCodeRegionHot()
+ {
+ if (GetCurrentRegionKind() == CORINFO_REGION_HOT)
+ {
+ return true;
+ }
+ else if (GetCurrentRegionKind() == CORINFO_REGION_COLD)
+ {
+ return false;
+ }
+ _ASSERTE(!"unsupported RegionKind");
+ return false;
+ }
+
+ //
+ // Marks the start of a region where we want to place any
+ // new signature Blobs into the Hot/Cold region
+ //
+ void BeginRegion(CorInfoRegionKind regionKind)
+ {
+ _ASSERTE(GetCurrentRegionKind() == CORINFO_REGION_NONE);
+ m_currentRegionKind = regionKind;
+ }
+
+ //
+ // Marks the end of a region and we no longer expect to
+ // need any new signature Blobs
+ //
+ void EndRegion(CorInfoRegionKind regionKind)
+ {
+ _ASSERTE(GetCurrentRegionKind() == regionKind);
+ m_currentRegionKind = CORINFO_REGION_NONE;
+ }
+
+ ICorCompilationDomain * GetDomain()
+ {
+ return m_zapper->m_pDomain;
+ }
+
+ ICorDynamicInfo * GetJitInfo()
+ {
+ return m_zapper->m_pEEJitInfo;
+ }
+
+ ICorCompileInfo * GetCompileInfo()
+ {
+ return m_zapper->m_pEECompileInfo;
+ }
+
+ ZapperOptions * GetZapperOptions()
+ {
+ return m_zapper->m_pOpt;
+ }
+
+ ZapNode * GetHelperThunkIfExists(CorInfoHelpFunc ftnNum)
+ {
+ return m_pHelperThunks[ftnNum];
+ }
+
+ ZapNode * GetHelperThunk(CorInfoHelpFunc ftnNum);
+
+ BOOL HasClassLayoutOrder()
+ {
+ return m_fHasClassLayoutOrder;
+ }
+
+ HRESULT PrintTokenDescription(CorZapLogLevel level, mdToken token);
+
+ // ICorCompileDataStore
+
+ // Returns ZapImage
+ virtual ZapImage * GetZapImage();
+ void Error(mdToken token, HRESULT error, LPCWSTR message);
+
+ // Returns virtual section for EE datastructures
+ ZapVirtualSection * GetSection(CorCompileSection section)
+ {
+ return m_pPreloadSections[section];
+ }
+
+ HRESULT LocateProfileData();
+ HRESULT parseProfileData ();
+ HRESULT convertProfileDataFromV1();
+ void RehydrateBasicBlockSection();
+ void RehydrateTokenSection(int sectionFormat, unsigned int flagTable[255]);
+ void RehydrateBlobStream();
+ HRESULT RehydrateProfileData();
+ HRESULT hashBBProfileData ();
+
+ void LoadProfileData();
+ CorProfileData * NewProfileData();
+ CorProfileData * GetProfileData();
+ bool CanConvertIbcData();
+
+ CompileStatus CompileProfileDataWorker(mdToken token, unsigned methodProfilingDataFlags);
+ void CompileProfileData();
+#ifdef CLR_STANDALONE_BINDER
+ PEDecoder *GetPEDecoder()
+ {
+ return &m_ModuleDecoder;
+ }
+
+ ZapMethodEntryPoint *GetMethodEntryPoint(CORINFO_METHOD_HANDLE handle, CORINFO_ACCESS_FLAGS accessFlags)
+ {
+ return m_pMethodEntryPoints->GetMethodEntryPoint(handle, accessFlags);
+ }
+#endif
+};
+
+class BinaryWriter
+{
+private:
+ char *m_buffer;
+ unsigned int m_length;
+ unsigned int m_currentPosition;
+ ZapHeap *m_heap;
+
+private:
+ // Make sure that the buffer is at least newLength bytes long;
+ // expand it if necessary.
+ void RequireLength(unsigned int newLength)
+ {
+ if (newLength <= m_length)
+ {
+ return;
+ }
+
+ if (newLength < (m_length * 3) / 2)
+ {
+ newLength = (m_length * 3) / 2;
+ }
+
+ char *newBuffer = new (m_heap) char[newLength];
+
+ memcpy(newBuffer, m_buffer, m_length);
+
+ m_length = newLength;
+ m_buffer = newBuffer;
+ }
+
+public:
+ BinaryWriter(unsigned int initialLength, ZapHeap *heap)
+ {
+ m_heap = heap;
+ m_length = initialLength;
+ m_buffer = new (m_heap) char[initialLength];
+ m_currentPosition = 0;
+ }
+
+ template <typename T>
+ void WriteAt(unsigned int position, const T &v)
+ {
+ RequireLength(position + sizeof(T));
+
+ *(T *)(m_buffer + position) = v;
+ }
+
+ template <typename T>
+ void Write(const T &v)
+ {
+ WriteAt<T>(m_currentPosition, v);
+ m_currentPosition += sizeof(T);
+ }
+
+ void Write(const char *data, unsigned int length)
+ {
+ RequireLength(m_currentPosition + length);
+
+ memcpy(m_buffer + m_currentPosition, data, length);
+ m_currentPosition += length;
+ }
+
+ BYTE *GetBuffer()
+ {
+ return (BYTE *)m_buffer;
+ }
+
+ unsigned int GetWrittenSize()
+ {
+ return m_currentPosition;
+ }
+};
+
+class ProfileReader
+{
+public:
+ ProfileReader(void *buffer, ULONG length)
+ {
+ profileBuffer = (char *) buffer;
+ bufferSize = length;
+ currentPos = 0;
+ }
+
+ bool Seek(ULONG pos)
+ {
+ if (pos <= bufferSize)
+ {
+ currentPos = pos;
+ return true;
+ }
+ else
+ {
+ _ASSERTE(!"ProfileReader: attempt to seek out of bounds");
+ return false;
+ }
+ }
+
+ void *Read(ULONG size)
+ {
+ ULONG oldPos = currentPos;
+
+ if (!Seek(currentPos + size))
+ {
+ return NULL;
+ }
+
+ return (void *)(profileBuffer + oldPos);
+ }
+
+ template <typename T> T Read()
+ {
+ T* pResult = (T*)Read(sizeof(T));
+
+ if (!pResult)
+ {
+ ThrowHR(E_FAIL);
+ }
+
+ return *pResult;
+ }
+
+ // Read an integer a la BinaryReader.Read7BitEncodedInt.
+ unsigned int Read7BitEncodedInt()
+ {
+ unsigned int result = 0;
+ int shift = 0;
+ unsigned char current = 0x80;
+
+ while ((currentPos < bufferSize) &&
+ (shift <= 28))
+ {
+ current = profileBuffer[currentPos++];
+ result |= (current & 0x7f) << shift;
+ shift += 7;
+
+ if (!(current & 0x80))
+ {
+ return result;
+ }
+ }
+
+ _ASSERTE(!"Improperly encoded value");
+ ThrowHR(E_FAIL);
+ }
+
+ // Read a token given a 'memory' value--the last token of this type read
+ // from the stream. The encoding takes advantage of the fact that two
+ // adjacent tokens in the file are usually of the same type, and therefore
+ // share a high byte. With the high byte removed the rest of the token can
+ // be encoded more efficiently.
+ mdToken ReadTokenWithMemory(mdToken &memory)
+ {
+ mdToken current;
+ mdToken result;
+
+ current = Read7BitEncodedInt();
+
+ unsigned char highByte = ((current >> 24) & 0xff);
+
+ if (highByte == 0)
+ {
+ result = current | (memory & 0xff000000);
+ }
+ else if (highByte == 0xff)
+ {
+ result = current & 0x00ffffff;
+ }
+ else
+ {
+ result = current;
+ }
+
+ memory = result;
+
+ return result;
+ }
+
+ // Read a 32-bit flag value using a lookup table built while processing the
+ // file. Flag values are represented by a one-byte index. If the index
+ // hasn't occurred before in the file, it is followed by the four-byte flag
+ // value it represents. The index 255 is used as an escape code--it is
+ // always followed by a flag value.
+ // flagTable must have 255 entries and they must all start as 0xFFFFFFFF.
+ unsigned int ReadFlagWithLookup(unsigned int flagTable[255])
+ {
+ unsigned char index;
+ unsigned int flags;
+
+ index = Read<unsigned char>();
+
+ if ((index < 255) && (flagTable[index] != 0xffffffff))
+ {
+ return flagTable[index];
+ }
+
+ flags = Read<unsigned int>();
+
+ if (index < 255)
+ {
+ flagTable[index] = flags;
+ }
+
+ return flags;
+ }
+
+ ULONG GetCurrentPos()
+ {
+ _ASSERTE(currentPos <= bufferSize);
+ return currentPos;
+ }
+
+private:
+ char *profileBuffer;
+ ULONG bufferSize;
+ ULONG currentPos;
+};
+
+struct RSDS {
+ DWORD magic;
+ GUID signature;
+ DWORD age;
+ char path[MAX_PATH];
+};
+
+#define SEEK(pos) \
+ if (!profileReader.Seek(pos)) return E_FAIL;
+
+#define READ_SIZE(dst,type,size) \
+ dst = (type *) profileReader.Read(size); \
+ if (!dst) return E_FAIL;
+
+#define READ(dst,type) \
+ READ_SIZE(dst,type,sizeof(type))
+
+#endif // __ZAPIMAGE_H__