[vm] Fix JumpToFrame execution state transition

Instead of handling FFI related execution state and safepoint
in assembly handle it in runtime code.

The transition needs to be done before JumpToFrame unwinds
stack because unwinding destroys exit frame and this can't
be done at safepoint as GC might be traversing the stack.

An incorrect order of operation was manifesting as crashes in
GC when one isolate in a group was encountering a lot of
exceptions thrown from an FFI call and another isolate is
triggering GCs.

To catch this in the future added a bit of validation to
ExitSafepoint runtime call which triggers when --use-slow-path
is enabled. Though after refactoring this code does not
trigger this code path anymore because it was completely
removed - but it is better than nothing.

This CL also removes a lot of unnecessary complexity which
was associated with handling this transition in the stub
itself.

TEST=ffi/vmspecific_handle_test

Bug: b/408377905
Cq-Include-Trybots: dart/try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-asan-linux-release-x64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-mac-release-arm64-try,vm-aot-msan-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-tsan-linux-release-x64-try,vm-aot-ubsan-linux-release-x64-try,vm-aot-win-debug-x64-try,vm-aot-win-debug-x64c-try,vm-appjit-linux-debug-x64-try,vm-asan-linux-release-arm64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-mac-debug-simarm64_arm64-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-x64-try,vm-linux-debug-ia32-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-msan-linux-release-arm64-try,vm-msan-linux-release-x64-try,vm-reload-linux-debug-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-tsan-linux-release-arm64-try,vm-tsan-linux-release-x64-try,vm-ubsan-linux-release-arm64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try
Change-Id: Ia073cb6bb9e1b5a0ea8514c7e048cee6019b84d6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/420324
Commit-Queue: Slava Egorov <vegorov@google.com>
Reviewed-by: Daco Harkes <dacoharkes@google.com>
This commit is contained in:
Vyacheslav Egorov
2025-04-07 05:22:56 -07:00
committed by Commit Queue
parent d33c6c3ef1
commit 8085a97a63
33 changed files with 2230 additions and 2450 deletions
+55
View File
@@ -1381,6 +1381,61 @@ void Thread::HandleStolen() {
/*was_stolen=*/true);
}
#ifndef PRODUCT
namespace {
// This visitor simply dereferences every non-Smi |ObjectPtr| it visits and
// checks that its class id is valid.
//
// It is used for fast validation of pointers on the stack: if a pointer is
// invalid it is likely to either cause a crash when dereferenced or have
// a garbage class id.
class FastPointerValidator : public ObjectPointerVisitor {
public:
explicit FastPointerValidator(IsolateGroup* isolate_group)
: ObjectPointerVisitor(isolate_group) {}
void VisitPointers(ObjectPtr* from, ObjectPtr* to) override {
for (ObjectPtr* ptr = from; ptr <= to; ptr++) {
const auto cid = (*ptr)->GetClassId();
RELEASE_ASSERT(class_table()->IsValidIndex(cid));
}
}
#if defined(DART_COMPRESSED_POINTERS)
void VisitCompressedPointers(uword heap_base,
CompressedObjectPtr* first,
CompressedObjectPtr* last) override {
// We are not expecting compressed pointers on the stack.
UNREACHABLE();
}
#endif
private:
DISALLOW_COPY_AND_ASSIGN(FastPointerValidator);
};
} // namespace
void Thread::ValidateExitFrameState() {
if (top_exit_frame_info() == 0) {
return;
}
FastPointerValidator fast_pointers_validator(isolate_group());
StackFrameIterator frames_iterator(
top_exit_frame_info(), ValidationPolicy::kValidateFrames, this,
StackFrameIterator::kNoCrossThreadIteration);
StackFrame* frame = frames_iterator.NextFrame();
while (frame != nullptr) {
frame->VisitObjectPointers(&fast_pointers_validator);
frame = frames_iterator.NextFrame();
}
}
#endif
void Thread::EnterSafepointUsingLock() {
isolate_group()->safepoint_handler()->EnterSafepointUsingLock(this);
}