summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFadi Hanna <fadim@microsoft.com>2019-04-01 12:07:47 -0700
committerGitHub <noreply@github.com>2019-04-01 12:07:47 -0700
commitbc9248cad132fa01dd2b641b6b22849bc7a05457 (patch)
tree5d1ee71059353a66004fc7a4d2501a7452db849f
parentff43a803a814eaaa5eba02cafa4a91def3e4c7be (diff)
downloadcoreclr-bc9248cad132fa01dd2b641b6b22849bc7a05457.tar.gz
coreclr-bc9248cad132fa01dd2b641b6b22849bc7a05457.tar.bz2
coreclr-bc9248cad132fa01dd2b641b6b22849bc7a05457.zip
Enable R2R compilation/inlining of PInvoke stubs where no marshalling is required (#22560)
* These changes enable the inlining of some PInvokes that do not require any marshalling. With inlined pinvokes, R2R performance should become slightly better, since we'll avoid jitting some of the pinvoke IL stubs that we jit today for S.P.CoreLib. Performance gains not yet measured. * Added JIT_PInvokeBegin/End helpers for all architectures. Linux stubs not yet implemented * Add INLINE_GETTHREAD for arm/arm64 * Set CORJIT_FLAG_USE_PINVOKE_HELPERS jit flag for ReadyToRun compilations * Updating R2RDump tool to handle pinvokes
-rw-r--r--src/inc/corcompile.h3
-rw-r--r--src/inc/jithelpers.h6
-rw-r--r--src/inc/readytorun.h8
-rw-r--r--src/inc/readytorunhelpers.h4
-rw-r--r--src/tools/r2rdump/R2RConstants.cs6
-rw-r--r--src/tools/r2rdump/R2RSignature.cs13
-rw-r--r--src/vm/CMakeLists.txt2
-rw-r--r--src/vm/amd64/PInvokeStubs.asm82
-rw-r--r--src/vm/amd64/asmconstants.h18
-rw-r--r--src/vm/amd64/pinvokestubs.S24
-rw-r--r--src/vm/arm/PInvokeStubs.asm90
-rw-r--r--src/vm/arm/asmconstants.h21
-rw-r--r--src/vm/arm/asmmacros.h36
-rw-r--r--src/vm/arm/pinvokestubs.S24
-rw-r--r--src/vm/arm64/PInvokeStubs.asm87
-rw-r--r--src/vm/arm64/asmconstants.h17
-rw-r--r--src/vm/arm64/asmmacros.h48
-rw-r--r--src/vm/arm64/pinvokestubs.S24
-rw-r--r--src/vm/dllimport.cpp8
-rw-r--r--src/vm/frames.h1
-rw-r--r--src/vm/gccover.cpp4
-rw-r--r--src/vm/i386/AsmMacros.inc23
-rw-r--r--src/vm/i386/PInvokeStubs.asm111
-rw-r--r--src/vm/i386/asmconstants.h17
-rw-r--r--src/vm/i386/pinvokestubs.S31
-rw-r--r--src/vm/jithelpers.cpp40
-rw-r--r--src/vm/jitinterface.cpp22
-rw-r--r--src/vm/method.cpp7
-rw-r--r--src/vm/methodtable.cpp48
-rw-r--r--src/vm/methodtable.h10
-rw-r--r--src/vm/zapsig.cpp28
-rw-r--r--src/zap/zapinfo.cpp25
-rw-r--r--src/zap/zapreadytorun.cpp2
33 files changed, 857 insertions, 33 deletions
diff --git a/src/inc/corcompile.h b/src/inc/corcompile.h
index f8f522c465..743791cc2a 100644
--- a/src/inc/corcompile.h
+++ b/src/inc/corcompile.h
@@ -698,13 +698,14 @@ enum CORCOMPILE_FIXUP_BLOB_KIND
ENCODE_DECLARINGTYPE_HANDLE,
+ ENCODE_INDIRECT_PINVOKE_TARGET, /* For calling a pinvoke method ptr */
+
ENCODE_MODULE_HANDLE = 0x50, /* Module token */
ENCODE_STATIC_FIELD_ADDRESS, /* For accessing a static field */
ENCODE_MODULE_ID_FOR_STATICS, /* For accessing static fields */
ENCODE_MODULE_ID_FOR_GENERIC_STATICS, /* For accessing static fields */
ENCODE_CLASS_ID_FOR_STATICS, /* For accessing static fields */
ENCODE_SYNC_LOCK, /* For synchronizing access to a type */
- ENCODE_INDIRECT_PINVOKE_TARGET, /* For calling a pinvoke method ptr */
ENCODE_PROFILING_HANDLE, /* For the method's profiling counter */
ENCODE_VARARGS_METHODDEF, /* For calling a varargs method */
ENCODE_VARARGS_METHODREF,
diff --git a/src/inc/jithelpers.h b/src/inc/jithelpers.h
index f305a4d765..2b362a779f 100644
--- a/src/inc/jithelpers.h
+++ b/src/inc/jithelpers.h
@@ -159,7 +159,7 @@
JITHELPER(CORINFO_HELP_VERIFICATION_RUNTIME_CHECK, JIT_VerificationRuntimeCheck,CORINFO_HELP_SIG_REG_ONLY)
// GC support
- DYNAMICJITHELPER(CORINFO_HELP_STOP_FOR_GC, JIT_RareDisableHelper,CORINFO_HELP_SIG_REG_ONLY)
+ DYNAMICJITHELPER(CORINFO_HELP_STOP_FOR_GC, JIT_RareDisableHelper, CORINFO_HELP_SIG_REG_ONLY)
#ifdef ENABLE_FAST_GCPOLL_HELPER
DYNAMICJITHELPER(CORINFO_HELP_POLL_GC, JIT_PollGC, CORINFO_HELP_SIG_REG_ONLY)
#else
@@ -354,8 +354,8 @@
JITHELPER(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JIT_ThrowPlatformNotSupportedException, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_THROW_TYPE_NOT_SUPPORTED, JIT_ThrowTypeNotSupportedException, CORINFO_HELP_SIG_REG_ONLY)
- JITHELPER(CORINFO_HELP_JIT_PINVOKE_BEGIN, NULL, CORINFO_HELP_SIG_UNDEF)
- JITHELPER(CORINFO_HELP_JIT_PINVOKE_END, NULL, CORINFO_HELP_SIG_UNDEF)
+ JITHELPER(CORINFO_HELP_JIT_PINVOKE_BEGIN, JIT_PInvokeBegin, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_JIT_PINVOKE_END, JIT_PInvokeEnd, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, NULL, CORINFO_HELP_SIG_UNDEF)
JITHELPER(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, NULL, CORINFO_HELP_SIG_UNDEF)
diff --git a/src/inc/readytorun.h b/src/inc/readytorun.h
index 4ca7528ae0..d80a80b1ed 100644
--- a/src/inc/readytorun.h
+++ b/src/inc/readytorun.h
@@ -15,7 +15,7 @@
#define READYTORUN_SIGNATURE 0x00525452 // 'RTR'
-#define READYTORUN_MAJOR_VERSION 0x0002
+#define READYTORUN_MAJOR_VERSION 0x0003
#define READYTORUN_MINOR_VERSION 0x0002
// R2R Version 2.1 adds the READYTORUN_SECTION_INLINING_INFO section
// R2R Version 2.2 adds the READYTORUN_SECTION_PROFILEDATA_INFO section
@@ -180,6 +180,8 @@ enum ReadyToRunFixupKind
READYTORUN_FIXUP_DelegateCtor = 0x2C, /* optimized delegate ctor */
READYTORUN_FIXUP_DeclaringTypeHandle = 0x2D,
+
+ READYTORUN_FIXUP_IndirectPInvokeTarget = 0x2E, /* Target of an inlined pinvoke */
};
//
@@ -230,6 +232,10 @@ enum ReadyToRunHelper
READYTORUN_HELPER_MemSet = 0x40,
READYTORUN_HELPER_MemCpy = 0x41,
+ // PInvoke helpers
+ READYTORUN_HELPER_PInvokeBegin = 0x42,
+ READYTORUN_HELPER_PInvokeEnd = 0x43,
+
// Get string handle lazily
READYTORUN_HELPER_GetString = 0x50,
diff --git a/src/inc/readytorunhelpers.h b/src/inc/readytorunhelpers.h
index ffddab39b4..a8c2327f51 100644
--- a/src/inc/readytorunhelpers.h
+++ b/src/inc/readytorunhelpers.h
@@ -111,5 +111,9 @@ HELPER(READYTORUN_HELPER_CheckedWriteBarrier_EBP, CORINFO_HELP_CHECKED_ASSIGN_
HELPER(READYTORUN_HELPER_EndCatch, CORINFO_HELP_ENDCATCH, OPTIMIZEFORSIZE)
#endif
+HELPER(READYTORUN_HELPER_PInvokeBegin, CORINFO_HELP_JIT_PINVOKE_BEGIN, )
+HELPER(READYTORUN_HELPER_PInvokeEnd, CORINFO_HELP_JIT_PINVOKE_END, )
+
+
#undef HELPER
#undef OPTIMIZEFORSPEED
diff --git a/src/tools/r2rdump/R2RConstants.cs b/src/tools/r2rdump/R2RConstants.cs
index 7e1c5e388f..7f2b2e3035 100644
--- a/src/tools/r2rdump/R2RConstants.cs
+++ b/src/tools/r2rdump/R2RConstants.cs
@@ -120,6 +120,8 @@ namespace R2RDump
READYTORUN_FIXUP_DelegateCtor = 0x2C, /* optimized delegate ctor */
READYTORUN_FIXUP_DeclaringTypeHandle = 0x2D,
+
+ READYTORUN_FIXUP_IndirectPInvokeTarget = 0x2E, /* Target of an inlined pinvoke */
}
//
@@ -171,6 +173,10 @@ namespace R2RDump
READYTORUN_HELPER_MemSet = 0x40,
READYTORUN_HELPER_MemCpy = 0x41,
+ // PInvoke helpers
+ READYTORUN_HELPER_PInvokeBegin = 0x42,
+ READYTORUN_HELPER_PInvokeEnd = 0x43,
+
// Get string handle lazily
READYTORUN_HELPER_GetString = 0x50,
diff --git a/src/tools/r2rdump/R2RSignature.cs b/src/tools/r2rdump/R2RSignature.cs
index 60e4c0fd0a..9bf44122b0 100644
--- a/src/tools/r2rdump/R2RSignature.cs
+++ b/src/tools/r2rdump/R2RSignature.cs
@@ -679,6 +679,10 @@ namespace R2RDump
builder.Append(" (DECLARING_TYPE_HANDLE)");
break;
+ case ReadyToRunFixupKind.READYTORUN_FIXUP_IndirectPInvokeTarget:
+ ParseMethod(builder);
+ builder.Append(" (INDIRECT_PINVOKE_TARGET)");
+ break;
default:
builder.Append(string.Format("Unknown fixup type: {0:X2}", fixupType));
@@ -1126,6 +1130,15 @@ namespace R2RDump
builder.Append("MEM_CPY");
break;
+ // PInvoke helpers
+ case ReadyToRunHelper.READYTORUN_HELPER_PInvokeBegin:
+ builder.Append("PINVOKE_BEGIN");
+ break;
+
+ case ReadyToRunHelper.READYTORUN_HELPER_PInvokeEnd:
+ builder.Append("PINVOKE_END");
+ break;
+
// Get string handle lazily
case ReadyToRunHelper.READYTORUN_HELPER_GetString:
builder.Append("GET_STRING");
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt
index b7ae17a156..f5cbaac86e 100644
--- a/src/vm/CMakeLists.txt
+++ b/src/vm/CMakeLists.txt
@@ -679,6 +679,7 @@ elseif(CLR_CMAKE_TARGET_ARCH_I386)
${ARCH_SOURCES_DIR}/asmhelpers.asm
${ARCH_SOURCES_DIR}/gmsasm.asm
${ARCH_SOURCES_DIR}/jithelp.asm
+ ${ARCH_SOURCES_DIR}/PInvokeStubs.asm
)
set(VM_HEADERS_WKS_ARCH_ASM
@@ -735,6 +736,7 @@ else(WIN32)
${ARCH_SOURCES_DIR}/asmhelpers.S
${ARCH_SOURCES_DIR}/jithelp.S
${ARCH_SOURCES_DIR}/gmsasm.S
+ ${ARCH_SOURCES_DIR}/pinvokestubs.S
${ARCH_SOURCES_DIR}/umthunkstub.S
)
elseif(CLR_CMAKE_TARGET_ARCH_ARM)
diff --git a/src/vm/amd64/PInvokeStubs.asm b/src/vm/amd64/PInvokeStubs.asm
index 82e33ac03d..8969ea910d 100644
--- a/src/vm/amd64/PInvokeStubs.asm
+++ b/src/vm/amd64/PInvokeStubs.asm
@@ -13,6 +13,14 @@ include AsmConstants.inc
extern GenericPInvokeCalliStubWorker:proc
extern VarargPInvokeStubWorker:proc
+extern JIT_PInvokeEndRarePath:proc
+
+extern s_gsCookie:QWORD
+extern ??_7InlinedCallFrame@@6B@:QWORD
+extern g_TrapReturningThreads:DWORD
+
+; Min amount of stack space that a nested function should allocate.
+MIN_SIZE equ 28h
;
; in:
@@ -135,4 +143,78 @@ NESTED_ENTRY VarargPInvokeGenILStub, _TEXT
NESTED_END VarargPInvokeGenILStub, _TEXT
+;
+; in:
+; InlinedCallFrame (rcx) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+; before actual InlinedCallFrame data)
+;
+;
+LEAF_ENTRY JIT_PInvokeBegin, _TEXT
+
+ mov rax, qword ptr [s_gsCookie]
+ mov qword ptr [rcx], rax
+ add rcx, SIZEOF_GSCookie
+
+ ;; set first slot to the value of InlinedCallFrame::`vftable' (checked by runtime code)
+ lea rax,[??_7InlinedCallFrame@@6B@]
+ mov qword ptr [rcx], rax
+
+ mov qword ptr [rcx + OFFSETOF__InlinedCallFrame__m_Datum], 0
+
+ mov rax, rsp
+ add rax, 8
+ mov qword ptr [rcx + OFFSETOF__InlinedCallFrame__m_pCallSiteSP], rax
+ mov qword ptr [rcx + OFFSETOF__InlinedCallFrame__m_pCalleeSavedFP], rbp
+
+ mov rax, [rsp]
+ mov qword ptr [rcx + OFFSETOF__InlinedCallFrame__m_pCallerReturnAddress], rax
+
+ INLINE_GETTHREAD rax
+ ;; pFrame->m_Next = pThread->m_pFrame;
+ mov rdx, qword ptr [rax + OFFSETOF__Thread__m_pFrame]
+ mov qword ptr [rcx + OFFSETOF__Frame__m_Next], rdx
+
+ ;; pThread->m_pFrame = pFrame;
+ mov qword ptr [rax + OFFSETOF__Thread__m_pFrame], rcx
+
+ ;; pThread->m_fPreemptiveGCDisabled = 0
+ mov dword ptr [rax + OFFSETOF__Thread__m_fPreemptiveGCDisabled], 0
+
+ ret
+
+LEAF_END JIT_PInvokeBegin, _TEXT
+
+;
+; in:
+; InlinedCallFrame (rcx) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+; before actual InlinedCallFrame data)
+;
+;
+LEAF_ENTRY JIT_PInvokeEnd, _TEXT
+
+ add rcx, SIZEOF_GSCookie
+
+ INLINE_GETTHREAD rdx
+
+ ;; rcx = pFrame
+ ;; rdx = pThread
+
+ ;; pThread->m_fPreemptiveGCDisabled = 1
+ mov dword ptr [rdx + OFFSETOF__Thread__m_fPreemptiveGCDisabled], 1
+
+ ;; Check return trap
+ cmp [g_TrapReturningThreads], 0
+ jnz RarePath
+
+ ;; pThread->m_pFrame = pFrame->m_Next
+ mov rax, qword ptr [rcx + OFFSETOF__Frame__m_Next]
+ mov qword ptr [rdx + OFFSETOF__Thread__m_pFrame], rax
+
+ ret
+
+RarePath:
+ jmp JIT_PInvokeEndRarePath
+
+LEAF_END JIT_PInvokeEnd, _TEXT
+
end
diff --git a/src/vm/amd64/asmconstants.h b/src/vm/amd64/asmconstants.h
index 1af07860ce..10a5ea0400 100644
--- a/src/vm/amd64/asmconstants.h
+++ b/src/vm/amd64/asmconstants.h
@@ -556,6 +556,24 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__StringObject__m_StringLength
ASMCONSTANTS_C_ASSERT(OFFSETOF__ArrayTypeDesc__m_Arg
== offsetof(ArrayTypeDesc, m_Arg));
+// For JIT_PInvokeBegin and JIT_PInvokeEnd helpers
+#define OFFSETOF__InlinedCallFrame__m_Datum 0x10
+ASMCONSTANTS_C_ASSERT(OFFSETOF__InlinedCallFrame__m_Datum
+ == offsetof(InlinedCallFrame, m_Datum));
+
+#define OFFSETOF__InlinedCallFrame__m_pCallSiteSP 0x20
+ASMCONSTANTS_C_ASSERT(OFFSETOF__InlinedCallFrame__m_pCallSiteSP
+ == offsetof(InlinedCallFrame, m_pCallSiteSP));
+
+#define OFFSETOF__InlinedCallFrame__m_pCallerReturnAddress 0x28
+ASMCONSTANTS_C_ASSERT(OFFSETOF__InlinedCallFrame__m_pCallerReturnAddress
+ == offsetof(InlinedCallFrame, m_pCallerReturnAddress));
+
+#define OFFSETOF__InlinedCallFrame__m_pCalleeSavedFP 0x30
+ASMCONSTANTS_C_ASSERT(OFFSETOF__InlinedCallFrame__m_pCalleeSavedFP
+ == offsetof(InlinedCallFrame, m_pCalleeSavedFP));
+
+
#define CallDescrData__pSrc 0x00
#define CallDescrData__numStackSlots 0x08
#ifdef UNIX_AMD64_ABI
diff --git a/src/vm/amd64/pinvokestubs.S b/src/vm/amd64/pinvokestubs.S
index 19521642ae..fceb7f0de9 100644
--- a/src/vm/amd64/pinvokestubs.S
+++ b/src/vm/amd64/pinvokestubs.S
@@ -127,3 +127,27 @@ NESTED_ENTRY VarargPInvokeGenILStub, _TEXT, NoHandler
jmp C_FUNC(VarargPInvokeStubHelper)
NESTED_END VarargPInvokeGenILStub, _TEXT
+
+//
+// IN:
+// InlinedCallFrame (rcx) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+// before actual InlinedCallFrame data)
+//
+//
+LEAF_ENTRY JIT_PInvokeBegin, _TEXT
+ // Not yet supported
+ int 3
+ ret
+LEAF_END JIT_PInvokeBegin, _TEXT
+
+//
+// IN:
+// InlinedCallFrame (rcx) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+// before actual InlinedCallFrame data)
+//
+//
+LEAF_ENTRY JIT_PInvokeEnd, _TEXT
+ // Not yet supported
+ int 3
+ ret
+LEAF_END JIT_PInvokeEnd, _TEXT
diff --git a/src/vm/arm/PInvokeStubs.asm b/src/vm/arm/PInvokeStubs.asm
index 791d66ab80..2e129a8505 100644
--- a/src/vm/arm/PInvokeStubs.asm
+++ b/src/vm/arm/PInvokeStubs.asm
@@ -16,7 +16,13 @@
IMPORT VarargPInvokeStubWorker
IMPORT GenericPInvokeCalliStubWorker
+ IMPORT JIT_PInvokeEndRarePath
+ IMPORT s_gsCookie
+ IMPORT g_TrapReturningThreads
+
+ SETALIAS InlinedCallFrame_vftable, ??_7InlinedCallFrame@@6B@
+ IMPORT $InlinedCallFrame_vftable
; ------------------------------------------------------------------
; Macro to generate PInvoke Stubs.
@@ -105,8 +111,92 @@ __PInvokeGenStubFuncName SETS "$__PInvokeGenStubFuncName":CC:"_RetBuffArg"
MEND
+
TEXTAREA
; ------------------------------------------------------------------
+; JIT_PInvokeBegin helper
+;
+; in:
+; r0 = InlinedCallFrame*: pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+; before actual InlinedCallFrame data)
+;
+ LEAF_ENTRY JIT_PInvokeBegin
+
+ ldr r1, =s_gsCookie
+ ldr r1, [r1]
+ str r1, [r0]
+ add r0, r0, SIZEOF__GSCookie
+
+ ;; r0 = pFrame
+
+ ;; set first slot to the value of InlinedCallFrame::`vftable' (checked by runtime code)
+ ldr r1, =$InlinedCallFrame_vftable
+ str r1, [r0]
+
+ mov r1, 0
+ str r1, [r0, #InlinedCallFrame__m_Datum]
+
+ str sp, [r0, #InlinedCallFrame__m_pCallSiteSP]
+ str r11, [r0, #InlinedCallFrame__m_pCalleeSavedFP]
+ str lr, [r0, #InlinedCallFrame__m_pCallerReturnAddress]
+
+ ;; r1 = GetThread(), TRASHES r2
+ INLINE_GETTHREAD r1, r2
+
+ ;; pFrame->m_Next = pThread->m_pFrame;
+ ldr r2, [r1, #Thread_m_pFrame]
+ str r2, [r0, #Frame__m_Next]
+
+ ;; pThread->m_pFrame = pFrame;
+ str r0, [r1, #Thread_m_pFrame]
+
+ ;; pThread->m_fPreemptiveGCDisabled = 0
+ mov r2, 0
+ str r2, [r1, #Thread_m_fPreemptiveGCDisabled]
+
+ bx lr
+
+ LEAF_END
+
+; ------------------------------------------------------------------
+; JIT_PInvokeEnd helper
+;
+; in:
+; r0 = InlinedCallFrame*
+;
+ LEAF_ENTRY JIT_PInvokeEnd
+
+ add r0, r0, SIZEOF__GSCookie
+
+ ;; r1 = GetThread(), TRASHES r2
+ INLINE_GETTHREAD r1, r2
+
+ ;; r0 = pFrame
+ ;; r1 = pThread
+
+ ;; pThread->m_fPreemptiveGCDisabled = 1
+ mov r2, 1
+ str r2, [r1, #Thread_m_fPreemptiveGCDisabled]
+
+ ;; Check return trap
+ ldr r2, =g_TrapReturningThreads
+ ldr r2, [r2]
+ cbnz r2, RarePath
+
+ ;; pThread->m_pFrame = pFrame->m_Next
+ ldr r2, [r0, #Frame__m_Next]
+ str r2, [r1, #Thread_m_pFrame]
+
+ bx lr
+
+RarePath
+ b JIT_PInvokeEndRarePath
+
+ LEAF_END
+
+ INLINE_GETTHREAD_CONSTANT_POOL
+
+; ------------------------------------------------------------------
; VarargPInvokeStub & VarargPInvokeGenILStub
; There is a separate stub when the method has a hidden return buffer arg.
;
diff --git a/src/vm/arm/asmconstants.h b/src/vm/arm/asmconstants.h
index c57c92a95b..9cb85a50fe 100644
--- a/src/vm/arm/asmconstants.h
+++ b/src/vm/arm/asmconstants.h
@@ -229,8 +229,25 @@ ASMCONSTANTS_C_ASSERT(CallDescrData__returnValue == offsetof(CallDescrD
#define SIZEOF__FaultingExceptionFrame (SIZEOF__Frame + 0x8 + SIZEOF__CONTEXT)
#define FaultingExceptionFrame__m_fFilterExecuted SIZEOF__Frame
-ASMCONSTANTS_C_ASSERT(SIZEOF__FaultingExceptionFrame == sizeof(FaultingExceptionFrame));
-ASMCONSTANTS_C_ASSERT(FaultingExceptionFrame__m_fFilterExecuted == offsetof(FaultingExceptionFrame, m_fFilterExecuted));
+ASMCONSTANTS_C_ASSERT(SIZEOF__FaultingExceptionFrame == sizeof(FaultingExceptionFrame))
+ASMCONSTANTS_C_ASSERT(FaultingExceptionFrame__m_fFilterExecuted == offsetof(FaultingExceptionFrame, m_fFilterExecuted))
+
+// For JIT_PInvokeBegin and JIT_PInvokeEnd helpers
+#define Frame__m_Next 0x04
+ASMCONSTANTS_C_ASSERT(Frame__m_Next == offsetof(Frame, m_Next))
+
+#define InlinedCallFrame__m_Datum 0x08
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_Datum == offsetof(InlinedCallFrame, m_Datum))
+
+#define InlinedCallFrame__m_pCallSiteSP 0x0C
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCallSiteSP == offsetof(InlinedCallFrame, m_pCallSiteSP))
+
+#define InlinedCallFrame__m_pCallerReturnAddress 0x10
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCallerReturnAddress == offsetof(InlinedCallFrame, m_pCallerReturnAddress))
+
+#define InlinedCallFrame__m_pCalleeSavedFP 0x14
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCalleeSavedFP == offsetof(InlinedCallFrame, m_pCalleeSavedFP))
+
#undef ASMCONSTANTS_RUNTIME_ASSERT
#undef ASMCONSTANTS_C_ASSERT
diff --git a/src/vm/arm/asmmacros.h b/src/vm/arm/asmmacros.h
index cff79c259b..97a6b8004b 100644
--- a/src/vm/arm/asmmacros.h
+++ b/src/vm/arm/asmmacros.h
@@ -159,3 +159,39 @@ __PWTB_StackAlloc SETA __PWTB_TransitionBlock
EPILOG_RETURN
MEND
+;-----------------------------------------------------------------------------
+; Macro to get a pointer to the Thread* object for the currently executing thread
+;
+__tls_array equ 0x2C ;; offsetof(TEB, ThreadLocalStoragePointer)
+
+ GBLS __SECTIONREL_gCurrentThreadInfo
+__SECTIONREL_gCurrentThreadInfo SETS "SECTIONREL_gCurrentThreadInfo"
+
+ MACRO
+ INLINE_GETTHREAD $destReg, $trashReg
+ EXTERN _tls_index
+
+ ldr $destReg, =_tls_index
+ ldr $destReg, [$destReg]
+ mrc p15, 0, $trashReg, c13, c0, 2
+ ldr $trashReg, [$trashReg, #__tls_array]
+ ldr $destReg, [$trashReg, $destReg, lsl #2]
+ ldr $trashReg, $__SECTIONREL_gCurrentThreadInfo
+ ldr $destReg,[$destReg, $trashReg] ; return gCurrentThreadInfo.m_pThread
+ MEND
+
+;-----------------------------------------------------------------------------
+; INLINE_GETTHREAD_CONSTANT_POOL macro has to be used after the last function in the .asm file that used
+; INLINE_GETTHREAD. Optionally, it can be also used after any function that used INLINE_GETTHREAD
+; to improve density, or to reduce distance betweeen the constant pool and its use.
+;
+ MACRO
+ INLINE_GETTHREAD_CONSTANT_POOL
+ EXTERN gCurrentThreadInfo
+
+$__SECTIONREL_gCurrentThreadInfo
+ DCDU gCurrentThreadInfo
+ RELOC 15 ;; SECREL
+
+__SECTIONREL_gCurrentThreadInfo SETS "$__SECTIONREL_gCurrentThreadInfo":CC:"_"
+ MEND
diff --git a/src/vm/arm/pinvokestubs.S b/src/vm/arm/pinvokestubs.S
index 202792550e..008441f563 100644
--- a/src/vm/arm/pinvokestubs.S
+++ b/src/vm/arm/pinvokestubs.S
@@ -76,6 +76,30 @@
.endmacro
// ------------------------------------------------------------------
+// IN:
+// InlinedCallFrame (r0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+// before actual InlinedCallFrame data)
+//
+//
+ LEAF_ENTRY JIT_PInvokeBegin, _TEXT
+ // Not yet supported
+ EMIT_BREAKPOINT
+ bx lr
+ LEAF_END JIT_PInvokeBegin, _TEXT
+
+// ------------------------------------------------------------------
+// IN:
+// InlinedCallFrame (r0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+// before actual InlinedCallFrame data)
+//
+//
+ LEAF_ENTRY JIT_PInvokeEnd, _TEXT
+ // Not yet supported
+ EMIT_BREAKPOINT
+ bx lr
+ LEAF_END JIT_PInvokeEnd, _TEXT
+
+// ------------------------------------------------------------------
// VarargPInvokeStub & VarargPInvokeGenILStub
// There is a separate stub when the method has a hidden return buffer arg.
//
diff --git a/src/vm/arm64/PInvokeStubs.asm b/src/vm/arm64/PInvokeStubs.asm
index 440af92b6b..87cb77f7a0 100644
--- a/src/vm/arm64/PInvokeStubs.asm
+++ b/src/vm/arm64/PInvokeStubs.asm
@@ -16,6 +16,13 @@
IMPORT VarargPInvokeStubWorker
IMPORT GenericPInvokeCalliStubWorker
+ IMPORT JIT_PInvokeEndRarePath
+
+ IMPORT s_gsCookie
+ IMPORT g_TrapReturningThreads
+
+ SETALIAS InlinedCallFrame_vftable, ??_7InlinedCallFrame@@6B@
+ IMPORT $InlinedCallFrame_vftable
; ------------------------------------------------------------------
@@ -107,9 +114,89 @@ __PInvokeStubWorkerName SETS "$FuncPrefix":CC:"StubWorker"
MEND
+
TEXTAREA
; ------------------------------------------------------------------
+; JIT_PInvokeBegin helper
+;
+; in:
+; x0 = InlinedCallFrame*
+;
+ LEAF_ENTRY JIT_PInvokeBegin
+
+ ldr x9, =s_gsCookie
+ ldr x9, [x9]
+ str x9, [x0]
+ add x10, x0, SIZEOF__GSCookie
+
+ ;; set first slot to the value of InlinedCallFrame::`vftable' (checked by runtime code)
+ ldr x9, =$InlinedCallFrame_vftable
+ str x9, [x10]
+
+ str xzr, [x10, #InlinedCallFrame__m_Datum]
+
+ mov x9, sp
+ str x9, [x10, #InlinedCallFrame__m_pCallSiteSP]
+ str fp, [x10, #InlinedCallFrame__m_pCalleeSavedFP]
+ str lr, [x10, #InlinedCallFrame__m_pCallerReturnAddress]
+
+ ;; x0 = GetThread(), TRASHES x9
+ INLINE_GETTHREAD x0, x9
+
+ ;; pFrame->m_Next = pThread->m_pFrame;
+ ldr x9, [x0, #Thread_m_pFrame]
+ str x9, [x10, #Frame__m_Next]
+
+ ;; pThread->m_pFrame = pFrame;
+ str x10, [x0, #Thread_m_pFrame]
+
+ ;; pThread->m_fPreemptiveGCDisabled = 0
+ str wzr, [x0, #Thread_m_fPreemptiveGCDisabled]
+
+ ret
+
+ LEAF_END
+
+; ------------------------------------------------------------------
+; JIT_PInvokeEnd helper
+;
+; in:
+; x0 = InlinedCallFrame*
+;
+ LEAF_ENTRY JIT_PInvokeEnd
+
+ add x0, x0, SIZEOF__GSCookie
+
+ ;; x1 = GetThread(), TRASHES x2
+ INLINE_GETTHREAD x1, x2
+
+ ;; x0 = pFrame
+ ;; x1 = pThread
+
+ ;; pThread->m_fPreemptiveGCDisabled = 1
+ mov x9, 1
+ str w9, [x1, #Thread_m_fPreemptiveGCDisabled]
+
+ ;; Check return trap
+ ldr x9, =g_TrapReturningThreads
+ ldr x9, [x9]
+ cbnz x9, RarePath
+
+ ;; pThread->m_pFrame = pFrame->m_Next
+ ldr x9, [x0, #Frame__m_Next]
+ str x9, [x1, #Thread_m_pFrame]
+
+ ret
+
+RarePath
+ b JIT_PInvokeEndRarePath
+
+ LEAF_END
+
+ INLINE_GETTHREAD_CONSTANT_POOL
+
+; ------------------------------------------------------------------
; VarargPInvokeStub & VarargPInvokeGenILStub
;
; in:
diff --git a/src/vm/arm64/asmconstants.h b/src/vm/arm64/asmconstants.h
index 1acc1b46d7..d2df47bab8 100644
--- a/src/vm/arm64/asmconstants.h
+++ b/src/vm/arm64/asmconstants.h
@@ -210,5 +210,22 @@ ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModu
ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics));
+// For JIT_PInvokeBegin and JIT_PInvokeEnd helpers
+#define Frame__m_Next 0x08
+ASMCONSTANTS_C_ASSERT(Frame__m_Next == offsetof(Frame, m_Next))
+
+#define InlinedCallFrame__m_Datum 0x10
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_Datum == offsetof(InlinedCallFrame, m_Datum))
+
+#define InlinedCallFrame__m_pCallSiteSP 0x20
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCallSiteSP == offsetof(InlinedCallFrame, m_pCallSiteSP))
+
+#define InlinedCallFrame__m_pCallerReturnAddress 0x28
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCallerReturnAddress == offsetof(InlinedCallFrame, m_pCallerReturnAddress))
+
+#define InlinedCallFrame__m_pCalleeSavedFP 0x30
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCalleeSavedFP == offsetof(InlinedCallFrame, m_pCalleeSavedFP))
+
+
#undef ASMCONSTANTS_RUNTIME_ASSERT
#undef ASMCONSTANTS_C_ASSERT
diff --git a/src/vm/arm64/asmmacros.h b/src/vm/arm64/asmmacros.h
index 5c6195b405..f7c83a60f0 100644
--- a/src/vm/arm64/asmmacros.h
+++ b/src/vm/arm64/asmmacros.h
@@ -299,3 +299,51 @@ $__RedirectionStubEndFuncName
MEND
+;-----------------------------------------------------------------------------
+; Macro to get a pointer to the Thread* object for the currently executing thread
+;
+__tls_array equ 0x58 ;; offsetof(TEB, ThreadLocalStoragePointer)
+
+ EXTERN _tls_index
+
+ GBLS __SECTIONREL_gCurrentThreadInfo
+__SECTIONREL_gCurrentThreadInfo SETS "SECTIONREL_gCurrentThreadInfo"
+
+ MACRO
+ INLINE_GETTHREAD $destReg, $trashReg
+
+ ;; The following macro variables are just some assembler magic to get the name of the 32-bit version
+ ;; of $trashReg. It does it by string manipulation. Replaces something like x3 with w3.
+ LCLS TrashRegister32Bit
+TrashRegister32Bit SETS "$trashReg"
+TrashRegister32Bit SETS "w":CC:("$TrashRegister32Bit":RIGHT:((:LEN:TrashRegister32Bit) - 1))
+
+ ldr $trashReg, =_tls_index
+ ldr $TrashRegister32Bit, [$trashReg]
+ ldr $destReg, [xpr, #__tls_array]
+ ldr $destReg, [$destReg, $trashReg lsl #3]
+ ldr $trashReg, =$__SECTIONREL_gCurrentThreadInfo
+ ldr $trashReg, [$trashReg]
+ ldr $destReg, [$destReg, $trashReg] ; return gCurrentThreadInfo.m_pThread
+ MEND
+
+;-----------------------------------------------------------------------------
+; INLINE_GETTHREAD_CONSTANT_POOL macro has to be used after the last function in the .asm file that used
+; INLINE_GETTHREAD. Optionally, it can be also used after any function that used INLINE_GETTHREAD
+; to improve density, or to reduce distance betweeen the constant pool and its use.
+;
+
+ MACRO
+ INLINE_GETTHREAD_CONSTANT_POOL
+
+ EXTERN gCurrentThreadInfo
+
+ ;; Section relocs are 32 bits. Using an extra DCD initialized to zero for 8-byte alignment.
+$__SECTIONREL_gCurrentThreadInfo
+ DCD gCurrentThreadInfo
+ RELOC 8, gCurrentThreadInfo ;; SECREL
+ DCD 0
+
+__SECTIONREL_gCurrentThreadInfo SETS "$__SECTIONREL_gCurrentThreadInfo":CC:"_"
+
+ MEND
diff --git a/src/vm/arm64/pinvokestubs.S b/src/vm/arm64/pinvokestubs.S
index ad64db855a..d0fd3958ea 100644
--- a/src/vm/arm64/pinvokestubs.S
+++ b/src/vm/arm64/pinvokestubs.S
@@ -87,6 +87,30 @@ LOCAL_LABEL(\__PInvokeStubFuncName\()_0):
.endm
// ------------------------------------------------------------------
+// IN:
+// InlinedCallFrame (x0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+// before actual InlinedCallFrame data)
+//
+//
+ LEAF_ENTRY JIT_PInvokeBegin, _TEXT
+ // Not yet supported
+ EMIT_BREAKPOINT
+ ret lr
+ LEAF_END JIT_PInvokeBegin, _TEXT
+
+// ------------------------------------------------------------------
+// IN:
+// InlinedCallFrame (x0) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+// before actual InlinedCallFrame data)
+//
+//
+ LEAF_ENTRY JIT_PInvokeEnd, _TEXT
+ // Not yet supported
+ EMIT_BREAKPOINT
+ ret lr
+ LEAF_END JIT_PInvokeEnd, _TEXT
+
+// ------------------------------------------------------------------
// VarargPInvokeStub & VarargPInvokeGenILStub
//
// in:
diff --git a/src/vm/dllimport.cpp b/src/vm/dllimport.cpp
index c83f05ce05..5fa9ac4b85 100644
--- a/src/vm/dllimport.cpp
+++ b/src/vm/dllimport.cpp
@@ -3472,6 +3472,14 @@ BOOL NDirect::MarshalingRequired(MethodDesc *pMD, PCCOR_SIGNATURE pSig /*= NULL*
return TRUE;
}
+#ifdef FEATURE_READYTORUN_COMPILER
+ if (IsReadyToRunCompilation())
+ {
+ if (!hndArgType.AsMethodTable()->IsLayoutInCurrentVersionBubble())
+ return TRUE;
+ }
+#endif
+
// return value is fine as long as it can be normalized to an integer
if (i == 0)
{
diff --git a/src/vm/frames.h b/src/vm/frames.h
index 3d092bd06e..5cc5e37d5e 100644
--- a/src/vm/frames.h
+++ b/src/vm/frames.h
@@ -3002,7 +3002,6 @@ public:
PTR_VOID m_StubSecretArg;
#endif // _WIN64
-protected:
// X86: ESP after pushing the outgoing arguments, and just before calling
// out to unmanaged code.
// Other platforms: the field stays set throughout the declaring method.
diff --git a/src/vm/gccover.cpp b/src/vm/gccover.cpp
index 6b2e7a6acf..a080289bb1 100644
--- a/src/vm/gccover.cpp
+++ b/src/vm/gccover.cpp
@@ -388,11 +388,7 @@ public:
//
// Similarly, inserting breakpoints can be avoided for JIT_PollGC() and JIT_StressGC().
-#if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_)
extern "C" FCDECL0(VOID, JIT_RareDisableHelper);
-#else
-FCDECL0(VOID, JIT_RareDisableHelper);
-#endif
/****************************************************************************/
/* sprinkle interupt instructions that will stop on every GCSafe location
diff --git a/src/vm/i386/AsmMacros.inc b/src/vm/i386/AsmMacros.inc
new file mode 100644
index 0000000000..86ce6ac626
--- /dev/null
+++ b/src/vm/i386/AsmMacros.inc
@@ -0,0 +1,23 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+; See the LICENSE file in the project root for more information.
+
+;
+; Define macros to build unwind data for prologues.
+;
+
+__tls_array equ 2Ch ;; offsetof(TEB, ThreadLocalStoragePointer)
+
+
+INLINE_GETTHREAD macro destReg, trashReg
+ ASSUME fs : NOTHING
+
+ EXTERN __tls_index:DWORD
+ EXTERN _gCurrentThreadInfo:DWORD
+
+ mov destReg, [__tls_index]
+ mov trashReg, fs:[__tls_array]
+ mov trashReg, [trashReg + destReg * 4]
+ add trashReg, SECTIONREL _gCurrentThreadInfo
+ mov destReg, [trashReg]
+endm
diff --git a/src/vm/i386/PInvokeStubs.asm b/src/vm/i386/PInvokeStubs.asm
new file mode 100644
index 0000000000..7295c568e7
--- /dev/null
+++ b/src/vm/i386/PInvokeStubs.asm
@@ -0,0 +1,111 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+; See the LICENSE file in the project root for more information.
+
+; ***********************************************************************
+; File: PInvokeStubs.asm
+;
+; ***********************************************************************
+;
+; *** NOTE: If you make changes to this file, propagate the changes to
+; PInvokeStubs.s in this directory
+
+; This contains JITinterface routines that are 100% x86 assembly
+
+ .586
+ .model flat
+
+ include asmconstants.inc
+ include asmmacros.inc
+
+ option casemap:none
+ .code
+
+extern _s_gsCookie:DWORD
+extern ??_7InlinedCallFrame@@6B@:DWORD
+extern _g_TrapReturningThreads:DWORD
+
+extern @JIT_PInvokeEndRarePath@0:proc
+
+.686P
+.XMM
+
+;
+; in:
+; InlinedCallFrame (ecx) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+; before actual InlinedCallFrame data)
+;
+;
+_JIT_PInvokeBegin@4 PROC public
+
+ mov eax, dword ptr [_s_gsCookie]
+ mov dword ptr [ecx], eax
+ add ecx, SIZEOF_GSCookie
+
+ ;; set first slot to the value of InlinedCallFrame::`vftable' (checked by runtime code)
+ lea eax,[??_7InlinedCallFrame@@6B@]
+ mov dword ptr [ecx], eax
+
+ mov dword ptr [ecx + InlinedCallFrame__m_Datum], 0
+
+
+ mov eax, esp
+ add eax, 4
+ mov dword ptr [ecx + InlinedCallFrame__m_pCallSiteSP], eax
+ mov dword ptr [ecx + InlinedCallFrame__m_pCalleeSavedFP], ebp
+
+ mov eax, [esp]
+ mov dword ptr [ecx + InlinedCallFrame__m_pCallerReturnAddress], eax
+
+ ;; edx = GetThread(). Trashes eax
+ INLINE_GETTHREAD edx, eax
+
+ ;; pFrame->m_Next = pThread->m_pFrame;
+ mov eax, dword ptr [edx + Thread_m_pFrame]
+ mov dword ptr [ecx + Frame__m_Next], eax
+
+ ;; pThread->m_pFrame = pFrame;
+ mov dword ptr [edx + Thread_m_pFrame], ecx
+
+ ;; pThread->m_fPreemptiveGCDisabled = 0
+ mov dword ptr [edx + Thread_m_fPreemptiveGCDisabled], 0
+
+ ret
+
+_JIT_PInvokeBegin@4 ENDP
+
+;
+; in:
+; InlinedCallFrame (ecx) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+; before actual InlinedCallFrame data)
+;
+;
+_JIT_PInvokeEnd@4 PROC public
+
+ add ecx, SIZEOF_GSCookie
+
+ ;; edx = GetThread(). Trashes eax
+ INLINE_GETTHREAD edx, eax
+
+ ;; ecx = pFrame
+ ;; edx = pThread
+
+ ;; pThread->m_fPreemptiveGCDisabled = 1
+ mov dword ptr [edx + Thread_m_fPreemptiveGCDisabled], 1
+
+ ;; Check return trap
+ cmp [_g_TrapReturningThreads], 0
+ jnz RarePath
+
+ ;; pThread->m_pFrame = pFrame->m_Next
+ mov eax, dword ptr [ecx + Frame__m_Next]
+ mov dword ptr [edx + Thread_m_pFrame], eax
+
+ ret
+
+RarePath:
+ jmp @JIT_PInvokeEndRarePath@0
+
+_JIT_PInvokeEnd@4 ENDP
+
+ end
diff --git a/src/vm/i386/asmconstants.h b/src/vm/i386/asmconstants.h
index 9b4735b5df..136a31e7b1 100644
--- a/src/vm/i386/asmconstants.h
+++ b/src/vm/i386/asmconstants.h
@@ -339,6 +339,23 @@ ASMCONSTANTS_C_ASSERT(Thread__m_pDomain == offsetof(Thread, m_pDomain));
#endif
+// For JIT_PInvokeBegin and JIT_PInvokeEnd helpers
+#define Frame__m_Next 0x04
+ASMCONSTANTS_C_ASSERT(Frame__m_Next == offsetof(Frame, m_Next));
+
+#define InlinedCallFrame__m_Datum 0x08
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_Datum == offsetof(InlinedCallFrame, m_Datum));
+
+#define InlinedCallFrame__m_pCallSiteSP 0x0C
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCallSiteSP == offsetof(InlinedCallFrame, m_pCallSiteSP));
+
+#define InlinedCallFrame__m_pCallerReturnAddress 0x10
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCallerReturnAddress == offsetof(InlinedCallFrame, m_pCallerReturnAddress));
+
+#define InlinedCallFrame__m_pCalleeSavedFP 0x14
+ASMCONSTANTS_C_ASSERT(InlinedCallFrame__m_pCalleeSavedFP == offsetof(InlinedCallFrame, m_pCalleeSavedFP));
+
+
#ifdef FEATURE_STUBS_AS_IL
// DelegateObject from src/vm/object.h
#define DelegateObject___target 0x04 // offset 0 is m_pMethTab of base class Object
diff --git a/src/vm/i386/pinvokestubs.S b/src/vm/i386/pinvokestubs.S
new file mode 100644
index 0000000000..74b20b51bb
--- /dev/null
+++ b/src/vm/i386/pinvokestubs.S
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+//
+// IN:
+// InlinedCallFrame (ecx) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+// before actual InlinedCallFrame data)
+//
+//
+LEAF_ENTRY JIT_PInvokeBegin, _TEXT
+ // Not yet supported
+ int 3
+ ret
+LEAF_END JIT_PInvokeBegin, _TEXT
+
+//
+// IN:
+// InlinedCallFrame (ecx) = pointer to the InlinedCallFrame data, including the GS cookie slot (GS cookie right
+// before actual InlinedCallFrame data)
+//
+//
+LEAF_ENTRY JIT_PInvokeEnd, _TEXT
+ // Not yet supported
+ int 3
+ ret
+LEAF_END JIT_PInvokeEnd, _TEXT
diff --git a/src/vm/jithelpers.cpp b/src/vm/jithelpers.cpp
index 0576ca7336..d30b4d3300 100644
--- a/src/vm/jithelpers.cpp
+++ b/src/vm/jithelpers.cpp
@@ -5591,15 +5591,50 @@ HCIMPL0(VOID, JIT_PollGC)
}
HCIMPLEND
+
+/*************************************************************/
+// This helper is similar to JIT_RareDisableHelper, but has more operations
+// tailored to the post-pinvoke operations.
+extern "C" FCDECL0(VOID, JIT_PInvokeEndRarePath);
+
+HCIMPL0(void, JIT_PInvokeEndRarePath)
+{
+ BEGIN_PRESERVE_LAST_ERROR;
+
+ FCALL_CONTRACT;
+
+ Thread *thread = GetThread();
+
+ // We need to disable the implicit FORBID GC region that exists inside an FCALL
+ // in order to call RareDisablePreemptiveGC().
+ FC_CAN_TRIGGER_GC();
+ thread->RareDisablePreemptiveGC();
+ FC_CAN_TRIGGER_GC_END();
+
+ FC_GC_POLL_NOT_NEEDED();
+
+ HELPER_METHOD_FRAME_BEGIN_NOPOLL(); // Set up a frame
+ thread->HandleThreadAbort();
+ HELPER_METHOD_FRAME_END();
+
+ InlinedCallFrame* frame = (InlinedCallFrame*)thread->m_pFrame;
+
+ thread->m_pFrame->Pop(thread);
+
+ END_PRESERVE_LAST_ERROR;
+}
+HCIMPLEND
+
/*************************************************************/
// For an inlined N/Direct call (and possibly for other places that need this service)
// we have noticed that the returning thread should trap for one reason or another.
// ECall sets up the frame.
+extern "C" FCDECL0(VOID, JIT_RareDisableHelper);
+
#if defined(_TARGET_ARM_) || defined(_TARGET_AMD64_)
// The JIT expects this helper to preserve the return value on AMD64 and ARM. We should eventually
// switch other platforms to the same convention since it produces smaller code.
-extern "C" FCDECL0(VOID, JIT_RareDisableHelper);
extern "C" FCDECL0(VOID, JIT_RareDisableHelperWorker);
HCIMPL0(void, JIT_RareDisableHelperWorker)
@@ -5783,6 +5818,9 @@ Thread * __stdcall JIT_InitPInvokeFrame(InlinedCallFrame *pFrame, PTR_VOID StubS
#endif // _WIN64
+EXTERN_C void JIT_PInvokeBegin(InlinedCallFrame* pFrame);
+EXTERN_C void JIT_PInvokeEnd(InlinedCallFrame* pFrame);
+
//========================================================================
//
// JIT HELPERS IMPLEMENTED AS FCALLS
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index 7c5a557e40..3a90262f5e 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -10181,11 +10181,27 @@ void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
}
else
{
- // inlinedCallFrameInfo is not used for R2R compilation
+ // We'll declare a fixed size to use for the inlined call frame for R2R here. The size we declare
+ // is currently slightly larger that the actual size of the struct, just in case we decide to add
+ // more fields to the struct in the future, in an effort to not completely invalidate existing R2R images.
+ // The assert below ensures that this fixed size is at least large enough to hold the data structures
+ // used at runtime.
+ // ** IMPORTANT ** If you ever need to change the value of this fixed size, make sure to change the R2R
+ // version number, otherwise older R2R images will probably crash when used.
+
+ const int r2rInlinedCallFrameSize = TARGET_POINTER_SIZE * 11;
+
+#if defined(_DEBUG) && !defined(CROSSBITNESS_COMPILE)
+ InlinedCallFrame::GetEEInfo(&pEEInfoOut->inlinedCallFrameInfo);
+ _ASSERTE(pEEInfoOut->inlinedCallFrameInfo.size <= r2rInlinedCallFrameSize);
+#endif
+
+ // inlinedCallFrameInfo is mostly not used for R2R compilation (only the size field is used)
ZeroMemory(&pEEInfoOut->inlinedCallFrameInfo, sizeof(pEEInfoOut->inlinedCallFrameInfo));
- pEEInfoOut->offsetOfThreadFrame = (DWORD)-1;
- pEEInfoOut->offsetOfGCState = (DWORD)-1;
+ pEEInfoOut->offsetOfThreadFrame = (DWORD)-1;
+ pEEInfoOut->offsetOfGCState = (DWORD)-1;
+ pEEInfoOut->inlinedCallFrameInfo.size = r2rInlinedCallFrameSize;
}
#ifndef CROSSBITNESS_COMPILE
diff --git a/src/vm/method.cpp b/src/vm/method.cpp
index 70d79ca515..d180014a3a 100644
--- a/src/vm/method.cpp
+++ b/src/vm/method.cpp
@@ -5127,6 +5127,13 @@ FARPROC NDirectMethodDesc::FindEntryPointWithMangling(HINSTANCE hMod, PTR_CUTF8
if (IsStdCall())
{
+ if (GetModule()->IsReadyToRun())
+ {
+ // Computing if marshalling is required also computes the required stack size. We need the stack size to correctly form the
+ // name of the import pinvoke function on x86
+ ((NDirectMethodDesc*)this)->MarshalingRequired();
+ }
+
DWORD probedEntrypointNameLength = (DWORD)(strlen(entryPointName) + 1); // 1 for null terminator
int dstbufsize = (int)(sizeof(char) * (probedEntrypointNameLength + 10)); // 10 for stdcall mangling
LPSTR szProbedEntrypointName = ((LPSTR)_alloca(dstbufsize + 1));
diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp
index 0589cb28ce..208c734f4e 100644
--- a/src/vm/methodtable.cpp
+++ b/src/vm/methodtable.cpp
@@ -10159,6 +10159,54 @@ static BOOL ComputeIsLayoutFixedInCurrentVersionBubble(MethodTable * pMT)
return TRUE;
}
+static BOOL ComputeIsLayoutInCurrentVersionBubble(MethodTable* pMT)
+{
+ if (pMT->IsTruePrimitive() || pMT->IsEnum())
+ return TRUE;
+
+ if (!pMT->GetModule()->IsInCurrentVersionBubble())
+ return FALSE;
+
+ ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS);
+ for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next())
+ {
+ MethodTable * pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
+ if (!pFieldMT->IsLayoutInCurrentVersionBubble())
+ return FALSE;
+ }
+
+ if (!pMT->IsValueType())
+ {
+ pMT = pMT->GetParentMethodTable();
+
+ while ((pMT != g_pObjectClass) && (pMT != NULL))
+ {
+ if (!pMT->IsLayoutInCurrentVersionBubble())
+ return FALSE;
+
+ pMT = pMT->GetParentMethodTable();
+ }
+ }
+
+ return TRUE;
+}
+
+BOOL MethodTable::IsLayoutInCurrentVersionBubble()
+{
+ STANDARD_VM_CONTRACT;
+
+ const MethodTableWriteableData * pWriteableData = GetWriteableData();
+ if (!(pWriteableData->m_dwFlags & MethodTableWriteableData::enum_flag_NGEN_IsLayoutInCurrentVersionBubbleComputed))
+ {
+ MethodTableWriteableData * pWriteableDataForWrite = GetWriteableDataForWrite();
+ if (ComputeIsLayoutInCurrentVersionBubble(this))
+ *EnsureWritablePages(&pWriteableDataForWrite->m_dwFlags) |= MethodTableWriteableData::enum_flag_NGEN_IsLayoutInCurrentVersionBubble;
+ *EnsureWritablePages(&pWriteableDataForWrite->m_dwFlags) |= MethodTableWriteableData::enum_flag_NGEN_IsLayoutInCurrentVersionBubbleComputed;
+ }
+
+ return (pWriteableData->m_dwFlags & MethodTableWriteableData::enum_flag_NGEN_IsLayoutInCurrentVersionBubble) != 0;
+}
+
//
// Is field layout in this type fixed within the current version bubble?
// This check does not take the inheritance chain into account.
diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h
index 84f8399dc2..74febebc39 100644
--- a/src/vm/methodtable.h
+++ b/src/vm/methodtable.h
@@ -326,8 +326,10 @@ struct MethodTableWriteableData
enum_flag_NGEN_OverridingInterface = 0x00080000, // Overriding interface that we should generate WinRT CCW stubs for.
#ifdef FEATURE_READYTORUN_COMPILER
- enum_flag_NGEN_IsLayoutFixedComputed = 0x0010000, // Set if we have cached the result of IsLayoutFixed computation
- enum_flag_NGEN_IsLayoutFixed = 0x0020000, // The result of the IsLayoutFixed computation
+ enum_flag_NGEN_IsLayoutFixedComputed = 0x0010000, // Set if we have cached the result of IsLayoutFixed computation
+ enum_flag_NGEN_IsLayoutFixed = 0x0020000, // The result of the IsLayoutFixed computation
+ enum_flag_NGEN_IsLayoutInCurrentVersionBubbleComputed = 0x0040000, // Set if we have cached the result of IsLayoutInCurrentVersionBubble computation
+ enum_flag_NGEN_IsLayoutInCurrentVersionBubble = 0x0080000, // The result of the IsLayoutInCurrentVersionBubble computation
#endif
#endif // FEATURE_PREJIT
@@ -4144,6 +4146,10 @@ public:
#ifdef FEATURE_READYTORUN_COMPILER
//
+ // Is field layout in this type within the current version bubble?
+ //
+ BOOL IsLayoutInCurrentVersionBubble();
+ //
// Is field layout in this type fixed within the current version bubble?
// This check does not take the inheritance chain into account.
//
diff --git a/src/vm/zapsig.cpp b/src/vm/zapsig.cpp
index dbb318d948..4db83ec4b0 100644
--- a/src/vm/zapsig.cpp
+++ b/src/vm/zapsig.cpp
@@ -1132,14 +1132,21 @@ BOOL ZapSig::EncodeMethod(
// FUTURE: This condition should likely be changed or reevaluated once support for smaller version bubbles is implemented.
if (IsReadyToRunCompilation() && (!IsLargeVersionBubbleEnabled() || !pMethod->GetModule()->IsInCurrentVersionBubble()))
{
- if (pResolvedToken == NULL)
+ if (pMethod->IsNDirect())
{
- _ASSERTE(!"CORINFO_RESOLVED_TOKEN required to encode method!");
- ThrowHR(E_FAIL);
+ ownerType = pMethod->GetMethodTable_NoLogging();
}
+ else
+ {
+ if (pResolvedToken == NULL)
+ {
+ _ASSERTE(!"CORINFO_RESOLVED_TOKEN required to encode method!");
+ ThrowHR(E_FAIL);
+ }
- // Encode the referencing method type
- ownerType = TypeHandle(pResolvedToken->hClass);
+ // Encode the referencing method type
+ ownerType = TypeHandle(pResolvedToken->hClass);
+ }
}
else
#endif
@@ -1198,7 +1205,9 @@ BOOL ZapSig::EncodeMethod(
methodFlags |= ENCODE_METHOD_SIG_Constrained;
}
- Module * pReferencingModule = (Module *)pResolvedToken->tokenScope;
+ Module * pReferencingModule = pMethod->IsNDirect() ?
+ pMethod->GetModule() :
+ (Module *)pResolvedToken->tokenScope;
if (!pReferencingModule->IsInCurrentVersionBubble())
{
@@ -1208,7 +1217,9 @@ BOOL ZapSig::EncodeMethod(
ThrowHR(E_FAIL);
}
- methodToken = pResolvedToken->token;
+ methodToken = pMethod->IsNDirect() ?
+ pMethod->GetMemberDef_NoLogging() :
+ pResolvedToken->token;
if (TypeFromToken(methodToken) == mdtMethodSpec)
{
@@ -1218,7 +1229,7 @@ BOOL ZapSig::EncodeMethod(
switch (TypeFromToken(methodToken))
{
case mdtMethodDef:
- _ASSERTE(pResolvedToken->pTypeSpec == NULL);
+ _ASSERTE(pMethod->IsNDirect() || pResolvedToken->pTypeSpec == NULL);
if (!ownerType.HasInstantiation() || ownerType.IsTypicalTypeDefinition())
{
methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
@@ -1226,6 +1237,7 @@ BOOL ZapSig::EncodeMethod(
break;
case mdtMemberRef:
+ _ASSERTE(pResolvedToken != NULL);
methodFlags |= ENCODE_METHOD_SIG_MemberRefToken;
if (pResolvedToken->pTypeSpec == NULL)
diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp
index 560400bd44..1e498463c6 100644
--- a/src/zap/zapinfo.cpp
+++ b/src/zap/zapinfo.cpp
@@ -205,8 +205,14 @@ CORJIT_FLAGS ZapInfo::ComputeJitFlags(CORINFO_METHOD_HANDLE handle)
#ifdef FEATURE_READYTORUN_COMPILER
if (IsReadyToRunCompilation())
+ {
jitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_READYTORUN);
+#ifndef PLATFORM_UNIX
+ // PInvoke Helpers are not yet implemented on non-Windows platforms
+ jitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_USE_PINVOKE_HELPERS);
#endif
+ }
+#endif // FEATURE_READYTORUN_COMPILER
return jitFlags;
}
@@ -1988,12 +1994,15 @@ void * ZapInfo::getAddressOfPInvokeFixup(CORINFO_METHOD_HANDLE method,void **ppI
m_pImage->m_pPreloader->AddMethodToTransitiveClosureOfInstantiations(method);
- CORINFO_MODULE_HANDLE moduleHandle = m_pEECompileInfo->GetLoaderModuleForEmbeddableMethod(method);
- if (moduleHandle == m_pImage->m_hModule
- && m_pImage->m_pPreloader->CanEmbedMethodHandle(method, m_currentMethodHandle))
+ if (!IsReadyToRunCompilation())
{
- *ppIndirection = NULL;
- return PVOID(m_pImage->GetWrappers()->GetAddrOfPInvokeFixup(method));
+ CORINFO_MODULE_HANDLE moduleHandle = m_pEECompileInfo->GetLoaderModuleForEmbeddableMethod(method);
+ if (moduleHandle == m_pImage->m_hModule
+ && m_pImage->m_pPreloader->CanEmbedMethodHandle(method, m_currentMethodHandle))
+ {
+ *ppIndirection = NULL;
+ return PVOID(m_pImage->GetWrappers()->GetAddrOfPInvokeFixup(method));
+ }
}
//
@@ -3849,9 +3858,11 @@ CorInfoUnmanagedCallConv ZapInfo::getUnmanagedCallConv(CORINFO_METHOD_HANDLE met
BOOL ZapInfo::pInvokeMarshalingRequired(CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig)
{
- // READYTORUN: FUTURE: P/Invoke
+#ifdef PLATFORM_UNIX
+ // TODO: Support for pinvoke helpers on non-Windows platforms
if (IsReadyToRunCompilation())
- return TRUE;
+ return TRUE;
+#endif
return m_pEEJitInfo->pInvokeMarshalingRequired(method, sig);
}
diff --git a/src/zap/zapreadytorun.cpp b/src/zap/zapreadytorun.cpp
index f0260a59aa..8d83ff7400 100644
--- a/src/zap/zapreadytorun.cpp
+++ b/src/zap/zapreadytorun.cpp
@@ -549,6 +549,8 @@ static_assert_no_msg((int)READYTORUN_FIXUP_DelegateCtor == (int)ENC
static_assert_no_msg((int)READYTORUN_FIXUP_DeclaringTypeHandle == (int)ENCODE_DECLARINGTYPE_HANDLE);
+static_assert_no_msg((int)READYTORUN_FIXUP_IndirectPInvokeTarget == (int)ENCODE_INDIRECT_PINVOKE_TARGET);
+
//
// READYTORUN_EXCEPTION
//