// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. .syntax unified .thumb #include // generated by the build from AsmOffsets.cpp #include #ifdef FEATURE_CACHED_INTERFACE_DISPATCH // TODO: Implement Arm support #ifdef _DEBUG .rodata AssertMsg: .asciz "__FILE__:%s: %s is not implemented\n" FileName: .asciz "StubDispatch.S" RhpCastableObjectDispatch_CommonStubName: .asciz "RhpCastableObjectDispatch_CommonStub" RhpTailCallTLSDispatchCellName: .asciz "RhpTailCallTLSDispatchCell" RhpCastableObjectDispatchHelper_TailCalledName: .asciz "RhpCastableObjectDispatchHelper_TailCalled" RhpCastableObjectDispatchHelperName: .asciz "RhpCastableObjectDispatchHelper" RhpVTableOffsetDispatchName: .asciz "RhpVTableOffsetDispatch" .text .macro GEN_ASSERT_FUNC func GEN_ASSERT AssertMsg, FileName, \func .endm #endif LEAF_ENTRY RhpCastableObjectDispatch_CommonStub, _TEXT #ifdef _DEBUG GEN_ASSERT_FUNC RhpCastableObjectDispatch_CommonStubName #else // UNIXTODO: Implement this function EMIT_BREAKPOINT #endif LEAF_END RhpCastableObjectDispatch_CommonStub, _TEXT LEAF_ENTRY RhpTailCallTLSDispatchCell, _TEXT #ifdef _DEBUG GEN_ASSERT_FUNC RhpTailCallTLSDispatchCellName #else // UNIXTODO: Implement this function EMIT_BREAKPOINT #endif LEAF_END RhpTailCallTLSDispatchCell, _TEXT LEAF_ENTRY RhpCastableObjectDispatchHelper_TailCalled, _TEXT #ifdef _DEBUG GEN_ASSERT_FUNC RhpCastableObjectDispatchHelper_TailCalledName #else // UNIXTODO: Implement this function EMIT_BREAKPOINT #endif LEAF_END RhpCastableObjectDispatchHelper_TailCalled, _TEXT LEAF_ENTRY RhpCastableObjectDispatchHelper, _TEXT #ifdef _DEBUG GEN_ASSERT_FUNC RhpCastableObjectDispatchHelperName #else // UNIXTODO: Implement this function EMIT_BREAKPOINT #endif LEAF_END RhpCastableObjectDispatchHelper, _TEXT // Macro that generates a stub consuming a cache with the given number of entries. .macro DEFINE_INTERFACE_DISPATCH_STUB entries LEAF_ENTRY RhpInterfaceDispatch\entries, _TEXT // r12 currently contains the indirection cell address. But we need more scratch registers and // we may A/V on a null this. Both of these suggest we need a real prolog and epilog. PROLOG_PUSH {r1-r2} // r12 currently holds the indirection cell address. We need to get the cache structure instead. ldr r2, [r12, #OFFSETOF__InterfaceDispatchCell__m_pCache] // Load the EEType from the object instance in r0. ldr r1, [r0] CurrentOffset = OFFSETOF__InterfaceDispatchCache__m_rgEntries // For each entry in the cache, see if its EEType type matches the EEType in r1. // If so, call the second cache entry. If not, skip the InterfaceDispatchCacheEntry. // R1 : Instance EEType* // R2: Cache data structure // R12 : Trashed. On succesful check, set to the target address to jump to. .rept \entries ldr r12, [r2, #CurrentOffset] cmp r1, r12 bne 0f ldr r12, [r2, #(CurrentOffset + 4)] b LOCAL_LABEL(99_\entries) 0: CurrentOffset = CurrentOffset + 8 .endr // Point r12 to the indirection cell using the back pointer in the cache block ldr r12, [r2, #OFFSETOF__InterfaceDispatchCache__m_pCell] EPILOG_POP {r1-r2} b C_FUNC(RhpInterfaceDispatchSlow) // Common epilog for cache hits. Have to out of line it here due to limitation on the number of // epilogs imposed by the unwind code macros. LOCAL_LABEL(99_\entries): // R2 contains address of the cache block. We store it in the red zone in case the target we jump // to needs it. Currently the RhpCastableObjectDispatchHelper is the only such target. // R12 contains the target address to jump to EPILOG_POP {r1} // The red zone is only 8 bytes long, so we have to store r2 into it between the pops. str r2, [sp, #-4] EPILOG_POP {r2} EPILOG_BRANCH_REG r12 LEAF_END RhpInterfaceDispatch\entries, _TEXT .endm // DEFINE_INTERFACE_DISPATCH_STUB // Define all the stub routines we currently need. // // The mrt100dbi requires these be exported to identify mrt100 code that dispatches back into managed. // If you change or add any new dispatch stubs, please also change slr.def and dbi\process.cpp CordbProcess::GetExportStepInfo // DEFINE_INTERFACE_DISPATCH_STUB 1 DEFINE_INTERFACE_DISPATCH_STUB 2 DEFINE_INTERFACE_DISPATCH_STUB 4 DEFINE_INTERFACE_DISPATCH_STUB 8 DEFINE_INTERFACE_DISPATCH_STUB 16 DEFINE_INTERFACE_DISPATCH_STUB 32 DEFINE_INTERFACE_DISPATCH_STUB 64 // Stub dispatch routine for dispatch to a vtable slot LEAF_ENTRY RhpVTableOffsetDispatch, _TEXT // On input we have the indirection cell data structure in r12. But we need more scratch registers and // we may A/V on a null this. Both of these suggest we need a real prolog and epilog. PROLOG_PUSH {r1} // r12 currently holds the indirection cell address. We need to update it to point to the vtable // offset instead. ldr r12, [r12, #OFFSETOF__InterfaceDispatchCell__m_pCache] // Load the EEType from the object instance in r0. ldr r1, [r0] // add the vtable offset to the EEType pointer add r12, r1, r12 // Load the target address of the vtable into r12 ldr r12, [r12] EPILOG_POP {r1} EPILOG_BRANCH_REG r12 LEAF_END RhpVTableOffsetDispatch, _TEXT // Initial dispatch on an interface when we don't have a cache yet. LEAF_ENTRY RhpInitialInterfaceDispatch, _TEXT // The stub that jumped here pushed r12, which contains the interface dispatch cell // we need to pop it here pop { r12 } // Just tail call to the cache miss helper. b C_FUNC(RhpInterfaceDispatchSlow) LEAF_END RhpInitialInterfaceDispatch, _TEXT // No as alternate entry due to missed thumb bit in this case // See https://github.com/dotnet/coreclr/issues/12953 LEAF_ENTRY RhpInitialDynamicInterfaceDispatch, _TEXT // Just tail call to the cache miss helper. b C_FUNC(RhpInterfaceDispatchSlow) LEAF_END RhpInitialDynamicInterfaceDispatch, _TEXT // Cache miss case, call the runtime to resolve the target and update the cache. // Use universal transition helper to allow an exception to flow out of resolution LEAF_ENTRY RhpInterfaceDispatchSlow, _TEXT // r12 has the interface dispatch cell address in it. // The calling convention of the universal thunk is that the parameter // for the universal thunk target is to be placed in sp-8 // and the universal thunk target address is to be placed in sp-4 str r12, [sp, #-8] ldr r12, =C_FUNC(RhpCidResolve) str r12, [sp, #-4] // jump to universal transition thunk b C_FUNC(RhpUniversalTransition_DebugStepTailCall) LEAF_END RhpInterfaceDispatchSlow, _TEXT #endif // FEATURE_CACHED_INTERFACE_DISPATCH