浏览代码

LibJS: Add a way to save/restore the entire execution context stack

This will be used by LibWeb to squirrel away the stack while performing
a microtask checkpoint in some cases. VM will simply consider saved
execution context stacks as GC roots as well.
Andreas Kling 3 年之前
父节点
当前提交
406d3199d0
共有 2 个文件被更改,包括 31 次插入10 次删除
  1. 26 10
      Userland/Libraries/LibJS/Runtime/VM.cpp
  2. 5 0
      Userland/Libraries/LibJS/Runtime/VM.h

+ 26 - 10
Userland/Libraries/LibJS/Runtime/VM.cpp

@@ -99,17 +99,23 @@ void VM::gather_roots(HashTable<Cell*>& roots)
     if (m_last_value.is_cell())
         roots.set(&m_last_value.as_cell());
 
-    for (auto& execution_context : m_execution_context_stack) {
-        if (execution_context->this_value.is_cell())
-            roots.set(&execution_context->this_value.as_cell());
-        roots.set(execution_context->arguments_object);
-        for (auto& argument : execution_context->arguments) {
-            if (argument.is_cell())
-                roots.set(&argument.as_cell());
+    auto gather_roots_from_execution_context_stack = [&roots](Vector<ExecutionContext*> const& stack) {
+        for (auto& execution_context : stack) {
+            if (execution_context->this_value.is_cell())
+                roots.set(&execution_context->this_value.as_cell());
+            roots.set(execution_context->arguments_object);
+            for (auto& argument : execution_context->arguments) {
+                if (argument.is_cell())
+                    roots.set(&argument.as_cell());
+            }
+            roots.set(execution_context->lexical_environment);
+            roots.set(execution_context->variable_environment);
         }
-        roots.set(execution_context->lexical_environment);
-        roots.set(execution_context->variable_environment);
-    }
+    };
+
+    gather_roots_from_execution_context_stack(m_execution_context_stack);
+    for (auto& saved_stack : m_saved_execution_context_stacks)
+        gather_roots_from_execution_context_stack(saved_stack);
 
 #define __JS_ENUMERATE(SymbolName, snake_name) \
     roots.set(well_known_symbol_##snake_name());
@@ -828,4 +834,14 @@ VM::CustomData::~CustomData()
 {
 }
 
+void VM::save_execution_context_stack()
+{
+    m_saved_execution_context_stacks.append(move(m_execution_context_stack));
+}
+
+void VM::restore_execution_context_stack()
+{
+    m_execution_context_stack = m_saved_execution_context_stacks.take_last();
+}
+
 }

+ 5 - 0
Userland/Libraries/LibJS/Runtime/VM.h

@@ -280,6 +280,9 @@ public:
 
     ThrowCompletionOr<Value> named_evaluation_if_anonymous_function(GlobalObject& global_object, ASTNode const& expression, FlyString const& name);
 
+    void save_execution_context_stack();
+    void restore_execution_context_stack();
+
 private:
     explicit VM(OwnPtr<CustomData>);
 
@@ -302,6 +305,8 @@ private:
 
     Vector<ExecutionContext*> m_execution_context_stack;
 
+    Vector<Vector<ExecutionContext*>> m_saved_execution_context_stacks;
+
     Value m_last_value;
     ScopeType m_unwind_until { ScopeType::None };
     FlyString m_unwind_until_label;