1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 10:28:10 +00:00

LibJS: Move most of Interpreter into VM

This patch moves the exception state, call stack and scope stack from
Interpreter to VM. I'm doing this to help myself discover what the
split between Interpreter and VM should be, by shuffling things around
and seeing what falls where.

With these changes, we no longer have a persistent lexical environment
for the current global object on the Interpreter's call stack. Instead,
we push/pop that environment on Interpreter::run() enter/exit.
Since it should only be used to find the global "this", and not for
variable storage (that goes directly into the global object instead!),
I had to insert some short-circuiting when walking the environment
parent chain during variable lookup.

Note that this is a "stepping stone" commit, not a final design.
This commit is contained in:
Andreas Kling 2020-09-27 15:18:55 +02:00
parent 838d9fa251
commit 6861c619c6
48 changed files with 765 additions and 726 deletions

View file

@ -45,35 +45,6 @@
namespace JS {
enum class ScopeType {
None,
Function,
Block,
Try,
Breakable,
Continuable,
};
struct ScopeFrame {
ScopeType type;
NonnullRefPtr<ScopeNode> scope_node;
bool pushed_environment { false };
};
struct CallFrame {
FlyString function_name;
Value this_value;
Vector<Value> arguments;
LexicalEnvironment* environment { nullptr };
};
struct Argument {
FlyString name;
Value value;
};
typedef Vector<Argument, 8> ArgumentVector;
class Interpreter : public Weakable<Interpreter> {
public:
template<typename GlobalObjectType, typename... Args>
@ -106,122 +77,23 @@ public:
Value run(GlobalObject&, const Program&);
Value execute_statement(GlobalObject&, const Statement&, ArgumentVector = {}, ScopeType = ScopeType::Block);
GlobalObject& global_object();
const GlobalObject& global_object() const;
VM& vm() { return *m_vm; }
const VM& vm() const { return *m_vm; }
Heap& heap() { return vm().heap(); }
Exception* exception() { return vm().exception(); }
void unwind(ScopeType type, FlyString label = {})
{
m_unwind_until = type;
m_unwind_until_label = label;
}
void stop_unwind() { m_unwind_until = ScopeType::None; }
bool should_unwind_until(ScopeType type, FlyString label) const
{
if (m_unwind_until_label.is_null())
return m_unwind_until == type;
return m_unwind_until == type && m_unwind_until_label == label;
}
bool should_unwind() const { return m_unwind_until != ScopeType::None; }
Value get_variable(const FlyString& name, GlobalObject&);
void set_variable(const FlyString& name, Value, GlobalObject&, bool first_assignment = false);
Reference get_reference(const FlyString& name);
void gather_roots(HashTable<Cell*>&);
void enter_scope(const ScopeNode&, ArgumentVector, ScopeType, GlobalObject&);
void exit_scope(const ScopeNode&);
Value construct(Function&, Function& new_target, Optional<MarkedValueList> arguments, GlobalObject&);
CallFrame& push_call_frame()
{
m_call_stack.append({ {}, js_undefined(), {}, nullptr });
return m_call_stack.last();
}
void pop_call_frame() { m_call_stack.take_last(); }
const CallFrame& call_frame() { return m_call_stack.last(); }
const Vector<CallFrame>& call_stack() { return m_call_stack; }
const LexicalEnvironment* current_environment() const { return m_call_stack.last().environment; }
LexicalEnvironment* current_environment() { return m_call_stack.last().environment; }
bool in_strict_mode() const
{
if (m_scope_stack.is_empty())
return true;
return m_scope_stack.last().scope_node->in_strict_mode();
}
template<typename Callback>
void for_each_argument(Callback callback)
{
if (m_call_stack.is_empty())
return;
for (auto& value : m_call_stack.last().arguments)
callback(value);
}
size_t argument_count() const
{
if (m_call_stack.is_empty())
return 0;
return m_call_stack.last().arguments.size();
}
Value argument(size_t index) const
{
if (m_call_stack.is_empty())
return {};
auto& arguments = m_call_stack.last().arguments;
return index < arguments.size() ? arguments[index] : js_undefined();
}
Value this_value(Object& global_object) const
{
if (m_call_stack.is_empty())
return &global_object;
return m_call_stack.last().this_value;
}
template<typename T, typename... Args>
void throw_exception(Args&&... args)
{
return throw_exception(T::create(global_object(), forward<Args>(args)...));
}
void throw_exception(Exception*);
void throw_exception(Value value)
{
return throw_exception(heap().allocate<Exception>(global_object(), value));
}
template<typename T, typename... Args>
void throw_exception(ErrorType type, Args&&... args)
{
return throw_exception(T::create(global_object(), String::format(type.message(), forward<Args>(args)...)));
}
Value last_value() const { return m_last_value; }
bool underscore_is_last_value() const { return m_underscore_is_last_value; }
void set_underscore_is_last_value(bool b) { m_underscore_is_last_value = b; }
Console& console() { return m_console; }
const Console& console() const { return m_console; }
String join_arguments() const;
Value resolve_this_binding() const;
const LexicalEnvironment* get_this_environment() const;
Value get_new_target() const;
bool in_strict_mode() const { return vm().in_strict_mode(); }
size_t argument_count() const { return vm().argument_count(); }
Value argument(size_t index) const { return vm().argument(index); }
Value this_value(Object& global_object) const { return vm().this_value(global_object); }
LexicalEnvironment* current_environment() { return vm().current_environment(); }
const CallFrame& call_frame() { return vm().call_frame(); }
private:
explicit Interpreter(VM&);
@ -230,18 +102,8 @@ private:
NonnullRefPtr<VM> m_vm;
Value m_last_value;
Vector<ScopeFrame> m_scope_stack;
Vector<CallFrame> m_call_stack;
Handle<Object> m_global_object;
ScopeType m_unwind_until { ScopeType::None };
FlyString m_unwind_until_label;
bool m_underscore_is_last_value { false };
Console m_console;
};