Skip to content

Commit ec43f73

Browse files
linusgawesomekling
authored andcommitted
LibJS: Extract most of Interpreter's run() into execute_statement()
Interpreter::run() was so far being used both as the "public API entry point" for running a JS::Program as well as internally to execute JS::Statement|s of all kinds - this is now more distinctly separated. A program as returned by the parser is still going through run(), which is responsible for creating the initial global call frame, but all other statements are executed via execute_statement() directly. Fixes #3437, a regression introduced by adding ASSERT(!exception()) to run() without considering the effects that would have on internal usage.
1 parent bd6390d commit ec43f73

File tree

5 files changed

+55
-25
lines changed

5 files changed

+55
-25
lines changed

Libraries/LibJS/AST.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ static String get_function_name(Interpreter& interpreter, Value value)
7676

7777
Value ScopeNode::execute(Interpreter& interpreter, GlobalObject& global_object) const
7878
{
79-
return interpreter.run(global_object, *this);
79+
return interpreter.execute_statement(global_object, *this);
8080
}
8181

8282
Value FunctionDeclaration::execute(Interpreter&, GlobalObject&) const
@@ -225,10 +225,10 @@ Value IfStatement::execute(Interpreter& interpreter, GlobalObject& global_object
225225
return {};
226226

227227
if (predicate_result.to_boolean())
228-
return interpreter.run(global_object, *m_consequent);
228+
return interpreter.execute_statement(global_object, *m_consequent);
229229

230230
if (m_alternate)
231-
return interpreter.run(global_object, *m_alternate);
231+
return interpreter.execute_statement(global_object, *m_alternate);
232232

233233
return js_undefined();
234234
}
@@ -239,7 +239,7 @@ Value WhileStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
239239
while (m_test->execute(interpreter, global_object).to_boolean()) {
240240
if (interpreter.exception())
241241
return {};
242-
last_value = interpreter.run(global_object, *m_body);
242+
last_value = interpreter.execute_statement(global_object, *m_body);
243243
if (interpreter.exception())
244244
return {};
245245
}
@@ -253,7 +253,7 @@ Value DoWhileStatement::execute(Interpreter& interpreter, GlobalObject& global_o
253253
do {
254254
if (interpreter.exception())
255255
return {};
256-
last_value = interpreter.run(global_object, *m_body);
256+
last_value = interpreter.execute_statement(global_object, *m_body);
257257
if (interpreter.exception())
258258
return {};
259259
} while (m_test->execute(interpreter, global_object).to_boolean());
@@ -293,7 +293,7 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
293293
return {};
294294
if (!test_result.to_boolean())
295295
break;
296-
last_value = interpreter.run(global_object, *m_body);
296+
last_value = interpreter.execute_statement(global_object, *m_body);
297297
if (interpreter.exception())
298298
return {};
299299
if (interpreter.should_unwind()) {
@@ -314,7 +314,7 @@ Value ForStatement::execute(Interpreter& interpreter, GlobalObject& global_objec
314314
}
315315
} else {
316316
while (true) {
317-
last_value = interpreter.run(global_object, *m_body);
317+
last_value = interpreter.execute_statement(global_object, *m_body);
318318
if (interpreter.exception())
319319
return {};
320320
if (interpreter.should_unwind()) {
@@ -381,7 +381,7 @@ Value ForInStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
381381
interpreter.set_variable(variable_name, property_name.value_and_attributes(object).value, global_object);
382382
if (interpreter.exception())
383383
return {};
384-
last_value = interpreter.run(global_object, *m_body);
384+
last_value = interpreter.execute_statement(global_object, *m_body);
385385
if (interpreter.exception())
386386
return {};
387387
if (interpreter.should_unwind()) {
@@ -421,7 +421,7 @@ Value ForOfStatement::execute(Interpreter& interpreter, GlobalObject& global_obj
421421

422422
get_iterator_values(global_object, rhs_result, [&](Value value) {
423423
interpreter.set_variable(variable_name, value, global_object);
424-
last_value = interpreter.run(global_object, *m_body);
424+
last_value = interpreter.execute_statement(global_object, *m_body);
425425
if (interpreter.exception())
426426
return IterationDecision::Break;
427427
if (interpreter.should_unwind()) {
@@ -1777,12 +1777,12 @@ void ThrowStatement::dump(int indent) const
17771777

17781778
Value TryStatement::execute(Interpreter& interpreter, GlobalObject& global_object) const
17791779
{
1780-
interpreter.run(global_object, block(), {}, ScopeType::Try);
1780+
interpreter.execute_statement(global_object, m_block, {}, ScopeType::Try);
17811781
if (auto* exception = interpreter.exception()) {
17821782
if (m_handler) {
17831783
interpreter.clear_exception();
17841784
ArgumentVector arguments { { m_handler->parameter(), exception->value() } };
1785-
interpreter.run(global_object, m_handler->body(), move(arguments));
1785+
interpreter.execute_statement(global_object, m_handler->body(), move(arguments));
17861786
}
17871787
}
17881788

Libraries/LibJS/Interpreter.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,26 @@ Interpreter::~Interpreter()
5858
{
5959
}
6060

61-
Value Interpreter::run(GlobalObject& global_object, const Statement& statement, ArgumentVector arguments, ScopeType scope_type)
61+
Value Interpreter::run(GlobalObject& global_object, const Program& program)
6262
{
6363
ASSERT(!exception());
6464

65-
if (statement.is_program()) {
66-
if (m_call_stack.is_empty()) {
67-
CallFrame global_call_frame;
68-
global_call_frame.this_value = &global_object;
69-
global_call_frame.function_name = "(global execution context)";
70-
global_call_frame.environment = heap().allocate<LexicalEnvironment>(global_object, LexicalEnvironment::EnvironmentRecordType::Global);
71-
global_call_frame.environment->bind_this_value(&global_object);
72-
if (exception())
73-
return {};
74-
m_call_stack.append(move(global_call_frame));
75-
}
65+
if (m_call_stack.is_empty()) {
66+
CallFrame global_call_frame;
67+
global_call_frame.this_value = &global_object;
68+
global_call_frame.function_name = "(global execution context)";
69+
global_call_frame.environment = heap().allocate<LexicalEnvironment>(global_object, LexicalEnvironment::EnvironmentRecordType::Global);
70+
global_call_frame.environment->bind_this_value(&global_object);
71+
if (exception())
72+
return {};
73+
m_call_stack.append(move(global_call_frame));
7674
}
7775

76+
return program.execute(*this, global_object);
77+
}
78+
79+
Value Interpreter::execute_statement(GlobalObject& global_object, const Statement& statement, ArgumentVector arguments, ScopeType scope_type)
80+
{
7881
if (!statement.is_scope_node())
7982
return statement.execute(*this, global_object);
8083

Libraries/LibJS/Interpreter.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ class Interpreter : public Weakable<Interpreter> {
100100

101101
~Interpreter();
102102

103-
Value run(GlobalObject&, const Statement&, ArgumentVector = {}, ScopeType = ScopeType::Block);
103+
Value run(GlobalObject&, const Program&);
104+
105+
Value execute_statement(GlobalObject&, const Statement&, ArgumentVector = {}, ScopeType = ScopeType::Block);
104106

105107
GlobalObject& global_object();
106108
const GlobalObject& global_object() const;

Libraries/LibJS/Runtime/ScriptFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ Value ScriptFunction::call(Interpreter& interpreter)
130130
arguments.append({ parameter.name, value });
131131
interpreter.current_environment()->set(parameter.name, { value, DeclarationKind::Var });
132132
}
133-
return interpreter.run(global_object(), m_body, arguments, ScopeType::Function);
133+
return interpreter.execute_statement(global_object(), m_body, arguments, ScopeType::Function);
134134
}
135135

136136
Value ScriptFunction::construct(Interpreter& interpreter, Function&)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
test("Issue #1992, exception thrown in catch {} block", () => {
2+
var tryHasBeenExecuted = false;
3+
var catchHasBeenExecuted = false;
4+
var finallyHasBeenExecuted = false;
5+
expect(() => {
6+
try {
7+
tryHasBeenExecuted = true;
8+
foo();
9+
// execution must not reach this step
10+
expect().fail();
11+
} catch (e) {
12+
catchHasBeenExecuted = true;
13+
bar();
14+
// ...also not this step
15+
expect().fail();
16+
} finally {
17+
finallyHasBeenExecuted = true;
18+
}
19+
// ...or this step
20+
expect().fail();
21+
}).toThrow(ReferenceError, "'bar' is not defined");
22+
expect(tryHasBeenExecuted).toBeTrue();
23+
expect(catchHasBeenExecuted).toBeTrue();
24+
expect(finallyHasBeenExecuted).toBeTrue();
25+
});

0 commit comments

Comments
 (0)