diff options
Diffstat (limited to 'src/ToolBox/superpmi/superpmi-shim-simple')
17 files changed, 2769 insertions, 0 deletions
diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/.gitmirror b/src/ToolBox/superpmi/superpmi-shim-simple/.gitmirror new file mode 100644 index 0000000000..f507630f94 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/.gitmirror @@ -0,0 +1 @@ +Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror.
\ No newline at end of file diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt b/src/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt new file mode 100644 index 0000000000..354e46d097 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/CMakeLists.txt @@ -0,0 +1,72 @@ +project(superpmi-shim-simple) + +remove_definitions(-DUNICODE) +remove_definitions(-D_UNICODE) + +add_definitions(-DFEATURE_NO_HOST) +add_definitions(-DSELF_NO_HOST) + +if(WIN32) + #use static crt + add_definitions(-MT) +endif(WIN32) + +include_directories(.) +include_directories(../superpmi-shared) + +set(SUPERPMI_SHIM_SIMPLE_SOURCES + coreclrcallbacks.cpp + jithost.cpp + icorjitcompiler.cpp + icorjitinfo.cpp + ieememorymanager.cpp + iexecutionengine.cpp + superpmi-shim-simple.cpp + ../superpmi-shared/callutils.cpp + ../superpmi-shared/compileresult.cpp + ../superpmi-shared/errorhandling.cpp + ../superpmi-shared/logging.cpp + ../superpmi-shared/mclist.cpp + ../superpmi-shared/methodcontext.cpp + ../superpmi-shared/methodcontextreader.cpp + ../superpmi-shared/simpletimer.cpp + ../superpmi-shared/spmiutil.cpp + ../superpmi-shared/tocfile.cpp + ../superpmi-shared/typeutils.cpp +) + +add_precompiled_header( + standardpch.h + ../superpmi-shared/standardpch.cpp + SUPERPMI_SHIM_SIMPLE_SOURCES +) + +if (WIN32) + preprocess_def_file(${CMAKE_CURRENT_SOURCE_DIR}/superpmi-shim-simple.def ${CMAKE_CURRENT_BINARY_DIR}/superpmi-shim-simple.def) + + list(APPEND SUPERPMI_SHIM_SIMPLE_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/superpmi-shim-simple.def) +endif (WIN32) + +add_library(superpmi-shim-simple + SHARED + ${SUPERPMI_SHIM_SIMPLE_SOURCES} +) + +if(CLR_CMAKE_PLATFORM_UNIX) + target_link_libraries(superpmi-shim-simple + utilcodestaticnohost + mscorrc_debug + coreclrpal + palrt + ) +else() + target_link_libraries(superpmi-shim-simple + advapi32.lib + ${STATIC_MT_CRT_LIB} + ${STATIC_MT_CPP_LIB} + ) + + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/superpmi-shim-simple.pdb DESTINATION PDB) +endif(CLR_CMAKE_PLATFORM_UNIX) + +install (TARGETS superpmi-shim-simple DESTINATION .) diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/coreclrcallbacks.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/coreclrcallbacks.cpp new file mode 100644 index 0000000000..cf35748672 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/coreclrcallbacks.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "coreclrcallbacks.h" +#include "iexecutionengine.h" + +typedef LPVOID (__stdcall * pfnEEHeapAllocInProcessHeap)(DWORD dwFlags, SIZE_T dwBytes); +typedef BOOL (__stdcall * pfnEEHeapFreeInProcessHeap)(DWORD dwFlags, LPVOID lpMem); + +CoreClrCallbacks *original_CoreClrCallbacks = nullptr; +pfnEEHeapAllocInProcessHeap original_EEHeapAllocInProcessHeap = nullptr; +pfnEEHeapFreeInProcessHeap original_EEHeapFreeInProcessHeap = nullptr; + +IExecutionEngine* STDMETHODCALLTYPE IEE_t() +{ + interceptor_IEE *iee = new interceptor_IEE(); + iee->original_IEE = original_CoreClrCallbacks->m_pfnIEE(); + return iee; +} + +/*#pragma warning( suppress :4996 ) //deprecated +HRESULT STDMETHODCALLTYPE GetCORSystemDirectory(LPWSTR pbuffer, DWORD cchBuffer, DWORD* pdwlength) +{ + DebugBreakorAV(131); + return 0; +} +*/ + +LPVOID STDMETHODCALLTYPE EEHeapAllocInProcessHeap (DWORD dwFlags, SIZE_T dwBytes) +{ + return original_EEHeapAllocInProcessHeap(dwFlags, dwBytes); +} + +BOOL STDMETHODCALLTYPE EEHeapFreeInProcessHeap (DWORD dwFlags, LPVOID lpMem) +{ + return original_EEHeapFreeInProcessHeap(dwFlags, lpMem); +} + +void* STDMETHODCALLTYPE GetCLRFunction(LPCSTR functionName) +{ + if(strcmp(functionName, "EEHeapAllocInProcessHeap")==0) + { + original_EEHeapAllocInProcessHeap = + (pfnEEHeapAllocInProcessHeap)original_CoreClrCallbacks->m_pfnGetCLRFunction("EEHeapAllocInProcessHeap"); + return (void*)EEHeapAllocInProcessHeap; + } + if(strcmp(functionName, "EEHeapFreeInProcessHeap")==0) + { + original_EEHeapFreeInProcessHeap = + (pfnEEHeapFreeInProcessHeap)original_CoreClrCallbacks->m_pfnGetCLRFunction("EEHeapFreeInProcessHeap"); + return (void*)EEHeapFreeInProcessHeap; + } + return original_CoreClrCallbacks->m_pfnGetCLRFunction(functionName); +} + diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/coreclrcallbacks.h b/src/ToolBox/superpmi/superpmi-shim-simple/coreclrcallbacks.h new file mode 100644 index 0000000000..2e3a673f57 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/coreclrcallbacks.h @@ -0,0 +1,20 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _CoreClrCallbacks +#define _CoreClrCallbacks + +#include "runtimedetails.h" + +IExecutionEngine* STDMETHODCALLTYPE IEE_t(); +HRESULT STDMETHODCALLTYPE GetCORSystemDirectory(LPWSTR pbuffer, DWORD cchBuffer, DWORD* pdwlength); +LPVOID STDMETHODCALLTYPE EEHeapAllocInProcessHeap (DWORD dwFlags, SIZE_T dwBytes); +BOOL STDMETHODCALLTYPE EEHeapFreeInProcessHeap (DWORD dwFlags, LPVOID lpMem); +void* STDMETHODCALLTYPE GetCLRFunction(LPCSTR functionName); + +// Added to allow us to persist a copy of the original callbacks +extern CoreClrCallbacks *original_CoreClrCallbacks; + +#endif
\ No newline at end of file diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.cpp new file mode 100644 index 0000000000..f6fceb2029 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.cpp @@ -0,0 +1,59 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "icorjitcompiler.h" +#include "icorjitinfo.h" + +interceptor_IEEMM *current_IEEMM = nullptr; //we want this to live beyond the scope of a single compileMethodCall + +CorJitResult __stdcall interceptor_ICJC::compileMethod ( + ICorJitInfo *comp, /* IN */ + struct CORINFO_METHOD_INFO *info, /* IN */ + unsigned /* code:CorJitFlag */ flags, /* IN */ + BYTE **nativeEntry, /* OUT */ + ULONG *nativeSizeOfCode /* OUT */ + ) +{ + interceptor_ICJI our_ICorJitInfo; + our_ICorJitInfo.original_ICorJitInfo = comp; + + if(current_IEEMM == nullptr) + current_IEEMM = new interceptor_IEEMM(); + + CorJitResult temp = original_ICorJitCompiler->compileMethod(&our_ICorJitInfo, info, flags, nativeEntry, nativeSizeOfCode); + + return temp; +} + +void interceptor_ICJC::clearCache() +{ + original_ICorJitCompiler->clearCache(); +} + +BOOL interceptor_ICJC::isCacheCleanupRequired() +{ + return original_ICorJitCompiler->isCacheCleanupRequired(); +} + +void interceptor_ICJC::ProcessShutdownWork(ICorStaticInfo* info) +{ + original_ICorJitCompiler->ProcessShutdownWork(info); +} + +void interceptor_ICJC::getVersionIdentifier(GUID* versionIdentifier /* OUT */) +{ + original_ICorJitCompiler->getVersionIdentifier(versionIdentifier); +} + +unsigned interceptor_ICJC::getMaxIntrinsicSIMDVectorLength(DWORD cpuCompileFlags) +{ + return original_ICorJitCompiler->getMaxIntrinsicSIMDVectorLength(cpuCompileFlags); +} + +void interceptor_ICJC::setRealJit(ICorJitCompiler* realJitCompiler) +{ + original_ICorJitCompiler->setRealJit(realJitCompiler); +} diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.h b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.h new file mode 100644 index 0000000000..a5eda6aa19 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitcompiler.h @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _ICorJitCompiler +#define _ICorJitCompiler + +#include "runtimedetails.h" +#include "ieememorymanager.h" + +class interceptor_ICJC : public ICorJitCompiler +{ + +#include "icorjitcompilerimpl.h" + +public: + // Added to help us track the original icjc and be able to easily indirect to it. + ICorJitCompiler *original_ICorJitCompiler; +}; + +extern interceptor_IEEMM *current_IEEMM; // we want a pointer to the memory manager to live beyond the scope of a single compileMethodCall (jit32 expects this) + +#endif diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp new file mode 100644 index 0000000000..89b19d8754 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -0,0 +1,1726 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "icorjitinfo.h" +#include "superpmi-shim-simple.h" +#include "ieememorymanager.h" +#include "icorjitcompiler.h" +#include "spmiutil.h" + +//Stuff on ICorStaticInfo +/**********************************************************************************/ +// +// ICorMethodInfo +// +/**********************************************************************************/ +// return flags (defined above, CORINFO_FLG_PUBLIC ...) +DWORD interceptor_ICJI::getMethodAttribs (CORINFO_METHOD_HANDLE ftn /* IN */) +{ + return original_ICorJitInfo->getMethodAttribs(ftn); +} + +// sets private JIT flags, which can be, retrieved using getAttrib. +void interceptor_ICJI::setMethodAttribs (CORINFO_METHOD_HANDLE ftn,/* IN */ + CorInfoMethodRuntimeFlags attribs/* IN */) +{ + original_ICorJitInfo->setMethodAttribs(ftn, attribs); +} + + +// Given a method descriptor ftnHnd, extract signature information into sigInfo +// +// 'memberParent' is typically only set when verifying. It should be the +// result of calling getMemberParent. +void interceptor_ICJI::getMethodSig ( + CORINFO_METHOD_HANDLE ftn, /* IN */ + CORINFO_SIG_INFO *sig, /* OUT */ + CORINFO_CLASS_HANDLE memberParent/* IN */ + ) +{ + original_ICorJitInfo->getMethodSig(ftn, sig, memberParent); +} + + + /********************************************************************* + * Note the following methods can only be used on functions known + * to be IL. This includes the method being compiled and any method + * that 'getMethodInfo' returns true for + *********************************************************************/ + + // return information about a method private to the implementation + // returns false if method is not IL, or is otherwise unavailable. + // This method is used to fetch data needed to inline functions + bool interceptor_ICJI::getMethodInfo ( + CORINFO_METHOD_HANDLE ftn, /* IN */ + CORINFO_METHOD_INFO* info /* OUT */ + ) +{ + return original_ICorJitInfo->getMethodInfo(ftn, info); +} + +// Decides if you have any limitations for inlining. If everything's OK, it will return +// INLINE_PASS and will fill out pRestrictions with a mask of restrictions the caller of this +// function must respect. If caller passes pRestrictions = nullptr, if there are any restrictions +// INLINE_FAIL will be returned +// +// The callerHnd must be the immediate caller (i.e. when we have a chain of inlined calls) +// +// The inlined method need not be verified + +CorInfoInline interceptor_ICJI::canInline ( + CORINFO_METHOD_HANDLE callerHnd, /* IN */ + CORINFO_METHOD_HANDLE calleeHnd, /* IN */ + DWORD* pRestrictions /* OUT */ + ) +{ + return original_ICorJitInfo->canInline(callerHnd, calleeHnd, pRestrictions); +} + +// Reports whether or not a method can be inlined, and why. canInline is responsible for reporting all +// inlining results when it returns INLINE_FAIL and INLINE_NEVER. All other results are reported by the +// JIT. +void interceptor_ICJI::reportInliningDecision (CORINFO_METHOD_HANDLE inlinerHnd, + CORINFO_METHOD_HANDLE inlineeHnd, + CorInfoInline inlineResult, + const char * reason) +{ + original_ICorJitInfo->reportInliningDecision(inlinerHnd, inlineeHnd, inlineResult, reason); +} + + +// Returns false if the call is across security boundaries thus we cannot tailcall +// +// The callerHnd must be the immediate caller (i.e. when we have a chain of inlined calls) +bool interceptor_ICJI::canTailCall ( + CORINFO_METHOD_HANDLE callerHnd, /* IN */ + CORINFO_METHOD_HANDLE declaredCalleeHnd, /* IN */ + CORINFO_METHOD_HANDLE exactCalleeHnd, /* IN */ + bool fIsTailPrefix /* IN */ + ) +{ + return original_ICorJitInfo->canTailCall(callerHnd, declaredCalleeHnd, exactCalleeHnd, fIsTailPrefix); +} + +// Reports whether or not a method can be tail called, and why. +// canTailCall is responsible for reporting all results when it returns +// false. All other results are reported by the JIT. +void interceptor_ICJI::reportTailCallDecision (CORINFO_METHOD_HANDLE callerHnd, + CORINFO_METHOD_HANDLE calleeHnd, + bool fIsTailPrefix, + CorInfoTailCall tailCallResult, + const char * reason) +{ + original_ICorJitInfo->reportTailCallDecision(callerHnd, calleeHnd, fIsTailPrefix, tailCallResult, reason); +} + +// get individual exception handler +void interceptor_ICJI::getEHinfo( + CORINFO_METHOD_HANDLE ftn, /* IN */ + unsigned EHnumber, /* IN */ + CORINFO_EH_CLAUSE* clause /* OUT */ + ) +{ + original_ICorJitInfo->getEHinfo(ftn, EHnumber, clause); +} + +// return class it belongs to +CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodClass ( + CORINFO_METHOD_HANDLE method + ) +{ + return original_ICorJitInfo->getMethodClass(method); +} + +// return module it belongs to +CORINFO_MODULE_HANDLE interceptor_ICJI::getMethodModule ( + CORINFO_METHOD_HANDLE method + ) +{ + return original_ICorJitInfo->getMethodModule(method); +} + +// This function returns the offset of the specified method in the +// vtable of it's owning class or interface. +void interceptor_ICJI::getMethodVTableOffset ( + CORINFO_METHOD_HANDLE method, /* IN */ + unsigned* offsetOfIndirection, /* OUT */ + unsigned* offsetAfterIndirection /* OUT */ + ) +{ + original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection); +} + +// If a method's attributes have (getMethodAttribs) CORINFO_FLG_INTRINSIC set, +// getIntrinsicID() returns the intrinsic ID. +CorInfoIntrinsics interceptor_ICJI::getIntrinsicID( + CORINFO_METHOD_HANDLE method, + bool* pMustExpand /* OUT */ + ) +{ + return original_ICorJitInfo->getIntrinsicID(method, pMustExpand); +} + +// Is the given module the System.Numerics.Vectors module? +bool interceptor_ICJI::isInSIMDModule( + CORINFO_CLASS_HANDLE classHnd + ) +{ + return original_ICorJitInfo->isInSIMDModule(classHnd); +} + +// return the unmanaged calling convention for a PInvoke +CorInfoUnmanagedCallConv interceptor_ICJI::getUnmanagedCallConv( + CORINFO_METHOD_HANDLE method + ) +{ + return original_ICorJitInfo->getUnmanagedCallConv(method); +} + +// return if any marshaling is required for PInvoke methods. Note that +// method == 0 => calli. The call site sig is only needed for the varargs or calli case +BOOL interceptor_ICJI::pInvokeMarshalingRequired( + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* callSiteSig + ) +{ + return original_ICorJitInfo->pInvokeMarshalingRequired(method, callSiteSig); +} + +// Check constraints on method type arguments (only). +// The parent class should be checked separately using satisfiesClassConstraints(parent). +BOOL interceptor_ICJI::satisfiesMethodConstraints( + CORINFO_CLASS_HANDLE parent, // the exact parent of the method + CORINFO_METHOD_HANDLE method + ) +{ + return original_ICorJitInfo->satisfiesMethodConstraints(parent, method); +} + +// Given a delegate target class, a target method parent class, a target method, +// a delegate class, check if the method signature is compatible with the Invoke method of the delegate +// (under the typical instantiation of any free type variables in the memberref signatures). +BOOL interceptor_ICJI::isCompatibleDelegate( + CORINFO_CLASS_HANDLE objCls, /* type of the delegate target, if any */ + CORINFO_CLASS_HANDLE methodParentCls, /* exact parent of the target method, if any */ + CORINFO_METHOD_HANDLE method, /* (representative) target method, if any */ + CORINFO_CLASS_HANDLE delegateCls, /* exact type of the delegate */ + BOOL *pfIsOpenDelegate /* is the delegate open */ + ) +{ + return original_ICorJitInfo->isCompatibleDelegate(objCls, methodParentCls, method, delegateCls, pfIsOpenDelegate); +} + +// Determines whether the delegate creation obeys security transparency rules +BOOL interceptor_ICJI::isDelegateCreationAllowed ( + CORINFO_CLASS_HANDLE delegateHnd, + CORINFO_METHOD_HANDLE calleeHnd + ) +{ + return original_ICorJitInfo->isDelegateCreationAllowed(delegateHnd, calleeHnd); +} + + +// Indicates if the method is an instance of the generic +// method that passes (or has passed) verification +CorInfoInstantiationVerification interceptor_ICJI::isInstantiationOfVerifiedGeneric ( + CORINFO_METHOD_HANDLE method /* IN */ + ) +{ + return original_ICorJitInfo->isInstantiationOfVerifiedGeneric(method); +} + +// Loads the constraints on a typical method definition, detecting cycles; +// for use in verification. +void interceptor_ICJI::initConstraintsForVerification( + CORINFO_METHOD_HANDLE method, /* IN */ + BOOL *pfHasCircularClassConstraints, /* OUT */ + BOOL *pfHasCircularMethodConstraint /* OUT */ + ) +{ + original_ICorJitInfo->initConstraintsForVerification(method, pfHasCircularClassConstraints, pfHasCircularMethodConstraint); +} + +CorInfoCanSkipVerificationResult interceptor_ICJI::canSkipMethodVerification ( + CORINFO_METHOD_HANDLE ftnHandle + ) +{ + return original_ICorJitInfo->canSkipMethodVerification(ftnHandle); +} + +// load and restore the method +void interceptor_ICJI::methodMustBeLoadedBeforeCodeIsRun( + CORINFO_METHOD_HANDLE method + ) +{ + original_ICorJitInfo->methodMustBeLoadedBeforeCodeIsRun(method); +} + +CORINFO_METHOD_HANDLE interceptor_ICJI::mapMethodDeclToMethodImpl( + CORINFO_METHOD_HANDLE method + ) +{ + return original_ICorJitInfo->mapMethodDeclToMethodImpl(method); +} + +// Returns the global cookie for the /GS unsafe buffer checks +// The cookie might be a constant value (JIT), or a handle to memory location (Ngen) +void interceptor_ICJI::getGSCookie( + GSCookie * pCookieVal, // OUT + GSCookie ** ppCookieVal // OUT + ) +{ + original_ICorJitInfo->getGSCookie(pCookieVal, ppCookieVal); +} + +/**********************************************************************************/ +// +// ICorModuleInfo +// +/**********************************************************************************/ + +// Resolve metadata token into runtime method handles. +void interceptor_ICJI::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken) +{ + original_ICorJitInfo->resolveToken(pResolvedToken); +} + +bool interceptor_ICJI::tryResolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken) +{ + return original_ICorJitInfo->tryResolveToken(pResolvedToken); +} + +// Signature information about the call sig +void interceptor_ICJI::findSig ( + CORINFO_MODULE_HANDLE module, /* IN */ + unsigned sigTOK, /* IN */ + CORINFO_CONTEXT_HANDLE context, /* IN */ + CORINFO_SIG_INFO *sig /* OUT */ + ) +{ + original_ICorJitInfo->findSig(module, sigTOK, context, sig); +} + +// for Varargs, the signature at the call site may differ from +// the signature at the definition. Thus we need a way of +// fetching the call site information +void interceptor_ICJI::findCallSiteSig ( + CORINFO_MODULE_HANDLE module, /* IN */ + unsigned methTOK, /* IN */ + CORINFO_CONTEXT_HANDLE context, /* IN */ + CORINFO_SIG_INFO *sig /* OUT */ + ) +{ + original_ICorJitInfo->findCallSiteSig(module, methTOK, context, sig); +} + +CORINFO_CLASS_HANDLE interceptor_ICJI::getTokenTypeAsHandle ( + CORINFO_RESOLVED_TOKEN * pResolvedToken /* IN */) +{ + return original_ICorJitInfo->getTokenTypeAsHandle(pResolvedToken); +} + +// Returns true if the module does not require verification +// +// If fQuickCheckOnlyWithoutCommit=TRUE, the function only checks that the +// module does not currently require verification in the current AppDomain. +// This decision could change in the future, and so should not be cached. +// If it is cached, it should only be used as a hint. +// This is only used by ngen for calculating certain hints. +// + +// Returns enum whether the module does not require verification +// Also see ICorMethodInfo::canSkipMethodVerification(); +CorInfoCanSkipVerificationResult interceptor_ICJI::canSkipVerification ( + CORINFO_MODULE_HANDLE module /* IN */ + ) +{ + return original_ICorJitInfo->canSkipVerification(module); +} + +// Checks if the given metadata token is valid +BOOL interceptor_ICJI::isValidToken ( + CORINFO_MODULE_HANDLE module, /* IN */ + unsigned metaTOK /* IN */ + ) +{ + return original_ICorJitInfo->isValidToken(module, metaTOK); +} + +// Checks if the given metadata token is valid StringRef +BOOL interceptor_ICJI::isValidStringRef ( + CORINFO_MODULE_HANDLE module, /* IN */ + unsigned metaTOK /* IN */ + ) +{ + return original_ICorJitInfo->isValidStringRef(module, metaTOK); +} + +BOOL interceptor_ICJI::shouldEnforceCallvirtRestriction( + CORINFO_MODULE_HANDLE scope + ) +{ + return original_ICorJitInfo->shouldEnforceCallvirtRestriction(scope); +} + +/**********************************************************************************/ +// +// ICorClassInfo +// +/**********************************************************************************/ + +// If the value class 'cls' is isomorphic to a primitive type it will +// return that type, otherwise it will return CORINFO_TYPE_VALUECLASS +CorInfoType interceptor_ICJI::asCorInfoType ( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->asCorInfoType(cls); +} + +// for completeness +const char* interceptor_ICJI::getClassName ( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getClassName(cls); +} + + +// Append a (possibly truncated) representation of the type cls to the preallocated buffer ppBuf of length pnBufLen +// If fNamespace=TRUE, include the namespace/enclosing classes +// If fFullInst=TRUE (regardless of fNamespace and fAssembly), include namespace and assembly for any type parameters +// If fAssembly=TRUE, suffix with a comma and the full assembly qualification +// return size of representation +int interceptor_ICJI::appendClassName( + __deref_inout_ecount(*pnBufLen) WCHAR** ppBuf, + int* pnBufLen, + CORINFO_CLASS_HANDLE cls, + BOOL fNamespace, + BOOL fFullInst, + BOOL fAssembly + ) +{ + return original_ICorJitInfo->appendClassName(ppBuf, pnBufLen, cls, fNamespace, fFullInst, fAssembly); +} + +// Quick check whether the type is a value class. Returns the same value as getClassAttribs(cls) & CORINFO_FLG_VALUECLASS, except faster. +BOOL interceptor_ICJI::isValueClass(CORINFO_CLASS_HANDLE cls) +{ + return original_ICorJitInfo->isValueClass(cls); +} + +// If this method returns true, JIT will do optimization to inline the check for +// GetTypeFromHandle(handle) == obj.GetType() +BOOL interceptor_ICJI::canInlineTypeCheckWithObjectVTable(CORINFO_CLASS_HANDLE cls) +{ + return original_ICorJitInfo->canInlineTypeCheckWithObjectVTable(cls); +} + +// return flags (defined above, CORINFO_FLG_PUBLIC ...) +DWORD interceptor_ICJI::getClassAttribs ( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getClassAttribs(cls); +} + +// Returns "TRUE" iff "cls" is a struct type such that return buffers used for returning a value +// of this type must be stack-allocated. This will generally be true only if the struct +// contains GC pointers, and does not exceed some size limit. Maintaining this as an invariant allows +// an optimization: the JIT may assume that return buffer pointers for return types for which this predicate +// returns TRUE are always stack allocated, and thus, that stores to the GC-pointer fields of such return +// buffers do not require GC write barriers. +BOOL interceptor_ICJI::isStructRequiringStackAllocRetBuf(CORINFO_CLASS_HANDLE cls) +{ + return original_ICorJitInfo->isStructRequiringStackAllocRetBuf(cls); +} + +CORINFO_MODULE_HANDLE interceptor_ICJI::getClassModule ( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getClassModule(cls); +} + +// Returns the assembly that contains the module "mod". +CORINFO_ASSEMBLY_HANDLE interceptor_ICJI::getModuleAssembly ( + CORINFO_MODULE_HANDLE mod + ) +{ + return original_ICorJitInfo->getModuleAssembly(mod); +} + +// Returns the name of the assembly "assem". +const char* interceptor_ICJI::getAssemblyName ( + CORINFO_ASSEMBLY_HANDLE assem + ) +{ + return original_ICorJitInfo->getAssemblyName(assem); +} + +// Allocate and delete process-lifetime objects. Should only be +// referred to from static fields, lest a leak occur. +// Note that "LongLifetimeFree" does not execute destructors, if "obj" +// is an array of a struct type with a destructor. +void* interceptor_ICJI::LongLifetimeMalloc(size_t sz) +{ + return original_ICorJitInfo->LongLifetimeMalloc(sz); +} + +void interceptor_ICJI::LongLifetimeFree(void* obj) +{ + original_ICorJitInfo->LongLifetimeFree(obj); +} + +size_t interceptor_ICJI::getClassModuleIdForStatics ( + CORINFO_CLASS_HANDLE cls, + CORINFO_MODULE_HANDLE *pModule, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); +} + +// return the number of bytes needed by an instance of the class +unsigned interceptor_ICJI::getClassSize ( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getClassSize(cls); +} + +unsigned interceptor_ICJI::getClassAlignmentRequirement ( + CORINFO_CLASS_HANDLE cls, + BOOL fDoubleAlignHint + ) +{ + return original_ICorJitInfo->getClassAlignmentRequirement(cls, fDoubleAlignHint); +} + +// This is only called for Value classes. It returns a boolean array +// in representing of 'cls' from a GC perspective. The class is +// assumed to be an array of machine words +// (of length // getClassSize(cls) / sizeof(void*)), +// 'gcPtrs' is a poitner to an array of BYTEs of this length. +// getClassGClayout fills in this array so that gcPtrs[i] is set +// to one of the CorInfoGCType values which is the GC type of +// the i-th machine word of an object of type 'cls' +// returns the number of GC pointers in the array +unsigned interceptor_ICJI::getClassGClayout ( + CORINFO_CLASS_HANDLE cls, /* IN */ + BYTE *gcPtrs /* OUT */ + ) +{ + return original_ICorJitInfo->getClassGClayout(cls, gcPtrs); +} + +// returns the number of instance fields in a class +unsigned interceptor_ICJI::getClassNumInstanceFields ( + CORINFO_CLASS_HANDLE cls /* IN */ + ) +{ + return original_ICorJitInfo->getClassNumInstanceFields(cls); +} + +CORINFO_FIELD_HANDLE interceptor_ICJI::getFieldInClass( + CORINFO_CLASS_HANDLE clsHnd, + INT num + ) +{ + return original_ICorJitInfo->getFieldInClass(clsHnd, num); +} + +BOOL interceptor_ICJI::checkMethodModifier( + CORINFO_METHOD_HANDLE hMethod, + LPCSTR modifier, + BOOL fOptional + ) +{ + return original_ICorJitInfo->checkMethodModifier(hMethod, modifier, fOptional); +} + +// returns the "NEW" helper optimized for "newCls." +CorInfoHelpFunc interceptor_ICJI::getNewHelper( + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_METHOD_HANDLE callerHandle + ) +{ + return original_ICorJitInfo->getNewHelper(pResolvedToken, callerHandle); +} + +// returns the newArr (1-Dim array) helper optimized for "arrayCls." +CorInfoHelpFunc interceptor_ICJI::getNewArrHelper( + CORINFO_CLASS_HANDLE arrayCls + ) +{ + return original_ICorJitInfo->getNewArrHelper(arrayCls); +} + +// returns the optimized "IsInstanceOf" or "ChkCast" helper +CorInfoHelpFunc interceptor_ICJI::getCastingHelper( + CORINFO_RESOLVED_TOKEN * pResolvedToken, + bool fThrowing + ) +{ + return original_ICorJitInfo->getCastingHelper(pResolvedToken, fThrowing); +} + +// returns helper to trigger static constructor +CorInfoHelpFunc interceptor_ICJI::getSharedCCtorHelper( + CORINFO_CLASS_HANDLE clsHnd + ) +{ + return original_ICorJitInfo->getSharedCCtorHelper(clsHnd); +} + +CorInfoHelpFunc interceptor_ICJI::getSecurityPrologHelper( + CORINFO_METHOD_HANDLE ftn + ) +{ + return original_ICorJitInfo->getSecurityPrologHelper(ftn); +} + +// This is not pretty. Boxing nullable<T> actually returns +// a boxed<T> not a boxed Nullable<T>. This call allows the verifier +// to call back to the EE on the 'box' instruction and get the transformed +// type to use for verification. +CORINFO_CLASS_HANDLE interceptor_ICJI::getTypeForBox( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getTypeForBox(cls); +} + +// returns the correct box helper for a particular class. Note +// that if this returns CORINFO_HELP_BOX, the JIT can assume +// 'standard' boxing (allocate object and copy), and optimize +CorInfoHelpFunc interceptor_ICJI::getBoxHelper( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getBoxHelper(cls); +} + +// returns the unbox helper. If 'helperCopies' points to a true +// value it means the JIT is requesting a helper that unboxes the +// value into a particular location and thus has the signature +// void unboxHelper(void* dest, CORINFO_CLASS_HANDLE cls, Object* obj) +// Otherwise (it is null or points at a FALSE value) it is requesting +// a helper that returns a poitner to the unboxed data +// void* unboxHelper(CORINFO_CLASS_HANDLE cls, Object* obj) +// The EE has the option of NOT returning the copy style helper +// (But must be able to always honor the non-copy style helper) +// The EE set 'helperCopies' on return to indicate what kind of +// helper has been created. + +CorInfoHelpFunc interceptor_ICJI::getUnBoxHelper( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getUnBoxHelper(cls); +} + +bool interceptor_ICJI::getReadyToRunHelper( + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_LOOKUP_KIND * pGenericLookupKind, + CorInfoHelpFunc id, + CORINFO_CONST_LOOKUP * pLookup + ) +{ + return original_ICorJitInfo->getReadyToRunHelper(pResolvedToken, pGenericLookupKind, id, pLookup); +} + +void interceptor_ICJI::getReadyToRunDelegateCtorHelper( + CORINFO_RESOLVED_TOKEN * pTargetMethod, + CORINFO_CLASS_HANDLE delegateType, + CORINFO_CONST_LOOKUP * pLookup + ) +{ + original_ICorJitInfo->getReadyToRunDelegateCtorHelper(pTargetMethod, delegateType, pLookup); +} + +const char* interceptor_ICJI::getHelperName( + CorInfoHelpFunc funcNum + ) +{ + return original_ICorJitInfo->getHelperName(funcNum); +} + +// This function tries to initialize the class (run the class constructor). +// this function returns whether the JIT must insert helper calls before +// accessing static field or method. +// +// See code:ICorClassInfo#ClassConstruction. +CorInfoInitClassResult interceptor_ICJI::initClass( + CORINFO_FIELD_HANDLE field, // Non-nullptr - inquire about cctor trigger before static field access + // nullptr - inquire about cctor trigger in method prolog + CORINFO_METHOD_HANDLE method, // Method referencing the field or prolog + CORINFO_CONTEXT_HANDLE context, // Exact context of method + BOOL speculative // TRUE means don't actually run it + ) +{ + return original_ICorJitInfo->initClass(field, method, context, speculative); +} + +// This used to be called "loadClass". This records the fact +// that the class must be loaded (including restored if necessary) before we execute the +// code that we are currently generating. When jitting code +// the function loads the class immediately. When zapping code +// the zapper will if necessary use the call to record the fact that we have +// to do a fixup/restore before running the method currently being generated. +// +// This is typically used to ensure value types are loaded before zapped +// code that manipulates them is executed, so that the GC can access information +// about those value types. +void interceptor_ICJI::classMustBeLoadedBeforeCodeIsRun( + CORINFO_CLASS_HANDLE cls + ) +{ + original_ICorJitInfo->classMustBeLoadedBeforeCodeIsRun(cls); +} + +// returns the class handle for the special builtin classes +CORINFO_CLASS_HANDLE interceptor_ICJI::getBuiltinClass ( + CorInfoClassId classId + ) +{ + return original_ICorJitInfo->getBuiltinClass(classId); +} + +// "System.Int32" ==> CORINFO_TYPE_INT.. +CorInfoType interceptor_ICJI::getTypeForPrimitiveValueClass( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getTypeForPrimitiveValueClass(cls); +} + +// TRUE if child is a subtype of parent +// if parent is an interface, then does child implement / extend parent +BOOL interceptor_ICJI::canCast( + CORINFO_CLASS_HANDLE child, // subtype (extends parent) + CORINFO_CLASS_HANDLE parent // base type + ) +{ + return original_ICorJitInfo->canCast(child, parent); +} + +// TRUE if cls1 and cls2 are considered equivalent types. +BOOL interceptor_ICJI::areTypesEquivalent( + CORINFO_CLASS_HANDLE cls1, + CORINFO_CLASS_HANDLE cls2 + ) +{ + return original_ICorJitInfo->areTypesEquivalent(cls1, cls2); +} + +// returns is the intersection of cls1 and cls2. +CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses( + CORINFO_CLASS_HANDLE cls1, + CORINFO_CLASS_HANDLE cls2 + ) +{ + return original_ICorJitInfo->mergeClasses(cls1, cls2); +} + +// Given a class handle, returns the Parent type. +// For COMObjectType, it returns Class Handle of System.Object. +// Returns 0 if System.Object is passed in. +CORINFO_CLASS_HANDLE interceptor_ICJI::getParentType ( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getParentType(cls); +} + +// Returns the CorInfoType of the "child type". If the child type is +// not a primitive type, *clsRet will be set. +// Given an Array of Type Foo, returns Foo. +// Given BYREF Foo, returns Foo +CorInfoType interceptor_ICJI::getChildType ( + CORINFO_CLASS_HANDLE clsHnd, + CORINFO_CLASS_HANDLE *clsRet + ) +{ + return original_ICorJitInfo->getChildType(clsHnd, clsRet); +} + +// Check constraints on type arguments of this class and parent classes +BOOL interceptor_ICJI::satisfiesClassConstraints( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->satisfiesClassConstraints(cls); +} + +// Check if this is a single dimensional array type +BOOL interceptor_ICJI::isSDArray( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->isSDArray(cls); +} + +// Get the numbmer of dimensions in an array +unsigned interceptor_ICJI::getArrayRank( + CORINFO_CLASS_HANDLE cls + ) +{ + return original_ICorJitInfo->getArrayRank(cls); +} + +// Get static field data for an array +void * interceptor_ICJI::getArrayInitializationData( + CORINFO_FIELD_HANDLE field, + DWORD size + ) +{ + return original_ICorJitInfo->getArrayInitializationData(field, size); +} + +// Check Visibility rules. +CorInfoIsAccessAllowedResult interceptor_ICJI::canAccessClass( + CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_METHOD_HANDLE callerHandle, + CORINFO_HELPER_DESC *pAccessHelper /* If canAccessMethod returns something other + than ALLOWED, then this is filled in. */ + ) +{ + return original_ICorJitInfo->canAccessClass(pResolvedToken, callerHandle, pAccessHelper); +} + +/**********************************************************************************/ +// +// ICorFieldInfo +// +/**********************************************************************************/ + +// this function is for debugging only. It returns the field name +// and if 'moduleName' is non-null, it sets it to something that will +// says which method (a class name, or a module name) +const char* interceptor_ICJI::getFieldName ( + CORINFO_FIELD_HANDLE ftn, /* IN */ + const char **moduleName /* OUT */ + ) +{ + return original_ICorJitInfo->getFieldName(ftn, moduleName); +} + +// return class it belongs to +CORINFO_CLASS_HANDLE interceptor_ICJI::getFieldClass ( + CORINFO_FIELD_HANDLE field + ) +{ + return original_ICorJitInfo->getFieldClass(field); +} + +// Return the field's type, if it is CORINFO_TYPE_VALUECLASS 'structType' is set +// the field's value class (if 'structType' == 0, then don't bother +// the structure info). +// +// 'memberParent' is typically only set when verifying. It should be the +// result of calling getMemberParent. +CorInfoType interceptor_ICJI::getFieldType( + CORINFO_FIELD_HANDLE field, + CORINFO_CLASS_HANDLE *structType, + CORINFO_CLASS_HANDLE memberParent/* IN */ + ) +{ + return original_ICorJitInfo->getFieldType(field, structType, memberParent); +} + +// return the data member's instance offset +unsigned interceptor_ICJI::getFieldOffset( + CORINFO_FIELD_HANDLE field + ) +{ + return original_ICorJitInfo->getFieldOffset(field); +} + +// TODO: jit64 should be switched to the same plan as the i386 jits - use +// getClassGClayout to figure out the need for writebarrier helper, and inline the copying. +// The interpretted value class copy is slow. Once this happens, USE_WRITE_BARRIER_HELPERS +bool interceptor_ICJI::isWriteBarrierHelperRequired( + CORINFO_FIELD_HANDLE field) +{ + return original_ICorJitInfo->isWriteBarrierHelperRequired(field); +} + +void interceptor_ICJI::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, + CORINFO_METHOD_HANDLE callerHandle, + CORINFO_ACCESS_FLAGS flags, + CORINFO_FIELD_INFO *pResult + ) +{ + original_ICorJitInfo->getFieldInfo(pResolvedToken, callerHandle, flags, pResult); +} + +// Returns true iff "fldHnd" represents a static field. +bool interceptor_ICJI::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) +{ + // this method does exist in some forms of the jit interface... if trip into one we'll know about it + DebugBreakorAV(67); + return true; +} + +/*********************************************************************************/ +// +// ICorDebugInfo +// +/*********************************************************************************/ + +// Query the EE to find out where interesting break points +// in the code are. The native compiler will ensure that these places +// have a corresponding break point in native code. +// +// Note that unless CORJIT_FLG_DEBUG_CODE is specified, this function will +// be used only as a hint and the native compiler should not change its +// code generation. +void interceptor_ICJI::getBoundaries( + CORINFO_METHOD_HANDLE ftn, // [IN] method of interest + unsigned int *cILOffsets, // [OUT] size of pILOffsets + DWORD **pILOffsets, // [OUT] IL offsets of interest + // jit MUST free with freeArray! + ICorDebugInfo::BoundaryTypes *implictBoundaries // [OUT] tell jit, all boundries of this type + ) +{ + original_ICorJitInfo->getBoundaries(ftn, cILOffsets, pILOffsets, implictBoundaries); +} + +// Report back the mapping from IL to native code, +// this map should include all boundaries that 'getBoundaries' +// reported as interesting to the debugger. + +// Note that debugger (and profiler) is assuming that all of the +// offsets form a contiguous block of memory, and that the +// OffsetMapping is sorted in order of increasing native offset. +void interceptor_ICJI::setBoundaries( + CORINFO_METHOD_HANDLE ftn, // [IN] method of interest + ULONG32 cMap, // [IN] size of pMap + ICorDebugInfo::OffsetMapping *pMap // [IN] map including all points of interest. + // jit allocated with allocateArray, EE frees + ) +{ + original_ICorJitInfo->setBoundaries(ftn, cMap, pMap); +} + +// Query the EE to find out the scope of local varables. +// normally the JIT would trash variables after last use, but +// under debugging, the JIT needs to keep them live over their +// entire scope so that they can be inspected. +// +// Note that unless CORJIT_FLG_DEBUG_CODE is specified, this function will +// be used only as a hint and the native compiler should not change its +// code generation. +void interceptor_ICJI::getVars( + CORINFO_METHOD_HANDLE ftn, // [IN] method of interest + ULONG32 *cVars, // [OUT] size of 'vars' + ICorDebugInfo::ILVarInfo **vars, // [OUT] scopes of variables of interest + // jit MUST free with freeArray! + bool *extendOthers // [OUT] it TRUE, then assume the scope + // of unmentioned vars is entire method + ) +{ + original_ICorJitInfo->getVars(ftn, cVars, vars, extendOthers); +} + +// Report back to the EE the location of every variable. +// note that the JIT might split lifetimes into different +// locations etc. + +void interceptor_ICJI::setVars( + CORINFO_METHOD_HANDLE ftn, // [IN] method of interest + ULONG32 cVars, // [IN] size of 'vars' + ICorDebugInfo::NativeVarInfo *vars // [IN] map telling where local vars are stored at what points + // jit allocated with allocateArray, EE frees + ) +{ + original_ICorJitInfo->setVars(ftn, cVars, vars); +} + +/*-------------------------- Misc ---------------------------------------*/ + +// Used to allocate memory that needs to handed to the EE. +// For eg, use this to allocated memory for reporting debug info, +// which will be handed to the EE by setVars() and setBoundaries() +void * interceptor_ICJI::allocateArray( + ULONG cBytes + ) +{ + return original_ICorJitInfo->allocateArray(cBytes); +} + +// JitCompiler will free arrays passed by the EE using this +// For eg, The EE returns memory in getVars() and getBoundaries() +// to the JitCompiler, which the JitCompiler should release using +// freeArray() +void interceptor_ICJI::freeArray( + void *array + ) +{ + original_ICorJitInfo->freeArray(array); +} + +/*********************************************************************************/ +// +// ICorArgInfo +// +/*********************************************************************************/ + +// advance the pointer to the argument list. +// a ptr of 0, is special and always means the first argument +CORINFO_ARG_LIST_HANDLE interceptor_ICJI::getArgNext ( + CORINFO_ARG_LIST_HANDLE args /* IN */ + ) +{ + return original_ICorJitInfo->getArgNext(args); +} + +// Get the type of a particular argument +// CORINFO_TYPE_UNDEF is returned when there are no more arguments +// If the type returned is a primitive type (or an enum) *vcTypeRet set to nullptr +// otherwise it is set to the TypeHandle associted with the type +// Enumerations will always look their underlying type (probably should fix this) +// Otherwise vcTypeRet is the type as would be seen by the IL, +// The return value is the type that is used for calling convention purposes +// (Thus if the EE wants a value class to be passed like an int, then it will +// return CORINFO_TYPE_INT +CorInfoTypeWithMod interceptor_ICJI::getArgType ( + CORINFO_SIG_INFO* sig, /* IN */ + CORINFO_ARG_LIST_HANDLE args, /* IN */ + CORINFO_CLASS_HANDLE *vcTypeRet /* OUT */ + ) +{ + return original_ICorJitInfo->getArgType(sig, args, vcTypeRet); +} + +// If the Arg is a CORINFO_TYPE_CLASS fetch the class handle associated with it +CORINFO_CLASS_HANDLE interceptor_ICJI::getArgClass ( + CORINFO_SIG_INFO* sig, /* IN */ + CORINFO_ARG_LIST_HANDLE args /* IN */ + ) +{ + return original_ICorJitInfo->getArgClass(sig, args); +} + +// Returns type of HFA for valuetype +CorInfoType interceptor_ICJI::getHFAType ( + CORINFO_CLASS_HANDLE hClass + ) +{ + return original_ICorJitInfo->getHFAType(hClass); +} + +/***************************************************************************** +* ICorErrorInfo contains methods to deal with SEH exceptions being thrown +* from the corinfo interface. These methods may be called when an exception +* with code EXCEPTION_COMPLUS is caught. +*****************************************************************************/ + +// Returns the HRESULT of the current exception +HRESULT interceptor_ICJI::GetErrorHRESULT( + struct _EXCEPTION_POINTERS *pExceptionPointers + ) +{ + return original_ICorJitInfo->GetErrorHRESULT(pExceptionPointers); +} + +// Fetches the message of the current exception +// Returns the size of the message (including terminating null). This can be +// greater than bufferLength if the buffer is insufficient. +ULONG interceptor_ICJI::GetErrorMessage( + __inout_ecount(bufferLength) LPWSTR buffer, + ULONG bufferLength + ) +{ + return original_ICorJitInfo->GetErrorMessage(buffer, bufferLength); +} + +// returns EXCEPTION_EXECUTE_HANDLER if it is OK for the compile to handle the +// exception, abort some work (like the inlining) and continue compilation +// returns EXCEPTION_CONTINUE_SEARCH if exception must always be handled by the EE +// things like ThreadStoppedException ... +// returns EXCEPTION_CONTINUE_EXECUTION if exception is fixed up by the EE + +int interceptor_ICJI::FilterException( + struct _EXCEPTION_POINTERS *pExceptionPointers + ) +{ + return original_ICorJitInfo->FilterException(pExceptionPointers); +} + +// Cleans up internal EE tracking when an exception is caught. +void interceptor_ICJI::HandleException( + struct _EXCEPTION_POINTERS *pExceptionPointers + ) +{ + original_ICorJitInfo->HandleException(pExceptionPointers); +} + +void interceptor_ICJI::ThrowExceptionForJitResult( + HRESULT result) +{ + original_ICorJitInfo->ThrowExceptionForJitResult(result); +} + +//Throws an exception defined by the given throw helper. +void interceptor_ICJI::ThrowExceptionForHelper( + const CORINFO_HELPER_DESC * throwHelper) +{ + original_ICorJitInfo->ThrowExceptionForHelper(throwHelper); +} + +/***************************************************************************** + * ICorStaticInfo contains EE interface methods which return values that are + * constant from invocation to invocation. Thus they may be embedded in + * persisted information like statically generated code. (This is of course + * assuming that all code versions are identical each time.) + *****************************************************************************/ + +// Return details about EE internal data structures +void interceptor_ICJI::getEEInfo( + CORINFO_EE_INFO *pEEInfoOut + ) +{ + original_ICorJitInfo->getEEInfo(pEEInfoOut); +} + +// Returns name of the JIT timer log +LPCWSTR interceptor_ICJI::getJitTimeLogFilename() +{ + return original_ICorJitInfo->getJitTimeLogFilename(); +} + + + /*********************************************************************************/ + // + // Diagnostic methods + // + /*********************************************************************************/ + +// this function is for debugging only. Returns method token. +// Returns mdMethodDefNil for dynamic methods. +mdMethodDef interceptor_ICJI::getMethodDefFromMethod( + CORINFO_METHOD_HANDLE hMethod + ) +{ + return original_ICorJitInfo->getMethodDefFromMethod(hMethod); +} + +// this function is for debugging only. It returns the method name +// and if 'moduleName' is non-null, it sets it to something that will +// says which method (a class name, or a module name) +const char* interceptor_ICJI::getMethodName ( + CORINFO_METHOD_HANDLE ftn, /* IN */ + const char **moduleName /* OUT */ + ) +{ + return original_ICorJitInfo->getMethodName(ftn, moduleName); +} + +// this function is for debugging only. It returns a value that +// is will always be the same for a given method. It is used +// to implement the 'jitRange' functionality +unsigned interceptor_ICJI::getMethodHash ( + CORINFO_METHOD_HANDLE ftn /* IN */ + ) +{ + return original_ICorJitInfo->getMethodHash(ftn); +} + +// this function is for debugging only. +size_t interceptor_ICJI::findNameOfToken ( + CORINFO_MODULE_HANDLE module, /* IN */ + mdToken metaTOK, /* IN */ + __out_ecount (FQNameCapacity) char * szFQName, /* OUT */ + size_t FQNameCapacity /* IN */ + ) +{ + return original_ICorJitInfo->findNameOfToken(module, metaTOK, szFQName, FQNameCapacity); +} + +bool interceptor_ICJI::getSystemVAmd64PassStructInRegisterDescriptor( + /* IN */ CORINFO_CLASS_HANDLE structHnd, + /* OUT */ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr + ) +{ + return original_ICorJitInfo->getSystemVAmd64PassStructInRegisterDescriptor(structHnd, structPassInRegDescPtr); +} + +//Stuff on ICorDynamicInfo +DWORD interceptor_ICJI::getThreadTLSIndex( + void **ppIndirection + ) +{ + return original_ICorJitInfo->getThreadTLSIndex(ppIndirection); +} + +const void * interceptor_ICJI::getInlinedCallFrameVptr( + void **ppIndirection + ) +{ + return original_ICorJitInfo->getInlinedCallFrameVptr(ppIndirection); +} + +LONG * interceptor_ICJI::getAddrOfCaptureThreadGlobal( + void **ppIndirection + ) +{ + return original_ICorJitInfo->getAddrOfCaptureThreadGlobal(ppIndirection); +} + +SIZE_T* interceptor_ICJI::getAddrModuleDomainID(CORINFO_MODULE_HANDLE module) +{ + return original_ICorJitInfo->getAddrModuleDomainID(module); +} + +// return the native entry point to an EE helper (see CorInfoHelpFunc) +void* interceptor_ICJI::getHelperFtn ( + CorInfoHelpFunc ftnNum, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getHelperFtn(ftnNum, ppIndirection); +} + +// return a callable address of the function (native code). This function +// may return a different value (depending on whether the method has +// been JITed or not. +void interceptor_ICJI::getFunctionEntryPoint( + CORINFO_METHOD_HANDLE ftn, /* IN */ + CORINFO_CONST_LOOKUP * pResult, /* OUT */ + CORINFO_ACCESS_FLAGS accessFlags) +{ + original_ICorJitInfo->getFunctionEntryPoint(ftn, pResult, accessFlags); +} + +// return a directly callable address. This can be used similarly to the +// value returned by getFunctionEntryPoint() except that it is +// guaranteed to be multi callable entrypoint. +void interceptor_ICJI::getFunctionFixedEntryPoint( + CORINFO_METHOD_HANDLE ftn, + CORINFO_CONST_LOOKUP * pResult) +{ + original_ICorJitInfo->getFunctionFixedEntryPoint(ftn, pResult); +} + +// get the synchronization handle that is passed to monXstatic function +void* interceptor_ICJI::getMethodSync( + CORINFO_METHOD_HANDLE ftn, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getMethodSync(ftn, ppIndirection); +} + +// These entry points must be called if a handle is being embedded in +// the code to be passed to a JIT helper function. (as opposed to just +// being passed back into the ICorInfo interface.) + +// get slow lazy string literal helper to use (CORINFO_HELP_STRCNS*). +// Returns CORINFO_HELP_UNDEF if lazy string literal helper cannot be used. +CorInfoHelpFunc interceptor_ICJI::getLazyStringLiteralHelper( + CORINFO_MODULE_HANDLE handle + ) +{ + return original_ICorJitInfo->getLazyStringLiteralHelper(handle); +} + +CORINFO_MODULE_HANDLE interceptor_ICJI::embedModuleHandle( + CORINFO_MODULE_HANDLE handle, + void **ppIndirection + ) +{ + return original_ICorJitInfo->embedModuleHandle(handle, ppIndirection); +} + +CORINFO_CLASS_HANDLE interceptor_ICJI::embedClassHandle( + CORINFO_CLASS_HANDLE handle, + void **ppIndirection + ) +{ + return original_ICorJitInfo->embedClassHandle(handle, ppIndirection); +} + +CORINFO_METHOD_HANDLE interceptor_ICJI::embedMethodHandle( + CORINFO_METHOD_HANDLE handle, + void **ppIndirection + ) +{ + return original_ICorJitInfo->embedMethodHandle(handle, ppIndirection); +} + +CORINFO_FIELD_HANDLE interceptor_ICJI::embedFieldHandle( + CORINFO_FIELD_HANDLE handle, + void **ppIndirection + ) +{ + return original_ICorJitInfo->embedFieldHandle(handle, ppIndirection); +} + +// Given a module scope (module), a method handle (context) and +// a metadata token (metaTOK), fetch the handle +// (type, field or method) associated with the token. +// If this is not possible at compile-time (because the current method's +// code is shared and the token contains generic parameters) +// then indicate how the handle should be looked up at run-time. +// +void interceptor_ICJI::embedGenericHandle( + CORINFO_RESOLVED_TOKEN * pResolvedToken, + BOOL fEmbedParent, // TRUE - embeds parent type handle of the field/method handle + CORINFO_GENERICHANDLE_RESULT * pResult) +{ + original_ICorJitInfo->embedGenericHandle(pResolvedToken, fEmbedParent, pResult); +} + +// Return information used to locate the exact enclosing type of the current method. +// Used only to invoke .cctor method from code shared across generic instantiations +// !needsRuntimeLookup statically known (enclosing type of method itself) +// needsRuntimeLookup: +// CORINFO_LOOKUP_THISOBJ use vtable pointer of 'this' param +// CORINFO_LOOKUP_CLASSPARAM use vtable hidden param +// CORINFO_LOOKUP_METHODPARAM use enclosing type of method-desc hidden param +CORINFO_LOOKUP_KIND interceptor_ICJI::getLocationOfThisType( + CORINFO_METHOD_HANDLE context + ) +{ + return original_ICorJitInfo->getLocationOfThisType(context); +} + +// return the unmanaged target *if method has already been prelinked.* +void* interceptor_ICJI::getPInvokeUnmanagedTarget( + CORINFO_METHOD_HANDLE method, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getPInvokeUnmanagedTarget(method, ppIndirection); +} + +// return address of fixup area for late-bound PInvoke calls. +void* interceptor_ICJI::getAddressOfPInvokeFixup( + CORINFO_METHOD_HANDLE method, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getAddressOfPInvokeFixup(method, ppIndirection); +} + +// return address of fixup area for late-bound PInvoke calls. +void interceptor_ICJI::getAddressOfPInvokeTarget( + CORINFO_METHOD_HANDLE method, + CORINFO_CONST_LOOKUP *pLookup + ) +{ + original_ICorJitInfo->getAddressOfPInvokeTarget(method, pLookup); +} + +// Generate a cookie based on the signature that would needs to be passed +// to CORINFO_HELP_PINVOKE_CALLI +LPVOID interceptor_ICJI::GetCookieForPInvokeCalliSig( + CORINFO_SIG_INFO* szMetaSig, + void ** ppIndirection + ) +{ + return original_ICorJitInfo->GetCookieForPInvokeCalliSig(szMetaSig, ppIndirection); +} + +// returns true if a VM cookie can be generated for it (might be false due to cross-module +// inlining, in which case the inlining should be aborted) +bool interceptor_ICJI::canGetCookieForPInvokeCalliSig( + CORINFO_SIG_INFO* szMetaSig + ) +{ + return original_ICorJitInfo->canGetCookieForPInvokeCalliSig(szMetaSig); +} + +// Gets a handle that is checked to see if the current method is +// included in "JustMyCode" +CORINFO_JUST_MY_CODE_HANDLE interceptor_ICJI::getJustMyCodeHandle( + CORINFO_METHOD_HANDLE method, + CORINFO_JUST_MY_CODE_HANDLE**ppIndirection + ) +{ + return original_ICorJitInfo->getJustMyCodeHandle(method, ppIndirection); +} + +// Gets a method handle that can be used to correlate profiling data. +// This is the IP of a native method, or the address of the descriptor struct +// for IL. Always guaranteed to be unique per process, and not to move. */ +void interceptor_ICJI::GetProfilingHandle( + BOOL *pbHookFunction, + void **pProfilerHandle, + BOOL *pbIndirectedHandles + ) +{ + original_ICorJitInfo->GetProfilingHandle(pbHookFunction, pProfilerHandle, pbIndirectedHandles); +} + +// Returns instructions on how to make the call. See code:CORINFO_CALL_INFO for possible return values. +void interceptor_ICJI::getCallInfo( + // Token info + CORINFO_RESOLVED_TOKEN * pResolvedToken, + + //Generics info + CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken, + + //Security info + CORINFO_METHOD_HANDLE callerHandle, + + //Jit info + CORINFO_CALLINFO_FLAGS flags, + + //out params + CORINFO_CALL_INFO *pResult + ) +{ + original_ICorJitInfo->getCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); +} + +BOOL interceptor_ICJI::canAccessFamily(CORINFO_METHOD_HANDLE hCaller, + CORINFO_CLASS_HANDLE hInstanceType) + +{ + return original_ICorJitInfo->canAccessFamily(hCaller, hInstanceType); +} +// Returns TRUE if the Class Domain ID is the RID of the class (currently true for every class +// except reflection emitted classes and generics) +BOOL interceptor_ICJI::isRIDClassDomainID(CORINFO_CLASS_HANDLE cls) +{ + return original_ICorJitInfo->isRIDClassDomainID(cls); +} + +// returns the class's domain ID for accessing shared statics +unsigned interceptor_ICJI::getClassDomainID ( + CORINFO_CLASS_HANDLE cls, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getClassDomainID(cls, ppIndirection); +} + + +// return the data's address (for static fields only) +void* interceptor_ICJI::getFieldAddress( + CORINFO_FIELD_HANDLE field, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getFieldAddress(field, ppIndirection); +} + +// registers a vararg sig & returns a VM cookie for it (which can contain other stuff) +CORINFO_VARARGS_HANDLE interceptor_ICJI::getVarArgsHandle( + CORINFO_SIG_INFO *pSig, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getVarArgsHandle(pSig, ppIndirection); +} + +// returns true if a VM cookie can be generated for it (might be false due to cross-module +// inlining, in which case the inlining should be aborted) +bool interceptor_ICJI::canGetVarArgsHandle( + CORINFO_SIG_INFO *pSig + ) +{ + return original_ICorJitInfo->canGetVarArgsHandle(pSig); +} + +// Allocate a string literal on the heap and return a handle to it +InfoAccessType interceptor_ICJI::constructStringLiteral( + CORINFO_MODULE_HANDLE module, + mdToken metaTok, + void **ppValue + ) +{ + return original_ICorJitInfo->constructStringLiteral(module, metaTok, ppValue); +} + +InfoAccessType interceptor_ICJI::emptyStringLiteral( + void **ppValue + ) +{ + return original_ICorJitInfo->emptyStringLiteral(ppValue); +} + +// (static fields only) given that 'field' refers to thread local store, +// return the ID (TLS index), which is used to find the begining of the +// TLS data area for the particular DLL 'field' is associated with. +DWORD interceptor_ICJI::getFieldThreadLocalStoreID ( + CORINFO_FIELD_HANDLE field, + void **ppIndirection + ) +{ + return original_ICorJitInfo->getFieldThreadLocalStoreID(field, ppIndirection); +} + +// Sets another object to intercept calls to "self" and current method being compiled +void interceptor_ICJI::setOverride( + ICorDynamicInfo *pOverride, + CORINFO_METHOD_HANDLE currentMethod + ) +{ + original_ICorJitInfo->setOverride(pOverride, currentMethod); +} + +// Adds an active dependency from the context method's module to the given module +// This is internal callback for the EE. JIT should not call it directly. +void interceptor_ICJI::addActiveDependency( + CORINFO_MODULE_HANDLE moduleFrom, + CORINFO_MODULE_HANDLE moduleTo + ) +{ + original_ICorJitInfo->addActiveDependency(moduleFrom, moduleTo); +} + +CORINFO_METHOD_HANDLE interceptor_ICJI::GetDelegateCtor( + CORINFO_METHOD_HANDLE methHnd, + CORINFO_CLASS_HANDLE clsHnd, + CORINFO_METHOD_HANDLE targetMethodHnd, + DelegateCtorArgs * pCtorData + ) +{ + return original_ICorJitInfo->GetDelegateCtor(methHnd, clsHnd, targetMethodHnd, pCtorData); +} + +void interceptor_ICJI::MethodCompileComplete( + CORINFO_METHOD_HANDLE methHnd + ) +{ + original_ICorJitInfo->MethodCompileComplete(methHnd); +} + +// return a thunk that will copy the arguments for the given signature. +void* interceptor_ICJI::getTailCallCopyArgsThunk ( + CORINFO_SIG_INFO *pSig, + CorInfoHelperTailCallSpecialHandling flags + ) +{ + return original_ICorJitInfo->getTailCallCopyArgsThunk(pSig, flags); +} + +//Stuff directly on ICorJitInfo + +// Returns extended flags for a particular compilation instance. +DWORD interceptor_ICJI::getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes) +{ + return original_ICorJitInfo->getJitFlags(jitFlags, sizeInBytes); +} + +// Runs the given function with the given parameter under an error trap +// and returns true if the function completes successfully. +bool interceptor_ICJI::runWithErrorTrap(void (*function)(void*), void *param) +{ + return original_ICorJitInfo->runWithErrorTrap(function, param); +} + +// return memory manager that the JIT can use to allocate a regular memory +IEEMemoryManager* interceptor_ICJI::getMemoryManager() +{ + if(current_IEEMM->original_IEEMM == nullptr) + current_IEEMM->original_IEEMM = original_ICorJitInfo->getMemoryManager(); + + return current_IEEMM; +} + +// get a block of memory for the code, readonly data, and read-write data +void interceptor_ICJI::allocMem ( + ULONG hotCodeSize, /* IN */ + ULONG coldCodeSize, /* IN */ + ULONG roDataSize, /* IN */ + ULONG xcptnsCount, /* IN */ + CorJitAllocMemFlag flag, /* IN */ + void ** hotCodeBlock, /* OUT */ + void ** coldCodeBlock, /* OUT */ + void ** roDataBlock /* OUT */ + ) +{ + return original_ICorJitInfo->allocMem(hotCodeSize, coldCodeSize, roDataSize, xcptnsCount, flag, hotCodeBlock, coldCodeBlock, roDataBlock); +} + +// Reserve memory for the method/funclet's unwind information. +// Note that this must be called before allocMem. It should be +// called once for the main method, once for every funclet, and +// once for every block of cold code for which allocUnwindInfo +// will be called. +// +// This is necessary because jitted code must allocate all the +// memory needed for the unwindInfo at the allocMem call. +// For prejitted code we split up the unwinding information into +// separate sections .rdata and .pdata. +// +void interceptor_ICJI::reserveUnwindInfo ( + BOOL isFunclet, /* IN */ + BOOL isColdCode, /* IN */ + ULONG unwindSize /* IN */ + ) +{ + original_ICorJitInfo->reserveUnwindInfo(isFunclet, isColdCode, unwindSize); +} + +// Allocate and initialize the .rdata and .pdata for this method or +// funclet, and get the block of memory needed for the machine-specific +// unwind information (the info for crawling the stack frame). +// Note that allocMem must be called first. +// +// Parameters: +// +// pHotCode main method code buffer, always filled in +// pColdCode cold code buffer, only filled in if this is cold code, +// null otherwise +// startOffset start of code block, relative to appropriate code buffer +// (e.g. pColdCode if cold, pHotCode if hot). +// endOffset end of code block, relative to appropriate code buffer +// unwindSize size of unwind info pointed to by pUnwindBlock +// pUnwindBlock pointer to unwind info +// funcKind type of funclet (main method code, handler, filter) +// +void interceptor_ICJI::allocUnwindInfo ( + BYTE * pHotCode, /* IN */ + BYTE * pColdCode, /* IN */ + ULONG startOffset, /* IN */ + ULONG endOffset, /* IN */ + ULONG unwindSize, /* IN */ + BYTE * pUnwindBlock, /* IN */ + CorJitFuncKind funcKind /* IN */ + ) +{ + original_ICorJitInfo->allocUnwindInfo(pHotCode, pColdCode, startOffset, endOffset, unwindSize, pUnwindBlock, funcKind); +} + +// Get a block of memory needed for the code manager information, +// (the info for enumerating the GC pointers while crawling the +// stack frame). +// Note that allocMem must be called first +void * interceptor_ICJI::allocGCInfo ( + size_t size /* IN */ + ) +{ + return original_ICorJitInfo->allocGCInfo(size); +} + +// only used on x64 +void interceptor_ICJI::yieldExecution() +{ + original_ICorJitInfo->yieldExecution(); +} + +// Indicate how many exception handler blocks are to be returned. +// This is guaranteed to be called before any 'setEHinfo' call. +// Note that allocMem must be called before this method can be called. +void interceptor_ICJI::setEHcount ( + unsigned cEH /* IN */ + ) +{ + original_ICorJitInfo->setEHcount(cEH); +} + +// Set the values for one particular exception handler block. +// +// Handler regions should be lexically contiguous. +// This is because FinallyIsUnwinding() uses lexicality to +// determine if a "finally" clause is executing. +void interceptor_ICJI::setEHinfo ( + unsigned EHnumber, /* IN */ + const CORINFO_EH_CLAUSE *clause /* IN */ + ) +{ + original_ICorJitInfo->setEHinfo(EHnumber, clause); +} + +// Level 1 -> fatalError, Level 2 -> Error, Level 3 -> Warning +// Level 4 means happens 10 times in a run, level 5 means 100, level 6 means 1000 ... +// returns non-zero if the logging succeeded +BOOL interceptor_ICJI::logMsg(unsigned level, const char* fmt, va_list args) +{ + return original_ICorJitInfo->logMsg(level, fmt, args); +} + +// do an assert. will return true if the code should retry (DebugBreak) +// returns false, if the assert should be igored. +int interceptor_ICJI::doAssert(const char* szFile, int iLine, const char* szExpr) +{ + return original_ICorJitInfo->doAssert(szFile, iLine, szExpr); +} + +void interceptor_ICJI::reportFatalError(CorJitResult result) +{ + original_ICorJitInfo->reportFatalError(result); +} + +// allocate a basic block profile buffer where execution counts will be stored +// for jitted basic blocks. +HRESULT interceptor_ICJI::allocBBProfileBuffer ( + ULONG count, // The number of basic blocks that we have + ProfileBuffer ** profileBuffer + ) +{ + return original_ICorJitInfo->allocBBProfileBuffer(count, profileBuffer); +} + +// get profile information to be used for optimizing the current method. The format +// of the buffer is the same as the format the JIT passes to allocBBProfileBuffer. +HRESULT interceptor_ICJI::getBBProfileData( + CORINFO_METHOD_HANDLE ftnHnd, + ULONG * count, // The number of basic blocks that we have + ProfileBuffer ** profileBuffer, + ULONG * numRuns + ) +{ + return original_ICorJitInfo->getBBProfileData(ftnHnd, count, profileBuffer, numRuns); +} + +// Associates a native call site, identified by its offset in the native code stream, with +// the signature information and method handle the JIT used to lay out the call site. If +// the call site has no signature information (e.g. a helper call) or has no method handle +// (e.g. a CALLI P/Invoke), then null should be passed instead. +void interceptor_ICJI::recordCallSite( + ULONG instrOffset, /* IN */ + CORINFO_SIG_INFO * callSig, /* IN */ + CORINFO_METHOD_HANDLE methodHandle /* IN */ + ) +{ + original_ICorJitInfo->recordCallSite(instrOffset, callSig, methodHandle); +} + +// A relocation is recorded if we are pre-jitting. +// A jump thunk may be inserted if we are jitting +void interceptor_ICJI::recordRelocation( + void * location, /* IN */ + void * target, /* IN */ + WORD fRelocType, /* IN */ + WORD slotNum, /* IN */ + INT32 addlDelta /* IN */ + ) +{ + original_ICorJitInfo->recordRelocation(location, target, fRelocType, slotNum, addlDelta); +} + +WORD interceptor_ICJI::getRelocTypeHint(void * target) +{ + return original_ICorJitInfo->getRelocTypeHint(target); +} + +// A callback to identify the range of address known to point to +// compiler-generated native entry points that call back into +// MSIL. +void interceptor_ICJI::getModuleNativeEntryPointRange( + void ** pStart, /* OUT */ + void ** pEnd /* OUT */ + ) +{ + original_ICorJitInfo->getModuleNativeEntryPointRange(pStart, pEnd); +} + +// For what machine does the VM expect the JIT to generate code? The VM +// returns one of the IMAGE_FILE_MACHINE_* values. Note that if the VM +// is cross-compiling (such as the case for crossgen), it will return a +// different value than if it was compiling for the host architecture. +// +DWORD interceptor_ICJI::getExpectedTargetArchitecture() +{ + return original_ICorJitInfo->getExpectedTargetArchitecture(); +} diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h new file mode 100644 index 0000000000..c266f036fb --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _ICorJitInfo +#define _ICorJitInfo + +#include "runtimedetails.h" +#include "ieememorymanager.h" + +class interceptor_ICJI : public ICorJitInfo +{ + +#include "icorjitinfoimpl.h" + +public: + + //Added to help us track the original icji and be able to easily indirect + //to it. And a simple way to keep one memory manager instance per instance. + ICorJitInfo *original_ICorJitInfo; +}; + +#endif diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/ieememorymanager.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/ieememorymanager.cpp new file mode 100644 index 0000000000..668b4b7728 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/ieememorymanager.cpp @@ -0,0 +1,72 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "ieememorymanager.h" +#include "superpmi-shim-simple.h" + +//*************************************************************************** +// IUnknown methods +//*************************************************************************** +HRESULT STDMETHODCALLTYPE interceptor_IEEMM::QueryInterface(REFIID id, void **pInterface) +{ + return original_IEEMM->QueryInterface(id, pInterface); +} +ULONG STDMETHODCALLTYPE interceptor_IEEMM::AddRef() +{ + return original_IEEMM->AddRef(); +} +ULONG STDMETHODCALLTYPE interceptor_IEEMM::Release() +{ + return original_IEEMM->Release(); +} + +//*************************************************************************** +// IEEMemoryManager methods for locking +//*************************************************************************** +LPVOID STDMETHODCALLTYPE interceptor_IEEMM::ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect) +{ + return original_IEEMM->ClrVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); +} +BOOL STDMETHODCALLTYPE interceptor_IEEMM::ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType) +{ + return original_IEEMM->ClrVirtualFree(lpAddress, dwSize, dwFreeType); +} +SIZE_T STDMETHODCALLTYPE interceptor_IEEMM::ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength) +{ + return original_IEEMM->ClrVirtualQuery(lpAddress, lpBuffer, dwLength); +} +BOOL STDMETHODCALLTYPE interceptor_IEEMM::ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect) +{ + return original_IEEMM->ClrVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); +} +HANDLE STDMETHODCALLTYPE interceptor_IEEMM::ClrGetProcessHeap() +{ + return original_IEEMM->ClrGetProcessHeap(); +} +HANDLE STDMETHODCALLTYPE interceptor_IEEMM::ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize) +{ + return original_IEEMM->ClrHeapCreate(flOptions, dwInitialSize, dwMaximumSize); +} +BOOL STDMETHODCALLTYPE interceptor_IEEMM::ClrHeapDestroy(HANDLE hHeap) +{ + return original_IEEMM->ClrHeapDestroy(hHeap); +} +LPVOID STDMETHODCALLTYPE interceptor_IEEMM::ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) +{ + return original_IEEMM->ClrHeapAlloc(hHeap, dwFlags, dwBytes); +} +BOOL STDMETHODCALLTYPE interceptor_IEEMM::ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) +{ + return original_IEEMM->ClrHeapFree(hHeap, dwFlags, lpMem); +} +BOOL STDMETHODCALLTYPE interceptor_IEEMM::ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem) +{ + return original_IEEMM->ClrHeapValidate(hHeap, dwFlags, lpMem); +} +HANDLE STDMETHODCALLTYPE interceptor_IEEMM::ClrGetProcessExecutableHeap() +{ + return original_IEEMM->ClrGetProcessExecutableHeap(); +} diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/ieememorymanager.h b/src/ToolBox/superpmi/superpmi-shim-simple/ieememorymanager.h new file mode 100644 index 0000000000..411c532b59 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/ieememorymanager.h @@ -0,0 +1,108 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _IEEMemoryManager +#define _IEEMemoryManager + +#include "runtimedetails.h" + +/* +interface IEEMemoryManager : IUnknown +{ + LPVOID ClrVirtualAlloc( + [in] LPVOID lpAddress, // region to reserve or commit + [in] SIZE_T dwSize, // size of region + [in] DWORD flAllocationType, // type of allocation + [in] DWORD flProtect // type of access protection + ) + + BOOL ClrVirtualFree( + [in] LPVOID lpAddress, // address of region + [in] SIZE_T dwSize, // size of region + [in] DWORD dwFreeType // operation type + ) + + SIZE_T ClrVirtualQuery( + [in] const void* lpAddress, // address of region + [in] PMEMORY_BASIC_INFORMATION lpBuffer, // information buffer + [in] SIZE_T dwLength // size of buffer + ) + + BOOL ClrVirtualProtect( + [in] LPVOID lpAddress, // region of committed pages + [in] SIZE_T dwSize, // size of the region + [in] DWORD flNewProtect, // desired access protection + [in] DWORD* lpflOldProtect // old protection + ) + + HANDLE ClrGetProcessHeap() + + HANDLE ClrHeapCreate( + [in] DWORD flOptions, // heap allocation attributes + [in] SIZE_T dwInitialSize, // initial heap size + [in] SIZE_T dwMaximumSize // maximum heap size + ) + + BOOL ClrHeapDestroy( + [in] HANDLE hHeap // handle to heap + ) + + LPVOID ClrHeapAlloc( + [in] HANDLE hHeap, // handle to private heap block + [in] DWORD dwFlags, // heap allocation control + [in] SIZE_T dwBytes // number of bytes to allocate + ) + + BOOL ClrHeapFree( + [in] HANDLE hHeap, // handle to heap + [in] DWORD dwFlags, // heap free options + [in] LPVOID lpMem // pointer to memory + ) + + BOOL ClrHeapValidate( + [in] HANDLE hHeap, // handle to heap + [in] DWORD dwFlags, // heap access options + [in] const void* lpMem // optional pointer to memory block + ) + + HANDLE ClrGetProcessExecutableHeap() + +}; // interface IEEMemoryManager + +*/ + +class interceptor_IEEMM : public IEEMemoryManager +{ +private: + + //*************************************************************************** + // IUnknown methods + //*************************************************************************** + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, void **pInterface); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + //*************************************************************************** + // IEEMemoryManager methods for locking + //*************************************************************************** + LPVOID STDMETHODCALLTYPE ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect); + BOOL STDMETHODCALLTYPE ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType); + SIZE_T STDMETHODCALLTYPE ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength); + BOOL STDMETHODCALLTYPE ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect); + HANDLE STDMETHODCALLTYPE ClrGetProcessHeap(); + HANDLE STDMETHODCALLTYPE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize); + BOOL STDMETHODCALLTYPE ClrHeapDestroy(HANDLE hHeap); + LPVOID STDMETHODCALLTYPE ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes); + BOOL STDMETHODCALLTYPE ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem); + BOOL STDMETHODCALLTYPE ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem); + HANDLE STDMETHODCALLTYPE ClrGetProcessExecutableHeap(); + +public: + // Added so we know where to make the real calls to. + IEEMemoryManager *original_IEEMM; +}; + +#endif diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/iexecutionengine.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/iexecutionengine.cpp new file mode 100644 index 0000000000..a137266751 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/iexecutionengine.cpp @@ -0,0 +1,158 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "iexecutionengine.h" +#include "superpmi-shim-simple.h" + +//*************************************************************************** +// IUnknown methods +//*************************************************************************** +HRESULT STDMETHODCALLTYPE interceptor_IEE::QueryInterface(REFIID id, void **pInterface) +{ + return original_IEE->QueryInterface(id, pInterface); +} +ULONG STDMETHODCALLTYPE interceptor_IEE::AddRef() +{ + return original_IEE->AddRef(); +} +ULONG STDMETHODCALLTYPE interceptor_IEE::Release() +{ + return original_IEE->Release(); +} + +//*************************************************************************** +// IExecutionEngine methods for TLS +//*************************************************************************** +// Associate a callback for cleanup with a TLS slot +VOID STDMETHODCALLTYPE interceptor_IEE::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback) +{ + original_IEE->TLS_AssociateCallback(slot, callback); +} +// Get the TLS block for fast Get/Set operations +LPVOID* STDMETHODCALLTYPE interceptor_IEE::TLS_GetDataBlock() +{ + return original_IEE->TLS_GetDataBlock(); +} + +// Get the value at a slot +LPVOID STDMETHODCALLTYPE interceptor_IEE::TLS_GetValue(DWORD slot) +{ + return original_IEE->TLS_GetValue(slot); +} + +// Get the value at a slot, return FALSE if TLS info block doesn't exist +BOOL STDMETHODCALLTYPE interceptor_IEE::TLS_CheckValue(DWORD slot, LPVOID * pValue) +{ + return original_IEE->TLS_CheckValue(slot, pValue); +} +// Set the value at a slot +VOID STDMETHODCALLTYPE interceptor_IEE::TLS_SetValue(DWORD slot, LPVOID pData) +{ + original_IEE->TLS_SetValue(slot, pData); +} +// Free TLS memory block and make callback +VOID STDMETHODCALLTYPE interceptor_IEE::TLS_ThreadDetaching() +{ + original_IEE->TLS_ThreadDetaching(); +} + +//*************************************************************************** +// IExecutionEngine methods for locking +//*************************************************************************** +CRITSEC_COOKIE STDMETHODCALLTYPE interceptor_IEE::CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags) +{ + return original_IEE->CreateLock(szTag, level, flags); +} +void STDMETHODCALLTYPE interceptor_IEE::DestroyLock(CRITSEC_COOKIE lock) +{ + original_IEE->DestroyLock(lock); +} +void STDMETHODCALLTYPE interceptor_IEE::AcquireLock(CRITSEC_COOKIE lock) +{ + original_IEE->AcquireLock(lock); +} +void STDMETHODCALLTYPE interceptor_IEE::ReleaseLock(CRITSEC_COOKIE lock) +{ + original_IEE->ReleaseLock(lock); +} + +EVENT_COOKIE STDMETHODCALLTYPE interceptor_IEE::CreateAutoEvent(BOOL bInitialState) +{ + return original_IEE->CreateAutoEvent(bInitialState); +} +EVENT_COOKIE STDMETHODCALLTYPE interceptor_IEE::CreateManualEvent(BOOL bInitialState) +{ + return original_IEE->CreateManualEvent(bInitialState); +} +void STDMETHODCALLTYPE interceptor_IEE::CloseEvent(EVENT_COOKIE event) +{ + original_IEE->CloseEvent(event); +} +BOOL STDMETHODCALLTYPE interceptor_IEE::ClrSetEvent(EVENT_COOKIE event) +{ + return original_IEE->ClrSetEvent(event); +} +BOOL STDMETHODCALLTYPE interceptor_IEE::ClrResetEvent(EVENT_COOKIE event) +{ + return original_IEE->ClrResetEvent(event); +} +DWORD STDMETHODCALLTYPE interceptor_IEE::WaitForEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable) +{ + return original_IEE->WaitForEvent(event, dwMilliseconds, bAlertable); +} +DWORD STDMETHODCALLTYPE interceptor_IEE::WaitForSingleObject(HANDLE handle, DWORD dwMilliseconds) +{ + return original_IEE->WaitForSingleObject(handle, dwMilliseconds); +} +SEMAPHORE_COOKIE STDMETHODCALLTYPE interceptor_IEE::ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax) +{ + return original_IEE->ClrCreateSemaphore(dwInitial, dwMax); +} +void STDMETHODCALLTYPE interceptor_IEE::ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore) +{ + original_IEE->ClrCloseSemaphore(semaphore); +} +DWORD STDMETHODCALLTYPE interceptor_IEE::ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable) +{ + return original_IEE->ClrWaitForSemaphore(semaphore, dwMilliseconds, bAlertable); +} +BOOL STDMETHODCALLTYPE interceptor_IEE::ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount) +{ + return original_IEE->ClrReleaseSemaphore(semaphore, lReleaseCount, lpPreviousCount); +} +MUTEX_COOKIE STDMETHODCALLTYPE interceptor_IEE::ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, + BOOL bInitialOwner, + LPCTSTR lpName) +{ + return original_IEE->ClrCreateMutex(lpMutexAttributes, bInitialOwner, lpName); +} +void STDMETHODCALLTYPE interceptor_IEE::ClrCloseMutex(MUTEX_COOKIE mutex) +{ + original_IEE->ClrCloseMutex(mutex); +} +BOOL STDMETHODCALLTYPE interceptor_IEE::ClrReleaseMutex(MUTEX_COOKIE mutex) +{ + return original_IEE->ClrReleaseMutex(mutex); +} +DWORD STDMETHODCALLTYPE interceptor_IEE::ClrWaitForMutex(MUTEX_COOKIE mutex, + DWORD dwMilliseconds, + BOOL bAlertable) +{ + return original_IEE->ClrWaitForMutex(mutex, dwMilliseconds, bAlertable); +} + +DWORD STDMETHODCALLTYPE interceptor_IEE::ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable) +{ + return original_IEE->ClrSleepEx(dwMilliseconds, bAlertable); +} +BOOL STDMETHODCALLTYPE interceptor_IEE::ClrAllocationDisallowed() +{ + return original_IEE->ClrAllocationDisallowed(); +} +void STDMETHODCALLTYPE interceptor_IEE::GetLastThrownObjectExceptionFromThread(void **ppvException) +{ + original_IEE->GetLastThrownObjectExceptionFromThread(ppvException); +} diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/iexecutionengine.h b/src/ToolBox/superpmi/superpmi-shim-simple/iexecutionengine.h new file mode 100644 index 0000000000..dd3d7ee1fa --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/iexecutionengine.h @@ -0,0 +1,150 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _IExecutionEngine +#define _IExecutionEngine + +#include "ieememorymanager.h" + +/* +interface IExecutionEngine : IUnknown +{ + // Thread Local Storage is based on logical threads. The underlying + // implementation could be threads, fibers, or something more exotic. + // Slot numbers are predefined. This is not a general extensibility + // mechanism. + + // Associate a callback function for releasing TLS on thread/fiber death. + // This can be NULL. + void TLS_AssociateCallback([in] DWORD slot, [in] PTLS_CALLBACK_FUNCTION callback) + + // May be called once to get the master TLS block slot for fast Get/Set operations + DWORD TLS_GetMasterSlotIndex() + + // Get the value at a slot + PVOID TLS_GetValue([in] DWORD slot) + + // Get the value at a slot, return FALSE if TLS info block doesn't exist + BOOL TLS_CheckValue([in] DWORD slot, [out] PVOID * pValue) + + // Set the value at a slot + void TLS_SetValue([in] DWORD slot, [in] PVOID pData) + + // Free TLS memory block and make callback + void TLS_ThreadDetaching() + + // Critical Sections are sometimes exposed to the host and therefore need to be + // reflected from all CLR DLLs to the EE. + // + // In addition, we always monitor interactions between the lock & the GC, based + // on the GC mode in which the lock is acquired and we restrict what operations + // are permitted while holding the lock based on this. + // + // Finally, we we rank all our locks to prevent deadlock across all the DLLs of + // the CLR. This is the level argument to CreateLock. + // + // All usage of these locks must be exception-safe. To achieve this, we suggest + // using Holders (see holder.h & crst.h). In fact, within the EE code cannot + // hold locks except by using exception-safe holders. + + CRITSEC_COOKIE CreateLock([in] LPCSTR szTag, [in] LPCSTR level, [in] CrstFlags flags) + + void DestroyLock([in] CRITSEC_COOKIE lock) + + void AcquireLock([in] CRITSEC_COOKIE lock) + + void ReleaseLock([in] CRITSEC_COOKIE lock) + + EVENT_COOKIE CreateAutoEvent([in] BOOL bInitialState) + EVENT_COOKIE CreateManualEvent([in] BOOL bInitialState) + void CloseEvent([in] EVENT_COOKIE event) + BOOL ClrSetEvent([in] EVENT_COOKIE event) + BOOL ClrResetEvent([in] EVENT_COOKIE event) + DWORD WaitForEvent([in] EVENT_COOKIE event, [in] DWORD dwMilliseconds, [in] BOOL bAlertable) + DWORD WaitForSingleObject([in] HANDLE handle, [in] DWORD dwMilliseconds) + + // OS header file defines CreateSemaphore. + SEMAPHORE_COOKIE ClrCreateSemaphore([in] DWORD dwInitial, [in] DWORD dwMax) + void ClrCloseSemaphore([in] SEMAPHORE_COOKIE semaphore) + DWORD ClrWaitForSemaphore([in] SEMAPHORE_COOKIE semaphore, [in] DWORD dwMilliseconds, [in] BOOL bAlertable) + BOOL ClrReleaseSemaphore([in] SEMAPHORE_COOKIE semaphore, [in] LONG lReleaseCount, [in] LONG *lpPreviousCount) + + MUTEX_COOKIE ClrCreateMutex([in]LPSECURITY_ATTRIBUTES lpMutexAttributes, [in]BOOL bInitialOwner, [in]LPCTSTR lpName) + DWORD ClrWaitForMutex([in] MUTEX_COOKIE mutex, [in] DWORD dwMilliseconds, [in] BOOL bAlertable) + BOOL ClrReleaseMutex([in] MUTEX_COOKIE mutex) + void ClrCloseMutex([in] MUTEX_COOKIE mutex) + + DWORD ClrSleepEx([in] DWORD dwMilliseconds, [in] BOOL bAlertable) + + BOOL ClrAllocationDisallowed() + + void GetLastThrownObjectExceptionFromThread([out] void **ppvException) + +}; // interface IExecutionEngine +*/ + +class interceptor_IEE : public IExecutionEngine +{ +private: + + //*************************************************************************** + // IUnknown methods + //*************************************************************************** + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, void **pInterface); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + //*************************************************************************** + // IExecutionEngine methods for TLS + //*************************************************************************** + // Associate a callback for cleanup with a TLS slot + VOID STDMETHODCALLTYPE TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback); + // Get the TLS block for fast Get/Set operations + LPVOID* STDMETHODCALLTYPE TLS_GetDataBlock(); + // Get the value at a slot + LPVOID STDMETHODCALLTYPE TLS_GetValue(DWORD slot); + // Get the value at a slot, return FALSE if TLS info block doesn't exist + BOOL STDMETHODCALLTYPE TLS_CheckValue(DWORD slot, LPVOID * pValue); + // Set the value at a slot + VOID STDMETHODCALLTYPE TLS_SetValue(DWORD slot, LPVOID pData); + // Free TLS memory block and make callback + VOID STDMETHODCALLTYPE TLS_ThreadDetaching(); + + //*************************************************************************** + // IExecutionEngine methods for locking + //*************************************************************************** + CRITSEC_COOKIE STDMETHODCALLTYPE CreateLock(LPCSTR szTag, LPCSTR level, CrstFlags flags); + void STDMETHODCALLTYPE DestroyLock(CRITSEC_COOKIE lock); + void STDMETHODCALLTYPE AcquireLock(CRITSEC_COOKIE lock); + void STDMETHODCALLTYPE ReleaseLock(CRITSEC_COOKIE lock); + EVENT_COOKIE STDMETHODCALLTYPE CreateAutoEvent(BOOL bInitialState); + EVENT_COOKIE STDMETHODCALLTYPE CreateManualEvent(BOOL bInitialState); + void STDMETHODCALLTYPE CloseEvent(EVENT_COOKIE event); + BOOL STDMETHODCALLTYPE ClrSetEvent(EVENT_COOKIE event); + BOOL STDMETHODCALLTYPE ClrResetEvent(EVENT_COOKIE event); + DWORD STDMETHODCALLTYPE WaitForEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable); + DWORD STDMETHODCALLTYPE WaitForSingleObject(HANDLE handle, DWORD dwMilliseconds); + SEMAPHORE_COOKIE STDMETHODCALLTYPE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax); + void STDMETHODCALLTYPE ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore); + DWORD STDMETHODCALLTYPE ClrWaitForSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable); + BOOL STDMETHODCALLTYPE ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount); + MUTEX_COOKIE STDMETHODCALLTYPE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, + BOOL bInitialOwner, + LPCTSTR lpName); + void STDMETHODCALLTYPE ClrCloseMutex(MUTEX_COOKIE mutex); + BOOL STDMETHODCALLTYPE ClrReleaseMutex(MUTEX_COOKIE mutex); + DWORD STDMETHODCALLTYPE ClrWaitForMutex(MUTEX_COOKIE mutex, + DWORD dwMilliseconds, + BOOL bAlertable); + DWORD STDMETHODCALLTYPE ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable); + BOOL STDMETHODCALLTYPE ClrAllocationDisallowed(); + void STDMETHODCALLTYPE GetLastThrownObjectExceptionFromThread(void **ppvException); + +public: + // Added so we know where to make the real calls to. + IExecutionEngine *original_IEE; +}; + +#endif
\ No newline at end of file diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/jithost.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/jithost.cpp new file mode 100644 index 0000000000..01bff37a01 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/jithost.cpp @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "standardpch.h" +#include "runtimedetails.h" +#include "spmiutil.h" +#include "jithost.h" + +JitHost* g_ourJitHost; + +JitHost::JitHost(ICorJitHost* wrappedHost) : wrappedHost(wrappedHost) +{ +} + +void* JitHost::allocateMemory(size_t size, bool usePageAllocator) +{ + return wrappedHost->allocateMemory(size, usePageAllocator); +} + +void JitHost::freeMemory(void* block, bool usePageAllocator) +{ + return wrappedHost->freeMemory(block, usePageAllocator); +} + +int JitHost::getIntConfigValue(const wchar_t* key, int defaultValue) +{ + return wrappedHost->getIntConfigValue(key, defaultValue); +} + +const wchar_t* JitHost::getStringConfigValue(const wchar_t* key) +{ + return wrappedHost->getStringConfigValue(key); +} + +void JitHost::freeStringConfigValue(const wchar_t* value) +{ + wrappedHost->freeStringConfigValue(value); +} diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/jithost.h b/src/ToolBox/superpmi/superpmi-shim-simple/jithost.h new file mode 100644 index 0000000000..7df1c581dc --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/jithost.h @@ -0,0 +1,22 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#ifndef _JITHOST +#define _JITHOST + +class JitHost : public ICorJitHost +{ +public: + JitHost(ICorJitHost* wrappedHost); + +#include "icorjithostimpl.h" + +private: + ICorJitHost* wrappedHost; +}; + +extern JitHost* g_ourJitHost; + +#endif diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp new file mode 100644 index 0000000000..2381d0fa38 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.cpp @@ -0,0 +1,217 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// SuperPMI-Shim.cpp - thin shim for the jit +//---------------------------------------------------------- + +#include "standardpch.h" +#include "superpmi-shim-simple.h" +#include "runtimedetails.h" +#include "coreclrcallbacks.h" +#include "icorjitcompiler.h" +#include "errorhandling.h" +#include "logging.h" +#include "spmiutil.h" +#include "jithost.h" + +HMODULE g_hRealJit = 0; //We leak this currently (could do the proper shutdown in process_detach) +WCHAR* g_realJitPath = nullptr; //We leak this (could do the proper shutdown in process_detach) +char* g_logFilePath = nullptr; //We *don't* leak this, hooray! +WCHAR* g_HomeDirectory = nullptr; +WCHAR* g_DefaultRealJitPath = nullptr; + +void SetDefaultPaths() +{ + if (g_HomeDirectory == nullptr) + { + g_HomeDirectory = GetEnvironmentVariableWithDefaultW(W("HOME"), W(".")); + } + + if (g_DefaultRealJitPath == nullptr) + { + size_t len = wcslen(g_HomeDirectory) + 1 + wcslen(DEFAULT_REAL_JIT_NAME_W) + 1; + g_DefaultRealJitPath = new WCHAR[len]; + wcscpy_s(g_DefaultRealJitPath, len, g_HomeDirectory); + wcscat_s(g_DefaultRealJitPath, len, DIRECTORY_SEPARATOR_STR_W); + wcscat_s(g_DefaultRealJitPath, len, DEFAULT_REAL_JIT_NAME_W); + } +} + +void SetLibName() +{ + if (g_realJitPath == nullptr) + { + g_realJitPath = GetEnvironmentVariableWithDefaultW(W("SuperPMIShimPath"), g_DefaultRealJitPath); + } +} + +// TODO: this only works for ANSI file paths... +void SetLogFilePath() +{ + if (g_logFilePath == nullptr) + { + // If the environment variable isn't set, we don't enable file logging + g_logFilePath = GetEnvironmentVariableWithDefaultA("SuperPMIShimLogFilePath", nullptr); + } +} + +extern "C" +BOOL +#ifndef FEATURE_PAL +APIENTRY +#endif // !FEATURE_PAL +DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: +#ifdef FEATURE_PAL + if (0 != PAL_InitializeDLL()) + { + fprintf(stderr, "Error: Fail to PAL_InitializeDLL\n"); + exit(1); + } +#endif // FEATURE_PAL + + Logger::Initialize(); + SetLogFilePath(); + Logger::OpenLogFile(g_logFilePath); + break; + + case DLL_PROCESS_DETACH: + Logger::Shutdown(); + + delete[] g_logFilePath; + g_logFilePath = nullptr; + + break; + + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + } + return TRUE; +} + +// Exported via def file +extern "C" +void __stdcall jitStartup(ICorJitHost* host) +{ + SetDefaultPaths(); + SetLibName(); + + //Load Library + if (g_hRealJit == 0) + { + g_hRealJit = ::LoadLibraryW(g_realJitPath); + if (g_hRealJit == 0) + { + LogError("getJit() - LoadLibrary failed to load '%ws' (0x%08x)", g_realJitPath, ::GetLastError()); + return; + } + } + + // Get the required entrypoint + PjitStartup pnjitStartup = (PjitStartup)::GetProcAddress(g_hRealJit, "jitStartup"); + if (pnjitStartup == nullptr) + { + // This portion of the interface is not used by the JIT under test. + g_ourJitHost = nullptr; + return; + } + + g_ourJitHost = new JitHost(host); + pnjitStartup(g_ourJitHost); +} + + +//Exported via def file +extern "C" +ICorJitCompiler* __stdcall getJit() +{ + DWORD dwRetVal = 0; + PgetJit pngetJit; + interceptor_ICJC *pJitInstance = nullptr; + ICorJitCompiler *tICJI = nullptr; + + SetDefaultPaths(); + SetLibName(); + + //Load Library + if(g_hRealJit == 0) + { + g_hRealJit = ::LoadLibraryW(g_realJitPath); + if(g_hRealJit == 0) + { + LogError("getJit() - LoadLibrary failed to load '%ws' (0x%08x)", g_realJitPath, ::GetLastError()); + return nullptr; + } + } + + //get the required entrypoints + pngetJit = (PgetJit)::GetProcAddress(g_hRealJit, "getJit"); + if(pngetJit == 0) + { + LogError("getJit() - GetProcAddress 'getJit' failed (0x%08x)", ::GetLastError()); + return nullptr; + } + + tICJI = pngetJit(); + if(tICJI == nullptr) + { + LogError("getJit() - pngetJit gave us null"); + return nullptr; + } + + pJitInstance = new interceptor_ICJC(); + pJitInstance->original_ICorJitCompiler = tICJI; + return pJitInstance; +} + +//Exported via def file +extern "C" +void __stdcall sxsJitStartup(CoreClrCallbacks const & original_cccallbacks) +{ + PsxsJitStartup pnsxsJitStartup; + + SetDefaultPaths(); + SetLibName(); + + //Load Library + if(g_hRealJit == 0) + { + g_hRealJit = ::LoadLibraryW(g_realJitPath); + if(g_hRealJit == 0) + { + LogError("sxsJitStartup() - LoadLibrary failed to load '%ws' (0x%08x)", g_realJitPath, ::GetLastError()); + return; + } + } + + //get entry point + pnsxsJitStartup = (PsxsJitStartup)::GetProcAddress(g_hRealJit, "sxsJitStartup"); + if(pnsxsJitStartup == 0) + { + LogError("sxsJitStartup() - GetProcAddress 'sxsJitStartup' failed (0x%08x)", ::GetLastError()); + return; + } + + //Setup CoreClrCallbacks and call sxsJitStartup + original_CoreClrCallbacks = new CoreClrCallbacks(); + original_CoreClrCallbacks->m_hmodCoreCLR = original_cccallbacks.m_hmodCoreCLR; + original_CoreClrCallbacks->m_pfnIEE = original_cccallbacks.m_pfnIEE; + original_CoreClrCallbacks->m_pfnGetCORSystemDirectory = original_cccallbacks.m_pfnGetCORSystemDirectory; + original_CoreClrCallbacks->m_pfnGetCLRFunction = original_cccallbacks.m_pfnGetCLRFunction; + + CoreClrCallbacks *temp = new CoreClrCallbacks(); + + temp->m_hmodCoreCLR = original_cccallbacks.m_hmodCoreCLR; + temp->m_pfnIEE = IEE_t; + temp->m_pfnGetCORSystemDirectory = original_cccallbacks.m_pfnGetCORSystemDirectory; + temp->m_pfnGetCLRFunction = GetCLRFunction; + + pnsxsJitStartup(*temp); +} diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.def b/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.def new file mode 100644 index 0000000000..436434c3de --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.def @@ -0,0 +1,5 @@ +LIBRARY +EXPORTS + getJit + jitStartup + sxsJitStartup diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.h b/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.h new file mode 100644 index 0000000000..2068a02775 --- /dev/null +++ b/src/ToolBox/superpmi/superpmi-shim-simple/superpmi-shim-simple.h @@ -0,0 +1,13 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +//---------------------------------------------------------- +// SuperPMI-Shim.h - thin shim for the jit +//---------------------------------------------------------- +#ifndef _SuperPMIShim +#define _SuperPMIShim + + +#endif |