Commit 1cb0fac0 authored by Shu-yu Guo's avatar Shu-yu Guo Committed by Commit Bot

[top-level-await] Ship top-level await

Note that top-level await is already on-by-default in blink. This flips
the flag in V8 only for other embedders.

Bug: v8:9344
Change-Id: Ic860b22316718b353a0493799fdf95200a71acc1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2746843
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73416}
parent 71db74d8
......@@ -1233,10 +1233,6 @@ void Shell::DoHostImportModuleDynamically(void* import_data) {
Local<Value> module_namespace = root_module->GetModuleNamespace();
if (i::FLAG_harmony_top_level_await) {
Local<Promise> result_promise(result.As<Promise>());
if (result_promise->State() == Promise::kRejected) {
resolver->Reject(realm, result_promise->Result()).ToChecked();
return;
}
// Setup callbacks, and then chain them to the result promise.
// ModuleResolutionData will be deleted by the callbacks.
......
......@@ -268,7 +268,6 @@ DEFINE_IMPLICATION(harmony_weak_refs_with_cleanup_some, harmony_weak_refs)
// Features that are complete (but still behind --harmony/es-staging flag).
#define HARMONY_STAGED_BASE(V) \
V(harmony_top_level_await, "harmony top level await") \
V(harmony_relative_indexing_methods, "harmony relative indexing methods") \
V(harmony_class_static_blocks, "harmony static initializer blocks")
......@@ -282,12 +281,13 @@ DEFINE_IMPLICATION(harmony_weak_refs_with_cleanup_some, harmony_weak_refs)
#endif
// Features that are shipping (turned on by default, but internal flag remains).
#define HARMONY_SHIPPING_BASE(V) \
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
V(harmony_atomics, "harmony atomics") \
V(harmony_weak_refs, "harmony weak references") \
V(harmony_regexp_match_indices, "harmony regexp match indices") \
V(harmony_private_brand_checks, "harmony private brand checks")
#define HARMONY_SHIPPING_BASE(V) \
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
V(harmony_atomics, "harmony atomics") \
V(harmony_weak_refs, "harmony weak references") \
V(harmony_regexp_match_indices, "harmony regexp match indices") \
V(harmony_private_brand_checks, "harmony private brand checks") \
V(harmony_top_level_await, "harmony top level await")
#ifdef V8_INTL_SUPPORT
#define HARMONY_SHIPPING(V) HARMONY_SHIPPING_BASE(V)
......
......@@ -23579,7 +23579,14 @@ void RunStreamingTest(const char** chunks, v8::ScriptType type,
if (i::FLAG_harmony_top_level_await) {
v8::Local<v8::Promise> promise = result.As<v8::Promise>();
CHECK_EQ(promise->State(), v8::Promise::kFulfilled);
CHECK_EQ(13, promise->Result()->Int32Value(env.local()).FromJust());
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());
......@@ -23607,17 +23614,20 @@ void RunStreamingTest(const char** chunks,
TEST(StreamingSimpleScript) {
// This script is unrealistically small, since no one chunk is enough to fill
// the backing buffer of Scanner, let alone overflow it.
const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
nullptr};
const char* chunks[] = {"function foo() { ret",
"urn 13; } globalThis.Result = f", "oo(); ", nullptr};
RunStreamingTest(chunks);
}
TEST(StreamingScriptConstantArray) {
// When run with Ignition, tests that the streaming parser canonicalizes
// handles so that they are only added to the constant pool array once.
const char* chunks[] = {
"var a = {};", "var b = {};", "var c = 'testing';",
"var d = 'testing';", "13;", nullptr};
const char* chunks[] = {"var a = {};",
"var b = {};",
"var c = 'testing';",
"var d = 'testing';",
"globalThis.Result = 13;",
nullptr};
RunStreamingTest(chunks);
}
......@@ -23632,7 +23642,7 @@ TEST(StreamingScriptEvalShadowing) {
" function g() {\n"
" return y\n"
" }\n"
" return g();\n"
" return (globalThis.Result = g());\n"
" })()\n"
"})()\n";
const char* chunks[] = {chunk1, nullptr};
......@@ -23656,7 +23666,7 @@ TEST(StreamingBiggerScript) {
" for (i = 0; i < 13; ++i) { result = result + 1; }\n"
" return result;\n"
"}\n";
const char* chunks[] = {chunk1, "foo(); ", nullptr};
const char* chunks[] = {chunk1, "globalThis.Result = foo(); ", nullptr};
RunStreamingTest(chunks);
}
......@@ -23668,7 +23678,8 @@ TEST(StreamingScriptWithParseError) {
" // This will result in a parse error.\n"
" var if else then foo";
char chunk2[] = " 13\n";
const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, "globalThis.Result = foo();",
nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
false);
......@@ -23679,7 +23690,8 @@ TEST(StreamingScriptWithParseError) {
" // This will be parsed successfully.\n"
" function foo() { return ";
char chunk2[] = " 13; }\n";
const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, "globalThis.Result = foo();",
nullptr};
RunStreamingTest(chunks);
}
......@@ -23696,7 +23708,7 @@ TEST(StreamingUtf8Script) {
" var foob\xec\x92\x81r = 13;\n"
" return foob\xec\x92\x81r;\n"
"}\n";
const char* chunks[] = {chunk1, "foo(); ", nullptr};
const char* chunks[] = {chunk1, "globalThis.Result = foo(); ", nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
......@@ -23720,7 +23732,8 @@ TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
for (int i = 0; i < 3; ++i) {
chunk2[i] = reference[i];
}
const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, "globalThis.Result = foo();",
nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
......@@ -23741,7 +23754,8 @@ TEST(StreamingUtf8ScriptWithSplitCharacters) {
chunk1[strlen(chunk1) - 1] = reference[0];
chunk2[0] = reference[1];
chunk2[1] = reference[2];
const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, "globalThis.Result = foo();",
nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
......@@ -23768,7 +23782,8 @@ TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
chunk2[0] = reference[0];
chunk2[1] = reference[1];
chunk3[0] = reference[2];
const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, chunk3,
"globalThis.Result = foo();", nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
// The small chunk is at the end of a character
......@@ -23786,7 +23801,8 @@ TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
chunk1[strlen(chunk1) - 1] = reference[0];
chunk2[0] = reference[1];
chunk2[1] = reference[2];
const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, chunk3,
"globalThis.Result = foo();", nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
// Case 2: the script ends with a multi-byte character. Make sure that it's
......@@ -23794,7 +23810,7 @@ TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
{
char chunk1[] =
"var foob\xec\x92\x81 = 13;\n"
"foob\xec\x92\x81";
"globalThis.Result = foob\xec\x92\x81";
const char* chunks[] = {chunk1, nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
......@@ -23819,7 +23835,8 @@ TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
chunk1[strlen(chunk1) - 1] = reference[0];
chunk2[0] = reference[1];
chunk3[0] = reference[2];
const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, chunk3, "globalThis.Result = foo();",
nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
......@@ -23890,7 +23907,8 @@ TEST(StreamingScriptWithInvalidUtf8) {
"}\n";
for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, "globalThis.Result = foo();",
nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
}
......@@ -23911,7 +23929,8 @@ TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
chunk1[strlen(chunk1) - 1] = reference[0];
chunk2[0] = reference[1];
chunk2[1] = reference[2];
const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, "globalThis.Result = foo();",
nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
......@@ -23932,7 +23951,8 @@ TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
chunk1[strlen(chunk1) - 1] = reference[0];
chunk2[0] = reference[1];
chunk2[1] = reference[2];
const char* chunks[] = {chunk1, chunk2, "foo();", nullptr};
const char* chunks[] = {chunk1, chunk2, "globalThis.Result = foo();",
nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
}
......@@ -24792,7 +24812,8 @@ TEST(ClassPrototypeCreationContext) {
TEST(SimpleStreamingScriptWithSourceURL) {
const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
const char* chunks[] = {"function foo() { ret",
"urn 13; } globalThis.Result = f", "oo();\n",
"//# sourceURL=bar2.js\n", nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
"bar2.js");
......@@ -24800,7 +24821,8 @@ TEST(SimpleStreamingScriptWithSourceURL) {
TEST(StreamingScriptWithSplitSourceURL) {
const char* chunks[] = {"function foo() { ret", "urn 13; } f",
const char* chunks[] = {"function foo() { ret",
"urn 13; } globalThis.Result = f",
"oo();\n//# sourceURL=b", "ar2.js\n", nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
"bar2.js");
......@@ -24809,7 +24831,8 @@ TEST(StreamingScriptWithSplitSourceURL) {
TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
" sourceMappingURL=bar2.js\n", "foo();", nullptr};
" sourceMappingURL=bar2.js\n",
"globalThis.Result = foo();", nullptr};
RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
nullptr, "bar2.js");
}
*%(basename)s:5: SyntaxError: await is only valid in async function
*%(basename)s:5: SyntaxError: await is only valid in async functions and the top level bodies of modules
function f() { await Promise.resolve(); }
^^^^^
SyntaxError: await is only valid in async function
SyntaxError: await is only valid in async functions and the top level bodies of modules
......@@ -5,8 +5,8 @@
// Flags: --allow-natives-syntax --harmony-dynamic-import
var error1, error2;
import('modules-skip-11.mjs').catch(e => error1 = e);
import('modules-skip-11.mjs').catch(e => error2 = e);
import('modules-skip-11.mjs').catch(e => { error1 = e });
import('modules-skip-11.mjs').catch(e => { error2 = e });
%PerformMicrotaskCheckpoint();
assertEquals(error1, error2);
......
......@@ -3,28 +3,9 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-dynamic-import
//
// Note: This test fails with top level await due to test1, which tries to
// import a module using top level await and expects it to fail.
var ran = false;
async function test1() {
try {
let x = await import('modules-skip-8.mjs');
%AbortJS('failure: should be unreachable');
} catch(e) {
assertEquals('Unexpected reserved word', e.message);
ran = true;
}
}
test1();
%PerformMicrotaskCheckpoint();
assertTrue(ran);
ran = false;
async function test2() {
try {
let x = await import('modules-skip-9.mjs');
......
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