Skip to content

Commit 5706831

Browse files
committed
LibJS: Make run_executable() return simple ThrowCompletionOr<Value>
We don't need to return two values; running an executable only ever produces a throw completion, or a normal completion, i.e a Value. This necessitated a few minor changes, such as adding a way to check if a JS::Cell is a GeneratorResult.
1 parent 2f7797f commit 5706831

File tree

10 files changed

+37
-51
lines changed

10 files changed

+37
-51
lines changed

Libraries/LibJS/Bytecode/Interpreter.cpp

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,7 @@ ThrowCompletionOr<Value> Interpreter::run(Script& script_record, GC::Ptr<Environ
256256
// 13. If result.[[Type]] is normal, then
257257
if (executable) {
258258
// a. Set result to Completion(Evaluation of script).
259-
auto result_or_error = run_executable(*script_context, *executable, {}, {});
260-
if (result_or_error.value.is_error())
261-
result = result_or_error.value.release_error();
262-
else {
263-
result = result_or_error.return_register_value.is_special_empty_value() ? normal_completion(js_undefined()) : result_or_error.return_register_value;
264-
}
259+
result = run_executable(*script_context, *executable, {}, {});
265260

266261
// b. If result is a normal completion and result.[[Value]] is empty, then
267262
if (result.type() == Completion::Type::Normal && result.value().is_special_empty_value()) {
@@ -707,7 +702,7 @@ Utf16FlyString const& Interpreter::get_identifier(IdentifierTableIndex index) co
707702
return m_running_execution_context->identifier_table.data()[index.value];
708703
}
709704

710-
Interpreter::ResultAndReturnRegister Interpreter::run_executable(ExecutionContext& context, Executable& executable, Optional<size_t> entry_point, Value initial_accumulator_value)
705+
ThrowCompletionOr<Value> Interpreter::run_executable(ExecutionContext& context, Executable& executable, Optional<size_t> entry_point, Value initial_accumulator_value)
711706
{
712707
dbgln_if(JS_BYTECODE_DEBUG, "Bytecode::Interpreter will run unit {}", &executable);
713708

@@ -754,17 +749,23 @@ Interpreter::ResultAndReturnRegister Interpreter::run_executable(ExecutionContex
754749
}
755750
}
756751

757-
auto return_value = js_undefined();
758-
if (!reg(Register::return_value()).is_special_empty_value())
759-
return_value = reg(Register::return_value());
752+
Value return_value;
753+
if (auto return_register_value = reg(Register::return_value()); !return_register_value.is_special_empty_value())
754+
return_value = return_register_value;
755+
else {
756+
return_value = reg(Register::accumulator());
757+
if (return_value.is_special_empty_value())
758+
return_value = js_undefined();
759+
}
760+
760761
auto exception = reg(Register::exception());
761762

762763
vm().run_queued_promise_jobs();
763764
vm().finish_execution_generation();
764765

765-
if (!exception.is_special_empty_value())
766-
return { throw_completion(exception), registers_and_constants_and_locals_and_arguments[0] };
767-
return { return_value, registers_and_constants_and_locals_and_arguments[0] };
766+
if (!exception.is_special_empty_value()) [[unlikely]]
767+
return throw_completion(exception);
768+
return return_value;
768769
}
769770

770771
void Interpreter::enter_unwind_context()

Libraries/LibJS/Bytecode/Interpreter.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,10 @@ class JS_API Interpreter {
3636

3737
ThrowCompletionOr<Value> run(ExecutionContext& context, Executable& executable, Optional<size_t> entry_point = {}, Value initial_accumulator_value = js_special_empty_value())
3838
{
39-
auto result_and_return_register = run_executable(context, executable, entry_point, initial_accumulator_value);
40-
return move(result_and_return_register.value);
39+
return run_executable(context, executable, entry_point, initial_accumulator_value);
4140
}
4241

43-
struct ResultAndReturnRegister {
44-
ThrowCompletionOr<Value> value;
45-
Value return_register_value;
46-
};
47-
ResultAndReturnRegister run_executable(ExecutionContext&, Executable&, Optional<size_t> entry_point, Value initial_accumulator_value = js_special_empty_value());
42+
ThrowCompletionOr<Value> run_executable(ExecutionContext&, Executable&, Optional<size_t> entry_point, Value initial_accumulator_value = js_special_empty_value());
4843

4944
ALWAYS_INLINE Value& accumulator() { return reg(Register::accumulator()); }
5045
ALWAYS_INLINE Value& saved_return_value() { return reg(Register::saved_return_value()); }

Libraries/LibJS/Heap/Cell.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class JS_API Cell : public GC::Cell {
1818
public:
1919
virtual void initialize(Realm&);
2020

21+
virtual bool is_generator_result() const { return false; }
22+
2123
ALWAYS_INLINE VM& vm() const { return *reinterpret_cast<VM*>(private_data()); }
2224
};
2325

Libraries/LibJS/Runtime/AbstractOperations.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -735,11 +735,7 @@ ThrowCompletionOr<Value> perform_eval(VM& vm, Value x, CallerMode strict_caller,
735735

736736
Optional<Value> eval_result;
737737

738-
auto result_or_error = vm.bytecode_interpreter().run_executable(*eval_context, *executable, {});
739-
if (result_or_error.value.is_error())
740-
return result_or_error.value.release_error();
741-
742-
eval_result = result_or_error.return_register_value;
738+
eval_result = TRY(vm.bytecode_interpreter().run_executable(*eval_context, *executable, {}));
743739

744740
// 32. If result.[[Type]] is normal and result.[[Value]] is empty, then
745741
// a. Set result to NormalCompletion(undefined).

Libraries/LibJS/Runtime/AsyncGenerator.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,13 @@ void AsyncGenerator::execute(VM& vm, Completion completion)
156156
while (true) {
157157
// Loosely based on step 4 of https://tc39.es/ecma262/#sec-asyncgeneratorstart
158158
auto generated_value = [](Value value) -> Value {
159-
if (value.is_cell())
159+
if (value.is_cell() && value.as_cell().is_generator_result())
160160
return static_cast<GeneratorResult const&>(value.as_cell()).result();
161161
return value.is_special_empty_value() ? js_undefined() : value;
162162
};
163163

164164
auto generated_continuation = [&](Value value) -> Optional<size_t> {
165-
if (value.is_cell()) {
165+
if (value.is_cell() && value.as_cell().is_generator_result()) {
166166
auto number_value = static_cast<GeneratorResult const&>(value.as_cell()).continuation();
167167
if (number_value.is_null())
168168
return {};
@@ -172,7 +172,7 @@ void AsyncGenerator::execute(VM& vm, Completion completion)
172172
};
173173

174174
auto generated_is_await = [](Value value) -> bool {
175-
if (value.is_cell())
175+
if (value.is_cell() && value.as_cell().is_generator_result())
176176
return static_cast<GeneratorResult const&>(value.as_cell()).is_await();
177177
return false;
178178
};
@@ -186,9 +186,8 @@ void AsyncGenerator::execute(VM& vm, Completion completion)
186186
// We should never enter `execute` again after the generator is complete.
187187
VERIFY(continuation_address.has_value());
188188

189-
auto next_result = bytecode_interpreter.run_executable(vm.running_execution_context(), *m_generating_function->bytecode_executable(), continuation_address, completion_cell);
189+
auto result_value = bytecode_interpreter.run_executable(vm.running_execution_context(), *m_generating_function->bytecode_executable(), continuation_address, completion_cell);
190190

191-
auto result_value = move(next_result.value);
192191
if (!result_value.is_throw_completion()) {
193192
m_previous_value = result_value.release_value();
194193
auto value = generated_value(m_previous_value);

Libraries/LibJS/Runtime/ECMAScriptFunctionObject.cpp

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ void async_block_start(VM& vm, T const& async_body, PromiseCapability const& pro
823823
if (maybe_executable.is_error())
824824
result = maybe_executable.release_error();
825825
else
826-
result = vm.bytecode_interpreter().run_executable(vm.running_execution_context(), *maybe_executable.value(), {}).value;
826+
result = vm.bytecode_interpreter().run_executable(vm.running_execution_context(), *maybe_executable.value(), {});
827827
}
828828
// c. Else,
829829
else {
@@ -886,13 +886,7 @@ template void async_function_start(VM&, PromiseCapability const&, GC::Function<C
886886
// 15.8.4 Runtime Semantics: EvaluateAsyncFunctionBody, https://tc39.es/ecma262/#sec-runtime-semantics-evaluatefunctionbody
887887
ThrowCompletionOr<Value> ECMAScriptFunctionObject::ordinary_call_evaluate_body(VM& vm, ExecutionContext& context)
888888
{
889-
auto result_and_frame = vm.bytecode_interpreter().run_executable(context, *bytecode_executable(), {});
890-
891-
if (result_and_frame.value.is_error()) [[unlikely]] {
892-
return result_and_frame.value.release_error();
893-
}
894-
895-
auto result = result_and_frame.value.release_value();
889+
auto result = TRY(vm.bytecode_interpreter().run_executable(context, *bytecode_executable(), {}));
896890

897891
// NOTE: Running the bytecode should eventually return a completion.
898892
// Until it does, we assume "return" and include the undefined fallback from the call site.

Libraries/LibJS/Runtime/GeneratorObject.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,13 @@ ThrowCompletionOr<GeneratorObject::IterationResult> GeneratorObject::execute(VM&
8484
// Loosely based on step 4 of https://tc39.es/ecma262/#sec-generatorstart mixed with https://tc39.es/ecma262/#sec-generatoryield at the end.
8585

8686
auto generated_value = [](Value value) -> Value {
87-
if (value.is_cell())
87+
if (value.is_cell() && value.as_cell().is_generator_result())
8888
return static_cast<GeneratorResult const&>(value.as_cell()).result();
8989
return value.is_special_empty_value() ? js_undefined() : value;
9090
};
9191

9292
auto generated_continuation = [&](Value value) -> Optional<size_t> {
93-
if (value.is_cell()) {
93+
if (value.is_cell() && value.as_cell().is_generator_result()) {
9494
auto number_value = static_cast<GeneratorResult const&>(value.as_cell()).continuation();
9595
if (number_value.is_null())
9696
return {};
@@ -108,11 +108,10 @@ ThrowCompletionOr<GeneratorObject::IterationResult> GeneratorObject::execute(VM&
108108
// We should never enter `execute` again after the generator is complete.
109109
VERIFY(next_block.has_value());
110110

111-
auto next_result = bytecode_interpreter.run_executable(vm.running_execution_context(), *m_generating_function->bytecode_executable(), next_block, compleion_cell);
111+
auto result_value = bytecode_interpreter.run_executable(vm.running_execution_context(), *m_generating_function->bytecode_executable(), next_block, compleion_cell);
112112

113113
vm.pop_execution_context();
114114

115-
auto result_value = move(next_result.value);
116115
if (result_value.is_throw_completion()) {
117116
// Uncaught exceptions disable the generator.
118117
m_generator_state = GeneratorState::Completed;

Libraries/LibJS/Runtime/GeneratorResult.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class GeneratorResult final : public Cell {
3131
[[nodiscard]] bool is_await() const { return m_is_await; }
3232

3333
private:
34+
virtual bool is_generator_result() const override { return true; }
3435
virtual void visit_edges(Cell::Visitor& visitor) override;
3536

3637
bool m_is_await { false };

Libraries/LibJS/Runtime/ShadowRealm.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,11 @@ ThrowCompletionOr<Value> perform_shadow_realm_eval(VM& vm, Value source, Realm&
175175
// 11. If result.[[Type]] is normal, then
176176
if (!eval_result.is_throw_completion()) {
177177
// a. Set result to the result of evaluating body.
178-
auto result_and_return_register = vm.bytecode_interpreter().run_executable(*eval_context, *executable, {});
179-
if (result_and_return_register.value.is_error()) {
180-
result = result_and_return_register.value.release_error();
178+
auto result_or_error = vm.bytecode_interpreter().run_executable(*eval_context, *executable, {});
179+
if (result_or_error.is_error()) {
180+
result = result_or_error.release_error();
181181
} else {
182-
// Resulting value is in the accumulator.
183-
result = result_and_return_register.return_register_value.is_special_empty_value() ? js_undefined() : result_and_return_register.return_register_value;
182+
result = result_or_error.value();
184183
}
185184
}
186185

Libraries/LibJS/SourceTextModule.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -743,11 +743,11 @@ ThrowCompletionOr<void> SourceTextModule::execute_module(VM& vm, GC::Ptr<Promise
743743
// c. Let result be the result of evaluating module.[[ECMAScriptCode]].
744744
Completion result;
745745

746-
auto result_and_return_register = vm.bytecode_interpreter().run_executable(*module_context, *executable, {});
747-
if (result_and_return_register.value.is_error()) {
748-
result = result_and_return_register.value.release_error();
746+
auto result_or_error = vm.bytecode_interpreter().run_executable(*module_context, *executable, {});
747+
if (result_or_error.is_error()) {
748+
result = result_or_error.release_error();
749749
} else {
750-
result = result_and_return_register.return_register_value.is_special_empty_value() ? js_undefined() : result_and_return_register.return_register_value;
750+
result = result_or_error.value().is_special_empty_value() ? js_undefined() : result_or_error.release_value();
751751
}
752752

753753
// d. Let env be moduleContext's LexicalEnvironment.

0 commit comments

Comments
 (0)