diff options
author | Fadi Hanna <fadim@microsoft.com> | 2016-05-13 20:35:54 -0700 |
---|---|---|
committer | Fadi Hanna <fadim@microsoft.com> | 2016-05-13 20:35:54 -0700 |
commit | 97b4ff0b438261ba11b357008630076054a6f25d (patch) | |
tree | 320c32b25b556124cb354ab06a86c8f6ae806d98 /src/vm/amd64 | |
parent | 5b065284dc57bc3a9eaee9f86b0df258b1d3d7af (diff) | |
download | coreclr-97b4ff0b438261ba11b357008630076054a6f25d.tar.gz coreclr-97b4ff0b438261ba11b357008630076054a6f25d.tar.bz2 coreclr-97b4ff0b438261ba11b357008630076054a6f25d.zip |
Initial implementation of generic dictionary access for R2R. (#4519)
For now, only TypeHandle dictionary entry slots are supported and encoded in a R2R version resilient format (the rest to come soon).
Support is only limited for x64 Windows platforms (rest is still TODO)
The basic idea: each dictionary access is initally a call to a DynamicHelper R2R cell that computes the dictionary signature, and patches the R2R cell address with an assembly stub that performs the dictionary lookup.
Diffstat (limited to 'src/vm/amd64')
-rw-r--r-- | src/vm/amd64/cgenamd64.cpp | 109 |
1 files changed, 107 insertions, 2 deletions
diff --git a/src/vm/amd64/cgenamd64.cpp b/src/vm/amd64/cgenamd64.cpp index a83c166474..e972ae8953 100644 --- a/src/vm/amd64/cgenamd64.cpp +++ b/src/vm/amd64/cgenamd64.cpp @@ -953,9 +953,16 @@ PCODE DynamicHelpers::CreateHelper(LoaderAllocator * pAllocator, TADDR arg, PCOD END_DYNAMIC_HELPER_EMIT(); } -PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR arg, PCODE target) +void DynamicHelpers::EmitHelperWithArg(BYTE*& p, LoaderAllocator * pAllocator, TADDR arg, PCODE target) { - BEGIN_DYNAMIC_HELPER_EMIT(15); + CONTRACTL + { + GC_NOTRIGGER; + PRECONDITION(p != NULL && target != NULL); + } + CONTRACTL_END; + + // Move an an argument into the second argument register and jump to a target function. #ifdef UNIX_AMD64_ABI *(UINT16 *)p = 0xBE48; // mov rsi, XXXXXX @@ -969,6 +976,13 @@ PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR ar *p++ = X86_INSTR_JMP_REL32; // jmp rel32 *(INT32 *)p = rel32UsingJumpStub((INT32 *)p, target, NULL, pAllocator); p += 4; +} + +PCODE DynamicHelpers::CreateHelperWithArg(LoaderAllocator * pAllocator, TADDR arg, PCODE target) +{ + BEGIN_DYNAMIC_HELPER_EMIT(15); + + EmitHelperWithArg(p, pAllocator, arg, target); END_DYNAMIC_HELPER_EMIT(); } @@ -1126,6 +1140,97 @@ PCODE DynamicHelpers::CreateHelperWithTwoArgs(LoaderAllocator * pAllocator, TADD END_DYNAMIC_HELPER_EMIT(); } +PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator, CORINFO_RUNTIME_LOOKUP * pLookup) +{ + STANDARD_VM_CONTRACT; + + // TODO: fix codegen for correct Unix ABI... + + // It's available only via the run-time helper function + if (pLookup->indirections == CORINFO_USEHELPER) + { + BEGIN_DYNAMIC_HELPER_EMIT(15); + + // rcx contains the generic context parameter + // mov rdx,pLookup->signature + // jmp pLookup->helper + EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper)); + + END_DYNAMIC_HELPER_EMIT(); + } + else + { + int indirectionsSize = 0; + for (WORD i = 0; i < pLookup->indirections; i++) + indirectionsSize += (pLookup->offsets[i] >= 0x80 ? 7 : 4); + + int codeSize = indirectionsSize + (pLookup->testForNull ? 30 : 4); + + BEGIN_DYNAMIC_HELPER_EMIT(codeSize); + + if (pLookup->testForNull) + { + // rcx contains the generic context parameter. Save a copy of it in the rax register + // mov rax,rcx + *(UINT32*)p = 0x00c88948; p += 3; + } + + for (WORD i = 0; i < pLookup->indirections; i++) + { + // mov rcx,qword ptr [rcx+offset] + if (pLookup->offsets[i] >= 0x80) + { + *(UINT32*)p = 0x00898b48; p += 3; + *p = (UINT32)pLookup->offsets[i]; p += 4; + } + else + { + *(UINT32*)p = 0x00498b48; p += 3; + *p++ = (BYTE)pLookup->offsets[i]; + } + } + + // No null test required + if (!pLookup->testForNull) + { + // No fixups needed for R2R + + // mov rax,rcx + *(UINT32*)p = 0x00c88948; p += 3; + *p++ = 0xC3; // ret + } + else + { + // rcx contains the value of the dictionary slot entry + + _ASSERTE(pLookup->indirections != 0); + + // test rcx,rcx + *(UINT32*)p = 0x00c98548; p += 3; + + // je 'HELPER_CALL' (a jump of 4 bytes) + *(UINT16*)p = 0x0474; p += 2; + + // mov rax,rcx + *(UINT32*)p = 0x00c88948; p += 3; + *p++ = 0xC3; // ret + + // 'HELPER_CALL' + { + // Put the generic context back into rcx (was previously saved in rax) + // mov rcx,rax + *(UINT32*)p = 0x00c18948; p += 3; + + // mov rdx,pLookup->signature + // jmp pLookup->helper + EmitHelperWithArg(p, pAllocator, (TADDR)pLookup->signature, CEEJitInfo::getHelperFtnStatic(pLookup->helper)); + } + } + + END_DYNAMIC_HELPER_EMIT(); + } +} + #endif // FEATURE_READYTORUN #endif // DACCESS_COMPILE |