OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |