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;