فهرست منبع

LibJS: Propagate exceptions across bytecode executable boundaries

To support situations like this:

    function foo() { throw 1; }

    try {
        foo();
    } catch (e) {
    }

Each unwind context now keeps track of its origin executable.

When an exception is thrown, we return from run() immediately if the
nearest unwind context isn't in the current executable.

This causes a natural unwind to the point where we find the
catch/finally block(s) to jump into.
Andreas Kling 3 سال پیش
والد
کامیت
3618ca2420
2فایلهای تغییر یافته به همراه4 افزوده شده و 1 حذف شده
  1. 1 0
      Userland/Libraries/LibJS/Bytecode/BasicBlock.h
  2. 3 1
      Userland/Libraries/LibJS/Bytecode/Interpreter.cpp

+ 1 - 0
Userland/Libraries/LibJS/Bytecode/BasicBlock.h

@@ -39,6 +39,7 @@ private:
 };
 };
 
 
 struct UnwindInfo {
 struct UnwindInfo {
+    Executable const* executable;
     BasicBlock const* handler;
     BasicBlock const* handler;
     BasicBlock const* finalizer;
     BasicBlock const* finalizer;
 };
 };

+ 3 - 1
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp

@@ -82,6 +82,8 @@ Value Interpreter::run(Executable const& executable, BasicBlock const* entry_poi
                 if (m_unwind_contexts.is_empty())
                 if (m_unwind_contexts.is_empty())
                     break;
                     break;
                 auto& unwind_context = m_unwind_contexts.last();
                 auto& unwind_context = m_unwind_contexts.last();
+                if (unwind_context.executable != m_current_executable)
+                    break;
                 if (unwind_context.handler) {
                 if (unwind_context.handler) {
                     block = unwind_context.handler;
                     block = unwind_context.handler;
                     unwind_context.handler = nullptr;
                     unwind_context.handler = nullptr;
@@ -156,7 +158,7 @@ Value Interpreter::run(Executable const& executable, BasicBlock const* entry_poi
 
 
 void Interpreter::enter_unwind_context(Optional<Label> handler_target, Optional<Label> finalizer_target)
 void Interpreter::enter_unwind_context(Optional<Label> handler_target, Optional<Label> finalizer_target)
 {
 {
-    m_unwind_contexts.empend(handler_target.has_value() ? &handler_target->block() : nullptr, finalizer_target.has_value() ? &finalizer_target->block() : nullptr);
+    m_unwind_contexts.empend(m_current_executable, handler_target.has_value() ? &handler_target->block() : nullptr, finalizer_target.has_value() ? &finalizer_target->block() : nullptr);
 }
 }
 
 
 void Interpreter::leave_unwind_context()
 void Interpreter::leave_unwind_context()