| OLD | NEW |
| (Empty) |
| 1 library dart2js.cps_ir.update_refinements; | |
| 2 | |
| 3 import '../world.dart'; | |
| 4 import 'cps_ir_nodes.dart'; | |
| 5 import 'optimizers.dart' show Pass; | |
| 6 import 'type_mask_system.dart'; | |
| 7 | |
| 8 /// Updates all references to use the most refined version in scope. | |
| 9 /// | |
| 10 /// [GVN] and [RedundantJoinElimination], and possibly other passes, can create | |
| 11 /// references that don't use the best refinement in scope. This pass improves | |
| 12 /// the refinement information. | |
| 13 /// | |
| 14 // | |
| 15 // TODO(asgerf): Could be done during GVN for another adjacent pass. | |
| 16 // It is easier to measure performance and rearrange passes when it has its | |
| 17 // own pass, but we can merge it with an adjacent pass later. | |
| 18 // | |
| 19 class UpdateRefinements extends TrampolineRecursiveVisitor implements Pass { | |
| 20 String get passName => 'Update refinements'; | |
| 21 | |
| 22 final TypeMaskSystem typeSystem; | |
| 23 World get classWorld => typeSystem.classWorld; | |
| 24 | |
| 25 Map<Primitive, Primitive> refinementFor = <Primitive, Primitive>{}; | |
| 26 | |
| 27 UpdateRefinements(this.typeSystem); | |
| 28 | |
| 29 void rewrite(FunctionDefinition node) { | |
| 30 visit(node); | |
| 31 } | |
| 32 | |
| 33 Expression traverseLetPrim(LetPrim node) { | |
| 34 Expression next = node.body; | |
| 35 visit(node.primitive); | |
| 36 return next; | |
| 37 } | |
| 38 | |
| 39 visitReceiverCheck(ReceiverCheck node) { | |
| 40 if (refine(node.valueRef)) { | |
| 41 // Update the type if the input has changed. | |
| 42 Primitive value = node.value; | |
| 43 if (value.type.needsNoSuchMethodHandling(node.selector, classWorld)) { | |
| 44 node.type = typeSystem.receiverTypeFor(node.selector, value.type); | |
| 45 } else { | |
| 46 // Check is no longer needed. | |
| 47 node | |
| 48 ..replaceUsesWith(value) | |
| 49 ..destroy(); | |
| 50 LetPrim letPrim = node.parent; | |
| 51 letPrim.remove(); | |
| 52 return; | |
| 53 } | |
| 54 } | |
| 55 // Use the ReceiverCheck as a refinement. | |
| 56 Primitive value = node.effectiveDefinition; | |
| 57 Primitive old = refinementFor[value]; | |
| 58 refinementFor[value] = node; | |
| 59 pushAction(() { | |
| 60 refinementFor[value] = old; | |
| 61 }); | |
| 62 } | |
| 63 | |
| 64 visitRefinement(Refinement node) { | |
| 65 if (refine(node.value)) { | |
| 66 // Update the type if the input has changed. | |
| 67 node.type = | |
| 68 typeSystem.intersection(node.value.definition.type, node.refineType); | |
| 69 } | |
| 70 Primitive value = node.effectiveDefinition; | |
| 71 Primitive old = refinementFor[value]; | |
| 72 refinementFor[value] = node; | |
| 73 pushAction(() { | |
| 74 refinementFor[value] = old; | |
| 75 }); | |
| 76 } | |
| 77 | |
| 78 visitBoundsCheck(BoundsCheck node) { | |
| 79 super.visitBoundsCheck(node); | |
| 80 if (node.hasIntegerCheck && typeSystem.isDefinitelyInt(node.index.type)) { | |
| 81 node.checks &= ~BoundsCheck.INTEGER; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 processReference(Reference ref) { | |
| 86 refine(ref); | |
| 87 } | |
| 88 | |
| 89 bool refine(Reference ref) { | |
| 90 Definition def = ref.definition; | |
| 91 if (def is Primitive) { | |
| 92 Primitive refinement = refinementFor[def.effectiveDefinition]; | |
| 93 if (refinement != null && refinement != ref.definition) { | |
| 94 ref.changeTo(refinement); | |
| 95 return true; | |
| 96 } | |
| 97 } | |
| 98 return false; | |
| 99 } | |
| 100 } | |
| OLD | NEW |