diff --git a/Applications/Browser/BrowserConsoleClient.cpp b/Applications/Browser/BrowserConsoleClient.cpp
index d7b54c06ce0..83802161223 100644
--- a/Applications/Browser/BrowserConsoleClient.cpp
+++ b/Applications/Browser/BrowserConsoleClient.cpp
@@ -41,7 +41,7 @@ namespace Browser {
JS::Value BrowserConsoleClient::log()
{
- m_console_widget.print_html(interpreter().join_arguments());
+ m_console_widget.print_html(interpreter().vm().join_arguments());
return JS::js_undefined();
}
@@ -50,7 +50,7 @@ JS::Value BrowserConsoleClient::info()
StringBuilder html;
html.append("");
html.append("(i) ");
- html.append(interpreter().join_arguments());
+ html.append(interpreter().vm().join_arguments());
html.append("");
m_console_widget.print_html(html.string_view());
return JS::js_undefined();
@@ -61,7 +61,7 @@ JS::Value BrowserConsoleClient::debug()
StringBuilder html;
html.append("");
html.append("(d) ");
- html.append(interpreter().join_arguments());
+ html.append(interpreter().vm().join_arguments());
html.append("");
m_console_widget.print_html(html.string_view());
return JS::js_undefined();
@@ -72,7 +72,7 @@ JS::Value BrowserConsoleClient::warn()
StringBuilder html;
html.append("");
html.append("(w) ");
- html.append(interpreter().join_arguments());
+ html.append(interpreter().vm().join_arguments());
html.append("");
m_console_widget.print_html(html.string_view());
return JS::js_undefined();
@@ -83,7 +83,7 @@ JS::Value BrowserConsoleClient::error()
StringBuilder html;
html.append("");
html.append("(e) ");
- html.append(interpreter().join_arguments());
+ html.append(interpreter().vm().join_arguments());
html.append("");
m_console_widget.print_html(html.string_view());
return JS::js_undefined();
@@ -98,7 +98,7 @@ JS::Value BrowserConsoleClient::clear()
JS::Value BrowserConsoleClient::trace()
{
StringBuilder html;
- html.append(interpreter().join_arguments());
+ html.append(interpreter().vm().join_arguments());
auto trace = get_trace();
for (auto& function_name : trace) {
if (function_name.is_empty())
diff --git a/Applications/Browser/ConsoleWidget.cpp b/Applications/Browser/ConsoleWidget.cpp
index e19a68ea385..5ef3e545a70 100644
--- a/Applications/Browser/ConsoleWidget.cpp
+++ b/Applications/Browser/ConsoleWidget.cpp
@@ -92,7 +92,7 @@ ConsoleWidget::ConsoleWidget()
auto hint = error.source_location_hint(js_source);
if (!hint.is_empty())
output_html.append(String::format("
%s
", escape_html_entities(hint).characters()));
- m_interpreter->throw_exception(error.to_string());
+ m_interpreter->vm().throw_exception(m_interpreter->global_object(), error.to_string());
} else {
m_interpreter->run(m_interpreter->global_object(), *program);
}
@@ -106,7 +106,7 @@ ConsoleWidget::ConsoleWidget()
return;
}
- print_html(JS::MarkupGenerator::html_from_value(m_interpreter->last_value()));
+ print_html(JS::MarkupGenerator::html_from_value(m_interpreter->vm().last_value()));
};
auto& clear_button = bottom_container.add();
diff --git a/Applications/Spreadsheet/JSIntegration.cpp b/Applications/Spreadsheet/JSIntegration.cpp
index 54f48a5ab54..4ffa06308d9 100644
--- a/Applications/Spreadsheet/JSIntegration.cpp
+++ b/Applications/Spreadsheet/JSIntegration.cpp
@@ -87,12 +87,12 @@ void SheetGlobalObject::initialize()
JS_DEFINE_NATIVE_FUNCTION(SheetGlobalObject::parse_cell_name)
{
if (interpreter.argument_count() != 1) {
- interpreter.throw_exception("Expected exactly one argument to parse_cell_name()");
+ interpreter.vm().throw_exception(global_object, "Expected exactly one argument to parse_cell_name()");
return {};
}
auto name_value = interpreter.argument(0);
if (!name_value.is_string()) {
- interpreter.throw_exception("Expected a String argument to parse_cell_name()");
+ interpreter.vm().throw_exception(global_object, "Expected a String argument to parse_cell_name()");
return {};
}
auto position = Sheet::parse_cell_name(name_value.as_string().string());
@@ -125,12 +125,12 @@ void WorkbookObject::initialize(JS::GlobalObject& global_object)
JS_DEFINE_NATIVE_FUNCTION(WorkbookObject::sheet)
{
if (interpreter.argument_count() != 1) {
- interpreter.throw_exception("Expected exactly one argument to sheet()");
+ interpreter.vm().throw_exception(global_object, "Expected exactly one argument to sheet()");
return {};
}
auto name_value = interpreter.argument(0);
if (!name_value.is_string() && !name_value.is_number()) {
- interpreter.throw_exception("Expected a String or Number argument to sheet()");
+ interpreter.vm().throw_exception(global_object, "Expected a String or Number argument to sheet()");
return {};
}
@@ -139,7 +139,7 @@ JS_DEFINE_NATIVE_FUNCTION(WorkbookObject::sheet)
return {};
if (!this_object->inherits("WorkbookObject")) {
- interpreter.throw_exception(JS::ErrorType::NotA, "WorkbookObject");
+ interpreter.vm().throw_exception(global_object, JS::ErrorType::NotA, "WorkbookObject");
return {};
}
diff --git a/Applications/Spreadsheet/Spreadsheet.cpp b/Applications/Spreadsheet/Spreadsheet.cpp
index 07a0164ccfa..bc97b603305 100644
--- a/Applications/Spreadsheet/Spreadsheet.cpp
+++ b/Applications/Spreadsheet/Spreadsheet.cpp
@@ -164,7 +164,7 @@ JS::Value Sheet::evaluate(const StringView& source, Cell* on_behalf_of)
return exc;
}
- auto value = interpreter().last_value();
+ auto value = interpreter().vm().last_value();
if (value.is_empty())
return JS::js_undefined();
return value;
diff --git a/Libraries/LibJS/AST.cpp b/Libraries/LibJS/AST.cpp
index d2a8a85cacb..3ec1aa3efc5 100644
--- a/Libraries/LibJS/AST.cpp
+++ b/Libraries/LibJS/AST.cpp
@@ -86,7 +86,7 @@ static String get_function_name(Interpreter& interpreter, Value value)
Value ScopeNode::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
- return interpreter.execute_statement(global_object, *this);
+ return interpreter.vm().execute_statement(global_object, *this);
}
Value FunctionDeclaration::execute(Interpreter&, GlobalObject&) const
@@ -113,7 +113,7 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete
if (m_callee->is_super_expression()) {
// If we are calling super, |this| has not been initalized yet, and would not be meaningful to provide.
- auto new_target = interpreter.get_new_target();
+ auto new_target = interpreter.vm().get_new_target();
ASSERT(new_target.is_function());
return { js_undefined(), new_target };
}
@@ -125,7 +125,7 @@ CallExpression::ThisAndCallee CallExpression::compute_this_and_callee(Interprete
if (interpreter.exception())
return {};
if (is_super_property_lookup && (lookup_target.is_null() || lookup_target.is_undefined())) {
- interpreter.throw_exception(ErrorType::ObjectPrototypeNullOrUndefinedOnSuperPropertyAccess, lookup_target.to_string_without_side_effects().characters());
+ interpreter.vm().throw_exception(global_object, ErrorType::ObjectPrototypeNullOrUndefinedOnSuperPropertyAccess, lookup_target.to_string_without_side_effects().characters());
return {};
}
@@ -160,9 +160,9 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
} else {
expression_string = static_cast(*m_callee).to_string_approximation();
}
- interpreter.throw_exception(ErrorType::IsNotAEvaluatedFrom, callee.to_string_without_side_effects().characters(), call_type, expression_string.characters());
+ interpreter.vm().throw_exception(global_object, ErrorType::IsNotAEvaluatedFrom, callee.to_string_without_side_effects().characters(), call_type, expression_string.characters());
} else {
- interpreter.throw_exception(ErrorType::IsNotA, callee.to_string_without_side_effects().characters(), call_type);
+ interpreter.vm().throw_exception(global_object, ErrorType::IsNotA, callee.to_string_without_side_effects().characters(), call_type);
}
return {};
}
@@ -192,17 +192,17 @@ Value CallExpression::execute(Interpreter& interpreter, GlobalObject& global_obj
Object* new_object = nullptr;
Value result;
if (is_new_expression()) {
- result = interpreter.construct(function, function, move(arguments), global_object);
+ result = interpreter.vm().construct(function, function, move(arguments), global_object);
if (result.is_object())
new_object = &result.as_object();
} else if (m_callee->is_super_expression()) {
auto* super_constructor = interpreter.current_environment()->current_function()->prototype();
// FIXME: Functions should track their constructor kind.
if (!super_constructor || !super_constructor->is_function()) {
- interpreter.throw_exception(ErrorType::NotAConstructor, "Super constructor");
+ interpreter.vm().throw_exception(global_object, ErrorType::NotAConstructor, "Super constructor");
return {};
}
- result = interpreter.construct(static_cast(*super_constructor), function, move(arguments), global_object);
+ result = interpreter.vm().construct(static_cast(*super_constructor), function, move(arguments), global_object);
if (interpreter.exception())
return {};
@@ -227,7 +227,7 @@ Value ReturnStatement::execute(Interpreter& interpreter, GlobalObject& global_ob
auto value = argument() ? argument()->execute(interpreter, global_object) : js_undefined();
if (interpreter.exception())
return {};
- interpreter.unwind(ScopeType::Function);
+ interpreter.vm().unwind(ScopeType::Function);
return value;
}
@@ -238,10 +238,10 @@ Value IfStatement::execute(Interpreter& interpreter, GlobalObject& global_object
return {};
if (predicate_result.to_boolean())
- return interpreter.execute_statement(global_object, *m_consequent);
+ return interpreter.vm().execute_statement(global_object, *m_consequent);
if (m_alternate)
- return interpreter.execute_statement(global_object, *m_alternate);
+ return interpreter.vm().execute_statement(global_object, *m_alternate);
return js_undefined();
}
@@ -252,7 +252,7 @@ Value WhileStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
while (m_test->execute(interpreter, global_object).to_boolean()) {
if (interpreter.exception())
return {};
- last_value = interpreter.execute_statement(global_object, *m_body);
+ last_value = interpreter.vm().execute_statement(global_object, *m_body);
if (interpreter.exception())
return {};
}
@@ -266,7 +266,7 @@ Value DoWhileStatement::execute(Interpreter& interpreter, GlobalObject& global_o
do {
if (interpreter.exception())
return {};
- last_value = interpreter.execute_statement(global_object, *m_body);
+ last_value = interpreter.vm().execute_statement(global_object, *m_body);
if (interpreter.exception())
return {};
} while (m_test->execute(interpreter, global_object).to_boolean());
@@ -283,12 +283,12 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
NonnullRefPtrVector decls;
decls.append(*static_cast(m_init.ptr()));
wrapper->add_variables(decls);
- interpreter.enter_scope(*wrapper, {}, ScopeType::Block, global_object);
+ interpreter.vm().enter_scope(*wrapper, {}, ScopeType::Block, global_object);
}
auto wrapper_cleanup = ScopeGuard([&] {
if (wrapper)
- interpreter.exit_scope(*wrapper);
+ interpreter.vm().exit_scope(*wrapper);
});
Value last_value = js_undefined();
@@ -306,14 +306,14 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
return {};
if (!test_result.to_boolean())
break;
- last_value = interpreter.execute_statement(global_object, *m_body);
+ last_value = interpreter.vm().execute_statement(global_object, *m_body);
if (interpreter.exception())
return {};
- if (interpreter.should_unwind()) {
- if (interpreter.should_unwind_until(ScopeType::Continuable, m_label)) {
- interpreter.stop_unwind();
- } else if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
- interpreter.stop_unwind();
+ if (interpreter.vm().should_unwind()) {
+ if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_label)) {
+ interpreter.vm().stop_unwind();
+ } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
+ interpreter.vm().stop_unwind();
break;
} else {
return js_undefined();
@@ -327,14 +327,14 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
}
} else {
while (true) {
- last_value = interpreter.execute_statement(global_object, *m_body);
+ last_value = interpreter.vm().execute_statement(global_object, *m_body);
if (interpreter.exception())
return {};
- if (interpreter.should_unwind()) {
- if (interpreter.should_unwind_until(ScopeType::Continuable, m_label)) {
- interpreter.stop_unwind();
- } else if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
- interpreter.stop_unwind();
+ if (interpreter.vm().should_unwind()) {
+ if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_label)) {
+ interpreter.vm().stop_unwind();
+ } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
+ interpreter.vm().stop_unwind();
break;
} else {
return js_undefined();
@@ -359,7 +359,7 @@ static FlyString variable_from_for_declaration(Interpreter& interpreter, GlobalO
ASSERT(!variable_declaration->declarations().is_empty());
if (variable_declaration->declaration_kind() != DeclarationKind::Var) {
wrapper = create_ast_node();
- interpreter.enter_scope(*wrapper, {}, ScopeType::Block, global_object);
+ interpreter.vm().enter_scope(*wrapper, {}, ScopeType::Block, global_object);
}
variable_declaration->execute(interpreter, global_object);
variable_name = variable_declaration->declarations().first().id().string();
@@ -381,7 +381,7 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
auto variable_name = variable_from_for_declaration(interpreter, global_object, m_lhs, wrapper);
auto wrapper_cleanup = ScopeGuard([&] {
if (wrapper)
- interpreter.exit_scope(*wrapper);
+ interpreter.vm().exit_scope(*wrapper);
});
auto last_value = js_undefined();
auto rhs_result = m_rhs->execute(interpreter, global_object);
@@ -391,17 +391,17 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
while (object) {
auto property_names = object->get_own_properties(*object, Object::PropertyKind::Key, true);
for (auto& property_name : property_names.as_object().indexed_properties()) {
- interpreter.set_variable(variable_name, property_name.value_and_attributes(object).value, global_object);
+ interpreter.vm().set_variable(variable_name, property_name.value_and_attributes(object).value, global_object);
if (interpreter.exception())
return {};
- last_value = interpreter.execute_statement(global_object, *m_body);
+ last_value = interpreter.vm().execute_statement(global_object, *m_body);
if (interpreter.exception())
return {};
- if (interpreter.should_unwind()) {
- if (interpreter.should_unwind_until(ScopeType::Continuable, m_label)) {
- interpreter.stop_unwind();
- } else if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
- interpreter.stop_unwind();
+ if (interpreter.vm().should_unwind()) {
+ if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_label)) {
+ interpreter.vm().stop_unwind();
+ } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
+ interpreter.vm().stop_unwind();
break;
} else {
return js_undefined();
@@ -425,7 +425,7 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
auto variable_name = variable_from_for_declaration(interpreter, global_object, m_lhs, wrapper);
auto wrapper_cleanup = ScopeGuard([&] {
if (wrapper)
- interpreter.exit_scope(*wrapper);
+ interpreter.vm().exit_scope(*wrapper);
});
auto last_value = js_undefined();
auto rhs_result = m_rhs->execute(interpreter, global_object);
@@ -433,15 +433,15 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
return {};
get_iterator_values(global_object, rhs_result, [&](Value value) {
- interpreter.set_variable(variable_name, value, global_object);
- last_value = interpreter.execute_statement(global_object, *m_body);
+ interpreter.vm().set_variable(variable_name, value, global_object);
+ last_value = interpreter.vm().execute_statement(global_object, *m_body);
if (interpreter.exception())
return IterationDecision::Break;
- if (interpreter.should_unwind()) {
- if (interpreter.should_unwind_until(ScopeType::Continuable, m_label)) {
- interpreter.stop_unwind();
- } else if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
- interpreter.stop_unwind();
+ if (interpreter.vm().should_unwind()) {
+ if (interpreter.vm().should_unwind_until(ScopeType::Continuable, m_label)) {
+ interpreter.vm().stop_unwind();
+ } else if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
+ interpreter.vm().stop_unwind();
return IterationDecision::Break;
} else {
return IterationDecision::Break;
@@ -453,7 +453,7 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
if (interpreter.exception())
return {};
- if (interpreter.should_unwind())
+ if (interpreter.vm().should_unwind())
return js_undefined();
return last_value;
}
@@ -560,7 +560,7 @@ Reference Expression::to_reference(Interpreter&, GlobalObject&) const
Reference Identifier::to_reference(Interpreter& interpreter, GlobalObject&) const
{
- return interpreter.get_reference(string());
+ return interpreter.vm().get_reference(string());
}
Reference MemberExpression::to_reference(Interpreter& interpreter, GlobalObject& global_object) const
@@ -601,7 +601,7 @@ Value UnaryExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
// FIXME: standard recommends checking with is_unresolvable but it ALWAYS return false here
if (reference.is_local_variable() || reference.is_global_variable()) {
auto name = reference.name();
- lhs_result = interpreter.get_variable(name.to_string(), global_object).value_or(js_undefined());
+ lhs_result = interpreter.vm().get_variable(name.to_string(), global_object).value_or(js_undefined());
if (interpreter.exception())
return {};
}
@@ -684,7 +684,7 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
if (interpreter.exception())
return {};
if (!super_constructor.is_function() && !super_constructor.is_null()) {
- interpreter.throw_exception(ErrorType::ClassDoesNotExtendAConstructorOrNull, super_constructor.to_string_without_side_effects().characters());
+ interpreter.vm().throw_exception(global_object, ErrorType::ClassDoesNotExtendAConstructorOrNull, super_constructor.to_string_without_side_effects().characters());
return {};
}
class_constructor->set_constructor_kind(Function::ConstructorKind::Derived);
@@ -712,7 +712,7 @@ Value ClassExpression::execute(Interpreter& interpreter, GlobalObject& global_ob
return {};
if (!class_prototype.is_object()) {
- interpreter.throw_exception(ErrorType::NotAnObject, "Class prototype");
+ interpreter.vm().throw_exception(global_object, ErrorType::NotAnObject, "Class prototype");
return {};
}
for (const auto& method : m_methods) {
@@ -1153,9 +1153,9 @@ void ForOfStatement::dump(int indent) const
Value Identifier::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
- auto value = interpreter.get_variable(string(), global_object);
+ auto value = interpreter.vm().get_variable(string(), global_object);
if (value.is_empty()) {
- interpreter.throw_exception(ErrorType::UnknownIdentifier, string().characters());
+ interpreter.vm().throw_exception(global_object, ErrorType::UnknownIdentifier, string().characters());
return {};
}
return value;
@@ -1180,7 +1180,7 @@ Value SpreadExpression::execute(Interpreter& interpreter, GlobalObject& global_o
Value ThisExpression::execute(Interpreter& interpreter, GlobalObject&) const
{
- return interpreter.resolve_this_binding();
+ return interpreter.vm().resolve_this_binding();
}
void ThisExpression::dump(int indent) const
@@ -1279,7 +1279,7 @@ Value AssignmentExpression::execute(Interpreter& interpreter, GlobalObject& glob
return {};
if (reference.is_unresolvable()) {
- interpreter.throw_exception(ErrorType::InvalidLeftHandAssignment);
+ interpreter.vm().throw_exception(global_object, ErrorType::InvalidLeftHandAssignment);
return {};
}
update_function_name(rhs_result, get_function_name(interpreter, reference.name().to_value(interpreter)));
@@ -1410,7 +1410,7 @@ Value VariableDeclaration::execute(Interpreter& interpreter, GlobalObject& globa
return {};
auto variable_name = declarator.id().string();
update_function_name(initalizer_result, variable_name);
- interpreter.set_variable(variable_name, initalizer_result, global_object, true);
+ interpreter.vm().set_variable(variable_name, initalizer_result, global_object, true);
}
}
return js_undefined();
@@ -1723,7 +1723,7 @@ Value TaggedTemplateLiteral::execute(Interpreter& interpreter, GlobalObject& glo
if (interpreter.exception())
return {};
if (!tag.is_function()) {
- interpreter.throw_exception(ErrorType::NotAFunction, tag.to_string_without_side_effects().characters());
+ interpreter.vm().throw_exception(global_object, ErrorType::NotAFunction, tag.to_string_without_side_effects().characters());
return {};
}
auto& tag_function = tag.as_function();
@@ -1793,12 +1793,12 @@ void ThrowStatement::dump(int indent) const
Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
- interpreter.execute_statement(global_object, m_block, {}, ScopeType::Try);
+ interpreter.vm().execute_statement(global_object, m_block, {}, ScopeType::Try);
if (auto* exception = interpreter.exception()) {
if (m_handler) {
interpreter.vm().clear_exception();
ArgumentVector arguments { { m_handler->parameter(), exception->value() } };
- interpreter.execute_statement(global_object, m_handler->body(), move(arguments));
+ interpreter.vm().execute_statement(global_object, m_handler->body(), move(arguments));
}
}
@@ -1807,14 +1807,14 @@ Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
// execute() the finalizer without an exception in our way.
auto* previous_exception = interpreter.exception();
interpreter.vm().clear_exception();
- interpreter.stop_unwind();
+ interpreter.vm().stop_unwind();
m_finalizer->execute(interpreter, global_object);
// If we previously had an exception and the finalizer didn't
// throw a new one, restore the old one.
// FIXME: This will print debug output in throw_exception() for
// a seconds time with INTERPRETER_DEBUG enabled.
if (previous_exception && !interpreter.exception())
- interpreter.throw_exception(previous_exception);
+ interpreter.vm().throw_exception(previous_exception);
}
return js_undefined();
@@ -1830,9 +1830,9 @@ Value CatchClause::execute(Interpreter&, GlobalObject&) const
Value ThrowStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const
{
auto value = m_argument->execute(interpreter, global_object);
- if (interpreter.exception())
+ if (interpreter.vm().exception())
return {};
- interpreter.throw_exception(value);
+ interpreter.vm().throw_exception(global_object, value);
return {};
}
@@ -1858,9 +1858,9 @@ Value SwitchStatement::execute(Interpreter& interpreter, GlobalObject& global_ob
statement.execute(interpreter, global_object);
if (interpreter.exception())
return {};
- if (interpreter.should_unwind()) {
- if (interpreter.should_unwind_until(ScopeType::Breakable, m_label)) {
- interpreter.stop_unwind();
+ if (interpreter.vm().should_unwind()) {
+ if (interpreter.vm().should_unwind_until(ScopeType::Breakable, m_label)) {
+ interpreter.vm().stop_unwind();
return {};
}
return {};
@@ -1878,13 +1878,13 @@ Value SwitchCase::execute(Interpreter&, GlobalObject&) const
Value BreakStatement::execute(Interpreter& interpreter, GlobalObject&) const
{
- interpreter.unwind(ScopeType::Breakable, m_target_label);
+ interpreter.vm().unwind(ScopeType::Breakable, m_target_label);
return js_undefined();
}
Value ContinueStatement::execute(Interpreter& interpreter, GlobalObject&) const
{
- interpreter.unwind(ScopeType::Continuable, m_target_label);
+ interpreter.vm().unwind(ScopeType::Continuable, m_target_label);
return js_undefined();
}
diff --git a/Libraries/LibJS/Console.cpp b/Libraries/LibJS/Console.cpp
index cd40739ebc9..eff5bec2e93 100644
--- a/Libraries/LibJS/Console.cpp
+++ b/Libraries/LibJS/Console.cpp
@@ -123,7 +123,7 @@ bool Console::counter_reset(String label)
Vector ConsoleClient::get_trace() const
{
Vector trace;
- auto& call_stack = m_console.interpreter().call_stack();
+ auto& call_stack = m_console.interpreter().vm().call_stack();
// -2 to skip the console.trace() call frame
for (ssize_t i = call_stack.size() - 2; i >= 0; --i)
trace.append(call_stack[i].function_name);
diff --git a/Libraries/LibJS/Interpreter.cpp b/Libraries/LibJS/Interpreter.cpp
index 4309074129c..f000c425018 100644
--- a/Libraries/LibJS/Interpreter.cpp
+++ b/Libraries/LibJS/Interpreter.cpp
@@ -56,272 +56,22 @@ Interpreter::~Interpreter()
Value Interpreter::run(GlobalObject& global_object, const Program& program)
{
- VM::InterpreterExecutionScope scope(*this);
-
- ASSERT(!exception());
-
- if (m_call_stack.is_empty()) {
- CallFrame global_call_frame;
- global_call_frame.this_value = &global_object;
- global_call_frame.function_name = "(global execution context)";
- global_call_frame.environment = heap().allocate(global_object, LexicalEnvironment::EnvironmentRecordType::Global);
- global_call_frame.environment->bind_this_value(&global_object);
- if (exception())
- return {};
- m_call_stack.append(move(global_call_frame));
- }
-
- return program.execute(*this, global_object);
-}
-
-Value Interpreter::execute_statement(GlobalObject& global_object, const Statement& statement, ArgumentVector arguments, ScopeType scope_type)
-{
- if (!statement.is_scope_node())
- return statement.execute(*this, global_object);
-
- auto& block = static_cast(statement);
- enter_scope(block, move(arguments), scope_type, global_object);
-
- if (block.children().is_empty())
- m_last_value = js_undefined();
-
- for (auto& node : block.children()) {
- m_last_value = node.execute(*this, global_object);
- if (should_unwind()) {
- if (!block.label().is_null() && should_unwind_until(ScopeType::Breakable, block.label()))
- stop_unwind();
- break;
- }
- }
-
- bool did_return = m_unwind_until == ScopeType::Function;
-
- if (m_unwind_until == scope_type)
- m_unwind_until = ScopeType::None;
-
- exit_scope(block);
-
- return did_return ? m_last_value : js_undefined();
-}
-
-void Interpreter::enter_scope(const ScopeNode& scope_node, ArgumentVector arguments, ScopeType scope_type, GlobalObject& global_object)
-{
- for (auto& declaration : scope_node.functions()) {
- auto* function = ScriptFunction::create(global_object, declaration.name(), declaration.body(), declaration.parameters(), declaration.function_length(), current_environment());
- set_variable(declaration.name(), function, global_object);
- }
-
- if (scope_type == ScopeType::Function) {
- m_scope_stack.append({ scope_type, scope_node, false });
- return;
- }
-
- HashMap scope_variables_with_declaration_kind;
- scope_variables_with_declaration_kind.ensure_capacity(16);
-
- for (auto& declaration : scope_node.variables()) {
- for (auto& declarator : declaration.declarations()) {
- if (scope_node.is_program()) {
- global_object.put(declarator.id().string(), js_undefined());
- if (exception())
- return;
- } else {
- scope_variables_with_declaration_kind.set(declarator.id().string(), { js_undefined(), declaration.declaration_kind() });
- }
- }
- }
-
- for (auto& argument : arguments) {
- scope_variables_with_declaration_kind.set(argument.name, { argument.value, DeclarationKind::Var });
- }
-
- bool pushed_lexical_environment = false;
-
- if (!scope_variables_with_declaration_kind.is_empty()) {
- auto* block_lexical_environment = heap().allocate(global_object, move(scope_variables_with_declaration_kind), current_environment());
- m_call_stack.last().environment = block_lexical_environment;
- pushed_lexical_environment = true;
- }
-
- m_scope_stack.append({ scope_type, scope_node, pushed_lexical_environment });
-}
-
-void Interpreter::exit_scope(const ScopeNode& scope_node)
-{
- while (!m_scope_stack.is_empty()) {
- auto popped_scope = m_scope_stack.take_last();
- if (popped_scope.pushed_environment)
- m_call_stack.last().environment = m_call_stack.last().environment->parent();
- if (popped_scope.scope_node.ptr() == &scope_node)
- break;
- }
-
- // If we unwind all the way, just reset m_unwind_until so that future "return" doesn't break.
- if (m_scope_stack.is_empty())
- m_unwind_until = ScopeType::None;
-}
-
-void Interpreter::set_variable(const FlyString& name, Value value, GlobalObject& global_object, bool first_assignment)
-{
- if (m_call_stack.size()) {
- for (auto* environment = current_environment(); environment; environment = environment->parent()) {
- auto possible_match = environment->get(name);
- if (possible_match.has_value()) {
- if (!first_assignment && possible_match.value().declaration_kind == DeclarationKind::Const) {
- throw_exception(ErrorType::InvalidAssignToConst);
- return;
- }
-
- environment->set(name, { value, possible_match.value().declaration_kind });
- return;
- }
- }
- }
-
- global_object.put(move(name), move(value));
-}
-
-Value Interpreter::get_variable(const FlyString& name, GlobalObject& global_object)
-{
- if (m_call_stack.size()) {
- for (auto* environment = current_environment(); environment; environment = environment->parent()) {
- auto possible_match = environment->get(name);
- if (possible_match.has_value())
- return possible_match.value().value;
- }
- }
- auto value = global_object.get(name);
- if (m_underscore_is_last_value && name == "_" && value.is_empty())
- return m_last_value;
- return value;
-}
-
-Reference Interpreter::get_reference(const FlyString& name)
-{
- if (m_call_stack.size()) {
- for (auto* environment = current_environment(); environment; environment = environment->parent()) {
- auto possible_match = environment->get(name);
- if (possible_match.has_value())
- return { Reference::LocalVariable, name };
- }
- }
- return { Reference::GlobalVariable, name };
-}
-
-void Interpreter::gather_roots(HashTable& roots)
-{
- if (m_last_value.is_cell())
- roots.set(m_last_value.as_cell());
-
- for (auto& call_frame : m_call_stack) {
- if (call_frame.this_value.is_cell())
- roots.set(call_frame.this_value.as_cell());
- for (auto& argument : call_frame.arguments) {
- if (argument.is_cell())
- roots.set(argument.as_cell());
- }
- roots.set(call_frame.environment);
- }
-}
-
-Value Interpreter::call_internal(Function& function, Value this_value, Optional arguments)
-{
- ASSERT(!exception());
+ ASSERT(!vm().exception());
VM::InterpreterExecutionScope scope(*this);
- auto& call_frame = push_call_frame();
- call_frame.function_name = function.name();
- call_frame.this_value = function.bound_this().value_or(this_value);
- call_frame.arguments = function.bound_arguments();
- if (arguments.has_value())
- call_frame.arguments.append(arguments.value().values());
- call_frame.environment = function.create_environment();
-
- ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
- call_frame.environment->bind_this_value(call_frame.this_value);
-
- auto result = function.call(*this);
- pop_call_frame();
- return result;
-}
-
-Value Interpreter::construct(Function& function, Function& new_target, Optional arguments, GlobalObject& global_object)
-{
- auto& call_frame = push_call_frame();
- call_frame.function_name = function.name();
- call_frame.arguments = function.bound_arguments();
- if (arguments.has_value())
- call_frame.arguments.append(arguments.value().values());
- call_frame.environment = function.create_environment();
-
- current_environment()->set_new_target(&new_target);
-
- Object* new_object = nullptr;
- if (function.constructor_kind() == Function::ConstructorKind::Base) {
- new_object = Object::create_empty(global_object);
- current_environment()->bind_this_value(new_object);
- if (exception())
- return {};
- auto prototype = new_target.get("prototype");
- if (exception())
- return {};
- if (prototype.is_object()) {
- new_object->set_prototype(&prototype.as_object());
- if (exception())
- return {};
- }
- }
-
- // If we are a Derived constructor, |this| has not been constructed before super is called.
- Value this_value = function.constructor_kind() == Function::ConstructorKind::Base ? new_object : Value {};
- call_frame.this_value = this_value;
- auto result = function.construct(*this, new_target);
-
- this_value = current_environment()->get_this_binding();
- pop_call_frame();
-
- // If we are constructing an instance of a derived class,
- // set the prototype on objects created by constructors that return an object (i.e. NativeFunction subclasses).
- if (function.constructor_kind() == Function::ConstructorKind::Base && new_target.constructor_kind() == Function::ConstructorKind::Derived && result.is_object()) {
- current_environment()->replace_this_binding(result);
- auto prototype = new_target.get("prototype");
- if (exception())
- return {};
- if (prototype.is_object()) {
- result.as_object().set_prototype(&prototype.as_object());
- if (exception())
- return {};
- }
- return result;
- }
-
- if (exception())
+ CallFrame global_call_frame;
+ global_call_frame.this_value = &global_object;
+ global_call_frame.function_name = "(global execution context)";
+ global_call_frame.environment = heap().allocate(global_object, LexicalEnvironment::EnvironmentRecordType::Global);
+ global_call_frame.environment->bind_this_value(&global_object);
+ if (vm().exception())
return {};
+ vm().call_stack().append(move(global_call_frame));
- if (result.is_object())
- return result;
-
- return this_value;
-}
-
-void Interpreter::throw_exception(Exception* exception)
-{
-#ifdef INTERPRETER_DEBUG
- if (exception->value().is_object() && exception->value().as_object().is_error()) {
- auto& error = static_cast(exception->value().as_object());
- dbg() << "Throwing JavaScript Error: " << error.name() << ", " << error.message();
-
- for (ssize_t i = m_call_stack.size() - 1; i >= 0; --i) {
- auto function_name = m_call_stack[i].function_name;
- if (function_name.is_empty())
- function_name = "";
- dbg() << " " << function_name;
- }
- }
-#endif
- vm().set_exception({}, exception);
- unwind(ScopeType::Try);
+ auto result = program.execute(*this, global_object);
+ vm().pop_call_frame();
+ return result;
}
GlobalObject& Interpreter::global_object()
@@ -334,35 +84,26 @@ const GlobalObject& Interpreter::global_object() const
return static_cast(*m_global_object.cell());
}
-String Interpreter::join_arguments() const
+Value Interpreter::call_internal(Function& function, Value this_value, Optional arguments)
{
- StringBuilder joined_arguments;
- for (size_t i = 0; i < argument_count(); ++i) {
- joined_arguments.append(argument(i).to_string_without_side_effects().characters());
- if (i != argument_count() - 1)
- joined_arguments.append(' ');
- }
- return joined_arguments.build();
-}
+ ASSERT(!exception());
-Value Interpreter::resolve_this_binding() const
-{
- return get_this_environment()->get_this_binding();
-}
+ VM::InterpreterExecutionScope scope(*this);
-const LexicalEnvironment* Interpreter::get_this_environment() const
-{
- // We will always return because the Global environment will always be reached, which has a |this| binding.
- for (const LexicalEnvironment* environment = current_environment(); environment; environment = environment->parent()) {
- if (environment->has_this_binding())
- return environment;
- }
- ASSERT_NOT_REACHED();
-}
+ auto& call_frame = vm().push_call_frame();
+ call_frame.function_name = function.name();
+ call_frame.this_value = function.bound_this().value_or(this_value);
+ call_frame.arguments = function.bound_arguments();
+ if (arguments.has_value())
+ call_frame.arguments.append(arguments.value().values());
+ call_frame.environment = function.create_environment();
-Value Interpreter::get_new_target() const
-{
- return get_this_environment()->new_target();
+ ASSERT(call_frame.environment->this_binding_status() == LexicalEnvironment::ThisBindingStatus::Uninitialized);
+ call_frame.environment->bind_this_value(call_frame.this_value);
+
+ auto result = function.call(*this);
+ vm().pop_call_frame();
+ return result;
}
}
diff --git a/Libraries/LibJS/Interpreter.h b/Libraries/LibJS/Interpreter.h
index 6ba52bc5a38..8d8b40acb2b 100644
--- a/Libraries/LibJS/Interpreter.h
+++ b/Libraries/LibJS/Interpreter.h
@@ -45,35 +45,6 @@
namespace JS {
-enum class ScopeType {
- None,
- Function,
- Block,
- Try,
- Breakable,
- Continuable,
-};
-
-struct ScopeFrame {
- ScopeType type;
- NonnullRefPtr scope_node;
- bool pushed_environment { false };
-};
-
-struct CallFrame {
- FlyString function_name;
- Value this_value;
- Vector arguments;
- LexicalEnvironment* environment { nullptr };
-};
-
-struct Argument {
- FlyString name;
- Value value;
-};
-
-typedef Vector ArgumentVector;
-
class Interpreter : public Weakable {
public:
template
@@ -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&);
-
- void enter_scope(const ScopeNode&, ArgumentVector, ScopeType, GlobalObject&);
- void exit_scope(const ScopeNode&);
-
- Value construct(Function&, Function& new_target, Optional 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& 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
- 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
- void throw_exception(Args&&... args)
- {
- return throw_exception(T::create(global_object(), forward(args)...));
- }
-
- void throw_exception(Exception*);
- void throw_exception(Value value)
- {
- return throw_exception(heap().allocate(global_object(), value));
- }
-
- template
- void throw_exception(ErrorType type, Args&&... args)
- {
- return throw_exception(T::create(global_object(), String::format(type.message(), forward(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 m_vm;
- Value m_last_value;
-
- Vector m_scope_stack;
- Vector m_call_stack;
-
Handle | |