summaryrefslogtreecommitdiff
path: root/src/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h
diff options
context:
space:
mode:
authorBruce Forstall <brucefo@microsoft.com>2016-08-19 15:56:04 -0700
committerBruce Forstall <brucefo@microsoft.com>2016-08-19 15:56:04 -0700
commitd85eb92698be624b181ae9685f9cceb09524f75f (patch)
tree081063522be61efd5d920ac8643f56b24963de9e /src/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h
parent951810348d16091f59f2be47f5054664272a618f (diff)
downloadcoreclr-d85eb92698be624b181ae9685f9cceb09524f75f.tar.gz
coreclr-d85eb92698be624b181ae9685f9cceb09524f75f.tar.bz2
coreclr-d85eb92698be624b181ae9685f9cceb09524f75f.zip
Open source SuperPMI
OVERVIEW ======== This directory contains the SuperPMI tool used for testing the .NET just-in-time (JIT) compiler. SuperPMI has two uses: 1. Verification that a JIT code change doesn't cause any asserts. 2. Finding test code where two JIT compilers generate different code, or verifying that the two compilers generate the same code. Case #1 is useful for doing quick regression checking when making a source code change to the JIT compiler. The process is: (a) make a JIT source code change, (b) run that newly built JIT through a SuperPMI run to verify no asserts have been introduced. Case #2 is useful for generating assembly language diffs, to help analyze the impact of a JIT code change. SuperPMI works in two phases: collection and playback. In the collection phase, the system is configured to collect SuperPMI data. Then, run any set of .NET managed programs. When these managed programs invoke the JIT compiler, SuperPMI gathers and captures all information passed between the JIT and its .NET host. In the playback phase, SuperPMI loads the JIT directly, and causes it to compile all the functions that it previously compiled, but using the collected data to provide answers to various questions that the JIT needs to ask. The .NET execution engine (EE) is not invoked at all. TOOLS ========== There are two native executable tools: superpmi and mcs. There is a .NET Core C# program that is built as part of the coreclr repo tests build called superpmicollect.exe. All will show a help screen if passed -?. COLLECTION ========== Set the following environment variables: SuperPMIShimLogPath=<full path to an empty temporary directory> SuperPMIShimPath=<full path to clrjit.dll, the "standalone" JIT> COMPlus_AltJit=* COMPlus_AltJitName=superpmi-shim-collector.dll (On Linux, use libclrjit.so and libsuperpmi-shim-collector.so. On Mac, use libclrjit.dylib and libsuperpmi-shim-collector.dylib.) Then, run some managed programs. When done running programs, un-set these variables. Now, you will have a large number of .mc files. Merge these using the mcs tool: mcs -merge base.mch *.mc One benefit of SuperPMI is the ability to remove duplicated compilations, so on replay only unique functions are compiled. Use the following to create a "unique" set of functions: mcs -removeDup -thin base.mch unique.mch Note that -thin is not required. However, it will delete all the compilation result collected during the collection phase, which makes the resulting MCH file smaller. Those compilation results are not required for playback. Use the superpmicollect.exe tool to automate and simplify this process. PLAYBACK ======== Once you have a merged, de-duplicated MCH collection, you can play it back using: superpmi unique.mch clrjit.dll You can do this much faster by utilizing all the processors on your machine, and replaying in parallel, using: superpmi -p unique.mch clrjit.dll REMAINING WORK ============= The basic of assembly diffing are there, using the "coredistools" package. The open source build needs to be altered to use this package to wire up the correct build steps. [tfs-changeset: 1623347]
Diffstat (limited to 'src/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h')
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h70
1 files changed, 70 insertions, 0 deletions
diff --git a/src/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h b/src/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h
new file mode 100644
index 0000000000..671b45b392
--- /dev/null
+++ b/src/ToolBox/superpmi/superpmi-shared/icorjitcompilerimpl.h
@@ -0,0 +1,70 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#ifndef _ICorJitCompilerImpl
+#define _ICorJitCompilerImpl
+
+// ICorJitCompilerImpl: declare for implementation all the members of the ICorJitCompiler interface (which are
+// specified as pure virtual methods). This is done once, here, and all implementations share it,
+// to avoid duplicated declarations. This file is #include'd within all the ICorJitCompiler implementation
+// classes.
+//
+// NOTE: this file is in exactly the same order, with exactly the same whitespace, as the ICorJitCompiler
+// interface declaration (with the "virtual" and "= 0" syntax removed). This is to make it easy to compare
+// against the interface declaration.
+
+public:
+ // compileMethod is the main routine to ask the JIT Compiler to create native code for a method. The
+ // method to be compiled is passed in the 'info' parameter, and the code:ICorJitInfo is used to allow the
+ // JIT to resolve tokens, and make any other callbacks needed to create the code. nativeEntry, and
+ // nativeSizeOfCode are just for convenience because the JIT asks the EE for the memory to emit code into
+ // (see code:ICorJitInfo.allocMem), so really the EE already knows where the method starts and how big
+ // it is (in fact, it could be in more than one chunk).
+ //
+ // * In the 32 bit jit this is implemented by code:CILJit.compileMethod
+ // * For the 64 bit jit this is implemented by code:PreJit.compileMethod
+ //
+ // Note: Obfuscators that are hacking the JIT depend on this method having __stdcall calling convention
+ CorJitResult __stdcall compileMethod (
+ ICorJitInfo *comp, /* IN */
+ struct CORINFO_METHOD_INFO *info, /* IN */
+ unsigned /* code:CorJitFlag */ flags, /* IN */
+ BYTE **nativeEntry, /* OUT */
+ ULONG *nativeSizeOfCode /* OUT */
+ );
+
+ // Some JIT compilers (most notably Phoenix), cache information about EE structures from one invocation
+ // of the compiler to the next. This can be a problem when appdomains are unloaded, as some of this
+ // cached information becomes stale. The code:ICorJitCompiler.isCacheCleanupRequired is called by the EE
+ // early first to see if jit needs these notifications, and if so, the EE will call ClearCache is called
+ // whenever the compiler should abandon its cache (eg on appdomain unload)
+ void clearCache();
+ BOOL isCacheCleanupRequired();
+
+ // Do any appropriate work at process shutdown. Default impl is to do nothing.
+ void ProcessShutdownWork(ICorStaticInfo* info); /* {}; */
+
+ // The EE asks the JIT for a "version identifier". This represents the version of the JIT/EE interface.
+ // If the JIT doesn't implement the same JIT/EE interface expected by the EE (because the JIT doesn't
+ // return the version identifier that the EE expects), then the EE fails to load the JIT.
+ //
+ void getVersionIdentifier(
+ GUID* versionIdentifier /* OUT */
+ );
+
+ // When the EE loads the System.Numerics.Vectors assembly, it asks the JIT what length (in bytes) of
+ // SIMD vector it supports as an intrinsic type. Zero means that the JIT does not support SIMD
+ // intrinsics, so the EE should use the default size (i.e. the size of the IL implementation).
+ unsigned getMaxIntrinsicSIMDVectorLength(DWORD cpuCompileFlags); /* { return 0; } */
+
+ // IL obfuscators sometimes interpose on the EE-JIT interface. This function allows the VM to
+ // tell the JIT to use a particular ICorJitCompiler to implement the methods of this interface,
+ // and not to implement those methods itself. The JIT must not return this method when getJit()
+ // is called. Instead, it must pass along all calls to this interface from within its own
+ // ICorJitCompiler implementation. If 'realJitCompiler' is nullptr, then the JIT should resume
+ // executing all the functions itself.
+ void setRealJit(ICorJitCompiler* realJitCompiler); /* { } */
+
+#endif