diff --git a/Meta/Lagom/CMakeLists.txt b/Meta/Lagom/CMakeLists.txt index 730d2bb549..1a350fdcbd 100644 --- a/Meta/Lagom/CMakeLists.txt +++ b/Meta/Lagom/CMakeLists.txt @@ -69,6 +69,7 @@ file(GLOB LIBMARKDOWN_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibMar file(GLOB LIBX86_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibX86/*.cpp") file(GLOB LIBJS_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibJS/*.cpp") file(GLOB LIBJS_SUBDIR_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibJS/*/*.cpp") +file(GLOB LIBJS_SUBSUBDIR_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibJS/*/*/*.cpp") file(GLOB LIBCOMPRESS_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibCompress/*.cpp") file(GLOB LIBCOMPRESS_TESTS CONFIGURE_DEPENDS "../../Tests/LibCompress/*.cpp") file(GLOB LIBCRYPTO_SOURCES CONFIGURE_DEPENDS "../../Userland/Libraries/LibCrypto/*.cpp") @@ -92,7 +93,7 @@ file(GLOB LIBTEST_MAIN CONFIGURE_DEPENDS "../../Userland/Libraries/LibTest/TestM set(LAGOM_REGEX_SOURCES ${LIBREGEX_LIBC_SOURCES} ${LIBREGEX_SOURCES}) set(LAGOM_CORE_SOURCES ${AK_SOURCES} ${LIBCORE_SOURCES}) -set(LAGOM_MORE_SOURCES ${LIBARCHIVE_SOURCES} ${LIBAUDIO_SOURCES} ${LIBELF_SOURCES} ${LIBIPC_SOURCES} ${LIBLINE_SOURCES} ${LIBJS_SOURCES} ${LIBJS_SUBDIR_SOURCES} ${LIBX86_SOURCES} ${LIBCRYPTO_SOURCES} ${LIBCOMPRESS_SOURCES} ${LIBCRYPTO_SUBDIR_SOURCES} ${LIBCRYPTO_SUBSUBDIR_SOURCES} ${LIBTLS_SOURCES} ${LIBTTF_SOURCES} ${LIBTEXTCODEC_SOURCES} ${LIBMARKDOWN_SOURCES} ${LIBGEMINI_SOURCES} ${LIBGFX_SOURCES} ${LIBGUI_GML_SOURCES} ${LIBHTTP_SOURCES} ${LAGOM_REGEX_SOURCES} ${SHELL_SOURCES} ${LIBSQL_SOURCES} ${LIBWASM_SOURCES} ${LIBIMAP_SOURCES}) +set(LAGOM_MORE_SOURCES ${LIBARCHIVE_SOURCES} ${LIBAUDIO_SOURCES} ${LIBELF_SOURCES} ${LIBIPC_SOURCES} ${LIBLINE_SOURCES} ${LIBJS_SOURCES} ${LIBJS_SUBDIR_SOURCES} ${LIBJS_SUBSUBDIR_SOURCES} ${LIBX86_SOURCES} ${LIBCRYPTO_SOURCES} ${LIBCOMPRESS_SOURCES} ${LIBCRYPTO_SUBDIR_SOURCES} ${LIBCRYPTO_SUBSUBDIR_SOURCES} ${LIBTLS_SOURCES} ${LIBTTF_SOURCES} ${LIBTEXTCODEC_SOURCES} ${LIBMARKDOWN_SOURCES} ${LIBGEMINI_SOURCES} ${LIBGFX_SOURCES} ${LIBGUI_GML_SOURCES} ${LIBHTTP_SOURCES} ${LAGOM_REGEX_SOURCES} ${SHELL_SOURCES} ${LIBSQL_SOURCES} ${LIBWASM_SOURCES} ${LIBIMAP_SOURCES}) set(LAGOM_TEST_SOURCES ${LIBTEST_SOURCES}) # FIXME: This is a hack, because the lagom stuff can be build individually or diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp b/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp index 0182d4412f..8bac7aa06a 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp @@ -66,6 +66,7 @@ void BasicBlock::grow(size_t additional_size) void InstructionStreamIterator::operator++() { + VERIFY(!at_end()); m_offset += dereference().length(); } diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index 11c9b6b745..ac0e8de028 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -80,10 +80,12 @@ public: #undef __BYTECODE_OP }; + bool is_terminator() const; Type type() const { return m_type; } size_t length() const; String to_string(Bytecode::Executable const&) const; void execute(Bytecode::Interpreter&) const; + void replace_references(BasicBlock const&, BasicBlock const&); static void destroy(Instruction&); protected: diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index eb63d3f895..4d4441cd7d 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -165,4 +165,38 @@ void Interpreter::continue_pending_unwind(Label const& resume_label) jump(resume_label); } } + +AK::Array, static_cast>(Interpreter::OptimizationLevel::__Count)> Interpreter::s_optimization_pipelines {}; + +Bytecode::PassManager& Interpreter::optimization_pipeline(Interpreter::OptimizationLevel level) +{ + auto underlying_level = to_underlying(level); + VERIFY(underlying_level <= to_underlying(Interpreter::OptimizationLevel::__Count)); + auto& entry = s_optimization_pipelines[underlying_level]; + + if (entry) + return *entry; + + auto pm = make(); + if (level == OptimizationLevel::Default) { + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + pm->add(); + } else { + VERIFY_NOT_REACHED(); + } + + auto& passes = *pm; + entry = move(pm); + + return passes; +} + } diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index 26b2dc9078..0dda59a99b 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -7,6 +7,7 @@ #pragma once #include "Generator.h" +#include "PassManager.h" #include #include #include @@ -60,9 +61,17 @@ public: Executable const& current_executable() { return *m_current_executable; } + enum class OptimizationLevel { + Default, + __Count, + }; + static Bytecode::PassManager& optimization_pipeline(OptimizationLevel = OptimizationLevel::Default); + private: RegisterWindow& registers() { return m_register_windows.last(); } + static AK::Array, static_cast>(Interpreter::OptimizationLevel::__Count)> s_optimization_pipelines; + VM& m_vm; GlobalObject& m_global_object; NonnullOwnPtrVector m_register_windows; diff --git a/Userland/Libraries/LibJS/Bytecode/Label.h b/Userland/Libraries/LibJS/Bytecode/Label.h index 8174463f6e..b1634b1d0d 100644 --- a/Userland/Libraries/LibJS/Bytecode/Label.h +++ b/Userland/Libraries/LibJS/Bytecode/Label.h @@ -14,14 +14,14 @@ namespace JS::Bytecode { class Label { public: explicit Label(BasicBlock const& block) - : m_block(block) + : m_block(&block) { } - auto& block() const { return m_block; } + auto& block() const { return *m_block; } private: - BasicBlock const& m_block; + BasicBlock const* m_block { nullptr }; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 676267e4d2..69744b6c22 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -165,6 +165,14 @@ void Jump::execute_impl(Bytecode::Interpreter& interpreter) const interpreter.jump(*m_true_target); } +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 }; +} + void JumpConditional::execute_impl(Bytecode::Interpreter& interpreter) const { VERIFY(m_true_target.has_value()); @@ -261,6 +269,16 @@ void EnterUnwindContext::execute_impl(Bytecode::Interpreter& interpreter) const interpreter.jump(m_entry_point); } +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 LeaveUnwindContext::execute_impl(Bytecode::Interpreter& interpreter) const { interpreter.leave_unwind_context(); @@ -271,6 +289,12 @@ void ContinuePendingUnwind::execute_impl(Bytecode::Interpreter& interpreter) con 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 }; +} + void PushLexicalEnvironment::execute_impl(Bytecode::Interpreter& interpreter) const { HashMap resolved_variables; @@ -292,6 +316,12 @@ void Yield::execute_impl(Bytecode::Interpreter& interpreter) const interpreter.do_return(object); } +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 }; +} + void GetByValue::execute_impl(Bytecode::Interpreter& interpreter) const { if (auto* object = interpreter.reg(m_base).to_object(interpreter.global_object())) { diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 0ca7ad91ab..653b9d1889 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -29,6 +29,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Register m_src; @@ -44,6 +45,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Value m_value; @@ -59,6 +61,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Register m_dst; @@ -88,20 +91,21 @@ private: O(RightShift, right_shift) \ O(UnsignedRightShift, unsigned_right_shift) -#define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \ - class OpTitleCase final : public Instruction { \ - public: \ - explicit OpTitleCase(Register lhs_reg) \ - : Instruction(Type::OpTitleCase) \ - , m_lhs_reg(lhs_reg) \ - { \ - } \ - \ - void execute_impl(Bytecode::Interpreter&) const; \ - String to_string_impl(Bytecode::Executable const&) const; \ - \ - private: \ - Register m_lhs_reg; \ +#define JS_DECLARE_COMMON_BINARY_OP(OpTitleCase, op_snake_case) \ + class OpTitleCase final : public Instruction { \ + public: \ + explicit OpTitleCase(Register lhs_reg) \ + : Instruction(Type::OpTitleCase) \ + , m_lhs_reg(lhs_reg) \ + { \ + } \ + \ + void execute_impl(Bytecode::Interpreter&) const; \ + String to_string_impl(Bytecode::Executable const&) const; \ + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } \ + \ + private: \ + Register m_lhs_reg; \ }; JS_ENUMERATE_COMMON_BINARY_OPS(JS_DECLARE_COMMON_BINARY_OP) @@ -114,16 +118,17 @@ JS_ENUMERATE_COMMON_BINARY_OPS(JS_DECLARE_COMMON_BINARY_OP) O(UnaryMinus, unary_minus) \ O(Typeof, typeof_) -#define JS_DECLARE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \ - class OpTitleCase final : public Instruction { \ - public: \ - OpTitleCase() \ - : Instruction(Type::OpTitleCase) \ - { \ - } \ - \ - void execute_impl(Bytecode::Interpreter&) const; \ - String to_string_impl(Bytecode::Executable const&) const; \ +#define JS_DECLARE_COMMON_UNARY_OP(OpTitleCase, op_snake_case) \ + class OpTitleCase final : public Instruction { \ + public: \ + OpTitleCase() \ + : Instruction(Type::OpTitleCase) \ + { \ + } \ + \ + void execute_impl(Bytecode::Interpreter&) const; \ + String to_string_impl(Bytecode::Executable const&) const; \ + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } \ }; JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP) @@ -139,6 +144,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: StringTableIndex m_string; @@ -153,6 +159,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } }; class NewBigInt final : public Instruction { @@ -165,6 +172,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Crypto::SignedBigInteger m_bigint; @@ -183,8 +191,12 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } - size_t length_impl() const { return sizeof(*this) + sizeof(Register) * m_element_count; } + size_t length_impl() const + { + return sizeof(*this) + sizeof(Register) * m_element_count; + } private: size_t m_element_count { 0 }; @@ -201,6 +213,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Register m_lhs; @@ -216,6 +229,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: StringTableIndex m_identifier; @@ -231,6 +245,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: StringTableIndex m_identifier; @@ -246,6 +261,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: StringTableIndex m_property; @@ -262,6 +278,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Register m_base; @@ -278,6 +295,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Register m_base; @@ -294,6 +312,7 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&) { } private: Register m_base; @@ -326,6 +345,10 @@ public: void execute_impl(Bytecode::Interpreter&) const; String to_string_impl(Bytecode::Executable const&) const; + void replace_references_impl(BasicBlock const&, BasicBlock const&); + + auto& true_target() const { return m_true_target; } + auto& false_target() const { return m_false_target; } protected: Optional