Commit 87851fda authored by jgruber's avatar jgruber Committed by Commit bot

[async-await] Move remaining async-await code to TF

This moves AsyncFunctionAwait{Caught,Uncaught} to CSA, and removes
async-await.js.

BUG=v8:5639

Review-Url: https://codereview.chromium.org/2643023002
Cr-Commit-Position: refs/heads/master@{#42579}
parent 2ca39001
...@@ -437,7 +437,6 @@ action("js2c") { ...@@ -437,7 +437,6 @@ action("js2c") {
"src/js/templates.js", "src/js/templates.js",
"src/js/spread.js", "src/js/spread.js",
"src/js/proxy.js", "src/js/proxy.js",
"src/js/async-await.js",
"src/js/harmony-string-padding.js", "src/js/harmony-string-padding.js",
"src/debug/mirrors.js", "src/debug/mirrors.js",
"src/debug/debug.js", "src/debug/debug.js",
......
...@@ -1935,14 +1935,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -1935,14 +1935,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Context::IS_PROMISE_INDEX); Context::IS_PROMISE_INDEX);
} }
{ // Internal: PerformPromiseThen
Handle<JSFunction> function =
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kPerformPromiseThen, 4, false);
InstallWithIntrinsicDefaultProto(isolate, function,
Context::PERFORM_PROMISE_THEN_INDEX);
}
{ // Internal: ResolvePromise { // Internal: ResolvePromise
// Also exposed as extrasUtils.resolvePromise. // Also exposed as extrasUtils.resolvePromise.
Handle<JSFunction> function = SimpleCreateFunction( Handle<JSFunction> function = SimpleCreateFunction(
...@@ -3350,57 +3342,85 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate, ...@@ -3350,57 +3342,85 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
script_source_mapping_url, attribs); script_source_mapping_url, attribs);
script_map->AppendDescriptor(&d); script_map->AppendDescriptor(&d);
} }
}
{ // -- A s y n c F u n c t i o n
// Builtin functions for AsyncFunction.
PrototypeIterator iter(native_context->async_function_map());
Handle<JSObject> async_function_prototype(iter.GetCurrent<JSObject>());
static const bool kUseStrictFunctionMap = true;
Handle<JSFunction> async_function_constructor = InstallFunction(
container, "AsyncFunction", JS_FUNCTION_TYPE, JSFunction::kSize,
async_function_prototype, Builtins::kAsyncFunctionConstructor,
kUseStrictFunctionMap);
async_function_constructor->shared()->DontAdaptArguments();
async_function_constructor->shared()->SetConstructStub(
*isolate->builtins()->AsyncFunctionConstructor());
async_function_constructor->shared()->set_length(1);
InstallWithIntrinsicDefaultProto(isolate, async_function_constructor,
Context::ASYNC_FUNCTION_FUNCTION_INDEX);
JSObject::ForceSetPrototype(async_function_constructor,
isolate->function_function());
JSObject::AddProperty(
async_function_prototype, factory->constructor_string(),
async_function_constructor,
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
JSFunction::SetPrototype(async_function_constructor,
async_function_prototype);
{ {
PrototypeIterator iter(native_context->async_function_map()); Handle<JSFunction> function =
Handle<JSObject> async_function_prototype(iter.GetCurrent<JSObject>()); SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncFunctionAwaitCaught, 3, false);
static const bool kUseStrictFunctionMap = true; InstallWithIntrinsicDefaultProto(
Handle<JSFunction> async_function_constructor = InstallFunction( isolate, function, Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX);
container, "AsyncFunction", JS_FUNCTION_TYPE, JSFunction::kSize, }
async_function_prototype, Builtins::kAsyncFunctionConstructor,
kUseStrictFunctionMap);
async_function_constructor->shared()->DontAdaptArguments();
async_function_constructor->shared()->SetConstructStub(
*isolate->builtins()->AsyncFunctionConstructor());
async_function_constructor->shared()->set_length(1);
InstallWithIntrinsicDefaultProto(isolate, async_function_constructor,
Context::ASYNC_FUNCTION_FUNCTION_INDEX);
JSObject::ForceSetPrototype(async_function_constructor,
isolate->function_function());
JSObject::AddProperty(
async_function_prototype, factory->constructor_string(),
async_function_constructor,
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
JSFunction::SetPrototype(async_function_constructor,
async_function_prototype);
Handle<JSFunction> async_function_next =
SimpleInstallFunction(container, "AsyncFunctionNext",
Builtins::kGeneratorPrototypeNext, 1, true);
Handle<JSFunction> async_function_throw =
SimpleInstallFunction(container, "AsyncFunctionThrow",
Builtins::kGeneratorPrototypeThrow, 1, true);
async_function_next->shared()->set_native(false);
async_function_throw->shared()->set_native(false);
{ {
Handle<JSFunction> function = SimpleCreateFunction( Handle<JSFunction> function =
isolate, factory->empty_string(), SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncFunctionPromiseCreate, 0, false); Builtins::kAsyncFunctionAwaitUncaught, 3, false);
InstallWithIntrinsicDefaultProto( InstallWithIntrinsicDefaultProto(
isolate, function, Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX); isolate, function, Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX);
} }
{ {
Handle<JSFunction> function = SimpleCreateFunction( Handle<Code> code =
isolate, factory->empty_string(), isolate->builtins()->AsyncFunctionAwaitRejectClosure();
Builtins::kAsyncFunctionPromiseRelease, 1, false); Handle<SharedFunctionInfo> info =
InstallWithIntrinsicDefaultProto( factory->NewSharedFunctionInfo(factory->empty_string(), code, false);
isolate, function, Context::ASYNC_FUNCTION_PROMISE_RELEASE_INDEX); info->set_internal_formal_parameter_count(1);
} info->set_length(1);
native_context->set_async_function_await_reject_shared_fun(*info);
}
{
Handle<Code> code =
isolate->builtins()->AsyncFunctionAwaitResolveClosure();
Handle<SharedFunctionInfo> info =
factory->NewSharedFunctionInfo(factory->empty_string(), code, false);
info->set_internal_formal_parameter_count(1);
info->set_length(1);
native_context->set_async_function_await_resolve_shared_fun(*info);
}
{
Handle<JSFunction> function =
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncFunctionPromiseCreate, 0, false);
InstallWithIntrinsicDefaultProto(
isolate, function, Context::ASYNC_FUNCTION_PROMISE_CREATE_INDEX);
}
{
Handle<JSFunction> function = SimpleCreateFunction(
isolate, factory->empty_string(),
Builtins::kAsyncFunctionPromiseRelease, 1, false);
InstallWithIntrinsicDefaultProto(
isolate, function, Context::ASYNC_FUNCTION_PROMISE_RELEASE_INDEX);
} }
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "src/builtins/builtins-promise.h" #include "src/builtins/builtins-async.h"
#include "src/builtins/builtins-utils.h" #include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/code-stub-assembler.h" #include "src/code-stub-assembler.h"
...@@ -14,12 +14,151 @@ typedef compiler::Node Node; ...@@ -14,12 +14,151 @@ typedef compiler::Node Node;
typedef CodeStubAssembler::ParameterMode ParameterMode; typedef CodeStubAssembler::ParameterMode ParameterMode;
typedef compiler::CodeAssemblerState CodeAssemblerState; typedef compiler::CodeAssemblerState CodeAssemblerState;
class AsyncFunctionBuiltinsAssembler : public PromiseBuiltinsAssembler { class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler {
public: public:
explicit AsyncFunctionBuiltinsAssembler(CodeAssemblerState* state) explicit AsyncFunctionBuiltinsAssembler(CodeAssemblerState* state)
: PromiseBuiltinsAssembler(state) {} : AsyncBuiltinsAssembler(state) {}
protected:
void AsyncFunctionAwait(Node* const context, Node* const generator,
Node* const awaited, Node* const outer_promise,
const bool is_predicted_as_caught);
void AsyncFunctionAwaitResumeClosure(
Node* const context, Node* const sent_value,
JSGeneratorObject::ResumeMode resume_mode);
};
namespace {
// Describe fields of Context associated with AsyncFunctionAwait resume
// closures.
// TODO(jgruber): Refactor to reuse code for upcoming async-generators.
class AwaitContext {
public:
enum Fields { kGeneratorSlot = Context::MIN_CONTEXT_SLOTS, kLength };
}; };
} // anonymous namespace
void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResumeClosure(
Node* context, Node* sent_value,
JSGeneratorObject::ResumeMode resume_mode) {
DCHECK(resume_mode == JSGeneratorObject::kNext ||
resume_mode == JSGeneratorObject::kThrow);
Node* const generator =
LoadContextElement(context, AwaitContext::kGeneratorSlot);
CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE));
// Inline version of GeneratorPrototypeNext / GeneratorPrototypeReturn with
// unnecessary runtime checks removed.
// TODO(jgruber): Refactor to reuse code from builtins-generator.cc.
// Ensure that the generator is neither closed nor running.
CSA_SLOW_ASSERT(
this,
SmiGreaterThan(
LoadObjectField(generator, JSGeneratorObject::kContinuationOffset),
SmiConstant(JSGeneratorObject::kGeneratorClosed)));
// Resume the {receiver} using our trampoline.
Callable callable = CodeFactory::ResumeGenerator(isolate());
CallStub(callable, context, sent_value, generator, SmiConstant(resume_mode));
// The resulting Promise is a throwaway, so it doesn't matter what it
// resolves to. What is important is that we don't end up keeping the
// whole chain of intermediate Promises alive by returning the return value
// of ResumeGenerator, as that would create a memory leak.
}
TF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) {
CSA_ASSERT_JS_ARGC_EQ(this, 1);
Node* const sentError = Parameter(1);
Node* const context = Parameter(4);
AsyncFunctionAwaitResumeClosure(context, sentError,
JSGeneratorObject::kThrow);
Return(UndefinedConstant());
}
TF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) {
CSA_ASSERT_JS_ARGC_EQ(this, 1);
Node* const sentValue = Parameter(1);
Node* const context = Parameter(4);
AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext);
Return(UndefinedConstant());
}
// ES#abstract-ops-async-function-await
// AsyncFunctionAwait ( value )
// Shared logic for the core of await. The parser desugars
// await awaited
// into
// yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited, .promise)
// The 'awaited' parameter is the value; the generator stands in
// for the asyncContext, and .promise is the larger promise under
// construction by the enclosing async function.
void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
Node* const context, Node* const generator, Node* const awaited,
Node* const outer_promise, const bool is_predicted_as_caught) {
CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE));
CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));
NodeGenerator1 create_closure_context = [&](Node* native_context) -> Node* {
Node* const context =
CreatePromiseContext(native_context, AwaitContext::kLength);
StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot,
generator);
return context;
};
// TODO(jgruber): AsyncBuiltinsAssembler::Await currently does not reuse
// the awaited promise if it is already a promise. Reuse is non-spec compliant
// but part of our old behavior gives us a couple of percent
// performance boost.
// TODO(jgruber): Use a faster specialized version of
// InternalPerformPromiseThen.
Node* const result = Await(
context, generator, awaited, outer_promise, create_closure_context,
Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN,
Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN, is_predicted_as_caught);
Return(result);
}
// Called by the parser from the desugaring of 'await' when catch
// prediction indicates that there is a locally surrounding catch block.
TF_BUILTIN(AsyncFunctionAwaitCaught, AsyncFunctionBuiltinsAssembler) {
CSA_ASSERT_JS_ARGC_EQ(this, 3);
Node* const generator = Parameter(1);
Node* const awaited = Parameter(2);
Node* const outer_promise = Parameter(3);
Node* const context = Parameter(6);
static const bool kIsPredictedAsCaught = true;
AsyncFunctionAwait(context, generator, awaited, outer_promise,
kIsPredictedAsCaught);
}
// Called by the parser from the desugaring of 'await' when catch
// prediction indicates no locally surrounding catch block.
TF_BUILTIN(AsyncFunctionAwaitUncaught, AsyncFunctionBuiltinsAssembler) {
CSA_ASSERT_JS_ARGC_EQ(this, 3);
Node* const generator = Parameter(1);
Node* const awaited = Parameter(2);
Node* const outer_promise = Parameter(3);
Node* const context = Parameter(6);
static const bool kIsPredictedAsCaught = false;
AsyncFunctionAwait(context, generator, awaited, outer_promise,
kIsPredictedAsCaught);
}
TF_BUILTIN(AsyncFunctionPromiseCreate, AsyncFunctionBuiltinsAssembler) { TF_BUILTIN(AsyncFunctionPromiseCreate, AsyncFunctionBuiltinsAssembler) {
CSA_ASSERT_JS_ARGC_EQ(this, 0); CSA_ASSERT_JS_ARGC_EQ(this, 0);
Node* const context = Parameter(3); Node* const context = Parameter(3);
......
...@@ -15,7 +15,7 @@ namespace internal { ...@@ -15,7 +15,7 @@ namespace internal {
Node* AsyncBuiltinsAssembler::Await( Node* AsyncBuiltinsAssembler::Await(
Node* context, Node* generator, Node* value, Node* outer_promise, Node* context, Node* generator, Node* value, Node* outer_promise,
const NodeGenerator1& create_closure_context, int on_resolve_context_index, const NodeGenerator1& create_closure_context, int on_resolve_context_index,
int on_reject_context_index, bool is_catchable) { int on_reject_context_index, bool is_predicted_as_caught) {
// Let promiseCapability be ! NewPromiseCapability(%Promise%). // Let promiseCapability be ! NewPromiseCapability(%Promise%).
Node* const wrapped_value = AllocateAndInitJSPromise(context); Node* const wrapped_value = AllocateAndInitJSPromise(context);
...@@ -55,18 +55,17 @@ Node* AsyncBuiltinsAssembler::Await( ...@@ -55,18 +55,17 @@ Node* AsyncBuiltinsAssembler::Await(
GotoUnless(IsDebugActive(), &do_perform_promise_then); GotoUnless(IsDebugActive(), &do_perform_promise_then);
{ {
Label common(this); Label common(this);
GotoIf(TaggedIsSmi(value), &common);
GotoUnless(HasInstanceType(value, JS_PROMISE_TYPE), &common); GotoUnless(HasInstanceType(value, JS_PROMISE_TYPE), &common);
{ {
// Mark the reject handler callback to be a forwarding edge, rather // Mark the reject handler callback to be a forwarding edge, rather
// than a meaningful catch handler // than a meaningful catch handler
Node* const key = Node* const key =
HeapConstant(factory()->promise_forwarding_handler_symbol()); HeapConstant(factory()->promise_forwarding_handler_symbol());
CallRuntime(Runtime::kSetProperty, on_reject, key, TrueConstant(), CallRuntime(Runtime::kSetProperty, context, on_reject, key,
SmiConstant(STRICT)); TrueConstant(), SmiConstant(STRICT));
if (!is_catchable) { if (is_predicted_as_caught) PromiseSetHandledHint(value);
PromiseSetHasHandler(value);
}
} }
Goto(&common); Goto(&common);
...@@ -76,8 +75,8 @@ Node* AsyncBuiltinsAssembler::Await( ...@@ -76,8 +75,8 @@ Node* AsyncBuiltinsAssembler::Await(
CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE)); CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));
Node* const key = HeapConstant(factory()->promise_handled_by_symbol()); Node* const key = HeapConstant(factory()->promise_handled_by_symbol());
CallRuntime(Runtime::kSetProperty, throwaway_promise, key, outer_promise, CallRuntime(Runtime::kSetProperty, context, throwaway_promise, key,
SmiConstant(STRICT)); outer_promise, SmiConstant(STRICT));
} }
Goto(&do_perform_promise_then); Goto(&do_perform_promise_then);
......
...@@ -26,7 +26,7 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler { ...@@ -26,7 +26,7 @@ class AsyncBuiltinsAssembler : public PromiseBuiltinsAssembler {
Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise, Node* Await(Node* context, Node* generator, Node* value, Node* outer_promise,
const NodeGenerator1& create_closure_context, const NodeGenerator1& create_closure_context,
int on_resolve_context_index, int on_reject_context_index, int on_resolve_context_index, int on_reject_context_index,
bool is_catchable); bool is_predicted_as_caught);
}; };
} // namespace internal } // namespace internal
......
...@@ -271,6 +271,13 @@ void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) { ...@@ -271,6 +271,13 @@ void PromiseBuiltinsAssembler::PromiseSetHasHandler(Node* promise) {
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags); StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
} }
void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) {
Node* const flags = LoadObjectField(promise, JSPromise::kFlagsOffset);
Node* const new_flags =
SmiOr(flags, SmiConstant(1 << JSPromise::kHandledHintBit));
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
}
Node* PromiseBuiltinsAssembler::SpeciesConstructor(Node* context, Node* object, Node* PromiseBuiltinsAssembler::SpeciesConstructor(Node* context, Node* object,
Node* default_constructor) { Node* default_constructor) {
Isolate* isolate = this->isolate(); Isolate* isolate = this->isolate();
...@@ -1159,23 +1166,6 @@ TF_BUILTIN(IsPromise, PromiseBuiltinsAssembler) { ...@@ -1159,23 +1166,6 @@ TF_BUILTIN(IsPromise, PromiseBuiltinsAssembler) {
Return(FalseConstant()); Return(FalseConstant());
} }
TF_BUILTIN(PerformPromiseThen, PromiseBuiltinsAssembler) {
Node* const promise = Parameter(1);
Node* const on_resolve = Parameter(2);
Node* const on_reject = Parameter(3);
Node* const deferred_promise = Parameter(4);
Node* const context = Parameter(7);
// No deferred_on_resolve/deferred_on_reject because this is just an
// internal promise created by async-await.
Node* const result = InternalPerformPromiseThen(
context, promise, on_resolve, on_reject, deferred_promise,
UndefinedConstant(), UndefinedConstant());
// TODO(gsathya): This is unused, but value is returned according to spec.
Return(result);
}
// ES#sec-promise.prototype.then // ES#sec-promise.prototype.then
// Promise.prototype.catch ( onFulfilled, onRejected ) // Promise.prototype.catch ( onFulfilled, onRejected )
TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) { TF_BUILTIN(PromiseThen, PromiseBuiltinsAssembler) {
......
...@@ -81,6 +81,7 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler { ...@@ -81,6 +81,7 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
Node* default_constructor); Node* default_constructor);
void PromiseSetHasHandler(Node* promise); void PromiseSetHasHandler(Node* promise);
void PromiseSetHandledHint(Node* promise);
void AppendPromiseCallback(int offset, compiler::Node* promise, void AppendPromiseCallback(int offset, compiler::Node* promise,
compiler::Node* value); compiler::Node* value);
......
...@@ -279,6 +279,10 @@ namespace internal { ...@@ -279,6 +279,10 @@ namespace internal {
CPP(ArrayBufferIsView) \ CPP(ArrayBufferIsView) \
\ \
/* AsyncFunction */ \ /* AsyncFunction */ \
TFJ(AsyncFunctionAwaitCaught, 3) \
TFJ(AsyncFunctionAwaitUncaught, 3) \
TFJ(AsyncFunctionAwaitRejectClosure, 1) \
TFJ(AsyncFunctionAwaitResolveClosure, 1) \
TFJ(AsyncFunctionPromiseCreate, 0) \ TFJ(AsyncFunctionPromiseCreate, 0) \
TFJ(AsyncFunctionPromiseRelease, 1) \ TFJ(AsyncFunctionPromiseRelease, 1) \
\ \
...@@ -643,7 +647,6 @@ namespace internal { ...@@ -643,7 +647,6 @@ namespace internal {
TFJ(PromiseRejectClosure, 1) \ TFJ(PromiseRejectClosure, 1) \
TFJ(PromiseThen, 2) \ TFJ(PromiseThen, 2) \
TFJ(PromiseCatch, 1) \ TFJ(PromiseCatch, 1) \
TFJ(PerformPromiseThen, 4) \
TFJ(ResolvePromise, 2) \ TFJ(ResolvePromise, 2) \
TFS(PromiseHandleReject, BUILTIN, kNoExtraICState, PromiseHandleReject) \ TFS(PromiseHandleReject, BUILTIN, kNoExtraICState, PromiseHandleReject) \
TFJ(PromiseHandle, 5) \ TFJ(PromiseHandle, 5) \
......
...@@ -67,7 +67,6 @@ enum ContextLookupFlags { ...@@ -67,7 +67,6 @@ enum ContextLookupFlags {
promise_internal_constructor) \ promise_internal_constructor) \
V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \ V(PROMISE_INTERNAL_REJECT_INDEX, JSFunction, promise_internal_reject) \
V(IS_PROMISE_INDEX, JSFunction, is_promise) \ V(IS_PROMISE_INDEX, JSFunction, is_promise) \
V(PERFORM_PROMISE_THEN_INDEX, JSFunction, perform_promise_then) \
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \ V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \ V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \ V(PROMISE_HANDLE_INDEX, JSFunction, promise_handle) \
...@@ -197,6 +196,10 @@ enum ContextLookupFlags { ...@@ -197,6 +196,10 @@ enum ContextLookupFlags {
V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun) \ V(ARRAY_BUFFER_FUN_INDEX, JSFunction, array_buffer_fun) \
V(ARRAY_BUFFER_MAP_INDEX, Map, array_buffer_map) \ V(ARRAY_BUFFER_MAP_INDEX, Map, array_buffer_map) \
V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \ V(ARRAY_FUNCTION_INDEX, JSFunction, array_function) \
V(ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN, SharedFunctionInfo, \
async_function_await_reject_shared_fun) \
V(ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN, SharedFunctionInfo, \
async_function_await_resolve_shared_fun) \
V(ASYNC_FUNCTION_FUNCTION_INDEX, JSFunction, async_function_constructor) \ V(ASYNC_FUNCTION_FUNCTION_INDEX, JSFunction, async_function_constructor) \
V(BOOL16X8_FUNCTION_INDEX, JSFunction, bool16x8_function) \ V(BOOL16X8_FUNCTION_INDEX, JSFunction, bool16x8_function) \
V(BOOL32X4_FUNCTION_INDEX, JSFunction, bool32x4_function) \ V(BOOL32X4_FUNCTION_INDEX, JSFunction, bool32x4_function) \
......
// Copyright 2016 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.
(function(global, utils, extrasUtils) {
"use strict";
%CheckIsBootstrapping();
// -------------------------------------------------------------------
// Imports
var AsyncFunctionNext;
var AsyncFunctionThrow;
utils.Import(function(from) {
AsyncFunctionNext = from.AsyncFunctionNext;
AsyncFunctionThrow = from.AsyncFunctionThrow;
});
var promiseHandledBySymbol =
utils.ImportNow("promise_handled_by_symbol");
var promiseForwardingHandlerSymbol =
utils.ImportNow("promise_forwarding_handler_symbol");
// -------------------------------------------------------------------
function PromiseCastResolved(value) {
// TODO(caitp): This is non spec compliant. See v8:5694.
if (%is_promise(value)) {
return value;
} else {
var promise = %promise_internal_constructor(UNDEFINED);
%promise_resolve(promise, value);
return promise;
}
}
// ES#abstract-ops-async-function-await
// AsyncFunctionAwait ( value )
// Shared logic for the core of await. The parser desugars
// await awaited
// into
// yield AsyncFunctionAwait{Caught,Uncaught}(.generator, awaited, .promise)
// The 'awaited' parameter is the value; the generator stands in
// for the asyncContext, and .promise is the larger promise under
// construction by the enclosing async function.
function AsyncFunctionAwait(generator, awaited, outerPromise) {
// Promise.resolve(awaited).then(
// value => AsyncFunctionNext(value),
// error => AsyncFunctionThrow(error)
// );
var promise = PromiseCastResolved(awaited);
var onFulfilled = sentValue => {
%_Call(AsyncFunctionNext, generator, sentValue);
// The resulting Promise is a throwaway, so it doesn't matter what it
// resolves to. What is important is that we don't end up keeping the
// whole chain of intermediate Promises alive by returning the value
// of AsyncFunctionNext, as that would create a memory leak.
return;
};
var onRejected = sentError => {
%_Call(AsyncFunctionThrow, generator, sentError);
// Similarly, returning the huge Promise here would cause a long
// resolution chain to find what the exception to throw is, and
// create a similar memory leak, and it does not matter what
// sort of rejection this intermediate Promise becomes.
return;
}
var throwawayPromise = %promise_internal_constructor(promise);
// The Promise will be thrown away and not handled, but it shouldn't trigger
// unhandled reject events as its work is done
%PromiseMarkAsHandled(throwawayPromise);
if (DEBUG_IS_ACTIVE) {
if (%is_promise(awaited)) {
// Mark the reject handler callback to be a forwarding edge, rather
// than a meaningful catch handler
SET_PRIVATE(onRejected, promiseForwardingHandlerSymbol, true);
}
// Mark the dependency to outerPromise in case the throwaway Promise is
// found on the Promise stack
SET_PRIVATE(throwawayPromise, promiseHandledBySymbol, outerPromise);
}
%perform_promise_then(promise, onFulfilled, onRejected, throwawayPromise);
}
// Called by the parser from the desugaring of 'await' when catch
// prediction indicates no locally surrounding catch block
function AsyncFunctionAwaitUncaught(generator, awaited, outerPromise) {
AsyncFunctionAwait(generator, awaited, outerPromise);
}
// Called by the parser from the desugaring of 'await' when catch
// prediction indicates that there is a locally surrounding catch block
function AsyncFunctionAwaitCaught(generator, awaited, outerPromise) {
if (DEBUG_IS_ACTIVE && %is_promise(awaited)) {
%PromiseMarkHandledHint(awaited);
}
AsyncFunctionAwait(generator, awaited, outerPromise);
}
%InstallToContext([
"async_function_await_caught", AsyncFunctionAwaitCaught,
"async_function_await_uncaught", AsyncFunctionAwaitUncaught,
]);
})
...@@ -198,15 +198,6 @@ RUNTIME_FUNCTION(Runtime_PromiseMarkAsHandled) { ...@@ -198,15 +198,6 @@ RUNTIME_FUNCTION(Runtime_PromiseMarkAsHandled) {
return isolate->heap()->undefined_value(); return isolate->heap()->undefined_value();
} }
RUNTIME_FUNCTION(Runtime_PromiseMarkHandledHint) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(JSPromise, promise, 0);
promise->set_handled_hint(true);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_PromiseHookInit) { RUNTIME_FUNCTION(Runtime_PromiseHookInit) {
HandleScope scope(isolate); HandleScope scope(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());
......
...@@ -311,7 +311,6 @@ namespace internal { ...@@ -311,7 +311,6 @@ namespace internal {
F(PromiseHookBefore, 1, 1) \ F(PromiseHookBefore, 1, 1) \
F(PromiseHookAfter, 1, 1) \ F(PromiseHookAfter, 1, 1) \
F(PromiseMarkAsHandled, 1, 1) \ F(PromiseMarkAsHandled, 1, 1) \
F(PromiseMarkHandledHint, 1, 1) \
F(PromiseRejectEventFromStack, 2, 1) \ F(PromiseRejectEventFromStack, 2, 1) \
F(PromiseRevokeReject, 1, 1) \ F(PromiseRevokeReject, 1, 1) \
F(PromiseResult, 1, 1) \ F(PromiseResult, 1, 1) \
......
...@@ -2265,7 +2265,6 @@ ...@@ -2265,7 +2265,6 @@
'js/templates.js', 'js/templates.js',
'js/spread.js', 'js/spread.js',
'js/proxy.js', 'js/proxy.js',
'js/async-await.js',
'js/harmony-string-padding.js', 'js/harmony-string-padding.js',
'debug/mirrors.js', 'debug/mirrors.js',
'debug/debug.js', 'debug/debug.js',
......
...@@ -24,4 +24,4 @@ async function bar() { ...@@ -24,4 +24,4 @@ async function bar() {
foo(); foo();
bar(); bar();
%RunMicrotasks(); %RunMicrotasks();
assertEquals(1, count); assertEquals(2, count);
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