| Index: pkg/compiler/lib/src/ssa/optimize.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
|
| index c5286677eddfc8d146f1d6588de4c43166f1274f..0703f1c44f3927a5d3d6835f6ab71060990b94de 100644
|
| --- a/pkg/compiler/lib/src/ssa/optimize.dart
|
| +++ b/pkg/compiler/lib/src/ssa/optimize.dart
|
| @@ -8,7 +8,7 @@ import '../common/tasks.dart' show CompilerTask;
|
| import '../compiler.dart' show Compiler;
|
| import '../constants/constant_system.dart';
|
| import '../constants/values.dart';
|
| -import '../core_types.dart' show CoreClasses;
|
| +import '../core_types.dart' show CommonElements, CoreClasses;
|
| import '../dart_types.dart';
|
| import '../elements/elements.dart';
|
| import '../js/js.dart' as js;
|
| @@ -139,10 +139,10 @@ bool isFixedLength(mask, Compiler compiler) {
|
| return true;
|
| }
|
| // TODO(sra): Recognize any combination of fixed length indexables.
|
| - if (mask.containsOnly(backend.helpers.jsFixedArrayClass) ||
|
| - mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) ||
|
| + if (mask.containsOnly(closedWorld.backendClasses.fixedListImplementation) ||
|
| + mask.containsOnly(closedWorld.backendClasses.constListImplementation) ||
|
| mask.containsOnlyString(closedWorld) ||
|
| - backend.isTypedArray(mask)) {
|
| + closedWorld.commonMasks.isTypedArray(mask)) {
|
| return true;
|
| }
|
| return false;
|
| @@ -170,12 +170,15 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| SsaInstructionSimplifier(
|
| this.constantSystem, this.backend, this.optimizer, this.registry);
|
|
|
| - CoreClasses get coreClasses => compiler.coreClasses;
|
| -
|
| ClosedWorld get closedWorld => compiler.closedWorld;
|
|
|
| + CommonElements get commonElements => closedWorld.commonElements;
|
| +
|
| BackendHelpers get helpers => backend.helpers;
|
|
|
| + GlobalTypeInferenceResults get globalInferenceResults =>
|
| + compiler.globalInference.results;
|
| +
|
| void visitGraph(HGraph visitee) {
|
| graph = visitee;
|
| visitDominatorTree(visitee);
|
| @@ -447,9 +450,9 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| if (folded != node) return folded;
|
| }
|
|
|
| - TypeMask receiverType = node.getDartReceiver(compiler).instructionType;
|
| + TypeMask receiverType = node.getDartReceiver(closedWorld).instructionType;
|
| Element element =
|
| - compiler.closedWorld.locateSingleElement(node.selector, receiverType);
|
| + closedWorld.locateSingleElement(node.selector, receiverType);
|
| // TODO(ngeoffray): Also fold if it's a getter or variable.
|
| if (element != null &&
|
| element.isFunction
|
| @@ -482,9 +485,10 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| element.isField &&
|
| element.name == node.selector.name) {
|
| FieldElement field = element;
|
| - if (!backend.isNative(field) && !node.isCallOnInterceptor(compiler)) {
|
| - HInstruction receiver = node.getDartReceiver(compiler);
|
| - TypeMask type = TypeMaskFactory.inferredTypeForElement(field, compiler);
|
| + if (!backend.isNative(field) && !node.isCallOnInterceptor(closedWorld)) {
|
| + HInstruction receiver = node.getDartReceiver(closedWorld);
|
| + TypeMask type = TypeMaskFactory.inferredTypeForElement(
|
| + field, globalInferenceResults);
|
| HInstruction load = new HFieldGet(field, receiver, type);
|
| node.block.addBefore(node, load);
|
| Selector callSelector = new Selector.callClosureFrom(node.selector);
|
| @@ -554,7 +558,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| native.NativeBehavior nativeBehavior =
|
| backend.getNativeMethodBehavior(method);
|
| TypeMask returnType =
|
| - TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler);
|
| + TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld);
|
| HInvokeDynamicMethod result =
|
| new HInvokeDynamicMethod(node.selector, node.mask, inputs, returnType);
|
| result.element = method;
|
| @@ -732,7 +736,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| return node;
|
| } else if (type.isTypedef) {
|
| return node;
|
| - } else if (element == coreClasses.functionClass) {
|
| + } else if (element == commonElements.functionClass) {
|
| return node;
|
| }
|
|
|
| @@ -742,11 +746,11 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
|
|
| HInstruction expression = node.expression;
|
| if (expression.isInteger(closedWorld)) {
|
| - if (element == coreClasses.intClass ||
|
| - element == coreClasses.numClass ||
|
| - Elements.isNumberOrStringSupertype(element, compiler)) {
|
| + if (element == commonElements.intClass ||
|
| + element == commonElements.numClass ||
|
| + Elements.isNumberOrStringSupertype(element, commonElements)) {
|
| return graph.addConstantBool(true, compiler);
|
| - } else if (element == coreClasses.doubleClass) {
|
| + } else if (element == commonElements.doubleClass) {
|
| // We let the JS semantics decide for that check. Currently
|
| // the code we emit will always return true.
|
| return node;
|
| @@ -754,11 +758,11 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| return graph.addConstantBool(false, compiler);
|
| }
|
| } else if (expression.isDouble(closedWorld)) {
|
| - if (element == coreClasses.doubleClass ||
|
| - element == coreClasses.numClass ||
|
| - Elements.isNumberOrStringSupertype(element, compiler)) {
|
| + if (element == commonElements.doubleClass ||
|
| + element == commonElements.numClass ||
|
| + Elements.isNumberOrStringSupertype(element, commonElements)) {
|
| return graph.addConstantBool(true, compiler);
|
| - } else if (element == coreClasses.intClass) {
|
| + } else if (element == commonElements.intClass) {
|
| // We let the JS semantics decide for that check. Currently
|
| // the code we emit will return true for a double that can be
|
| // represented as a 31-bit integer and for -0.0.
|
| @@ -767,14 +771,14 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| return graph.addConstantBool(false, compiler);
|
| }
|
| } else if (expression.isNumber(closedWorld)) {
|
| - if (element == coreClasses.numClass) {
|
| + if (element == commonElements.numClass) {
|
| return graph.addConstantBool(true, compiler);
|
| } else {
|
| // We cannot just return false, because the expression may be of
|
| // type int or double.
|
| }
|
| } else if (expression.canBePrimitiveNumber(closedWorld) &&
|
| - element == coreClasses.intClass) {
|
| + element == commonElements.intClass) {
|
| // We let the JS semantics decide for that check.
|
| return node;
|
| // We need the [:hasTypeArguments:] check because we don't have
|
| @@ -784,7 +788,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| } else if (!RuntimeTypes.hasTypeArguments(type)) {
|
| TypeMask expressionMask = expression.instructionType;
|
| assert(TypeMask.assertIsNormalized(expressionMask, closedWorld));
|
| - TypeMask typeMask = (element == coreClasses.nullClass)
|
| + TypeMask typeMask = (element == commonElements.nullClass)
|
| ? new TypeMask.subtype(element, closedWorld)
|
| : new TypeMask.nonNullSubtype(element, closedWorld);
|
| if (expressionMask.union(typeMask, closedWorld) == typeMask) {
|
| @@ -845,7 +849,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| FieldElement findConcreteFieldForDynamicAccess(
|
| HInstruction receiver, Selector selector) {
|
| TypeMask receiverType = receiver.instructionType;
|
| - return compiler.closedWorld.locateSingleField(selector, receiverType);
|
| + return closedWorld.locateSingleField(selector, receiverType);
|
| }
|
|
|
| HInstruction visitFieldGet(HFieldGet node) {
|
| @@ -916,7 +920,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| HInstruction folded = handleInterceptedCall(node);
|
| if (folded != node) return folded;
|
| }
|
| - HInstruction receiver = node.getDartReceiver(compiler);
|
| + HInstruction receiver = node.getDartReceiver(closedWorld);
|
| FieldElement field =
|
| findConcreteFieldForDynamicAccess(receiver, node.selector);
|
| if (field != null) return directFieldGet(receiver, field);
|
| @@ -943,9 +947,10 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| TypeMask type;
|
| if (backend.isNative(field.enclosingClass)) {
|
| type = TypeMaskFactory.fromNativeBehavior(
|
| - backend.getNativeFieldLoadBehavior(field), compiler);
|
| + backend.getNativeFieldLoadBehavior(field), closedWorld);
|
| } else {
|
| - type = TypeMaskFactory.inferredTypeForElement(field, compiler);
|
| + type =
|
| + TypeMaskFactory.inferredTypeForElement(field, globalInferenceResults);
|
| }
|
|
|
| return new HFieldGet(field, receiver, type, isAssignable: isAssignable);
|
| @@ -957,7 +962,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| if (folded != node) return folded;
|
| }
|
|
|
| - HInstruction receiver = node.getDartReceiver(compiler);
|
| + HInstruction receiver = node.getDartReceiver(closedWorld);
|
| FieldElement field =
|
| findConcreteFieldForDynamicAccess(receiver, node.selector);
|
| if (field == null || !field.isAssignable) return node;
|
| @@ -1094,7 +1099,7 @@ class SsaInstructionSimplifier extends HBaseVisitor
|
| if (input.canBeNull()) return null;
|
| Selector selector = Selectors.toString_;
|
| TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector(
|
| - selector, input.instructionType, compiler);
|
| + selector, input.instructionType, globalInferenceResults);
|
| if (!toStringType.containsOnlyString(closedWorld)) return null;
|
| // All intercepted classes extend `Interceptor`, so if the receiver can't
|
| // be a class extending `Interceptor` then it can be called directly.
|
| @@ -1437,10 +1442,10 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
|
| /// effects after [instruction], throws [NoSuchMethodError] on the
|
| /// same receiver of [instruction].
|
| bool hasFollowingThrowingNSM(HInstruction instruction) {
|
| - HInstruction receiver = instruction.getDartReceiver(compiler);
|
| + HInstruction receiver = instruction.getDartReceiver(closedWorld);
|
| HInstruction current = instruction.next;
|
| do {
|
| - if ((current.getDartReceiver(compiler) == receiver) &&
|
| + if ((current.getDartReceiver(closedWorld) == receiver) &&
|
| current.canThrow()) {
|
| return true;
|
| }
|
| @@ -1484,9 +1489,9 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
|
| if (use is HFieldSet) {
|
| // The use must be the receiver. Even if the use is also the argument,
|
| // i.e. a.x = a, the store is still dead if all other uses are dead.
|
| - if (use.getDartReceiver(compiler) == instruction) return true;
|
| + if (use.getDartReceiver(closedWorld) == instruction) return true;
|
| } else if (use is HFieldGet) {
|
| - assert(use.getDartReceiver(compiler) == instruction);
|
| + assert(use.getDartReceiver(closedWorld) == instruction);
|
| if (isDeadCode(use)) return true;
|
| }
|
| return false;
|
| @@ -1500,7 +1505,7 @@ class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
|
|
|
| bool isTrivialDeadStore(HInstruction instruction) {
|
| return instruction is HFieldSet &&
|
| - isTrivialDeadStoreReceiver(instruction.getDartReceiver(compiler));
|
| + isTrivialDeadStoreReceiver(instruction.getDartReceiver(closedWorld));
|
| }
|
|
|
| bool isDeadCode(HInstruction instruction) {
|
| @@ -2229,6 +2234,8 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
|
|
|
| SsaLoadElimination(this.compiler);
|
|
|
| + ClosedWorld get closedWorld => compiler.closedWorld;
|
| +
|
| void visitGraph(HGraph graph) {
|
| memories = new List<MemorySet>(graph.blocks.length);
|
| List<HBasicBlock> blocks = graph.blocks;
|
| @@ -2249,7 +2256,7 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
|
| void visitBasicBlock(HBasicBlock block) {
|
| if (block.predecessors.length == 0) {
|
| // Entry block.
|
| - memorySet = new MemorySet(compiler);
|
| + memorySet = new MemorySet(closedWorld);
|
| } else if (block.predecessors.length == 1 &&
|
| block.predecessors[0].successors.length == 1) {
|
| // No need to clone, there is no other successor for
|
| @@ -2283,7 +2290,7 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
|
| void visitFieldGet(HFieldGet instruction) {
|
| if (instruction.isNullCheck) return;
|
| MemberElement element = instruction.element;
|
| - HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck();
|
| + HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck();
|
| HInstruction existing = memorySet.lookupFieldValue(element, receiver);
|
| if (existing != null) {
|
| instruction.block.rewriteWithBetterUser(instruction, existing);
|
| @@ -2294,7 +2301,7 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
|
| }
|
|
|
| void visitFieldSet(HFieldSet instruction) {
|
| - HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck();
|
| + HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck();
|
| memorySet.registerFieldValueUpdate(
|
| instruction.element, receiver, instruction.inputs.last);
|
| }
|
| @@ -2434,7 +2441,7 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
|
| * refinements to help further optimizations.
|
| */
|
| class MemorySet {
|
| - final Compiler compiler;
|
| + final ClosedWorld closedWorld;
|
|
|
| /**
|
| * Maps a field to a map of receiver to value.
|
| @@ -2453,9 +2460,7 @@ class MemorySet {
|
| */
|
| final Setlet<HInstruction> nonEscapingReceivers = new Setlet<HInstruction>();
|
|
|
| - MemorySet(this.compiler);
|
| -
|
| - JavaScriptBackend get backend => compiler.backend;
|
| + MemorySet(this.closedWorld);
|
|
|
| /**
|
| * Returns whether [first] and [second] always alias to the same object.
|
| @@ -2475,11 +2480,11 @@ class MemorySet {
|
| // Typed arrays of different types might have a shared buffer.
|
| if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true;
|
| return !first.instructionType
|
| - .isDisjoint(second.instructionType, compiler.closedWorld);
|
| + .isDisjoint(second.instructionType, closedWorld);
|
| }
|
|
|
| bool isFinal(Element element) {
|
| - return compiler.closedWorld.fieldNeverChanges(element);
|
| + return closedWorld.fieldNeverChanges(element);
|
| }
|
|
|
| bool isConcrete(HInstruction instruction) {
|
| @@ -2489,8 +2494,7 @@ class MemorySet {
|
| }
|
|
|
| bool couldBeTypedArray(HInstruction receiver) {
|
| - JavaScriptBackend backend = compiler.backend;
|
| - return backend.couldBeTypedArray(receiver.instructionType);
|
| + return closedWorld.commonMasks.couldBeTypedArray(receiver.instructionType);
|
| }
|
|
|
| /**
|
| @@ -2513,7 +2517,7 @@ class MemorySet {
|
| void registerFieldValueUpdate(
|
| MemberElement element, HInstruction receiver, HInstruction value) {
|
| assert(receiver == null || receiver == receiver.nonCheck());
|
| - if (backend.isNative(element)) {
|
| + if (closedWorld.backendClasses.isNative(element)) {
|
| return; // TODO(14955): Remove this restriction?
|
| }
|
| // [value] is being set in some place in memory, we remove it from
|
| @@ -2533,7 +2537,7 @@ class MemorySet {
|
| void registerFieldValue(
|
| MemberElement element, HInstruction receiver, HInstruction value) {
|
| assert(receiver == null || receiver == receiver.nonCheck());
|
| - if (backend.isNative(element)) {
|
| + if (closedWorld.backendClasses.isNative(element)) {
|
| return; // TODO(14955): Remove this restriction?
|
| }
|
| Map<HInstruction, HInstruction> map =
|
| @@ -2643,8 +2647,8 @@ class MemorySet {
|
| HBasicBlock block, int predecessorIndex) {
|
| if (first == null || second == null) return null;
|
| if (first == second) return first;
|
| - TypeMask phiType = second.instructionType
|
| - .union(first.instructionType, compiler.closedWorld);
|
| + TypeMask phiType =
|
| + second.instructionType.union(first.instructionType, closedWorld);
|
| if (first is HPhi && first.block == block) {
|
| HPhi phi = first;
|
| phi.addInput(second);
|
| @@ -2668,7 +2672,7 @@ class MemorySet {
|
| */
|
| MemorySet intersectionFor(
|
| MemorySet other, HBasicBlock block, int predecessorIndex) {
|
| - MemorySet result = new MemorySet(compiler);
|
| + MemorySet result = new MemorySet(closedWorld);
|
| if (other == null) {
|
| // This is the first visit to a loop header ([other] is `null` because we
|
| // have not visited the back edge). Copy the nonEscapingReceivers that are
|
| @@ -2733,7 +2737,7 @@ class MemorySet {
|
| * Returns a copy of [this].
|
| */
|
| MemorySet clone() {
|
| - MemorySet result = new MemorySet(compiler);
|
| + MemorySet result = new MemorySet(closedWorld);
|
|
|
| fieldValues.forEach((element, values) {
|
| result.fieldValues[element] =
|
|
|