Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1448)

Unified Diff: pkg/compiler/lib/src/ssa/builder.dart

Issue 839323003: Implementation of async-await transformation on js ast. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/resolution/registry.dart ('k') | pkg/compiler/lib/src/ssa/codegen.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/ssa/builder.dart
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 43798cd7243067a82a320d3321048a8e36a8730b..ee4408e47472a0ef8bd29586827c5933a063f71e 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -19,7 +19,52 @@ class SsaFunctionCompiler implements FunctionCompiler {
js.Fun compile(CodegenWorkItem work) {
HGraph graph = builder.build(work);
optimizer.optimize(work, graph);
- return generator.generateCode(work, graph);
+ Element element = work.element;
+ js.Expression result = generator.generateCode(work, graph);
+ if (element is FunctionElement) {
+ JavaScriptBackend backend = builder.backend;
+
+ AsyncRewriter rewriter = null;
+ if (element.asyncMarker == AsyncMarker.ASYNC) {
+ rewriter = new AsyncRewriter(
+ backend.compiler,
+ backend.compiler.currentElement,
+ thenHelper:
+ backend.emitter.staticFunctionAccess(backend.getThenHelper()),
+ newCompleter: backend.emitter.staticFunctionAccess(
+ backend.getCompleterConstructor()),
+ safeVariableName: backend.namer.safeVariableName);
+ } else if (element.asyncMarker == AsyncMarker.SYNC_STAR) {
+ rewriter = new AsyncRewriter(
+ backend.compiler,
+ backend.compiler.currentElement,
+ endOfIteration: backend.emitter.staticFunctionAccess(
+ backend.getEndOfIteration()),
+ newIterable: backend.emitter.staticFunctionAccess(
+ backend.getSyncStarIterableConstructor()),
+ yieldStarExpression: backend.emitter.staticFunctionAccess(
+ backend.getYieldStar()),
+ safeVariableName: backend.namer.safeVariableName);
+ }
+ else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
+ rewriter = new AsyncRewriter(
+ backend.compiler,
+ backend.compiler.currentElement,
+ streamHelper: backend.emitter.staticFunctionAccess(
+ backend.getStreamHelper()),
+ newController: backend.emitter.staticFunctionAccess(
+ backend.getASyncStarControllerConstructor()),
+ safeVariableName: backend.namer.safeVariableName,
+ yieldExpression: backend.emitter.staticFunctionAccess(
+ backend.getYieldSingle()),
+ yieldStarExpression: backend.emitter.staticFunctionAccess(
+ backend.getYieldStar()));
+ }
+ if (rewriter != null) {
+ result = rewriter.rewrite(result);
+ }
+ }
+ return result;
}
Iterable<CompilerTask> get tasks {
@@ -362,7 +407,7 @@ class LocalsHandler {
bool isAccessedDirectly(Local local) {
assert(local != null);
return !redirectionMapping.containsKey(local)
- && !closureData.usedVariablesInTry.contains(local);
+ && !closureData.variablesUsedInTryOrGenerator.contains(local);
}
bool isStoredInClosureField(Local local) {
@@ -379,8 +424,8 @@ class LocalsHandler {
return redirectionMapping.containsKey(local);
}
- bool isUsedInTry(Local local) {
- return closureData.usedVariablesInTry.contains(local);
+ bool isUsedInTryOrGenerator(Local local) {
+ return closureData.variablesUsedInTryOrGenerator.contains(local);
}
/**
@@ -422,7 +467,7 @@ class LocalsHandler {
builder.add(lookup);
return lookup;
} else {
- assert(isUsedInTry(local));
+ assert(isUsedInTryOrGenerator(local));
HLocalValue localValue = getLocal(local);
HInstruction instruction = new HLocalGet(
local, localValue, builder.backend.dynamicType);
@@ -478,7 +523,7 @@ class LocalsHandler {
HInstruction box = readLocal(redirect.box);
builder.add(new HFieldSet(redirect, box, value));
} else {
- assert(isUsedInTry(local));
+ assert(isUsedInTryOrGenerator(local));
HLocalValue localValue = getLocal(local);
builder.add(new HLocalSet(local, localValue, value));
}
@@ -5164,14 +5209,17 @@ class SsaBuilder extends ResolvedVisitor {
}
visitYield(ast.Yield node) {
- // Dummy implementation.
visit(node.expression);
- pop();
+ HInstruction yielded = pop();
+ add(new HYield(yielded, node.hasStar));
}
visitAwait(ast.Await node) {
- // Dummy implementation.
visit(node.expression);
+ HInstruction awaited = pop();
+ // TODO(herhut): Improve this type.
+ push(new HAwait(awaited, new TypeMask.subclass(compiler.objectClass,
+ compiler.world)));
}
visitTypeAnnotation(ast.TypeAnnotation node) {
@@ -5315,7 +5363,78 @@ class SsaBuilder extends ResolvedVisitor {
return new JumpHandler(this, element);
}
+ buildAsyncForIn(ast.ForIn node) {
+ assert(node.isAsync);
+ // The async-for is implemented with a StreamIterator.
+ HInstruction streamIterator;
+
+ visit(node.expression);
+ HInstruction expression = pop();
+ pushInvokeStatic(node,
+ backend.getStreamIteratorConstructor(),
+ [expression, graph.addConstantNull(compiler)]);
+ streamIterator = pop();
+
+ void buildInitializer() {}
+
+ HInstruction buildCondition() {
+ Selector selector = elements.getMoveNextSelector(node);
+ pushInvokeDynamic(node, selector, [streamIterator]);
+ HInstruction future = pop();
+ push(new HAwait(future, new TypeMask.subclass(compiler.objectClass,
+ compiler.world)));
+ return popBoolified();
+ }
+ void buildBody() {
+ Selector call = elements.getCurrentSelector(node);
+ pushInvokeDynamic(node, call, [streamIterator]);
+
+ ast.Node identifier = node.declaredIdentifier;
+ Element variable = elements.getForInVariable(node);
+ Selector selector = elements.getSelector(identifier);
+
+ HInstruction value = pop();
+ if (identifier.asSend() != null
+ && Elements.isInstanceSend(identifier, elements)) {
+ HInstruction receiver = generateInstanceSendReceiver(identifier);
+ assert(receiver != null);
+ generateInstanceSetterWithCompiledReceiver(
+ null,
+ receiver,
+ value,
+ selector: selector,
+ location: identifier);
+ } else {
+ generateNonInstanceSetter(
+ null, variable, value, location: identifier);
+ }
+ pop(); // Pop the value pushed by the setter call.
+
+ visit(node.body);
+ }
+
+ void buildUpdate() {};
+
+ buildProtectedByFinally(() {
+ handleLoop(node,
+ buildInitializer,
+ buildCondition,
+ buildUpdate,
+ buildBody);
+ }, () {
+ pushInvokeDynamic(node, new Selector.call("cancel", null, 0),
+ [streamIterator]);
+ push(new HAwait(pop(), new TypeMask.subclass(compiler.objectClass,
+ compiler.world)));
+ pop();
+ });
+ }
+
visitForIn(ast.ForIn node) {
+ if (node.isAsync) {
+ return buildAsyncForIn(node);
+ }
+
// Generate a structure equivalent to:
// Iterator<E> $iter = <iterable>.iterator;
// while ($iter.moveNext()) {
@@ -5851,6 +5970,85 @@ class SsaBuilder extends ResolvedVisitor {
compiler.internalError(node, 'SsaFromAstMixin.visitCaseMatch.');
}
+ /// Calls [buildTry] inside a synthetic try block with [buildFinally] in the
+ /// finally block.
+ void buildProtectedByFinally(void buildTry(), void buildFinally()) {
+ HBasicBlock enterBlock = openNewBlock();
+ HTry tryInstruction = new HTry();
+ close(tryInstruction);
+ bool oldInTryStatement = inTryStatement;
+ inTryStatement = true;
+
+ HBasicBlock startTryBlock;
+ HBasicBlock endTryBlock;
+ HBasicBlock startFinallyBlock;
+ HBasicBlock endFinallyBlock;
+
+ startTryBlock = graph.addNewBlock();
+ open(startTryBlock);
+ buildTry();
+ // We use a [HExitTry] instead of a [HGoto] for the try block
+ // because it will have two successors: the join block, and
+ // the finally block.
+ if (!isAborted()) endTryBlock = close(new HExitTry());
+ SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock);
+
+ SubGraph finallyGraph = null;
+
+ startFinallyBlock = graph.addNewBlock();
+ open(startFinallyBlock);
+ buildFinally();
+ if (!isAborted()) endFinallyBlock = close(new HGoto());
+ tryInstruction.finallyBlock = startFinallyBlock;
+ finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock);
+
+ HBasicBlock exitBlock = graph.addNewBlock();
+
+ void addExitTrySuccessor(HBasicBlock successor) {
+ // Iterate over all blocks created inside this try/catch, and
+ // attach successor information to blocks that end with
+ // [HExitTry].
+ for (int i = startTryBlock.id; i < successor.id; i++) {
+ HBasicBlock block = graph.blocks[i];
+ var last = block.last;
+ if (last is HExitTry) {
+ block.addSuccessor(successor);
+ }
+ }
+ }
+
+ // Setup all successors. The entry block that contains the [HTry]
+ // has 1) the body 2) the finally, and 4) the exit
+ // blocks as successors.
+ enterBlock.addSuccessor(startTryBlock);
+ enterBlock.addSuccessor(startFinallyBlock);
+ enterBlock.addSuccessor(exitBlock);
+
+ // The body has the finally block as successor.
+ if (endTryBlock != null) {
+ endTryBlock.addSuccessor(startFinallyBlock);
+ endTryBlock.addSuccessor(exitBlock);
+ }
+
+ // The finally block has the exit block as successor.
+ endFinallyBlock.addSuccessor(exitBlock);
+
+ // If a block inside try/catch aborts (eg with a return statement),
+ // we explicitely mark this block a predecessor of the catch
+ // block and the finally block.
+ addExitTrySuccessor(startFinallyBlock);
+
+ open(exitBlock);
+ enterBlock.setBlockFlow(
+ new HTryBlockInformation(
+ wrapStatementGraph(bodyGraph),
+ null, // No catch-variable.
+ null, // No catchGraph.
+ wrapStatementGraph(finallyGraph)),
+ exitBlock);
+ inTryStatement = oldInTryStatement;
+ }
+
visitTryStatement(ast.TryStatement node) {
// Save the current locals. The catch block and the finally block
// must not reuse the existing locals handler. None of the variables
@@ -6222,6 +6420,7 @@ class InlineWeeder extends ast.Visitor {
new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops);
weeder.visit(functionExpression.initializers);
weeder.visit(functionExpression.body);
+ weeder.visit(functionExpression.asyncModifier);
return !weeder.tooDifficult;
}
@@ -6248,6 +6447,13 @@ class InlineWeeder extends ast.Visitor {
}
}
+ @override
+ void visitAsyncModifier(ast.AsyncModifier node) {
+ if (node.isYielding || node.isAsynchronous) {
+ tooDifficult = true;
+ }
+ }
+
void visitFunctionExpression(ast.Node node) {
if (!registerNode()) return;
tooDifficult = true;
« no previous file with comments | « pkg/compiler/lib/src/resolution/registry.dart ('k') | pkg/compiler/lib/src/ssa/codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698