diff options
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp | 18 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/BasicBlock.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.cpp | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Generator.h | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Instruction.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Interpreter.cpp | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Interpreter.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Op.cpp | 68 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/Op.h | 66 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/StringTable.cpp | 33 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Bytecode/StringTable.h | 33 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Forward.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp | 2 | ||||
-rw-r--r-- | Userland/Utilities/js.cpp | 6 |
16 files changed, 173 insertions, 82 deletions
diff --git a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp index a772ed82b2..866a143136 100644 --- a/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp +++ b/Userland/Libraries/LibJS/Bytecode/ASTCodegen.cpp @@ -208,12 +208,12 @@ void BigIntLiteral::generate_bytecode(Bytecode::Generator& generator) const void StringLiteral::generate_bytecode(Bytecode::Generator& generator) const { - generator.emit<Bytecode::Op::NewString>(m_value); + generator.emit<Bytecode::Op::NewString>(generator.intern_string(m_value)); } void Identifier::generate_bytecode(Bytecode::Generator& generator) const { - generator.emit<Bytecode::Op::GetVariable>(m_string); + generator.emit<Bytecode::Op::GetVariable>(generator.intern_string(m_string)); } void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) const @@ -223,7 +223,7 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con if (m_op == AssignmentOp::Assignment) { m_rhs->generate_bytecode(generator); - generator.emit<Bytecode::Op::SetVariable>(identifier.string()); + generator.emit<Bytecode::Op::SetVariable>(generator.intern_string(identifier.string())); return; } @@ -273,7 +273,7 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con TODO(); } - generator.emit<Bytecode::Op::SetVariable>(identifier.string()); + generator.emit<Bytecode::Op::SetVariable>(generator.intern_string(identifier.string())); return; } @@ -289,7 +289,8 @@ void AssignmentExpression::generate_bytecode(Bytecode::Generator& generator) con } else { VERIFY(is<Identifier>(expression.property())); m_rhs->generate_bytecode(generator); - generator.emit<Bytecode::Op::PutById>(object_reg, static_cast<Identifier const&>(expression.property()).string()); + auto identifier_table_ref = generator.intern_string(static_cast<Identifier const&>(expression.property()).string()); + generator.emit<Bytecode::Op::PutById>(object_reg, identifier_table_ref); return; } } @@ -487,7 +488,8 @@ void MemberExpression::generate_bytecode(Bytecode::Generator& generator) const TODO(); } else { VERIFY(is<Identifier>(property())); - generator.emit<Bytecode::Op::GetById>(static_cast<Identifier const&>(property()).string()); + auto identifier_table_ref = generator.intern_string(static_cast<Identifier const&>(property()).string()); + generator.emit<Bytecode::Op::GetById>(identifier_table_ref); } } @@ -643,7 +645,7 @@ void UpdateExpression::generate_bytecode(Bytecode::Generator& generator) const { if (is<Identifier>(*m_argument)) { auto& identifier = static_cast<Identifier const&>(*m_argument); - generator.emit<Bytecode::Op::GetVariable>(identifier.string()); + generator.emit<Bytecode::Op::GetVariable>(generator.intern_string(identifier.string())); Optional<Bytecode::Register> previous_value_for_postfix_reg; if (!m_prefixed) { @@ -656,7 +658,7 @@ void UpdateExpression::generate_bytecode(Bytecode::Generator& generator) const else generator.emit<Bytecode::Op::Decrement>(); - generator.emit<Bytecode::Op::SetVariable>(identifier.string()); + generator.emit<Bytecode::Op::SetVariable>(generator.intern_string(identifier.string())); if (!m_prefixed) generator.emit<Bytecode::Op::Load>(*previous_value_for_postfix_reg); diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp b/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp index 072f6aa78e..a0a15903ed 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.cpp @@ -47,13 +47,13 @@ void BasicBlock::seal() // It also doesn't work because instructions that have String members use RefPtr internally which must be in writable memory. } -void BasicBlock::dump() const +void BasicBlock::dump(Bytecode::Executable const& executable) const { Bytecode::InstructionStreamIterator it(instruction_stream()); if (!m_name.is_empty()) warnln("{}:", m_name); while (!it.at_end()) { - warnln("[{:4x}] {}", it.offset(), (*it).to_string()); + warnln("[{:4x}] {}", it.offset(), (*it).to_string(executable)); ++it; } } diff --git a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h index 0601b89a93..17f0e8f73b 100644 --- a/Userland/Libraries/LibJS/Bytecode/BasicBlock.h +++ b/Userland/Libraries/LibJS/Bytecode/BasicBlock.h @@ -45,7 +45,7 @@ public: void seal(); - void dump() const; + void dump(Executable const&) const; ReadonlyBytes instruction_stream() const { return ReadonlyBytes { m_buffer, m_buffer_size }; } void* next_slot() { return m_buffer + m_buffer_size; } diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.cpp b/Userland/Libraries/LibJS/Bytecode/Generator.cpp index c9141e682d..51dd218852 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Generator.cpp @@ -14,6 +14,7 @@ namespace JS::Bytecode { Generator::Generator() + : m_string_table(make<StringTable>()) { } @@ -26,7 +27,7 @@ Executable Generator::generate(ASTNode const& node) Generator generator; generator.switch_to_basic_block(generator.make_block()); node.generate_bytecode(generator); - return { move(generator.m_root_basic_blocks), generator.m_next_register }; + return { move(generator.m_root_basic_blocks), move(generator.m_string_table), generator.m_next_register }; } void Generator::grow(size_t additional_size) diff --git a/Userland/Libraries/LibJS/Bytecode/Generator.h b/Userland/Libraries/LibJS/Bytecode/Generator.h index f7e115353b..6cfe411a44 100644 --- a/Userland/Libraries/LibJS/Bytecode/Generator.h +++ b/Userland/Libraries/LibJS/Bytecode/Generator.h @@ -12,13 +12,17 @@ #include <LibJS/Bytecode/BasicBlock.h> #include <LibJS/Bytecode/Label.h> #include <LibJS/Bytecode/Register.h> +#include <LibJS/Bytecode/StringTable.h> #include <LibJS/Forward.h> namespace JS::Bytecode { struct Executable { NonnullOwnPtrVector<BasicBlock> basic_blocks; + NonnullOwnPtr<StringTable> string_table; size_t number_of_registers { 0 }; + + String const& get_string(StringTableIndex index) const { return string_table->get(index); } }; class Generator { @@ -74,6 +78,11 @@ public: return m_current_basic_block->is_terminated(); } + StringTableIndex intern_string(StringView const& string) + { + return m_string_table->insert(string); + } + private: Generator(); ~Generator(); @@ -83,6 +92,7 @@ private: BasicBlock* m_current_basic_block { nullptr }; NonnullOwnPtrVector<BasicBlock> m_root_basic_blocks; + NonnullOwnPtr<StringTable> m_string_table; u32 m_next_register { 1 }; u32 m_next_block { 1 }; diff --git a/Userland/Libraries/LibJS/Bytecode/Instruction.h b/Userland/Libraries/LibJS/Bytecode/Instruction.h index c4467437c0..9b67fa096c 100644 --- a/Userland/Libraries/LibJS/Bytecode/Instruction.h +++ b/Userland/Libraries/LibJS/Bytecode/Instruction.h @@ -73,7 +73,7 @@ public: Type type() const { return m_type; } size_t length() const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; void execute(Bytecode::Interpreter&) const; static void destroy(Instruction&); diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp index 42f0fae921..9bae427052 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.cpp @@ -5,6 +5,7 @@ */ #include <AK/Debug.h> +#include <AK/TemporaryChange.h> #include <LibJS/Bytecode/BasicBlock.h> #include <LibJS/Bytecode/Instruction.h> #include <LibJS/Bytecode/Interpreter.h> @@ -38,6 +39,8 @@ Value Interpreter::run(Executable const& executable) { dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter will run unit {:p}", &executable); + TemporaryChange restore_executable { m_current_executable, &executable }; + CallFrame global_call_frame; if (vm().call_stack().is_empty()) { global_call_frame.this_value = &global_object(); diff --git a/Userland/Libraries/LibJS/Bytecode/Interpreter.h b/Userland/Libraries/LibJS/Bytecode/Interpreter.h index 8e5c495967..d9e64ae9c4 100644 --- a/Userland/Libraries/LibJS/Bytecode/Interpreter.h +++ b/Userland/Libraries/LibJS/Bytecode/Interpreter.h @@ -39,6 +39,8 @@ public: } void do_return(Value return_value) { m_return_value = return_value; } + Executable const& current_executable() { return *m_current_executable; } + private: RegisterWindow& registers() { return m_register_windows.last(); } @@ -47,6 +49,7 @@ private: NonnullOwnPtrVector<RegisterWindow> m_register_windows; Optional<BasicBlock const*> m_pending_jump; Value m_return_value; + Executable const* m_current_executable { nullptr }; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.cpp b/Userland/Libraries/LibJS/Bytecode/Op.cpp index 87ee3c8690..cea771567f 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.cpp +++ b/Userland/Libraries/LibJS/Bytecode/Op.cpp @@ -16,11 +16,11 @@ namespace JS::Bytecode { -String Instruction::to_string() const +String Instruction::to_string(Bytecode::Executable const& executable) const { #define __BYTECODE_OP(op) \ case Instruction::Type::op: \ - return static_cast<Bytecode::Op::op const&>(*this).to_string(); + return static_cast<Bytecode::Op::op const&>(*this).to_string(executable); switch (type()) { ENUMERATE_BYTECODE_OPS(__BYTECODE_OP) @@ -77,7 +77,7 @@ static Value typed_equals(GlobalObject&, Value src1, Value src2) auto rhs = interpreter.accumulator(); \ interpreter.accumulator() = op_snake_case(interpreter.global_object(), lhs, rhs); \ } \ - String OpTitleCase::to_string() const \ + String OpTitleCase::to_string(Bytecode::Executable const&) const \ { \ return String::formatted(#OpTitleCase " {}", m_lhs_reg); \ } @@ -99,7 +99,7 @@ static Value typeof_(GlobalObject& global_object, Value value) { \ interpreter.accumulator() = op_snake_case(interpreter.global_object(), interpreter.accumulator()); \ } \ - String OpTitleCase::to_string() const \ + String OpTitleCase::to_string(Bytecode::Executable const&) const \ { \ return #OpTitleCase; \ } @@ -122,7 +122,7 @@ void NewArray::execute(Bytecode::Interpreter& interpreter) const void NewString::execute(Bytecode::Interpreter& interpreter) const { - interpreter.accumulator() = js_string(interpreter.vm(), m_string); + interpreter.accumulator() = js_string(interpreter.vm(), interpreter.current_executable().get_string(m_string)); } void NewObject::execute(Bytecode::Interpreter& interpreter) const @@ -137,24 +137,24 @@ void ConcatString::execute(Bytecode::Interpreter& interpreter) const void GetVariable::execute(Bytecode::Interpreter& interpreter) const { - interpreter.accumulator() = interpreter.vm().get_variable(m_identifier, interpreter.global_object()); + interpreter.accumulator() = interpreter.vm().get_variable(interpreter.current_executable().get_string(m_identifier), interpreter.global_object()); } void SetVariable::execute(Bytecode::Interpreter& interpreter) const { - interpreter.vm().set_variable(m_identifier, interpreter.accumulator(), interpreter.global_object()); + interpreter.vm().set_variable(interpreter.current_executable().get_string(m_identifier), interpreter.accumulator(), interpreter.global_object()); } void GetById::execute(Bytecode::Interpreter& interpreter) const { if (auto* object = interpreter.accumulator().to_object(interpreter.global_object())) - interpreter.accumulator() = object->get(m_property); + interpreter.accumulator() = object->get(interpreter.current_executable().get_string(m_property)); } void PutById::execute(Bytecode::Interpreter& interpreter) const { if (auto* object = interpreter.reg(m_base).to_object(interpreter.global_object())) - object->put(m_property, interpreter.accumulator()); + object->put(interpreter.current_executable().get_string(m_property), interpreter.accumulator()); } void Jump::execute(Bytecode::Interpreter& interpreter) const @@ -255,27 +255,27 @@ void Decrement::execute(Bytecode::Interpreter& interpreter) const interpreter.accumulator() = js_bigint(interpreter.vm().heap(), old_value.as_bigint().big_integer().minus(Crypto::SignedBigInteger { 1 })); } -String Load::to_string() const +String Load::to_string(Bytecode::Executable const&) const { return String::formatted("Load {}", m_src); } -String LoadImmediate::to_string() const +String LoadImmediate::to_string(Bytecode::Executable const&) const { return String::formatted("LoadImmediate {}", m_value); } -String Store::to_string() const +String Store::to_string(Bytecode::Executable const&) const { return String::formatted("Store {}", m_dst); } -String NewBigInt::to_string() const +String NewBigInt::to_string(Bytecode::Executable const&) const { return String::formatted("NewBigInt \"{}\"", m_bigint.to_base10()); } -String NewArray::to_string() const +String NewArray::to_string(Bytecode::Executable const&) const { StringBuilder builder; builder.append("NewArray"); @@ -291,63 +291,63 @@ String NewArray::to_string() const return builder.to_string(); } -String NewString::to_string() const +String NewString::to_string(Bytecode::Executable const& executable) const { - return String::formatted("NewString \"{}\"", m_string); + return String::formatted("NewString {} (\"{}\")", m_string, executable.string_table->get(m_string)); } -String NewObject::to_string() const +String NewObject::to_string(Bytecode::Executable const&) const { return "NewObject"; } -String ConcatString::to_string() const +String ConcatString::to_string(Bytecode::Executable const&) const { return String::formatted("ConcatString {}", m_lhs); } -String GetVariable::to_string() const +String GetVariable::to_string(Bytecode::Executable const& executable) const { - return String::formatted("GetVariable {}", m_identifier); + return String::formatted("GetVariable {} ({})", m_identifier, executable.string_table->get(m_identifier)); } -String SetVariable::to_string() const +String SetVariable::to_string(Bytecode::Executable const& executable) const { - return String::formatted("SetVariable {}", m_identifier); + return String::formatted("SetVariable {} ({})", m_identifier, executable.string_table->get(m_identifier)); } -String PutById::to_string() const +String PutById::to_string(Bytecode::Executable const& executable) const { - return String::formatted("PutById base:{}, property:{}", m_base, m_property); + return String::formatted("PutById base:{}, property:{} ({})", m_base, m_property, executable.string_table->get(m_property)); } -String GetById::to_string() const +String GetById::to_string(Bytecode::Executable const& executable) const { - return String::formatted("GetById {}", m_property); + return String::formatted("GetById {} ({})", m_property, executable.string_table->get(m_property)); } -String Jump::to_string() const +String Jump::to_string(Bytecode::Executable const&) const { if (m_true_target.has_value()) return String::formatted("Jump {}", *m_true_target); return String::formatted("Jump <empty>"); } -String JumpConditional::to_string() const +String JumpConditional::to_string(Bytecode::Executable const&) const { auto true_string = m_true_target.has_value() ? String::formatted("{}", *m_true_target) : "<empty>"; auto false_string = m_false_target.has_value() ? String::formatted("{}", *m_false_target) : "<empty>"; return String::formatted("JumpConditional true:{} false:{}", true_string, false_string); } -String JumpNullish::to_string() const +String JumpNullish::to_string(Bytecode::Executable const&) const { auto true_string = m_true_target.has_value() ? String::formatted("{}", *m_true_target) : "<empty>"; auto false_string = m_false_target.has_value() ? String::formatted("{}", *m_false_target) : "<empty>"; return String::formatted("JumpNullish null:{} nonnull:{}", true_string, false_string); } -String Call::to_string() const +String Call::to_string(Bytecode::Executable const&) const { StringBuilder builder; builder.appendff("Call callee:{}, this:{}", m_callee, m_this_value); @@ -363,22 +363,22 @@ String Call::to_string() const return builder.to_string(); } -String EnterScope::to_string() const +String EnterScope::to_string(Bytecode::Executable const&) const { return "EnterScope"; } -String Return::to_string() const +String Return::to_string(Bytecode::Executable const&) const { return "Return"; } -String Increment::to_string() const +String Increment::to_string(Bytecode::Executable const&) const { return "Increment"; } -String Decrement::to_string() const +String Decrement::to_string(Bytecode::Executable const&) const { return "Decrement"; } diff --git a/Userland/Libraries/LibJS/Bytecode/Op.h b/Userland/Libraries/LibJS/Bytecode/Op.h index 59ce5f30c1..7398724afc 100644 --- a/Userland/Libraries/LibJS/Bytecode/Op.h +++ b/Userland/Libraries/LibJS/Bytecode/Op.h @@ -7,11 +7,11 @@ #pragma once -#include <AK/FlyString.h> #include <LibCrypto/BigInt/SignedBigInteger.h> #include <LibJS/Bytecode/Instruction.h> #include <LibJS/Bytecode/Label.h> #include <LibJS/Bytecode/Register.h> +#include <LibJS/Bytecode/StringTable.h> #include <LibJS/Heap/Cell.h> #include <LibJS/Runtime/Value.h> @@ -26,7 +26,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: Register m_src; @@ -41,7 +41,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: Value m_value; @@ -56,7 +56,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: Register m_dst; @@ -96,7 +96,7 @@ private: } \ \ void execute(Bytecode::Interpreter&) const; \ - String to_string() const; \ + String to_string(Bytecode::Executable const&) const; \ \ private: \ Register m_lhs_reg; \ @@ -121,7 +121,7 @@ JS_ENUMERATE_COMMON_BINARY_OPS(JS_DECLARE_COMMON_BINARY_OP) } \ \ void execute(Bytecode::Interpreter&) const; \ - String to_string() const; \ + String to_string(Bytecode::Executable const&) const; \ }; JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP) @@ -129,17 +129,17 @@ JS_ENUMERATE_COMMON_UNARY_OPS(JS_DECLARE_COMMON_UNARY_OP) class NewString final : public Instruction { public: - NewString(String string) + NewString(StringTableIndex string) : Instruction(Type::NewString) , m_string(move(string)) { } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: - String m_string; + StringTableIndex m_string; }; class NewObject final : public Instruction { @@ -150,7 +150,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; }; class NewBigInt final : public Instruction { @@ -162,7 +162,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: Crypto::SignedBigInteger m_bigint; @@ -180,7 +180,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; size_t length() const { return sizeof(*this) + sizeof(Register) * m_element_count; } @@ -198,7 +198,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: Register m_lhs; @@ -206,52 +206,52 @@ private: class SetVariable final : public Instruction { public: - SetVariable(FlyString identifier) + SetVariable(StringTableIndex identifier) : Instruction(Type::SetVariable) , m_identifier(move(identifier)) { } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: - FlyString m_identifier; + StringTableIndex m_identifier; }; class GetVariable final : public Instruction { public: - GetVariable(FlyString identifier) + GetVariable(StringTableIndex identifier) : Instruction(Type::GetVariable) , m_identifier(move(identifier)) { } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: - FlyString m_identifier; + StringTableIndex m_identifier; }; class GetById final : public Instruction { public: - GetById(FlyString property) + GetById(StringTableIndex property) : Instruction(Type::GetById) , m_property(move(property)) { } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: - FlyString m_property; + StringTableIndex m_property; }; class PutById final : public Instruction { public: - PutById(Register base, FlyString property) + PutById(Register base, StringTableIndex property) : Instruction(Type::PutById) , m_base(base) , m_property(move(property)) @@ -259,11 +259,11 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: Register m_base; - FlyString m_property; + StringTableIndex m_property; }; class Jump : public Instruction { @@ -291,7 +291,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; protected: Optional<Label> m_true_target; @@ -306,7 +306,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; }; class JumpNullish final : public Jump { @@ -317,7 +317,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; }; // NOTE: This instruction is variable-width depending on the number of arguments! @@ -334,7 +334,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; size_t length() const { return sizeof(*this) + sizeof(Register) * m_argument_count; } @@ -354,7 +354,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; private: ScopeNode const& m_scope_node; @@ -370,7 +370,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; }; class Increment final : public Instruction { @@ -381,7 +381,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; }; class Decrement final : public Instruction { @@ -392,7 +392,7 @@ public: } void execute(Bytecode::Interpreter&) const; - String to_string() const; + String to_string(Bytecode::Executable const&) const; }; } diff --git a/Userland/Libraries/LibJS/Bytecode/StringTable.cpp b/Userland/Libraries/LibJS/Bytecode/StringTable.cpp new file mode 100644 index 0000000000..53a7e3ce76 --- /dev/null +++ b/Userland/Libraries/LibJS/Bytecode/StringTable.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibJS/Bytecode/StringTable.h> + +namespace JS::Bytecode { + +StringTableIndex StringTable::insert(StringView string) +{ + for (size_t i = 0; i < m_strings.size(); i++) { + if (m_strings[i] == string) + return i; + } + m_strings.append(string); + return m_strings.size() - 1; +} + +String const& StringTable::get(StringTableIndex index) const +{ + return m_strings[index.value()]; +} + +void StringTable::dump() const +{ + outln("String Table:"); + for (size_t i = 0; i < m_strings.size(); i++) + outln("{}: {}", i, m_strings[i]); +} + +} diff --git a/Userland/Libraries/LibJS/Bytecode/StringTable.h b/Userland/Libraries/LibJS/Bytecode/StringTable.h new file mode 100644 index 0000000000..1da174332c --- /dev/null +++ b/Userland/Libraries/LibJS/Bytecode/StringTable.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/DistinctNumeric.h> +#include <AK/String.h> +#include <AK/Vector.h> + +namespace JS::Bytecode { + +TYPEDEF_DISTINCT_NUMERIC_GENERAL(size_t, false, true, false, false, false, false, StringTableIndex); + +class StringTable { + AK_MAKE_NONMOVABLE(StringTable); + AK_MAKE_NONCOPYABLE(StringTable); + +public: + StringTable() = default; + + StringTableIndex insert(StringView string); + String const& get(StringTableIndex) const; + void dump() const; + bool is_empty() const { return m_strings.is_empty(); } + +private: + Vector<String> m_strings; +}; + +} diff --git a/Userland/Libraries/LibJS/CMakeLists.txt b/Userland/Libraries/LibJS/CMakeLists.txt index 1b81a75e9a..d28e72c016 100644 --- a/Userland/Libraries/LibJS/CMakeLists.txt +++ b/Userland/Libraries/LibJS/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES Bytecode/Instruction.cpp Bytecode/Interpreter.cpp Bytecode/Op.cpp + Bytecode/StringTable.cpp Console.cpp Heap/CellAllocator.cpp Heap/BlockAllocator.cpp diff --git a/Userland/Libraries/LibJS/Forward.h b/Userland/Libraries/LibJS/Forward.h index c6e1a96405..9e0a6058ce 100644 --- a/Userland/Libraries/LibJS/Forward.h +++ b/Userland/Libraries/LibJS/Forward.h @@ -166,6 +166,7 @@ class Handle; namespace Bytecode { class BasicBlock; +struct Executable; class Generator; class Instruction; class Interpreter; diff --git a/Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp b/Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp index 9deaaef637..f57dad44eb 100644 --- a/Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp +++ b/Userland/Libraries/LibJS/Runtime/ScriptFunction.cpp @@ -156,7 +156,7 @@ Value ScriptFunction::execute_function_body() if constexpr (JS_BYTECODE_DEBUG) { dbgln("Compiled Bytecode::Block for function '{}':", m_name); for (auto& block : m_bytecode_executable->basic_blocks) - block.dump(); + block.dump(*m_bytecode_executable); } } return bytecode_interpreter->run(*m_bytecode_executable); diff --git a/Userland/Utilities/js.cpp b/Userland/Utilities/js.cpp index ee2efc19f1..b99d2c5387 100644 --- a/Userland/Utilities/js.cpp +++ b/Userland/Utilities/js.cpp @@ -516,7 +516,11 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source auto unit = JS::Bytecode::Generator::generate(*program); if (s_dump_bytecode) { for (auto& block : unit.basic_blocks) - block.dump(); + block.dump(unit); + if (!unit.string_table->is_empty()) { + outln(); + unit.string_table->dump(); + } } if (s_run_bytecode) { |