summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
//