[vm/interpreter] Fix interpreter frame recognition in stack walking
When GC is visiting pointers, it scans mutator thread even if it is not
active. It could happen if a thread has (temporarily) exitted isolate.
In such case, stack frame iteration would not find interpreter and
would not recognize interpreter frames. An attempt to visit interpreter
frame as non-interpreter causes crashes/assertions.
The fix is to move interpreter from Isolate to Thread. This way
interpreter is available for stack walking even if thread doesn't have
isolate.
Change-Id: Iff12ce7391b19a6f87bd4fac94137cba5623dfb9
Reviewed-on: https://dart-review.googlesource.com/c/80760
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/exceptions.cc b/runtime/vm/exceptions.cc
index 45d836a..06f5a47 100644
--- a/runtime/vm/exceptions.cc
+++ b/runtime/vm/exceptions.cc
@@ -540,7 +540,7 @@
// TODO(regis): We still possibly need to unwind interpreter frames if they
// are callee frames of the C++ frame handling the exception.
if (FLAG_enable_interpreter) {
- Interpreter* interpreter = thread->isolate()->interpreter();
+ Interpreter* interpreter = thread->interpreter();
if ((interpreter != NULL) && interpreter->HasFrame(frame_pointer)) {
interpreter->JumpToFrame(program_counter, stack_pointer, frame_pointer,
thread);
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index deac92b..3185b93 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -568,18 +568,14 @@
Interpreter::~Interpreter() {
delete[] stack_;
- Isolate* isolate = Isolate::Current();
- if (isolate != NULL) {
- isolate->set_interpreter(NULL);
- }
}
// Get the active Interpreter for the current isolate.
Interpreter* Interpreter::Current() {
- Interpreter* interpreter = Isolate::Current()->interpreter();
+ Interpreter* interpreter = Thread::Current()->interpreter();
if (interpreter == NULL) {
interpreter = new Interpreter();
- Isolate::Current()->set_interpreter(interpreter);
+ Thread::Current()->set_interpreter(interpreter);
}
return interpreter;
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index cefcfc2..114918a 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -909,9 +909,6 @@
library_tag_handler_(NULL),
api_state_(NULL),
random_(),
-#if !defined(DART_PRECOMPILED_RUNTIME)
- interpreter_(NULL),
-#endif
simulator_(NULL),
mutex_(new Mutex(NOT_IN_PRODUCT("Isolate::mutex_"))),
symbols_mutex_(new Mutex(NOT_IN_PRODUCT("Isolate::symbols_mutex_"))),
@@ -993,9 +990,6 @@
ASSERT(marking_stack_ == NULL);
delete object_store_;
delete api_state_;
-#if !defined(DART_PRECOMPILED_RUNTIME)
- delete interpreter_;
-#endif
#if defined(USING_SIMULATOR)
delete simulator_;
#endif
@@ -2003,12 +1997,6 @@
}
#endif // !defined(DART_PRECOMPILED_RUNTIME)
-#if !defined(DART_PRECOMPILED_RUNTIME)
- if (interpreter() != NULL) {
- interpreter()->VisitObjectPointers(visitor);
- }
-#endif
-
#if defined(TARGET_ARCH_DBC)
if (simulator() != NULL) {
simulator()->VisitObjectPointers(visitor);
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 9db354c..dd92e29 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -420,11 +420,6 @@
Random* random() { return &random_; }
-#if !defined(DART_PRECOMPILED_RUNTIME)
- Interpreter* interpreter() const { return interpreter_; }
- void set_interpreter(Interpreter* value) { interpreter_ = value; }
-#endif
-
Simulator* simulator() const { return simulator_; }
void set_simulator(Simulator* value) { simulator_ = value; }
@@ -973,9 +968,6 @@
Dart_LibraryTagHandler library_tag_handler_;
ApiState* api_state_;
Random random_;
-#if !defined(DART_PRECOMPILED_RUNTIME)
- Interpreter* interpreter_;
-#endif
Simulator* simulator_;
Mutex* mutex_; // Protects compiler stats.
Mutex* symbols_mutex_; // Protects concurrent access to the symbol table.
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index e58fb70..ad00ea5 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -2091,7 +2091,7 @@
#if !defined(DART_PRECOMPILED_RUNTIME)
if (FLAG_enable_interpreter) {
// Do not allocate an interpreter, if none is allocated yet.
- Interpreter* interpreter = Isolate::Current()->interpreter();
+ Interpreter* interpreter = Thread::Current()->interpreter();
if (interpreter != NULL) {
interpreter_stack_overflow =
interpreter->get_sp() >= interpreter->stack_limit();
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 796eae1..a8936df 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -436,6 +436,7 @@
}
void StackFrameIterator::SetupNextExitFrameData() {
+ ASSERT(entry_.fp() != 0);
uword exit_address =
entry_.fp() + ((entry_.is_interpreted() ? kKBCExitLinkSlotFromEntryFp
: kExitLinkSlotFromEntryFp) *
@@ -583,8 +584,7 @@
// TODO(regis): We should rely on a new thread vm_tag to identify an
// interpreter frame and not need the HasFrame() method.
ASSERT(FLAG_enable_interpreter);
- Isolate* isolate = thread_->isolate();
- Interpreter* interpreter = isolate != NULL ? isolate->interpreter() : NULL;
+ Interpreter* interpreter = thread_->interpreter();
is_interpreted_ = (interpreter != NULL) && interpreter->HasFrame(exit_marker);
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 1f267cc..0f42ef5 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -33,6 +33,10 @@
ASSERT(isolate_ == NULL);
ASSERT(store_buffer_block_ == NULL);
ASSERT(marking_stack_block_ == NULL);
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ delete interpreter_;
+ interpreter_ = nullptr;
+#endif
// There should be no top api scopes at this point.
ASSERT(api_top_scope() == NULL);
// Delete the resusable api scope if there is one.
@@ -95,6 +99,9 @@
hierarchy_info_(NULL),
type_usage_info_(NULL),
pending_functions_(GrowableObjectArray::null()),
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ interpreter_(nullptr),
+#endif
active_exception_(Object::null()),
active_stacktrace_(Object::null()),
resume_pc_(0),
@@ -668,6 +675,12 @@
visitor->VisitPointer(reinterpret_cast<RawObject**>(&sticky_error_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&async_stack_trace_));
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ if (interpreter() != NULL) {
+ interpreter()->VisitObjectPointers(visitor);
+ }
+#endif
+
// Visit the api local scope as it has all the api local handles.
ApiLocalScope* scope = api_top_scope_;
while (scope != NULL) {
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 4e01da6..5f4c710 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -34,6 +34,7 @@
class Heap;
class HierarchyInfo;
class Instance;
+class Interpreter;
class Isolate;
class Library;
class LongJumpScope;
@@ -401,6 +402,11 @@
type_usage_info_ = value;
}
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ Interpreter* interpreter() const { return interpreter_; }
+ void set_interpreter(Interpreter* value) { interpreter_ = value; }
+#endif
+
int32_t no_callback_scope_depth() const { return no_callback_scope_depth_; }
void IncrementNoCallbackScopeDepth() {
@@ -877,6 +883,10 @@
TypeUsageInfo* type_usage_info_;
RawGrowableObjectArray* pending_functions_;
+#if !defined(DART_PRECOMPILED_RUNTIME)
+ Interpreter* interpreter_;
+#endif
+
// JumpToExceptionHandler state:
RawObject* active_exception_;
RawObject* active_stacktrace_;