
If there's a current Bytecode::Interpreter in action, ScriptFunction will now compile itself into bytecode and execute in that context. This patch also adds the Return bytecode instruction so that we can actually return values from called functions. :^) Return values are propagated from callee to caller via the caller's $0 register. Bytecode::Interpreter now keeps a stack of register "windows". These are not very efficient, but it should be pretty straightforward to convert them to e.g a sliding register window architecture later on. This is pretty dang cool! :^)
48 lines
1.2 KiB
C++
48 lines
1.2 KiB
C++
/*
|
|
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/NonnullOwnPtrVector.h>
|
|
#include <LibJS/Bytecode/Label.h>
|
|
#include <LibJS/Bytecode/Register.h>
|
|
#include <LibJS/Forward.h>
|
|
#include <LibJS/Heap/Cell.h>
|
|
#include <LibJS/Runtime/Value.h>
|
|
|
|
namespace JS::Bytecode {
|
|
|
|
using RegisterWindow = Vector<Value>;
|
|
|
|
class Interpreter {
|
|
public:
|
|
explicit Interpreter(GlobalObject&);
|
|
~Interpreter();
|
|
|
|
// FIXME: Remove this thing once we don't need it anymore!
|
|
static Interpreter* current();
|
|
|
|
GlobalObject& global_object() { return m_global_object; }
|
|
VM& vm() { return m_vm; }
|
|
|
|
Value run(Bytecode::Block const&);
|
|
|
|
Value& reg(Register const& r) { return registers()[r.index()]; }
|
|
|
|
void jump(Label const& label) { m_pending_jump = label.address(); }
|
|
void do_return(Value return_value) { m_return_value = return_value; }
|
|
|
|
private:
|
|
RegisterWindow& registers() { return m_register_windows.last(); }
|
|
|
|
VM& m_vm;
|
|
GlobalObject& m_global_object;
|
|
NonnullOwnPtrVector<RegisterWindow> m_register_windows;
|
|
Optional<size_t> m_pending_jump;
|
|
Value m_return_value;
|
|
};
|
|
|
|
}
|