| 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 17 matching lines...) Expand all Loading... |
| 368 } | 347 } |
| 369 | 348 |
| 370 HInstruction visitInvokeStatic(HInvokeStatic node) { | 349 HInstruction visitInvokeStatic(HInvokeStatic node) { |
| 371 if (isFixedSizeListConstructor(node)) { | 350 if (isFixedSizeListConstructor(node)) { |
| 372 node.instructionType = HType.FIXED_ARRAY; | 351 node.instructionType = HType.FIXED_ARRAY; |
| 373 } | 352 } |
| 374 return node; | 353 return node; |
| 375 } | 354 } |
| 376 | 355 |
| 377 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 356 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 378 if (node.isInterceptorCall) return handleInterceptorCall(node); | 357 if (node.isCallOnInterceptor) return handleInterceptorCall(node); |
| 379 HType receiverType = node.receiver.instructionType; | 358 HType receiverType = node.receiver.instructionType; |
| 380 Selector selector = receiverType.refine(node.selector, compiler); | 359 Selector selector = receiverType.refine(node.selector, compiler); |
| 381 Element element = compiler.world.locateSingleElement(selector); | 360 Element element = compiler.world.locateSingleElement(selector); |
| 382 // TODO(ngeoffray): Also fold if it's a getter or variable. | 361 // TODO(ngeoffray): Also fold if it's a getter or variable. |
| 383 if (element != null && element.isFunction()) { | 362 if (element != null && element.isFunction()) { |
| 384 FunctionElement method = element; | 363 FunctionElement method = element; |
| 385 FunctionSignature parameters = method.computeSignature(compiler); | 364 FunctionSignature parameters = method.computeSignature(compiler); |
| 386 // TODO(ngeoffray): If the method has optional parameters, | 365 // TODO(ngeoffray): If the method has optional parameters, |
| 387 // we should pass the default values. | 366 // we should pass the default values. |
| 388 if (parameters.optionalParameterCount == 0 | 367 if (parameters.optionalParameterCount == 0 |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 602 HInvokeStatic call = node.receiver; | 581 HInvokeStatic call = node.receiver; |
| 603 if (isFixedSizeListConstructor(call)) { | 582 if (isFixedSizeListConstructor(call)) { |
| 604 return call.inputs[1]; | 583 return call.inputs[1]; |
| 605 } | 584 } |
| 606 } | 585 } |
| 607 } | 586 } |
| 608 return node; | 587 return node; |
| 609 } | 588 } |
| 610 | 589 |
| 611 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 590 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
| 612 if (node.isInterceptorCall) return handleInterceptorCall(node); | 591 if (node.isCallOnInterceptor) return handleInterceptorCall(node); |
| 613 | 592 |
| 614 Element field = | 593 Element field = |
| 615 findConcreteFieldForDynamicAccess(node.receiver, node.selector); | 594 findConcreteFieldForDynamicAccess(node.receiver, node.selector); |
| 616 if (field == null) return node; | 595 if (field == null) return node; |
| 617 | 596 |
| 618 Modifiers modifiers = field.modifiers; | 597 Modifiers modifiers = field.modifiers; |
| 619 bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); | 598 bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); |
| 620 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { | 599 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { |
| 621 // If no setter is ever used for this field it is only initialized in the | 600 // If no setter is ever used for this field it is only initialized in the |
| 622 // initializer list. | 601 // initializer list. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 638 } | 617 } |
| 639 } | 618 } |
| 640 if (type != null) { | 619 if (type != null) { |
| 641 result.instructionType = type; | 620 result.instructionType = type; |
| 642 } | 621 } |
| 643 } | 622 } |
| 644 return result; | 623 return result; |
| 645 } | 624 } |
| 646 | 625 |
| 647 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 626 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 648 if (node.isInterceptorCall) return handleInterceptorCall(node); | 627 if (node.isCallOnInterceptor) return handleInterceptorCall(node); |
| 649 | 628 |
| 650 Element field = | 629 Element field = |
| 651 findConcreteFieldForDynamicAccess(node.receiver, node.selector); | 630 findConcreteFieldForDynamicAccess(node.receiver, node.selector); |
| 652 if (field == null || !field.isAssignable()) return node; | 631 if (field == null || !field.isAssignable()) return node; |
| 653 HInstruction value = node.inputs[1]; | 632 // Use [:node.inputs.last:] in case the call follows the |
| 633 // interceptor calling convention, but is not a call on an |
| 634 // interceptor. |
| 635 HInstruction value = node.inputs.last; |
| 654 if (compiler.enableTypeAssertions) { | 636 if (compiler.enableTypeAssertions) { |
| 655 HInstruction other = value.convertType( | 637 HInstruction other = value.convertType( |
| 656 compiler, | 638 compiler, |
| 657 field.computeType(compiler), | 639 field.computeType(compiler), |
| 658 HTypeConversion.CHECKED_MODE_CHECK); | 640 HTypeConversion.CHECKED_MODE_CHECK); |
| 659 if (other != value) { | 641 if (other != value) { |
| 660 node.block.addBefore(node, other); | 642 node.block.addBefore(node, other); |
| 661 value = other; | 643 value = other; |
| 662 } | 644 } |
| 663 } | 645 } |
| 664 return new HFieldSet(field, node.inputs[0], value); | 646 return new HFieldSet(field, node.inputs[0], value); |
| 665 } | 647 } |
| 666 | 648 |
| 667 HInstruction visitStringConcat(HStringConcat node) { | 649 HInstruction visitStringConcat(HStringConcat node) { |
| 668 DartString folded = const LiteralDartString(""); | 650 DartString folded = const LiteralDartString(""); |
| 669 for (int i = 0; i < node.inputs.length; i++) { | 651 for (int i = 0; i < node.inputs.length; i++) { |
| 670 HInstruction part = node.inputs[i]; | 652 HInstruction part = node.inputs[i]; |
| 671 if (!part.isConstant()) return node; | 653 if (!part.isConstant()) return node; |
| 672 HConstant constant = part; | 654 HConstant constant = part; |
| 673 if (!constant.constant.isPrimitive()) return node; | 655 if (!constant.constant.isPrimitive()) return node; |
| 674 PrimitiveConstant primitive = constant.constant; | 656 PrimitiveConstant primitive = constant.constant; |
| 675 folded = new DartString.concat(folded, primitive.toDartString()); | 657 folded = new DartString.concat(folded, primitive.toDartString()); |
| 676 } | 658 } |
| 677 return graph.addConstant(constantSystem.createString(folded, node.node)); | 659 return graph.addConstant(constantSystem.createString(folded, node.node)); |
| 678 } | 660 } |
| 679 | 661 |
| 680 HInstruction visitInterceptor(HInterceptor node) { | 662 HInstruction visitInterceptor(HInterceptor node) { |
| 681 if (node.isConstant()) return node; | 663 if (node.isConstant()) return node; |
| 664 // If the intercepted object does not need to be intercepted, just |
| 665 // return the object (the [:getInterceptor:] method would have |
| 666 // returned the object). |
| 667 HType type = node.receiver.instructionType; |
| 668 if (!type.canBePrimitive(compiler)) { |
| 669 print('IN HERE BECAUSE OF $type'); |
| 670 if (!(type.canBeNull() |
| 671 && node.interceptedClasses.contains(compiler.objectClass))) { |
| 672 return node.receiver; |
| 673 } |
| 674 } |
| 682 HInstruction constant = tryComputeConstantInterceptor( | 675 HInstruction constant = tryComputeConstantInterceptor( |
| 683 node.inputs[0], node.interceptedClasses); | 676 node.inputs[0], node.interceptedClasses); |
| 684 if (constant == null) return node; | 677 if (constant == null) return node; |
| 678 |
| 685 return constant; | 679 return constant; |
| 686 } | 680 } |
| 687 | 681 |
| 688 HInstruction tryComputeConstantInterceptor(HInstruction input, | 682 HInstruction tryComputeConstantInterceptor(HInstruction input, |
| 689 Set<ClassElement> intercepted) { | 683 Set<ClassElement> intercepted) { |
| 690 HType type = input.instructionType; | 684 HType type = input.instructionType; |
| 691 ClassElement constantInterceptor; | 685 ClassElement constantInterceptor; |
| 692 if (type.isInteger()) { | 686 if (type.isInteger()) { |
| 693 constantInterceptor = backend.jsIntClass; | 687 constantInterceptor = backend.jsIntClass; |
| 694 } else if (type.isDouble()) { | 688 } else if (type.isDouble()) { |
| (...skipping 840 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1535 HBasicBlock block = user.block; | 1529 HBasicBlock block = user.block; |
| 1536 block.addAfter(user, interceptor); | 1530 block.addAfter(user, interceptor); |
| 1537 block.rewrite(user, interceptor); | 1531 block.rewrite(user, interceptor); |
| 1538 block.remove(user); | 1532 block.remove(user); |
| 1539 | 1533 |
| 1540 // The interceptor will be removed in the dead code elimination | 1534 // The interceptor will be removed in the dead code elimination |
| 1541 // phase. Note that removing it here would not work because of how | 1535 // phase. Note that removing it here would not work because of how |
| 1542 // the [visitBasicBlock] is implemented. | 1536 // the [visitBasicBlock] is implemented. |
| 1543 } | 1537 } |
| 1544 } | 1538 } |
| OLD | NEW |