Revert "[top-level-await] Remove --harmony-top-level-await"

This reverts commit 3ee4804f83.

Reason for revert: breaks blink_unit_tests:
https://ci.chromium.org/ui/p/v8/builders/ci/V8%20Blink%20Linux/15074/overview

Original change's description:
> [top-level-await] Remove --harmony-top-level-await
>
> TLA has been shipped since v8.9.
>
> Bug: v8:9344, chromium:1271114
> Change-Id: Ibebf21da8bacb1f0d212390133847495ad8553e5
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3307103
> Commit-Queue: Shu-yu Guo <syg@chromium.org>
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Marja Hölttä <marja@chromium.org>
> Reviewed-by: Igor Sheludko <ishell@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#78169}

Bug: v8:9344, chromium:1271114
Change-Id: I0874bcaba18fde3b48f5ef7eeae89f2fa4978d51
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3308422
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78170}
This commit is contained in:
Adam Klein 2021-11-30 22:12:54 +00:00 committed by V8 LUCI CQ
parent 3ee4804f83
commit 6f60dea6b8
26 changed files with 945 additions and 684 deletions

View File

@ -37,6 +37,7 @@ namespace internal {
T(AwaitNotInAsyncContext, \
"await is only valid in async functions and the top level bodies of " \
"modules") \
T(AwaitNotInAsyncFunction, "await is only valid in async function") \
T(AwaitNotInDebugEvaluate, \
"await can not be used when evaluating code " \
"while paused in the debugger") \

View File

@ -1137,10 +1137,14 @@ MaybeLocal<Value> Shell::JSONModuleEvaluationSteps(Local<Context> context,
CHECK(!try_catch.HasCaught());
CHECK(!result.IsNothing() && result.FromJust());
Local<Promise::Resolver> resolver =
Promise::Resolver::New(context).ToLocalChecked();
resolver->Resolve(context, Undefined(isolate)).ToChecked();
return resolver->GetPromise();
if (i::FLAG_harmony_top_level_await) {
Local<Promise::Resolver> resolver =
Promise::Resolver::New(context).ToLocalChecked();
resolver->Resolve(context, Undefined(isolate)).ToChecked();
return resolver->GetPromise();
}
return Undefined(isolate);
}
struct DynamicImportData {
@ -1318,7 +1322,7 @@ void Shell::DoHostImportModuleDynamically(void* import_data) {
if (root_module->InstantiateModule(realm, ResolveModuleCallback)
.FromMaybe(false)) {
maybe_result = root_module->Evaluate(realm);
CHECK(!maybe_result.IsEmpty());
CHECK_IMPLIES(i::FLAG_harmony_top_level_await, !maybe_result.IsEmpty());
EmptyMessageQueues(isolate);
}
@ -1330,21 +1334,28 @@ void Shell::DoHostImportModuleDynamically(void* import_data) {
}
Local<Value> module_namespace = root_module->GetModuleNamespace();
Local<Promise> result_promise(result.As<Promise>());
if (i::FLAG_harmony_top_level_await) {
Local<Promise> result_promise(result.As<Promise>());
// Setup callbacks, and then chain them to the result promise.
// ModuleResolutionData will be deleted by the callbacks.
auto module_resolution_data =
new ModuleResolutionData(isolate, module_namespace, resolver);
Local<v8::External> edata = External::New(isolate, module_resolution_data);
Local<Function> callback_success;
CHECK(Function::New(realm, ModuleResolutionSuccessCallback, edata)
.ToLocal(&callback_success));
Local<Function> callback_failure;
CHECK(Function::New(realm, ModuleResolutionFailureCallback, edata)
.ToLocal(&callback_failure));
result_promise->Then(realm, callback_success, callback_failure)
.ToLocalChecked();
// Setup callbacks, and then chain them to the result promise.
// ModuleResolutionData will be deleted by the callbacks.
auto module_resolution_data =
new ModuleResolutionData(isolate, module_namespace, resolver);
Local<v8::External> edata = External::New(isolate, module_resolution_data);
Local<Function> callback_success;
CHECK(Function::New(realm, ModuleResolutionSuccessCallback, edata)
.ToLocal(&callback_success));
Local<Function> callback_failure;
CHECK(Function::New(realm, ModuleResolutionFailureCallback, edata)
.ToLocal(&callback_failure));
result_promise->Then(realm, callback_success, callback_failure)
.ToLocalChecked();
} else {
// TODO(cbruni): Clean up exception handling after introducing new
// API for evaluating async modules.
DCHECK(!try_catch.HasCaught());
resolver->Resolve(realm, module_namespace).ToChecked();
}
}
bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
@ -1376,7 +1387,7 @@ bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
if (root_module->InstantiateModule(realm, ResolveModuleCallback)
.FromMaybe(false)) {
maybe_result = root_module->Evaluate(realm);
CHECK(!maybe_result.IsEmpty());
CHECK_IMPLIES(i::FLAG_harmony_top_level_await, !maybe_result.IsEmpty());
EmptyMessageQueues(isolate);
}
Local<Value> result;
@ -1385,27 +1396,28 @@ bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
ReportException(isolate, &try_catch);
return false;
}
// Loop until module execution finishes
// TODO(cbruni): This is a bit wonky. "Real" engines would not be
// able to just busy loop waiting for execution to finish.
Local<Promise> result_promise(result.As<Promise>());
while (result_promise->State() == Promise::kPending) {
isolate->PerformMicrotaskCheckpoint();
}
if (result_promise->State() == Promise::kRejected) {
// If the exception has been caught by the promise pipeline, we rethrow
// here in order to ReportException.
// TODO(cbruni): Clean this up after we create a new API for the case
// where TLA is enabled.
if (!try_catch.HasCaught()) {
isolate->ThrowException(result_promise->Result());
} else {
DCHECK_EQ(try_catch.Exception(), result_promise->Result());
if (i::FLAG_harmony_top_level_await) {
// Loop until module execution finishes
// TODO(cbruni): This is a bit wonky. "Real" engines would not be
// able to just busy loop waiting for execution to finish.
Local<Promise> result_promise(result.As<Promise>());
while (result_promise->State() == Promise::kPending) {
isolate->PerformMicrotaskCheckpoint();
}
if (result_promise->State() == Promise::kRejected) {
// If the exception has been caught by the promise pipeline, we rethrow
// here in order to ReportException.
// TODO(cbruni): Clean this up after we create a new API for the case
// where TLA is enabled.
if (!try_catch.HasCaught()) {
isolate->ThrowException(result_promise->Result());
} else {
DCHECK_EQ(try_catch.Exception(), result_promise->Result());
}
ReportException(isolate, &try_catch);
return false;
}
ReportException(isolate, &try_catch);
return false;
}
DCHECK(!try_catch.HasCaught());

View File

@ -336,6 +336,7 @@ DEFINE_BOOL(harmony_shipping, true, "enable all shipped harmony features")
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
V(harmony_atomics, "harmony atomics") \
V(harmony_private_brand_checks, "harmony private brand checks") \
V(harmony_top_level_await, "harmony top level await") \
V(harmony_relative_indexing_methods, "harmony relative indexing methods") \
V(harmony_error_cause, "harmony error cause property") \
V(harmony_object_has_own, "harmony Object.hasOwn") \

View File

@ -4394,6 +4394,7 @@ void Genesis::InitializeCallSiteBuiltins() {
#define EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(id) \
void Genesis::InitializeGlobal_##id() {}
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_top_level_await)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_import_assertions)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_private_brand_checks)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_class_static_blocks)

View File

@ -247,7 +247,11 @@ MaybeHandle<Object> Module::Evaluate(Isolate* isolate, Handle<Module> module) {
PrintStatusMessage(*module, "Evaluating module ");
#endif // DEBUG
STACK_CHECK(isolate, MaybeHandle<Object>());
return Module::EvaluateMaybeAsync(isolate, module);
if (FLAG_harmony_top_level_await) {
return Module::EvaluateMaybeAsync(isolate, module);
} else {
return Module::InnerEvaluate(isolate, module);
}
}
MaybeHandle<Object> Module::EvaluateMaybeAsync(Isolate* isolate,
@ -296,6 +300,32 @@ MaybeHandle<Object> Module::EvaluateMaybeAsync(Isolate* isolate,
}
}
MaybeHandle<Object> Module::InnerEvaluate(Isolate* isolate,
Handle<Module> module) {
if (module->status() == kErrored) {
isolate->Throw(module->GetException());
return MaybeHandle<Object>();
} else if (module->status() == kEvaluated) {
return isolate->factory()->undefined_value();
}
// InnerEvaluate can be called both to evaluate top level modules without
// the harmony_top_level_await flag and recursively to evaluate
// SyntheticModules in the dependency graphs of SourceTextModules.
//
// However, SyntheticModules transition directly to 'Evaluated,' so we should
// never see an 'Evaluating' module at this point.
CHECK_EQ(module->status(), kLinked);
if (module->IsSourceTextModule()) {
return SourceTextModule::Evaluate(isolate,
Handle<SourceTextModule>::cast(module));
} else {
return SyntheticModule::Evaluate(isolate,
Handle<SyntheticModule>::cast(module));
}
}
Handle<JSModuleNamespace> Module::GetModuleNamespace(Isolate* isolate,
Handle<Module> module) {
Handle<HeapObject> object(module->module_namespace(), isolate);

View File

@ -119,6 +119,9 @@ class Module : public TorqueGeneratedModule<Module, HeapObject> {
static V8_WARN_UNUSED_RESULT MaybeHandle<Object> EvaluateMaybeAsync(
Isolate* isolate, Handle<Module> module);
static V8_WARN_UNUSED_RESULT MaybeHandle<Object> InnerEvaluate(
Isolate* isolate, Handle<Module> module);
// Set module's status back to kUnlinked and reset other internal state.
// This is used when instantiation fails.
static void Reset(Isolate* isolate, Handle<Module> module);

View File

@ -1008,12 +1008,20 @@ MaybeHandle<Object> SourceTextModule::ExecuteModule(
isolate->native_context()->generator_next_internal(), isolate);
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
Execution::TryCall(isolate, resume, generator, 0, nullptr,
Execution::MessageHandling::kKeepPending, nullptr,
false),
Object);
// With top_level_await, we need to catch any exceptions and reject
// 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));
return handle(JSIteratorResult::cast(*result).value(), isolate);
}

View File

@ -119,20 +119,22 @@ MaybeHandle<Object> SyntheticModule::Evaluate(Isolate* isolate,
Handle<Object> result_from_callback = Utils::OpenHandle(*result);
Handle<JSPromise> capability;
if (result_from_callback->IsJSPromise()) {
capability = Handle<JSPromise>::cast(result_from_callback);
} else {
// The host's evaluation steps should have returned a resolved Promise,
// but as an allowance to hosts that have not yet finished the migration
// to top-level await, create a Promise if the callback result didn't give
// us one.
capability = isolate->factory()->NewJSPromise();
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
.ToHandleChecked();
}
if (FLAG_harmony_top_level_await) {
Handle<JSPromise> capability;
if (result_from_callback->IsJSPromise()) {
capability = Handle<JSPromise>::cast(result_from_callback);
} else {
// The host's evaluation steps should have returned a resolved Promise,
// but as an allowance to hosts that have not yet finished the migration
// to top-level await, create a Promise if the callback result didn't give
// us one.
capability = isolate->factory()->NewJSPromise();
JSPromise::Resolve(capability, isolate->factory()->undefined_value())
.ToHandleChecked();
}
module->set_top_level_capability(*capability);
module->set_top_level_capability(*capability);
}
return result_from_callback;
}

View File

@ -36,6 +36,7 @@ UnoptimizedCompileFlags::UnoptimizedCompileFlags(Isolate* isolate,
set_allow_lazy_compile(true);
set_collect_source_positions(!FLAG_enable_lazy_source_positions ||
isolate->NeedsDetailedOptimizedCodeLineInfo());
set_allow_harmony_top_level_await(FLAG_harmony_top_level_await);
}
// static

View File

@ -60,6 +60,7 @@ class Zone;
V(allow_natives_syntax, bool, 1, _) \
V(allow_lazy_compile, bool, 1, _) \
V(collect_source_positions, bool, 1, _) \
V(allow_harmony_top_level_await, bool, 1, _) \
V(is_repl_mode, bool, 1, _)
class V8_EXPORT_PRIVATE UnoptimizedCompileFlags {

View File

@ -923,9 +923,12 @@ class ParserBase {
if (flags().parsing_while_debugging() == ParsingWhileDebugging::kYes) {
ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitNotInDebugEvaluate);
} else {
} else if (flags().allow_harmony_top_level_await()) {
ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitNotInAsyncContext);
} else {
ReportMessageAt(scanner()->location(),
MessageTemplate::kAwaitNotInAsyncFunction);
}
return;
}
@ -1065,7 +1068,8 @@ class ParserBase {
return IsResumableFunction(function_state_->kind());
}
bool is_await_allowed() const {
return is_async_function() || IsModule(function_state_->kind());
return is_async_function() || (flags().allow_harmony_top_level_await() &&
IsModule(function_state_->kind()));
}
bool is_await_as_identifier_disallowed() {
return flags().is_module() ||

View File

@ -587,27 +587,31 @@ FunctionLiteral* Parser::DoParseProgram(Isolate* isolate, ParseInfo* info) {
kNoSourcePosition, FunctionKind::kGeneratorFunction);
body.Add(
factory()->NewExpressionStatement(initial_yield, kNoSourcePosition));
// First parse statements into a buffer. Then, if there was a
// top level await, create an inner block and rewrite the body of the
// module as an async function. Otherwise merge the statements back
// into the main body.
BlockT block = impl()->NullBlock();
{
StatementListT statements(pointer_buffer());
ParseModuleItemList(&statements);
// Modules will always have an initial yield. If there are any
// additional suspends, i.e. awaits, then we treat the module as an
// AsyncModule.
if (function_state.suspend_count() > 1) {
scope->set_is_async_module();
block = factory()->NewBlock(true, statements);
} else {
statements.MergeInto(&body);
if (flags().allow_harmony_top_level_await()) {
// First parse statements into a buffer. Then, if there was a
// top level await, create an inner block and rewrite the body of the
// module as an async function. Otherwise merge the statements back
// into the main body.
BlockT block = impl()->NullBlock();
{
StatementListT statements(pointer_buffer());
ParseModuleItemList(&statements);
// Modules will always have an initial yield. If there are any
// additional suspends, i.e. awaits, then we treat the module as an
// AsyncModule.
if (function_state.suspend_count() > 1) {
scope->set_is_async_module();
block = factory()->NewBlock(true, statements);
} else {
statements.MergeInto(&body);
}
}
}
if (IsAsyncModule(scope->function_kind())) {
impl()->RewriteAsyncFunctionBody(
&body, block, factory()->NewUndefinedLiteral(kNoSourcePosition));
if (IsAsyncModule(scope->function_kind())) {
impl()->RewriteAsyncFunctionBody(
&body, block, factory()->NewUndefinedLiteral(kNoSourcePosition));
}
} else {
ParseModuleItemList(&body);
}
if (!has_error() &&
!module()->Validate(this->scope()->AsModuleScope(),

View File

@ -6,6 +6,7 @@
wrap: no
module: yes
top level: yes
top level await: yes
---
snippet: "

View File

@ -83,7 +83,7 @@ bytecodes: [
/* 48 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
/* 53 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 58 E> */ B(LdaKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(286),
B(Wide), B(LdaSmi), I16(287),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -115,7 +115,7 @@ bytecodes: [
/* 41 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(LdaKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(285),
B(Wide), B(LdaSmi), I16(286),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -147,7 +147,7 @@ bytecodes: [
/* 48 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
/* 53 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 58 E> */ B(LdaKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(286),
B(Wide), B(LdaSmi), I16(287),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -179,7 +179,7 @@ bytecodes: [
/* 41 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(LdaKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(285),
B(Wide), B(LdaSmi), I16(286),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),

View File

@ -56,7 +56,7 @@ bytecodes: [
/* 44 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
/* 49 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 54 E> */ B(LdaKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(284),
B(Wide), B(LdaSmi), I16(285),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -89,7 +89,7 @@ bytecodes: [
/* 44 E> */ B(StaKeyedPropertyAsDefine), R(this), R(0), U8(0),
/* 49 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 54 E> */ B(LdaKeyedProperty), R(this), U8(2),
B(Wide), B(LdaSmi), I16(284),
B(Wide), B(LdaSmi), I16(285),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),

View File

@ -24,7 +24,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(1),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -59,13 +59,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(284),
B(Wide), B(LdaSmi), I16(285),
B(Star3),
B(LdaConstant), U8(1),
B(Star4),
@ -97,13 +97,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 61 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(284),
B(Wide), B(LdaSmi), I16(285),
B(Star3),
B(LdaConstant), U8(1),
B(Star4),
@ -143,7 +143,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -165,7 +165,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star3),
B(LdaConstant), U8(0),
B(Star4),
@ -180,7 +180,7 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star2),
B(LdaConstant), U8(0),
B(Star3),
@ -214,13 +214,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(286),
B(Wide), B(LdaSmi), I16(287),
B(Star3),
B(LdaConstant), U8(1),
B(Star4),
@ -251,13 +251,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 58 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(285),
B(Wide), B(LdaSmi), I16(286),
B(Star3),
B(LdaConstant), U8(1),
B(Star4),
@ -288,13 +288,13 @@ bytecodes: [
B(TestReferenceEqual), R(this),
B(Mov), R(this), R(0),
B(JumpIfTrue), U8(16),
B(Wide), B(LdaSmi), I16(278),
B(Wide), B(LdaSmi), I16(279),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),
/* 65 E> */ B(CallRuntime), U16(Runtime::kNewTypeError), R(1), U8(2),
B(Throw),
B(Wide), B(LdaSmi), I16(286),
B(Wide), B(LdaSmi), I16(287),
B(Star3),
B(LdaConstant), U8(1),
B(Star4),
@ -323,7 +323,7 @@ bytecode array length: 19
bytecodes: [
/* 46 S> */ B(LdaImmutableCurrentContextSlot), U8(3),
/* 51 E> */ B(LdaKeyedProperty), R(this), U8(0),
B(Wide), B(LdaSmi), I16(285),
B(Wide), B(LdaSmi), I16(286),
B(Star1),
B(LdaConstant), U8(0),
B(Star2),

View File

@ -49,6 +49,7 @@ class ProgramOptions final {
top_level_(false),
print_callee_(false),
async_iteration_(false),
top_level_await_(false),
verbose_(false) {}
bool Validate() const;
@ -70,6 +71,7 @@ class ProgramOptions final {
bool top_level() const { return top_level_; }
bool print_callee() const { return print_callee_; }
bool async_iteration() const { return async_iteration_; }
bool top_level_await() const { return top_level_await_; }
bool verbose() const { return verbose_; }
bool suppress_runtime_errors() const { return baseline() && !verbose_; }
std::vector<std::string> input_filenames() const { return input_filenames_; }
@ -88,6 +90,7 @@ class ProgramOptions final {
bool top_level_;
bool print_callee_;
bool async_iteration_;
bool top_level_await_;
bool verbose_;
std::vector<std::string> input_filenames_;
std::string output_filename_;
@ -190,6 +193,8 @@ ProgramOptions ProgramOptions::FromCommandLine(int argc, char** argv) {
options.print_callee_ = true;
} else if (strcmp(argv[i], "--async-iteration") == 0) {
options.async_iteration_ = true;
} else if (strcmp(argv[i], "--harmony-top-level-await") == 0) {
options.top_level_await_ = true;
} else if (strcmp(argv[i], "--verbose") == 0) {
options.verbose_ = true;
} else if (strncmp(argv[i], "--output=", 9) == 0) {
@ -307,6 +312,8 @@ void ProgramOptions::UpdateFromHeader(std::istream* stream) {
print_callee_ = ParseBoolean(line.c_str() + strlen(kPrintCallee));
} else if (line.compare(0, 17, "async iteration: ") == 0) {
async_iteration_ = ParseBoolean(line.c_str() + 17);
} else if (line.compare(0, 17, "top level await: ") == 0) {
top_level_await_ = ParseBoolean(line.c_str() + 17);
} else if (line == "---") {
break;
} else if (line.empty()) {
@ -329,6 +336,7 @@ void ProgramOptions::PrintHeader(std::ostream* stream) const {
if (top_level_) *stream << "\ntop level: yes";
if (print_callee_) *stream << "\nprint callee: yes";
if (async_iteration_) *stream << "\nasync iteration: yes";
if (top_level_await_) *stream << "\ntop level await: yes";
*stream << "\n\n";
}
@ -436,11 +444,15 @@ void GenerateExpectationsFile(std::ostream* stream,
printer.set_test_function_name(options.test_function_name());
}
if (options.top_level_await()) i::FLAG_harmony_top_level_await = true;
*stream << "#\n# Autogenerated by generate-bytecode-expectations.\n#\n\n";
options.PrintHeader(stream);
for (const std::string& snippet : snippet_list) {
printer.PrintExpectation(stream, snippet);
}
i::FLAG_harmony_top_level_await = false;
}
bool WriteExpectationsFile(const std::vector<std::string>& snippet_list,
@ -499,6 +511,7 @@ void PrintUsage(const char* exec_path) {
" --test-function-name=foo "
"Specify the name of the test function.\n"
" --top-level Process top level code, not the top-level function.\n"
" --top-level-await Enable await at the module level.\n"
" --output=file.name\n"
" Specify the output file. If not specified, output goes to "
"stdout.\n"

View File

@ -2992,6 +2992,8 @@ TEST(Modules) {
}
TEST(AsyncModules) {
bool previous_top_level_await_flag = i::FLAG_harmony_top_level_await;
i::FLAG_harmony_top_level_await = true;
InitializedIgnitionHandleScope scope;
BytecodeExpectationsPrinter printer(CcTest::isolate());
printer.set_wrap(false);
@ -3015,6 +3017,7 @@ TEST(AsyncModules) {
CHECK(CompareTexts(BuildActual(printer, snippets),
LoadGolden("AsyncModules.golden")));
i::FLAG_harmony_top_level_await = previous_top_level_await_flag;
}
TEST(SuperCallAndSpread) {

View File

@ -23839,16 +23839,21 @@ void RunStreamingTest(const char** chunks, v8::ScriptType type,
CHECK_EQ(Module::kInstantiated, module->GetStatus());
v8::Local<Value> result = module->Evaluate(env.local()).ToLocalChecked();
CHECK_EQ(Module::kEvaluated, module->GetStatus());
v8::Local<v8::Promise> promise = result.As<v8::Promise>();
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
// Fulfilled top-level await promises always resolve to undefined. Check
// the test result via a global variable.
CHECK_EQ(13, env->Global()
->Get(env.local(), v8_str("Result"))
.ToLocalChecked()
->Int32Value(env.local())
.FromJust());
if (i::FLAG_harmony_top_level_await) {
v8::Local<v8::Promise> promise = result.As<v8::Promise>();
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
// Fulfilled top-level await promises always resolve to undefined. Check
// the test result via a global variable.
CHECK_EQ(13, env->Global()
->Get(env.local(), v8_str("Result"))
.ToLocalChecked()
->Int32Value(env.local())
.FromJust());
} else {
CHECK(!result.IsEmpty());
CHECK_EQ(13, result->Int32Value(env.local()).FromJust());
}
} else {
CHECK(maybe_module.IsEmpty());
}
@ -24425,7 +24430,7 @@ TEST(ModuleCodeCache) {
const char* origin = "code cache test";
const char* source =
"export default 5; export const a = 10; function f() { return 42; } "
"(function() { globalThis.Result = f(); })();";
"(function() { return f(); })();";
v8::ScriptCompiler::CachedData* cache;
{
@ -24446,14 +24451,13 @@ TEST(ModuleCodeCache) {
// Evaluate for possible lazy compilation.
Local<Value> completion_value =
module->Evaluate(context).ToLocalChecked();
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
CHECK_EQ(42, context->Global()
->Get(context, v8_str("Result"))
.ToLocalChecked()
->Int32Value(context)
.FromJust());
if (i::FLAG_harmony_top_level_await) {
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
} else {
CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
}
// Now create the cache. Note that it is freed, obscurely, when
// ScriptCompiler::Source goes out of scope below.
@ -24484,14 +24488,13 @@ TEST(ModuleCodeCache) {
Local<Value> completion_value =
module->Evaluate(context).ToLocalChecked();
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
CHECK_EQ(42, context->Global()
->Get(context, v8_str("Result"))
.ToLocalChecked()
->Int32Value(context)
.FromJust());
if (i::FLAG_harmony_top_level_await) {
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
} else {
CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
}
}
isolate->Dispose();
}
@ -24743,8 +24746,8 @@ TEST(ImportFromSyntheticModule) {
Local<String> url = v8_str("www.test.com");
Local<String> source_text = v8_str(
"import {test_export} from './synthetic.module'; "
"(function() { globalThis.Result = test_export; })();");
"import {test_export} from './synthetic.module';"
"(function() { return test_export; })();");
v8::ScriptOrigin origin(isolate, url, 0, 0, false, -1, Local<v8::Value>(),
false, false, true);
v8::ScriptCompiler::Source source(source_text, origin);
@ -24754,14 +24757,13 @@ TEST(ImportFromSyntheticModule) {
.ToChecked();
Local<Value> completion_value = module->Evaluate(context).ToLocalChecked();
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
CHECK_EQ(42, context->Global()
->Get(context, v8_str("Result"))
.ToLocalChecked()
->Int32Value(context)
.FromJust());
if (i::FLAG_harmony_top_level_await) {
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
} else {
CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
}
}
TEST(ImportFromSyntheticModuleThrow) {
@ -24789,10 +24791,14 @@ TEST(ImportFromSyntheticModuleThrow) {
CHECK_EQ(module->GetStatus(), Module::kInstantiated);
TryCatch try_catch(isolate);
v8::MaybeLocal<Value> completion_value = module->Evaluate(context);
Local<v8::Promise> promise(
Local<v8::Promise>::Cast(completion_value.ToLocalChecked()));
CHECK_EQ(promise->State(), v8::Promise::kRejected);
CHECK_EQ(promise->Result(), try_catch.Exception());
if (i::FLAG_harmony_top_level_await) {
Local<v8::Promise> promise(
Local<v8::Promise>::Cast(completion_value.ToLocalChecked()));
CHECK_EQ(promise->State(), v8::Promise::kRejected);
CHECK_EQ(promise->Result(), try_catch.Exception());
} else {
CHECK(completion_value.IsEmpty());
}
CHECK_EQ(module->GetStatus(), Module::kErrored);
CHECK(try_catch.HasCaught());
@ -24826,9 +24832,13 @@ TEST(CodeCacheModuleScriptMismatch) {
// Evaluate for possible lazy compilation.
Local<Value> completion_value =
module->Evaluate(context).ToLocalChecked();
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
if (i::FLAG_harmony_top_level_await) {
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
} else {
CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
}
// Now create the cache. Note that it is freed, obscurely, when
// ScriptCompiler::Source goes out of scope below.
@ -24922,9 +24932,13 @@ TEST(CodeCacheScriptModuleMismatch) {
Local<Value> completion_value =
module->Evaluate(context).ToLocalChecked();
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
if (i::FLAG_harmony_top_level_await) {
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
} else {
CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
}
}
isolate->Dispose();
}
@ -24958,9 +24972,13 @@ TEST(InvalidCodeCacheDataInCompileModule) {
CHECK(cached_data->rejected);
Local<Value> completion_value = module->Evaluate(context).ToLocalChecked();
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
if (i::FLAG_harmony_top_level_await) {
Local<v8::Promise> promise(Local<v8::Promise>::Cast(completion_value));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
} else {
CHECK_EQ(42, completion_value->Int32Value(context).FromJust());
}
}
void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
@ -26486,7 +26504,7 @@ TEST(ImportMeta) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
Local<String> url = v8_str("www.google.com");
Local<String> source_text = v8_str("globalThis.Result = import.meta;");
Local<String> source_text = v8_str("import.meta;");
v8::ScriptOrigin origin(isolate, url, 0, 0, false, -1, Local<v8::Value>(),
false, false, true);
v8::ScriptCompiler::Source source(source_text, origin);
@ -26508,14 +26526,14 @@ TEST(ImportMeta) {
module->InstantiateModule(context.local(), UnexpectedModuleResolveCallback)
.ToChecked();
Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
Local<v8::Promise> promise(Local<v8::Promise>::Cast(result));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
CHECK(context.local()
->Global()
->Get(context.local(), v8_str("Result"))
.ToLocalChecked()
->StrictEquals(Local<v8::Value>::Cast(v8::Utils::ToLocal(meta))));
if (i::FLAG_harmony_top_level_await) {
Local<v8::Promise> promise(Local<v8::Promise>::Cast(result));
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK(promise->Result()->IsUndefined());
} else {
CHECK(
result->StrictEquals(Local<v8::Value>::Cast(v8::Utils::ToLocal(meta))));
}
}
void HostInitializeImportMetaObjectCallbackThrow(Local<Context> context,
@ -26544,8 +26562,10 @@ TEST(ImportMetaThrowUnhandled) {
.ToChecked();
Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
auto promise = Local<v8::Promise>::Cast(result);
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
if (i::FLAG_harmony_top_level_await) {
auto promise = Local<v8::Promise>::Cast(result);
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
}
Local<Object> ns = module->GetModuleNamespace().As<Object>();
Local<Value> closure =
@ -26587,8 +26607,10 @@ TEST(ImportMetaThrowHandled) {
.ToChecked();
Local<Value> result = module->Evaluate(context.local()).ToLocalChecked();
auto promise = Local<v8::Promise>::Cast(result);
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
if (i::FLAG_harmony_top_level_await) {
auto promise = Local<v8::Promise>::Cast(result);
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
}
Local<Object> ns = module->GetModuleNamespace().As<Object>();
Local<Value> closure =

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,9 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// MODULE
//
// Flags: --harmony-top-level-await --ignore-unhandled-promises
import "modules-skip-1-top-level-await-fail.mjs"

View File

@ -0,0 +1,3 @@
*modules-skip-1-top-level-await-fail.mjs:7: ReferenceError: x is not defined
await x;
^

View File

@ -0,0 +1,9 @@
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// MODULE
//
// Flags: --harmony-top-level-await --ignore-unhandled-promises
import "modules-skip-2-top-level-await-fail.mjs"

View File

@ -0,0 +1,3 @@
*modules-skip-2-top-level-await-fail.mjs:7: ReferenceError: ththsths is not defined
ththsths
^

View File

@ -1306,6 +1306,12 @@
'regress/regress-crbug-1104608': [SKIP],
}],
##############################################################################
['variant == top_level_await', {
# specifically expects to fail on top level await.
'harmony/modules-import-15': [SKIP],
}], # variant == top_level_await
##############################################################################
['variant == stress_js_bg_compile_wasm_code_gc', {
# Runs significantly slower with --stress-wasm-code-gc, problematic

View File

@ -44,6 +44,7 @@ ALL_VARIANT_FLAGS = {
"turboprop_as_toptier": [["--turboprop-as-toptier", "--turboprop"]],
"instruction_scheduling": [["--turbo-instruction-scheduling"]],
"stress_instruction_scheduling": [["--turbo-stress-instruction-scheduling"]],
"top_level_await": [["--harmony-top-level-await"]],
"wasm_write_protect_code": [["--wasm-write-protect-code-memory"]],
# Google3 variants.
"google3_icu": [[]],