[dart2js] Smaller code by caching values
- Move more that one assignment into var-list
- Move 'this' to a local variable
- Move repeated large 'fast' constants to local variable
Currently under flag --experiment-code-1
Change-Id: I091cab47f498b4ec3759b9ed358bcc0f2e73fdb1
Reviewed-on: https://dart-review.googlesource.com/c/77025
Commit-Queue: Stephen Adams <sra@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 2bbd9c2..c68391d 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -26,6 +26,11 @@
'--experimental-track-allocations';
static const String experimentalAllocationsPath =
'--experimental-allocations-path';
+
+ // Temporary experiment for code generation of locals for frequently used
+ // 'this' and constants.
+ static const String experimentLocalNames = '--experiment-code-1';
+
static const String fastStartup = '--fast-startup';
static const String fatalWarnings = '--fatal-warnings';
static const String generateCodeWithCompileTimeErrors =
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 7b6ca85..5555b38 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -376,6 +376,8 @@
new OptionHandler(Flags.experimentalTrackAllocations, passThrough),
new OptionHandler("${Flags.experimentalAllocationsPath}=.+", passThrough),
+ new OptionHandler(Flags.experimentLocalNames, passThrough),
+
// The following three options must come last.
new OptionHandler('-D.+=.*', addInEnvironment),
new OptionHandler('-.*', (String argument) {
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 46ae073..c0d1ef5 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -679,7 +679,8 @@
List<js.Statement> statements = [
new js.ExpressionStatement(new js.VariableDeclarationList(
- holders.map(emitHolderInitialization).toList())),
+ holders.map(emitHolderInitialization).toList(),
+ indentSplits: false)),
js.js.statement(
'var holders = #',
new js.ArrayInitializer(holders
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index 9dbf70e..586171e 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -232,6 +232,9 @@
/// This is an experimental feature.
bool experimentalTrackAllocations = false;
+ /// Expermental optimization.
+ bool experimentLocalNames = false;
+
/// The path to the file that contains the profiled allocations.
///
/// The file must contain the Map that was produced by using
@@ -286,6 +289,7 @@
_hasOption(options, Flags.experimentalTrackAllocations)
..experimentalAllocationsPath = _extractStringOption(
options, "${Flags.experimentalAllocationsPath}=", null)
+ ..experimentLocalNames = _hasOption(options, Flags.experimentLocalNames)
..generateCodeWithCompileTimeErrors =
_hasOption(options, Flags.generateCodeWithCompileTimeErrors)
..generateSourceMap = !_hasOption(options, Flags.noSourceMaps)
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index 2a86ba0..61ed394 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -1395,7 +1395,7 @@
// TODO(efortuna): Source information!
push(new HInvokeStatic(
commonElements.loadDeferredLibrary,
- [graph.addConstantString(loadId, closedWorld)],
+ <HInstruction>[graph.addConstantString(loadId, closedWorld)],
abstractValueDomain.nonNullType,
const <DartType>[],
targetCanThrow: false));
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index fca7000..52cd6c9 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -184,6 +184,10 @@
* copies to perform on block transitioning.
*/
VariableNames variableNames;
+
+ /// `true` when we need to generate a `var` declaration at function entry,
+ /// `false` if we can generate a `var` declaration at first assignment in the
+ /// middle of the function.
bool shouldGroupVarDeclarations = false;
/**
@@ -370,6 +374,7 @@
.visitGraph(graph);
new SsaConditionMerger(generateAtUseSite, controlFlowOperators)
.visitGraph(graph);
+ new SsaShareRegionConstants(_options).visitGraph(graph);
SsaLiveIntervalBuilder intervalBuilder =
new SsaLiveIntervalBuilder(generateAtUseSite, controlFlowOperators);
intervalBuilder.visitGraph(graph);
@@ -384,6 +389,11 @@
}
void handleDelayedVariableDeclarations(SourceInformation sourceInformation) {
+ if (_options.experimentLocalNames) {
+ handleDelayedVariableDeclarations2(sourceInformation);
+ return;
+ }
+
// If we have only one variable declaration and the first statement is an
// assignment to that variable then we can merge the two. We count the
// number of variables in the variable allocator to try to avoid this issue,
@@ -426,6 +436,57 @@
}
}
+ void handleDelayedVariableDeclarations2(SourceInformation sourceInformation) {
+ // Create 'var' list at the start of function. Move assignment statements
+ // from the top of the body into the variable initializers.
+ if (collectedVariableDeclarations.isEmpty) return;
+
+ List<js.VariableInitialization> declarations = [];
+ List<js.Statement> statements = currentContainer.statements;
+ int nextStatement = 0;
+
+ while (nextStatement < statements.length) {
+ if (collectedVariableDeclarations.isEmpty) break;
+ js.Statement statement = statements[nextStatement];
+ if (statement is js.ExpressionStatement) {
+ js.Expression expression = statement.expression;
+ if (expression is js.Assignment && !expression.isCompound) {
+ js.Expression left = expression.leftHandSide;
+ if (left is js.VariableReference) {
+ String name = left.name;
+ js.Expression value = expression.value;
+ if (_safeInInitializer(value) &&
+ collectedVariableDeclarations.remove(name)) {
+ var initialization = new js.VariableInitialization(
+ new js.VariableDeclaration(name), value)
+ .withSourceInformation(expression.sourceInformation);
+ declarations.add(initialization);
+ ++nextStatement;
+ continue;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ List<js.VariableInitialization> uninitialized = [];
+ for (String name in collectedVariableDeclarations) {
+ uninitialized.add(new js.VariableInitialization(
+ new js.VariableDeclaration(name), null));
+ }
+ var declarationList =
+ new js.VariableDeclarationList(uninitialized + declarations)
+ .withSourceInformation(sourceInformation);
+ statements.replaceRange(
+ 0, nextStatement, [new js.ExpressionStatement(declarationList)]);
+ }
+
+ // An expression is safe to be pulled into a 'var' initializer if it does not
+ // contain assignments to locals. We don't generate assignments to locals
+ // inside expressions.
+ bool _safeInInitializer(js.Expression node) => true;
+
visitGraph(HGraph graph) {
preGenerateMethod(graph);
currentGraph = graph;
@@ -1400,6 +1461,10 @@
.withSourceInformation(sourceInformation));
}
+ visitLateValue(HLateValue node) {
+ use(node.target);
+ }
+
visitInvokeBinary(HInvokeBinary node, String op) {
handleInvokeBinary(node, op, node.sourceInformation);
}
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index 6608085..1a9ab2f 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -832,3 +832,188 @@
}
}
}
+
+/// Insert 'caches' for whole-function region-constants when the local minified
+/// name would be shorter than repeated references. These are caches for 'this'
+/// and constant values.
+class SsaShareRegionConstants extends HBaseVisitor {
+ final CompilerOptions _options;
+
+ SsaShareRegionConstants(this._options);
+
+ visitGraph(HGraph graph) {
+ if (!_options.experimentLocalNames) return;
+ // We need the async rewrite to be smarter about hoisting region constants
+ // before it is worth-while.
+ if (graph.needsAsyncRewrite) return;
+
+ // 'HThis' and constants are in the entry block. No need to walk the rest of
+ // the graph.
+ visitBasicBlock(graph.entry);
+ }
+
+ visitBasicBlock(HBasicBlock block) {
+ HInstruction instruction = block.first;
+ while (instruction != null) {
+ HInstruction next = instruction.next;
+ instruction.accept(this);
+ instruction = next;
+ }
+ }
+
+ // Not all occurences should be replaced with a local variable cache, so we
+ // filter the uses.
+ int _countCacheableUses(
+ HInstruction node, bool Function(HInstruction) cacheable) {
+ return node.usedBy.where(cacheable).length;
+ }
+
+ // Replace cacheable uses with a reference to a HLateValue node.
+ _cache(
+ HInstruction node, bool Function(HInstruction) cacheable, String name) {
+ var users = node.usedBy.toList();
+ var reference = new HLateValue(node);
+ // TODO(sra): The sourceInformation should really be from the function
+ // entry, not the use of `this`.
+ reference.sourceInformation = node.sourceInformation;
+ reference.sourceElement = _ExpressionName(name);
+ node.block.addAfter(node, reference);
+ for (HInstruction user in users) {
+ if (cacheable(user)) {
+ user.changeUse(node, reference);
+ }
+ }
+ }
+
+ void visitThis(HThis node) {
+ int size = 4;
+ // Compare the size of the unchanged minified with the size of the minified
+ // code where 'this' is assigned to a variable. We assume the variable has
+ // minified size 1.
+ //
+ // The size overhead of introducing a variable in the worst case includes
+ // 'var ':
+ //
+ // 1234 // size
+ // var x=this; // (minified ';' can be end-of-line)
+ // 123456 7 // additional overhead
+ //
+ // TODO(sra): If there are multiple values that can potentially be cached,
+ // they can share the 'var ' cost, even if none of them are beneficial
+ // individually.
+ int useCount = node.usedBy.length;
+ if (useCount * size <= 7 + size + useCount * 1) return;
+ _cache(node, (_) => true, '_this');
+ }
+
+ void visitConstant(HConstant node) {
+ if (node.usedBy.length <= 1) return;
+ ConstantValue constant = node.constant;
+
+ if (constant.isNull) {
+ _handleNull(node);
+ return;
+ }
+
+ if (constant.isInt) {
+ _handleInt(node, constant);
+ return;
+ }
+
+ if (constant.isString) {
+ _handleString(node, constant);
+ return;
+ }
+ }
+
+ void _handleNull(HConstant node) {
+ int size = 4;
+
+ bool _isCacheableUse(HInstruction instruction) {
+ // One-shot interceptors have `null` as a dummy interceptor.
+ if (instruction is HOneShotInterceptor) return false;
+
+ if (instruction is HInvoke) return true;
+ if (instruction is HCreate) return true;
+ if (instruction is HPhi) return true;
+
+ // We return `null` by removing the return expression or statement.
+ if (instruction is HReturn) return false;
+
+ // JavaScript `x == null` is more efficient than `x == _null`.
+ if (instruction is HIdentity) return false;
+
+ // TODO(sra): Deterimine if other uses result in faster JavaScript code.
+ return false;
+ }
+
+ int useCount = _countCacheableUses(node, _isCacheableUse);
+ if (useCount * size <= 7 + size + useCount * 1) return;
+ _cache(node, _isCacheableUse, '_null');
+ return;
+ }
+
+ void _handleInt(HConstant node, IntConstantValue intConstant) {
+ BigInt value = intConstant.intValue;
+ String text = value.toString();
+ int size = text.length;
+ if (size <= 3) return;
+
+ bool _isCacheableUse(HInstruction instruction) {
+ if (instruction is HInvoke) return true;
+ if (instruction is HCreate) return true;
+ if (instruction is HReturn) return true;
+ if (instruction is HPhi) return true;
+
+ // JavaScript `x === 5` is more efficient than `x === _5`.
+ if (instruction is HIdentity) return false;
+
+ // Foreign code templates may use literals in ways that are beneficial.
+ if (instruction is HForeignCode) return false;
+
+ // TODO(sra): Deterimine if other uses result in faster JavaScript code.
+ return false;
+ }
+
+ int useCount = _countCacheableUses(node, _isCacheableUse);
+ if (useCount * size <= 7 + size + useCount * 1) return;
+ _cache(node, _isCacheableUse, '_${text.replaceFirst("-", "_")}');
+ }
+
+ void _handleString(HConstant node, StringConstantValue stringConstant) {
+ String value = stringConstant.stringValue;
+ int length = value.length;
+ int size = length + 2; // Include quotes.
+ if (size <= 2) return;
+
+ bool _isCacheableUse(HInstruction instruction) {
+ // Foreign code templates may use literals in ways that are beneficial.
+ if (instruction is HForeignCode) return false;
+
+ // Cache larger strings even if unfortunate.
+ if (length >= 16) return true;
+
+ if (instruction is HInvoke) return true;
+ if (instruction is HCreate) return true;
+ if (instruction is HReturn) return true;
+ if (instruction is HPhi) return true;
+
+ // TODO(sra): Check if a.x="s" can avoid or specialize a write barrier.
+ if (instruction is HFieldSet) return true;
+
+ // TODO(sra): Deterimine if other uses result in faster JavaScript code.
+ return false;
+ }
+
+ int useCount = _countCacheableUses(node, _isCacheableUse);
+ if (useCount * size <= 7 + size + useCount * 1) return;
+ _cache(node, _isCacheableUse, '_s${length}_');
+ }
+}
+
+/// A simple Entity to give intermediate values nice names when not generating
+/// minified code.
+class _ExpressionName implements Entity {
+ final String name;
+ _ExpressionName(this.name);
+}
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 32ea8a9..f815b64 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -65,6 +65,7 @@
R visitInvokeGeneratorBody(HInvokeGeneratorBody node);
R visitIs(HIs node);
R visitIsViaInterceptor(HIsViaInterceptor node);
+ R visitLateValue(HLateValue node);
R visitLazyStatic(HLazyStatic node);
R visitLess(HLess node);
R visitLessEqual(HLessEqual node);
@@ -478,6 +479,7 @@
visitTruncatingDivide(HTruncatingDivide node) => visitBinaryArithmetic(node);
visitTry(HTry node) => visitControlFlow(node);
visitIs(HIs node) => visitInstruction(node);
+ visitLateValue(HLateValue node) => visitInstruction(node);
visitIsViaInterceptor(HIsViaInterceptor node) => visitInstruction(node);
visitTypeConversion(HTypeConversion node) => visitCheck(node);
visitTypeKnown(HTypeKnown node) => visitCheck(node);
@@ -3077,6 +3079,22 @@
}
}
+/// HLateValue is a late-stage instruction that can be used to force a value
+/// into a temporary.
+///
+/// HLateValue is useful for naming values that would otherwise be generated at
+/// use site, for example, if 'this' is used many times, replacing uses of
+/// 'this' with HLateValhe(HThis) will have the effect of copying 'this' to a
+/// temporary will reduce the size of minified code.
+class HLateValue extends HLateInstruction {
+ HLateValue(HInstruction target) : super([target], target.instructionType);
+
+ HInstruction get target => inputs.single;
+
+ accept(HVisitor visitor) => visitor.visitLateValue(this);
+ toString() => 'HLateValue($target)';
+}
+
class HTypeConversion extends HCheck {
// Values for [kind].
static const int CHECKED_MODE_CHECK = 0;
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index f72cc6b..61a56cd 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -158,6 +158,10 @@
return "$prefix${instruction.id}";
}
+ String visitLateValue(HLateValue node) {
+ return "LateValue: ${temporaryId(node.inputs[0])}";
+ }
+
String visitBoolify(HBoolify node) {
return "Boolify: ${temporaryId(node.inputs[0])}";
}
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index 9b933ae..2c44a3c 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -1046,7 +1046,12 @@
class VariableDeclarationList extends Expression {
final List<VariableInitialization> declarations;
- VariableDeclarationList(this.declarations);
+ /// When pretty-printing a declaration list with multiple declarations over
+ /// several lines, the declarations are usually indented with respect to the
+ /// `var` keyword. Set [indentSplits] to `false` to suppress the indentation.
+ final bool indentSplits;
+
+ VariableDeclarationList(this.declarations, {this.indentSplits = true});
T accept<T>(NodeVisitor<T> visitor) =>
visitor.visitVariableDeclarationList(this);
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index 21f94bd..e56cca8 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -678,8 +678,53 @@
@override
visitVariableDeclarationList(VariableDeclarationList list) {
out("var ");
- visitCommaSeparated(list.declarations, ASSIGNMENT,
- newInForInit: inForInit, newAtStatementBegin: false);
+ List<Node> nodes = list.declarations;
+ if (inForInit) {
+ visitCommaSeparated(nodes, ASSIGNMENT,
+ newInForInit: inForInit, newAtStatementBegin: false);
+ } else {
+ // Print 'big' declarations on their own line, while keeping adjacent
+ // small and uninitialized declarations on the same line.
+ bool useIndent = nodes.length > 1 && list.indentSplits;
+ if (useIndent) {
+ indentMore();
+ }
+ bool lastWasBig = false;
+ for (int i = 0; i < nodes.length; i++) {
+ Node node = nodes[i];
+ bool thisIsBig = !_isSmallInitialization(node);
+ if (i > 0) {
+ atStatementBegin = false;
+ out(",");
+ if (lastWasBig || thisIsBig) {
+ lineOut();
+ indent();
+ } else {
+ spaceOut();
+ }
+ }
+ visitNestedExpression(node, ASSIGNMENT,
+ newInForInit: inForInit, newAtStatementBegin: false);
+ lastWasBig = thisIsBig;
+ }
+ if (useIndent) {
+ indentLess();
+ }
+ }
+ }
+
+ static bool _isSmallInitialization(Node node) {
+ if (node is VariableInitialization) {
+ Node value = node.value;
+ if (value == null) return true;
+ if (value is This) return true;
+ if (value is LiteralNull) return true;
+ if (value is LiteralNumber) return true;
+ if (value is LiteralString && value.value.length <= 8) return true;
+ if (value is ObjectInitializer && value.properties.isEmpty) return true;
+ if (value is ArrayInitializer && value.elements.isEmpty) return true;
+ }
+ return false;
}
@override
diff --git a/tests/compiler/dart2js/async_await/async_await_js_transform_test.dart b/tests/compiler/dart2js/async_await/async_await_js_transform_test.dart
index f86c1f1..d31c169 100644
--- a/tests/compiler/dart2js/async_await/async_await_js_transform_test.dart
+++ b/tests/compiler/dart2js/async_await/async_await_js_transform_test.dart
@@ -66,7 +66,9 @@
/// 01: ok
r"""function() {
- var __goto = 0, __completer = NewCompleter(CompleterType), closures, v0, v1, v2, v3;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ closures, v0, v1, v2, v3;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -102,7 +104,9 @@
await foo();
}""", """
function(a) {
- var __goto = 0, __completer = NewCompleter(CompleterType), __self = this;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ __self = this;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -147,7 +151,9 @@
return 4;
}""", """
function(b) {
- var __goto = 0, __completer = NewCompleter(CompleterType), __returnValue, __handler = 2, __currentError, __next = [], __helper;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ __returnValue, __handler = 2, __currentError, __next = [], __helper;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1) {
__currentError = __result;
@@ -257,7 +263,9 @@
f = --foo1()[await foo2()];
}""", """
function(c) {
- var __goto = 0, __completer = NewCompleter(CompleterType), a, b, c, d, e, f, __temp1;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ a, b, c, d, e, f, __temp1;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -309,7 +317,9 @@
h = foo1() && foo2();
}""", """
function(d2) {
- var __goto = 0, __completer = NewCompleter(CompleterType), a, b, c, d, e, f, g, h, __temp1;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ a, b, c, d, e, f, g, h, __temp1;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -441,7 +451,8 @@
}
}""", """
function(x, y) {
- var __goto = 0, __completer = NewCompleter(CompleterType);
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType);
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -525,7 +536,9 @@
}
""", """
function(f) {
- var __goto = 0, __completer = NewCompleter(CompleterType), a;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ a;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -585,7 +598,9 @@
}
""", """
function(g) {
- var __goto = 0, __completer = NewCompleter(CompleterType), __returnValue, i, __temp1;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ __returnValue, i, __temp1;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -665,7 +680,9 @@
}
""", """
function(a, h) {
- var __goto = 0, __completer = NewCompleter(CompleterType), x, __temp1, __temp2;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ x, __temp1, __temp2;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -741,7 +758,9 @@
}
""", """
function(c, i) {
- var __goto = 0, __completer = NewCompleter(CompleterType), __handler = 1, __currentError, __next = [], x, y, __error, __error1;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ __handler = 1, __currentError, __next = [], x, y, __error, __error1;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1) {
__currentError = __result;
@@ -851,7 +870,9 @@
}
""", """
function(x, y, j) {
- var __goto = 0, __completer = NewCompleter(CompleterType), __temp1, __temp2, __temp3;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ __temp1, __temp2, __temp3;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -929,7 +950,9 @@
}
}""", """
function(x, y, k) {
- var __goto = 0, __completer = NewCompleter(CompleterType), __returnValue, __temp1;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ __returnValue, __temp1;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -1052,7 +1075,8 @@
}
}""", """
function(l) {
- var __goto = 0, __completer = NewCompleter(CompleterType);
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType);
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1)
return rethrowHelper(__result, __completer);
@@ -1099,7 +1123,9 @@
print(exception);
}""", """
function(m) {
- var __goto = 0, __completer = NewCompleter(CompleterType), __handler = 1, __currentError, __next = [], exception, __exception;
+ var __goto = 0,
+ __completer = NewCompleter(CompleterType),
+ __handler = 1, __currentError, __next = [], exception, __exception;
var body = _wrapJsFunctionForAsync(function(__errorCode, __result) {
if (__errorCode === 1) {
__currentError = __result;
diff --git a/tests/compiler/dart2js/sourcemaps/helpers/html_parts.dart b/tests/compiler/dart2js/sourcemaps/helpers/html_parts.dart
index 5724641..77dd7cf 100644
--- a/tests/compiler/dart2js/sourcemaps/helpers/html_parts.dart
+++ b/tests/compiler/dart2js/sourcemaps/helpers/html_parts.dart
@@ -84,7 +84,7 @@
data['title'] = annotations.map((l) => l.title).join(',');
}
if (id != null) {
- Set ids = annotations.map((l) => l.id).toSet();
+ Set ids = annotations.map<int>((l) => l.id).toSet();
data['name'] = elementScheme.getName(id, ids);
data['href'] = elementScheme.getHref(id, ids);
data['onclick'] = elementScheme.onClick(id, ids);