diff options
Diffstat (limited to 'src/vm/arm64/stubs.cpp')
-rw-r--r-- | src/vm/arm64/stubs.cpp | 120 |
1 files changed, 69 insertions, 51 deletions
diff --git a/src/vm/arm64/stubs.cpp b/src/vm/arm64/stubs.cpp index 35e0ee74cd..dd9e43a062 100644 --- a/src/vm/arm64/stubs.cpp +++ b/src/vm/arm64/stubs.cpp @@ -88,6 +88,7 @@ class BranchInstructionFormat : public InstructionFormat // Encoding of the VariationCode: // bit(0) indicates whether this is a direct or an indirect jump. // bit(1) indicates whether this is a branch with link -a.k.a call- (BL(R)) or not (B(R)) + // bit(2) indicates whether this is a relative indirect branch or not public: enum VariationCodes @@ -96,7 +97,9 @@ class BranchInstructionFormat : public InstructionFormat BIF_VAR_CALL = 0x00000002, BIF_VAR_JUMP = 0x00000000, - BIF_VAR_INDIRECT_CALL = 0x00000003 + BIF_VAR_INDIRECT_CALL = 0x00000003, + + BIF_VAR_RELATIVE_INDIRECT = 0x00000004 }; private: BOOL IsIndirect(UINT variationCode) @@ -107,6 +110,12 @@ class BranchInstructionFormat : public InstructionFormat { return (variationCode & BIF_VAR_CALL) != 0; } + BOOL IsRelativeIndirect(UINT variationCode) + { + BOOL result = (variationCode & BIF_VAR_RELATIVE_INDIRECT) != 0; + _ASSERTE(result && IsIndirect(variationCode) || !result); + return result; + } public: @@ -120,7 +129,9 @@ class BranchInstructionFormat : public InstructionFormat LIMITED_METHOD_CONTRACT; _ASSERTE(refSize == InstructionFormat::k64); - if (IsIndirect(variationCode)) + if (IsRelativeIndirect(variationCode)) + return 20; + else if (IsIndirect(variationCode)) return 12; else return 8; @@ -155,62 +166,59 @@ class BranchInstructionFormat : public InstructionFormat { LIMITED_METHOD_CONTRACT; - if (IsIndirect(variationCode)) - { - _ASSERTE(((UINT_PTR)pDataBuffer & 7) == 0); - __int64 dataOffset = pDataBuffer - pOutBuffer; - - if (dataOffset < -1048576 || dataOffset > 1048572) - COMPlusThrow(kNotSupportedException); + _ASSERTE(((UINT_PTR)pDataBuffer & 7) == 0); + __int64 dataOffset = pDataBuffer - pOutBuffer; + + if (dataOffset < -1048576 || dataOffset > 1048572) + COMPlusThrow(kNotSupportedException); - DWORD imm19 = (DWORD)(0x7FFFF & (dataOffset >> 2)); + DWORD imm19 = (DWORD)(0x7FFFF & (dataOffset >> 2)); - // +0: ldr x16, [pc, #dataOffset] + // +0: ldr x16, [pc, #dataOffset] + *((DWORD*)pOutBuffer) = (0x58000010 | (imm19 << 5)); + DWORD offsetbranch = 0; + + if (IsRelativeIndirect(variationCode)) + { + // TODO-ARM64-CQ: update this! + // REG_IP1 (x17) is always reserved on arm64 (see Compiler::compRsvdRegCheck) + // and is used as a temporary register. Use it as temp register here too. + // + // +4: mov x17, x16 + // +8: ldr x16, [x16] + // +12: add x16, x16, x17 + *((DWORD*)(pOutBuffer+4)) = 0xAA1003F1; + *((DWORD*)(pOutBuffer+8)) = 0xF9400210; + *((DWORD*)(pOutBuffer+12)) = 0x8B110210; + offsetbranch = 16; + } + else if (IsIndirect(variationCode)) + { // +4: ldr x16, [x16] - // +8: b(l)r x16 - *((DWORD*)pOutBuffer) = (0x58000010 | (imm19 << 5)); *((DWORD*)(pOutBuffer+4)) = 0xF9400210; - if (IsCall(variationCode)) - { - *((DWORD*)(pOutBuffer+8)) = 0xD63F0200; // blr x16 - } - else - { - *((DWORD*)(pOutBuffer+8)) = 0xD61F0200; // br x16 - } + offsetbranch = 8; + } + else + { + offsetbranch = 4; + } + _ASSERTE(offsetbranch != 0); - *((__int64*)pDataBuffer) = fixedUpReference + (__int64)pOutBuffer; + // +offsetbranch: b(l)r x16 + if (IsCall(variationCode)) + { + *((DWORD*)(pOutBuffer+offsetbranch)) = 0xD63F0200; // blr x16 } else { - - _ASSERTE(((UINT_PTR)pDataBuffer & 7) == 0); - __int64 dataOffset = pDataBuffer - pOutBuffer; - - if (dataOffset < -1048576 || dataOffset > 1048572) - COMPlusThrow(kNotSupportedException); - - DWORD imm19 = (DWORD)(0x7FFFF & (dataOffset >> 2)); - - // +0: ldr x16, [pc, #dataOffset] - // +4: b(l)r x16 - *((DWORD*)pOutBuffer) = (0x58000010 | (imm19 << 5)); - if (IsCall(variationCode)) - { - *((DWORD*)(pOutBuffer+4)) = 0xD63F0200; // blr x16 - } - else - { - *((DWORD*)(pOutBuffer+4)) = 0xD61F0200; // br x16 - } - - if (!ClrSafeInt<__int64>::addition(fixedUpReference, (__int64)pOutBuffer, fixedUpReference)) - COMPlusThrowArithmetic(); - *((__int64*)pDataBuffer) = fixedUpReference; + *((DWORD*)(pOutBuffer+offsetbranch)) = 0xD61F0200; // br x16 } - } + if (!ClrSafeInt<__int64>::addition(fixedUpReference, (__int64)pOutBuffer, fixedUpReference)) + COMPlusThrowArithmetic(); + *((__int64*)pDataBuffer) = fixedUpReference; + } }; //----------------------------------------------------------------------- @@ -1856,16 +1864,19 @@ VOID StubLinkerCPU::EmitComputedInstantiatingMethodStub(MethodDesc* pSharedMD, s EmitCallManagedMethod(pSharedMD, TRUE /* tail call */); } -void StubLinkerCPU::EmitCallLabel(CodeLabel *target, BOOL fTailCall, BOOL fIndirect) +void StubLinkerCPU::EmitCallLabel(CodeLabel *target, BOOL fTailCall, BOOL fIndirect, BOOL fRelativeIndirect) { + _ASSERTE(fRelativeIndirect && fIndirect || !fRelativeIndirect); + BranchInstructionFormat::VariationCodes variationCode = BranchInstructionFormat::VariationCodes::BIF_VAR_JUMP; if (!fTailCall) variationCode = static_cast<BranchInstructionFormat::VariationCodes>(variationCode | BranchInstructionFormat::VariationCodes::BIF_VAR_CALL); if (fIndirect) variationCode = static_cast<BranchInstructionFormat::VariationCodes>(variationCode | BranchInstructionFormat::VariationCodes::BIF_VAR_INDIRECT); + if (fRelativeIndirect) + variationCode = static_cast<BranchInstructionFormat::VariationCodes>(variationCode | BranchInstructionFormat::VariationCodes::BIF_VAR_RELATIVE_INDIRECT); EmitLabelRef(target, reinterpret_cast<BranchInstructionFormat&>(gBranchIF), (UINT)variationCode); - } void StubLinkerCPU::EmitCallManagedMethod(MethodDesc *pMD, BOOL fTailCall) @@ -1873,11 +1884,18 @@ void StubLinkerCPU::EmitCallManagedMethod(MethodDesc *pMD, BOOL fTailCall) // Use direct call if possible. if (pMD->HasStableEntryPoint()) { - EmitCallLabel(NewExternalCodeLabel((LPVOID)pMD->GetStableEntryPoint()), fTailCall, FALSE); + EmitCallLabel(NewExternalCodeLabel((LPVOID)pMD->GetStableEntryPoint()), fTailCall, FALSE, FALSE); } else { - EmitCallLabel(NewExternalCodeLabel((LPVOID)pMD->GetAddrOfSlot()), fTailCall, TRUE); + BOOL isRelative = MethodTable::VTableIndir2_t::isRelative + && pMD->IsVtableSlot(); + +#ifndef FEATURE_NGEN_RELOCS_OPTIMIZATIONS + _ASSERTE(!isRelative); +#endif + + EmitCallLabel(NewExternalCodeLabel((LPVOID)pMD->GetAddrOfSlot()), fTailCall, TRUE, isRelative); } } |