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

Side by Side Diff: pkg/compiler/lib/src/ssa/codegen.dart

Issue 1859343004: dartfmt pkg/compiler (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 8 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 unified diff | Download patch
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/codegen_helpers.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import '../common.dart'; 5 import '../common.dart';
6 import '../common/codegen.dart' show 6 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
7 CodegenRegistry, 7 import '../common/tasks.dart' show CompilerTask;
8 CodegenWorkItem; 8 import '../compiler.dart' show Compiler;
9 import '../common/tasks.dart' show
10 CompilerTask;
11 import '../compiler.dart' show
12 Compiler;
13 import '../constants/constant_system.dart'; 9 import '../constants/constant_system.dart';
14 import '../constants/values.dart'; 10 import '../constants/values.dart';
15 import '../core_types.dart' show 11 import '../core_types.dart' show CoreClasses;
16 CoreClasses;
17 import '../dart_types.dart'; 12 import '../dart_types.dart';
18 import '../elements/elements.dart'; 13 import '../elements/elements.dart';
19 import '../io/source_information.dart'; 14 import '../io/source_information.dart';
20 import '../js/js.dart' as js; 15 import '../js/js.dart' as js;
21 import '../js_backend/backend_helpers.dart' show 16 import '../js_backend/backend_helpers.dart' show BackendHelpers;
22 BackendHelpers;
23 import '../js_backend/js_backend.dart'; 17 import '../js_backend/js_backend.dart';
24 import '../js_emitter/js_emitter.dart' show 18 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
25 CodeEmitterTask,
26 NativeEmitter;
27 import '../native/native.dart' as native; 19 import '../native/native.dart' as native;
28 import '../types/types.dart'; 20 import '../types/types.dart';
29 import '../universe/call_structure.dart' show 21 import '../universe/call_structure.dart' show CallStructure;
30 CallStructure; 22 import '../universe/selector.dart' show Selector;
31 import '../universe/selector.dart' show 23 import '../universe/use.dart' show DynamicUse, StaticUse, TypeUse;
32 Selector;
33 import '../universe/use.dart' show
34 DynamicUse,
35 StaticUse,
36 TypeUse;
37 import '../util/util.dart'; 24 import '../util/util.dart';
38 import '../world.dart' show 25 import '../world.dart' show ClassWorld, World;
39 ClassWorld,
40 World;
41 26
42 import 'nodes.dart'; 27 import 'nodes.dart';
43 import 'codegen_helpers.dart'; 28 import 'codegen_helpers.dart';
44 import 'variable_allocator.dart'; 29 import 'variable_allocator.dart';
45 30
46 class SsaCodeGeneratorTask extends CompilerTask { 31 class SsaCodeGeneratorTask extends CompilerTask {
47
48 final JavaScriptBackend backend; 32 final JavaScriptBackend backend;
49 final SourceInformationStrategy sourceInformationFactory; 33 final SourceInformationStrategy sourceInformationFactory;
50 34
51 SsaCodeGeneratorTask(JavaScriptBackend backend, 35 SsaCodeGeneratorTask(JavaScriptBackend backend, this.sourceInformationFactory)
52 this.sourceInformationFactory)
53 : this.backend = backend, 36 : this.backend = backend,
54 super(backend.compiler); 37 super(backend.compiler);
55 38
56 String get name => 'SSA code generator'; 39 String get name => 'SSA code generator';
57 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; 40 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter;
58 41
59 js.Fun buildJavaScriptFunction(FunctionElement element, 42 js.Fun buildJavaScriptFunction(
60 List<js.Parameter> parameters, 43 FunctionElement element, List<js.Parameter> parameters, js.Block body) {
61 js.Block body) {
62 js.AsyncModifier asyncModifier = element.asyncMarker.isAsync 44 js.AsyncModifier asyncModifier = element.asyncMarker.isAsync
63 ? (element.asyncMarker.isYielding 45 ? (element.asyncMarker.isYielding
64 ? const js.AsyncModifier.asyncStar() 46 ? const js.AsyncModifier.asyncStar()
65 : const js.AsyncModifier.async()) 47 : const js.AsyncModifier.async())
66 : (element.asyncMarker.isYielding 48 : (element.asyncMarker.isYielding
67 ? const js.AsyncModifier.syncStar() 49 ? const js.AsyncModifier.syncStar()
68 : const js.AsyncModifier.sync()); 50 : const js.AsyncModifier.sync());
69 51
70 return new js.Fun(parameters, body, asyncModifier: asyncModifier) 52 return new js.Fun(parameters, body, asyncModifier: asyncModifier)
71 .withSourceInformation( 53 .withSourceInformation(sourceInformationFactory
72 sourceInformationFactory.createBuilderForContext(element) 54 .createBuilderForContext(element)
73 .buildDeclaration(element)); 55 .buildDeclaration(element));
74 } 56 }
75 57
76 js.Expression generateCode(CodegenWorkItem work, HGraph graph) { 58 js.Expression generateCode(CodegenWorkItem work, HGraph graph) {
77 if (work.element.isField) { 59 if (work.element.isField) {
78 return generateLazyInitializer(work, graph); 60 return generateLazyInitializer(work, graph);
79 } else { 61 } else {
80 return generateMethod(work, graph); 62 return generateMethod(work, graph);
81 } 63 }
82 } 64 }
83 65
84 js.Expression generateLazyInitializer(work, graph) { 66 js.Expression generateLazyInitializer(work, graph) {
85 return measure(() { 67 return measure(() {
86 compiler.tracer.traceGraph("codegen", graph); 68 compiler.tracer.traceGraph("codegen", graph);
87 SourceInformation sourceInformation = 69 SourceInformation sourceInformation = sourceInformationFactory
88 sourceInformationFactory.createBuilderForContext(work.element) 70 .createBuilderForContext(work.element)
89 .buildDeclaration(work.element); 71 .buildDeclaration(work.element);
90 SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work); 72 SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work);
91 codegen.visitGraph(graph); 73 codegen.visitGraph(graph);
92 return new js.Fun(codegen.parameters, codegen.body) 74 return new js.Fun(codegen.parameters, codegen.body)
93 .withSourceInformation(sourceInformation); 75 .withSourceInformation(sourceInformation);
94 }); 76 });
95 } 77 }
96 78
97 js.Expression generateMethod(CodegenWorkItem work, HGraph graph) { 79 js.Expression generateMethod(CodegenWorkItem work, HGraph graph) {
98 return measure(() { 80 return measure(() {
99 FunctionElement element = work.element; 81 FunctionElement element = work.element;
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
170 HGraph currentGraph; 152 HGraph currentGraph;
171 153
172 // Records a block-information that is being handled specially. 154 // Records a block-information that is being handled specially.
173 // Used to break bad recursion. 155 // Used to break bad recursion.
174 HBlockInformation currentBlockInformation; 156 HBlockInformation currentBlockInformation;
175 // The subgraph is used to delimit traversal for some constructions, e.g., 157 // The subgraph is used to delimit traversal for some constructions, e.g.,
176 // if branches. 158 // if branches.
177 SubGraph subGraph; 159 SubGraph subGraph;
178 160
179 SsaCodeGenerator(this.backend, CodegenWorkItem work, 161 SsaCodeGenerator(this.backend, CodegenWorkItem work,
180 {SourceInformation sourceInformation}) 162 {SourceInformation sourceInformation})
181 : this.work = work, 163 : this.work = work,
182 declaredLocals = new Set<String>(), 164 declaredLocals = new Set<String>(),
183 collectedVariableDeclarations = new Set<String>(), 165 collectedVariableDeclarations = new Set<String>(),
184 currentContainer = new js.Block.empty(), 166 currentContainer = new js.Block.empty(),
185 parameters = <js.Parameter>[], 167 parameters = <js.Parameter>[],
186 expressionStack = <js.Expression>[], 168 expressionStack = <js.Expression>[],
187 oldContainerStack = <js.Block>[], 169 oldContainerStack = <js.Block>[],
188 generateAtUseSite = new Set<HInstruction>(), 170 generateAtUseSite = new Set<HInstruction>(),
189 controlFlowOperators = new Set<HInstruction>(), 171 controlFlowOperators = new Set<HInstruction>(),
190 breakAction = new Map<Entity, EntityAction>(), 172 breakAction = new Map<Entity, EntityAction>(),
191 continueAction = new Map<Entity, EntityAction>(); 173 continueAction = new Map<Entity, EntityAction>();
192 174
193 Compiler get compiler => backend.compiler; 175 Compiler get compiler => backend.compiler;
194 176
195 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter; 177 NativeEmitter get nativeEmitter => backend.emitter.nativeEmitter;
196 178
197 CodegenRegistry get registry => work.registry; 179 CodegenRegistry get registry => work.registry;
198 180
199 BackendHelpers get helpers => backend.helpers; 181 BackendHelpers get helpers => backend.helpers;
200 182
201 native.NativeEnqueuer get nativeEnqueuer { 183 native.NativeEnqueuer get nativeEnqueuer {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 } 223 }
242 224
243 void insertStatementAtStart(js.Statement statement) { 225 void insertStatementAtStart(js.Statement statement) {
244 currentContainer.statements.insert(0, statement); 226 currentContainer.statements.insert(0, statement);
245 } 227 }
246 228
247 /** 229 /**
248 * If the [instruction] is not `null` it will be used to attach the position 230 * If the [instruction] is not `null` it will be used to attach the position
249 * to the [expression]. 231 * to the [expression].
250 */ 232 */
251 pushExpressionAsStatement(js.Expression expression, 233 pushExpressionAsStatement(
252 SourceInformation sourceInformation) { 234 js.Expression expression, SourceInformation sourceInformation) {
253 pushStatement(new js.ExpressionStatement(expression) 235 pushStatement(new js.ExpressionStatement(expression)
254 .withSourceInformation(sourceInformation)); 236 .withSourceInformation(sourceInformation));
255 } 237 }
256 238
257 /** 239 /**
258 * If the [instruction] is not `null` it will be used to attach the position 240 * If the [instruction] is not `null` it will be used to attach the position
259 * to the [expression]. 241 * to the [expression].
260 */ 242 */
261 push(js.Expression expression) { 243 push(js.Expression expression) {
262 expressionStack.add(expression); 244 expressionStack.add(expression);
263 } 245 }
264 246
265 js.Expression pop() { 247 js.Expression pop() {
266 return expressionStack.removeLast(); 248 return expressionStack.removeLast();
267 } 249 }
268 250
269 void preGenerateMethod(HGraph graph) { 251 void preGenerateMethod(HGraph graph) {
270 new SsaInstructionSelection(compiler).visitGraph(graph); 252 new SsaInstructionSelection(compiler).visitGraph(graph);
271 new SsaTypeKnownRemover().visitGraph(graph); 253 new SsaTypeKnownRemover().visitGraph(graph);
272 new SsaTrustedCheckRemover(compiler).visitGraph(graph); 254 new SsaTrustedCheckRemover(compiler).visitGraph(graph);
273 new SsaInstructionMerger(generateAtUseSite, compiler).visitGraph(graph); 255 new SsaInstructionMerger(generateAtUseSite, compiler).visitGraph(graph);
274 new SsaConditionMerger( 256 new SsaConditionMerger(generateAtUseSite, controlFlowOperators)
275 generateAtUseSite, controlFlowOperators).visitGraph(graph); 257 .visitGraph(graph);
276 SsaLiveIntervalBuilder intervalBuilder = new SsaLiveIntervalBuilder( 258 SsaLiveIntervalBuilder intervalBuilder = new SsaLiveIntervalBuilder(
277 compiler, generateAtUseSite, controlFlowOperators); 259 compiler, generateAtUseSite, controlFlowOperators);
278 intervalBuilder.visitGraph(graph); 260 intervalBuilder.visitGraph(graph);
279 SsaVariableAllocator allocator = new SsaVariableAllocator( 261 SsaVariableAllocator allocator = new SsaVariableAllocator(
280 compiler, 262 compiler,
281 intervalBuilder.liveInstructions, 263 intervalBuilder.liveInstructions,
282 intervalBuilder.liveIntervals, 264 intervalBuilder.liveIntervals,
283 generateAtUseSite); 265 generateAtUseSite);
284 allocator.visitGraph(graph); 266 allocator.visitGraph(graph);
285 variableNames = allocator.names; 267 variableNames = allocator.names;
(...skipping 15 matching lines...) Expand all
301 if (statement.expression is js.Assignment) { 283 if (statement.expression is js.Assignment) {
302 js.Assignment assignment = statement.expression; 284 js.Assignment assignment = statement.expression;
303 if (!assignment.isCompound && 285 if (!assignment.isCompound &&
304 assignment.leftHandSide is js.VariableReference) { 286 assignment.leftHandSide is js.VariableReference) {
305 js.VariableReference variableReference = assignment.leftHandSide; 287 js.VariableReference variableReference = assignment.leftHandSide;
306 if (variableReference.name == name) { 288 if (variableReference.name == name) {
307 js.VariableDeclaration decl = new js.VariableDeclaration(name); 289 js.VariableDeclaration decl = new js.VariableDeclaration(name);
308 js.VariableInitialization initialization = 290 js.VariableInitialization initialization =
309 new js.VariableInitialization(decl, assignment.value); 291 new js.VariableInitialization(decl, assignment.value);
310 currentContainer.statements[0] = new js.ExpressionStatement( 292 currentContainer.statements[0] = new js.ExpressionStatement(
311 new js.VariableDeclarationList([initialization])) 293 new js.VariableDeclarationList([initialization]))
312 .withSourceInformation(sourceInformation); 294 .withSourceInformation(sourceInformation);
313 return; 295 return;
314 } 296 }
315 } 297 }
316 } 298 }
317 } 299 }
318 // If we can't merge the declaration with the first assignment then we 300 // If we can't merge the declaration with the first assignment then we
319 // just do it with a new var z,y,x; statement. 301 // just do it with a new var z,y,x; statement.
320 List<js.VariableInitialization> declarations = 302 List<js.VariableInitialization> declarations =
321 <js.VariableInitialization>[]; 303 <js.VariableInitialization>[];
322 collectedVariableDeclarations.forEach((String name) { 304 collectedVariableDeclarations.forEach((String name) {
323 declarations.add(new js.VariableInitialization( 305 declarations.add(new js.VariableInitialization(
324 new js.VariableDeclaration(name), null)); 306 new js.VariableDeclaration(name), null));
325 }); 307 });
326 var declarationList = new js.VariableDeclarationList(declarations) 308 var declarationList = new js.VariableDeclarationList(declarations)
327 .withSourceInformation(sourceInformation);; 309 .withSourceInformation(sourceInformation);
310 ;
328 insertStatementAtStart(new js.ExpressionStatement(declarationList)); 311 insertStatementAtStart(new js.ExpressionStatement(declarationList));
329 } 312 }
330 } 313 }
331 314
332 visitGraph(HGraph graph) { 315 visitGraph(HGraph graph) {
333 preGenerateMethod(graph); 316 preGenerateMethod(graph);
334 currentGraph = graph; 317 currentGraph = graph;
335 subGraph = new SubGraph(graph.entry, graph.exit); 318 subGraph = new SubGraph(graph.entry, graph.exit);
336 visitBasicBlock(graph.entry); 319 visitBasicBlock(graph.entry);
337 handleDelayedVariableDeclarations(graph.sourceInformation); 320 handleDelayedVariableDeclarations(graph.sourceInformation);
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
407 } 390 }
408 391
409 bool isJSExpression(HExpressionInformation info) { 392 bool isJSExpression(HExpressionInformation info) {
410 return !identical(expressionType(info), TYPE_STATEMENT); 393 return !identical(expressionType(info), TYPE_STATEMENT);
411 } 394 }
412 395
413 bool isJSCondition(HExpressionInformation info) { 396 bool isJSCondition(HExpressionInformation info) {
414 HSubExpressionBlockInformation graph = info; 397 HSubExpressionBlockInformation graph = info;
415 SubExpression limits = graph.subExpression; 398 SubExpression limits = graph.subExpression;
416 return !identical(expressionType(info), TYPE_STATEMENT) && 399 return !identical(expressionType(info), TYPE_STATEMENT) &&
417 (limits.end.last is HConditionalBranch); 400 (limits.end.last is HConditionalBranch);
418 } 401 }
419 402
420 /** 403 /**
421 * Generate statements from block information. 404 * Generate statements from block information.
422 * If the block information contains expressions, generate only 405 * If the block information contains expressions, generate only
423 * assignments, and if it ends in a conditional branch, don't generate 406 * assignments, and if it ends in a conditional branch, don't generate
424 * the condition. 407 * the condition.
425 */ 408 */
426 void generateStatements(HBlockInformation block) { 409 void generateStatements(HBlockInformation block) {
427 if (block is HStatementInformation) { 410 if (block is HStatementInformation) {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
485 result = new js.Binary(',', sequenceElements.removeLast(), result); 468 result = new js.Binary(',', sequenceElements.removeLast(), result);
486 } 469 }
487 return result; 470 return result;
488 } 471 }
489 } 472 }
490 473
491 /** 474 /**
492 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET]. 475 * Only visits the arguments starting at inputs[HInvoke.ARGUMENTS_OFFSET].
493 */ 476 */
494 List<js.Expression> visitArguments(List<HInstruction> inputs, 477 List<js.Expression> visitArguments(List<HInstruction> inputs,
495 {int start: HInvoke.ARGUMENTS_OFFSET}) { 478 {int start: HInvoke.ARGUMENTS_OFFSET}) {
496 assert(inputs.length >= start); 479 assert(inputs.length >= start);
497 List<js.Expression> result = new List<js.Expression>(inputs.length - start); 480 List<js.Expression> result = new List<js.Expression>(inputs.length - start);
498 for (int i = start; i < inputs.length; i++) { 481 for (int i = start; i < inputs.length; i++) {
499 use(inputs[i]); 482 use(inputs[i]);
500 result[i - start] = pop(); 483 result[i - start] = pop();
501 } 484 }
502 return result; 485 return result;
503 } 486 }
504 487
505 bool isVariableDeclared(String variableName) { 488 bool isVariableDeclared(String variableName) {
506 return declaredLocals.contains(variableName) || 489 return declaredLocals.contains(variableName) ||
507 collectedVariableDeclarations.contains(variableName); 490 collectedVariableDeclarations.contains(variableName);
508 } 491 }
509 492
510 js.Expression generateExpressionAssignment(String variableName, 493 js.Expression generateExpressionAssignment(
511 js.Expression value) { 494 String variableName, js.Expression value) {
512 if (value is js.Binary) { 495 if (value is js.Binary) {
513 js.Binary binary = value; 496 js.Binary binary = value;
514 String op = binary.op; 497 String op = binary.op;
515 if (op == '+' || op == '-' || op == '/' || op == '*' || op == '%' || 498 if (op == '+' ||
516 op == '^' || op == '&' || op == '|') { 499 op == '-' ||
500 op == '/' ||
501 op == '*' ||
502 op == '%' ||
503 op == '^' ||
504 op == '&' ||
505 op == '|') {
517 if (binary.left is js.VariableUse && 506 if (binary.left is js.VariableUse &&
518 (binary.left as js.VariableUse).name == variableName) { 507 (binary.left as js.VariableUse).name == variableName) {
519 // We know now, that we can shorten x = x + y into x += y. 508 // We know now, that we can shorten x = x + y into x += y.
520 // Also check for the shortcut where y equals 1: x++ and x--. 509 // Also check for the shortcut where y equals 1: x++ and x--.
521 if ((op == '+' || op == '-') && 510 if ((op == '+' || op == '-') &&
522 binary.right is js.LiteralNumber && 511 binary.right is js.LiteralNumber &&
523 (binary.right as js.LiteralNumber).value == "1") { 512 (binary.right as js.LiteralNumber).value == "1") {
524 return new js.Prefix(op == '+' ? '++' : '--', binary.left); 513 return new js.Prefix(op == '+' ? '++' : '--', binary.left);
525 } 514 }
526 return new js.Assignment.compound(binary.left, op, binary.right); 515 return new js.Assignment.compound(binary.left, op, binary.right);
527 } 516 }
528 } 517 }
529 } 518 }
530 return new js.Assignment(new js.VariableUse(variableName), value) 519 return new js.Assignment(new js.VariableUse(variableName), value)
531 .withSourceInformation(value.sourceInformation); 520 .withSourceInformation(value.sourceInformation);
532 } 521 }
533 522
534 void assignVariable(String variableName, 523 void assignVariable(String variableName, js.Expression value,
535 js.Expression value, 524 SourceInformation sourceInformation) {
536 SourceInformation sourceInformation) {
537 if (isGeneratingExpression) { 525 if (isGeneratingExpression) {
538 // If we are in an expression then we can't declare the variable here. 526 // If we are in an expression then we can't declare the variable here.
539 // We have no choice, but to use it and then declare it separately. 527 // We have no choice, but to use it and then declare it separately.
540 if (!isVariableDeclared(variableName)) { 528 if (!isVariableDeclared(variableName)) {
541 collectedVariableDeclarations.add(variableName); 529 collectedVariableDeclarations.add(variableName);
542 } 530 }
543 push(generateExpressionAssignment(variableName, value)); 531 push(generateExpressionAssignment(variableName, value));
544 // Otherwise if we are trying to declare inline and we are in a statement 532 // Otherwise if we are trying to declare inline and we are in a statement
545 // then we declare (unless it was already declared). 533 // then we declare (unless it was already declared).
546 } else if (!shouldGroupVarDeclarations && 534 } else if (!shouldGroupVarDeclarations &&
547 !declaredLocals.contains(variableName)) { 535 !declaredLocals.contains(variableName)) {
548 // It may be necessary to remove it from the ones to be declared later. 536 // It may be necessary to remove it from the ones to be declared later.
549 collectedVariableDeclarations.remove(variableName); 537 collectedVariableDeclarations.remove(variableName);
550 declaredLocals.add(variableName); 538 declaredLocals.add(variableName);
551 js.VariableDeclaration decl = new js.VariableDeclaration(variableName); 539 js.VariableDeclaration decl = new js.VariableDeclaration(variableName);
552 js.VariableInitialization initialization = 540 js.VariableInitialization initialization =
553 new js.VariableInitialization(decl, value); 541 new js.VariableInitialization(decl, value);
554 542
555 pushExpressionAsStatement(new js.VariableDeclarationList( 543 pushExpressionAsStatement(
556 <js.VariableInitialization>[initialization]), 544 new js.VariableDeclarationList(
545 <js.VariableInitialization>[initialization]),
557 sourceInformation); 546 sourceInformation);
558 } else { 547 } else {
559 // Otherwise we are just going to use it. If we have not already declared 548 // Otherwise we are just going to use it. If we have not already declared
560 // it then we make sure we will declare it later. 549 // it then we make sure we will declare it later.
561 if (!declaredLocals.contains(variableName)) { 550 if (!declaredLocals.contains(variableName)) {
562 collectedVariableDeclarations.add(variableName); 551 collectedVariableDeclarations.add(variableName);
563 } 552 }
564 pushExpressionAsStatement( 553 pushExpressionAsStatement(
565 generateExpressionAssignment(variableName, value), 554 generateExpressionAssignment(variableName, value), sourceInformation);
566 sourceInformation);
567 } 555 }
568 } 556 }
569 557
570 void define(HInstruction instruction) { 558 void define(HInstruction instruction) {
571 // For simple type checks like i = intTypeCheck(i), we don't have to 559 // For simple type checks like i = intTypeCheck(i), we don't have to
572 // emit an assignment, because the intTypeCheck just returns its 560 // emit an assignment, because the intTypeCheck just returns its
573 // argument. 561 // argument.
574 bool needsAssignment = true; 562 bool needsAssignment = true;
575 if (instruction is HTypeConversion) { 563 if (instruction is HTypeConversion) {
576 HTypeConversion typeConversion = instruction; 564 HTypeConversion typeConversion = instruction;
577 String inputName = variableNames.getName(typeConversion.checkedInput); 565 String inputName = variableNames.getName(typeConversion.checkedInput);
578 if (variableNames.getName(instruction) == inputName) { 566 if (variableNames.getName(instruction) == inputName) {
579 needsAssignment = false; 567 needsAssignment = false;
580 } 568 }
581 } 569 }
582 if (instruction is HLocalValue) { 570 if (instruction is HLocalValue) {
583 needsAssignment = false; 571 needsAssignment = false;
584 } 572 }
585 573
586 if (needsAssignment && 574 if (needsAssignment &&
587 !instruction.isControlFlow() && variableNames.hasName(instruction)) { 575 !instruction.isControlFlow() &&
576 variableNames.hasName(instruction)) {
588 visitExpression(instruction); 577 visitExpression(instruction);
589 assignVariable(variableNames.getName(instruction), pop(), 578 assignVariable(variableNames.getName(instruction), pop(),
590 instruction.sourceInformation); 579 instruction.sourceInformation);
591 return; 580 return;
592 } 581 }
593 582
594 if (isGeneratingExpression) { 583 if (isGeneratingExpression) {
595 visitExpression(instruction); 584 visitExpression(instruction);
596 } else { 585 } else {
597 visitStatement(instruction); 586 visitStatement(instruction);
598 } 587 }
599 } 588 }
600 589
(...skipping 30 matching lines...) Expand all
631 js.Expression expression = pop(); 620 js.Expression expression = pop();
632 pushExpressionAsStatement(expression, node.sourceInformation); 621 pushExpressionAsStatement(expression, node.sourceInformation);
633 } 622 }
634 } 623 }
635 624
636 void continueAsBreak(LabelDefinition target) { 625 void continueAsBreak(LabelDefinition target) {
637 pushStatement(new js.Break(backend.namer.continueLabelName(target))); 626 pushStatement(new js.Break(backend.namer.continueLabelName(target)));
638 } 627 }
639 628
640 void implicitContinueAsBreak(JumpTarget target) { 629 void implicitContinueAsBreak(JumpTarget target) {
641 pushStatement(new js.Break( 630 pushStatement(
642 backend.namer.implicitContinueLabelName(target))); 631 new js.Break(backend.namer.implicitContinueLabelName(target)));
643 } 632 }
644 633
645 void implicitBreakWithLabel(JumpTarget target) { 634 void implicitBreakWithLabel(JumpTarget target) {
646 pushStatement(new js.Break(backend.namer.implicitBreakLabelName(target))); 635 pushStatement(new js.Break(backend.namer.implicitBreakLabelName(target)));
647 } 636 }
648 637
649 js.Statement wrapIntoLabels(js.Statement result, 638 js.Statement wrapIntoLabels(
650 List<LabelDefinition> labels) { 639 js.Statement result, List<LabelDefinition> labels) {
651 for (LabelDefinition label in labels) { 640 for (LabelDefinition label in labels) {
652 if (label.isTarget) { 641 if (label.isTarget) {
653 String breakLabelString = backend.namer.breakLabelName(label); 642 String breakLabelString = backend.namer.breakLabelName(label);
654 result = new js.LabeledStatement(breakLabelString, result); 643 result = new js.LabeledStatement(breakLabelString, result);
655 } 644 }
656 } 645 }
657 return result; 646 return result;
658 } 647 }
659 648
660
661 // The regular [visitIf] method implements the needed logic. 649 // The regular [visitIf] method implements the needed logic.
662 bool visitIfInfo(HIfBlockInformation info) => false; 650 bool visitIfInfo(HIfBlockInformation info) => false;
663 651
664 bool visitSwitchInfo(HSwitchBlockInformation info) { 652 bool visitSwitchInfo(HSwitchBlockInformation info) {
665 bool isExpression = isJSExpression(info.expression); 653 bool isExpression = isJSExpression(info.expression);
666 if (!isExpression) { 654 if (!isExpression) {
667 generateStatements(info.expression); 655 generateStatements(info.expression);
668 } 656 }
669 657
670 if (isExpression) { 658 if (isExpression) {
671 push(generateExpression(info.expression)); 659 push(generateExpression(info.expression));
672 } else { 660 } else {
673 use(info.expression.conditionExpression); 661 use(info.expression.conditionExpression);
674 } 662 }
675 js.Expression key = pop(); 663 js.Expression key = pop();
676 List<js.SwitchClause> cases = <js.SwitchClause>[]; 664 List<js.SwitchClause> cases = <js.SwitchClause>[];
677 HSwitch switchInstruction = info.expression.end.last; 665 HSwitch switchInstruction = info.expression.end.last;
678 List<HInstruction> inputs = switchInstruction.inputs; 666 List<HInstruction> inputs = switchInstruction.inputs;
679 List<HBasicBlock> successors = switchInstruction.block.successors; 667 List<HBasicBlock> successors = switchInstruction.block.successors;
680 668
681 js.Block oldContainer = currentContainer; 669 js.Block oldContainer = currentContainer;
682 for (int inputIndex = 1, statementIndex = 0; 670 for (int inputIndex = 1, statementIndex = 0;
683 inputIndex < inputs.length; 671 inputIndex < inputs.length;
684 statementIndex++) { 672 statementIndex++) {
685 HBasicBlock successor = successors[inputIndex - 1]; 673 HBasicBlock successor = successors[inputIndex - 1];
686 // If liveness analysis has figured out that this case is dead, 674 // If liveness analysis has figured out that this case is dead,
687 // omit the code for it. 675 // omit the code for it.
688 if (successor.isLive) { 676 if (successor.isLive) {
689 do { 677 do {
690 visit(inputs[inputIndex]); 678 visit(inputs[inputIndex]);
691 currentContainer = new js.Block.empty(); 679 currentContainer = new js.Block.empty();
692 cases.add(new js.Case(pop(), currentContainer)); 680 cases.add(new js.Case(pop(), currentContainer));
693 inputIndex++; 681 inputIndex++;
694 } while ((successors[inputIndex - 1] == successor) 682 } while ((successors[inputIndex - 1] == successor) &&
695 && (inputIndex < inputs.length)); 683 (inputIndex < inputs.length));
696 684
697 generateStatements(info.statements[statementIndex]); 685 generateStatements(info.statements[statementIndex]);
698 } else { 686 } else {
699 // Skip all the case statements that belong to this 687 // Skip all the case statements that belong to this
700 // block. 688 // block.
701 while ((successors[inputIndex - 1] == successor) 689 while ((successors[inputIndex - 1] == successor) &&
702 && (inputIndex < inputs.length)) { 690 (inputIndex < inputs.length)) {
703 ++inputIndex; 691 ++inputIndex;
704 } 692 }
705 } 693 }
706 } 694 }
707 695
708 // If the default case is dead, we omit it. Likewise, if it is an 696 // If the default case is dead, we omit it. Likewise, if it is an
709 // empty block, we omit it, too. 697 // empty block, we omit it, too.
710 if (info.statements.last.start.isLive) { 698 if (info.statements.last.start.isLive) {
711 currentContainer = new js.Block.empty(); 699 currentContainer = new js.Block.empty();
712 generateStatements(info.statements.last); 700 generateStatements(info.statements.last);
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 // part of the LoopBlockInformation and must therefore be handled here. 790 // part of the LoopBlockInformation and must therefore be handled here.
803 js.Block oldContainer = currentContainer; 791 js.Block oldContainer = currentContainer;
804 js.Block avoidContainer = new js.Block.empty(); 792 js.Block avoidContainer = new js.Block.empty();
805 currentContainer = avoidContainer; 793 currentContainer = avoidContainer;
806 assignPhisOfSuccessors(condition.end.successors.last); 794 assignPhisOfSuccessors(condition.end.successors.last);
807 bool hasPhiUpdates = !avoidContainer.statements.isEmpty; 795 bool hasPhiUpdates = !avoidContainer.statements.isEmpty;
808 currentContainer = oldContainer; 796 currentContainer = oldContainer;
809 797
810 if (isConditionExpression && 798 if (isConditionExpression &&
811 !hasPhiUpdates && 799 !hasPhiUpdates &&
812 info.updates != null && isJSExpression(info.updates)) { 800 info.updates != null &&
801 isJSExpression(info.updates)) {
813 // If we have an updates graph, and it's expressible as an 802 // If we have an updates graph, and it's expressible as an
814 // expression, generate a for-loop. 803 // expression, generate a for-loop.
815 js.Expression jsInitialization = null; 804 js.Expression jsInitialization = null;
816 if (initialization != null) { 805 if (initialization != null) {
817 int delayedVariablesCount = collectedVariableDeclarations.length; 806 int delayedVariablesCount = collectedVariableDeclarations.length;
818 jsInitialization = generateExpression(initialization); 807 jsInitialization = generateExpression(initialization);
819 if (!shouldGroupVarDeclarations && 808 if (!shouldGroupVarDeclarations &&
820 delayedVariablesCount < collectedVariableDeclarations.length) { 809 delayedVariablesCount < collectedVariableDeclarations.length) {
821 // We just added a new delayed variable-declaration. See if we can 810 // We just added a new delayed variable-declaration. See if we can
822 // put in a 'var' in front of the initialization to make it go 811 // put in a 'var' in front of the initialization to make it go
823 // away. We walk the 'tree' of comma-operators to find the 812 // away. We walk the 'tree' of comma-operators to find the
824 // expressions and see if they are all assignments that can be 813 // expressions and see if they are all assignments that can be
825 // converted into declarations. 814 // converted into declarations.
826 815
827 List<js.Assignment> assignments; 816 List<js.Assignment> assignments;
828 817
829 bool allSimpleAssignments(js.Expression expression) { 818 bool allSimpleAssignments(js.Expression expression) {
830 if (expression is js.Assignment) { 819 if (expression is js.Assignment) {
831 js.Assignment assignment = expression; 820 js.Assignment assignment = expression;
832 if (assignment.leftHandSide is js.VariableUse && 821 if (assignment.leftHandSide is js.VariableUse &&
833 !assignment.isCompound) { 822 !assignment.isCompound) {
834 if (assignments == null) assignments = <js.Assignment>[]; 823 if (assignments == null) assignments = <js.Assignment>[];
835 assignments.add(expression); 824 assignments.add(expression);
836 return true; 825 return true;
837 } 826 }
838 } else if (expression.isCommaOperator) { 827 } else if (expression.isCommaOperator) {
839 js.Binary binary = expression; 828 js.Binary binary = expression;
840 return allSimpleAssignments(binary.left) 829 return allSimpleAssignments(binary.left) &&
841 && allSimpleAssignments(binary.right); 830 allSimpleAssignments(binary.right);
842 } 831 }
843 return false; 832 return false;
844 } 833 }
845 834
846 if (allSimpleAssignments(jsInitialization)) { 835 if (allSimpleAssignments(jsInitialization)) {
847 List<js.VariableInitialization> inits = 836 List<js.VariableInitialization> inits =
848 <js.VariableInitialization>[]; 837 <js.VariableInitialization>[];
849 for (js.Assignment assignment in assignments) { 838 for (js.Assignment assignment in assignments) {
850 String id = (assignment.leftHandSide as js.VariableUse).name; 839 String id = (assignment.leftHandSide as js.VariableUse).name;
851 js.Node declaration = new js.VariableDeclaration(id); 840 js.Node declaration = new js.VariableDeclaration(id);
852 inits.add(new js.VariableInitialization(declaration, 841 inits.add(new js.VariableInitialization(
853 assignment.value)); 842 declaration, assignment.value));
854 collectedVariableDeclarations.remove(id); 843 collectedVariableDeclarations.remove(id);
855 declaredLocals.add(id); 844 declaredLocals.add(id);
856 } 845 }
857 jsInitialization = new js.VariableDeclarationList(inits); 846 jsInitialization = new js.VariableDeclarationList(inits);
858 } 847 }
859 } 848 }
860 } 849 }
861 js.Expression jsCondition = generateExpression(condition); 850 js.Expression jsCondition = generateExpression(condition);
862 js.Expression jsUpdates = generateExpression(info.updates); 851 js.Expression jsUpdates = generateExpression(info.updates);
863 // The body might be labeled. Ignore this when recursing on the 852 // The body might be labeled. Ignore this when recursing on the
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
918 } 907 }
919 // We inserted a basic block to avoid critical edges. This block is 908 // We inserted a basic block to avoid critical edges. This block is
920 // part of the LoopBlockInformation and must therefore be handled here. 909 // part of the LoopBlockInformation and must therefore be handled here.
921 js.Block oldContainer = currentContainer; 910 js.Block oldContainer = currentContainer;
922 js.Block exitAvoidContainer = new js.Block.empty(); 911 js.Block exitAvoidContainer = new js.Block.empty();
923 currentContainer = exitAvoidContainer; 912 currentContainer = exitAvoidContainer;
924 assignPhisOfSuccessors(condition.end.successors.last); 913 assignPhisOfSuccessors(condition.end.successors.last);
925 bool hasExitPhiUpdates = !exitAvoidContainer.statements.isEmpty; 914 bool hasExitPhiUpdates = !exitAvoidContainer.statements.isEmpty;
926 currentContainer = oldContainer; 915 currentContainer = oldContainer;
927 916
928
929 oldContainer = currentContainer; 917 oldContainer = currentContainer;
930 js.Block body = new js.Block.empty(); 918 js.Block body = new js.Block.empty();
931 // If there are phi copies in the block that jumps to the 919 // If there are phi copies in the block that jumps to the
932 // loop entry, we must emit the condition like this: 920 // loop entry, we must emit the condition like this:
933 // do { 921 // do {
934 // body; 922 // body;
935 // if (condition) { 923 // if (condition) {
936 // phi updates; 924 // phi updates;
937 // continue; 925 // continue;
938 // } else { 926 // } else {
(...skipping 14 matching lines...) Expand all
953 push(generateExpression(condition)); 941 push(generateExpression(condition));
954 } else { 942 } else {
955 generateStatements(condition); 943 generateStatements(condition);
956 use(condition.conditionExpression); 944 use(condition.conditionExpression);
957 } 945 }
958 js.Expression jsCondition = pop(); 946 js.Expression jsCondition = pop();
959 if (jsCondition == null) { 947 if (jsCondition == null) {
960 // If the condition is dead code, we turn the do-while into 948 // If the condition is dead code, we turn the do-while into
961 // a simpler while because we will never reach the condition 949 // a simpler while because we will never reach the condition
962 // at the end of the loop anyway. 950 // at the end of the loop anyway.
963 loop = new js.While( 951 loop = new js.While(newLiteralBool(true, info.sourceInformation),
964 newLiteralBool(true, info.sourceInformation), 952 unwrapStatement(body))
965 unwrapStatement(body)) 953 .withSourceInformation(info.sourceInformation);
966 .withSourceInformation(info.sourceInformation);
967 } else { 954 } else {
968 if (hasPhiUpdates || hasExitPhiUpdates) { 955 if (hasPhiUpdates || hasExitPhiUpdates) {
969 updateBody.statements.add(new js.Continue(null)); 956 updateBody.statements.add(new js.Continue(null));
970 js.Statement jsBreak = new js.Break(null); 957 js.Statement jsBreak = new js.Break(null);
971 js.Statement exitLoop; 958 js.Statement exitLoop;
972 if (exitAvoidContainer.statements.isEmpty) { 959 if (exitAvoidContainer.statements.isEmpty) {
973 exitLoop = jsBreak; 960 exitLoop = jsBreak;
974 } else { 961 } else {
975 exitAvoidContainer.statements.add(jsBreak); 962 exitAvoidContainer.statements.add(jsBreak);
976 exitLoop = exitAvoidContainer; 963 exitLoop = exitAvoidContainer;
977 } 964 }
978 body.statements.add( 965 body.statements.add(new js.If(jsCondition, updateBody, exitLoop));
979 new js.If(jsCondition, updateBody, exitLoop));
980 jsCondition = newLiteralBool(true, info.sourceInformation); 966 jsCondition = newLiteralBool(true, info.sourceInformation);
981 } 967 }
982 loop = new js.Do(unwrapStatement(body), jsCondition) 968 loop = new js.Do(unwrapStatement(body), jsCondition)
983 .withSourceInformation(info.sourceInformation); 969 .withSourceInformation(info.sourceInformation);
984 } 970 }
985 currentContainer = oldContainer; 971 currentContainer = oldContainer;
986 break; 972 break;
987 default: 973 default:
988 reporter.internalError(condition.conditionExpression, 974 reporter.internalError(condition.conditionExpression,
989 'Unexpected loop kind: ${info.kind}.'); 975 'Unexpected loop kind: ${info.kind}.');
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
1135 } 1121 }
1136 1122
1137 void emitAssignment(String destination, String source) { 1123 void emitAssignment(String destination, String source) {
1138 assignVariable(destination, new js.VariableUse(source), null); 1124 assignVariable(destination, new js.VariableUse(source), null);
1139 } 1125 }
1140 1126
1141 /** 1127 /**
1142 * Sequentialize a list of conceptually parallel copies. Parallel 1128 * Sequentialize a list of conceptually parallel copies. Parallel
1143 * copies may contain cycles, that this method breaks. 1129 * copies may contain cycles, that this method breaks.
1144 */ 1130 */
1145 void sequentializeCopies(Iterable<Copy> copies, 1131 void sequentializeCopies(Iterable<Copy> copies, String tempName,
1146 String tempName, 1132 void doAssignment(String target, String source)) {
1147 void doAssignment(String target, String source)) {
1148 // Map to keep track of the current location (ie the variable that 1133 // Map to keep track of the current location (ie the variable that
1149 // holds the initial value) of a variable. 1134 // holds the initial value) of a variable.
1150 Map<String, String> currentLocation = new Map<String, String>(); 1135 Map<String, String> currentLocation = new Map<String, String>();
1151 1136
1152 // Map to keep track of the initial value of a variable. 1137 // Map to keep track of the initial value of a variable.
1153 Map<String, String> initialValue = new Map<String, String>(); 1138 Map<String, String> initialValue = new Map<String, String>();
1154 1139
1155 // List of variables to assign a value. 1140 // List of variables to assign a value.
1156 List<String> worklist = <String>[]; 1141 List<String> worklist = <String>[];
1157 1142
1158 // List of variables that we can assign a value to (ie are not 1143 // List of variables that we can assign a value to (ie are not
1159 // being used anymore). 1144 // being used anymore).
1160 List<String> ready = <String>[]; 1145 List<String> ready = <String>[];
1161 1146
1162 // Prune [copies] by removing self-copies. 1147 // Prune [copies] by removing self-copies.
1163 List<Copy> prunedCopies = <Copy>[]; 1148 List<Copy> prunedCopies = <Copy>[];
1164 for (Copy copy in copies) { 1149 for (Copy copy in copies) {
1165 if (copy.source != copy.destination) { 1150 if (copy.source != copy.destination) {
1166 prunedCopies.add(copy); 1151 prunedCopies.add(copy);
1167 } 1152 }
1168 } 1153 }
1169 copies = prunedCopies; 1154 copies = prunedCopies;
1170 1155
1171
1172 // For each copy, set the current location of the source to 1156 // For each copy, set the current location of the source to
1173 // itself, and the initial value of the destination to the source. 1157 // itself, and the initial value of the destination to the source.
1174 // Add the destination to the list of copies to make. 1158 // Add the destination to the list of copies to make.
1175 for (Copy copy in copies) { 1159 for (Copy copy in copies) {
1176 currentLocation[copy.source] = copy.source; 1160 currentLocation[copy.source] = copy.source;
1177 initialValue[copy.destination] = copy.source; 1161 initialValue[copy.destination] = copy.source;
1178 worklist.add(copy.destination); 1162 worklist.add(copy.destination);
1179 } 1163 }
1180 1164
1181 // For each copy, if the destination does not have a current 1165 // For each copy, if the destination does not have a current
(...skipping 20 matching lines...) Expand all
1202 if (source == copy && initialValue[source] != null) { 1186 if (source == copy && initialValue[source] != null) {
1203 ready.add(source); 1187 ready.add(source);
1204 } 1188 }
1205 } 1189 }
1206 1190
1207 // Check if we have a cycle. 1191 // Check if we have a cycle.
1208 String current = worklist.removeLast(); 1192 String current = worklist.removeLast();
1209 // If [current] is used as a source, and the assignment has been 1193 // If [current] is used as a source, and the assignment has been
1210 // done, we are done with this variable. Otherwise there is a 1194 // done, we are done with this variable. Otherwise there is a
1211 // cycle that we break by using a temporary name. 1195 // cycle that we break by using a temporary name.
1212 if (currentLocation[current] != null 1196 if (currentLocation[current] != null &&
1213 && current != currentLocation[initialValue[current]]) { 1197 current != currentLocation[initialValue[current]]) {
1214 doAssignment(tempName, current); 1198 doAssignment(tempName, current);
1215 currentLocation[current] = tempName; 1199 currentLocation[current] = tempName;
1216 // [current] can now be safely updated. Copies of [current] 1200 // [current] can now be safely updated. Copies of [current]
1217 // will now use [tempName]. 1201 // will now use [tempName].
1218 ready.add(current); 1202 ready.add(current);
1219 } 1203 }
1220 } 1204 }
1221 } 1205 }
1222 1206
1223 void assignPhisOfSuccessors(HBasicBlock node) { 1207 void assignPhisOfSuccessors(HBasicBlock node) {
1224 CopyHandler handler = variableNames.getCopyHandler(node); 1208 CopyHandler handler = variableNames.getCopyHandler(node);
1225 if (handler == null) return; 1209 if (handler == null) return;
1226 1210
1227 // Map the instructions to strings. 1211 // Map the instructions to strings.
1228 Iterable<Copy> copies = handler.copies.map((Copy copy) { 1212 Iterable<Copy> copies = handler.copies.map((Copy copy) {
1229 return new Copy(variableNames.getName(copy.source), 1213 return new Copy(variableNames.getName(copy.source),
1230 variableNames.getName(copy.destination)); 1214 variableNames.getName(copy.destination));
1231 }); 1215 });
1232 1216
1233 sequentializeCopies(copies, variableNames.getSwapTemp(), emitAssignment); 1217 sequentializeCopies(copies, variableNames.getSwapTemp(), emitAssignment);
1234 1218
1235 for (Copy copy in handler.assignments) { 1219 for (Copy copy in handler.assignments) {
1236 String name = variableNames.getName(copy.destination); 1220 String name = variableNames.getName(copy.destination);
1237 use(copy.source); 1221 use(copy.source);
1238 assignVariable(name, pop(), null); 1222 assignVariable(name, pop(), null);
1239 } 1223 }
1240 } 1224 }
1241 1225
1242 void iterateBasicBlock(HBasicBlock node) { 1226 void iterateBasicBlock(HBasicBlock node) {
1243 HInstruction instruction = node.first; 1227 HInstruction instruction = node.first;
1244 while (!identical(instruction, node.last)) { 1228 while (!identical(instruction, node.last)) {
1245 if (!isGenerateAtUseSite(instruction)) { 1229 if (!isGenerateAtUseSite(instruction)) {
1246 define(instruction); 1230 define(instruction);
1247 } 1231 }
1248 instruction = instruction.next; 1232 instruction = instruction.next;
1249 } 1233 }
1250 assignPhisOfSuccessors(node); 1234 assignPhisOfSuccessors(node);
1251 visit(instruction); 1235 visit(instruction);
1252 } 1236 }
1253 1237
1254 void handleInvokeBinary(HInvokeBinary node, 1238 void handleInvokeBinary(
1255 String op, 1239 HInvokeBinary node, String op, SourceInformation sourceInformation) {
1256 SourceInformation sourceInformation) {
1257 use(node.left); 1240 use(node.left);
1258 js.Expression jsLeft = pop(); 1241 js.Expression jsLeft = pop();
1259 use(node.right); 1242 use(node.right);
1260 push(new js.Binary(op, jsLeft, pop()) 1243 push(new js.Binary(op, jsLeft, pop())
1261 .withSourceInformation(sourceInformation)); 1244 .withSourceInformation(sourceInformation));
1262 } 1245 }
1263 1246
1264 visitInvokeBinary(HInvokeBinary node, String op) { 1247 visitInvokeBinary(HInvokeBinary node, String op) {
1265 handleInvokeBinary(node, op, node.sourceInformation); 1248 handleInvokeBinary(node, op, node.sourceInformation);
1266 } 1249 }
1267 1250
1268 visitRelational(HRelational node, String op) { 1251 visitRelational(HRelational node, String op) {
1269 handleInvokeBinary(node, op, node.sourceInformation); 1252 handleInvokeBinary(node, op, node.sourceInformation);
1270 } 1253 }
1271 1254
1272 // We want the outcome of bit-operations to be positive. We use the unsigned 1255 // We want the outcome of bit-operations to be positive. We use the unsigned
1273 // shift operator to achieve this. 1256 // shift operator to achieve this.
1274 visitBitInvokeBinary(HBinaryBitOp node, String op) { 1257 visitBitInvokeBinary(HBinaryBitOp node, String op) {
1275 visitInvokeBinary(node, op); 1258 visitInvokeBinary(node, op);
1276 if (op != '>>>' && requiresUintConversion(node)) { 1259 if (op != '>>>' && requiresUintConversion(node)) {
1277 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")) 1260 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0"))
1278 .withSourceInformation(node.sourceInformation)); 1261 .withSourceInformation(node.sourceInformation));
1279 } 1262 }
1280 } 1263 }
1281 1264
1282 visitInvokeUnary(HInvokeUnary node, String op) { 1265 visitInvokeUnary(HInvokeUnary node, String op) {
1283 use(node.operand); 1266 use(node.operand);
1284 push(new js.Prefix(op, pop()) 1267 push(
1285 .withSourceInformation(node.sourceInformation)); 1268 new js.Prefix(op, pop()).withSourceInformation(node.sourceInformation));
1286 } 1269 }
1287 1270
1288 // We want the outcome of bit-operations to be positive. We use the unsigned 1271 // We want the outcome of bit-operations to be positive. We use the unsigned
1289 // shift operator to achieve this. 1272 // shift operator to achieve this.
1290 visitBitInvokeUnary(HInvokeUnary node, String op) { 1273 visitBitInvokeUnary(HInvokeUnary node, String op) {
1291 visitInvokeUnary(node, op); 1274 visitInvokeUnary(node, op);
1292 if (requiresUintConversion(node)) { 1275 if (requiresUintConversion(node)) {
1293 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0")) 1276 push(new js.Binary(">>>", pop(), new js.LiteralNumber("0"))
1294 .withSourceInformation(node.sourceInformation)); 1277 .withSourceInformation(node.sourceInformation));
1295 } 1278 }
1296 } 1279 }
1297 1280
1298 void emitIdentityComparison(HIdentity instruction, 1281 void emitIdentityComparison(
1299 SourceInformation sourceInformation, 1282 HIdentity instruction, SourceInformation sourceInformation,
1300 {bool inverse: false}) { 1283 {bool inverse: false}) {
1301 String op = instruction.singleComparisonOp; 1284 String op = instruction.singleComparisonOp;
1302 HInstruction left = instruction.left; 1285 HInstruction left = instruction.left;
1303 HInstruction right = instruction.right; 1286 HInstruction right = instruction.right;
1304 if (op != null) { 1287 if (op != null) {
1305 use(left); 1288 use(left);
1306 js.Expression jsLeft = pop(); 1289 js.Expression jsLeft = pop();
1307 use(right); 1290 use(right);
1308 push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop()) 1291 push(new js.Binary(mapRelationalOperator(op, inverse), jsLeft, pop())
1309 .withSourceInformation(sourceInformation)); 1292 .withSourceInformation(sourceInformation));
1310 } else { 1293 } else {
1311 assert(NullConstantValue.JsNull == 'null'); 1294 assert(NullConstantValue.JsNull == 'null');
1312 use(left); 1295 use(left);
1313 js.Binary leftEqualsNull = 1296 js.Binary leftEqualsNull =
1314 new js.Binary("==", pop(), new js.LiteralNull()); 1297 new js.Binary("==", pop(), new js.LiteralNull());
1315 use(right); 1298 use(right);
1316 js.Binary rightEqualsNull = 1299 js.Binary rightEqualsNull = new js.Binary(
1317 new js.Binary(mapRelationalOperator("==", inverse), 1300 mapRelationalOperator("==", inverse), pop(), new js.LiteralNull());
1318 pop(), new js.LiteralNull());
1319 use(right); 1301 use(right);
1320 use(left); 1302 use(left);
1321 js.Binary tripleEq = new js.Binary(mapRelationalOperator("===", inverse), 1303 js.Binary tripleEq =
1322 pop(), pop()); 1304 new js.Binary(mapRelationalOperator("===", inverse), pop(), pop());
1323 1305
1324 push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq) 1306 push(new js.Conditional(leftEqualsNull, rightEqualsNull, tripleEq)
1325 .withSourceInformation(sourceInformation)); 1307 .withSourceInformation(sourceInformation));
1326 } 1308 }
1327 } 1309 }
1328 1310
1329 visitIdentity(HIdentity node) { 1311 visitIdentity(HIdentity node) {
1330 emitIdentityComparison(node, node.sourceInformation, inverse: false); 1312 emitIdentityComparison(node, node.sourceInformation, inverse: false);
1331 } 1313 }
1332 1314
1333 visitAdd(HAdd node) => visitInvokeBinary(node, '+'); 1315 visitAdd(HAdd node) => visitInvokeBinary(node, '+');
1334 visitDivide(HDivide node) => visitInvokeBinary(node, '/'); 1316 visitDivide(HDivide node) => visitInvokeBinary(node, '/');
1335 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*'); 1317 visitMultiply(HMultiply node) => visitInvokeBinary(node, '*');
1336 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-'); 1318 visitSubtract(HSubtract node) => visitInvokeBinary(node, '-');
1337 visitBitAnd(HBitAnd node) => visitBitInvokeBinary(node, '&'); 1319 visitBitAnd(HBitAnd node) => visitBitInvokeBinary(node, '&');
1338 visitBitNot(HBitNot node) => visitBitInvokeUnary(node, '~'); 1320 visitBitNot(HBitNot node) => visitBitInvokeUnary(node, '~');
1339 visitBitOr(HBitOr node) => visitBitInvokeBinary(node, '|'); 1321 visitBitOr(HBitOr node) => visitBitInvokeBinary(node, '|');
1340 visitBitXor(HBitXor node) => visitBitInvokeBinary(node, '^'); 1322 visitBitXor(HBitXor node) => visitBitInvokeBinary(node, '^');
1341 visitShiftLeft(HShiftLeft node) => visitBitInvokeBinary(node, '<<'); 1323 visitShiftLeft(HShiftLeft node) => visitBitInvokeBinary(node, '<<');
1342 visitShiftRight(HShiftRight node) => visitBitInvokeBinary(node, '>>>'); 1324 visitShiftRight(HShiftRight node) => visitBitInvokeBinary(node, '>>>');
1343 1325
1344 visitTruncatingDivide(HTruncatingDivide node) { 1326 visitTruncatingDivide(HTruncatingDivide node) {
1345 assert(node.isUInt31(compiler)); 1327 assert(node.isUInt31(compiler));
1346 // TODO(karlklose): Enable this assertion again when type propagation is 1328 // TODO(karlklose): Enable this assertion again when type propagation is
1347 // fixed. Issue 23555. 1329 // fixed. Issue 23555.
1348 // assert(node.left.isUInt32(compiler)); 1330 // assert(node.left.isUInt32(compiler));
1349 assert(node.right.isPositiveInteger(compiler)); 1331 assert(node.right.isPositiveInteger(compiler));
1350 use(node.left); 1332 use(node.left);
1351 js.Expression jsLeft = pop(); 1333 js.Expression jsLeft = pop();
1352 use(node.right); 1334 use(node.right);
1353 push(new js.Binary('/', jsLeft, pop()) 1335 push(new js.Binary('/', jsLeft, pop())
1354 .withSourceInformation(node.sourceInformation)); 1336 .withSourceInformation(node.sourceInformation));
1355 push(new js.Binary('|', pop(), new js.LiteralNumber("0")) 1337 push(new js.Binary('|', pop(), new js.LiteralNumber("0"))
1356 .withSourceInformation(node.sourceInformation)); 1338 .withSourceInformation(node.sourceInformation));
1357 } 1339 }
1358 1340
1359 visitNegate(HNegate node) => visitInvokeUnary(node, '-'); 1341 visitNegate(HNegate node) => visitInvokeUnary(node, '-');
1360 1342
1361 visitLess(HLess node) => visitRelational(node, '<'); 1343 visitLess(HLess node) => visitRelational(node, '<');
1362 visitLessEqual(HLessEqual node) => visitRelational(node, '<='); 1344 visitLessEqual(HLessEqual node) => visitRelational(node, '<=');
1363 visitGreater(HGreater node) => visitRelational(node, '>'); 1345 visitGreater(HGreater node) => visitRelational(node, '>');
1364 visitGreaterEqual(HGreaterEqual node) => visitRelational(node, '>='); 1346 visitGreaterEqual(HGreaterEqual node) => visitRelational(node, '>=');
1365 1347
1366 visitBoolify(HBoolify node) { 1348 visitBoolify(HBoolify node) {
1367 assert(node.inputs.length == 1); 1349 assert(node.inputs.length == 1);
1368 use(node.inputs[0]); 1350 use(node.inputs[0]);
1369 push(new js.Binary('===', pop(), 1351 push(new js.Binary(
1370 newLiteralBool(true, node.sourceInformation)) 1352 '===', pop(), newLiteralBool(true, node.sourceInformation))
1371 .withSourceInformation(node.sourceInformation)); 1353 .withSourceInformation(node.sourceInformation));
1372 } 1354 }
1373 1355
1374 visitExit(HExit node) { 1356 visitExit(HExit node) {
1375 // Don't do anything. 1357 // Don't do anything.
1376 } 1358 }
1377 1359
1378 visitGoto(HGoto node) { 1360 visitGoto(HGoto node) {
1379 HBasicBlock block = node.block; 1361 HBasicBlock block = node.block;
1380 assert(block.successors.length == 1); 1362 assert(block.successors.length == 1);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1417 if (action == null) return false; 1399 if (action == null) return false;
1418 action(entity); 1400 action(entity);
1419 return true; 1401 return true;
1420 } 1402 }
1421 1403
1422 visitBreak(HBreak node) { 1404 visitBreak(HBreak node) {
1423 assert(node.block.successors.length == 1); 1405 assert(node.block.successors.length == 1);
1424 if (node.label != null) { 1406 if (node.label != null) {
1425 LabelDefinition label = node.label; 1407 LabelDefinition label = node.label;
1426 if (!tryCallAction(breakAction, label)) { 1408 if (!tryCallAction(breakAction, label)) {
1427 pushStatement( 1409 pushStatement(new js.Break(backend.namer.breakLabelName(label))
1428 new js.Break(backend.namer.breakLabelName(label)) 1410 .withSourceInformation(node.sourceInformation));
1429 .withSourceInformation(node.sourceInformation));
1430 } 1411 }
1431 } else { 1412 } else {
1432 JumpTarget target = node.target; 1413 JumpTarget target = node.target;
1433 if (!tryCallAction(breakAction, target)) { 1414 if (!tryCallAction(breakAction, target)) {
1434 if (node.breakSwitchContinueLoop) { 1415 if (node.breakSwitchContinueLoop) {
1435 pushStatement( 1416 pushStatement(
1436 new js.Break(backend.namer.implicitContinueLabelName(target)) 1417 new js.Break(backend.namer.implicitContinueLabelName(target))
1437 .withSourceInformation(node.sourceInformation)); 1418 .withSourceInformation(node.sourceInformation));
1438 } else { 1419 } else {
1439 pushStatement(new js.Break(null) 1420 pushStatement(
1440 .withSourceInformation(node.sourceInformation)); 1421 new js.Break(null).withSourceInformation(node.sourceInformation));
1441 } 1422 }
1442 } 1423 }
1443 } 1424 }
1444 } 1425 }
1445 1426
1446 visitContinue(HContinue node) { 1427 visitContinue(HContinue node) {
1447 assert(node.block.successors.length == 1); 1428 assert(node.block.successors.length == 1);
1448 if (node.label != null) { 1429 if (node.label != null) {
1449 LabelDefinition label = node.label; 1430 LabelDefinition label = node.label;
1450 if (!tryCallAction(continueAction, label)) { 1431 if (!tryCallAction(continueAction, label)) {
1451 // TODO(floitsch): should this really be the breakLabelName? 1432 // TODO(floitsch): should this really be the breakLabelName?
1452 pushStatement( 1433 pushStatement(new js.Continue(backend.namer.breakLabelName(label))
1453 new js.Continue(backend.namer.breakLabelName(label)) 1434 .withSourceInformation(node.sourceInformation));
1454 .withSourceInformation(node.sourceInformation));
1455 } 1435 }
1456 } else { 1436 } else {
1457 JumpTarget target = node.target; 1437 JumpTarget target = node.target;
1458 if (!tryCallAction(continueAction, target)) { 1438 if (!tryCallAction(continueAction, target)) {
1459 if (target.isSwitch) { 1439 if (target.isSwitch) {
1460 pushStatement( 1440 pushStatement(
1461 new js.Continue(backend.namer.implicitContinueLabelName(target)) 1441 new js.Continue(backend.namer.implicitContinueLabelName(target))
1462 .withSourceInformation(node.sourceInformation)); 1442 .withSourceInformation(node.sourceInformation));
1463 } else { 1443 } else {
1464 pushStatement(new js.Continue(null) 1444 pushStatement(new js.Continue(null)
(...skipping 21 matching lines...) Expand all
1486 bool tryControlFlowOperation(HIf node) { 1466 bool tryControlFlowOperation(HIf node) {
1487 if (!controlFlowOperators.contains(node)) return false; 1467 if (!controlFlowOperators.contains(node)) return false;
1488 HPhi phi = node.joinBlock.phis.first; 1468 HPhi phi = node.joinBlock.phis.first;
1489 bool atUseSite = isGenerateAtUseSite(phi); 1469 bool atUseSite = isGenerateAtUseSite(phi);
1490 // Don't generate a conditional operator in this situation: 1470 // Don't generate a conditional operator in this situation:
1491 // i = condition ? bar() : i; 1471 // i = condition ? bar() : i;
1492 // But generate this instead: 1472 // But generate this instead:
1493 // if (condition) i = bar(); 1473 // if (condition) i = bar();
1494 // Usually, the variable name is longer than 'if' and it takes up 1474 // Usually, the variable name is longer than 'if' and it takes up
1495 // more space to duplicate the name. 1475 // more space to duplicate the name.
1496 if (!atUseSite 1476 if (!atUseSite &&
1497 && variableNames.getName(phi) == variableNames.getName(phi.inputs[1])) { 1477 variableNames.getName(phi) == variableNames.getName(phi.inputs[1])) {
1498 return false; 1478 return false;
1499 } 1479 }
1500 if (!atUseSite) define(phi); 1480 if (!atUseSite) define(phi);
1501 visitBasicBlock(node.joinBlock); 1481 visitBasicBlock(node.joinBlock);
1502 return true; 1482 return true;
1503 } 1483 }
1504 1484
1505 void generateIf(HIf node, HIfBlockInformation info) { 1485 void generateIf(HIf node, HIfBlockInformation info) {
1506 use(node.inputs[0]); 1486 use(node.inputs[0]);
1507 js.Expression test = pop(); 1487 js.Expression test = pop();
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
1562 push(js.js('# && #', [receiverExpression, constant])); 1542 push(js.js('# && #', [receiverExpression, constant]));
1563 } else { 1543 } else {
1564 assert(node.inputs.length == 1); 1544 assert(node.inputs.length == 1);
1565 registry.registerSpecializedGetInterceptor(node.interceptedClasses); 1545 registry.registerSpecializedGetInterceptor(node.interceptedClasses);
1566 js.Name name = 1546 js.Name name =
1567 backend.namer.nameForGetInterceptor(node.interceptedClasses); 1547 backend.namer.nameForGetInterceptor(node.interceptedClasses);
1568 var isolate = new js.VariableUse( 1548 var isolate = new js.VariableUse(
1569 backend.namer.globalObjectFor(helpers.interceptorsLibrary)); 1549 backend.namer.globalObjectFor(helpers.interceptorsLibrary));
1570 use(node.receiver); 1550 use(node.receiver);
1571 List<js.Expression> arguments = <js.Expression>[pop()]; 1551 List<js.Expression> arguments = <js.Expression>[pop()];
1572 push(js.propertyCall(isolate, name, arguments) 1552 push(js
1573 .withSourceInformation(node.sourceInformation)); 1553 .propertyCall(isolate, name, arguments)
1554 .withSourceInformation(node.sourceInformation));
1574 registry.registerUseInterceptor(); 1555 registry.registerUseInterceptor();
1575 } 1556 }
1576 } 1557 }
1577 1558
1578 visitInvokeDynamicMethod(HInvokeDynamicMethod node) { 1559 visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
1579 use(node.receiver); 1560 use(node.receiver);
1580 js.Expression object = pop(); 1561 js.Expression object = pop();
1581 String methodName; 1562 String methodName;
1582 List<js.Expression> arguments = visitArguments(node.inputs); 1563 List<js.Expression> arguments = visitArguments(node.inputs);
1583 Element target = node.element; 1564 Element target = node.element;
1584 1565
1585 // TODO(herhut): The namer should return the appropriate backendname here. 1566 // TODO(herhut): The namer should return the appropriate backendname here.
1586 if (target != null && !node.isInterceptedCall) { 1567 if (target != null && !node.isInterceptedCall) {
1587 if (target == helpers.jsArrayAdd) { 1568 if (target == helpers.jsArrayAdd) {
1588 methodName = 'push'; 1569 methodName = 'push';
1589 } else if (target == helpers.jsArrayRemoveLast) { 1570 } else if (target == helpers.jsArrayRemoveLast) {
1590 methodName = 'pop'; 1571 methodName = 'pop';
1591 } else if (target == helpers.jsStringSplit) { 1572 } else if (target == helpers.jsStringSplit) {
1592 methodName = 'split'; 1573 methodName = 'split';
1593 // Split returns a List, so we make sure the backend knows the 1574 // Split returns a List, so we make sure the backend knows the
1594 // list class is instantiated. 1575 // list class is instantiated.
1595 registry.registerInstantiatedClass(coreClasses.listClass); 1576 registry.registerInstantiatedClass(coreClasses.listClass);
1596 } else if (backend.isNative(target) && target.isFunction 1577 } else if (backend.isNative(target) &&
1597 && !node.isInterceptedCall) { 1578 target.isFunction &&
1579 !node.isInterceptedCall) {
1598 // A direct (i.e. non-interceptor) native call is the result of 1580 // A direct (i.e. non-interceptor) native call is the result of
1599 // optimization. The optimization ensures any type checks or 1581 // optimization. The optimization ensures any type checks or
1600 // conversions have been satisified. 1582 // conversions have been satisified.
1601 methodName = backend.nativeData.getFixedBackendName(target); 1583 methodName = backend.nativeData.getFixedBackendName(target);
1602 } 1584 }
1603 } 1585 }
1604 1586
1605 js.Name methodLiteral; 1587 js.Name methodLiteral;
1606 if (methodName == null) { 1588 if (methodName == null) {
1607 methodLiteral = backend.namer.invocationName(node.selector); 1589 methodLiteral = backend.namer.invocationName(node.selector);
1608 registerMethodInvoke(node); 1590 registerMethodInvoke(node);
1609 } else { 1591 } else {
1610 methodLiteral = backend.namer.asName(methodName); 1592 methodLiteral = backend.namer.asName(methodName);
1611 } 1593 }
1612 push(js.propertyCall(object, methodLiteral, arguments) 1594 push(js
1613 .withSourceInformation(node.sourceInformation)); 1595 .propertyCall(object, methodLiteral, arguments)
1596 .withSourceInformation(node.sourceInformation));
1614 } 1597 }
1615 1598
1616 void visitInvokeConstructorBody(HInvokeConstructorBody node) { 1599 void visitInvokeConstructorBody(HInvokeConstructorBody node) {
1617 use(node.inputs[0]); 1600 use(node.inputs[0]);
1618 js.Expression object = pop(); 1601 js.Expression object = pop();
1619 js.Name methodName = backend.namer.instanceMethodName(node.element); 1602 js.Name methodName = backend.namer.instanceMethodName(node.element);
1620 List<js.Expression> arguments = visitArguments(node.inputs); 1603 List<js.Expression> arguments = visitArguments(node.inputs);
1621 push(js.propertyCall(object, methodName, arguments) 1604 push(js
1622 .withSourceInformation(node.sourceInformation)); 1605 .propertyCall(object, methodName, arguments)
1623 registry.registerStaticUse( 1606 .withSourceInformation(node.sourceInformation));
1624 new StaticUse.constructorBodyInvoke( 1607 registry.registerStaticUse(new StaticUse.constructorBodyInvoke(
1625 node.element, new CallStructure.unnamed(arguments.length))); 1608 node.element, new CallStructure.unnamed(arguments.length)));
1626 } 1609 }
1627 1610
1628 void visitOneShotInterceptor(HOneShotInterceptor node) { 1611 void visitOneShotInterceptor(HOneShotInterceptor node) {
1629 List<js.Expression> arguments = visitArguments(node.inputs); 1612 List<js.Expression> arguments = visitArguments(node.inputs);
1630 var isolate = new js.VariableUse( 1613 var isolate = new js.VariableUse(
1631 backend.namer.globalObjectFor(helpers.interceptorsLibrary)); 1614 backend.namer.globalObjectFor(helpers.interceptorsLibrary));
1632 Selector selector = node.selector; 1615 Selector selector = node.selector;
1633 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); 1616 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask);
1634 js.Name methodName = backend.registerOneShotInterceptor(selector); 1617 js.Name methodName = backend.registerOneShotInterceptor(selector);
1635 push(js.propertyCall(isolate, methodName, arguments) 1618 push(js
1619 .propertyCall(isolate, methodName, arguments)
1636 .withSourceInformation(node.sourceInformation)); 1620 .withSourceInformation(node.sourceInformation));
1637 if (selector.isGetter) { 1621 if (selector.isGetter) {
1638 registerGetter(node); 1622 registerGetter(node);
1639 } else if (selector.isSetter) { 1623 } else if (selector.isSetter) {
1640 registerSetter(node); 1624 registerSetter(node);
1641 } else { 1625 } else {
1642 registerMethodInvoke(node); 1626 registerMethodInvoke(node);
1643 } 1627 }
1644 registry.registerUseInterceptor(); 1628 registry.registerUseInterceptor();
1645 } 1629 }
1646 1630
1647 TypeMask getOptimizedSelectorFor(HInvokeDynamic node, 1631 TypeMask getOptimizedSelectorFor(
1648 Selector selector, 1632 HInvokeDynamic node, Selector selector, TypeMask mask) {
1649 TypeMask mask) {
1650 if (node.element != null) { 1633 if (node.element != null) {
1651 // Create an artificial type mask to make sure only 1634 // Create an artificial type mask to make sure only
1652 // [node.element] will be enqueued. We're not using the receiver 1635 // [node.element] will be enqueued. We're not using the receiver
1653 // type because our optimizations might end up in a state where the 1636 // type because our optimizations might end up in a state where the
1654 // invoke dynamic knows more than the receiver. 1637 // invoke dynamic knows more than the receiver.
1655 ClassElement enclosing = node.element.enclosingClass; 1638 ClassElement enclosing = node.element.enclosingClass;
1656 if (compiler.world.isInstantiated(enclosing)) { 1639 if (compiler.world.isInstantiated(enclosing)) {
1657 return new TypeMask.nonNullExact( 1640 return new TypeMask.nonNullExact(enclosing.declaration, compiler.world);
1658 enclosing.declaration, compiler.world);
1659 } else { 1641 } else {
1660 // The element is mixed in so a non-null subtype mask is the most 1642 // The element is mixed in so a non-null subtype mask is the most
1661 // precise we have. 1643 // precise we have.
1662 assert(invariant(node, compiler.world.isUsedAsMixin(enclosing), 1644 assert(invariant(node, compiler.world.isUsedAsMixin(enclosing),
1663 message: "Element ${node.element} from $enclosing expected " 1645 message: "Element ${node.element} from $enclosing expected "
1664 "to be mixed in.")); 1646 "to be mixed in."));
1665 return new TypeMask.nonNullSubtype( 1647 return new TypeMask.nonNullSubtype(
1666 enclosing.declaration, compiler.world); 1648 enclosing.declaration, compiler.world);
1667 } 1649 }
1668 } 1650 }
1669 // If [JSInvocationMirror._invokeOn] is enabled, and this call 1651 // If [JSInvocationMirror._invokeOn] is enabled, and this call
1670 // might hit a `noSuchMethod`, we register an untyped selector. 1652 // might hit a `noSuchMethod`, we register an untyped selector.
1671 return compiler.world.extendMaskIfReachesAll(selector, mask); 1653 return compiler.world.extendMaskIfReachesAll(selector, mask);
1672 } 1654 }
1673 1655
1674 void registerMethodInvoke(HInvokeDynamic node) { 1656 void registerMethodInvoke(HInvokeDynamic node) {
1675 Selector selector = node.selector; 1657 Selector selector = node.selector;
1676 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); 1658 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask);
1677 1659
1678 // If we don't know what we're calling or if we are calling a getter, 1660 // If we don't know what we're calling or if we are calling a getter,
1679 // we need to register that fact that we may be calling a closure 1661 // we need to register that fact that we may be calling a closure
1680 // with the same arguments. 1662 // with the same arguments.
1681 Element target = node.element; 1663 Element target = node.element;
1682 if (target == null || target.isGetter) { 1664 if (target == null || target.isGetter) {
1683 // TODO(kasperl): If we have a typed selector for the call, we 1665 // TODO(kasperl): If we have a typed selector for the call, we
1684 // may know something about the types of closures that need 1666 // may know something about the types of closures that need
1685 // the specific closure call method. 1667 // the specific closure call method.
1686 Selector call = new Selector.callClosureFrom(selector); 1668 Selector call = new Selector.callClosureFrom(selector);
1687 registry.registerDynamicUse( 1669 registry.registerDynamicUse(new DynamicUse(call, null));
1688 new DynamicUse(call, null));
1689 } 1670 }
1690 registry.registerDynamicUse( 1671 registry.registerDynamicUse(new DynamicUse(selector, mask));
1691 new DynamicUse(selector, mask));
1692 } 1672 }
1693 1673
1694 void registerSetter(HInvokeDynamic node) { 1674 void registerSetter(HInvokeDynamic node) {
1695 Selector selector = node.selector; 1675 Selector selector = node.selector;
1696 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); 1676 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask);
1697 registry.registerDynamicUse( 1677 registry.registerDynamicUse(new DynamicUse(selector, mask));
1698 new DynamicUse(selector, mask));
1699 } 1678 }
1700 1679
1701 void registerGetter(HInvokeDynamic node) { 1680 void registerGetter(HInvokeDynamic node) {
1702 Selector selector = node.selector; 1681 Selector selector = node.selector;
1703 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask); 1682 TypeMask mask = getOptimizedSelectorFor(node, selector, node.mask);
1704 registry.registerDynamicUse( 1683 registry.registerDynamicUse(new DynamicUse(selector, mask));
1705 new DynamicUse(selector, mask));
1706 } 1684 }
1707 1685
1708 visitInvokeDynamicSetter(HInvokeDynamicSetter node) { 1686 visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
1709 use(node.receiver); 1687 use(node.receiver);
1710 js.Name name = backend.namer.invocationName(node.selector); 1688 js.Name name = backend.namer.invocationName(node.selector);
1711 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) 1689 push(js
1712 .withSourceInformation(node.sourceInformation)); 1690 .propertyCall(pop(), name, visitArguments(node.inputs))
1691 .withSourceInformation(node.sourceInformation));
1713 registerSetter(node); 1692 registerSetter(node);
1714 } 1693 }
1715 1694
1716 visitInvokeDynamicGetter(HInvokeDynamicGetter node) { 1695 visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
1717 use(node.receiver); 1696 use(node.receiver);
1718 js.Name name = backend.namer.invocationName(node.selector); 1697 js.Name name = backend.namer.invocationName(node.selector);
1719 push(js.propertyCall(pop(), name, visitArguments(node.inputs)) 1698 push(js
1720 .withSourceInformation(node.sourceInformation)); 1699 .propertyCall(pop(), name, visitArguments(node.inputs))
1700 .withSourceInformation(node.sourceInformation));
1721 registerGetter(node); 1701 registerGetter(node);
1722 } 1702 }
1723 1703
1724 visitInvokeClosure(HInvokeClosure node) { 1704 visitInvokeClosure(HInvokeClosure node) {
1725 Selector call = new Selector.callClosureFrom(node.selector); 1705 Selector call = new Selector.callClosureFrom(node.selector);
1726 use(node.receiver); 1706 use(node.receiver);
1727 push(js.propertyCall(pop(), 1707 push(js
1728 backend.namer.invocationName(call), 1708 .propertyCall(pop(), backend.namer.invocationName(call),
1729 visitArguments(node.inputs)) 1709 visitArguments(node.inputs))
1730 .withSourceInformation(node.sourceInformation)); 1710 .withSourceInformation(node.sourceInformation));
1731 registry.registerDynamicUse( 1711 registry.registerDynamicUse(new DynamicUse(call, null));
1732 new DynamicUse(call, null));
1733 } 1712 }
1734 1713
1735 visitInvokeStatic(HInvokeStatic node) { 1714 visitInvokeStatic(HInvokeStatic node) {
1736 Element element = node.element; 1715 Element element = node.element;
1737 List<DartType> instantiatedTypes = node.instantiatedTypes; 1716 List<DartType> instantiatedTypes = node.instantiatedTypes;
1738 1717
1739 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) { 1718 if (instantiatedTypes != null && !instantiatedTypes.isEmpty) {
1740 instantiatedTypes.forEach((type) { 1719 instantiatedTypes.forEach((type) {
1741 registry.registerInstantiation(type); 1720 registry.registerInstantiation(type);
1742 }); 1721 });
(...skipping 13 matching lines...) Expand all
1756 registry.registerStaticUse( 1735 registry.registerStaticUse(
1757 new StaticUse.staticInvoke(throwFunction, CallStructure.ONE_ARG)); 1736 new StaticUse.staticInvoke(throwFunction, CallStructure.ONE_ARG));
1758 1737
1759 // Calling using `(0, #)(#)` instead of `#(#)` separates the property load 1738 // Calling using `(0, #)(#)` instead of `#(#)` separates the property load
1760 // of the static function access from the call. For some reason this 1739 // of the static function access from the call. For some reason this
1761 // helps V8 see that the call never happens so V8 makes the call a 1740 // helps V8 see that the call never happens so V8 makes the call a
1762 // deoptimization. This removes the call from the optimized loop, making 1741 // deoptimization. This removes the call from the optimized loop, making
1763 // more optimizations available to the loop. This form is 50% faster on 1742 // more optimizations available to the loop. This form is 50% faster on
1764 // some small loop, almost as fast as loops with no concurrent 1743 // some small loop, almost as fast as loops with no concurrent
1765 // modification check. 1744 // modification check.
1766 push(js.js('# || (0, #)(#)',[ 1745 push(js.js('# || (0, #)(#)', [
1767 arguments[0], 1746 arguments[0],
1768 backend.emitter.staticFunctionAccess(throwFunction), 1747 backend.emitter.staticFunctionAccess(throwFunction),
1769 arguments[1]])); 1748 arguments[1]
1749 ]));
1770 } else { 1750 } else {
1771 CallStructure callStructure = new CallStructure.unnamed(arguments.length); 1751 CallStructure callStructure = new CallStructure.unnamed(arguments.length);
1772 registry.registerStaticUse( 1752 registry.registerStaticUse(element.isConstructor
1773 element.isConstructor 1753 ? new StaticUse.constructorInvoke(element, callStructure)
1774 ? new StaticUse.constructorInvoke(element, callStructure) 1754 : new StaticUse.staticInvoke(element, callStructure));
1775 : new StaticUse.staticInvoke(element, callStructure));
1776 push(backend.emitter.staticFunctionAccess(element)); 1755 push(backend.emitter.staticFunctionAccess(element));
1777 push(new js.Call(pop(), arguments, 1756 push(new js.Call(pop(), arguments,
1778 sourceInformation: node.sourceInformation)); 1757 sourceInformation: node.sourceInformation));
1779 } 1758 }
1780
1781 } 1759 }
1782 1760
1783 visitInvokeSuper(HInvokeSuper node) { 1761 visitInvokeSuper(HInvokeSuper node) {
1784 Element superElement = node.element; 1762 Element superElement = node.element;
1785 ClassElement superClass = superElement.enclosingClass; 1763 ClassElement superClass = superElement.enclosingClass;
1786 if (superElement.isField) { 1764 if (superElement.isField) {
1787 js.Name fieldName = 1765 js.Name fieldName = backend.namer.instanceFieldPropertyName(superElement);
1788 backend.namer.instanceFieldPropertyName(superElement);
1789 use(node.inputs[0]); 1766 use(node.inputs[0]);
1790 js.PropertyAccess access = 1767 js.PropertyAccess access = new js.PropertyAccess(pop(), fieldName)
1791 new js.PropertyAccess(pop(), fieldName) 1768 .withSourceInformation(node.sourceInformation);
1792 .withSourceInformation(node.sourceInformation);
1793 if (node.isSetter) { 1769 if (node.isSetter) {
1794 registry.registerStaticUse( 1770 registry.registerStaticUse(superElement.isSetter
1795 superElement.isSetter 1771 ? new StaticUse.superSetterSet(superElement)
1796 ? new StaticUse.superSetterSet(superElement) 1772 : new StaticUse.superFieldSet(superElement));
1797 : new StaticUse.superFieldSet(superElement));
1798 use(node.value); 1773 use(node.value);
1799 push(new js.Assignment(access, pop()) 1774 push(new js.Assignment(access, pop())
1800 .withSourceInformation(node.sourceInformation)); 1775 .withSourceInformation(node.sourceInformation));
1801 } else { 1776 } else {
1802 registry.registerStaticUse(new StaticUse.superGet(superElement)); 1777 registry.registerStaticUse(new StaticUse.superGet(superElement));
1803 push(access); 1778 push(access);
1804 } 1779 }
1805 } else { 1780 } else {
1806 Selector selector = node.selector; 1781 Selector selector = node.selector;
1807 if (!backend.maybeRegisterAliasedSuperMember(superElement, selector)) { 1782 if (!backend.maybeRegisterAliasedSuperMember(superElement, selector)) {
1808 js.Name methodName; 1783 js.Name methodName;
1809 if (selector.isGetter && !superElement.isGetter) { 1784 if (selector.isGetter && !superElement.isGetter) {
1810 // If this is a tear-off, register the fact that a tear-off closure 1785 // If this is a tear-off, register the fact that a tear-off closure
1811 // will be created, and that this tear-off must bypass ordinary 1786 // will be created, and that this tear-off must bypass ordinary
1812 // dispatch to ensure the super method is invoked. 1787 // dispatch to ensure the super method is invoked.
1813 FunctionElement helper = backend.helpers.closureFromTearOff; 1788 FunctionElement helper = backend.helpers.closureFromTearOff;
1814 registry.registerStaticUse(new StaticUse.staticInvoke(helper, 1789 registry.registerStaticUse(new StaticUse.staticInvoke(
1815 new CallStructure.unnamed(helper.parameters.length))); 1790 helper, new CallStructure.unnamed(helper.parameters.length)));
1816 registry.registerStaticUse(new StaticUse.superTearOff(node.element)); 1791 registry.registerStaticUse(new StaticUse.superTearOff(node.element));
1817 methodName = backend.namer.invocationName(selector); 1792 methodName = backend.namer.invocationName(selector);
1818 } else { 1793 } else {
1819 methodName = backend.namer.instanceMethodName(superElement); 1794 methodName = backend.namer.instanceMethodName(superElement);
1820 } 1795 }
1821 registry.registerStaticUse( 1796 registry.registerStaticUse(new StaticUse.superInvoke(
1822 new StaticUse.superInvoke( 1797 superElement, new CallStructure.unnamed(node.inputs.length)));
1823 superElement, 1798 push(js.js('#.#.call(#)', [
1824 new CallStructure.unnamed(node.inputs.length))); 1799 backend.emitter
1825 push(js.js('#.#.call(#)', 1800 .prototypeAccess(superClass, hasBeenInstantiated: true),
1826 [backend.emitter.prototypeAccess(superClass, 1801 methodName,
1827 hasBeenInstantiated: true), 1802 visitArguments(node.inputs, start: 0)
1828 methodName, visitArguments(node.inputs, start: 0)]) 1803 ]).withSourceInformation(node.sourceInformation));
1829 .withSourceInformation(node.sourceInformation));
1830 } else { 1804 } else {
1831 use(node.receiver); 1805 use(node.receiver);
1832 registry.registerStaticUse( 1806 registry.registerStaticUse(new StaticUse.superInvoke(
1833 new StaticUse.superInvoke( 1807 superElement, new CallStructure.unnamed(node.inputs.length - 1)));
1834 superElement, 1808 push(js.js('#.#(#)', [
1835 new CallStructure.unnamed(node.inputs.length - 1))); 1809 pop(),
1836 push( 1810 backend.namer.aliasedSuperMemberPropertyName(superElement),
1837 js.js('#.#(#)', [ 1811 visitArguments(node.inputs, start: 1)
1838 pop(), backend.namer.aliasedSuperMemberPropertyName(superElement), 1812 ]) // Skip receiver argument.
1839 visitArguments(node.inputs, start: 1)]) // Skip receiver argument. 1813 .withSourceInformation(node.sourceInformation));
1840 .withSourceInformation(node.sourceInformation));
1841 } 1814 }
1842 } 1815 }
1843 } 1816 }
1844 1817
1845 visitFieldGet(HFieldGet node) { 1818 visitFieldGet(HFieldGet node) {
1846 use(node.receiver); 1819 use(node.receiver);
1847 Element element = node.element; 1820 Element element = node.element;
1848 if (node.isNullCheck) { 1821 if (node.isNullCheck) {
1849 // We access a JavaScript member we know all objects besides 1822 // We access a JavaScript member we know all objects besides
1850 // null and undefined have: V8 does not like accessing a member 1823 // null and undefined have: V8 does not like accessing a member
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1895 .withSourceInformation(node.sourceInformation)); 1868 .withSourceInformation(node.sourceInformation));
1896 } 1869 }
1897 } 1870 }
1898 1871
1899 visitLocalGet(HLocalGet node) { 1872 visitLocalGet(HLocalGet node) {
1900 use(node.receiver); 1873 use(node.receiver);
1901 } 1874 }
1902 1875
1903 visitLocalSet(HLocalSet node) { 1876 visitLocalSet(HLocalSet node) {
1904 use(node.value); 1877 use(node.value);
1905 assignVariable(variableNames.getName(node.receiver), 1878 assignVariable(
1906 pop(), 1879 variableNames.getName(node.receiver), pop(), node.sourceInformation);
1907 node.sourceInformation);
1908 } 1880 }
1909 1881
1910 void registerForeignTypes(HForeign node) { 1882 void registerForeignTypes(HForeign node) {
1911 native.NativeBehavior nativeBehavior = node.nativeBehavior; 1883 native.NativeBehavior nativeBehavior = node.nativeBehavior;
1912 if (nativeBehavior == null) return; 1884 if (nativeBehavior == null) return;
1913 nativeEnqueuer.registerNativeBehavior(nativeBehavior, node); 1885 nativeEnqueuer.registerNativeBehavior(nativeBehavior, node);
1914 } 1886 }
1915 1887
1916 visitForeignCode(HForeignCode node) { 1888 visitForeignCode(HForeignCode node) {
1917 List<HInstruction> inputs = node.inputs; 1889 List<HInstruction> inputs = node.inputs;
1918 if (node.isJsStatement()) { 1890 if (node.isJsStatement()) {
1919 List<js.Expression> interpolatedExpressions = <js.Expression>[]; 1891 List<js.Expression> interpolatedExpressions = <js.Expression>[];
1920 for (int i = 0; i < inputs.length; i++) { 1892 for (int i = 0; i < inputs.length; i++) {
1921 use(inputs[i]); 1893 use(inputs[i]);
1922 interpolatedExpressions.add(pop()); 1894 interpolatedExpressions.add(pop());
1923 } 1895 }
1924 pushStatement(node.codeTemplate.instantiate(interpolatedExpressions) 1896 pushStatement(node.codeTemplate
1897 .instantiate(interpolatedExpressions)
1925 .withSourceInformation(node.sourceInformation)); 1898 .withSourceInformation(node.sourceInformation));
1926 } else { 1899 } else {
1927 List<js.Expression> interpolatedExpressions = <js.Expression>[]; 1900 List<js.Expression> interpolatedExpressions = <js.Expression>[];
1928 for (int i = 0; i < inputs.length; i++) { 1901 for (int i = 0; i < inputs.length; i++) {
1929 use(inputs[i]); 1902 use(inputs[i]);
1930 interpolatedExpressions.add(pop()); 1903 interpolatedExpressions.add(pop());
1931 } 1904 }
1932 push(node.codeTemplate.instantiate(interpolatedExpressions) 1905 push(node.codeTemplate
1906 .instantiate(interpolatedExpressions)
1933 .withSourceInformation(node.sourceInformation)); 1907 .withSourceInformation(node.sourceInformation));
1934 } 1908 }
1935 1909
1936 // TODO(sra): Tell world.nativeEnqueuer about the types created here. 1910 // TODO(sra): Tell world.nativeEnqueuer about the types created here.
1937 registerForeignTypes(node); 1911 registerForeignTypes(node);
1938 } 1912 }
1939 1913
1940 visitForeignNew(HForeignNew node) { 1914 visitForeignNew(HForeignNew node) {
1941 js.Expression jsClassReference = 1915 js.Expression jsClassReference =
1942 backend.emitter.constructorAccess(node.element); 1916 backend.emitter.constructorAccess(node.element);
1943 List<js.Expression> arguments = visitArguments(node.inputs, start: 0); 1917 List<js.Expression> arguments = visitArguments(node.inputs, start: 0);
1944 push(new js.New(jsClassReference, arguments) 1918 push(new js.New(jsClassReference, arguments)
1945 .withSourceInformation(node.sourceInformation)); 1919 .withSourceInformation(node.sourceInformation));
1946 registerForeignTypes(node); 1920 registerForeignTypes(node);
1947 // We also use ForeignNew to instantiate closure classes that belong to 1921 // We also use ForeignNew to instantiate closure classes that belong to
1948 // function expressions. We have to register their use here, as otherwise 1922 // function expressions. We have to register their use here, as otherwise
1949 // code for them might not be emitted. 1923 // code for them might not be emitted.
1950 if (node.element.isClosure) { 1924 if (node.element.isClosure) {
1951 registry.registerInstantiatedClass(node.element); 1925 registry.registerInstantiatedClass(node.element);
1952 } 1926 }
1953 if (node.instantiatedTypes == null) { 1927 if (node.instantiatedTypes == null) {
1954 return; 1928 return;
1955 } 1929 }
1956 node.instantiatedTypes.forEach((type) { 1930 node.instantiatedTypes.forEach((type) {
1957 registry.registerInstantiation(type); 1931 registry.registerInstantiation(type);
1958 }); 1932 });
1959 } 1933 }
1960 1934
1961 js.Expression newLiteralBool(bool value, 1935 js.Expression newLiteralBool(
1962 SourceInformation sourceInformation) { 1936 bool value, SourceInformation sourceInformation) {
1963 if (compiler.options.enableMinification) { 1937 if (compiler.options.enableMinification) {
1964 // Use !0 for true, !1 for false. 1938 // Use !0 for true, !1 for false.
1965 return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1")) 1939 return new js.Prefix("!", new js.LiteralNumber(value ? "0" : "1"))
1966 .withSourceInformation(sourceInformation); 1940 .withSourceInformation(sourceInformation);
1967 } else { 1941 } else {
1968 return new js.LiteralBool(value) 1942 return new js.LiteralBool(value).withSourceInformation(sourceInformation);
1969 .withSourceInformation(sourceInformation);
1970 } 1943 }
1971 } 1944 }
1972 1945
1973 void generateConstant(ConstantValue constant, 1946 void generateConstant(
1974 SourceInformation sourceInformation) { 1947 ConstantValue constant, SourceInformation sourceInformation) {
1975 if (constant.isFunction) { 1948 if (constant.isFunction) {
1976 FunctionConstantValue function = constant; 1949 FunctionConstantValue function = constant;
1977 registry.registerStaticUse( 1950 registry.registerStaticUse(new StaticUse.staticTearOff(function.element));
1978 new StaticUse.staticTearOff(function.element));
1979 } 1951 }
1980 if (constant.isType) { 1952 if (constant.isType) {
1981 // If the type is a web component, we need to ensure the constructors are 1953 // If the type is a web component, we need to ensure the constructors are
1982 // available to 'upgrade' the native object. 1954 // available to 'upgrade' the native object.
1983 TypeConstantValue type = constant; 1955 TypeConstantValue type = constant;
1984 Element element = type.representedType.element; 1956 Element element = type.representedType.element;
1985 if (element != null && element.isClass) { 1957 if (element != null && element.isClass) {
1986 registry.registerTypeConstant(element); 1958 registry.registerTypeConstant(element);
1987 } 1959 }
1988 } 1960 }
(...skipping 12 matching lines...) Expand all
2001 registry.registerCompileTimeConstant(node.constant); 1973 registry.registerCompileTimeConstant(node.constant);
2002 } 1974 }
2003 1975
2004 visitNot(HNot node) { 1976 visitNot(HNot node) {
2005 assert(node.inputs.length == 1); 1977 assert(node.inputs.length == 1);
2006 generateNot(node.inputs[0], node.sourceInformation); 1978 generateNot(node.inputs[0], node.sourceInformation);
2007 } 1979 }
2008 1980
2009 static String mapRelationalOperator(String op, bool inverse) { 1981 static String mapRelationalOperator(String op, bool inverse) {
2010 Map<String, String> inverseOperator = const <String, String>{ 1982 Map<String, String> inverseOperator = const <String, String>{
2011 "==" : "!=", 1983 "==": "!=",
2012 "!=" : "==", 1984 "!=": "==",
2013 "===": "!==", 1985 "===": "!==",
2014 "!==": "===", 1986 "!==": "===",
2015 "<" : ">=", 1987 "<": ">=",
2016 "<=" : ">", 1988 "<=": ">",
2017 ">" : "<=", 1989 ">": "<=",
2018 ">=" : "<" 1990 ">=": "<"
2019 }; 1991 };
2020 return inverse ? inverseOperator[op] : op; 1992 return inverse ? inverseOperator[op] : op;
2021 } 1993 }
2022 1994
2023 void generateNot(HInstruction input, SourceInformation sourceInformation) { 1995 void generateNot(HInstruction input, SourceInformation sourceInformation) {
2024 bool canGenerateOptimizedComparison(HInstruction instruction) { 1996 bool canGenerateOptimizedComparison(HInstruction instruction) {
2025 if (instruction is !HRelational) return false; 1997 if (instruction is! HRelational) return false;
2026 1998
2027 HRelational relational = instruction; 1999 HRelational relational = instruction;
2028 2000
2029 HInstruction left = relational.left; 2001 HInstruction left = relational.left;
2030 HInstruction right = relational.right; 2002 HInstruction right = relational.right;
2031 if (left.isStringOrNull(compiler) && right.isStringOrNull(compiler)) { 2003 if (left.isStringOrNull(compiler) && right.isStringOrNull(compiler)) {
2032 return true; 2004 return true;
2033 } 2005 }
2034 2006
2035 // This optimization doesn't work for NaN, so we only do it if the 2007 // This optimization doesn't work for NaN, so we only do it if the
2036 // type is known to be an integer. 2008 // type is known to be an integer.
2037 return left.isInteger(compiler) && right.isInteger(compiler); 2009 return left.isInteger(compiler) && right.isInteger(compiler);
2038 } 2010 }
2039 2011
2040 bool handledBySpecialCase = false; 2012 bool handledBySpecialCase = false;
2041 if (isGenerateAtUseSite(input)) { 2013 if (isGenerateAtUseSite(input)) {
2042 handledBySpecialCase = true; 2014 handledBySpecialCase = true;
2043 if (input is HIs) { 2015 if (input is HIs) {
2044 emitIs(input, '!==', sourceInformation); 2016 emitIs(input, '!==', sourceInformation);
2045 } else if (input is HIsViaInterceptor) { 2017 } else if (input is HIsViaInterceptor) {
2046 emitIsViaInterceptor(input, sourceInformation, negative: true); 2018 emitIsViaInterceptor(input, sourceInformation, negative: true);
2047 } else if (input is HNot) { 2019 } else if (input is HNot) {
2048 use(input.inputs[0]); 2020 use(input.inputs[0]);
2049 } else if (input is HIdentity) { 2021 } else if (input is HIdentity) {
2050 emitIdentityComparison(input, sourceInformation, inverse: true); 2022 emitIdentityComparison(input, sourceInformation, inverse: true);
2051 } else if (input is HBoolify) { 2023 } else if (input is HBoolify) {
2052 use(input.inputs[0]); 2024 use(input.inputs[0]);
2053 push(new js.Binary("!==", pop(), 2025 push(new js.Binary(
2054 newLiteralBool(true, input.sourceInformation)) 2026 "!==", pop(), newLiteralBool(true, input.sourceInformation))
2055 .withSourceInformation(sourceInformation)); 2027 .withSourceInformation(sourceInformation));
2056 } else if (canGenerateOptimizedComparison(input)) { 2028 } else if (canGenerateOptimizedComparison(input)) {
2057 HRelational relational = input; 2029 HRelational relational = input;
2058 BinaryOperation operation = 2030 BinaryOperation operation =
2059 relational.operation(backend.constantSystem); 2031 relational.operation(backend.constantSystem);
2060 String op = mapRelationalOperator(operation.name, true); 2032 String op = mapRelationalOperator(operation.name, true);
2061 handleInvokeBinary(input, op, sourceInformation); 2033 handleInvokeBinary(input, op, sourceInformation);
2062 } else { 2034 } else {
2063 handledBySpecialCase = false; 2035 handledBySpecialCase = false;
2064 } 2036 }
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
2110 js.Expression then = pop(); 2082 js.Expression then = pop();
2111 use(node.inputs[1]); 2083 use(node.inputs[1]);
2112 push(new js.Conditional(test, then, pop())); 2084 push(new js.Conditional(test, then, pop()));
2113 } 2085 }
2114 } 2086 }
2115 2087
2116 visitReturn(HReturn node) { 2088 visitReturn(HReturn node) {
2117 assert(node.inputs.length == 1); 2089 assert(node.inputs.length == 1);
2118 HInstruction input = node.inputs[0]; 2090 HInstruction input = node.inputs[0];
2119 if (input.isConstantNull()) { 2091 if (input.isConstantNull()) {
2120 pushStatement(new js.Return() 2092 pushStatement(
2121 .withSourceInformation(node.sourceInformation)); 2093 new js.Return().withSourceInformation(node.sourceInformation));
2122 } else { 2094 } else {
2123 use(node.inputs[0]); 2095 use(node.inputs[0]);
2124 pushStatement(new js.Return(pop()) 2096 pushStatement(
2125 .withSourceInformation(node.sourceInformation)); 2097 new js.Return(pop()).withSourceInformation(node.sourceInformation));
2126 } 2098 }
2127 } 2099 }
2128 2100
2129 visitThis(HThis node) { 2101 visitThis(HThis node) {
2130 push(new js.This()); 2102 push(new js.This());
2131 } 2103 }
2132 2104
2133 visitThrow(HThrow node) { 2105 visitThrow(HThrow node) {
2134 if (node.isRethrow) { 2106 if (node.isRethrow) {
2135 use(node.inputs[0]); 2107 use(node.inputs[0]);
2136 pushStatement(new js.Throw(pop()) 2108 pushStatement(
2137 .withSourceInformation(node.sourceInformation)); 2109 new js.Throw(pop()).withSourceInformation(node.sourceInformation));
2138 } else { 2110 } else {
2139 generateThrowWithHelper(helpers.wrapExceptionHelper, node.inputs[0], 2111 generateThrowWithHelper(helpers.wrapExceptionHelper, node.inputs[0],
2140 sourceInformation: node.sourceInformation); 2112 sourceInformation: node.sourceInformation);
2141 } 2113 }
2142 } 2114 }
2143 2115
2144 visitAwait(HAwait node) { 2116 visitAwait(HAwait node) {
2145 use(node.inputs[0]); 2117 use(node.inputs[0]);
2146 push(new js.Await(pop()) 2118 push(new js.Await(pop()).withSourceInformation(node.sourceInformation));
2147 .withSourceInformation(node.sourceInformation));
2148 } 2119 }
2149 2120
2150 visitYield(HYield node) { 2121 visitYield(HYield node) {
2151 use(node.inputs[0]); 2122 use(node.inputs[0]);
2152 pushStatement(new js.DartYield(pop(), node.hasStar) 2123 pushStatement(new js.DartYield(pop(), node.hasStar)
2153 .withSourceInformation(node.sourceInformation)); 2124 .withSourceInformation(node.sourceInformation));
2154 } 2125 }
2155 2126
2156 visitRangeConversion(HRangeConversion node) { 2127 visitRangeConversion(HRangeConversion node) {
2157 // Range conversion instructions are removed by the value range 2128 // Range conversion instructions are removed by the value range
(...skipping 26 matching lines...) Expand all
2184 if (node.staticChecks != HBoundsCheck.ALWAYS_BELOW_LENGTH) { 2155 if (node.staticChecks != HBoundsCheck.ALWAYS_BELOW_LENGTH) {
2185 var index = node.index; 2156 var index = node.index;
2186 use(index); 2157 use(index);
2187 js.Expression jsIndex = pop(); 2158 js.Expression jsIndex = pop();
2188 use(node.length); 2159 use(node.length);
2189 over = new js.Binary(">=", jsIndex, pop()); 2160 over = new js.Binary(">=", jsIndex, pop());
2190 } 2161 }
2191 assert(over != null || under != null); 2162 assert(over != null || under != null);
2192 js.Expression underOver = under == null 2163 js.Expression underOver = under == null
2193 ? over 2164 ? over
2194 : over == null 2165 : over == null ? under : new js.Binary("||", under, over);
2195 ? under
2196 : new js.Binary("||", under, over);
2197 js.Statement thenBody = new js.Block.empty(); 2166 js.Statement thenBody = new js.Block.empty();
2198 js.Block oldContainer = currentContainer; 2167 js.Block oldContainer = currentContainer;
2199 currentContainer = thenBody; 2168 currentContainer = thenBody;
2200 generateThrowWithHelper(helpers.throwIndexOutOfRangeException, 2169 generateThrowWithHelper(helpers.throwIndexOutOfRangeException,
2201 [node.array, node.reportedIndex]); 2170 [node.array, node.reportedIndex]);
2202 currentContainer = oldContainer; 2171 currentContainer = oldContainer;
2203 thenBody = unwrapStatement(thenBody); 2172 thenBody = unwrapStatement(thenBody);
2204 pushStatement(new js.If.noElse(underOver, thenBody) 2173 pushStatement(new js.If.noElse(underOver, thenBody)
2205 .withSourceInformation(node.sourceInformation)); 2174 .withSourceInformation(node.sourceInformation));
2206 } else { 2175 } else {
2207 generateThrowWithHelper(helpers.throwIndexOutOfRangeException, 2176 generateThrowWithHelper(
2208 [node.array, node.index]); 2177 helpers.throwIndexOutOfRangeException, [node.array, node.index]);
2209 } 2178 }
2210 } 2179 }
2211 2180
2212 void generateThrowWithHelper(Element helper, argument, 2181 void generateThrowWithHelper(Element helper, argument,
2213 {SourceInformation sourceInformation}) { 2182 {SourceInformation sourceInformation}) {
2214 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); 2183 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper);
2215 List arguments = []; 2184 List arguments = [];
2216 var location; 2185 var location;
2217 if (argument is List) { 2186 if (argument is List) {
2218 location = argument[0]; 2187 location = argument[0];
2219 argument.forEach((instruction) { 2188 argument.forEach((instruction) {
2220 use(instruction); 2189 use(instruction);
2221 arguments.add(pop()); 2190 arguments.add(pop());
2222 }); 2191 });
2223 } else { 2192 } else {
2224 location = argument; 2193 location = argument;
2225 use(argument); 2194 use(argument);
2226 arguments.add(pop()); 2195 arguments.add(pop());
2227 } 2196 }
2228 registry.registerStaticUse( 2197 registry.registerStaticUse(new StaticUse.staticInvoke(
2229 new StaticUse.staticInvoke( 2198 helper, new CallStructure.unnamed(arguments.length)));
2230 helper, new CallStructure.unnamed(arguments.length)));
2231 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false), 2199 js.Call value = new js.Call(jsHelper, arguments.toList(growable: false),
2232 sourceInformation: sourceInformation); 2200 sourceInformation: sourceInformation);
2233 // BUG(4906): Using throw/return here adds to the size of the generated code 2201 // BUG(4906): Using throw/return here adds to the size of the generated code
2234 // but it has the advantage of explicitly telling the JS engine that 2202 // but it has the advantage of explicitly telling the JS engine that
2235 // this code path will terminate abruptly. Needs more work. 2203 // this code path will terminate abruptly. Needs more work.
2236 if (helper == helpers.wrapExceptionHelper) { 2204 if (helper == helpers.wrapExceptionHelper) {
2237 pushStatement(new js.Throw(value) 2205 pushStatement(
2238 .withSourceInformation(sourceInformation)); 2206 new js.Throw(value).withSourceInformation(sourceInformation));
2239 } else { 2207 } else {
2240 Element element = work.element; 2208 Element element = work.element;
2241 if (element is FunctionElement && element.asyncMarker.isYielding) { 2209 if (element is FunctionElement && element.asyncMarker.isYielding) {
2242 // `return <expr>;` is illegal in a sync* or async* function. 2210 // `return <expr>;` is illegal in a sync* or async* function.
2243 // To have the the async-translator working, we avoid introducing 2211 // To have the the async-translator working, we avoid introducing
2244 // `return` nodes. 2212 // `return` nodes.
2245 pushStatement(new js.ExpressionStatement(value) 2213 pushStatement(new js.ExpressionStatement(value)
2246 .withSourceInformation(sourceInformation)); 2214 .withSourceInformation(sourceInformation));
2247 } else { 2215 } else {
2248 pushStatement(new js.Return(value) 2216 pushStatement(
2249 .withSourceInformation(sourceInformation)); 2217 new js.Return(value).withSourceInformation(sourceInformation));
2250 } 2218 }
2251 } 2219 }
2252 } 2220 }
2253 2221
2254 visitThrowExpression(HThrowExpression node) { 2222 visitThrowExpression(HThrowExpression node) {
2255 HInstruction argument = node.inputs[0]; 2223 HInstruction argument = node.inputs[0];
2256 use(argument); 2224 use(argument);
2257 2225
2258 Element helper = helpers.throwExpressionHelper; 2226 Element helper = helpers.throwExpressionHelper;
2259 registry.registerStaticUse( 2227 registry.registerStaticUse(
2260 new StaticUse.staticInvoke(helper, CallStructure.ONE_ARG)); 2228 new StaticUse.staticInvoke(helper, CallStructure.ONE_ARG));
2261 2229
2262 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper); 2230 js.Expression jsHelper = backend.emitter.staticFunctionAccess(helper);
2263 js.Call value = new js.Call(jsHelper, [pop()]) 2231 js.Call value = new js.Call(jsHelper, [pop()])
2264 .withSourceInformation(node.sourceInformation); 2232 .withSourceInformation(node.sourceInformation);
2265 push(value); 2233 push(value);
2266 } 2234 }
2267 2235
2268 void visitSwitch(HSwitch node) { 2236 void visitSwitch(HSwitch node) {
2269 // Switches are handled using [visitSwitchInfo]. 2237 // Switches are handled using [visitSwitchInfo].
2270 } 2238 }
2271 2239
2272 void visitStatic(HStatic node) { 2240 void visitStatic(HStatic node) {
2273 Element element = node.element; 2241 Element element = node.element;
2274 assert(element.isFunction || element.isField); 2242 assert(element.isFunction || element.isField);
2275 if (element.isFunction) { 2243 if (element.isFunction) {
2276 push(backend.emitter.isolateStaticClosureAccess(element) 2244 push(backend.emitter
2277 .withSourceInformation(node.sourceInformation)); 2245 .isolateStaticClosureAccess(element)
2278 registry.registerStaticUse( 2246 .withSourceInformation(node.sourceInformation));
2279 new StaticUse.staticTearOff(element)); 2247 registry.registerStaticUse(new StaticUse.staticTearOff(element));
2280 } else { 2248 } else {
2281 push(backend.emitter.staticFieldAccess(element) 2249 push(backend.emitter
2282 .withSourceInformation(node.sourceInformation)); 2250 .staticFieldAccess(element)
2283 registry.registerStaticUse( 2251 .withSourceInformation(node.sourceInformation));
2284 new StaticUse.staticGet(element)); 2252 registry.registerStaticUse(new StaticUse.staticGet(element));
2285 } 2253 }
2286 } 2254 }
2287 2255
2288 void visitLazyStatic(HLazyStatic node) { 2256 void visitLazyStatic(HLazyStatic node) {
2289 Element element = node.element; 2257 Element element = node.element;
2290 registry.registerStaticUse( 2258 registry.registerStaticUse(new StaticUse.staticInit(element));
2291 new StaticUse.staticInit(element));
2292 js.Expression lazyGetter = 2259 js.Expression lazyGetter =
2293 backend.emitter.isolateLazyInitializerAccess(element); 2260 backend.emitter.isolateLazyInitializerAccess(element);
2294 js.Call call = new js.Call(lazyGetter, <js.Expression>[], 2261 js.Call call = new js.Call(lazyGetter, <js.Expression>[],
2295 sourceInformation: node.sourceInformation); 2262 sourceInformation: node.sourceInformation);
2296 push(call); 2263 push(call);
2297 } 2264 }
2298 2265
2299 void visitStaticStore(HStaticStore node) { 2266 void visitStaticStore(HStaticStore node) {
2300 registry.registerStaticUse( 2267 registry.registerStaticUse(new StaticUse.staticSet(node.element));
2301 new StaticUse.staticSet(node.element));
2302 js.Node variable = backend.emitter.staticFieldAccess(node.element); 2268 js.Node variable = backend.emitter.staticFieldAccess(node.element);
2303 use(node.inputs[0]); 2269 use(node.inputs[0]);
2304 push(new js.Assignment(variable, pop()) 2270 push(new js.Assignment(variable, pop())
2305 .withSourceInformation(node.sourceInformation)); 2271 .withSourceInformation(node.sourceInformation));
2306 } 2272 }
2307 2273
2308 void visitStringConcat(HStringConcat node) { 2274 void visitStringConcat(HStringConcat node) {
2309 use(node.left); 2275 use(node.left);
2310 js.Expression jsLeft = pop(); 2276 js.Expression jsLeft = pop();
2311 use(node.right); 2277 use(node.right);
2312 push(new js.Binary('+', jsLeft, pop()) 2278 push(new js.Binary('+', jsLeft, pop())
2313 .withSourceInformation(node.sourceInformation)); 2279 .withSourceInformation(node.sourceInformation));
2314 } 2280 }
2315 2281
2316 void visitStringify(HStringify node) { 2282 void visitStringify(HStringify node) {
2317 HInstruction input = node.inputs.first; 2283 HInstruction input = node.inputs.first;
2318 if (input.isString(compiler)) { 2284 if (input.isString(compiler)) {
2319 use(input); 2285 use(input);
2320 } else if (input.isInteger(compiler) || input.isBoolean(compiler)) { 2286 } else if (input.isInteger(compiler) || input.isBoolean(compiler)) {
2321 // JavaScript's + operator with a string for the left operand will convert 2287 // JavaScript's + operator with a string for the left operand will convert
2322 // the right operand to a string, and the conversion result is correct. 2288 // the right operand to a string, and the conversion result is correct.
2323 use(input); 2289 use(input);
2324 if (node.usedBy.length == 1 2290 if (node.usedBy.length == 1 &&
2325 && node.usedBy[0] is HStringConcat 2291 node.usedBy[0] is HStringConcat &&
2326 && node.usedBy[0].inputs[1] == node) { 2292 node.usedBy[0].inputs[1] == node) {
2327 // The context is already <string> + value. 2293 // The context is already <string> + value.
2328 } else { 2294 } else {
2329 // Force an empty string for the first operand. 2295 // Force an empty string for the first operand.
2330 push(new js.Binary('+', js.string(""), pop()) 2296 push(new js.Binary('+', js.string(""), pop())
2331 .withSourceInformation(node.sourceInformation)); 2297 .withSourceInformation(node.sourceInformation));
2332 } 2298 }
2333 } else { 2299 } else {
2334 Element convertToString = backend.helpers.stringInterpolationHelper; 2300 Element convertToString = backend.helpers.stringInterpolationHelper;
2335 registry.registerStaticUse( 2301 registry.registerStaticUse(
2336 new StaticUse.staticInvoke(convertToString, CallStructure.ONE_ARG)); 2302 new StaticUse.staticInvoke(convertToString, CallStructure.ONE_ARG));
2337 js.Expression jsHelper = 2303 js.Expression jsHelper =
2338 backend.emitter.staticFunctionAccess(convertToString); 2304 backend.emitter.staticFunctionAccess(convertToString);
2339 use(input); 2305 use(input);
2340 push(new js.Call(jsHelper, <js.Expression>[pop()], 2306 push(new js.Call(jsHelper, <js.Expression>[pop()],
2341 sourceInformation: node.sourceInformation)); 2307 sourceInformation: node.sourceInformation));
2342 } 2308 }
2343 } 2309 }
2344 2310
2345 void visitLiteralList(HLiteralList node) { 2311 void visitLiteralList(HLiteralList node) {
2346 registry.registerInstantiatedClass(coreClasses.listClass); 2312 registry.registerInstantiatedClass(coreClasses.listClass);
2347 generateArrayLiteral(node); 2313 generateArrayLiteral(node);
2348 } 2314 }
2349 2315
2350 void generateArrayLiteral(HLiteralList node) { 2316 void generateArrayLiteral(HLiteralList node) {
2351 List<js.Expression> elements = node.inputs.map((HInstruction input) { 2317 List<js.Expression> elements = node.inputs.map((HInstruction input) {
(...skipping 23 matching lines...) Expand all
2375 } 2341 }
2376 2342
2377 void checkInt(HInstruction input, String cmp) { 2343 void checkInt(HInstruction input, String cmp) {
2378 use(input); 2344 use(input);
2379 js.Expression left = pop(); 2345 js.Expression left = pop();
2380 use(input); 2346 use(input);
2381 js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0")); 2347 js.Expression or0 = new js.Binary("|", pop(), new js.LiteralNumber("0"));
2382 push(new js.Binary(cmp, left, or0)); 2348 push(new js.Binary(cmp, left, or0));
2383 } 2349 }
2384 2350
2385 void checkBigInt(HInstruction input, String cmp, 2351 void checkBigInt(
2386 SourceInformation sourceInformation) { 2352 HInstruction input, String cmp, SourceInformation sourceInformation) {
2387 use(input); 2353 use(input);
2388 js.Expression left = pop(); 2354 js.Expression left = pop();
2389 use(input); 2355 use(input);
2390 js.Expression right = pop(); 2356 js.Expression right = pop();
2391 // TODO(4984): Deal with infinity and -0.0. 2357 // TODO(4984): Deal with infinity and -0.0.
2392 push(js.js('Math.floor(#) $cmp #', <js.Expression>[left, right]) 2358 push(js.js('Math.floor(#) $cmp #',
2393 .withSourceInformation(sourceInformation)); 2359 <js.Expression>[left, right]).withSourceInformation(sourceInformation));
2394 } 2360 }
2395 2361
2396 void checkTypeOf(HInstruction input, String cmp, String typeName, 2362 void checkTypeOf(HInstruction input, String cmp, String typeName,
2397 SourceInformation sourceInformation) { 2363 SourceInformation sourceInformation) {
2398 use(input); 2364 use(input);
2399 js.Expression typeOf = new js.Prefix("typeof", pop()); 2365 js.Expression typeOf = new js.Prefix("typeof", pop());
2400 push(new js.Binary(cmp, typeOf, js.string(typeName))); 2366 push(new js.Binary(cmp, typeOf, js.string(typeName)));
2401 } 2367 }
2402 2368
2403 void checkNum(HInstruction input, String cmp, 2369 void checkNum(
2404 SourceInformation sourceInformation) { 2370 HInstruction input, String cmp, SourceInformation sourceInformation) {
2405 return checkTypeOf(input, cmp, 'number', sourceInformation); 2371 return checkTypeOf(input, cmp, 'number', sourceInformation);
2406 } 2372 }
2407 2373
2408 void checkDouble(HInstruction input, String cmp, 2374 void checkDouble(
2409 SourceInformation sourceInformation) { 2375 HInstruction input, String cmp, SourceInformation sourceInformation) {
2410 return checkNum(input, cmp, sourceInformation); 2376 return checkNum(input, cmp, sourceInformation);
2411 } 2377 }
2412 2378
2413 void checkString(HInstruction input, String cmp, 2379 void checkString(
2414 SourceInformation sourceInformation) { 2380 HInstruction input, String cmp, SourceInformation sourceInformation) {
2415 return checkTypeOf(input, cmp, 'string', sourceInformation); 2381 return checkTypeOf(input, cmp, 'string', sourceInformation);
2416 } 2382 }
2417 2383
2418 void checkBool(HInstruction input, String cmp, 2384 void checkBool(
2419 SourceInformation sourceInformation) { 2385 HInstruction input, String cmp, SourceInformation sourceInformation) {
2420 return checkTypeOf(input, cmp, 'boolean', sourceInformation); 2386 return checkTypeOf(input, cmp, 'boolean', sourceInformation);
2421 } 2387 }
2422 2388
2423 void checkObject(HInstruction input, String cmp, 2389 void checkObject(
2424 SourceInformation sourceInformation) { 2390 HInstruction input, String cmp, SourceInformation sourceInformation) {
2425 assert(NullConstantValue.JsNull == 'null'); 2391 assert(NullConstantValue.JsNull == 'null');
2426 if (cmp == "===") { 2392 if (cmp == "===") {
2427 checkTypeOf(input, '===', 'object', sourceInformation); 2393 checkTypeOf(input, '===', 'object', sourceInformation);
2428 js.Expression left = pop(); 2394 js.Expression left = pop();
2429 use(input); 2395 use(input);
2430 js.Expression notNull = new js.Binary("!==", pop(), new js.LiteralNull()); 2396 js.Expression notNull = new js.Binary("!==", pop(), new js.LiteralNull());
2431 push(new js.Binary("&&", left, notNull) 2397 push(new js.Binary("&&", left, notNull)
2432 .withSourceInformation(sourceInformation)); 2398 .withSourceInformation(sourceInformation));
2433 } else { 2399 } else {
2434 assert(cmp == "!=="); 2400 assert(cmp == "!==");
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
2480 void checkNull(HInstruction input) { 2446 void checkNull(HInstruction input) {
2481 use(input); 2447 use(input);
2482 push(new js.Binary('==', pop(), new js.LiteralNull())); 2448 push(new js.Binary('==', pop(), new js.LiteralNull()));
2483 } 2449 }
2484 2450
2485 void checkNonNull(HInstruction input) { 2451 void checkNonNull(HInstruction input) {
2486 use(input); 2452 use(input);
2487 push(new js.Binary('!=', pop(), new js.LiteralNull())); 2453 push(new js.Binary('!=', pop(), new js.LiteralNull()));
2488 } 2454 }
2489 2455
2490 void checkType(HInstruction input, HInstruction interceptor, 2456 void checkType(HInstruction input, HInstruction interceptor, DartType type,
2491 DartType type, 2457 SourceInformation sourceInformation,
2492 SourceInformation sourceInformation, 2458 {bool negative: false}) {
2493 {bool negative: false}) {
2494 Element element = type.element; 2459 Element element = type.element;
2495 if (element == helpers.jsArrayClass) { 2460 if (element == helpers.jsArrayClass) {
2496 checkArray(input, negative ? '!==': '==='); 2461 checkArray(input, negative ? '!==' : '===');
2497 return; 2462 return;
2498 } else if (element == helpers.jsMutableArrayClass) { 2463 } else if (element == helpers.jsMutableArrayClass) {
2499 if (negative) { 2464 if (negative) {
2500 checkImmutableArray(input); 2465 checkImmutableArray(input);
2501 } else { 2466 } else {
2502 checkMutableArray(input); 2467 checkMutableArray(input);
2503 } 2468 }
2504 return; 2469 return;
2505 } else if (element == helpers.jsExtendableArrayClass) { 2470 } else if (element == helpers.jsExtendableArrayClass) {
2506 if (negative) { 2471 if (negative) {
(...skipping 12 matching lines...) Expand all
2519 } else if (element == helpers.jsUnmodifiableArrayClass) { 2484 } else if (element == helpers.jsUnmodifiableArrayClass) {
2520 if (negative) { 2485 if (negative) {
2521 checkMutableArray(input); 2486 checkMutableArray(input);
2522 } else { 2487 } else {
2523 checkImmutableArray(input); 2488 checkImmutableArray(input);
2524 } 2489 }
2525 return; 2490 return;
2526 } 2491 }
2527 if (interceptor != null) { 2492 if (interceptor != null) {
2528 checkTypeViaProperty(interceptor, type, sourceInformation, 2493 checkTypeViaProperty(interceptor, type, sourceInformation,
2529 negative: negative); 2494 negative: negative);
2530 } else { 2495 } else {
2531 checkTypeViaProperty(input, type, sourceInformation, negative: negative); 2496 checkTypeViaProperty(input, type, sourceInformation, negative: negative);
2532 } 2497 }
2533 } 2498 }
2534 2499
2535 void checkTypeViaProperty(HInstruction input, DartType type, 2500 void checkTypeViaProperty(
2536 SourceInformation sourceInformation, 2501 HInstruction input, DartType type, SourceInformation sourceInformation,
2537 {bool negative: false}) { 2502 {bool negative: false}) {
2538 registry.registerTypeUse(new TypeUse.isCheck(type)); 2503 registry.registerTypeUse(new TypeUse.isCheck(type));
2539 2504
2540 use(input); 2505 use(input);
2541 2506
2542 js.PropertyAccess field = 2507 js.PropertyAccess field =
2543 new js.PropertyAccess(pop(), backend.namer.operatorIsType(type)) 2508 new js.PropertyAccess(pop(), backend.namer.operatorIsType(type))
2544 .withSourceInformation(sourceInformation); 2509 .withSourceInformation(sourceInformation);
2545 // We always negate at least once so that the result is boolified. 2510 // We always negate at least once so that the result is boolified.
2546 push(new js.Prefix('!', field) 2511 push(new js.Prefix('!', field).withSourceInformation(sourceInformation));
2547 .withSourceInformation(sourceInformation));
2548 // If the result is not negated, put another '!' in front. 2512 // If the result is not negated, put another '!' in front.
2549 if (!negative) { 2513 if (!negative) {
2550 push(new js.Prefix('!', pop()) 2514 push(new js.Prefix('!', pop()).withSourceInformation(sourceInformation));
2551 .withSourceInformation(sourceInformation));
2552 } 2515 }
2553 } 2516 }
2554 2517
2555 void checkTypeViaInstanceof( 2518 void checkTypeViaInstanceof(
2556 HInstruction input, DartType type, 2519 HInstruction input, DartType type, SourceInformation sourceInformation,
2557 SourceInformation sourceInformation,
2558 {bool negative: false}) { 2520 {bool negative: false}) {
2559 registry.registerTypeUse(new TypeUse.isCheck(type)); 2521 registry.registerTypeUse(new TypeUse.isCheck(type));
2560 2522
2561 use(input); 2523 use(input);
2562 2524
2563 js.Expression jsClassReference = 2525 js.Expression jsClassReference =
2564 backend.emitter.constructorAccess(type.element); 2526 backend.emitter.constructorAccess(type.element);
2565 push(js.js('# instanceof #', [pop(), jsClassReference]) 2527 push(js.js('# instanceof #',
2566 .withSourceInformation(sourceInformation)); 2528 [pop(), jsClassReference]).withSourceInformation(sourceInformation));
2567 if (negative) { 2529 if (negative) {
2568 push(new js.Prefix('!', pop()) 2530 push(new js.Prefix('!', pop()).withSourceInformation(sourceInformation));
2569 .withSourceInformation(sourceInformation));
2570 } 2531 }
2571 registry.registerInstantiation(type); 2532 registry.registerInstantiation(type);
2572 } 2533 }
2573 2534
2574 void handleNumberOrStringSupertypeCheck(HInstruction input, 2535 void handleNumberOrStringSupertypeCheck(
2575 HInstruction interceptor, 2536 HInstruction input,
2576 DartType type, 2537 HInstruction interceptor,
2577 SourceInformation sourceInformation, 2538 DartType type,
2578 {bool negative: false}) { 2539 SourceInformation sourceInformation,
2540 {bool negative: false}) {
2579 assert(!identical(type.element, coreClasses.listClass) && 2541 assert(!identical(type.element, coreClasses.listClass) &&
2580 !Elements.isListSupertype(type.element, compiler) && 2542 !Elements.isListSupertype(type.element, compiler) &&
2581 !Elements.isStringOnlySupertype(type.element, compiler)); 2543 !Elements.isStringOnlySupertype(type.element, compiler));
2582 String relation = negative ? '!==' : '==='; 2544 String relation = negative ? '!==' : '===';
2583 checkNum(input, relation, sourceInformation); 2545 checkNum(input, relation, sourceInformation);
2584 js.Expression numberTest = pop(); 2546 js.Expression numberTest = pop();
2585 checkString(input, relation, sourceInformation); 2547 checkString(input, relation, sourceInformation);
2586 js.Expression stringTest = pop(); 2548 js.Expression stringTest = pop();
2587 checkObject(input, relation, sourceInformation); 2549 checkObject(input, relation, sourceInformation);
2588 js.Expression objectTest = pop(); 2550 js.Expression objectTest = pop();
2589 checkType(input, interceptor, type, sourceInformation, negative: negative); 2551 checkType(input, interceptor, type, sourceInformation, negative: negative);
2590 String combiner = negative ? '&&' : '||'; 2552 String combiner = negative ? '&&' : '||';
2591 String combiner2 = negative ? '||' : '&&'; 2553 String combiner2 = negative ? '||' : '&&';
2592 push(new js.Binary(combiner, 2554 push(new js.Binary(
2593 new js.Binary(combiner, numberTest, stringTest) 2555 combiner,
2594 .withSourceInformation(sourceInformation), 2556 new js.Binary(combiner, numberTest, stringTest)
2595 new js.Binary(combiner2, objectTest, pop()) 2557 .withSourceInformation(sourceInformation),
2596 .withSourceInformation(sourceInformation)) 2558 new js.Binary(combiner2, objectTest, pop())
2559 .withSourceInformation(sourceInformation))
2597 .withSourceInformation(sourceInformation)); 2560 .withSourceInformation(sourceInformation));
2598 } 2561 }
2599 2562
2600 void handleStringSupertypeCheck(HInstruction input, 2563 void handleStringSupertypeCheck(HInstruction input, HInstruction interceptor,
2601 HInstruction interceptor, 2564 DartType type, SourceInformation sourceInformation,
2602 DartType type, 2565 {bool negative: false}) {
2603 SourceInformation sourceInformation, 2566 assert(!identical(type.element, coreClasses.listClass) &&
2604 {bool negative: false}) { 2567 !Elements.isListSupertype(type.element, compiler) &&
2605 assert(!identical(type.element, coreClasses.listClass) 2568 !Elements.isNumberOrStringSupertype(type.element, compiler));
2606 && !Elements.isListSupertype(type.element, compiler)
2607 && !Elements.isNumberOrStringSupertype(type.element, compiler));
2608 String relation = negative ? '!==' : '==='; 2569 String relation = negative ? '!==' : '===';
2609 checkString(input, relation, sourceInformation); 2570 checkString(input, relation, sourceInformation);
2610 js.Expression stringTest = pop(); 2571 js.Expression stringTest = pop();
2611 checkObject(input, relation, sourceInformation); 2572 checkObject(input, relation, sourceInformation);
2612 js.Expression objectTest = pop(); 2573 js.Expression objectTest = pop();
2613 checkType(input, interceptor, type, sourceInformation, negative: negative); 2574 checkType(input, interceptor, type, sourceInformation, negative: negative);
2614 String combiner = negative ? '||' : '&&'; 2575 String combiner = negative ? '||' : '&&';
2615 push(new js.Binary(negative ? '&&' : '||', 2576 push(new js.Binary(negative ? '&&' : '||', stringTest,
2616 stringTest, 2577 new js.Binary(combiner, objectTest, pop())));
2617 new js.Binary(combiner, objectTest, pop())));
2618 } 2578 }
2619 2579
2620 void handleListOrSupertypeCheck(HInstruction input, 2580 void handleListOrSupertypeCheck(HInstruction input, HInstruction interceptor,
2621 HInstruction interceptor, 2581 DartType type, SourceInformation sourceInformation,
2622 DartType type, 2582 {bool negative: false}) {
2623 SourceInformation sourceInformation, 2583 assert(!identical(type.element, coreClasses.stringClass) &&
2624 { bool negative: false }) { 2584 !Elements.isStringOnlySupertype(type.element, compiler) &&
2625 assert(!identical(type.element, coreClasses.stringClass) 2585 !Elements.isNumberOrStringSupertype(type.element, compiler));
2626 && !Elements.isStringOnlySupertype(type.element, compiler)
2627 && !Elements.isNumberOrStringSupertype(type.element, compiler));
2628 String relation = negative ? '!==' : '==='; 2586 String relation = negative ? '!==' : '===';
2629 checkObject(input, relation, sourceInformation); 2587 checkObject(input, relation, sourceInformation);
2630 js.Expression objectTest = pop(); 2588 js.Expression objectTest = pop();
2631 checkArray(input, relation); 2589 checkArray(input, relation);
2632 js.Expression arrayTest = pop(); 2590 js.Expression arrayTest = pop();
2633 checkType(input, interceptor, type, sourceInformation, negative: negative); 2591 checkType(input, interceptor, type, sourceInformation, negative: negative);
2634 String combiner = negative ? '&&' : '||'; 2592 String combiner = negative ? '&&' : '||';
2635 push(new js.Binary(negative ? '||' : '&&', 2593 push(new js.Binary(negative ? '||' : '&&', objectTest,
2636 objectTest, 2594 new js.Binary(combiner, arrayTest, pop()))
2637 new js.Binary(combiner, arrayTest, pop()))
2638 .withSourceInformation(sourceInformation)); 2595 .withSourceInformation(sourceInformation));
2639 } 2596 }
2640 2597
2641 void visitIs(HIs node) { 2598 void visitIs(HIs node) {
2642 emitIs(node, "===", node.sourceInformation); 2599 emitIs(node, "===", node.sourceInformation);
2643 } 2600 }
2644 2601
2645 void visitIsViaInterceptor(HIsViaInterceptor node) { 2602 void visitIsViaInterceptor(HIsViaInterceptor node) {
2646 emitIsViaInterceptor(node, node.sourceInformation, negative: false); 2603 emitIsViaInterceptor(node, node.sourceInformation, negative: false);
2647 } 2604 }
2648 2605
2649 void emitIs(HIs node, String relation, SourceInformation sourceInformation) { 2606 void emitIs(HIs node, String relation, SourceInformation sourceInformation) {
2650 DartType type = node.typeExpression; 2607 DartType type = node.typeExpression;
2651 registry.registerTypeUse(new TypeUse.isCheck(type)); 2608 registry.registerTypeUse(new TypeUse.isCheck(type));
2652 HInstruction input = node.expression; 2609 HInstruction input = node.expression;
2653 2610
2654 // If this is changed to single == there are several places below that must 2611 // If this is changed to single == there are several places below that must
2655 // be changed to match. 2612 // be changed to match.
2656 assert(relation == '===' || relation == '!=='); 2613 assert(relation == '===' || relation == '!==');
2657 bool negative = relation == '!=='; 2614 bool negative = relation == '!==';
2658 2615
2659 if (node.isVariableCheck || node.isCompoundCheck) { 2616 if (node.isVariableCheck || node.isCompoundCheck) {
(...skipping 26 matching lines...) Expand all
2686 // The is check in the code tells us that it might not be an 2643 // The is check in the code tells us that it might not be an
2687 // int. So we do a typeof first to avoid possible 2644 // int. So we do a typeof first to avoid possible
2688 // deoptimizations on the JS engine due to the Math.floor check. 2645 // deoptimizations on the JS engine due to the Math.floor check.
2689 checkNum(input, relation, sourceInformation); 2646 checkNum(input, relation, sourceInformation);
2690 js.Expression numTest = pop(); 2647 js.Expression numTest = pop();
2691 checkBigInt(input, relation, sourceInformation); 2648 checkBigInt(input, relation, sourceInformation);
2692 push(new js.Binary(negative ? '||' : '&&', numTest, pop()) 2649 push(new js.Binary(negative ? '||' : '&&', numTest, pop())
2693 .withSourceInformation(sourceInformation)); 2650 .withSourceInformation(sourceInformation));
2694 } else if (node.useInstanceOf) { 2651 } else if (node.useInstanceOf) {
2695 assert(interceptor == null); 2652 assert(interceptor == null);
2696 checkTypeViaInstanceof(input, type, 2653 checkTypeViaInstanceof(input, type, sourceInformation,
2697 sourceInformation, 2654 negative: negative);
2698 negative: negative);
2699 } else if (Elements.isNumberOrStringSupertype(element, compiler)) { 2655 } else if (Elements.isNumberOrStringSupertype(element, compiler)) {
2700 handleNumberOrStringSupertypeCheck( 2656 handleNumberOrStringSupertypeCheck(
2701 input, interceptor, type, 2657 input, interceptor, type, sourceInformation,
2702 sourceInformation,
2703 negative: negative); 2658 negative: negative);
2704 } else if (Elements.isStringOnlySupertype(element, compiler)) { 2659 } else if (Elements.isStringOnlySupertype(element, compiler)) {
2705 handleStringSupertypeCheck( 2660 handleStringSupertypeCheck(input, interceptor, type, sourceInformation,
2706 input, interceptor, type,
2707 sourceInformation,
2708 negative: negative); 2661 negative: negative);
2709 } else if (identical(element, coreClasses.listClass) || 2662 } else if (identical(element, coreClasses.listClass) ||
2710 Elements.isListSupertype(element, compiler)) { 2663 Elements.isListSupertype(element, compiler)) {
2711 handleListOrSupertypeCheck( 2664 handleListOrSupertypeCheck(input, interceptor, type, sourceInformation,
2712 input, interceptor, type,
2713 sourceInformation,
2714 negative: negative); 2665 negative: negative);
2715 } else if (type.isFunctionType) { 2666 } else if (type.isFunctionType) {
2716 checkType(input, interceptor, type, 2667 checkType(input, interceptor, type, sourceInformation,
2717 sourceInformation, 2668 negative: negative);
2718 negative: negative); 2669 } else if ((input.canBePrimitive(compiler) &&
2719 } else if ((input.canBePrimitive(compiler) 2670 !input.canBePrimitiveArray(compiler)) ||
2720 && !input.canBePrimitiveArray(compiler)) 2671 input.canBeNull()) {
2721 || input.canBeNull()) {
2722 checkObject(input, relation, node.sourceInformation); 2672 checkObject(input, relation, node.sourceInformation);
2723 js.Expression objectTest = pop(); 2673 js.Expression objectTest = pop();
2724 checkType(input, interceptor, type, 2674 checkType(input, interceptor, type, sourceInformation,
2725 sourceInformation, 2675 negative: negative);
2726 negative: negative);
2727 push(new js.Binary(negative ? '||' : '&&', objectTest, pop()) 2676 push(new js.Binary(negative ? '||' : '&&', objectTest, pop())
2728 .withSourceInformation(sourceInformation)); 2677 .withSourceInformation(sourceInformation));
2729 } else { 2678 } else {
2730 checkType(input, interceptor, type, 2679 checkType(input, interceptor, type, sourceInformation,
2731 sourceInformation, 2680 negative: negative);
2732 negative: negative);
2733 } 2681 }
2734 } 2682 }
2735 } 2683 }
2736 2684
2737 void emitIsViaInterceptor(HIsViaInterceptor node, 2685 void emitIsViaInterceptor(
2738 SourceInformation sourceInformation, 2686 HIsViaInterceptor node, SourceInformation sourceInformation,
2739 {bool negative: false}) { 2687 {bool negative: false}) {
2740 checkTypeViaProperty(node.interceptor, node.typeExpression, 2688 checkTypeViaProperty(
2741 sourceInformation, 2689 node.interceptor, node.typeExpression, sourceInformation,
2742 negative: negative); 2690 negative: negative);
2743 } 2691 }
2744 2692
2745 js.Expression generateReceiverOrArgumentTypeTest( 2693 js.Expression generateReceiverOrArgumentTypeTest(
2746 HInstruction input, TypeMask checkedType) { 2694 HInstruction input, TypeMask checkedType) {
2747 ClassWorld classWorld = compiler.world; 2695 ClassWorld classWorld = compiler.world;
2748 TypeMask inputType = input.instructionType; 2696 TypeMask inputType = input.instructionType;
2749 // Figure out if it is beneficial to turn this into a null check. 2697 // Figure out if it is beneficial to turn this into a null check.
2750 // V8 generally prefers 'typeof' checks, but for integers and 2698 // V8 generally prefers 'typeof' checks, but for integers and
2751 // indexable primitives we cannot compile this test into a single 2699 // indexable primitives we cannot compile this test into a single
2752 // typeof check so the null check is cheaper. 2700 // typeof check so the null check is cheaper.
2753 bool isIntCheck = checkedType.containsOnlyInt(classWorld); 2701 bool isIntCheck = checkedType.containsOnlyInt(classWorld);
2754 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler); 2702 bool turnIntoNumCheck = isIntCheck && input.isIntegerOrNull(compiler);
2755 bool turnIntoNullCheck = !turnIntoNumCheck 2703 bool turnIntoNullCheck = !turnIntoNumCheck &&
2756 && (checkedType.nullable() == inputType) 2704 (checkedType.nullable() == inputType) &&
2757 && (isIntCheck 2705 (isIntCheck ||
2758 || checkedType.satisfies(helpers.jsIndexableClass, classWorld)); 2706 checkedType.satisfies(helpers.jsIndexableClass, classWorld));
2759 2707
2760 if (turnIntoNullCheck) { 2708 if (turnIntoNullCheck) {
2761 use(input); 2709 use(input);
2762 return new js.Binary("==", pop(), new js.LiteralNull()) 2710 return new js.Binary("==", pop(), new js.LiteralNull())
2763 .withSourceInformation(input.sourceInformation); 2711 .withSourceInformation(input.sourceInformation);
2764 } else if (isIntCheck && !turnIntoNumCheck) { 2712 } else if (isIntCheck && !turnIntoNumCheck) {
2765 // input is !int 2713 // input is !int
2766 checkBigInt(input, '!==', input.sourceInformation); 2714 checkBigInt(input, '!==', input.sourceInformation);
2767 return pop(); 2715 return pop();
2768 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) { 2716 } else if (turnIntoNumCheck || checkedType.containsOnlyNum(classWorld)) {
(...skipping 12 matching lines...) Expand all
2781 reporter.internalError(input, 'Unexpected check: $checkedType.'); 2729 reporter.internalError(input, 'Unexpected check: $checkedType.');
2782 return null; 2730 return null;
2783 } 2731 }
2784 2732
2785 void visitTypeConversion(HTypeConversion node) { 2733 void visitTypeConversion(HTypeConversion node) {
2786 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) { 2734 if (node.isArgumentTypeCheck || node.isReceiverTypeCheck) {
2787 ClassWorld classWorld = compiler.world; 2735 ClassWorld classWorld = compiler.world;
2788 // An int check if the input is not int or null, is not 2736 // An int check if the input is not int or null, is not
2789 // sufficient for doing an argument or receiver check. 2737 // sufficient for doing an argument or receiver check.
2790 assert(compiler.options.trustTypeAnnotations || 2738 assert(compiler.options.trustTypeAnnotations ||
2791 !node.checkedType.containsOnlyInt(classWorld) || 2739 !node.checkedType.containsOnlyInt(classWorld) ||
2792 node.checkedInput.isIntegerOrNull(compiler)); 2740 node.checkedInput.isIntegerOrNull(compiler));
2793 js.Expression test = generateReceiverOrArgumentTypeTest( 2741 js.Expression test = generateReceiverOrArgumentTypeTest(
2794 node.checkedInput, node.checkedType); 2742 node.checkedInput, node.checkedType);
2795 js.Block oldContainer = currentContainer; 2743 js.Block oldContainer = currentContainer;
2796 js.Statement body = new js.Block.empty(); 2744 js.Statement body = new js.Block.empty();
2797 currentContainer = body; 2745 currentContainer = body;
2798 if (node.isArgumentTypeCheck) { 2746 if (node.isArgumentTypeCheck) {
2799 generateThrowWithHelper( 2747 generateThrowWithHelper(
2800 helpers.throwIllegalArgumentException, 2748 helpers.throwIllegalArgumentException, node.checkedInput,
2801 node.checkedInput,
2802 sourceInformation: node.sourceInformation); 2749 sourceInformation: node.sourceInformation);
2803 } else if (node.isReceiverTypeCheck) { 2750 } else if (node.isReceiverTypeCheck) {
2804 use(node.checkedInput); 2751 use(node.checkedInput);
2805 js.Name methodName = 2752 js.Name methodName =
2806 backend.namer.invocationName(node.receiverTypeCheckSelector); 2753 backend.namer.invocationName(node.receiverTypeCheckSelector);
2807 js.Expression call = js.propertyCall(pop(), methodName, []); 2754 js.Expression call = js.propertyCall(pop(), methodName, []);
2808 pushStatement(new js.Return(call)); 2755 pushStatement(new js.Return(call));
2809 } 2756 }
2810 currentContainer = oldContainer; 2757 currentContainer = oldContainer;
2811 body = unwrapStatement(body); 2758 body = unwrapStatement(body);
2812 pushStatement(new js.If.noElse(test, body) 2759 pushStatement(new js.If.noElse(test, body)
2813 .withSourceInformation(node.sourceInformation)); 2760 .withSourceInformation(node.sourceInformation));
2814 return; 2761 return;
2815 } 2762 }
2816 2763
2817 assert(node.isCheckedModeCheck || node.isCastTypeCheck); 2764 assert(node.isCheckedModeCheck || node.isCastTypeCheck);
2818 DartType type = node.typeExpression; 2765 DartType type = node.typeExpression;
2819 assert(type.kind != TypeKind.TYPEDEF); 2766 assert(type.kind != TypeKind.TYPEDEF);
2820 if (type.isFunctionType) { 2767 if (type.isFunctionType) {
2821 // TODO(5022): We currently generate $isFunction checks for 2768 // TODO(5022): We currently generate $isFunction checks for
2822 // function types. 2769 // function types.
2823 registry.registerTypeUse( 2770 registry.registerTypeUse(
2824 new TypeUse.isCheck(compiler.coreTypes.functionType)); 2771 new TypeUse.isCheck(compiler.coreTypes.functionType));
2825 } 2772 }
2826 registry.registerTypeUse(new TypeUse.isCheck(type)); 2773 registry.registerTypeUse(new TypeUse.isCheck(type));
2827 2774
2828 CheckedModeHelper helper; 2775 CheckedModeHelper helper;
2829 if (node.isBooleanConversionCheck) { 2776 if (node.isBooleanConversionCheck) {
2830 helper = 2777 helper = const CheckedModeHelper('boolConversionCheck');
2831 const CheckedModeHelper('boolConversionCheck');
2832 } else { 2778 } else {
2833 helper = 2779 helper =
2834 backend.getCheckedModeHelper(type, typeCast: node.isCastTypeCheck); 2780 backend.getCheckedModeHelper(type, typeCast: node.isCastTypeCheck);
2835 } 2781 }
2836 2782
2837 if (helper == null) { 2783 if (helper == null) {
2838 assert(type.isFunctionType); 2784 assert(type.isFunctionType);
2839 use(node.inputs[0]); 2785 use(node.inputs[0]);
2840 } else { 2786 } else {
2841 push(helper.generateCall(this, node)); 2787 push(helper.generateCall(this, node));
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2877 var arguments = [returnType]; 2823 var arguments = [returnType];
2878 if (!parameterTypes.isEmpty || !optionalParameterTypes.isEmpty) { 2824 if (!parameterTypes.isEmpty || !optionalParameterTypes.isEmpty) {
2879 arguments.add(new js.ArrayInitializer(parameterTypes)); 2825 arguments.add(new js.ArrayInitializer(parameterTypes));
2880 } 2826 }
2881 if (!optionalParameterTypes.isEmpty) { 2827 if (!optionalParameterTypes.isEmpty) {
2882 arguments.add(new js.ArrayInitializer(optionalParameterTypes)); 2828 arguments.add(new js.ArrayInitializer(optionalParameterTypes));
2883 } 2829 }
2884 push(js.js('#(#)', [accessHelper('buildFunctionType'), arguments])); 2830 push(js.js('#(#)', [accessHelper('buildFunctionType'), arguments]));
2885 } else { 2831 } else {
2886 var arguments = [ 2832 var arguments = [
2887 returnType, 2833 returnType,
2888 new js.ArrayInitializer(parameterTypes), 2834 new js.ArrayInitializer(parameterTypes),
2889 new js.ObjectInitializer(namedParameters)]; 2835 new js.ObjectInitializer(namedParameters)
2836 ];
2890 push(js.js('#(#)', [accessHelper('buildNamedFunctionType'), arguments])); 2837 push(js.js('#(#)', [accessHelper('buildNamedFunctionType'), arguments]));
2891 } 2838 }
2892 } 2839 }
2893 2840
2894 void visitReadTypeVariable(HReadTypeVariable node) { 2841 void visitReadTypeVariable(HReadTypeVariable node) {
2895 TypeVariableElement element = node.dartType.element; 2842 TypeVariableElement element = node.dartType.element;
2896 Element helperElement = helpers.convertRtiToRuntimeType; 2843 Element helperElement = helpers.convertRtiToRuntimeType;
2897 registry.registerStaticUse( 2844 registry.registerStaticUse(
2898 new StaticUse.staticInvoke(helperElement, CallStructure.ONE_ARG)); 2845 new StaticUse.staticInvoke(helperElement, CallStructure.ONE_ARG));
2899 2846
2900 use(node.inputs[0]); 2847 use(node.inputs[0]);
2901 if (node.hasReceiver) { 2848 if (node.hasReceiver) {
2902 if (backend.isInterceptorClass(element.enclosingClass)) { 2849 if (backend.isInterceptorClass(element.enclosingClass)) {
2903 int index = element.index; 2850 int index = element.index;
2904 js.Expression receiver = pop(); 2851 js.Expression receiver = pop();
2905 js.Expression helper = backend.emitter 2852 js.Expression helper =
2906 .staticFunctionAccess(helperElement); 2853 backend.emitter.staticFunctionAccess(helperElement);
2907 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])', 2854 push(js.js(r'#(#.$builtinTypeInfo && #.$builtinTypeInfo[#])',
2908 [helper, receiver, receiver, js.js.number(index)])); 2855 [helper, receiver, receiver, js.js.number(index)]));
2909 } else { 2856 } else {
2910 backend.emitter.registerReadTypeVariable(element); 2857 backend.emitter.registerReadTypeVariable(element);
2911 push(js.js('#.#()', 2858 push(js.js(
2912 [pop(), backend.namer.nameForReadTypeVariable(element)])); 2859 '#.#()', [pop(), backend.namer.nameForReadTypeVariable(element)]));
2913 } 2860 }
2914 } else { 2861 } else {
2915 push(js.js('#(#)', [ 2862 push(js.js('#(#)',
2916 backend.emitter.staticFunctionAccess(helperElement), 2863 [backend.emitter.staticFunctionAccess(helperElement), pop()]));
2917 pop()]));
2918 } 2864 }
2919 } 2865 }
2920 2866
2921 void visitInterfaceType(HInterfaceType node) { 2867 void visitInterfaceType(HInterfaceType node) {
2922 List<js.Expression> typeArguments = <js.Expression>[]; 2868 List<js.Expression> typeArguments = <js.Expression>[];
2923 for (HInstruction type in node.inputs) { 2869 for (HInstruction type in node.inputs) {
2924 use(type); 2870 use(type);
2925 typeArguments.add(pop()); 2871 typeArguments.add(pop());
2926 } 2872 }
2927 2873
(...skipping 13 matching lines...) Expand all
2941 void visitDynamicType(HDynamicType node) { 2887 void visitDynamicType(HDynamicType node) {
2942 push(js.js('#()', accessHelper('getDynamicRuntimeType'))); 2888 push(js.js('#()', accessHelper('getDynamicRuntimeType')));
2943 } 2889 }
2944 2890
2945 js.PropertyAccess accessHelper(String name, [int argumentCount = 0]) { 2891 js.PropertyAccess accessHelper(String name, [int argumentCount = 0]) {
2946 Element helper = helpers.findHelper(name); 2892 Element helper = helpers.findHelper(name);
2947 if (helper == null) { 2893 if (helper == null) {
2948 // For mocked-up tests. 2894 // For mocked-up tests.
2949 return js.js('(void 0).$name'); 2895 return js.js('(void 0).$name');
2950 } 2896 }
2951 registry.registerStaticUse( 2897 registry.registerStaticUse(new StaticUse.staticInvoke(
2952 new StaticUse.staticInvoke(helper, 2898 helper, new CallStructure.unnamed(argumentCount)));
2953 new CallStructure.unnamed(argumentCount)));
2954 return backend.emitter.staticFunctionAccess(helper); 2899 return backend.emitter.staticFunctionAccess(helper);
2955 } 2900 }
2956 2901
2957 @override 2902 @override
2958 void visitRef(HRef node) { 2903 void visitRef(HRef node) {
2959 visit(node.value); 2904 visit(node.value);
2960 } 2905 }
2961 } 2906 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/codegen_helpers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698