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 |