1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5/*****************************************************************************\
6* *
7* CorJit.h - EE / JIT interface *
8* *
9* Version 1.0 *
10*******************************************************************************
11* *
12* *
13* *
14\*****************************************************************************/
15
16//////////////////////////////////////////////////////////////////////////////////////////////////////////
17//
18// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
19//
20// The JIT/EE interface is versioned. By "interface", we mean mean any and all communication between the
21// JIT and the EE. Any time a change is made to the interface, the JIT/EE interface version identifier
22// must be updated. See code:JITEEVersionIdentifier for more information.
23//
24// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
25//
26//////////////////////////////////////////////////////////////////////////////////////////////////////////
27
28#ifndef _COR_JIT_H_
29#define _COR_JIT_H_
30
31#include <corinfo.h>
32
33#include <stdarg.h>
34
35#include <corjitflags.h>
36
37#define CORINFO_STACKPROBE_DEPTH 256*sizeof(UINT_PTR) // Guaranteed stack until an fcall/unmanaged
38 // code can set up a frame. Please make sure
39 // this is less than a page. This is due to
40 // 2 reasons:
41 //
42 // If we need to probe more than a page
43 // size, we need one instruction per page
44 // (7 bytes per instruction)
45 //
46 // The JIT wants some safe space so it doesn't
47 // have to put a probe on every call site. It achieves
48 // this by probing n bytes more than CORINFO_STACKPROBE_DEPTH
49 // If it hasn't used more than n for its own stuff, it
50 // can do a call without doing any other probe
51 //
52 // In any case, we do really expect this define to be
53 // small, as setting up a frame should be only pushing
54 // a couple of bytes on the stack
55 //
56 // There is a compile time assert
57 // in the x86 jit to protect you from this
58 //
59
60
61
62
63/*****************************************************************************/
64 // These are error codes returned by CompileMethod
65enum CorJitResult
66{
67 // Note that I dont use FACILITY_NULL for the facility number,
68 // we may want to get a 'real' facility number
69 CORJIT_OK = NO_ERROR,
70 CORJIT_BADCODE = MAKE_HRESULT(SEVERITY_ERROR,FACILITY_NULL, 1),
71 CORJIT_OUTOFMEM = MAKE_HRESULT(SEVERITY_ERROR,FACILITY_NULL, 2),
72 CORJIT_INTERNALERROR = MAKE_HRESULT(SEVERITY_ERROR,FACILITY_NULL, 3),
73 CORJIT_SKIPPED = MAKE_HRESULT(SEVERITY_ERROR,FACILITY_NULL, 4),
74 CORJIT_RECOVERABLEERROR = MAKE_HRESULT(SEVERITY_ERROR,FACILITY_NULL, 5),
75};
76
77/*****************************************************************************
78Here is how CORJIT_FLAG_SKIP_VERIFICATION should be interepreted.
79Note that even if any method is inlined, it need not be verified.
80
81if (CORJIT_FLAG_SKIP_VERIFICATION is passed in to ICorJitCompiler::compileMethod())
82{
83 No verification needs to be done.
84 Just compile the method, generating unverifiable code if necessary
85}
86else
87{
88 switch(ICorMethodInfo::isInstantiationOfVerifiedGeneric())
89 {
90 case INSTVER_NOT_INSTANTIATION:
91
92 //
93 // Non-generic case, or open generic instantiation
94 //
95
96 switch(canSkipMethodVerification())
97 {
98 case CORINFO_VERIFICATION_CANNOT_SKIP:
99 {
100 ICorMethodInfo::initConstraintsForVerification(&circularConstraints)
101 if (circularConstraints)
102 {
103 Just emit code to call CORINFO_HELP_VERIFICATION
104 The IL will not be compiled
105 }
106 else
107 {
108 Verify the method.
109 if (unverifiable code is detected)
110 {
111 In place of branches with unverifiable code, emit code to call CORINFO_HELP_VERIFICATION
112 Mark the method (and any of its instantiations) as unverifiable
113 }
114 Compile the rest of the verifiable code
115 }
116 }
117
118 case CORINFO_VERIFICATION_CAN_SKIP:
119 {
120 No verification needs to be done.
121 Just compile the method, generating unverifiable code if necessary
122 }
123
124 case CORINFO_VERIFICATION_RUNTIME_CHECK:
125 {
126 ICorMethodInfo::initConstraintsForVerification(&circularConstraints)
127 if (circularConstraints)
128 {
129 Just emit code to call CORINFO_HELP_VERIFICATION
130 The IL will not be compiled
131
132 TODO: This could be changed to call CORINFO_HELP_VERIFICATION_RUNTIME_CHECK
133 }
134 else
135 {
136 Verify the method.
137 if (unverifiable code is detected)
138 {
139 In the prolog, emit code to call CORINFO_HELP_VERIFICATION_RUNTIME_CHECK
140 Mark the method (and any of its instantiations) as unverifiable
141 }
142 Compile the method, generating unverifiable code if necessary
143 }
144 }
145 case CORINFO_VERIFICATION_DONT_JIT:
146 {
147 ICorMethodInfo::initConstraintsForVerification(&circularConstraints)
148 if (circularConstraints)
149 {
150 Just emit code to call CORINFO_HELP_VERIFICATION
151 The IL will not be compiled
152 }
153 else
154 {
155 Verify the method.
156 if (unverifiable code is detected)
157 {
158 Fail the jit
159 }
160 }
161 }
162 }
163
164 case INSTVER_GENERIC_PASSED_VERIFICATION:
165 {
166 This cannot ever happen because the VM would pass in CORJIT_FLAG_SKIP_VERIFICATION.
167 }
168
169 case INSTVER_GENERIC_FAILED_VERIFICATION:
170
171 switch(canSkipMethodVerification())
172 {
173 case CORINFO_VERIFICATION_CANNOT_SKIP:
174 {
175 This cannot be supported because the compiler does not know which branches should call CORINFO_HELP_VERIFICATION.
176 The CLR will throw a VerificationException instead of trying to compile this method
177 }
178
179 case CORINFO_VERIFICATION_CAN_SKIP:
180 {
181 This cannot ever happen because the CLR would pass in CORJIT_FLAG_SKIP_VERIFICATION.
182 }
183
184 case CORINFO_VERIFICATION_RUNTIME_CHECK:
185 {
186 No verification needs to be done.
187 In the prolog, emit code to call CORINFO_HELP_VERIFICATION_RUNTIME_CHECK
188 Compile the method, generating unverifiable code if necessary
189 }
190 case CORINFO_VERIFICATION_DONT_JIT:
191 {
192 Fail the jit
193 }
194 }
195 }
196}
197
198*/
199
200/*****************************************************************************/
201// These are flags passed to ICorJitInfo::allocMem
202// to guide the memory allocation for the code, readonly data, and read-write data
203enum CorJitAllocMemFlag
204{
205 CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN = 0x00000000, // The code will be use the normal alignment
206 CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN = 0x00000001, // The code will be 16-byte aligned
207 CORJIT_ALLOCMEM_FLG_RODATA_16BYTE_ALIGN = 0x00000002, // The read-only data will be 16-byte aligned
208};
209
210inline CorJitAllocMemFlag operator |(CorJitAllocMemFlag a, CorJitAllocMemFlag b)
211{
212 return static_cast<CorJitAllocMemFlag>(static_cast<int>(a) | static_cast<int>(b));
213}
214
215enum CorJitFuncKind
216{
217 CORJIT_FUNC_ROOT, // The main/root function (always id==0)
218 CORJIT_FUNC_HANDLER, // a funclet associated with an EH handler (finally, fault, catch, filter handler)
219 CORJIT_FUNC_FILTER // a funclet associated with an EH filter
220};
221
222// We have a performance-investigation mode (defined by the FEATURE_USE_ASM_GC_WRITE_BARRIERS and
223// FEATURE_COUNT_GC_WRITE_BARRIER preprocessor symbols) in which the JIT adds an argument of this
224// enumeration to checked write barrier calls in order to classify them.
225enum CheckedWriteBarrierKinds {
226 CWBKind_Unclassified, // Not one of the ones below.
227 CWBKind_RetBuf, // Store through a return buffer pointer argument.
228 CWBKind_ByRefArg, // Store through a by-ref argument (not an implicit return buffer).
229 CWBKind_OtherByRefLocal, // Store through a by-ref local variable.
230 CWBKind_AddrOfLocal, // Store through the address of a local (arguably a bug that this happens at all).
231};
232
233#include "corjithost.h"
234
235extern "C" void __stdcall jitStartup(ICorJitHost* host);
236
237class ICorJitCompiler;
238class ICorJitInfo;
239struct IEEMemoryManager;
240
241extern "C" ICorJitCompiler* __stdcall getJit();
242
243// #EEToJitInterface
244// ICorJitCompiler is the interface that the EE uses to get IL bytecode converted to native code. Note that
245// to accomplish this the JIT has to call back to the EE to get symbolic information. The code:ICorJitInfo
246// type passed as 'comp' to compileMethod is the mechanism to get this information. This is often the more
247// interesting interface.
248//
249//
250class ICorJitCompiler
251{
252public:
253 // compileMethod is the main routine to ask the JIT Compiler to create native code for a method. The
254 // method to be compiled is passed in the 'info' parameter, and the code:ICorJitInfo is used to allow the
255 // JIT to resolve tokens, and make any other callbacks needed to create the code. nativeEntry, and
256 // nativeSizeOfCode are just for convenience because the JIT asks the EE for the memory to emit code into
257 // (see code:ICorJitInfo.allocMem), so really the EE already knows where the method starts and how big
258 // it is (in fact, it could be in more than one chunk).
259 //
260 // * In the 32 bit jit this is implemented by code:CILJit.compileMethod
261 // * For the 64 bit jit this is implemented by code:PreJit.compileMethod
262 //
263 // Note: Obfuscators that are hacking the JIT depend on this method having __stdcall calling convention
264 virtual CorJitResult __stdcall compileMethod (
265 ICorJitInfo *comp, /* IN */
266 struct CORINFO_METHOD_INFO *info, /* IN */
267 unsigned /* code:CorJitFlag */ flags, /* IN */
268 BYTE **nativeEntry, /* OUT */
269 ULONG *nativeSizeOfCode /* OUT */
270 ) = 0;
271
272 // Some JIT compilers (most notably Phoenix), cache information about EE structures from one invocation
273 // of the compiler to the next. This can be a problem when appdomains are unloaded, as some of this
274 // cached information becomes stale. The code:ICorJitCompiler.isCacheCleanupRequired is called by the EE
275 // early first to see if jit needs these notifications, and if so, the EE will call ClearCache is called
276 // whenever the compiler should abandon its cache (eg on appdomain unload)
277 virtual void clearCache() = 0;
278 virtual BOOL isCacheCleanupRequired() = 0;
279
280 // Do any appropriate work at process shutdown. Default impl is to do nothing.
281 virtual void ProcessShutdownWork(ICorStaticInfo* info) {};
282
283 // The EE asks the JIT for a "version identifier". This represents the version of the JIT/EE interface.
284 // If the JIT doesn't implement the same JIT/EE interface expected by the EE (because the JIT doesn't
285 // return the version identifier that the EE expects), then the EE fails to load the JIT.
286 //
287 virtual void getVersionIdentifier(
288 GUID* versionIdentifier /* OUT */
289 ) = 0;
290
291 // When the EE loads the System.Numerics.Vectors assembly, it asks the JIT what length (in bytes) of
292 // SIMD vector it supports as an intrinsic type. Zero means that the JIT does not support SIMD
293 // intrinsics, so the EE should use the default size (i.e. the size of the IL implementation).
294 virtual unsigned getMaxIntrinsicSIMDVectorLength(CORJIT_FLAGS cpuCompileFlags) { return 0; }
295
296 // IL obfuscators sometimes interpose on the EE-JIT interface. This function allows the VM to
297 // tell the JIT to use a particular ICorJitCompiler to implement the methods of this interface,
298 // and not to implement those methods itself. The JIT must not return this method when getJit()
299 // is called. Instead, it must pass along all calls to this interface from within its own
300 // ICorJitCompiler implementation. If 'realJitCompiler' is nullptr, then the JIT should resume
301 // executing all the functions itself.
302 virtual void setRealJit(ICorJitCompiler* realJitCompiler) { }
303
304};
305
306//------------------------------------------------------------------------------------------
307// #JitToEEInterface
308//
309// ICorJitInfo is the main interface that the JIT uses to call back to the EE and get information. It is
310// the companion to code:ICorJitCompiler#EEToJitInterface. The concrete implementation of this in the
311// runtime is the code:CEEJitInfo type. There is also a version of this for the NGEN case.
312//
313// See code:ICorMethodInfo#EEJitContractDetails for subtle conventions used by this interface.
314//
315// There is more information on the JIT in the book of the runtime entry
316// http://devdiv/sites/CLR/Product%20Documentation/2.0/BookOfTheRuntime/JIT/JIT%20Design.doc
317//
318class ICorJitInfo : public ICorDynamicInfo
319{
320public:
321 // return memory manager that the JIT can use to allocate a regular memory
322 virtual IEEMemoryManager* getMemoryManager() = 0;
323
324 // get a block of memory for the code, readonly data, and read-write data
325 virtual void allocMem (
326 ULONG hotCodeSize, /* IN */
327 ULONG coldCodeSize, /* IN */
328 ULONG roDataSize, /* IN */
329 ULONG xcptnsCount, /* IN */
330 CorJitAllocMemFlag flag, /* IN */
331 void ** hotCodeBlock, /* OUT */
332 void ** coldCodeBlock, /* OUT */
333 void ** roDataBlock /* OUT */
334 ) = 0;
335
336 // Reserve memory for the method/funclet's unwind information.
337 // Note that this must be called before allocMem. It should be
338 // called once for the main method, once for every funclet, and
339 // once for every block of cold code for which allocUnwindInfo
340 // will be called.
341 //
342 // This is necessary because jitted code must allocate all the
343 // memory needed for the unwindInfo at the allocMem call.
344 // For prejitted code we split up the unwinding information into
345 // separate sections .rdata and .pdata.
346 //
347 virtual void reserveUnwindInfo (
348 BOOL isFunclet, /* IN */
349 BOOL isColdCode, /* IN */
350 ULONG unwindSize /* IN */
351 ) = 0;
352
353 // Allocate and initialize the .rdata and .pdata for this method or
354 // funclet, and get the block of memory needed for the machine-specific
355 // unwind information (the info for crawling the stack frame).
356 // Note that allocMem must be called first.
357 //
358 // Parameters:
359 //
360 // pHotCode main method code buffer, always filled in
361 // pColdCode cold code buffer, only filled in if this is cold code,
362 // null otherwise
363 // startOffset start of code block, relative to appropriate code buffer
364 // (e.g. pColdCode if cold, pHotCode if hot).
365 // endOffset end of code block, relative to appropriate code buffer
366 // unwindSize size of unwind info pointed to by pUnwindBlock
367 // pUnwindBlock pointer to unwind info
368 // funcKind type of funclet (main method code, handler, filter)
369 //
370 virtual void allocUnwindInfo (
371 BYTE * pHotCode, /* IN */
372 BYTE * pColdCode, /* IN */
373 ULONG startOffset, /* IN */
374 ULONG endOffset, /* IN */
375 ULONG unwindSize, /* IN */
376 BYTE * pUnwindBlock, /* IN */
377 CorJitFuncKind funcKind /* IN */
378 ) = 0;
379
380 // Get a block of memory needed for the code manager information,
381 // (the info for enumerating the GC pointers while crawling the
382 // stack frame).
383 // Note that allocMem must be called first
384 virtual void * allocGCInfo (
385 size_t size /* IN */
386 ) = 0;
387
388 virtual void yieldExecution() = 0;
389
390 // Indicate how many exception handler blocks are to be returned.
391 // This is guaranteed to be called before any 'setEHinfo' call.
392 // Note that allocMem must be called before this method can be called.
393 virtual void setEHcount (
394 unsigned cEH /* IN */
395 ) = 0;
396
397 // Set the values for one particular exception handler block.
398 //
399 // Handler regions should be lexically contiguous.
400 // This is because FinallyIsUnwinding() uses lexicality to
401 // determine if a "finally" clause is executing.
402 virtual void setEHinfo (
403 unsigned EHnumber, /* IN */
404 const CORINFO_EH_CLAUSE *clause /* IN */
405 ) = 0;
406
407 // Level -> fatalError, Level 2 -> Error, Level 3 -> Warning
408 // Level 4 means happens 10 times in a run, level 5 means 100, level 6 means 1000 ...
409 // returns non-zero if the logging succeeded
410 virtual BOOL logMsg(unsigned level, const char* fmt, va_list args) = 0;
411
412 // do an assert. will return true if the code should retry (DebugBreak)
413 // returns false, if the assert should be igored.
414 virtual int doAssert(const char* szFile, int iLine, const char* szExpr) = 0;
415
416 virtual void reportFatalError(CorJitResult result) = 0;
417
418 struct ProfileBuffer // Also defined here: code:CORBBTPROF_BLOCK_DATA
419 {
420 ULONG ILOffset;
421 ULONG ExecutionCount;
422 };
423
424 // allocate a basic block profile buffer where execution counts will be stored
425 // for jitted basic blocks.
426 virtual HRESULT allocBBProfileBuffer (
427 ULONG count, // The number of basic blocks that we have
428 ProfileBuffer ** profileBuffer
429 ) = 0;
430
431 // get profile information to be used for optimizing the current method. The format
432 // of the buffer is the same as the format the JIT passes to allocBBProfileBuffer.
433 virtual HRESULT getBBProfileData(
434 CORINFO_METHOD_HANDLE ftnHnd,
435 ULONG * count, // The number of basic blocks that we have
436 ProfileBuffer ** profileBuffer,
437 ULONG * numRuns
438 ) = 0;
439
440 // Associates a native call site, identified by its offset in the native code stream, with
441 // the signature information and method handle the JIT used to lay out the call site. If
442 // the call site has no signature information (e.g. a helper call) or has no method handle
443 // (e.g. a CALLI P/Invoke), then null should be passed instead.
444 virtual void recordCallSite(
445 ULONG instrOffset, /* IN */
446 CORINFO_SIG_INFO * callSig, /* IN */
447 CORINFO_METHOD_HANDLE methodHandle /* IN */
448 ) = 0;
449
450 // A relocation is recorded if we are pre-jitting.
451 // A jump thunk may be inserted if we are jitting
452 virtual void recordRelocation(
453 void * location, /* IN */
454 void * target, /* IN */
455 WORD fRelocType, /* IN */
456 WORD slotNum = 0, /* IN */
457 INT32 addlDelta = 0 /* IN */
458 ) = 0;
459
460 virtual WORD getRelocTypeHint(void * target) = 0;
461
462 // A callback to identify the range of address known to point to
463 // compiler-generated native entry points that call back into
464 // MSIL.
465 virtual void getModuleNativeEntryPointRange(
466 void ** pStart, /* OUT */
467 void ** pEnd /* OUT */
468 ) = 0;
469
470 // For what machine does the VM expect the JIT to generate code? The VM
471 // returns one of the IMAGE_FILE_MACHINE_* values. Note that if the VM
472 // is cross-compiling (such as the case for crossgen), it will return a
473 // different value than if it was compiling for the host architecture.
474 //
475 virtual DWORD getExpectedTargetArchitecture() = 0;
476
477 // Fetches extended flags for a particular compilation instance. Returns
478 // the number of bytes written to the provided buffer.
479 virtual DWORD getJitFlags(
480 CORJIT_FLAGS* flags, /* IN: Points to a buffer that will hold the extended flags. */
481 DWORD sizeInBytes /* IN: The size of the buffer. Note that this is effectively a
482 version number for the CORJIT_FLAGS value. */
483 ) = 0;
484};
485
486/**********************************************************************************/
487#endif // _COR_CORJIT_H_
488