Commit 854f28ce authored by Joshua Litt's avatar Joshua Litt Committed by Commit Bot

[top-level-await] Stop throwing exceptions with TLA.

Bug: v8:9970
Change-Id: I0e542fc63211e78800eab82257ccab9583305433
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1946534Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Joshua Litt <joshualitt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65351}
parent b7c67e0a
...@@ -40,7 +40,7 @@ struct InvokeParams { ...@@ -40,7 +40,7 @@ struct InvokeParams {
Isolate* isolate, Handle<Object> callable, Handle<Object> receiver, Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
int argc, Handle<Object>* argv, int argc, Handle<Object>* argv,
Execution::MessageHandling message_handling, Execution::MessageHandling message_handling,
MaybeHandle<Object>* exception_out); MaybeHandle<Object>* exception_out, bool reschedule_terminate);
static InvokeParams SetUpForRunMicrotasks(Isolate* isolate, static InvokeParams SetUpForRunMicrotasks(Isolate* isolate,
MicrotaskQueue* microtask_queue, MicrotaskQueue* microtask_queue,
...@@ -59,6 +59,7 @@ struct InvokeParams { ...@@ -59,6 +59,7 @@ struct InvokeParams {
bool is_construct; bool is_construct;
Execution::Target execution_target; Execution::Target execution_target;
bool reschedule_terminate;
}; };
// static // static
...@@ -77,6 +78,7 @@ InvokeParams InvokeParams::SetUpForNew(Isolate* isolate, ...@@ -77,6 +78,7 @@ InvokeParams InvokeParams::SetUpForNew(Isolate* isolate,
params.exception_out = nullptr; params.exception_out = nullptr;
params.is_construct = true; params.is_construct = true;
params.execution_target = Execution::Target::kCallable; params.execution_target = Execution::Target::kCallable;
params.reschedule_terminate = true;
return params; return params;
} }
...@@ -96,6 +98,7 @@ InvokeParams InvokeParams::SetUpForCall(Isolate* isolate, ...@@ -96,6 +98,7 @@ InvokeParams InvokeParams::SetUpForCall(Isolate* isolate,
params.exception_out = nullptr; params.exception_out = nullptr;
params.is_construct = false; params.is_construct = false;
params.execution_target = Execution::Target::kCallable; params.execution_target = Execution::Target::kCallable;
params.reschedule_terminate = true;
return params; return params;
} }
...@@ -103,7 +106,7 @@ InvokeParams InvokeParams::SetUpForCall(Isolate* isolate, ...@@ -103,7 +106,7 @@ InvokeParams InvokeParams::SetUpForCall(Isolate* isolate,
InvokeParams InvokeParams::SetUpForTryCall( InvokeParams InvokeParams::SetUpForTryCall(
Isolate* isolate, Handle<Object> callable, Handle<Object> receiver, Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
int argc, Handle<Object>* argv, Execution::MessageHandling message_handling, int argc, Handle<Object>* argv, Execution::MessageHandling message_handling,
MaybeHandle<Object>* exception_out) { MaybeHandle<Object>* exception_out, bool reschedule_terminate) {
InvokeParams params; InvokeParams params;
params.target = callable; params.target = callable;
params.receiver = NormalizeReceiver(isolate, receiver); params.receiver = NormalizeReceiver(isolate, receiver);
...@@ -115,6 +118,7 @@ InvokeParams InvokeParams::SetUpForTryCall( ...@@ -115,6 +118,7 @@ InvokeParams InvokeParams::SetUpForTryCall(
params.exception_out = exception_out; params.exception_out = exception_out;
params.is_construct = false; params.is_construct = false;
params.execution_target = Execution::Target::kCallable; params.execution_target = Execution::Target::kCallable;
params.reschedule_terminate = reschedule_terminate;
return params; return params;
} }
...@@ -134,6 +138,7 @@ InvokeParams InvokeParams::SetUpForRunMicrotasks( ...@@ -134,6 +138,7 @@ InvokeParams InvokeParams::SetUpForRunMicrotasks(
params.exception_out = exception_out; params.exception_out = exception_out;
params.is_construct = false; params.is_construct = false;
params.execution_target = Execution::Target::kRunMicrotasks; params.execution_target = Execution::Target::kRunMicrotasks;
params.reschedule_terminate = true;
return params; return params;
} }
...@@ -343,7 +348,7 @@ MaybeHandle<Object> InvokeWithTryCatch(Isolate* isolate, ...@@ -343,7 +348,7 @@ MaybeHandle<Object> InvokeWithTryCatch(Isolate* isolate,
} }
} }
if (is_termination) { if (is_termination && params.reschedule_terminate) {
// Reschedule terminate execution exception. // Reschedule terminate execution exception.
isolate->OptionalRescheduleException(false); isolate->OptionalRescheduleException(false);
} }
...@@ -386,16 +391,14 @@ MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor, ...@@ -386,16 +391,14 @@ MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
} }
// static // static
MaybeHandle<Object> Execution::TryCall(Isolate* isolate, MaybeHandle<Object> Execution::TryCall(
Handle<Object> callable, Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
Handle<Object> receiver, int argc, int argc, Handle<Object> argv[], MessageHandling message_handling,
Handle<Object> argv[], MaybeHandle<Object>* exception_out, bool reschedule_terminate) {
MessageHandling message_handling,
MaybeHandle<Object>* exception_out) {
return InvokeWithTryCatch( return InvokeWithTryCatch(
isolate, isolate, InvokeParams::SetUpForTryCall(
InvokeParams::SetUpForTryCall(isolate, callable, receiver, argc, argv, isolate, callable, receiver, argc, argv, message_handling,
message_handling, exception_out)); exception_out, reschedule_terminate));
} }
// static // static
......
...@@ -54,7 +54,7 @@ class Execution final : public AllStatic { ...@@ -54,7 +54,7 @@ class Execution final : public AllStatic {
V8_EXPORT_PRIVATE static MaybeHandle<Object> TryCall( V8_EXPORT_PRIVATE static MaybeHandle<Object> TryCall(
Isolate* isolate, Handle<Object> callable, Handle<Object> receiver, Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
int argc, Handle<Object> argv[], MessageHandling message_handling, int argc, Handle<Object> argv[], MessageHandling message_handling,
MaybeHandle<Object>* exception_out); MaybeHandle<Object>* exception_out, bool reschedule_terminate = true);
// Convenience method for performing RunMicrotasks // Convenience method for performing RunMicrotasks
static MaybeHandle<Object> TryRunMicrotasks( static MaybeHandle<Object> TryRunMicrotasks(
Isolate* isolate, MicrotaskQueue* microtask_queue, Isolate* isolate, MicrotaskQueue* microtask_queue,
......
...@@ -906,7 +906,9 @@ MaybeHandle<Object> SourceTextModule::InnerExecuteAsyncModule( ...@@ -906,7 +906,9 @@ MaybeHandle<Object> SourceTextModule::InnerExecuteAsyncModule(
Handle<Object> result; Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION( ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, isolate, result,
Execution::Call(isolate, resume, async_function_object, 0, nullptr), Execution::TryCall(isolate, resume, async_function_object, 0, nullptr,
Execution::MessageHandling::kKeepPending, nullptr,
false),
Object); Object);
return result; return result;
} }
...@@ -919,9 +921,21 @@ MaybeHandle<Object> SourceTextModule::ExecuteModule( ...@@ -919,9 +921,21 @@ MaybeHandle<Object> SourceTextModule::ExecuteModule(
Handle<JSFunction> resume( Handle<JSFunction> resume(
isolate->native_context()->generator_next_internal(), isolate); isolate->native_context()->generator_next_internal(), isolate);
Handle<Object> result; Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, Execution::Call(isolate, resume, generator, 0, nullptr), // With top_level_await, we need to catch any exceptions and reject
Object); // the top level capability.
if (FLAG_harmony_top_level_await) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
Execution::TryCall(isolate, resume, generator, 0, nullptr,
Execution::MessageHandling::kKeepPending, nullptr,
false),
Object);
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
Execution::Call(isolate, resume, generator, 0, nullptr), Object);
}
DCHECK(JSIteratorResult::cast(*result).done().BooleanValue(isolate)); DCHECK(JSIteratorResult::cast(*result).done().BooleanValue(isolate));
return handle(JSIteratorResult::cast(*result).value(), isolate); return handle(JSIteratorResult::cast(*result).value(), isolate);
} }
......
...@@ -258,49 +258,49 @@ TEST(ModuleEvaluationError1) { ...@@ -258,49 +258,49 @@ TEST(ModuleEvaluationError1) {
.FromJust()); .FromJust());
CHECK_EQ(Module::kInstantiated, module->GetStatus()); CHECK_EQ(Module::kInstantiated, module->GetStatus());
MaybeLocal<Value> result_1;
{ {
v8::TryCatch inner_try_catch(isolate); v8::TryCatch inner_try_catch(isolate);
result_1 = module->Evaluate(env.local()); MaybeLocal<Value> result = module->Evaluate(env.local());
CHECK_EQ(Module::kErrored, module->GetStatus()); CHECK_EQ(Module::kErrored, module->GetStatus());
Local<Value> exception = module->GetException(); Local<Value> exception = module->GetException();
CHECK(exception->StrictEquals(v8_str("boom"))); CHECK(exception->StrictEquals(v8_str("boom")));
ExpectInt32("Object.x", 1); ExpectInt32("Object.x", 1);
CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); if (i::FLAG_harmony_top_level_await) {
// With top level await, we do not throw and errored evaluation returns
// a rejected promise with the exception.
CHECK(!inner_try_catch.HasCaught());
Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked());
CHECK_EQ(promise->State(), v8::Promise::kRejected);
CHECK_EQ(promise->Result(), module->GetException());
} else {
CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
CHECK(result.IsEmpty());
}
} }
MaybeLocal<Value> result_2;
{ {
v8::TryCatch inner_try_catch(isolate); v8::TryCatch inner_try_catch(isolate);
result_2 = module->Evaluate(env.local()); MaybeLocal<Value> result = module->Evaluate(env.local());
CHECK_EQ(Module::kErrored, module->GetStatus()); CHECK_EQ(Module::kErrored, module->GetStatus());
Local<Value> exception = module->GetException(); Local<Value> exception = module->GetException();
CHECK(exception->StrictEquals(v8_str("boom"))); CHECK(exception->StrictEquals(v8_str("boom")));
ExpectInt32("Object.x", 1); ExpectInt32("Object.x", 1);
if (i::FLAG_harmony_top_level_await) { if (i::FLAG_harmony_top_level_await) {
// With top level await we do not rethrow the exception. // With top level await, we do not throw and errored evaluation returns
// a rejected promise with the exception.
CHECK(!inner_try_catch.HasCaught()); CHECK(!inner_try_catch.HasCaught());
Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked());
CHECK_EQ(promise->State(), v8::Promise::kRejected);
CHECK_EQ(promise->Result(), module->GetException());
} else { } else {
CHECK(inner_try_catch.HasCaught()); CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
CHECK(result.IsEmpty());
} }
} }
if (i::FLAG_harmony_top_level_await) {
// With top level await, errored evaluation returns a rejected promise
// with the exception.
Local<Promise> promise_1 =
Local<Promise>::Cast(result_1.ToLocalChecked());
Local<Promise> promise_2 =
Local<Promise>::Cast(result_2.ToLocalChecked());
CHECK_EQ(promise_1->State(), v8::Promise::kRejected);
CHECK_EQ(promise_2->State(), v8::Promise::kRejected);
CHECK_EQ(promise_1->Result(), module->GetException());
CHECK_EQ(promise_2->Result(), module->GetException());
} else {
CHECK(result_1.IsEmpty() && result_2.IsEmpty());
}
CHECK(!try_catch.HasCaught()); CHECK(!try_catch.HasCaught());
} }
...@@ -342,15 +342,25 @@ TEST(ModuleEvaluationError2) { ...@@ -342,15 +342,25 @@ TEST(ModuleEvaluationError2) {
.FromJust()); .FromJust());
CHECK_EQ(Module::kInstantiated, failure_module->GetStatus()); CHECK_EQ(Module::kInstantiated, failure_module->GetStatus());
MaybeLocal<Value> result_1;
{ {
v8::TryCatch inner_try_catch(isolate); v8::TryCatch inner_try_catch(isolate);
result_1 = failure_module->Evaluate(env.local()); MaybeLocal<Value> result = failure_module->Evaluate(env.local());
CHECK_EQ(Module::kErrored, failure_module->GetStatus()); CHECK_EQ(Module::kErrored, failure_module->GetStatus());
Local<Value> exception = failure_module->GetException(); Local<Value> exception = failure_module->GetException();
CHECK(exception->StrictEquals(v8_str("boom"))); CHECK(exception->StrictEquals(v8_str("boom")));
CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); if (i::FLAG_harmony_top_level_await) {
// With top level await, we do not throw and errored evaluation returns
// a rejected promise with the exception.
CHECK(!inner_try_catch.HasCaught());
Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked());
CHECK_EQ(promise->State(), v8::Promise::kRejected);
CHECK_EQ(promise->Result(), failure_module->GetException());
} else {
CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
CHECK(result.IsEmpty());
}
} }
Local<String> dependent_text = Local<String> dependent_text =
...@@ -367,39 +377,28 @@ TEST(ModuleEvaluationError2) { ...@@ -367,39 +377,28 @@ TEST(ModuleEvaluationError2) {
.FromJust()); .FromJust());
CHECK_EQ(Module::kInstantiated, dependent_module->GetStatus()); CHECK_EQ(Module::kInstantiated, dependent_module->GetStatus());
MaybeLocal<Value> result_2;
{ {
v8::TryCatch inner_try_catch(isolate); v8::TryCatch inner_try_catch(isolate);
result_2 = dependent_module->Evaluate(env.local()); MaybeLocal<Value> result = dependent_module->Evaluate(env.local());
CHECK_EQ(Module::kErrored, dependent_module->GetStatus()); CHECK_EQ(Module::kErrored, dependent_module->GetStatus());
Local<Value> exception = dependent_module->GetException(); Local<Value> exception = dependent_module->GetException();
CHECK(exception->StrictEquals(v8_str("boom"))); CHECK(exception->StrictEquals(v8_str("boom")));
CHECK_EQ(exception, failure_module->GetException()); CHECK_EQ(exception, failure_module->GetException());
if (i::FLAG_harmony_top_level_await) { if (i::FLAG_harmony_top_level_await) {
// With top level await we do not rethrow the exception. // With top level await, we do not throw and errored evaluation returns
// a rejected promise with the exception.
CHECK(!inner_try_catch.HasCaught()); CHECK(!inner_try_catch.HasCaught());
Local<Promise> promise = Local<Promise>::Cast(result.ToLocalChecked());
CHECK_EQ(promise->State(), v8::Promise::kRejected);
CHECK_EQ(promise->Result(), failure_module->GetException());
} else { } else {
CHECK(inner_try_catch.HasCaught()); CHECK(inner_try_catch.HasCaught());
CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom"))); CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
CHECK(result.IsEmpty());
} }
} }
if (i::FLAG_harmony_top_level_await) {
// With top level await, errored evaluation returns a rejected promise
// with the exception.
Local<Promise> promise_1 =
Local<Promise>::Cast(result_1.ToLocalChecked());
Local<Promise> promise_2 =
Local<Promise>::Cast(result_2.ToLocalChecked());
CHECK_EQ(promise_1->State(), v8::Promise::kRejected);
CHECK_EQ(promise_2->State(), v8::Promise::kRejected);
CHECK_EQ(promise_1->Result(), failure_module->GetException());
CHECK_EQ(promise_2->Result(), failure_module->GetException());
} else {
CHECK(result_1.IsEmpty() && result_2.IsEmpty());
}
CHECK(!try_catch.HasCaught()); CHECK(!try_catch.HasCaught());
} }
i::FLAG_harmony_top_level_await = prev_top_level_await; i::FLAG_harmony_top_level_await = prev_top_level_await;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment