| 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 abstract class OptimizationPhase { | 7 abstract class OptimizationPhase { |
| 8 String get name; | 8 String get name; |
| 9 void visitGraph(HGraph graph); | 9 void visitGraph(HGraph graph); |
| 10 } | 10 } |
| (...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 result.element = target; | 310 result.element = target; |
| 311 return result; | 311 return result; |
| 312 } | 312 } |
| 313 } else if (selector.isGetter()) { | 313 } else if (selector.isGetter()) { |
| 314 if (selector.applies(backend.jsArrayLength, compiler)) { | 314 if (selector.applies(backend.jsArrayLength, compiler)) { |
| 315 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); | 315 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); |
| 316 if (optimized != null) return optimized; | 316 if (optimized != null) return optimized; |
| 317 } | 317 } |
| 318 } | 318 } |
| 319 | 319 |
| 320 // Check if this call does not need to be intercepted. | |
| 321 HType type = input.instructionType; | |
| 322 // TODO(kasperl): Get rid of this refinement once the receiver | |
| 323 // specialization phase takes care of it. | |
| 324 Selector refined = type.refine(selector, compiler); | |
| 325 Set<ClassElement> classes = backend.getInterceptedClassesOn( | |
| 326 refined, canBeNull: type.canBeNull()); | |
| 327 if (classes == null) { | |
| 328 if (selector.isGetter()) { | |
| 329 // Change the call to a regular invoke dynamic call. | |
| 330 return new HInvokeDynamicGetter(selector, null, input, false); | |
| 331 } else if (selector.isSetter()) { | |
| 332 return new HInvokeDynamicSetter( | |
| 333 selector, null, input, node.inputs[2], false); | |
| 334 } else { | |
| 335 // Change the call to a regular invoke dynamic call. | |
| 336 return new HInvokeDynamicMethod( | |
| 337 selector, node.inputs.getRange(1, node.inputs.length - 1)); | |
| 338 } | |
| 339 } | |
| 340 | |
| 341 // If the intercepted call is through a constant interceptor, we | 320 // If the intercepted call is through a constant interceptor, we |
| 342 // know which element to call. | 321 // know which element to call. |
| 343 if (node is !HOneShotInterceptor | 322 if (node is !HOneShotInterceptor |
| 344 && interceptor.isConstant() | 323 && interceptor.isConstant() |
| 345 && selector.isCall()) { | 324 && selector.isCall()) { |
| 346 DartType type = interceptor.instructionType.computeType(compiler); | 325 DartType type = interceptor.instructionType.computeType(compiler); |
| 347 ClassElement cls = type.element; | 326 ClassElement cls = type.element; |
| 348 node.element = cls.lookupSelector(selector); | 327 node.element = cls.lookupSelector(selector); |
| 349 } | 328 } |
| 350 return node; | 329 return node; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 367 } | 346 } |
| 368 | 347 |
| 369 HInstruction visitInvokeStatic(HInvokeStatic node) { | 348 HInstruction visitInvokeStatic(HInvokeStatic node) { |
| 370 if (isFixedSizeListConstructor(node)) { | 349 if (isFixedSizeListConstructor(node)) { |
| 371 node.instructionType = HType.FIXED_ARRAY; | 350 node.instructionType = HType.FIXED_ARRAY; |
| 372 } | 351 } |
| 373 return node; | 352 return node; |
| 374 } | 353 } |
| 375 | 354 |
| 376 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 355 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 377 if (node.isInterceptorCall) return handleInterceptorCall(node); | 356 if (node.isCallOnInterceptor) return handleInterceptorCall(node); |
| 378 HType receiverType = node.receiver.instructionType; | 357 HType receiverType = node.receiver.instructionType; |
| 379 Selector selector = receiverType.refine(node.selector, compiler); | 358 Selector selector = receiverType.refine(node.selector, compiler); |
| 380 Element element = compiler.world.locateSingleElement(selector); | 359 Element element = compiler.world.locateSingleElement(selector); |
| 381 // TODO(ngeoffray): Also fold if it's a getter or variable. | 360 // TODO(ngeoffray): Also fold if it's a getter or variable. |
| 382 if (element != null && element.isFunction()) { | 361 if (element != null && element.isFunction()) { |
| 383 FunctionElement method = element; | 362 FunctionElement method = element; |
| 384 FunctionSignature parameters = method.computeSignature(compiler); | 363 FunctionSignature parameters = method.computeSignature(compiler); |
| 385 // TODO(ngeoffray): If the method has optional parameters, | 364 // TODO(ngeoffray): If the method has optional parameters, |
| 386 // we should pass the default values. | 365 // we should pass the default values. |
| 387 if (parameters.optionalParameterCount == 0 | 366 if (parameters.optionalParameterCount == 0 |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 HInvokeStatic call = node.receiver; | 580 HInvokeStatic call = node.receiver; |
| 602 if (isFixedSizeListConstructor(call)) { | 581 if (isFixedSizeListConstructor(call)) { |
| 603 return call.inputs[1]; | 582 return call.inputs[1]; |
| 604 } | 583 } |
| 605 } | 584 } |
| 606 } | 585 } |
| 607 return node; | 586 return node; |
| 608 } | 587 } |
| 609 | 588 |
| 610 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 589 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 611 if (node.isInterceptorCall) return handleInterceptorCall(node); | 590 if (node.isCallOnInterceptor) return handleInterceptorCall(node); |
| 612 | 591 |
| 613 Element field = | 592 Element field = |
| 614 findConcreteFieldForDynamicAccess(node.receiver, node.selector); | 593 findConcreteFieldForDynamicAccess(node.receiver, node.selector); |
| 615 if (field == null) return node; | 594 if (field == null) return node; |
| 616 | 595 |
| 617 Modifiers modifiers = field.modifiers; | 596 Modifiers modifiers = field.modifiers; |
| 618 bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); | 597 bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); |
| 619 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { | 598 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { |
| 620 // If no setter is ever used for this field it is only initialized in the | 599 // If no setter is ever used for this field it is only initialized in the |
| 621 // initializer list. | 600 // initializer list. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 637 } | 616 } |
| 638 } | 617 } |
| 639 if (type != null) { | 618 if (type != null) { |
| 640 result.instructionType = type; | 619 result.instructionType = type; |
| 641 } | 620 } |
| 642 } | 621 } |
| 643 return result; | 622 return result; |
| 644 } | 623 } |
| 645 | 624 |
| 646 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 625 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 647 if (node.isInterceptorCall) return handleInterceptorCall(node); | 626 if (node.isCallOnInterceptor) return handleInterceptorCall(node); |
| 648 | 627 |
| 649 Element field = | 628 Element field = |
| 650 findConcreteFieldForDynamicAccess(node.receiver, node.selector); | 629 findConcreteFieldForDynamicAccess(node.receiver, node.selector); |
| 651 if (field == null || !field.isAssignable()) return node; | 630 if (field == null || !field.isAssignable()) return node; |
| 652 HInstruction value = node.inputs[1]; | 631 // Use [:node.inputs.last:] in case the call follows the |
| 632 // interceptor calling convention, but is not a call on an |
| 633 // interceptor. |
| 634 HInstruction value = node.inputs.last; |
| 653 if (compiler.enableTypeAssertions) { | 635 if (compiler.enableTypeAssertions) { |
| 654 HInstruction other = value.convertType( | 636 HInstruction other = value.convertType( |
| 655 compiler, | 637 compiler, |
| 656 field.computeType(compiler), | 638 field.computeType(compiler), |
| 657 HTypeConversion.CHECKED_MODE_CHECK); | 639 HTypeConversion.CHECKED_MODE_CHECK); |
| 658 if (other != value) { | 640 if (other != value) { |
| 659 node.block.addBefore(node, other); | 641 node.block.addBefore(node, other); |
| 660 value = other; | 642 value = other; |
| 661 } | 643 } |
| 662 } | 644 } |
| 663 return new HFieldSet(field, node.inputs[0], value); | 645 return new HFieldSet(field, node.inputs[0], value); |
| 664 } | 646 } |
| 665 | 647 |
| 666 HInstruction visitStringConcat(HStringConcat node) { | 648 HInstruction visitStringConcat(HStringConcat node) { |
| 667 DartString folded = const LiteralDartString(""); | 649 DartString folded = const LiteralDartString(""); |
| 668 for (int i = 0; i < node.inputs.length; i++) { | 650 for (int i = 0; i < node.inputs.length; i++) { |
| 669 HInstruction part = node.inputs[i]; | 651 HInstruction part = node.inputs[i]; |
| 670 if (!part.isConstant()) return node; | 652 if (!part.isConstant()) return node; |
| 671 HConstant constant = part; | 653 HConstant constant = part; |
| 672 if (!constant.constant.isPrimitive()) return node; | 654 if (!constant.constant.isPrimitive()) return node; |
| 673 PrimitiveConstant primitive = constant.constant; | 655 PrimitiveConstant primitive = constant.constant; |
| 674 folded = new DartString.concat(folded, primitive.toDartString()); | 656 folded = new DartString.concat(folded, primitive.toDartString()); |
| 675 } | 657 } |
| 676 return graph.addConstant(constantSystem.createString(folded, node.node)); | 658 return graph.addConstant(constantSystem.createString(folded, node.node)); |
| 677 } | 659 } |
| 678 | 660 |
| 679 HInstruction visitInterceptor(HInterceptor node) { | 661 HInstruction visitInterceptor(HInterceptor node) { |
| 680 if (node.isConstant()) return node; | 662 if (node.isConstant()) return node; |
| 663 // If the intercepted object does not need to be intercepted, just |
| 664 // return the object (the [:getInterceptor:] method would have |
| 665 // returned the object). |
| 666 HType type = node.receiver.instructionType; |
| 667 if (!type.canBePrimitive()) { |
| 668 |
| 669 if (!(type.canBeNull() |
| 670 && node.interceptedClasses.contains(compiler.objectClass))) { |
| 671 return node.receiver; |
| 672 } |
| 673 } |
| 681 HInstruction constant = tryComputeConstantInterceptor( | 674 HInstruction constant = tryComputeConstantInterceptor( |
| 682 node.inputs[0], node.interceptedClasses); | 675 node.inputs[0], node.interceptedClasses); |
| 683 if (constant == null) return node; | 676 if (constant == null) return node; |
| 677 |
| 684 return constant; | 678 return constant; |
| 685 } | 679 } |
| 686 | 680 |
| 687 HInstruction tryComputeConstantInterceptor(HInstruction input, | 681 HInstruction tryComputeConstantInterceptor(HInstruction input, |
| 688 Set<ClassElement> intercepted) { | 682 Set<ClassElement> intercepted) { |
| 689 HType type = input.instructionType; | 683 HType type = input.instructionType; |
| 690 ClassElement constantInterceptor; | 684 ClassElement constantInterceptor; |
| 691 if (type.isInteger()) { | 685 if (type.isInteger()) { |
| 692 constantInterceptor = backend.jsIntClass; | 686 constantInterceptor = backend.jsIntClass; |
| 693 } else if (type.isDouble()) { | 687 } else if (type.isDouble()) { |
| (...skipping 840 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1534 HBasicBlock block = user.block; | 1528 HBasicBlock block = user.block; |
| 1535 block.addAfter(user, interceptor); | 1529 block.addAfter(user, interceptor); |
| 1536 block.rewrite(user, interceptor); | 1530 block.rewrite(user, interceptor); |
| 1537 block.remove(user); | 1531 block.remove(user); |
| 1538 | 1532 |
| 1539 // The interceptor will be removed in the dead code elimination | 1533 // The interceptor will be removed in the dead code elimination |
| 1540 // phase. Note that removing it here would not work because of how | 1534 // phase. Note that removing it here would not work because of how |
| 1541 // the [visitBasicBlock] is implemented. | 1535 // the [visitBasicBlock] is implemented. |
| 1542 } | 1536 } |
| 1543 } | 1537 } |
| OLD | NEW |