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:
parent
838d9fa251
commit
6861c619c6
48 changed files with 765 additions and 726 deletions
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue