@@ -950,8 +950,9 @@ void Simulator::set_register(Instr* instr,
950950 R31Type r31t) {
951951 // Register is in range.
952952 ASSERT ((reg >= 0 ) && (reg < kNumberOfCpuRegisters ));
953- #if !defined(DART_TARGET_OS_FUCHSIA)
954- ASSERT (instr == nullptr || reg != R18); // R18 is globally reserved on iOS.
953+ #if defined(DART_TARGET_OS_MACOS) || defined(DART_TARGET_OS_WINDOWS)
954+ // R18 is globally reserved on macOS/iOS, the TEB pointer on Windows.
955+ ASSERT (instr == nullptr || reg != R18);
955956#endif
956957
957958 if ((reg != R31) || (r31t != R31IsZR)) {
@@ -1682,7 +1683,7 @@ void Simulator::DoRedirectedCall(Instr* instr) {
16821683 Redirection* redirection = Redirection::FromHltInstruction (instr);
16831684 uword external = redirection->external_function ();
16841685 if (IsTracingExecution ()) {
1685- THR_Print (" Call to host function at 0x%" Pd " \n " , external);
1686+ THR_Print (" Call to host function at 0x%" Px " \n " , external);
16861687 }
16871688
16881689 if (redirection->call_kind () == kRuntimeCall ) {
@@ -1746,6 +1747,65 @@ void Simulator::DoRedirectedCall(Instr* instr) {
17461747 }
17471748}
17481749
1750+ struct CalloutContext {
1751+ uword saved_stack_pointer;
1752+ uword saved_frame_pointer;
1753+ uword simulator_stack_pointer;
1754+ uword simulator_frame_pointer;
1755+ uword integer_arguments[8 ];
1756+ uword double_arguments[8 ];
1757+ uword r8;
1758+ uword target;
1759+ };
1760+
1761+ extern " C" void FfiCalloutTrampoline (CalloutContext*);
1762+
1763+ void Simulator::DoRedirectedFfiCall (Instr* instr) {
1764+ #if !defined(HOST_ARCH_ARM64)
1765+ FATAL (" Unsupported FFI call" );
1766+ #else
1767+ // We can't instrument the runtime.
1768+ memory_.FlushAll ();
1769+
1770+ SimulatorSetjmpBuffer buffer (this );
1771+ if (!setjmp (buffer.buffer_ )) {
1772+ int64_t saved_pc = get_pc ();
1773+ uword external = get_register (R9);
1774+ if (IsTracingExecution ()) {
1775+ THR_Print (" Call to FFI function at 0x%" Px " \n " , external);
1776+ }
1777+
1778+ CalloutContext ctxt;
1779+ ctxt.simulator_stack_pointer = get_register (R31);
1780+ ctxt.simulator_frame_pointer = get_register (FP);
1781+ for (intptr_t i = 0 ; i < 8 ; i++) {
1782+ ctxt.integer_arguments [i] = get_register (static_cast <Register>(R0 + i));
1783+ ctxt.double_arguments [i] =
1784+ get_vregisterd (static_cast <VRegister>(V0 + i), 0 );
1785+ }
1786+ ctxt.r8 = get_register (R8);
1787+ ctxt.target = external;
1788+
1789+ FfiCalloutTrampoline (&ctxt);
1790+
1791+ if (IsTracingExecution ()) {
1792+ THR_Print (" Return from FFI function at 0x%" Px " \n " , external);
1793+ }
1794+
1795+ ClobberVolatileRegisters ();
1796+ set_register (instr, R0, ctxt.integer_arguments [0 ]);
1797+ set_register (instr, R1, ctxt.integer_arguments [1 ]);
1798+ set_vregisterd (V0, 0 , ctxt.double_arguments [0 ]);
1799+ set_vregisterd (V1, 0 , ctxt.double_arguments [1 ]);
1800+
1801+ // Skip over hlt and blr.
1802+ set_pc (saved_pc + 2 * Instr::kInstrSize );
1803+ } else {
1804+ // Coming via long jump from a throw. Continue to exception handler.
1805+ }
1806+ #endif
1807+ }
1808+
17491809void Simulator::ClobberVolatileRegisters () {
17501810 // Clear atomic reservation.
17511811 exclusive_access_addr_ = exclusive_access_value_ = 0 ;
@@ -1787,6 +1847,8 @@ void Simulator::DecodeExceptionGen(Instr* instr) {
17871847 dbg.Stop (instr, " breakpoint" );
17881848 } else if (imm == Instr::kSimulatorRedirectCode ) {
17891849 DoRedirectedCall (instr);
1850+ } else if (imm == Instr::kSimulatorFfiRedirectCode ) {
1851+ DoRedirectedFfiCall (instr);
17901852 } else {
17911853 UnimplementedInstruction (instr);
17921854 }
0 commit comments