blob: 5ce47a2d150c1c1cb729a9d5a42b1cb3a1731e43 [file] [log] [blame]
library dart2js.cps_ir.update_refinements;
import 'cps_ir_nodes.dart';
import 'optimizers.dart' show Pass;
import 'type_mask_system.dart';
import '../world.dart';
/// Updates all references to use the most refined version in scope.
///
/// [GVN] and [RedundantJoinElimination], and possibly other passes, can create
/// references that don't use the best refinement in scope. This pass improves
/// the refinement information.
///
//
// TODO(asgerf): Could be done during GVN for another adjacent pass.
// It is easier to measure performance and rearrange passes when it has its
// own pass, but we can merge it with an adjacent pass later.
//
class UpdateRefinements extends TrampolineRecursiveVisitor implements Pass {
String get passName => 'Update refinements';
final TypeMaskSystem typeSystem;
World get classWorld => typeSystem.classWorld;
Map<Primitive, Primitive> refinementFor = <Primitive, Primitive>{};
UpdateRefinements(this.typeSystem);
void rewrite(FunctionDefinition node) {
visit(node);
}
Expression traverseLetPrim(LetPrim node) {
Expression next = node.body;
visit(node.primitive);
return next;
}
visitReceiverCheck(ReceiverCheck node) {
if (refine(node.value)) {
// Update the type if the input has changed.
Primitive value = node.value.definition;
if (value.type.needsNoSuchMethodHandling(node.selector, classWorld)) {
node.type = typeSystem.receiverTypeFor(node.selector, value.type);
} else {
// Check is no longer needed.
node..replaceUsesWith(value)..destroy();
LetPrim letPrim = node.parent;
letPrim.remove();
return;
}
}
// Use the ReceiverCheck as a refinement.
Primitive value = node.effectiveDefinition;
Primitive old = refinementFor[value];
refinementFor[value] = node;
pushAction(() {
refinementFor[value] = old;
});
}
visitRefinement(Refinement node) {
if (refine(node.value)) {
// Update the type if the input has changed.
node.type = typeSystem.intersection(node.value.definition.type,
node.refineType);
}
Primitive value = node.effectiveDefinition;
Primitive old = refinementFor[value];
refinementFor[value] = node;
pushAction(() {
refinementFor[value] = old;
});
}
visitBoundsCheck(BoundsCheck node) {
super.visitBoundsCheck(node);
if (node.hasIntegerCheck &&
typeSystem.isDefinitelyInt(node.index.definition.type)) {
node.checks &= ~BoundsCheck.INTEGER;
}
}
processReference(Reference ref) {
refine(ref);
}
bool refine(Reference ref) {
Definition def = ref.definition;
if (def is Primitive) {
Primitive refinement = refinementFor[def.effectiveDefinition];
if (refinement != null && refinement != ref.definition) {
ref.changeTo(refinement);
return true;
}
}
return false;
}
}