From 10698e451c105b73540e550b0a6bbf632193a8fb Mon Sep 17 00:00:00 2001 From: hippiehunter Date: Thu, 14 Sep 2017 17:21:50 -0700 Subject: [PATCH] Implemented portable pinvoke infrastructure for CppCodeGen --- .../src/CppCodeGen/ILToCppImporter.cs | 18 ++++++++ src/Native/Bootstrap/CppCodeGen.h | 17 +++++++- src/Native/Bootstrap/common.h | 11 ++--- src/Native/Bootstrap/main.cpp | 13 ++++++ src/Native/Runtime/inc/rhbinder.h | 15 +++++++ src/Native/Runtime/portable.cpp | 13 ------ src/Native/Runtime/thread.cpp | 41 +++++++++++++++++++ src/Native/Runtime/thread.h | 3 ++ 8 files changed, 112 insertions(+), 19 deletions(-) diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs index 2ee5e142dd4..88faf7d411d 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs @@ -917,6 +917,17 @@ private void ImportCall(ILOpcode opcode, int token) return; } + //this assumes that there will only ever be at most one RawPInvoke call in a given method + if (method.IsRawPInvoke()) + { + AppendLine(); + Append("PInvokeTransitionFrame __piframe"); + AppendSemicolon(); + AppendLine(); + Append("__pinvoke(&__piframe)"); + AppendSemicolon(); + } + TypeDesc constrained = null; if (opcode != ILOpcode.newobj) { @@ -1216,6 +1227,13 @@ private void ImportCall(ILOpcode opcode, int token) PushExpression(retKind, temp, retType); } AppendSemicolon(); + + if (method.IsRawPInvoke()) + { + AppendLine(); + Append("__pinvoke_return(&__piframe)"); + AppendSemicolon(); + } } private void PassCallArguments(MethodSignature methodSignature, TypeDesc thisArgument) diff --git a/src/Native/Bootstrap/CppCodeGen.h b/src/Native/Bootstrap/CppCodeGen.h index 65ef9c0a5da..c1ef78eb37a 100644 --- a/src/Native/Bootstrap/CppCodeGen.h +++ b/src/Native/Bootstrap/CppCodeGen.h @@ -41,4 +41,19 @@ inline double __uint64_to_double(uint64_t v) return val.d; } -#endif // __CPP_CODE_GEN_H +struct ReversePInvokeFrame +{ + void* m_savedPInvokeTransitionFrame; + void* m_savedThread; +}; + +struct PInvokeTransitionFrame +{ + void* m_RIP; + void* m_FramePointer; + void* m_pThread; // unused by stack crawler, this is so GetThread is only called once per method + // can be an invalid pointer in universal transition cases (which never need to call GetThread) + uint32_t m_dwFlags; // PInvokeTransitionFrameFlags + uint64_t m_PreservedRegs[]; +}; +#endif diff --git a/src/Native/Bootstrap/common.h b/src/Native/Bootstrap/common.h index 1aa9679e310..06a1ac5e6a7 100644 --- a/src/Native/Bootstrap/common.h +++ b/src/Native/Bootstrap/common.h @@ -73,15 +73,16 @@ struct RawEEType void* m_pIndirectionModule; }; -struct ReversePInvokeFrame -{ - void* m_savedPInvokeTransitionFrame; - void* m_savedThread; -}; +struct ReversePInvokeFrame; void __reverse_pinvoke(ReversePInvokeFrame* pRevFrame); void __reverse_pinvoke_return(ReversePInvokeFrame* pRevFrame); +struct PInvokeTransitionFrame; + +void __pinvoke(PInvokeTransitionFrame* pFrame); +void __pinvoke_return(PInvokeTransitionFrame* pFrame); + typedef size_t UIntNative; inline bool IS_ALIGNED(UIntNative val, UIntNative alignment) diff --git a/src/Native/Bootstrap/main.cpp b/src/Native/Bootstrap/main.cpp index a4726c176fe..8bb2bab23eb 100644 --- a/src/Native/Bootstrap/main.cpp +++ b/src/Native/Bootstrap/main.cpp @@ -151,6 +151,19 @@ void __reverse_pinvoke_return(ReversePInvokeFrame* pRevFrame) RhpReversePInvokeReturn2(pRevFrame); } +extern "C" void RhpPInvoke2(PInvokeTransitionFrame* pFrame); +extern "C" void RhpPInvokeReturn2(PInvokeTransitionFrame* pFrame); + +void __pinvoke(PInvokeTransitionFrame* pFrame) +{ + RhpPInvoke2(pFrame); +} + +void __pinvoke_return(PInvokeTransitionFrame* pFrame) +{ + RhpPInvokeReturn2(pFrame); +} + namespace System_Private_CoreLib { namespace System { class Object { diff --git a/src/Native/Runtime/inc/rhbinder.h b/src/Native/Runtime/inc/rhbinder.h index 695660a7d22..49e39f6a772 100644 --- a/src/Native/Runtime/inc/rhbinder.h +++ b/src/Native/Runtime/inc/rhbinder.h @@ -631,6 +631,20 @@ enum PInvokeTransitionFrameFlags #pragma warning(push) #pragma warning(disable:4200) // nonstandard extension used: zero-sized array in struct/union class Thread; +#ifdef USE_PORTABLE_HELPERS +//the members of this structure are currently unused except m_pThread and exist only to allow compilation +//of StackFrameIterator their values are not currently being filled in and will require significant rework +//in order to satisfy the runtime requirements of StackFrameIterator +struct PInvokeTransitionFrame +{ + void* m_RIP; + void* m_FramePointer; + Thread* m_pThread; // unused by stack crawler, this is so GetThread is only called once per method + // can be an invalid pointer in universal transition cases (which never need to call GetThread) + uint32_t m_dwFlags; // PInvokeTransitionFrameFlags + uint64_t m_PreservedRegs[]; +}; +#else struct PInvokeTransitionFrame { #ifdef _TARGET_ARM_ @@ -646,6 +660,7 @@ struct PInvokeTransitionFrame #endif UIntTarget m_PreservedRegs[]; }; +#endif //USE_PORTABLE_HELPERS #pragma warning(pop) #ifdef _TARGET_AMD64_ diff --git a/src/Native/Runtime/portable.cpp b/src/Native/Runtime/portable.cpp index c6615b375a2..f1e04f98091 100644 --- a/src/Native/Runtime/portable.cpp +++ b/src/Native/Runtime/portable.cpp @@ -208,19 +208,6 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numE } #endif -// -// PInvoke -// -COOP_PINVOKE_HELPER(void, RhpPInvoke, (void* pFrame)) -{ - // TODO: RhpPInvoke -} - -COOP_PINVOKE_HELPER(void, RhpPInvokeReturn, (void* pFrame)) -{ - // TODO: RhpPInvokeReturn -} - COOP_PINVOKE_HELPER(void, RhpInitialDynamicInterfaceDispatch, ()) { ASSERT_UNCONDITIONALLY("NYI"); diff --git a/src/Native/Runtime/thread.cpp b/src/Native/Runtime/thread.cpp index 2c64a22fa86..c106963fced 100644 --- a/src/Native/Runtime/thread.cpp +++ b/src/Native/Runtime/thread.cpp @@ -1158,6 +1158,31 @@ FORCEINLINE void Thread::InlineReversePInvokeReturn(ReversePInvokeFrame * pFrame } } +FORCEINLINE void Thread::InlinePInvoke(PInvokeTransitionFrame * pFrame) +{ + pFrame->m_pThread = this; + // set our mode to preemptive + m_pTransitionFrame = pFrame; + + // We need to prevent compiler reordering between above write and below read. + _ReadWriteBarrier(); + + // now check if we need to trap the thread + if (ThreadStore::IsTrapThreadsRequested()) + { + RhpWaitForSuspend2(); + } +} + +FORCEINLINE void Thread::InlinePInvokeReturn(PInvokeTransitionFrame * pFrame) +{ + m_pTransitionFrame = NULL; + if (ThreadStore::IsTrapThreadsRequested()) + { + RhpWaitForGC2(pFrame); + } +} + Object * Thread::GetThreadAbortException() { return m_threadAbortException; @@ -1287,4 +1312,20 @@ COOP_PINVOKE_HELPER(void, RhpReversePInvokeReturn2, (ReversePInvokeFrame * pFram pFrame->m_savedThread->InlineReversePInvokeReturn(pFrame); } +#ifdef USE_PORTABLE_HELPERS + +COOP_PINVOKE_HELPER(void, RhpPInvoke2, (PInvokeTransitionFrame* pFrame)) +{ + Thread * pCurThread = ThreadStore::RawGetCurrentThread(); + pCurThread->InlinePInvoke(pFrame); +} + +COOP_PINVOKE_HELPER(void, RhpPInvokeReturn2, (PInvokeTransitionFrame* pFrame)) +{ + //reenter cooperative mode + pFrame->m_pThread->InlinePInvokeReturn(pFrame); +} + +#endif //USE_PORTABLE_HELPERS + #endif // !DACCESS_COMPILE diff --git a/src/Native/Runtime/thread.h b/src/Native/Runtime/thread.h index e88881ff48d..63a89c71529 100644 --- a/src/Native/Runtime/thread.h +++ b/src/Native/Runtime/thread.h @@ -255,6 +255,9 @@ class Thread : private ThreadBuffer bool InlineTryFastReversePInvoke(ReversePInvokeFrame * pFrame); void InlineReversePInvokeReturn(ReversePInvokeFrame * pFrame); + void InlinePInvoke(PInvokeTransitionFrame * pFrame); + void InlinePInvokeReturn(PInvokeTransitionFrame * pFrame); + Object * GetThreadAbortException(); void SetThreadAbortException(Object *exception);