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 |