Przeglądaj źródła

LibJS: Add TemporaryClearException helper class

This is very similar to AK::TemporaryChange (and in fact replaces one
use of it), but since we can't directly set VM's m_exception from
outside of the VM, we need something more sophisticated.
Sometimes we need to temporarily remove the stored exception for some
other operation to succeed (e.g. anything that uses call(), as well as
get_without_side_effects()) and later restore it - the boilerplate code
required for this is annoying enough to justify a helper.
Linus Groh 4 lat temu
rodzic
commit
5caab0148c

+ 34 - 0
Userland/Libraries/LibJS/Runtime/TemporaryClearException.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021, Linus Groh <mail@linusgroh.de>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibJS/Runtime/Exception.h>
+#include <LibJS/Runtime/VM.h>
+
+namespace JS {
+
+class TemporaryClearException {
+public:
+    explicit TemporaryClearException(VM& vm)
+        : m_vm(vm)
+        , m_previous_exception(vm.exception())
+    {
+        m_vm.clear_exception();
+    }
+
+    ~TemporaryClearException()
+    {
+        if (m_previous_exception)
+            m_vm.set_exception(*m_previous_exception);
+    }
+
+private:
+    VM& m_vm;
+    Exception* m_previous_exception;
+};
+
+}

+ 2 - 2
Userland/Libraries/LibJS/Runtime/VM.cpp

@@ -8,7 +8,6 @@
 #include <AK/Debug.h>
 #include <AK/ScopeGuard.h>
 #include <AK/StringBuilder.h>
-#include <AK/TemporaryChange.h>
 #include <LibJS/Interpreter.h>
 #include <LibJS/Runtime/Array.h>
 #include <LibJS/Runtime/Error.h>
@@ -18,6 +17,7 @@
 #include <LibJS/Runtime/Reference.h>
 #include <LibJS/Runtime/ScriptFunction.h>
 #include <LibJS/Runtime/Symbol.h>
+#include <LibJS/Runtime/TemporaryClearException.h>
 #include <LibJS/Runtime/VM.h>
 
 namespace JS {
@@ -376,7 +376,7 @@ void VM::run_queued_promise_jobs()
     dbgln_if(PROMISE_DEBUG, "Running queued promise jobs");
     // Temporarily get rid of the exception, if any - job functions must be called
     // either way, and that can't happen if we already have an exception stored.
-    TemporaryChange change(m_exception, static_cast<Exception*>(nullptr));
+    TemporaryClearException clear_exception(*this);
     while (!m_promise_jobs.is_empty()) {
         auto* job = m_promise_jobs.take_first();
         dbgln_if(PROMISE_DEBUG, "Calling promise job function @ {}", job);