From 77d7f715e3a50e1f9140fe41fd0bcdc8b117ff52 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Fri, 21 Jul 2023 09:59:50 -0400 Subject: [PATCH] LibJS+CI: Remove bytecode optimization passes for now These passes have not been shown to actually optimize any JS, and tests have become very flaky with optimizations enabled. Until some measurable benefit is shown, remove the optimization passes to reduce overhead of maintaining bytecode operations and to reduce CI churn. The framework for optimizations will live on in git history, and can be restored once proven useful. --- .github/workflows/libjs-test262.yml | 9 +- Tests/LibJS/test262-runner.cpp | 4 - .../Libraries/LibJS/Bytecode/Instruction.h | 2 - .../Libraries/LibJS/Bytecode/Interpreter.cpp | 42 --- .../Libraries/LibJS/Bytecode/Interpreter.h | 4 - Userland/Libraries/LibJS/Bytecode/Op.cpp | 82 ------ Userland/Libraries/LibJS/Bytecode/Op.h | 260 ------------------ .../Libraries/LibJS/Bytecode/Pass/DumpCFG.cpp | 26 -- .../LibJS/Bytecode/Pass/GenerateCFG.cpp | 220 --------------- .../LibJS/Bytecode/Pass/LoadElimination.cpp | 208 -------------- .../LibJS/Bytecode/Pass/MergeBlocks.cpp | 185 ------------- .../LibJS/Bytecode/Pass/PlaceBlocks.cpp | 58 ---- .../LibJS/Bytecode/Pass/UnifySameBlocks.cpp | 66 ----- .../Libraries/LibJS/Bytecode/PassManager.h | 136 --------- Userland/Libraries/LibJS/CMakeLists.txt | 6 - .../Runtime/ECMAScriptFunctionObject.cpp | 1 - Userland/Utilities/js.cpp | 3 - 17 files changed, 1 insertion(+), 1311 deletions(-) delete mode 100644 Userland/Libraries/LibJS/Bytecode/Pass/DumpCFG.cpp delete mode 100644 Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp delete mode 100644 Userland/Libraries/LibJS/Bytecode/Pass/LoadElimination.cpp delete mode 100644 Userland/Libraries/LibJS/Bytecode/Pass/MergeBlocks.cpp delete mode 100644 Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp delete mode 100644 Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp delete mode 100644 Userland/Libraries/LibJS/Bytecode/PassManager.h diff --git a/.github/workflows/libjs-test262.yml b/.github/workflows/libjs-test262.yml index 591ca05a9a1..2abd81bd669 100644 --- a/.github/workflows/libjs-test262.yml +++ b/.github/workflows/libjs-test262.yml @@ -107,7 +107,6 @@ jobs: run: | cp -f ../libjs-website/test262/data/per-file-master.json . cp -f ../libjs-website/test262/data/per-file-bytecode-master.json . - cp -f ../libjs-website/test262/data/per-file-bytecode-optimized-master.json . cp -f ../libjs-website/wasm/data/per-file-master.json wasm-per-file-master.json - name: Run test262 and test262-parser-tests @@ -119,8 +118,7 @@ jobs: --test262-parser-tests ../test262-parser-tests \ --results-json ../libjs-website/test262/data/results.json \ --per-file-output ../libjs-website/test262/data/per-file-master.json \ - --per-file-bytecode-output ../libjs-website/test262/data/per-file-bytecode-master.json \ - --per-file-bytecode-optimized-output ../libjs-website/test262/data/per-file-bytecode-optimized-master.json + --per-file-bytecode-output ../libjs-website/test262/data/per-file-bytecode-master.json - name: Run test-wasm working-directory: libjs-test262/Build @@ -169,11 +167,6 @@ jobs: working-directory: libjs-test262 run: ./per_file_result_diff.py -o per-file-bytecode-master.json -n ../libjs-website/test262/data/per-file-bytecode-master.json - - name: Compare optimized bytecode - continue-on-error: true - working-directory: libjs-test262 - run: ./per_file_result_diff.py -o per-file-bytecode-optimized-master.json -n ../libjs-website/test262/data/per-file-bytecode-optimized-master.json - - name: Compare non-bytecode to bytecode continue-on-error: true working-directory: libjs-test262 diff --git a/Tests/LibJS/test262-runner.cpp b/Tests/LibJS/test262-runner.cpp index 791631118d1..148abe7db08 100644 --- a/Tests/LibJS/test262-runner.cpp +++ b/Tests/LibJS/test262-runner.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -564,13 +563,11 @@ int main(int argc, char** argv) bool enable_debug_printing = false; bool disable_core_dumping = false; bool use_bytecode = false; - bool enable_bytecode_optimizations = false; Core::ArgsParser args_parser; args_parser.set_general_help("LibJS test262 runner for streaming tests"); args_parser.add_option(s_harness_file_directory, "Directory containing the harness files", "harness-location", 'l', "harness-files"); args_parser.add_option(use_bytecode, "Use the bytecode interpreter", "use-bytecode", 'b'); - args_parser.add_option(enable_bytecode_optimizations, "Enable the bytecode optimization passes", "enable-bytecode-optimizations", 'e'); args_parser.add_option(s_parse_only, "Only parse the files", "parse-only", 'p'); args_parser.add_option(timeout, "Seconds before test should timeout", "timeout", 't', "seconds"); args_parser.add_option(enable_debug_printing, "Enable debug printing", "debug", 'd'); @@ -578,7 +575,6 @@ int main(int argc, char** argv) args_parser.parse(arguments); JS::Bytecode::Interpreter::set_enabled(use_bytecode); - JS::Bytecode::Interpreter::set_optimizations_enabled(enable_bytecode_optimizations); #if !defined(AK_OS_MACOS) && !defined(AK_OS_EMSCRIPTEN) if (disable_core_dumping && prctl(PR_SET_DUMPABLE, 0, 0) < 0) { diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 74697c61387..13d2db87f6a 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -134,8 +134,6 @@ public: size_t length() const; DeprecatedString to_deprecated_string(Bytecode::Executable const&) const; ThrowCompletionOr execute(Bytecode::Interpreter&) const; - void replace_references(BasicBlock const&, BasicBlock const&); - void replace_references(Register, Register); static void destroy(Instruction&); protected: diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 2671ecfc17e..9efb741ca7b 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -32,13 +31,6 @@ void Interpreter::set_enabled(bool enabled) s_bytecode_interpreter_enabled = enabled; } -static bool s_optimizations_enabled = false; - -void Interpreter::set_optimizations_enabled(bool enabled) -{ - s_optimizations_enabled = enabled; -} - bool g_dump_bytecode = false; Interpreter::Interpreter(VM& vm) @@ -124,11 +116,6 @@ ThrowCompletionOr Interpreter::run(Script& script_record, JS::GCPtrdump(); @@ -403,26 +390,6 @@ VM::InterpreterExecutionScope Interpreter::ast_interpreter_scope(Realm& realm) return { *m_ast_interpreter }; } -Bytecode::PassManager& Interpreter::optimization_pipeline() -{ - static auto s_optimization_pipeline = [] { - auto pm = make(); - pm->add(); - pm->add(); - pm->add(); - pm->add(); - pm->add(); - pm->add(); - pm->add(); - pm->add(); - pm->add(); - pm->add(); - pm->add(); - return pm; - }(); - return *s_optimization_pipeline; -} - size_t Interpreter::pc() const { return m_pc ? m_pc->offset() : 0; @@ -442,15 +409,6 @@ ThrowCompletionOr> compile(VM& vm, ASTNode c auto bytecode_executable = executable_result.release_value(); bytecode_executable->name = name; - if (s_optimizations_enabled) { - auto& passes = Bytecode::Interpreter::optimization_pipeline(); - passes.perform(*bytecode_executable); - if constexpr (JS_BYTECODE_DEBUG) { - dbgln("Optimisation passes took {}us", passes.elapsed()); - dbgln("Compiled Bytecode::Block for function '{}':", name); - } - } - if (Bytecode::g_dump_bytecode) bytecode_executable->dump(); diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index 019837dc100..bb0de83e13c 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -17,7 +17,6 @@ namespace JS::Bytecode { class InstructionStreamIterator; -class PassManager; struct CallFrame { void visit_edges(Cell::Visitor& visitor) @@ -39,7 +38,6 @@ class Interpreter { public: [[nodiscard]] static bool enabled(); static void set_enabled(bool); - static void set_optimizations_enabled(bool); explicit Interpreter(VM&); ~Interpreter(); @@ -94,8 +92,6 @@ public: size_t pc() const; DeprecatedString debug_position() const; - static Bytecode::PassManager& optimization_pipeline(); - VM::InterpreterExecutionScope ast_interpreter_scope(Realm&); void visit_edges(Cell::Visitor&); diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 9de0101f4db..1e37fd6aee6 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -257,14 +257,6 @@ ThrowCompletionOr ImportCall::execute_impl(Bytecode::Interpreter& interpre return {}; } -void ImportCall::replace_references_impl(Register from, Register to) -{ - if (m_specifier == from) - m_specifier = to; - if (m_options == from) - m_options = to; -} - // FIXME: Since the accumulator is a Value, we store an object there and have to convert back and forth between that an Iterator records. Not great. // Make sure to put this into the accumulator before the iterator object disappears from the stack to prevent the members from being GC'd. static Object* iterator_to_object(VM& vm, IteratorRecord iterator) @@ -774,14 +766,6 @@ ThrowCompletionOr GetImportMeta::execute_impl(Bytecode::Interpreter& inter return {}; } -void Jump::replace_references_impl(BasicBlock const& from, BasicBlock const& to) -{ - if (m_true_target.has_value() && &m_true_target->block() == &from) - m_true_target = Label { to }; - if (m_false_target.has_value() && &m_false_target->block() == &from) - m_false_target = Label { to }; -} - ThrowCompletionOr JumpConditional::execute_impl(Bytecode::Interpreter& interpreter) const { VERIFY(m_true_target.has_value()); @@ -1045,54 +1029,6 @@ ThrowCompletionOr EnterUnwindContext::execute_impl(Bytecode::Interpreter& return {}; } -void NewFunction::replace_references_impl(Register from, Register to) -{ - if (m_home_object == from) - m_home_object = to; -} - -void EnterUnwindContext::replace_references_impl(BasicBlock const& from, BasicBlock const& to) -{ - if (&m_entry_point.block() == &from) - m_entry_point = Label { to }; - if (m_handler_target.has_value() && &m_handler_target->block() == &from) - m_handler_target = Label { to }; - if (m_finalizer_target.has_value() && &m_finalizer_target->block() == &from) - m_finalizer_target = Label { to }; -} - -void CopyObjectExcludingProperties::replace_references_impl(Register from, Register to) -{ - if (m_from_object == from) - m_from_object = to; - - for (size_t i = 0; i < m_excluded_names_count; ++i) { - if (m_excluded_names[i] == from) - m_excluded_names[i] = to; - } -} - -void Call::replace_references_impl(Register from, Register to) -{ - if (m_callee == from) - m_callee = to; - - if (m_this_value == from) - m_this_value = to; - - if (m_first_argument == from) - m_first_argument = to; -} - -void CallWithArgumentArray::replace_references_impl(Register from, Register to) -{ - if (m_callee == from) - m_callee = to; - - if (m_this_value == from) - m_this_value = to; -} - ThrowCompletionOr ScheduleJump::execute_impl(Bytecode::Interpreter& interpreter) const { interpreter.schedule_jump(m_target); @@ -1116,12 +1052,6 @@ ThrowCompletionOr ContinuePendingUnwind::execute_impl(Bytecode::Interprete return interpreter.continue_pending_unwind(m_resume_target); } -void ContinuePendingUnwind::replace_references_impl(BasicBlock const& from, BasicBlock const& to) -{ - if (&m_resume_target.block() == &from) - m_resume_target = Label { to }; -} - ThrowCompletionOr PushDeclarativeEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const { auto environment = interpreter.vm().heap().allocate_without_realm(interpreter.vm().lexical_environment()); @@ -1148,12 +1078,6 @@ ThrowCompletionOr Yield::execute_impl(Bytecode::Interpreter& interpreter) return {}; } -void Yield::replace_references_impl(BasicBlock const& from, BasicBlock const& to) -{ - if (m_continuation_label.has_value() && &m_continuation_label->block() == &from) - m_continuation_label = Label { to }; -} - ThrowCompletionOr Await::execute_impl(Bytecode::Interpreter& interpreter) const { auto yielded_value = interpreter.accumulator().value_or(js_undefined()); @@ -1167,12 +1091,6 @@ ThrowCompletionOr Await::execute_impl(Bytecode::Interpreter& interpreter) return {}; } -void Await::replace_references_impl(BasicBlock const& from, BasicBlock const& to) -{ - if (&m_continuation_label.block() == &from) - m_continuation_label = Label { to }; -} - ThrowCompletionOr GetByValue::execute_impl(Bytecode::Interpreter& interpreter) const { auto& vm = interpreter.vm(); diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index e111aaf7e93..754870b9c04 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -39,12 +39,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_src == from) - m_src = to; - } private: Register m_src; @@ -60,8 +54,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: Value m_value; @@ -77,8 +69,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } Register dst() const { return m_dst; } @@ -121,14 +111,6 @@ private: \ ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; \ - void replace_references_impl(BasicBlock const&, BasicBlock const&) \ - { \ - } \ - void replace_references_impl(Register from, Register to) \ - { \ - if (m_lhs_reg == from) \ - m_lhs_reg = to; \ - } \ \ private: \ Register m_lhs_reg; \ @@ -154,12 +136,6 @@ JS_ENUMERATE_COMMON_BINARY_OPS(JS_DECLARE_COMMON_BINARY_OP) \ ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; \ - void replace_references_impl(BasicBlock const&, BasicBlock const&) \ - { \ - } \ - void replace_references_impl(Register, Register) \ - { \ - } \ }; JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP) @@ -175,8 +151,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: StringTableIndex m_string; @@ -191,8 +165,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class NewRegExp final : public Instruction { @@ -207,8 +179,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: StringTableIndex m_source_index; @@ -230,12 +200,6 @@ private: \ ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; \ DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; \ - void replace_references_impl(BasicBlock const&, BasicBlock const&) \ - { \ - } \ - void replace_references_impl(Register, Register) \ - { \ - } \ \ private: \ StringTableIndex m_error_string; \ @@ -258,8 +222,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to); size_t length_impl() const { return sizeof(*this) + sizeof(Register) * m_excluded_names_count; } @@ -279,8 +241,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: Crypto::SignedBigInteger m_bigint; @@ -305,10 +265,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - // Note: The underlying element range shall never be changed item, by item - // shifting it may be done in the future - void replace_references_impl(Register from, Register) { VERIFY(!m_element_count || from.index() < start().index() || from.index() > end().index()); } size_t length_impl() const { @@ -345,10 +301,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - - // Note: This should never do anything, the lhs should always be an array, that is currently being constructed - void replace_references_impl(Register from, Register) { VERIFY(from != m_lhs); } private: Register m_lhs; @@ -366,8 +318,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register); private: Register m_specifier; @@ -383,8 +333,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class ConcatString final : public Instruction { @@ -397,9 +345,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - // Note: lhs should always be a string in construction, so this should never do anything - void replace_references_impl(Register from, Register) { VERIFY(from != m_lhs); } private: Register m_lhs; @@ -419,8 +364,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class EnterObjectEnvironment final : public Instruction { @@ -432,8 +375,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class CreateVariable final : public Instruction { @@ -449,8 +390,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IdentifierTableIndex m_identifier; @@ -476,8 +415,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } IdentifierTableIndex identifier() const { return m_identifier; } @@ -497,8 +434,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } size_t index() const { return m_index; } @@ -516,8 +451,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } IdentifierTableIndex identifier() const { return m_identifier; } @@ -538,8 +471,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IdentifierTableIndex m_identifier; @@ -556,8 +487,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } size_t index() const { return m_index; } @@ -575,8 +504,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } IdentifierTableIndex identifier() const { return m_identifier; } @@ -595,8 +522,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IdentifierTableIndex m_property; @@ -615,12 +540,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_this_value == from) - m_this_value = to; - } private: IdentifierTableIndex m_property; @@ -638,8 +557,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IdentifierTableIndex m_property; @@ -655,8 +572,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IdentifierTableIndex m_property; @@ -683,12 +598,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - } private: Register m_base; @@ -709,14 +618,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - if (m_this_value == from) - m_this_value = to; - } private: Register m_base; @@ -737,12 +638,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - } private: Register m_base; @@ -760,8 +655,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IdentifierTableIndex m_property; @@ -778,8 +671,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: Register m_this_value; @@ -796,12 +687,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - } private: Register m_base; @@ -818,14 +703,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - if (m_this_value == from) - m_this_value = to; - } private: Register m_base; @@ -844,14 +721,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - if (m_property == from) - m_property = to; - } private: Register m_base; @@ -872,16 +741,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - if (m_property == from) - m_property = to; - if (m_this_value == from) - m_this_value = to; - } private: Register m_base; @@ -900,12 +759,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - } private: Register m_base; @@ -922,12 +775,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register from, Register to) - { - if (m_base == from) - m_base = to; - } private: Register m_base; @@ -960,8 +807,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&); - void replace_references_impl(Register, Register) { } auto& true_target() const { return m_true_target; } auto& false_target() const { return m_false_target; } @@ -1033,8 +878,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register); private: Register m_callee; @@ -1063,8 +906,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register); private: Register m_callee; @@ -1083,8 +924,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: bool m_is_synthetic; @@ -1101,8 +940,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: ClassExpression const& m_class_expression; @@ -1121,8 +958,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register); private: FunctionExpression const& m_function_node; @@ -1140,8 +975,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: ScopeNode const& m_scope_node; @@ -1158,8 +991,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class Increment final : public Instruction { @@ -1171,8 +1002,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class Decrement final : public Instruction { @@ -1184,8 +1013,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class ToNumeric final : public Instruction { @@ -1197,8 +1024,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class Throw final : public Instruction { @@ -1212,8 +1037,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class ThrowIfNotObject final : public Instruction { @@ -1225,8 +1048,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class ThrowIfNullish final : public Instruction { @@ -1238,8 +1059,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class EnterUnwindContext final : public Instruction { @@ -1256,8 +1075,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&); - void replace_references_impl(Register, Register) { } auto& entry_point() const { return m_entry_point; } auto& handler_target() const { return m_handler_target; } @@ -1291,13 +1108,6 @@ public: Label target() const { return m_target; } ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; - void replace_references_impl(BasicBlock const& from, BasicBlock const& to) - { - if (&m_target.block() == &from) - m_target = Label { to }; - } - void replace_references_impl(Register, Register) { } - DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; private: @@ -1313,8 +1123,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class LeaveUnwindContext final : public Instruction { @@ -1326,8 +1134,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class ContinuePendingUnwind final : public Instruction { @@ -1342,8 +1148,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&); - void replace_references_impl(Register, Register) { } auto& resume_target() const { return m_resume_target; } @@ -1368,8 +1172,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&); - void replace_references_impl(Register, Register) { } auto& continuation() const { return m_continuation_label; } @@ -1389,8 +1191,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&); - void replace_references_impl(Register, Register) { } auto& continuation() const { return m_continuation_label; } @@ -1408,8 +1208,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: HashMap m_variables; @@ -1425,8 +1223,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IteratorHint m_hint { IteratorHint::Sync }; @@ -1442,8 +1238,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IdentifierTableIndex m_property; @@ -1458,8 +1252,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class IteratorClose final : public Instruction { @@ -1473,8 +1265,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: Completion::Type m_completion_type { Completion::Type::Normal }; @@ -1492,8 +1282,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: Completion::Type m_completion_type { Completion::Type::Normal }; @@ -1509,8 +1297,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class IteratorResultDone final : public Instruction { @@ -1522,8 +1308,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class IteratorResultValue final : public Instruction { @@ -1535,8 +1319,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class ResolveThisBinding final : public Instruction { @@ -1548,8 +1330,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class ResolveSuperBase final : public Instruction { @@ -1561,8 +1341,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class GetNewTarget final : public Instruction { @@ -1574,8 +1352,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class GetImportMeta final : public Instruction { @@ -1587,8 +1363,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } }; class TypeofVariable final : public Instruction { @@ -1601,8 +1375,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: IdentifierTableIndex m_identifier; @@ -1618,8 +1390,6 @@ public: ThrowCompletionOr execute_impl(Bytecode::Interpreter&) const; DeprecatedString to_deprecated_string_impl(Bytecode::Executable const&) const; - void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - void replace_references_impl(Register, Register) { } private: size_t m_index; @@ -1644,36 +1414,6 @@ ALWAYS_INLINE ThrowCompletionOr Instruction::execute(Bytecode::Interpreter #undef __BYTECODE_OP } -ALWAYS_INLINE void Instruction::replace_references(BasicBlock const& from, BasicBlock const& to) -{ -#define __BYTECODE_OP(op) \ - case Instruction::Type::op: \ - return static_cast(*this).replace_references_impl(from, to); - - switch (type()) { - ENUMERATE_BYTECODE_OPS(__BYTECODE_OP) - default: - VERIFY_NOT_REACHED(); - } - -#undef __BYTECODE_OP -} - -ALWAYS_INLINE void Instruction::replace_references(Register from, Register to) -{ -#define __BYTECODE_OP(op) \ - case Instruction::Type::op: \ - return static_cast(*this).replace_references_impl(from, to); - - switch (type()) { - ENUMERATE_BYTECODE_OPS(__BYTECODE_OP) - default: - VERIFY_NOT_REACHED(); - } - -#undef __BYTECODE_OP -} - ALWAYS_INLINE size_t Instruction::length() const { if (type() == Type::NewArray) diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/DumpCFG.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/DumpCFG.cpp deleted file mode 100644 index e40b1bff177..00000000000 --- a/Userland/Libraries/LibJS/Bytecode/Pass/DumpCFG.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2021, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace JS::Bytecode::Passes { - -void DumpCFG::perform(PassPipelineExecutable& executable) -{ - started(); - - VERIFY(executable.cfg.has_value()); - outln(m_file, "CFG Dump for {} basic blocks:", executable.executable.basic_blocks.size()); - for (auto& entry : executable.cfg.value()) { - for (auto& value : entry.value) - outln(m_file, "{} -> {}", entry.key->name(), value->name()); - } - outln(m_file); - - finished(); -} - -} diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp deleted file mode 100644 index 180e6dfe14e..00000000000 --- a/Userland/Libraries/LibJS/Bytecode/Pass/GenerateCFG.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright (c) 2021, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace JS::Bytecode::Passes { - -struct UnwindFrame { - BasicBlock const* handler; - BasicBlock const* finalizer; - Vector finalizer_targets; -}; - -static HashTable seen_blocks; -static Vector unwind_frames; - -static BasicBlock const* next_handler_or_finalizer() -{ - return unwind_frames.last()->handler ?: unwind_frames.last()->finalizer; -} - -static void generate_cfg_for_block(BasicBlock const& current_block, PassPipelineExecutable& executable) -{ - seen_blocks.set(¤t_block); - - auto enter_label = [&](Label const& label, BasicBlock const& entering_block) { - executable.cfg->ensure(&entering_block).set(&label.block()); - executable.inverted_cfg->ensure(&label.block()).set(&entering_block); - - // The finalizers and handlers of an unwind context are handled separately - if (!seen_blocks.contains(&label.block()) - && &label.block() != unwind_frames.last()->handler - && &label.block() != unwind_frames.last()->finalizer) - generate_cfg_for_block(label.block(), executable); - }; - - if (auto const* block = next_handler_or_finalizer()) - enter_label(Label { *block }, current_block); - - for (InstructionStreamIterator it { current_block.instruction_stream() }; !it.at_end(); ++it) { - auto const& instruction = *it; - - if (instruction.type() == Instruction::Type::LeaveUnwindContext) { - if (unwind_frames.last()->finalizer && unwind_frames.last()->finalizer != ¤t_block) - dbgln("FIXME: Popping finalizer from the unwind context from outside the finalizer"); - unwind_frames.take_last(); - - if (auto const* block = next_handler_or_finalizer()) - enter_label(Label { *block }, current_block); - } - - if (!instruction.is_terminator()) - continue; - - using enum Instruction::Type; - switch (instruction.type()) { - case Jump: { - auto true_target = *static_cast(instruction).true_target(); - enter_label(true_target, current_block); - return; - } - case JumpConditional: - case JumpNullish: - case JumpUndefined: { - // FIXME: It would be nice if we could avoid this copy, if we know that the unwind context stays the same in both paths - // Or with a COW capable Vector alternative - // Note: We might partially unwind here, so we need to make a copy of - // the current context to assure that the falsy code path has the same one - { - TemporaryChange saved_context { unwind_frames, unwind_frames }; - - auto true_target = *static_cast(instruction).true_target(); - enter_label(true_target, current_block); - } - - auto false_target = *static_cast(instruction).false_target(); - enter_label(false_target, current_block); - return; - } - case Yield: { - auto continuation = static_cast(instruction).continuation(); - if (continuation.has_value()) { - executable.exported_blocks->set(&continuation->block()); - enter_label(*continuation, current_block); - } else if (auto const* finalizer = unwind_frames.last()->finalizer) { - enter_label(Label { *finalizer }, current_block); - unwind_frames.last()->finalizer_targets.append(nullptr); - } - return; - } - case Await: { - auto const& continuation = static_cast(instruction).continuation(); - executable.exported_blocks->set(&continuation.block()); - enter_label(continuation, current_block); - return; - } - case EnterUnwindContext: { - auto entry_point = static_cast(instruction).entry_point(); - auto handler_target = static_cast(instruction).handler_target(); - auto finalizer_target = static_cast(instruction).finalizer_target(); - - // We keep the frame alive here on the stack, to save some allocation size - UnwindFrame frame { - .handler = handler_target.has_value() ? &handler_target->block() : nullptr, - .finalizer = finalizer_target.has_value() ? &finalizer_target->block() : nullptr, - .finalizer_targets = {} - }; - - unwind_frames.append(&frame); - - { - // This will enter the handler and finalizer when needed. - TemporaryChange saved_context { unwind_frames, unwind_frames }; - enter_label(entry_point, current_block); - } - frame.handler = nullptr; - if (handler_target.has_value()) { - // We manually generate the CFG, because we previously skiped it - TemporaryChange saved_context { unwind_frames, unwind_frames }; - generate_cfg_for_block(handler_target->block(), executable); - } - - if (finalizer_target.has_value()) { - // We manually generate the CFG, because we previously halted before entering it - generate_cfg_for_block(finalizer_target->block(), executable); - VERIFY(unwind_frames.last() != &frame); - - // We previously halted execution when we would enter the finalizer, - // So we now have to visit all possible targets - // This mainly affects the ScheduleJump instruction - for (auto const* block : frame.finalizer_targets) { - if (block == nullptr) { - // This signals a `return`, which we do not handle specially, so we skip - continue; - } - if (!seen_blocks.contains(block)) - generate_cfg_for_block(*block, executable); - } - } else { - VERIFY(unwind_frames.last() == &frame); - unwind_frames.take_last(); - VERIFY(frame.finalizer_targets.is_empty()); - } - - return; - } - case ContinuePendingUnwind: { - auto resume_target = static_cast(instruction).resume_target(); - enter_label(resume_target, current_block); - // Note: We already mark these possible control flow changes further up, but when we get - // get better error awareness, being explicit here will be required - if (auto const* handler = unwind_frames.last()->handler) - enter_label(Label { *handler }, current_block); - else if (auto const* finalizer = unwind_frames.last()->finalizer) - enter_label(Label { *finalizer }, current_block); - - return; - } - case Throw: - // Note: We technically register that we enter the handler in the prelude, - // but lets be correct and mark it again, - // this will be useful once we have more info on which instruction can - // actually fail - if (auto const* handler = unwind_frames.last()->handler) { - enter_label(Label { *handler }, current_block); - } else if (auto const* finalizer = unwind_frames.last()->finalizer) { - enter_label(Label { *finalizer }, current_block); - // Note: This error might bubble through the finalizer to the next handler/finalizer, - // This is currently marked in the general path - } - return; - case Return: - if (auto const* finalizer = unwind_frames.last()->finalizer) { - enter_label(Label { *finalizer }, current_block); - unwind_frames.last()->finalizer_targets.append(nullptr); - } - return; - case ScheduleJump: { - enter_label(Label { *unwind_frames.last()->finalizer }, current_block); - - unwind_frames.last()->finalizer_targets.append( - &static_cast(instruction).target().block()); - return; - } - default: - dbgln("Unhandled terminator instruction: `{}`", instruction.to_deprecated_string(executable.executable)); - VERIFY_NOT_REACHED(); - }; - } - - // We have left the block, but not through a designated terminator, - // so before we return, we need to check if we still need to go through a finalizer - if (auto const* finalizer = unwind_frames.last()->finalizer) - enter_label(Label { *finalizer }, current_block); -} - -void GenerateCFG::perform(PassPipelineExecutable& executable) -{ - started(); - - executable.cfg = HashMap> {}; - executable.inverted_cfg = HashMap> {}; - executable.exported_blocks = HashTable {}; - - seen_blocks.clear(); - unwind_frames.clear(); - UnwindFrame top_level_frame = {}; - - unwind_frames.append(&top_level_frame); - - generate_cfg_for_block(*executable.executable.basic_blocks.first(), executable); - - finished(); -} - -} diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/LoadElimination.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/LoadElimination.cpp deleted file mode 100644 index 0745fc1c715..00000000000 --- a/Userland/Libraries/LibJS/Bytecode/Pass/LoadElimination.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2022, Leon Albrecht . - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -namespace JS::Bytecode::Passes { - -static NonnullOwnPtr eliminate_loads(BasicBlock const& block, size_t number_of_registers) -{ - auto array_ranges = Bitmap::create(number_of_registers, false).release_value_but_fixme_should_propagate_errors(); - - for (auto it = InstructionStreamIterator(block.instruction_stream()); !it.at_end(); ++it) { - if ((*it).type() == Instruction::Type::NewArray) { - Op::NewArray const& array_instruction = static_cast(*it); - if (size_t element_count = array_instruction.element_count()) - array_ranges.set_range(array_instruction.start().index(), element_count); - } else if ((*it).type() == Instruction::Type::Call) { - auto const& call_instruction = static_cast(*it); - if (size_t element_count = call_instruction.argument_count()) - array_ranges.set_range(call_instruction.first_argument().index(), element_count); - } - } - - auto new_block = BasicBlock::create(block.name(), block.size()); - HashMap identifier_table {}; - HashMap register_rerouting_table {}; - - for (auto it = InstructionStreamIterator(block.instruction_stream()); !it.at_end();) { - using enum Instruction::Type; - - // Note: When creating a variable, we technically purge the cache of any - // variables of the same name; - // In practice, we always generate a coinciding SetVariable, which - // does the same - switch ((*it).type()) { - case GetVariable: { - auto const& get_variable = static_cast(*it); - ++it; - auto const& next_instruction = *it; - - if (auto reg = identifier_table.find(get_variable.identifier().value()); reg != identifier_table.end()) { - // If we have already seen a variable, we can replace its GetVariable with a simple Load - // knowing that it was already stored in a register - new (new_block->next_slot()) Op::Load(reg->value); - new_block->grow(sizeof(Op::Load)); - - if (next_instruction.type() == Instruction::Type::Store) { - // If the next instruction is a Store, that is not meant to - // construct an array, we can simply elide that store and reroute - // all further references to the stores destination to the cached - // instance of variable. - // FIXME: We might be able to elide the previous load in the non-array case, - // because we do not yet reuse the accumulator - auto const& store = static_cast(next_instruction); - - if (array_ranges.get(store.dst().index())) { - // re-emit the store - new (new_block->next_slot()) Op::Store(store); - new_block->grow(sizeof(Op::Store)); - } else { - register_rerouting_table.set(store.dst().index(), reg->value); - } - - ++it; - } - - continue; - } - // Otherwise we need to emit the GetVariable - new (new_block->next_slot()) Op::GetVariable(get_variable); - new_block->grow(sizeof(Op::GetVariable)); - - // And if the next instruction is a Store, we can cache it's destination - if (next_instruction.type() == Instruction::Type::Store) { - auto const& store = static_cast(next_instruction); - identifier_table.set(get_variable.identifier().value(), store.dst()); - - new (new_block->next_slot()) Op::Store(store); - new_block->grow(sizeof(Op::Store)); - ++it; - } - - continue; - } - case SetVariable: { - // When a variable is set we need to remove it from the cache, because - // we don't have an accurate view on it anymore - // FIXME: If the previous instruction was a `Load $reg`, we could - // update the cache instead - auto const& set_variable = static_cast(*it); - - identifier_table.remove(set_variable.identifier().value()); - - break; - } - case DeleteVariable: { - // When a variable is deleted we need to remove it from the cache, it does not - // exist anymore, although a variable of the same name may exist in upper scopes - auto const& set_variable = static_cast(*it); - - identifier_table.remove(set_variable.identifier().value()); - - break; - } - case Store: { - // If we store to a position that we have are rerouting from, - // we need to remove it from the routeing table - // FIXME: This may be redundant due to us assigning to registers only once - auto const& store = static_cast(*it); - register_rerouting_table.remove(store.dst().index()); - - break; - } - case DeleteById: - case DeleteByIdWithThis: - case DeleteByValue: - case DeleteByValueWithThis: - // These can trigger proxies, which call into user code - // So these are treated like calls - case GetByValue: - case GetByValueWithThis: - case GetById: - case GetByIdWithThis: - case PutByValue: - case PutByValueWithThis: - case PutById: - case PutByIdWithThis: - // Attribute accesses (`a.o` or `a[o]`) may result in calls to getters or setters - // or may trigger proxies - // So these are treated like calls - case Call: - case CallWithArgumentArray: - // Calls, especially to local functions and eval, may poison visible and - // cached variables, hence we need to clear the lookup cache after emitting them - // FIXME: In strict mode and with better identifier metrics, we might be able - // to safe some caching with a more fine-grained identifier table - // FIXME: We might be able to save some lookups to objects like `this` - // which should not change their pointer - memcpy(new_block->next_slot(), &*it, (*it).length()); - for (auto route : register_rerouting_table) - reinterpret_cast(new_block->next_slot())->replace_references(Register { route.key }, route.value); - new_block->grow((*it).length()); - - identifier_table.clear_with_capacity(); - - ++it; - continue; - case NewBigInt: - // FIXME: This is the only non trivially copyable Instruction, - // so we need to do some extra work here - new (new_block->next_slot()) Op::NewBigInt(static_cast(*it)); - new_block->grow(sizeof(Op::NewBigInt)); - ++it; - continue; - default: - break; - } - - memcpy(new_block->next_slot(), &*it, (*it).length()); - for (auto route : register_rerouting_table) { - // rerouting from key to value - reinterpret_cast(new_block->next_slot())->replace_references(Register { route.key }, route.value); - } - // because we are replacing the current block, we need to replace references - // to ourselves here - reinterpret_cast(new_block->next_slot())->replace_references(block, *new_block); - - new_block->grow((*it).length()); - - ++it; - } - return new_block; -} - -void EliminateLoads::perform(PassPipelineExecutable& executable) -{ - started(); - - // FIXME: If we walk the CFG instead of the block list, we might be able to - // save some work between blocks - for (auto it = executable.executable.basic_blocks.begin(); it != executable.executable.basic_blocks.end(); ++it) { - auto const& old_block = *it; - auto new_block = eliminate_loads(*old_block, executable.executable.number_of_registers); - - // We will replace the old block, with a new one, so we need to replace all references, - // to the old one with the new one - for (auto& block : executable.executable.basic_blocks) { - InstructionStreamIterator it { block->instruction_stream() }; - while (!it.at_end()) { - auto& instruction = *it; - ++it; - const_cast(instruction).replace_references(*old_block, *new_block); - } - } - - executable.executable.basic_blocks[it.index()] = move(new_block); - } - - finished(); -} - -} diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/MergeBlocks.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/MergeBlocks.cpp deleted file mode 100644 index adda0527511..00000000000 --- a/Userland/Libraries/LibJS/Bytecode/Pass/MergeBlocks.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2021, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace JS::Bytecode::Passes { - -void MergeBlocks::perform(PassPipelineExecutable& executable) -{ - started(); - - VERIFY(executable.cfg.has_value()); - VERIFY(executable.inverted_cfg.has_value()); - auto cfg = executable.cfg.release_value(); - auto inverted_cfg = executable.inverted_cfg.release_value(); - - // Figure out which blocks can be merged - HashTable blocks_to_merge; - HashMap blocks_to_replace; - Vector blocks_to_remove; - Vector boundaries; - - for (auto& entry : cfg) { - if (entry.value.size() != 1) - continue; - - if (executable.exported_blocks->contains(*entry.value.begin())) - continue; - - if (!entry.key->is_terminated()) - continue; - - if (entry.key->terminator()->type() != Instruction::Type::Jump) - continue; - - { - InstructionStreamIterator it { entry.key->instruction_stream() }; - auto& first_instruction = *it; - if (first_instruction.type() == Instruction::Type::Jump) { - auto const* replacing_block = &static_cast(first_instruction).true_target()->block(); - if (replacing_block != entry.key) { - blocks_to_replace.set(entry.key, replacing_block); - } - continue; - } - } - - if (auto cfg_iter = inverted_cfg.find(*entry.value.begin()); cfg_iter != inverted_cfg.end()) { - auto& predecessor_entry = cfg_iter->value; - if (predecessor_entry.size() != 1) - continue; - } - - // The two blocks are safe to merge. - blocks_to_merge.set(entry.key); - } - - for (auto& entry : blocks_to_replace) { - auto const* replacement = entry.value; - for (;;) { - auto lookup = blocks_to_replace.get(replacement); - if (!lookup.has_value()) - break; - if (replacement == *lookup) - break; - replacement = *lookup; - } - entry.value = replacement; - } - - auto replace_blocks = [&](auto& blocks, auto& replacement) { - Optional first_successor_position; - for (auto& entry : blocks) { - blocks_to_remove.append(entry); - auto it = executable.executable.basic_blocks.find_if([entry](auto& block) { return entry == block; }); - VERIFY(!it.is_end()); - if (!first_successor_position.has_value()) - first_successor_position = it.index(); - } - for (auto& block : executable.executable.basic_blocks) { - InstructionStreamIterator it { block->instruction_stream() }; - while (!it.at_end()) { - auto& instruction = *it; - ++it; - for (auto& entry : blocks) - const_cast(instruction).replace_references(*entry, replacement); - } - } - return first_successor_position; - }; - - for (auto& entry : blocks_to_replace) { - AK::Array candidates { entry.key }; - (void)replace_blocks(candidates, *entry.value); - } - - while (!blocks_to_merge.is_empty()) { - auto it = blocks_to_merge.begin(); - auto const* current_block = *it; - blocks_to_merge.remove(it); - - Vector successors { current_block }; - for (;;) { - auto const* last = successors.last(); - auto entry = cfg.find(last); - if (entry == cfg.end()) - break; - auto const* successor = *entry->value.begin(); - successors.append(successor); - - if (!blocks_to_merge.remove(successor)) - break; - } - - auto blocks_to_merge_copy = blocks_to_merge; - // We need to do the following multiple times, due to it not being - // guaranteed, that the blocks are in sequential order - bool did_prepend = true; - while (did_prepend) { - did_prepend = false; - for (auto const* last : blocks_to_merge) { - auto entry = cfg.find(last); - if (entry == cfg.end()) - continue; - auto const* successor = *entry->value.begin(); - if (successor == successors.first()) { - successors.prepend(last); - blocks_to_merge_copy.remove(last); - did_prepend = true; - } - } - } - - blocks_to_merge = move(blocks_to_merge_copy); - - size_t size = 0; - StringBuilder builder; - builder.append("merge"sv); - for (auto& entry : successors) { - size += entry->size(); - builder.append('.'); - builder.append(entry->name()); - } - - auto new_block = BasicBlock::create(builder.to_deprecated_string(), size); - auto& block = *new_block; - auto first_successor_position = replace_blocks(successors, *new_block); - VERIFY(first_successor_position.has_value()); - - size_t last_successor_index = successors.size() - 1; - for (size_t i = 0; i < successors.size(); ++i) { - auto& entry = successors[i]; - InstructionStreamIterator it { entry->instruction_stream() }; - while (!it.at_end()) { - auto& instruction = *it; - ++it; - if (instruction.is_terminator() && last_successor_index != i) - break; - // FIXME: Op::NewBigInt is not trivially copyable, so we cant use - // a simple memcpy to transfer them. - // When this is resolved we can use a single memcpy to copy - // the whole block at once - if (instruction.type() == Instruction::Type::NewBigInt) { - new (block.next_slot()) Op::NewBigInt(static_cast(instruction)); - block.grow(sizeof(Op::NewBigInt)); - } else { - auto instruction_size = instruction.length(); - memcpy(block.next_slot(), &instruction, instruction_size); - block.grow(instruction_size); - } - } - } - - executable.executable.basic_blocks.insert(*first_successor_position, move(new_block)); - } - - executable.executable.basic_blocks.remove_all_matching([&blocks_to_remove](auto& candidate) { return blocks_to_remove.contains_slow(candidate.ptr()); }); - - finished(); -} - -} diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp deleted file mode 100644 index 195c46e125f..00000000000 --- a/Userland/Libraries/LibJS/Bytecode/Pass/PlaceBlocks.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2021, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include - -namespace JS::Bytecode::Passes { - -void PlaceBlocks::perform(PassPipelineExecutable& executable) -{ - started(); - - VERIFY(executable.cfg.has_value()); - auto cfg = executable.cfg.release_value(); - - Vector replaced_blocks; - HashTable reachable_blocks; - - // Visit the blocks in CFG order - Function visit = [&](auto* block) { - if (reachable_blocks.contains(block)) - return; - - reachable_blocks.set(block); - replaced_blocks.append(*const_cast(block)); - - auto children = cfg.find(block); - if (children == cfg.end()) - return; - - for (auto& entry : children->value) - visit(entry); - }; - - // Make sure to visit the entry block first - visit(executable.executable.basic_blocks.first()); - - for (auto& entry : cfg) - visit(entry.key); - - // Put the unreferenced blocks back in at the end - for (auto& entry : static_cast>&>(executable.executable.basic_blocks)) { - if (reachable_blocks.contains(entry.ptr())) - (void)entry.leak_ptr(); - else - replaced_blocks.append(*entry.leak_ptr()); // Don't try to do DCE here. - } - - executable.executable.basic_blocks.clear(); - for (auto& block : replaced_blocks) - executable.executable.basic_blocks.append(adopt_own(block)); - - finished(); -} - -} diff --git a/Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp b/Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp deleted file mode 100644 index bf3841153f3..00000000000 --- a/Userland/Libraries/LibJS/Bytecode/Pass/UnifySameBlocks.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2021, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace JS::Bytecode::Passes { - -void UnifySameBlocks::perform(PassPipelineExecutable& executable) -{ - started(); - - VERIFY(executable.cfg.has_value()); - VERIFY(executable.inverted_cfg.has_value()); - auto cfg = executable.cfg.release_value(); - auto inverted_cfg = executable.inverted_cfg.release_value(); - - HashMap equal_blocks; - - for (size_t i = 0; i < executable.executable.basic_blocks.size(); ++i) { - auto& block = executable.executable.basic_blocks[i]; - auto block_bytes = block->instruction_stream(); - for (auto& candidate_block : executable.executable.basic_blocks.span().slice(i + 1)) { - if (equal_blocks.contains(&*candidate_block)) - continue; - // FIXME: This can probably be relaxed a bit... - if (candidate_block->size() != block->size()) - continue; - - auto candidate_bytes = candidate_block->instruction_stream(); - // FIXME: NewBigInt's value is not correctly reflected by its encoding in memory, - // this will yield false negatives for blocks containing that - if (memcmp(candidate_bytes.data(), block_bytes.data(), candidate_block->size()) == 0) - equal_blocks.set(candidate_block.ptr(), block); - } - } - - auto replace_blocks = [&](auto& match, auto& replacement) { - Optional first_successor_position; - auto it = executable.executable.basic_blocks.find_if([match](auto& block) { return match == block; }); - VERIFY(!it.is_end()); - executable.executable.basic_blocks.remove(it.index()); - if (!first_successor_position.has_value()) - first_successor_position = it.index(); - - for (auto& block : executable.executable.basic_blocks) { - InstructionStreamIterator it { block->instruction_stream() }; - while (!it.at_end()) { - auto& instruction = *it; - ++it; - const_cast(instruction).replace_references(*match, replacement); - } - } - return first_successor_position; - }; - - for (auto& entry : equal_blocks) - (void)replace_blocks(entry.key, *entry.value); - - finished(); -} - -} diff --git a/Userland/Libraries/LibJS/Bytecode/PassManager.h b/Userland/Libraries/LibJS/Bytecode/PassManager.h deleted file mode 100644 index 6f87ec91afd..00000000000 --- a/Userland/Libraries/LibJS/Bytecode/PassManager.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2021, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace JS::Bytecode { - -struct PassPipelineExecutable { - Executable& executable; - Optional>> cfg {}; - Optional>> inverted_cfg {}; - Optional> exported_blocks {}; -}; - -class Pass { -public: - Pass() = default; - virtual ~Pass() = default; - - virtual void perform(PassPipelineExecutable&) = 0; - void started() - { - m_timer.start(); - } - void finished() - { - m_time_difference = m_timer.elapsed_time(); - } - - u64 elapsed() const { return m_time_difference.to_microseconds(); } - -protected: - Core::ElapsedTimer m_timer; - Duration m_time_difference {}; -}; - -class PassManager : public Pass { -public: - PassManager() = default; - ~PassManager() override = default; - - void add(NonnullOwnPtr pass) { m_passes.append(move(pass)); } - - template - void add(Args&&... args) { m_passes.append(make(forward(args)...)); } - - void perform(Executable& executable) - { - PassPipelineExecutable pipeline_executable { executable }; - perform(pipeline_executable); - } - - virtual void perform(PassPipelineExecutable& executable) override - { - started(); - for (auto& pass : m_passes) - pass->perform(executable); - finished(); - } - -private: - Vector> m_passes; -}; - -namespace Passes { - -class GenerateCFG : public Pass { -public: - GenerateCFG() = default; - ~GenerateCFG() override = default; - -private: - virtual void perform(PassPipelineExecutable&) override; -}; - -class MergeBlocks : public Pass { -public: - MergeBlocks() = default; - ~MergeBlocks() override = default; - -private: - virtual void perform(PassPipelineExecutable&) override; -}; - -class PlaceBlocks : public Pass { -public: - PlaceBlocks() = default; - ~PlaceBlocks() override = default; - -private: - virtual void perform(PassPipelineExecutable&) override; -}; - -class UnifySameBlocks : public Pass { -public: - UnifySameBlocks() = default; - ~UnifySameBlocks() override = default; - -private: - virtual void perform(PassPipelineExecutable&) override; -}; - -class DumpCFG : public Pass { -public: - DumpCFG(FILE* file) - : m_file(file) - { - } - - ~DumpCFG() override = default; - -private: - virtual void perform(PassPipelineExecutable&) override; - - FILE* m_file { nullptr }; -}; - -class EliminateLoads : public Pass { -public: - EliminateLoads() = default; - virtual ~EliminateLoads() override = default; - -private: - virtual void perform(PassPipelineExecutable&) override; -}; - -} - -} diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index 3e0d8e5f5fa..2d5f828fd66 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -9,12 +9,6 @@ set(SOURCES Bytecode/Instruction.cpp Bytecode/Interpreter.cpp Bytecode/Op.cpp - Bytecode/Pass/DumpCFG.cpp - Bytecode/Pass/GenerateCFG.cpp - Bytecode/Pass/LoadElimination.cpp - Bytecode/Pass/MergeBlocks.cpp - Bytecode/Pass/PlaceBlocks.cpp - Bytecode/Pass/UnifySameBlocks.cpp Bytecode/RegexTable.cpp Bytecode/StringTable.cpp Console.cpp diff --git a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp index 0e071fa9b51..5dff73d7b5c 100644 --- a/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp +++ b/Userland/Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/Userland/Utilities/js.cpp b/Userland/Utilities/js.cpp index ecf0bb89173..e51a1199e0b 100644 --- a/Userland/Utilities/js.cpp +++ b/Userland/Utilities/js.cpp @@ -576,14 +576,12 @@ ErrorOr serenity_main(Main::Arguments arguments) StringView evaluate_script; Vector script_paths; bool use_bytecode = false; - bool optimize_bytecode = false; Core::ArgsParser args_parser; args_parser.set_general_help("This is a JavaScript interpreter."); args_parser.add_option(s_dump_ast, "Dump the AST", "dump-ast", 'A'); args_parser.add_option(JS::Bytecode::g_dump_bytecode, "Dump the bytecode", "dump-bytecode", 'd'); args_parser.add_option(use_bytecode, "Run the bytecode", "run-bytecode", 'b'); - args_parser.add_option(optimize_bytecode, "Optimize the bytecode", "optimize-bytecode", 'p'); args_parser.add_option(s_as_module, "Treat as module", "as-module", 'm'); args_parser.add_option(s_print_last_result, "Print last result", "print-last-result", 'l'); args_parser.add_option(s_strip_ansi, "Disable ANSI colors", "disable-ansi-colors", 'i'); @@ -597,7 +595,6 @@ ErrorOr serenity_main(Main::Arguments arguments) args_parser.parse(arguments); JS::Bytecode::Interpreter::set_enabled(use_bytecode); - JS::Bytecode::Interpreter::set_optimizations_enabled(optimize_bytecode); bool syntax_highlight = !disable_syntax_highlight;