summaryrefslogtreecommitdiff
path: root/src/vm/arm/stubs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/arm/stubs.cpp')
-rw-r--r--src/vm/arm/stubs.cpp88
1 files changed, 85 insertions, 3 deletions
diff --git a/src/vm/arm/stubs.cpp b/src/vm/arm/stubs.cpp
index 916c949df1..cb9ff602ff 100644
--- a/src/vm/arm/stubs.cpp
+++ b/src/vm/arm/stubs.cpp
@@ -1680,6 +1680,13 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray)
void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall)
{
+ bool isRelative = MethodTable::VTableIndir2_t::isRelative
+ && pMD->IsVtableSlot();
+
+#ifndef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
+ _ASSERTE(!isRelative);
+#endif
+
// Use direct call if possible.
if (pMD->HasStableEntryPoint())
{
@@ -1691,14 +1698,47 @@ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall)
// mov r12, #slotaddress
ThumbEmitMovConstant(ThumbReg(12), (TADDR)pMD->GetAddrOfSlot());
+ if (isRelative)
+ {
+ if (!fTailcall)
+ {
+ // str r4, [sp, 0]
+ ThumbEmitStoreRegIndirect(ThumbReg(4), thumbRegSp, 0);
+ }
+
+ // mov r4, r12
+ ThumbEmitMovRegReg(ThumbReg(4), ThumbReg(12));
+ }
+
// ldr r12, [r12]
ThumbEmitLoadRegIndirect(ThumbReg(12), ThumbReg(12), 0);
+
+ if (isRelative)
+ {
+ // add r12, r4
+ ThumbEmitAddReg(ThumbReg(12), ThumbReg(4));
+
+ if (!fTailcall)
+ {
+ // ldr r4, [sp, 0]
+ ThumbEmitLoadRegIndirect(ThumbReg(4), thumbRegSp, 0);
+ }
+ }
}
if (fTailcall)
{
- // bx r12
- ThumbEmitJumpRegister(ThumbReg(12));
+ if (!isRelative)
+ {
+ // bx r12
+ ThumbEmitJumpRegister(ThumbReg(12));
+ }
+ else
+ {
+ // Replace LR with R12 on stack: hybrid-tail call, same as for EmitShuffleThunk
+ // str r12, [sp, 4]
+ ThumbEmitStoreRegIndirect(ThumbReg(12), thumbRegSp, 4);
+ }
}
else
{
@@ -1835,6 +1875,13 @@ void StubLinkerCPU::ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *p
}
}
+ bool isRelative = MethodTable::VTableIndir2_t::isRelative
+ && pMD->IsVtableSlot();
+
+#ifndef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
+ _ASSERTE(!isRelative);
+#endif
+
// Update descriptor count to the actual number used.
cArgDescriptors = idxCurrentDesc;
@@ -1927,7 +1974,17 @@ void StubLinkerCPU::ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *p
}
// Emit a tail call to the target method.
+ if (isRelative)
+ {
+ ThumbEmitProlog(1, 0, FALSE);
+ }
+
ThumbEmitCallManagedMethod(pMD, true);
+
+ if (isRelative)
+ {
+ ThumbEmitEpilog();
+ }
}
else
{
@@ -1936,7 +1993,9 @@ void StubLinkerCPU::ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *p
// Calculate the size of the new stack frame:
//
// +------------+
- // SP -> | | <-+
+ // SP -> | | <-- Space for helper arg, if isRelative is true
+ // +------------+
+ // | | <-+
// : : | Outgoing arguments
// | | <-+
// +------------+
@@ -1967,6 +2026,12 @@ void StubLinkerCPU::ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *p
DWORD cbStackArgs = (pLastArg->m_idxDst + 1) * 4;
DWORD cbStackFrame = cbStackArgs + sizeof(GSCookie) + sizeof(StubHelperFrame);
cbStackFrame = ALIGN_UP(cbStackFrame, 8);
+
+ if (isRelative)
+ {
+ cbStackFrame += 4;
+ }
+
DWORD cbStackFrameWithoutSavedRegs = cbStackFrame - (13 * 4); // r0-r11,lr
// Prolog:
@@ -2175,8 +2240,25 @@ void StubLinkerCPU::EmitUnboxMethodStub(MethodDesc *pMD)
// add r0, #4
ThumbEmitIncrement(ThumbReg(0), 4);
+ bool isRelative = MethodTable::VTableIndir2_t::isRelative
+ && pMD->IsVtableSlot();
+
+#ifndef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
+ _ASSERTE(!isRelative);
+#endif
+
+ if (isRelative)
+ {
+ ThumbEmitProlog(1, 0, FALSE);
+ }
+
// Tail call the real target.
ThumbEmitCallManagedMethod(pMD, true /* tail call */);
+
+ if (isRelative)
+ {
+ ThumbEmitEpilog();
+ }
}
}