Index: pkg/compiler/lib/src/js/rewrite_async.dart |
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart |
index 961ec7b80f28af26cb94433d0f55431b1129310d..7e0ecb548329f5e00c226a05c3cc259558714476 100644 |
--- a/pkg/compiler/lib/src/js/rewrite_async.dart |
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart |
@@ -4,8 +4,6 @@ |
library rewrite_async; |
-// TODO(sigurdm): Avoid using variables in templates. It could blow up memory |
-// use. |
// TODO(sigurdm): Move the try/catch expression to a js_helper function. |
// That would also simplify the sync* case, where the error can just be thrown. |
@@ -601,22 +599,25 @@ class AsyncRewriter extends js.NodeVisitor { |
} |
switch (async) { |
case const js.AsyncModifier.async(): |
- String returnValue = |
- analysis.hasExplicitReturns ? returnValueName : "null"; |
addStatement(js.js.statement( |
- "return #thenHelper($returnValue, #successCode, " |
- "$completerName, null)", { |
- "thenHelper": asyncHelper, |
- "successCode": js.number(error_codes.SUCCESS)})); |
+ "return #runtimeHelper(#returnValue, #successCode, " |
+ "#completer, null)", { |
+ "runtimeHelper": asyncHelper, |
+ "successCode": js.number(error_codes.SUCCESS), |
+ "returnValue": analysis.hasExplicitReturns |
+ ? returnValueName |
+ : new js.LiteralNull(), |
+ "completer": completerName})); |
break; |
case const js.AsyncModifier.syncStar(): |
addStatement(new js.Return(new js.Call(endOfIteration, []))); |
break; |
case const js.AsyncModifier.asyncStar(): |
addStatement(js.js.statement( |
- "return #streamHelper(null, #successCode, $controllerName)", { |
+ "return #streamHelper(null, #successCode, #controller)", { |
"streamHelper": streamHelper, |
- "successCode": js.number(error_codes.SUCCESS)})); |
+ "successCode": js.number(error_codes.SUCCESS), |
+ "controller": controllerName})); |
break; |
default: |
diagnosticListener.internalError( |
@@ -625,10 +626,11 @@ class AsyncRewriter extends js.NodeVisitor { |
if (isAsync || isAsyncStar) { |
beginLabel(rethrowLabel); |
addStatement(js.js.statement( |
- "return #thenHelper($currentErrorName, #errorCode, " |
- "${isAsync ? completerName : controllerName})", { |
+ "return #thenHelper(#currentError, #errorCode, #controller)", { |
"thenHelper": isAsync ? asyncHelper : streamHelper, |
- "errorCode": js.number(error_codes.ERROR)})); |
+ "errorCode": js.number(error_codes.ERROR), |
+ "currentError": currentErrorName, |
+ "controller": isAsync ? completerName : controllerName})); |
} else { |
assert(isSyncStar); |
beginLabel(rethrowLabel); |
@@ -647,13 +649,16 @@ class AsyncRewriter extends js.NodeVisitor { |
js.Statement generateInitializer() { |
if (isAsync) { |
return js.js.statement( |
- "return #asyncHelper(null, $bodyName, $completerName, null);", { |
- "asyncHelper": asyncHelper |
+ "return #asyncHelper(null, #body, #completer, null);", { |
+ "asyncHelper": asyncHelper, |
+ "body": bodyName, |
+ "completer": completerName, |
}); |
} else if (isAsyncStar) { |
return js.js.statement( |
- "return #streamOfController($controllerName);", { |
- "streamOfController": streamOfController |
+ "return #streamOfController(#controller);", { |
+ "streamOfController": streamOfController, |
+ "controller": controllerName, |
}); |
} else { |
throw diagnosticListener.internalError( |
@@ -828,15 +833,21 @@ class AsyncRewriter extends js.NodeVisitor { |
js.Statement helperBody = |
new js.Switch(new js.VariableUse(gotoName), clauses); |
if (hasJumpThoughOuterLabel) { |
- helperBody = js.js.statement("$outerLabelName: #", [helperBody]); |
+ helperBody = new js.LabeledStatement(outerLabelName, helperBody); |
} |
helperBody = js.js.statement(""" |
try { |
#body |
- } catch ($errorName){ |
- $currentErrorName = $errorName; |
- $gotoName = $handlerName; |
- }""", {"body": helperBody}); |
+ } catch (#error){ |
+ #currentError = #error; |
+ #goto = #handler; |
+ }""", { |
+ "body": helperBody, |
+ "goto": gotoName, |
+ "error": errorName, |
+ "currentError": currentErrorName, |
+ "handler": handlerName, |
+ }); |
List<js.VariableInitialization> inits = <js.VariableInitialization>[]; |
js.VariableInitialization makeInit(String name, js.Expression initValue) { |
@@ -878,10 +889,10 @@ class AsyncRewriter extends js.NodeVisitor { |
return js.js(""" |
function (#params) { |
if (#needsThis) |
- var $selfName = this; |
+ var #self = this; |
return new #newIterable(function () { |
#varDecl; |
- return function $bodyName() { |
+ return function #body() { |
while (true) |
#helperBody; |
}; |
@@ -892,27 +903,29 @@ class AsyncRewriter extends js.NodeVisitor { |
"needsThis": analysis.hasThis, |
"helperBody": helperBody, |
"varDecl": varDecl, |
- "newIterable": newIterable |
+ "newIterable": newIterable, |
+ "body": bodyName, |
+ "self": selfName, |
}); |
} |
return js.js(""" |
function (#params) { |
#varDecl; |
- function $bodyName($errorCodeName, $resultName) { |
+ function #bodyName(#errorCode, #result) { |
if (#hasYield) |
- switch ($errorCodeName) { |
- case #streamWasCanceled: |
- $nextName = $nextWhenCanceledName; |
- $gotoName = $nextName.pop(); |
+ switch (#errorCode) { |
+ case #STREAM_WAS_CANCELED: |
+ #next = #nextWhenCanceled; |
+ #goto = #next.pop(); |
break; |
- case #errorCode: |
- $currentErrorName = $resultName; |
- $gotoName = $handlerName; |
+ case #ERROR: |
+ #currentError = #result; |
+ #goto = #handler; |
} |
else |
- if ($errorCodeName == #errorCode) { |
- $currentErrorName = $resultName; |
- $gotoName = $handlerName; |
+ if (#errorCode == #ERROR) { |
+ #currentError = #result; |
+ #goto = #handler; |
} |
while (true) |
#helperBody; |
@@ -921,11 +934,19 @@ class AsyncRewriter extends js.NodeVisitor { |
}""", { |
"params": node.params, |
"varDecl": varDecl, |
- "streamWasCanceled": js.number(error_codes.STREAM_WAS_CANCELED), |
- "errorCode": js.number(error_codes.ERROR), |
+ "STREAM_WAS_CANCELED": js.number(error_codes.STREAM_WAS_CANCELED), |
+ "ERROR": js.number(error_codes.ERROR), |
"hasYield": analysis.hasYield, |
"helperBody": helperBody, |
- "init": generateInitializer() |
+ "init": generateInitializer(), |
+ "bodyName": bodyName, |
+ "currentError": currentErrorName, |
+ "goto": gotoName, |
+ "handler": handlerName, |
+ "next": nextName, |
+ "nextWhenCanceled": nextWhenCanceledName, |
+ "errorCode": errorCodeName, |
+ "result": resultName, |
}); |
} |
@@ -984,11 +1005,13 @@ class AsyncRewriter extends js.NodeVisitor { |
addStatement(setGotoVariable(afterAwait)); |
addStatement(js.js.statement(""" |
return #asyncHelper(#value, |
- $bodyName, |
- ${isAsync ? completerName : controllerName}); |
+ #body, |
+ #controller); |
""", { |
"asyncHelper": isAsync ? asyncHelper : streamHelper, |
"value": value, |
+ "body": bodyName, |
+ "controller": isAsync ? completerName : controllerName, |
})); |
}, store: false); |
beginLabel(afterAwait); |
@@ -1165,7 +1188,7 @@ class AsyncRewriter extends js.NodeVisitor { |
hasJumpThroughFinally = true; |
js.Expression jsJumpStack = new js.ArrayInitializer( |
jumpStack.map((int label) => js.number(label)).toList()); |
- addStatement(js.js.statement("$nextName = #", [jsJumpStack])); |
+ addStatement(js.js.statement("# = #", [nextName, jsJumpStack])); |
} |
addGoto(firstTarget); |
} |
@@ -1338,6 +1361,11 @@ class AsyncRewriter extends js.NodeVisitor { |
} |
@override |
+ visitInterpolatedDeclaration(js.InterpolatedDeclaration node) { |
+ return unsupported(node); |
+ } |
+ |
+ @override |
visitInterpolatedLiteral(js.InterpolatedLiteral node) => unsupported(node); |
@override |
@@ -1485,7 +1513,7 @@ class AsyncRewriter extends js.NodeVisitor { |
js.Node target = analysis.targets[node]; |
if (node.value != null) { |
withExpression(node.value, (js.Expression value) { |
- addStatement(js.js.statement("$returnValueName = #", [value])); |
+ addStatement(js.js.statement("# = #", [returnValueName, value])); |
}, store: false); |
} |
translateJump(target, exitLabel); |
@@ -1666,7 +1694,8 @@ class AsyncRewriter extends js.NodeVisitor { |
} else { |
// The handler is reset as the first thing in the finally block. |
addStatement( |
- js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)])); |
+ js.js.statement("# = [#];", |
+ [nextName, js.number(afterFinallyLabel)])); |
addGoto(finallyLabel); |
} |
@@ -1692,8 +1721,8 @@ class AsyncRewriter extends js.NodeVisitor { |
if (node.finallyPart != null) { |
// The error has been caught, so after the finally, continue after the |
// try. |
- addStatement(js.js.statement("$nextName = [#];", |
- [js.number(afterFinallyLabel)])); |
+ addStatement(js.js.statement("# = [#];", |
+ [nextName, js.number(afterFinallyLabel)])); |
addGoto(finallyLabel); |
} else { |
addGoto(afterFinallyLabel); |
@@ -1713,8 +1742,8 @@ class AsyncRewriter extends js.NodeVisitor { |
// [enclosingFinallies] can be empty if there is no surrounding finally |
// blocks. Then [nextLabel] will be [rethrowLabel]. |
addStatement( |
- js.js.statement("$nextName = #;", new js.ArrayInitializer( |
- enclosingFinallies.map(js.number).toList()))); |
+ js.js.statement("# = #;", [nextName, new js.ArrayInitializer( |
+ enclosingFinallies.map(js.number).toList())])); |
} |
if (node.finallyPart == null) { |
// The finally-block belonging to [node] will be visited because of |
@@ -1729,7 +1758,7 @@ class AsyncRewriter extends js.NodeVisitor { |
setErrorHandler(); |
visitStatement(node.finallyPart); |
addStatement(new js.Comment("// goto the next finally handler")); |
- addStatement(js.js.statement("$gotoName = $nextName.pop();")); |
+ addStatement(js.js.statement("# = #.pop();", [gotoName, nextName])); |
addBreak(); |
} |
beginLabel(afterFinallyLabel); |
@@ -1832,15 +1861,17 @@ class AsyncRewriter extends js.NodeVisitor { |
enclosingFinallyLabels.addAll(jumpTargets |
.where((js.Node node) => finallyLabels[node] != null) |
.map((js.Block node) => finallyLabels[node])); |
- addStatement(js.js.statement("$nextWhenCanceledName = #", |
- [new js.ArrayInitializer(enclosingFinallyLabels.map(js.number) |
- .toList())])); |
+ addStatement(js.js.statement("# = #;", |
+ [nextWhenCanceledName, new js.ArrayInitializer( |
+ enclosingFinallyLabels.map(js.number).toList())])); |
addStatement(js.js.statement(""" |
- return #streamHelper(#yieldExpression(#expression), |
- $bodyName, $controllerName);""", { |
+ return #streamHelper(#yieldExpression(#expression), #body, |
+ #controller);""", { |
"streamHelper": streamHelper, |
"yieldExpression": node.hasStar ? yieldStarExpression : yieldExpression, |
"expression": expression, |
+ "body": bodyName, |
+ "controller": controllerName, |
})); |
} |
@@ -2089,6 +2120,11 @@ class PreTranslationAnalysis extends js.NodeVisitor<bool> { |
} |
@override |
+ bool visitInterpolatedDeclaration(js.InterpolatedDeclaration node) { |
+ return unsupported(node); |
+ } |
+ |
+ @override |
bool visitInterpolatedLiteral(js.InterpolatedLiteral node) { |
return unsupported(node); |
} |