Commit 5386c006 authored by littledan's avatar littledan Committed by Commit bot

Desugar async/await to create the resulting Promise upfront

As part of the work to implement catch prediction for async functions,
the resulting Promise that is the output of the function needs to be
available earlier for a couple reasons:
- To be able to do %DebugPushPromise/%DebugPopPromise over the body
  of the async function
- To be able to pass the resulting promise into AsyncFunctionAwait
  in order to set up the dependency chains

This patch creates the Promise earlier and pushes it onto the debug
stack; a later patch will set up the dependency chain. Although the
debug stack is set up, it's not anticipated that this will change
the catch prediction helpfully yet, as everything will still likely
be predicted as 'caught' for now, as before.

R=caitp@igalia.com,yangguo@chromium.org
CC=neis@chromium.org,gsathya@chromium.org
BUG=v8:5167

Review-Url: https://codereview.chromium.org/2233923003
Cr-Commit-Position: refs/heads/master@{#38957}
parent 6a67f02c
......@@ -283,10 +283,12 @@ class AstValue : public ZoneObject {
F(default, "default") \
F(done, "done") \
F(dot, ".") \
F(dot_debug_is_active, ".debug_is_active") \
F(dot_for, ".for") \
F(dot_generator, ".generator") \
F(dot_generator_object, ".generator_object") \
F(dot_iterator, ".iterator") \
F(dot_promise, ".promise") \
F(dot_result, ".result") \
F(dot_switch_tag, ".switch_tag") \
F(dot_catch, ".catch") \
......
......@@ -87,10 +87,10 @@ enum ContextLookupFlags {
promise_has_user_defined_reject_handler) \
V(PROMISE_REJECT_INDEX, JSFunction, promise_reject) \
V(PROMISE_RESOLVE_INDEX, JSFunction, promise_resolve) \
V(PROMISE_CREATE_RESOLVED_INDEX, JSFunction, promise_create_resolved) \
V(PROMISE_CREATE_REJECTED_INDEX, JSFunction, promise_create_rejected) \
V(PROMISE_THEN_INDEX, JSFunction, promise_then) \
V(RANGE_ERROR_FUNCTION_INDEX, JSFunction, range_error_function) \
V(REJECT_PROMISE_NO_DEBUG_EVENT_INDEX, JSFunction, \
reject_promise_no_debug_event) \
V(REFERENCE_ERROR_FUNCTION_INDEX, JSFunction, reference_error_function) \
V(SET_ADD_METHOD_INDEX, JSFunction, set_add) \
V(SET_DELETE_METHOD_INDEX, JSFunction, set_delete) \
......
......@@ -919,6 +919,7 @@ void FullCodeGenerator::EmitContinue(Statement* target) {
// accumulator on the stack.
ClearAccumulator();
while (!current->IsContinueTarget(target)) {
if (HasStackOverflow()) return;
if (current->IsTryFinally()) {
Comment cmnt(masm(), "[ Deferred continue through finally");
current->Exit(&context_length);
......@@ -959,6 +960,7 @@ void FullCodeGenerator::EmitBreak(Statement* target) {
// accumulator on the stack.
ClearAccumulator();
while (!current->IsBreakTarget(target)) {
if (HasStackOverflow()) return;
if (current->IsTryFinally()) {
Comment cmnt(masm(), "[ Deferred break through finally");
current->Exit(&context_length);
......@@ -994,6 +996,7 @@ void FullCodeGenerator::EmitUnwindAndReturn() {
NestedStatement* current = nesting_stack_;
int context_length = 0;
while (current != NULL) {
if (HasStackOverflow()) return;
if (current->IsTryFinally()) {
Comment cmnt(masm(), "[ Deferred return through finally");
current->Exit(&context_length);
......
......@@ -17,6 +17,7 @@ var GlobalPromise;
var NewPromiseCapability;
var PerformPromiseThen;
var PromiseCastResolved;
var RejectPromise;
utils.Import(function(from) {
AsyncFunctionNext = from.AsyncFunctionNext;
......@@ -25,6 +26,7 @@ utils.Import(function(from) {
NewPromiseCapability = from.NewPromiseCapability;
PromiseCastResolved = from.PromiseCastResolved;
PerformPromiseThen = from.PerformPromiseThen;
RejectPromise = from.RejectPromise;
});
// -------------------------------------------------------------------
......@@ -47,6 +49,14 @@ function AsyncFunctionAwait(generator, value) {
throwawayCapability);
}
%InstallToContext([ "async_function_await", AsyncFunctionAwait ]);
// How the parser rejects promises from async/await desugaring
function RejectPromiseNoDebugEvent(promise, reason) {
return RejectPromise(promise, reason, false);
}
%InstallToContext([
"async_function_await", AsyncFunctionAwait,
"reject_promise_no_debug_event", RejectPromiseNoDebugEvent,
]);
})
......@@ -207,6 +207,7 @@ function PostNatives(utils) {
"RegExpSubclassSearch",
"RegExpSubclassSplit",
"RegExpSubclassTest",
"RejectPromise",
"SetIterator",
"SetIteratorNext",
"SetValues",
......
......@@ -381,22 +381,6 @@ function PromiseReject(r) {
}
}
// Shortcut Promise.reject and Promise.resolve() implementations, used by
// Async Functions implementation.
function PromiseCreateRejected(r) {
var promise = PromiseCreateAndSet(kRejected, r);
// This is called from the desugaring of async/await; no reason to
// create a redundant reject event.
%PromiseRejectEvent(promise, r, false);
return promise;
}
function PromiseCreateResolved(value) {
var promise = PromiseInit(new GlobalPromise(promiseRawSymbol));
var resolveResult = ResolvePromise(promise, value);
return promise;
}
function PromiseCastResolved(value) {
if (IsPromise(value)) {
return value;
......@@ -627,8 +611,6 @@ utils.InstallFunctions(GlobalPromise.prototype, DONT_ENUM, [
"promise_reject", DoRejectPromise,
"promise_resolve", ResolvePromise,
"promise_then", PromiseThen,
"promise_create_rejected", PromiseCreateRejected,
"promise_create_resolved", PromiseCreateResolved
]);
// This allows extras to create promises quickly without building extra
......@@ -647,6 +629,7 @@ utils.Export(function(to) {
to.GlobalPromise = GlobalPromise;
to.NewPromiseCapability = NewPromiseCapability;
to.PerformPromiseThen = PerformPromiseThen;
to.RejectPromise = RejectPromise;
});
})
This diff is collapsed.
......@@ -561,7 +561,7 @@ class Parser : public ParserBase<Parser> {
Block* BuildParameterInitializationBlock(
const ParserFormalParameters& parameters, bool* ok);
Block* BuildRejectPromiseOnException(Block* block);
Block* BuildRejectPromiseOnException(Block* block, bool* ok);
// Consumes the ending }.
ZoneList<Statement*>* ParseEagerFunctionBody(
......@@ -654,8 +654,10 @@ class Parser : public ParserBase<Parser> {
void RewriteParameterInitializer(Expression* expr, Scope* scope);
Expression* BuildCreateJSGeneratorObject(int pos, FunctionKind kind);
Expression* BuildPromiseResolve(Expression* value, int pos);
Expression* BuildPromiseReject(Expression* value, int pos);
Expression* BuildResolvePromise(Expression* value, int pos);
Expression* BuildRejectPromise(Expression* value, int pos);
VariableProxy* BuildDotPromise();
VariableProxy* BuildDotDebugIsActive();
// Generic AST generator for throwing errors from compiled code.
Expression* NewThrowError(Runtime::FunctionId function_id,
......@@ -956,7 +958,10 @@ class Parser : public ParserBase<Parser> {
if (parameters.is_simple) return;
auto* init_block = BuildParameterInitializationBlock(parameters, ok);
if (!*ok) return;
if (is_async) init_block = BuildRejectPromiseOnException(init_block);
if (is_async) {
init_block = BuildRejectPromiseOnException(init_block, ok);
if (!*ok) return;
}
if (init_block != nullptr) body->Add(init_block, zone());
}
......
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