diff options
author | dotnet bot <dotnet-bot@microsoft.com> | 2016-04-14 23:59:59 +0300 |
---|---|---|
committer | Michal Strehovský <MichalStrehovsky@users.noreply.github.com> | 2016-04-14 23:59:59 +0300 |
commit | 9ed921ffded2f76e55e9a24fd8b8c9d3d2570c43 (patch) | |
tree | 62a773a7c336793f6b17f4be98c1ebbbd99d82f5 /src/Native/Runtime/MiscHelpers.cpp | |
parent | 9804f42dce998498b693915ff1b2051478dadc97 (diff) |
Improve Reverse PInvoke performance in ProjectN (#1138)
Recently while experimenting with interop performance micro-benchmarks, I observed that Reverse PInvoke code path in ProjectN is 8-10x slower
than Desktop CLR. Morgan also noticed the slow down and extra memory allocation on this code path while doing the Unity app investigation.
This change aims to improve this code path to achieve parity with Desktop CLR.
This change improve Reverse PInvoke performance by:
1. Remove the dictionary in McgModuleManager which maps between thunk address and delegate. Instead store a weak GCHandle of the delegate in the thunk data section.
2. Optimize open static delegate by storing the static function pointer directly in the thunk data. And later on reverse pinvoke code path directly do a CallI on the function pointer. Modified MCG to generate special function to handle open static delegates.
3. While storing the function pointer, store jump stub code target address. Added a runtime helper to get the jump stub target.
4. Reorder some instructions in RhpReversePInvoke and InteropNative_CommonStub functions so that the hot path get better instruction cache use.
Results:
X86
33% slower than Desktop CLR (75 vs 92 instruction)
5.5x faster than latest ProjectN
AMD64
9% faster than Desktop CLR (54 vs 67 instructions)
7.5x faster than latest ProjectN
[tfs-changeset: 1596255]
Diffstat (limited to 'src/Native/Runtime/MiscHelpers.cpp')
-rw-r--r-- | src/Native/Runtime/MiscHelpers.cpp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/Native/Runtime/MiscHelpers.cpp b/src/Native/Runtime/MiscHelpers.cpp index 4d08e4e06..ff7346177 100644 --- a/src/Native/Runtime/MiscHelpers.cpp +++ b/src/Native/Runtime/MiscHelpers.cpp @@ -483,6 +483,65 @@ COOP_PINVOKE_HELPER(UInt8 *, RhGetCodeTarget, (UInt8 * pCodeOrg)) return pCodeOrg; } +// Given a pointer to code, find out if this points to a jump stub, and if so, return the address that stub jumps to +COOP_PINVOKE_HELPER(UInt8 *, RhGetJmpStubCodeTarget, (UInt8 * pCodeOrg)) +{ + // Search for the module containing the code + FOREACH_MODULE(pModule) + { + // If the code pointer doesn't point to a module's stub range, + // it can't be pointing to a stub + if (!pModule->ContainsStubAddress(pCodeOrg)) + continue; + +#ifdef _TARGET_AMD64_ + UInt8 * pCode = pCodeOrg; + + // if this is a jmp stub + if (pCode[0] == 0xe9) + { + // relative jump - dist is relative to the point *after* the instruction + Int32 distToTarget = *(Int32 *)&pCode[1]; + UInt8 * target = pCode + 5 + distToTarget; + return target; + } + return pCodeOrg; + +#elif _TARGET_X86_ + UInt8 * pCode = pCodeOrg; + + // if this is a jmp stub + if (pCode[0] == 0xe9) + { + // relative jump - dist is relative to the point *after* the instruction + Int32 distToTarget = *(Int32 *)&pCode[1]; + UInt8 * pTarget = pCode + 5 + distToTarget; + return pTarget; + } + return pCodeOrg; + +#elif _TARGET_ARM_ + const UInt16 THUMB_BIT = 1; + UInt16 * pCode = (UInt16 *)((size_t)pCodeOrg & ~THUMB_BIT); + // if this is a jmp stub + if ((pCode[0] & 0xf800) == 0xf000 && (pCode[1] & 0xd000) == 0x9000) + { + Int32 distToTarget = GetThumb2BlRel24(pCode); + UInt8 * pTarget = (UInt8 *)(pCode + 2) + distToTarget + THUMB_BIT; + return (UInt8 *)pTarget; + } +#elif _TARGET_ARM64_ + PORTABILITY_ASSERT("@TODO: FIXME:ARM64"); +#else +#error 'Unsupported Architecture' +#endif + } + END_FOREACH_MODULE; + + return pCodeOrg; +} + + // // Return true if the array slice is valid // |