diff --git a/runtime/vm/runtime_entry.h b/runtime/vm/runtime_entry.h index e6e678fecfe..e2b582cdb60 100644 --- a/runtime/vm/runtime_entry.h +++ b/runtime/vm/runtime_entry.h @@ -55,6 +55,9 @@ class RuntimeEntry : public BaseRuntimeEntry { bool is_float() const { return is_float_; } bool can_lazy_deopt() const { return can_lazy_deopt_; } uword GetEntryPoint() const; + uword GetEntryPointNoRedirect() const { + return reinterpret_cast(function()); + } static uword InterpretCallEntry(); diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc index 4c12e243ec7..2af4bbaa395 100644 --- a/runtime/vm/simulator_arm64.cc +++ b/runtime/vm/simulator_arm64.cc @@ -4088,6 +4088,17 @@ void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) { // Keep the following code in sync with `StubCode::JumpToFrameStub()`. + // Check if we exited generated from FFI. If so do transition - this is needed + // because normally runtime calls transition back to generated via destructor + // of TransitionGeneratedToVM/Native that is part of runtime boilerplate + // code (see DEFINE_RUNTIME_ENTRY_IMPL in runtime_entry.h). Ffi calls don't + // have this boilerplate, don't have this stack resource, have to transition + // explicitly. + if (thread->exit_through_ffi() == dart::Thread::kExitThroughFfi) { + thread->ExitSafepoint(); + thread->set_execution_state(Thread::kThreadInGenerated); + } + // Unwind the C++ stack and continue simulation in the target frame. set_pc(static_cast(pc)); set_register(nullptr, SP, static_cast(sp)); diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc index a323c2378fb..bcbb2954707 100644 --- a/runtime/vm/thread.cc +++ b/runtime/vm/thread.cc @@ -218,6 +218,13 @@ void Thread::InitVMConstants() { LEAF_RUNTIME_ENTRY_LIST(INIT_VALUE) #undef INIT_VALUE +#if defined(SIMULATOR_FFI) + // FfiCallInstr calls this through the CallNativeThroughSafepoint stub instead + // of like a normal leaf runtime call. + PropagateError_entry_point_ = + kPropagateErrorRuntimeEntry.GetEntryPointNoRedirect(); +#endif + // Setup the thread specific reusable handles. #define REUSABLE_HANDLE_ALLOCATION(object) \ this->object##_handle_ = this->AllocateReusableHandle(); diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h index 4e3f53f0ca7..436b014f5c4 100644 --- a/runtime/vm/thread.h +++ b/runtime/vm/thread.h @@ -485,6 +485,7 @@ class Thread : public ThreadState { kExitThroughRuntimeCall = 2, }; + uword exit_through_ffi() { return exit_through_ffi_; } static intptr_t exit_through_ffi_offset() { return OFFSET_OF(Thread, exit_through_ffi_); } diff --git a/tests/ffi/abi_test.dart b/tests/ffi/abi_test.dart index 15c6776586d..d230c5ee9e1 100644 --- a/tests/ffi/abi_test.dart +++ b/tests/ffi/abi_test.dart @@ -18,7 +18,9 @@ void testCurrent() { } void testPlatformVersionCompatibility() { - final abiStringFromPlatformVersion = Platform.version.split('"')[1]; + final abiStringFromPlatformVersion = Platform.version + .split('"')[1] + .replaceAll("sim", ""); final abiStringFromCurrent = Abi.current().toString(); Expect.equals(abiStringFromPlatformVersion, abiStringFromCurrent); }