Skip to content

Commit

Permalink
Revert promises optimizations due to regressions in async hooks
Browse files Browse the repository at this point in the history
Revert "[async-await] Eliminate throwaway promise in async functions."

This reverts commit a840f1f.

Revert "[async-generators] Also avoid throwaway promise here."

This reverts commit feb545c.

Revert "[async-await] Turn await closures into intrinsics."

This reverts commit d97bb31.

Revert "[async-generators] Add fast-path for primitives in AsyncGeneratorYield."

This reverts commit e57b500.

Revert "[async-generators] Add fast-path to skip "then" lookup in AsyncGeneratorResolve."

This reverts commit c15802e.

Revert "[promises] Correctly run before/after hooks for await."

This reverts commit ca76392.

Bug: v8:7253, v8:7745
Change-Id: I25ad0d2df3cfbc84dbb431aa25b268bce8a39e89
Reviewed-on: https://chromium-review.googlesource.com/1049975
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53139}
  • Loading branch information
MayaLekova authored and Commit Bot committed May 14, 2018
1 parent 989285b commit 91ddb65
Show file tree
Hide file tree
Showing 36 changed files with 703 additions and 621 deletions.
72 changes: 72 additions & 0 deletions src/bootstrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,50 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
native_context()->set_async_iterator_value_unwrap_shared_fun(*info);
}

{ // --- A s y n c G e n e r a t o r ---
Handle<JSFunction> await_caught =
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncGeneratorAwaitCaught, 1, false);
native_context()->set_async_generator_await_caught(*await_caught);

Handle<JSFunction> await_uncaught =
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncGeneratorAwaitUncaught, 1, false);
native_context()->set_async_generator_await_uncaught(*await_uncaught);

Handle<SharedFunctionInfo> info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorAwaitResolveClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_await_resolve_shared_fun(*info);

info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorAwaitRejectClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_await_reject_shared_fun(*info);

info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorYieldResolveClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_yield_resolve_shared_fun(*info);

info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorReturnResolveClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_return_resolve_shared_fun(*info);

info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorReturnClosedResolveClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_return_closed_resolve_shared_fun(
*info);

info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncGeneratorReturnClosedRejectClosure,
factory->empty_string(), 1);
native_context()->set_async_generator_return_closed_reject_shared_fun(
*info);
}

{ // --- A r r a y ---
Handle<JSFunction> array_function = InstallFunction(
global, "Array", JS_ARRAY_TYPE, JSArray::kSize, 0,
Expand Down Expand Up @@ -4025,6 +4069,34 @@ void Bootstrapper::ExportFromRuntime(Isolate* isolate,
JSFunction::SetPrototype(async_function_constructor,
async_function_prototype);

{
Handle<JSFunction> function =
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncFunctionAwaitCaught, 2, false);
native_context->set_async_function_await_caught(*function);
}

{
Handle<JSFunction> function =
SimpleCreateFunction(isolate, factory->empty_string(),
Builtins::kAsyncFunctionAwaitUncaught, 2, false);
native_context->set_async_function_await_uncaught(*function);
}

{
Handle<SharedFunctionInfo> info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncFunctionAwaitRejectClosure,
factory->empty_string(), 1);
native_context->set_async_function_await_reject_shared_fun(*info);
}

{
Handle<SharedFunctionInfo> info = SimpleCreateSharedFunctionInfo(
isolate, Builtins::kAsyncFunctionAwaitResolveClosure,
factory->empty_string(), 1);
native_context->set_async_function_await_resolve_shared_fun(*info);
}

{
Handle<JSFunction> function =
SimpleCreateFunction(isolate, factory->empty_string(),
Expand Down
96 changes: 69 additions & 27 deletions src/builtins/builtins-async-function-gen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,37 @@ class AsyncFunctionBuiltinsAssembler : public AsyncBuiltinsAssembler {
Node* const awaited, Node* const outer_promise,
const bool is_predicted_as_caught);

void AsyncFunctionAwaitResume(Node* const context, Node* const argument,
Node* const generator,
JSGeneratorObject::ResumeMode resume_mode);
void AsyncFunctionAwaitResumeClosure(
Node* const context, Node* const sent_value,
JSGeneratorObject::ResumeMode resume_mode);
};

void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResume(
Node* const context, Node* const argument, Node* const generator,
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) {
CSA_ASSERT(this, IsJSGeneratorObject(generator));
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,
Expand All @@ -47,23 +66,31 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwaitResume(

// Resume the {receiver} using our trampoline.
Callable callable = CodeFactory::ResumeGenerator(isolate());
TailCallStub(callable, context, argument, generator);
CallStub(callable, context, sent_value, generator);

// 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(AsyncFunctionAwaitFulfill, AsyncFunctionBuiltinsAssembler) {
Node* const argument = Parameter(Descriptor::kArgument);
Node* const generator = Parameter(Descriptor::kGenerator);
TF_BUILTIN(AsyncFunctionAwaitRejectClosure, AsyncFunctionBuiltinsAssembler) {
CSA_ASSERT_JS_ARGC_EQ(this, 1);
Node* const sentError = Parameter(Descriptor::kSentError);
Node* const context = Parameter(Descriptor::kContext);
AsyncFunctionAwaitResume(context, argument, generator,
JSGeneratorObject::kNext);

AsyncFunctionAwaitResumeClosure(context, sentError,
JSGeneratorObject::kThrow);
Return(UndefinedConstant());
}

TF_BUILTIN(AsyncFunctionAwaitReject, AsyncFunctionBuiltinsAssembler) {
Node* const argument = Parameter(Descriptor::kArgument);
Node* const generator = Parameter(Descriptor::kGenerator);
TF_BUILTIN(AsyncFunctionAwaitResolveClosure, AsyncFunctionBuiltinsAssembler) {
CSA_ASSERT_JS_ARGC_EQ(this, 1);
Node* const sentValue = Parameter(Descriptor::kSentValue);
Node* const context = Parameter(Descriptor::kContext);
AsyncFunctionAwaitResume(context, argument, generator,
JSGeneratorObject::kThrow);

AsyncFunctionAwaitResumeClosure(context, sentValue, JSGeneratorObject::kNext);
Return(UndefinedConstant());
}

// ES#abstract-ops-async-function-await
Expand All @@ -78,12 +105,25 @@ TF_BUILTIN(AsyncFunctionAwaitReject, AsyncFunctionBuiltinsAssembler) {
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, IsJSGeneratorObject(generator));
CSA_SLOW_ASSERT(this, IsJSPromise(outer_promise));

Await(context, generator, awaited, outer_promise,
Builtins::kAsyncFunctionAwaitFulfill,
Builtins::kAsyncFunctionAwaitReject, is_predicted_as_caught);
CSA_SLOW_ASSERT(this, HasInstanceType(generator, JS_GENERATOR_OBJECT_TYPE));
CSA_SLOW_ASSERT(this, HasInstanceType(outer_promise, JS_PROMISE_TYPE));

ContextInitializer init_closure_context = [&](Node* context) {
StoreContextElementNoWriteBarrier(context, AwaitContext::kGeneratorSlot,
generator);
};

// 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.

Await(context, generator, awaited, outer_promise, AwaitContext::kLength,
init_closure_context, Context::ASYNC_FUNCTION_AWAIT_RESOLVE_SHARED_FUN,
Context::ASYNC_FUNCTION_AWAIT_REJECT_SHARED_FUN,
is_predicted_as_caught);

// Return outer promise to avoid adding an load of the outer promise before
// suspending in BytecodeGenerator.
Expand All @@ -93,28 +133,30 @@ void AsyncFunctionBuiltinsAssembler::AsyncFunctionAwait(
// 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(Descriptor::kGenerator);
Node* const value = Parameter(Descriptor::kValue);
Node* const awaited = Parameter(Descriptor::kAwaited);
Node* const outer_promise = Parameter(Descriptor::kOuterPromise);
Node* const context = Parameter(Descriptor::kContext);

static const bool kIsPredictedAsCaught = true;

AsyncFunctionAwait(context, generator, value, outer_promise,
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(Descriptor::kGenerator);
Node* const value = Parameter(Descriptor::kValue);
Node* const awaited = Parameter(Descriptor::kAwaited);
Node* const outer_promise = Parameter(Descriptor::kOuterPromise);
Node* const context = Parameter(Descriptor::kContext);

static const bool kIsPredictedAsCaught = false;

AsyncFunctionAwait(context, generator, value, outer_promise,
AsyncFunctionAwait(context, generator, awaited, outer_promise,
kIsPredictedAsCaught);
}

Expand Down
Loading

0 comments on commit 91ddb65

Please sign in to comment.