// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. // FFI trampolines for the simulator and the interpreter. // This is not written as VM stub because we need it be executable in contexts where we cannot JIT. // (Alternatively, we could start requiring the VM snapshot to be provided in every mode.) #if defined(__APPLE__) #define LOCAL_SYMBOL(x) L##x #else #define LOCAL_SYMBOL(x) .L##x #endif #if defined(__aarch64__) && (defined(SIMULATOR_FFI) || (defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME))) .text #if defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME) #if defined(__APPLE__) .globl _FfiCallTrampoline .private_extern _FfiCallTrampoline _FfiCallTrampoline: #else .globl FfiCallTrampoline .type FfiCallTrampoline, %function FfiCallTrampoline: #endif stp fp, lr, [sp, #-16]! mov fp, sp // Spill a preserved register to save args. stp x19, x20, [sp, #-16]! mov x19, x0 // FfiCallArguments* args // Copy top frame from Dart stack to C stack ldr x0, [x19, #0] // FfiCallArguments.stack_area ldr x1, [x19, #8] // FfiCallArguments.stack_area_end LOCAL_SYMBOL(copy1): ldp x2, x3, [x1, #-16]! // From stack_area stp x2, x3, [sp, #-16]! // To C SP cmp x1, x0 b.gt LOCAL_SYMBOL(copy1) // Load the ABI argument registers. Note that Dart FFI does not support // full 128-bit SIMD arguments, so we don't need to set the full V // registers. ldp x0, x1, [x19, #16] // FfiCallArguments.cpu_registers ldp x2, x3, [x19, #32] ldp x4, x5, [x19, #48] ldp x6, x7, [x19, #64] ldr x8, [x19, #80] ldp d0, d1, [x19, #272] // FfiCallArguments.fpu_registers ldp d2, d3, [x19, #288] ldp d4, d5, [x19, #304] ldp d6, d7, [x19, #320] // Call target. ldr lr, [x19, #528] // FfiCallArguments.target blr lr // Save the ABI result registers. stp x0, x1, [x19, #16] // FfiCallArguments.cpu_registers stp d0, d1, [x19, #272] // FfiCallArguments.fpu_registers stp d2, d3, [x19, #288] add sp, fp, -16 ldp x19, x20, [sp], #16 ldp fp, lr, [sp], #16 ret #if !defined(__APPLE__) .size FfiCallTrampoline,.-FfiCallTrampoline #endif #endif // defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME) #if defined(SIMULATOR_FFI) #if defined(__APPLE__) .globl _SimulatorFfiCalloutTrampoline .private_extern _SimulatorFfiCalloutTrampoline _SimulatorFfiCalloutTrampoline: #else .globl SimulatorFfiCalloutTrampoline .type SimulatorFfiCalloutTrampoline, %function SimulatorFfiCalloutTrampoline: #endif stp fp, lr, [sp, #-16]! mov fp, sp // Spill a preserved register to save the context pointer. stp x19, x20, [sp, #-16]! mov x19, x0 // Copy top frame from Dart stack to C stack ldr x0, [x19, #16] // CalloutContext.simulator_stack_pointer (CSP) ldr x1, [x19, #24] // CalloutContext.simulator_frame_pointer add x1, x1, 15 // Round up the frame pointer, since the Dart frame pointer and x1, x1, ~15 // is not double-word aligned. LOCAL_SYMBOL(copy2): ldp x2, x3, [x1, #-16]! // From Dart FP stp x2, x3, [sp, #-16]! // To C SP cmp x1, x0 b.gt LOCAL_SYMBOL(copy2) // Load the ABI argument registers. Note that Dart FFI does not support // full 128-bit SIMD arguments, so we don't need to set the full V // registers. ldp x0, x1, [x19, #32] // CalloutContext.integer_arguments[0] ldp x2, x3, [x19, #48] ldp x4, x5, [x19, #64] ldp x6, x7, [x19, #80] ldp d0, d1, [x19, #96] // CalloutContext.double_arguments[0] ldp d2, d3, [x19, #112] ldp d4, d5, [x19, #128] ldp d6, d7, [x19, #144] ldr x8, [x19, #160] // CalloutContext.r8 // Call target. ldr lr, [x19, #168] // CalloutContext.target blr lr // Save the ABI result registers. stp x0, x1, [x19, #32] // CalloutContext.integer_arguments[0] stp d0, d1, [x19, #96] // CalloutContext.double_arguments[0] stp d2, d3, [x19, #112] add sp, fp, -16 ldp x19, x20, [sp], #16 ldp fp, lr, [sp], #16 ret #if !defined(__APPLE__) .size SimulatorFfiCalloutTrampoline,.-SimulatorFfiCalloutTrampoline #endif #if defined(__APPLE__) .globl _SimulatorFfiCallbackTrampoline .private_extern _SimulatorFfiCallbackTrampoline _SimulatorFfiCallbackTrampoline: #else .globl SimulatorFfiCallbackTrampoline .type SimulatorFfiCallbackTrampoline, %function SimulatorFfiCallbackTrampoline: #endif LOCAL_SYMBOL(start): #if defined(__Fuchsia__) .rept 483 // FfiCallbackMetadata::NumCallbackTrampolinesPerPage() #elif defined(__APPLE__) .rept 2019 // FfiCallbackMetadata::NumCallbackTrampolinesPerPage() #else .rept 8163 // FfiCallbackMetadata::NumCallbackTrampolinesPerPage() #endif adr x9, 0 b LOCAL_SYMBOL(body) .endr LOCAL_SYMBOL(body): mov x10, sp stp fp, lr, [sp, #-16]! mov fp, sp add sp, sp, -144 // Allocate CallbackContext // Save ABI argument registers. stp x0, x1, [sp, #0] // CallbackContext.integer_arguments[0] stp x2, x3, [sp, #16] stp x4, x5, [sp, #32] stp x6, x7, [sp, #48] stp d0, d1, [sp, #64] // CallbackContext.double_arguments[0] stp d2, d3, [sp, #80] stp d4, d5, [sp, #96] stp d6, d7, [sp, #112] str x8, [sp, #128] // CallbackContext.r8 str x10, [sp, #136] // CallbackContext.sp // Pass arguments registers and thunk address to the runtime. mov x0, sp mov x1, x9 // I.e., which callback. adr x2, LOCAL_SYMBOL(start) #if defined(__Fuchsia__) and x2, x2, ~(0x1000-1) // FfiCallbackMetadata::kPageSize = 4k add x2, x2, 0x2000 #elif defined(__APPLE__) and x2, x2, ~(0x4000-1) // FfiCallbackMetadata::kPageSize = 16k add x2, x2, 0x8000 #else and x2, x2, ~(0x10000-1) // FfiCallbackMetadata::kPageSize = 64k add x2, x2, 0x20000 #endif ldr x2, [x2, #8] // FfiCallbackMetadata::kDoRedirectedFfiCallback blr x2 // DoRedirectedFfiCallback // Load ABI result registers. ldp x0, x1, [sp, #0] // CallbackContext.integer_arguments[0] ldp d0, d1, [sp, #64] // CallbackContext.double_arguments[0] ldp d2, d3, [sp, #80] mov sp, fp ldp fp, lr, [sp], #16 ret #if !defined(__APPLE__) .size SimulatorFfiCallbackTrampoline,.-SimulatorFfiCallbackTrampoline #endif #if defined(__APPLE__) .globl _SimulatorFfiCallbackTrampolineEnd .private_extern _SimulatorFfiCallbackTrampolineEnd _SimulatorFfiCallbackTrampolineEnd: #else .globl SimulatorFfiCallbackTrampolineEnd .type SimulatorFfiCallbackTrampolineEnd, %function SimulatorFfiCallbackTrampolineEnd: #endif brk 0 #endif // defined(SIMULATOR_FFI) #endif // defined(__aarch64__) && (defined(SIMULATOR_FFI) || (defined(DART_BYTECODE_INTERPRETER) && !defined(DART_PRECOMPILED_RUNTIME)))