mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 15:40:19 +00:00
LibJS: Start fleshing out a bytecode for the JavaScript engine :^)
This patch begins the work of implementing JavaScript execution in a bytecode VM instead of an AST tree-walk interpreter. It's probably quite naive, but we have to start somewhere. The basic idea is that you call Bytecode::Generator::generate() on an AST node and it hands you back a Bytecode::Block filled with instructions that can then be interpreted by a Bytecode::Interpreter. This first version only implements two instructions: Load and Add. :^) Each bytecode block has infinity registers, and the interpreter resizes its register file to fit the block being executed. Two new `js` options are added in this patch as well: `-d` will dump the generated bytecode `-b` will execute the generated bytecode Note that unless `-d` and/or `-b` are specified, none of the bytecode related stuff in LibJS runs at all. This is implemented in parallel with the existing AST interpreter. :^)
This commit is contained in:
parent
f9395efaac
commit
69dddd4ef5
Notes:
sideshowbarker
2024-07-18 12:42:51 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/69dddd4ef58
16 changed files with 487 additions and 24 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
|
@ -13,6 +13,9 @@
|
|||
#include <AK/TemporaryChange.h>
|
||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Bytecode/Generator.h>
|
||||
#include <LibJS/Bytecode/Op.h>
|
||||
#include <LibJS/Bytecode/Register.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Runtime/Accessor.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
|
@ -2234,4 +2237,49 @@ void ScopeNode::add_functions(NonnullRefPtrVector<FunctionDeclaration> functions
|
|||
m_functions.append(move(functions));
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ASTNode::generate_bytecode(Bytecode::Generator&) const
|
||||
{
|
||||
dbgln("Missing generate_bytecode()");
|
||||
TODO();
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ScopeNode::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
for (auto& child : children()) {
|
||||
[[maybe_unused]] auto reg = child.generate_bytecode(generator);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> ExpressionStatement::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
return m_expression->generate_bytecode(generator);
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> BinaryExpression::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto lhs_reg = m_lhs->generate_bytecode(generator);
|
||||
auto rhs_reg = m_rhs->generate_bytecode(generator);
|
||||
|
||||
VERIFY(lhs_reg.has_value());
|
||||
VERIFY(rhs_reg.has_value());
|
||||
|
||||
switch (m_op) {
|
||||
case BinaryOp::Addition: {
|
||||
auto dst_reg = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Add>(dst_reg, *lhs_reg, *rhs_reg);
|
||||
return dst_reg;
|
||||
}
|
||||
default:
|
||||
TODO();
|
||||
}
|
||||
}
|
||||
|
||||
Optional<Bytecode::Register> NumericLiteral::generate_bytecode(Bytecode::Generator& generator) const
|
||||
{
|
||||
auto dst = generator.allocate_register();
|
||||
generator.emit<Bytecode::Op::Load>(dst, m_value);
|
||||
return dst;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
|
@ -37,6 +37,7 @@ class ASTNode : public RefCounted<ASTNode> {
|
|||
public:
|
||||
virtual ~ASTNode() { }
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const = 0;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const;
|
||||
virtual void dump(int indent) const;
|
||||
|
||||
const SourceRange& source_range() const { return m_source_range; }
|
||||
|
@ -96,6 +97,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
const Expression& expression() const { return m_expression; };
|
||||
|
||||
|
@ -120,6 +122,7 @@ public:
|
|||
const NonnullRefPtrVector<Statement>& children() const { return m_children; }
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
void add_variables(NonnullRefPtrVector<VariableDeclaration>);
|
||||
void add_functions(NonnullRefPtrVector<FunctionDeclaration>);
|
||||
|
@ -522,6 +525,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
BinaryOp m_op;
|
||||
|
@ -630,6 +634,7 @@ public:
|
|||
|
||||
virtual Value execute(Interpreter&, GlobalObject&) const override;
|
||||
virtual void dump(int indent) const override;
|
||||
virtual Optional<Bytecode::Register> generate_bytecode(Bytecode::Generator&) const override;
|
||||
|
||||
private:
|
||||
Value m_value;
|
||||
|
|
38
Userland/Libraries/LibJS/Bytecode/Block.cpp
Normal file
38
Userland/Libraries/LibJS/Bytecode/Block.cpp
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/String.h>
|
||||
#include <LibJS/Bytecode/Block.h>
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
NonnullOwnPtr<Block> Block::create()
|
||||
{
|
||||
return adopt_own(*new Block);
|
||||
}
|
||||
|
||||
Block::Block()
|
||||
{
|
||||
}
|
||||
|
||||
Block::~Block()
|
||||
{
|
||||
}
|
||||
|
||||
void Block::append(Badge<Bytecode::Generator>, NonnullOwnPtr<Instruction> instruction)
|
||||
{
|
||||
m_instructions.append(move(instruction));
|
||||
}
|
||||
|
||||
void Block::dump() const
|
||||
{
|
||||
for (size_t i = 0; i < m_instructions.size(); ++i) {
|
||||
warnln("[{:3}] {}", i, m_instructions[i].to_string());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
35
Userland/Libraries/LibJS/Bytecode/Block.h
Normal file
35
Userland/Libraries/LibJS/Bytecode/Block.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/NonnullOwnPtrVector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
class Block {
|
||||
public:
|
||||
static NonnullOwnPtr<Block> create();
|
||||
~Block();
|
||||
|
||||
NonnullOwnPtrVector<Instruction> const& instructions() const { return m_instructions; }
|
||||
void dump() const;
|
||||
|
||||
size_t register_count() const { return m_register_count; }
|
||||
|
||||
void append(Badge<Bytecode::Generator>, NonnullOwnPtr<Instruction>);
|
||||
void set_register_count(Badge<Bytecode::Generator>, size_t count) { m_register_count = count; }
|
||||
|
||||
private:
|
||||
Block();
|
||||
|
||||
size_t m_register_count { 0 };
|
||||
NonnullOwnPtrVector<Instruction> m_instructions;
|
||||
};
|
||||
|
||||
}
|
45
Userland/Libraries/LibJS/Bytecode/Generator.cpp
Normal file
45
Userland/Libraries/LibJS/Bytecode/Generator.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Bytecode/Block.h>
|
||||
#include <LibJS/Bytecode/Generator.h>
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
#include <LibJS/Bytecode/Register.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
Generator::Generator()
|
||||
{
|
||||
m_block = Block::create();
|
||||
}
|
||||
|
||||
Generator::~Generator()
|
||||
{
|
||||
}
|
||||
|
||||
OwnPtr<Block> Generator::generate(ASTNode const& node)
|
||||
{
|
||||
Generator generator;
|
||||
[[maybe_unused]] auto dummy = node.generate_bytecode(generator);
|
||||
generator.m_block->set_register_count({}, generator.m_next_register);
|
||||
return move(generator.m_block);
|
||||
}
|
||||
|
||||
void Generator::append(NonnullOwnPtr<Instruction> instruction)
|
||||
{
|
||||
m_block->append({}, move(instruction));
|
||||
}
|
||||
|
||||
Register Generator::allocate_register()
|
||||
{
|
||||
VERIFY(m_next_register != NumericLimits<u32>::max());
|
||||
return Register { m_next_register++ };
|
||||
}
|
||||
|
||||
}
|
37
Userland/Libraries/LibJS/Bytecode/Generator.h
Normal file
37
Userland/Libraries/LibJS/Bytecode/Generator.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
class Generator {
|
||||
public:
|
||||
static OwnPtr<Block> generate(ASTNode const&);
|
||||
|
||||
Register allocate_register();
|
||||
|
||||
template<typename OpType, typename... Args>
|
||||
void emit(Args&&... args)
|
||||
{
|
||||
auto instruction = make<OpType>(forward<Args>(args)...);
|
||||
append(move(instruction));
|
||||
}
|
||||
|
||||
private:
|
||||
Generator();
|
||||
~Generator();
|
||||
|
||||
void append(NonnullOwnPtr<Instruction>);
|
||||
|
||||
OwnPtr<Block> m_block;
|
||||
u32 m_next_register { 1 };
|
||||
};
|
||||
|
||||
}
|
15
Userland/Libraries/LibJS/Bytecode/Instruction.cpp
Normal file
15
Userland/Libraries/LibJS/Bytecode/Instruction.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
Instruction::~Instruction()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
22
Userland/Libraries/LibJS/Bytecode/Instruction.h
Normal file
22
Userland/Libraries/LibJS/Bytecode/Instruction.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Forward.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
class Instruction {
|
||||
public:
|
||||
virtual ~Instruction();
|
||||
|
||||
virtual String to_string() const = 0;
|
||||
virtual void execute(Bytecode::Interpreter&) const = 0;
|
||||
};
|
||||
|
||||
}
|
42
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp
Normal file
42
Userland/Libraries/LibJS/Bytecode/Interpreter.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/Block.h>
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
Interpreter::Interpreter(GlobalObject& global_object)
|
||||
: m_global_object(global_object)
|
||||
{
|
||||
}
|
||||
|
||||
Interpreter::~Interpreter()
|
||||
{
|
||||
}
|
||||
|
||||
void Interpreter::run(Bytecode::Block const& block)
|
||||
{
|
||||
dbgln("Bytecode::Interpreter will run block {:p}", &block);
|
||||
|
||||
m_registers.resize(block.register_count());
|
||||
|
||||
for (auto& instruction : block.instructions())
|
||||
instruction.execute(*this);
|
||||
|
||||
dbgln("Bytecode::Interpreter did run block {:p}", &block);
|
||||
for (size_t i = 0; i < m_registers.size(); ++i) {
|
||||
String value_string;
|
||||
if (m_registers[i].is_empty())
|
||||
value_string = "(empty)";
|
||||
else
|
||||
value_string = m_registers[i].to_string_without_side_effects();
|
||||
dbgln("[{:3}] {}", i, value_string);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
32
Userland/Libraries/LibJS/Bytecode/Interpreter.h
Normal file
32
Userland/Libraries/LibJS/Bytecode/Interpreter.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Bytecode/Register.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
class Interpreter {
|
||||
public:
|
||||
explicit Interpreter(GlobalObject&);
|
||||
~Interpreter();
|
||||
|
||||
GlobalObject& global_object() { return m_global_object; }
|
||||
|
||||
void run(Bytecode::Block const&);
|
||||
|
||||
Value& reg(Register const& r) { return m_registers[r.index()]; }
|
||||
|
||||
private:
|
||||
GlobalObject& m_global_object;
|
||||
Vector<Value> m_registers;
|
||||
};
|
||||
|
||||
}
|
33
Userland/Libraries/LibJS/Bytecode/Op.cpp
Normal file
33
Userland/Libraries/LibJS/Bytecode/Op.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Bytecode/Op.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS::Bytecode::Op {
|
||||
|
||||
void Load::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = m_value;
|
||||
}
|
||||
|
||||
void Add::execute(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
interpreter.reg(m_dst) = add(interpreter.global_object(), interpreter.reg(m_src1), interpreter.reg(m_src2));
|
||||
}
|
||||
|
||||
String Load::to_string() const
|
||||
{
|
||||
return String::formatted("Load dst:r{}, value:{}", m_dst.index(), m_value.to_string_without_side_effects());
|
||||
}
|
||||
|
||||
String Add::to_string() const
|
||||
{
|
||||
return String::formatted("Add dst:r{}, src1:r{}, src2:r{}", m_dst.index(), m_src1.index(), m_src2.index());
|
||||
}
|
||||
|
||||
}
|
52
Userland/Libraries/LibJS/Bytecode/Op.h
Normal file
52
Userland/Libraries/LibJS/Bytecode/Op.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibJS/Bytecode/Instruction.h>
|
||||
#include <LibJS/Bytecode/Register.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS::Bytecode::Op {
|
||||
|
||||
class Load final : public Instruction {
|
||||
public:
|
||||
Load(Register dst, Value value)
|
||||
: m_dst(dst)
|
||||
, m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Load() override { }
|
||||
virtual void execute(Bytecode::Interpreter&) const override;
|
||||
virtual String to_string() const override;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
Value m_value;
|
||||
};
|
||||
|
||||
class Add final : public Instruction {
|
||||
public:
|
||||
Add(Register dst, Register src1, Register src2)
|
||||
: m_dst(dst)
|
||||
, m_src1(src1)
|
||||
, m_src2(src2)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Add() override { }
|
||||
virtual void execute(Bytecode::Interpreter&) const override;
|
||||
virtual String to_string() const override;
|
||||
|
||||
private:
|
||||
Register m_dst;
|
||||
Register m_src1;
|
||||
Register m_src2;
|
||||
};
|
||||
|
||||
}
|
26
Userland/Libraries/LibJS/Bytecode/Register.h
Normal file
26
Userland/Libraries/LibJS/Bytecode/Register.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace JS::Bytecode {
|
||||
|
||||
class Register {
|
||||
public:
|
||||
explicit Register(u32 index)
|
||||
: m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
u32 index() const { return m_index; }
|
||||
|
||||
private:
|
||||
u32 m_index { 0 };
|
||||
};
|
||||
|
||||
}
|
|
@ -1,25 +1,30 @@
|
|||
set(SOURCES
|
||||
AST.cpp
|
||||
Console.cpp
|
||||
Heap/CellAllocator.cpp
|
||||
Heap/BlockAllocator.cpp
|
||||
Heap/Handle.cpp
|
||||
Heap/HeapBlock.cpp
|
||||
Heap/Heap.cpp
|
||||
Interpreter.cpp
|
||||
Lexer.cpp
|
||||
MarkupGenerator.cpp
|
||||
Parser.cpp
|
||||
Runtime/Array.cpp
|
||||
Runtime/ArrayBuffer.cpp
|
||||
Runtime/ArrayBufferConstructor.cpp
|
||||
Runtime/ArrayBufferPrototype.cpp
|
||||
Runtime/ArrayConstructor.cpp
|
||||
Runtime/ArrayIterator.cpp
|
||||
Runtime/ArrayIteratorPrototype.cpp
|
||||
Runtime/ArrayPrototype.cpp
|
||||
Runtime/BigInt.cpp
|
||||
Runtime/BigIntConstructor.cpp
|
||||
AST.cpp
|
||||
Bytecode/Block.cpp
|
||||
Bytecode/Generator.cpp
|
||||
Bytecode/Instruction.cpp
|
||||
Bytecode/Interpreter.cpp
|
||||
Bytecode/Op.cpp
|
||||
Console.cpp
|
||||
Heap/CellAllocator.cpp
|
||||
Heap/BlockAllocator.cpp
|
||||
Heap/Handle.cpp
|
||||
Heap/HeapBlock.cpp
|
||||
Heap/Heap.cpp
|
||||
Interpreter.cpp
|
||||
Lexer.cpp
|
||||
MarkupGenerator.cpp
|
||||
Parser.cpp
|
||||
Runtime/Array.cpp
|
||||
Runtime/ArrayBuffer.cpp
|
||||
Runtime/ArrayBufferConstructor.cpp
|
||||
Runtime/ArrayBufferPrototype.cpp
|
||||
Runtime/ArrayConstructor.cpp
|
||||
Runtime/ArrayIterator.cpp
|
||||
Runtime/ArrayIteratorPrototype.cpp
|
||||
Runtime/ArrayPrototype.cpp
|
||||
Runtime/BigInt.cpp
|
||||
Runtime/BigIntConstructor.cpp
|
||||
Runtime/BigIntObject.cpp
|
||||
Runtime/BigIntPrototype.cpp
|
||||
Runtime/BooleanConstructor.cpp
|
||||
|
|
|
@ -162,4 +162,12 @@ JS_ENUMERATE_TYPED_ARRAYS
|
|||
template<class T>
|
||||
class Handle;
|
||||
|
||||
namespace Bytecode {
|
||||
class Block;
|
||||
class Generator;
|
||||
class Instruction;
|
||||
class Interpreter;
|
||||
class Register;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
|
@ -14,6 +14,9 @@
|
|||
#include <LibCore/File.h>
|
||||
#include <LibCore/StandardPaths.h>
|
||||
#include <LibJS/AST.h>
|
||||
#include <LibJS/Bytecode/Block.h>
|
||||
#include <LibJS/Bytecode/Generator.h>
|
||||
#include <LibJS/Bytecode/Interpreter.h>
|
||||
#include <LibJS/Console.h>
|
||||
#include <LibJS/Interpreter.h>
|
||||
#include <LibJS/Parser.h>
|
||||
|
@ -73,6 +76,8 @@ private:
|
|||
};
|
||||
|
||||
static bool s_dump_ast = false;
|
||||
static bool s_dump_bytecode = false;
|
||||
static bool s_run_bytecode = false;
|
||||
static bool s_print_last_result = false;
|
||||
static RefPtr<Line::Editor> s_editor;
|
||||
static String s_history_path = String::formatted("{}/.js-history", Core::StandardPaths::home_directory());
|
||||
|
@ -489,6 +494,19 @@ static bool parse_and_run(JS::Interpreter& interpreter, const StringView& source
|
|||
if (s_dump_ast)
|
||||
program->dump(0);
|
||||
|
||||
if (s_dump_bytecode || s_run_bytecode) {
|
||||
auto block = JS::Bytecode::Generator::generate(*program);
|
||||
VERIFY(block);
|
||||
|
||||
if (s_dump_bytecode)
|
||||
block->dump();
|
||||
|
||||
if (s_run_bytecode) {
|
||||
JS::Bytecode::Interpreter bytecode_interpreter(interpreter.global_object());
|
||||
bytecode_interpreter.run(*block);
|
||||
}
|
||||
}
|
||||
|
||||
if (parser.has_errors()) {
|
||||
auto error = parser.errors()[0];
|
||||
auto hint = error.source_location_hint(source);
|
||||
|
@ -744,6 +762,8 @@ int main(int argc, char** argv)
|
|||
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(s_dump_bytecode, "Dump the bytecode", "dump-bytecode", 'd');
|
||||
args_parser.add_option(s_run_bytecode, "Run the bytecode", "run-bytecode", 'b');
|
||||
args_parser.add_option(s_print_last_result, "Print last result", "print-last-result", 'l');
|
||||
args_parser.add_option(gc_on_every_allocation, "GC on every allocation", "gc-on-every-allocation", 'g');
|
||||
args_parser.add_option(disable_syntax_highlight, "Disable live syntax highlighting", "no-syntax-highlight", 's');
|
||||
|
|
Loading…
Reference in a new issue