diff options
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 // |