summaryrefslogtreecommitdiff
path: root/src/vm/arm64/stubs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/arm64/stubs.cpp')
-rw-r--r--src/vm/arm64/stubs.cpp120
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);
}
}