| 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 |