| 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 import '../closure.dart'; | 5 import '../closure.dart'; |
| 6 import '../common.dart'; | 6 import '../common.dart'; |
| 7 import '../compiler.dart' show Compiler; | 7 import '../compiler.dart' show Compiler; |
| 8 import '../constants/constant_system.dart'; | 8 import '../constants/constant_system.dart'; |
| 9 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| 11 import '../elements/elements.dart'; | 11 import '../elements/elements.dart' |
| 12 show Entity, JumpTarget, LabelDefinition, Local; |
| 13 import '../elements/entities.dart'; |
| 12 import '../io/source_information.dart'; | 14 import '../io/source_information.dart'; |
| 13 import '../js/js.dart' as js; | 15 import '../js/js.dart' as js; |
| 14 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 16 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 15 import '../js_backend/js_backend.dart'; | 17 import '../js_backend/js_backend.dart'; |
| 16 import '../native/native.dart' as native; | 18 import '../native/native.dart' as native; |
| 17 import '../tree/dartstring.dart' as ast; | 19 import '../tree/dartstring.dart' as ast; |
| 18 import '../types/constants.dart' show computeTypeMask; | 20 import '../types/constants.dart' show computeTypeMask; |
| 19 import '../types/types.dart'; | 21 import '../types/types.dart'; |
| 20 import '../universe/selector.dart' show Selector; | 22 import '../universe/selector.dart' show Selector; |
| 21 import '../universe/side_effects.dart' show SideEffects; | 23 import '../universe/side_effects.dart' show SideEffects; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 assert(instruction != list.first); | 149 assert(instruction != list.first); |
| 148 } | 150 } |
| 149 } | 151 } |
| 150 | 152 |
| 151 currentBlock = node; | 153 currentBlock = node; |
| 152 visitInstructionList(node); | 154 visitInstructionList(node); |
| 153 } | 155 } |
| 154 } | 156 } |
| 155 | 157 |
| 156 class HGraph { | 158 class HGraph { |
| 157 Element element; // Used for debug printing. | 159 // TODO(johnniwinther): Maybe this should be [MemberLike]. |
| 160 Entity element; // Used for debug printing. |
| 158 HBasicBlock entry; | 161 HBasicBlock entry; |
| 159 HBasicBlock exit; | 162 HBasicBlock exit; |
| 160 HThis thisInstruction; | 163 HThis thisInstruction; |
| 161 | 164 |
| 162 /// Receiver parameter, set for methods using interceptor calling convention. | 165 /// Receiver parameter, set for methods using interceptor calling convention. |
| 163 HParameterValue explicitReceiverParameter; | 166 HParameterValue explicitReceiverParameter; |
| 164 bool isRecursiveMethod = false; | 167 bool isRecursiveMethod = false; |
| 165 bool calledInLoop = false; | 168 bool calledInLoop = false; |
| 166 final List<HBasicBlock> blocks = <HBasicBlock>[]; | 169 final List<HBasicBlock> blocks = <HBasicBlock>[]; |
| 167 | 170 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 ..sourceInformation = sourceInformation; | 220 ..sourceInformation = sourceInformation; |
| 218 entry.addAtExit(result); | 221 entry.addAtExit(result); |
| 219 constants[constant] = result; | 222 constants[constant] = result; |
| 220 } else if (result.block == null) { | 223 } else if (result.block == null) { |
| 221 // The constant was not used anymore. | 224 // The constant was not used anymore. |
| 222 entry.addAtExit(result); | 225 entry.addAtExit(result); |
| 223 } | 226 } |
| 224 return result; | 227 return result; |
| 225 } | 228 } |
| 226 | 229 |
| 227 HConstant addDeferredConstant(ConstantValue constant, PrefixElement prefix, | 230 HConstant addDeferredConstant(ConstantValue constant, Entity prefix, |
| 228 SourceInformation sourceInformation, Compiler compiler) { | 231 SourceInformation sourceInformation, Compiler compiler) { |
| 229 // TODO(sigurdm,johnniwinter): These deferred constants should be created | 232 // TODO(sigurdm,johnniwinther): These deferred constants should be created |
| 230 // by the constant evaluator. | 233 // by the constant evaluator. |
| 231 ConstantValue wrapper = new DeferredConstantValue(constant, prefix); | 234 ConstantValue wrapper = new DeferredConstantValue(constant, prefix); |
| 232 compiler.deferredLoadTask.registerConstantDeferredUse(wrapper, prefix); | 235 compiler.deferredLoadTask.registerConstantDeferredUse(wrapper, prefix); |
| 233 return addConstant(wrapper, compiler, sourceInformation: sourceInformation); | 236 return addConstant(wrapper, compiler, sourceInformation: sourceInformation); |
| 234 } | 237 } |
| 235 | 238 |
| 236 HConstant addConstantInt(int i, Compiler compiler) { | 239 HConstant addConstantInt(int i, Compiler compiler) { |
| 237 return addConstant(compiler.backend.constantSystem.createInt(i), compiler); | 240 return addConstant(compiler.backend.constantSystem.createInt(i), compiler); |
| 238 } | 241 } |
| 239 | 242 |
| (...skipping 681 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 921 bool isValue() => instructionType.isValue; | 924 bool isValue() => instructionType.isValue; |
| 922 | 925 |
| 923 bool canBeNull() => instructionType.isNullable; | 926 bool canBeNull() => instructionType.isNullable; |
| 924 | 927 |
| 925 bool isNull() => instructionType.isNull; | 928 bool isNull() => instructionType.isNull; |
| 926 | 929 |
| 927 bool isConflicting() => instructionType.isEmpty; | 930 bool isConflicting() => instructionType.isEmpty; |
| 928 | 931 |
| 929 /// Returns `true` if [typeMask] contains [cls]. | 932 /// Returns `true` if [typeMask] contains [cls]. |
| 930 static bool containsType( | 933 static bool containsType( |
| 931 TypeMask typeMask, ClassElement cls, ClosedWorld closedWorld) { | 934 TypeMask typeMask, ClassEntity cls, ClosedWorld closedWorld) { |
| 932 return closedWorld.isInstantiated(cls) && | 935 return closedWorld.isInstantiated(cls) && |
| 933 typeMask.contains(cls, closedWorld); | 936 typeMask.contains(cls, closedWorld); |
| 934 } | 937 } |
| 935 | 938 |
| 936 /// Returns `true` if [typeMask] contains only [cls]. | 939 /// Returns `true` if [typeMask] contains only [cls]. |
| 937 static bool containsOnlyType( | 940 static bool containsOnlyType( |
| 938 TypeMask typeMask, ClassElement cls, ClosedWorld closedWorld) { | 941 TypeMask typeMask, ClassEntity cls, ClosedWorld closedWorld) { |
| 939 return closedWorld.isInstantiated(cls) && typeMask.containsOnly(cls); | 942 return closedWorld.isInstantiated(cls) && typeMask.containsOnly(cls); |
| 940 } | 943 } |
| 941 | 944 |
| 942 /// Returns `true` if [typeMask] is an instance of [cls]. | 945 /// Returns `true` if [typeMask] is an instance of [cls]. |
| 943 static bool isInstanceOf( | 946 static bool isInstanceOf( |
| 944 TypeMask typeMask, ClassElement cls, ClosedWorld closedWorld) { | 947 TypeMask typeMask, ClassEntity cls, ClosedWorld closedWorld) { |
| 945 return closedWorld.isImplemented(cls) && | 948 return closedWorld.isImplemented(cls) && |
| 946 typeMask.satisfies(cls, closedWorld); | 949 typeMask.satisfies(cls, closedWorld); |
| 947 } | 950 } |
| 948 | 951 |
| 949 bool canBePrimitive(Compiler compiler) { | 952 bool canBePrimitive(Compiler compiler) { |
| 950 return canBePrimitiveNumber(compiler) || | 953 return canBePrimitiveNumber(compiler) || |
| 951 canBePrimitiveArray(compiler) || | 954 canBePrimitiveArray(compiler) || |
| 952 canBePrimitiveBoolean(compiler) || | 955 canBePrimitiveBoolean(compiler) || |
| 953 canBePrimitiveString(compiler) || | 956 canBePrimitiveString(compiler) || |
| 954 isNull(); | 957 isNull(); |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 } | 1363 } |
| 1361 return false; | 1364 return false; |
| 1362 } | 1365 } |
| 1363 | 1366 |
| 1364 HInstruction convertType(Compiler compiler, DartType type, int kind) { | 1367 HInstruction convertType(Compiler compiler, DartType type, int kind) { |
| 1365 if (type == null) return this; | 1368 if (type == null) return this; |
| 1366 type = type.unaliased; | 1369 type = type.unaliased; |
| 1367 // Only the builder knows how to create [HTypeConversion] | 1370 // Only the builder knows how to create [HTypeConversion] |
| 1368 // instructions with generics. It has the generic type context | 1371 // instructions with generics. It has the generic type context |
| 1369 // available. | 1372 // available. |
| 1370 assert(type.kind != TypeKind.TYPE_VARIABLE); | 1373 assert(!type.isTypeVariable); |
| 1371 assert(type.treatAsRaw || type.isFunctionType); | 1374 assert(type.treatAsRaw || type.isFunctionType); |
| 1372 if (type.isDynamic) return this; | 1375 if (type.isDynamic) return this; |
| 1373 if (type.isObject) return this; | 1376 if (type.isObject) return this; |
| 1374 // The type element is either a class or the void element. | 1377 // The type element is either a class or the void element. |
| 1375 Element element = type.element; | |
| 1376 JavaScriptBackend backend = compiler.backend; | 1378 JavaScriptBackend backend = compiler.backend; |
| 1377 if (type.kind != TypeKind.INTERFACE) { | 1379 if (type.isVoid || type.isFunctionType) { |
| 1378 return new HTypeConversion(type, kind, backend.dynamicType, this); | 1380 return new HTypeConversion(type, kind, backend.dynamicType, this); |
| 1379 } else if (kind == HTypeConversion.BOOLEAN_CONVERSION_CHECK) { | 1381 } |
| 1382 assert(type.isInterfaceType); |
| 1383 if (kind == HTypeConversion.BOOLEAN_CONVERSION_CHECK) { |
| 1380 // Boolean conversion checks work on non-nullable booleans. | 1384 // Boolean conversion checks work on non-nullable booleans. |
| 1381 return new HTypeConversion(type, kind, backend.boolType, this); | 1385 return new HTypeConversion(type, kind, backend.boolType, this); |
| 1382 } else if (kind == HTypeConversion.CHECKED_MODE_CHECK && !type.treatAsRaw) { | 1386 } else if (kind == HTypeConversion.CHECKED_MODE_CHECK && !type.treatAsRaw) { |
| 1383 throw 'creating compound check to $type (this = ${this})'; | 1387 throw 'creating compound check to $type (this = ${this})'; |
| 1384 } else { | 1388 } else { |
| 1385 TypeMask subtype = | 1389 Entity cls = type.element; |
| 1386 new TypeMask.subtype(element.declaration, compiler.closedWorld); | 1390 TypeMask subtype = new TypeMask.subtype(cls, compiler.closedWorld); |
| 1387 return new HTypeConversion(type, kind, subtype, this); | 1391 return new HTypeConversion(type, kind, subtype, this); |
| 1388 } | 1392 } |
| 1389 } | 1393 } |
| 1390 | 1394 |
| 1391 /** | 1395 /** |
| 1392 * Return whether the instructions do not belong to a loop or | 1396 * Return whether the instructions do not belong to a loop or |
| 1393 * belong to the same loop. | 1397 * belong to the same loop. |
| 1394 */ | 1398 */ |
| 1395 bool hasSameLoopHeaderAs(HInstruction other) { | 1399 bool hasSameLoopHeaderAs(HInstruction other) { |
| 1396 return block.enclosingLoopHeader == other.block.enclosingLoopHeader; | 1400 return block.enclosingLoopHeader == other.block.enclosingLoopHeader; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1500 } | 1504 } |
| 1501 | 1505 |
| 1502 abstract class HControlFlow extends HInstruction { | 1506 abstract class HControlFlow extends HInstruction { |
| 1503 HControlFlow(inputs) : super(inputs, const TypeMask.nonNullEmpty()); | 1507 HControlFlow(inputs) : super(inputs, const TypeMask.nonNullEmpty()); |
| 1504 bool isControlFlow() => true; | 1508 bool isControlFlow() => true; |
| 1505 bool isJsStatement() => true; | 1509 bool isJsStatement() => true; |
| 1506 } | 1510 } |
| 1507 | 1511 |
| 1508 // Allocates and initializes an instance. | 1512 // Allocates and initializes an instance. |
| 1509 class HCreate extends HInstruction { | 1513 class HCreate extends HInstruction { |
| 1510 final ClassElement element; | 1514 final ClassEntity element; |
| 1511 | 1515 |
| 1512 /// Does this instruction have reified type information as the last input? | 1516 /// Does this instruction have reified type information as the last input? |
| 1513 final bool hasRtiInput; | 1517 final bool hasRtiInput; |
| 1514 | 1518 |
| 1515 /// If this field is not `null`, this call is from an inlined constructor and | 1519 /// If this field is not `null`, this call is from an inlined constructor and |
| 1516 /// we have to register the instantiated type in the code generator. The | 1520 /// we have to register the instantiated type in the code generator. The |
| 1517 /// [instructionType] of this node is not enough, because we also need the | 1521 /// [instructionType] of this node is not enough, because we also need the |
| 1518 /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations]. | 1522 /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations]. |
| 1519 List<DartType> instantiatedTypes; | 1523 List<DartType> instantiatedTypes; |
| 1520 | 1524 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1555 // calling convention, which adds the actual receiver as a | 1559 // calling convention, which adds the actual receiver as a |
| 1556 // parameter to the call. | 1560 // parameter to the call. |
| 1557 return (selector != null) && (inputs.length - 2 == selector.argumentCount); | 1561 return (selector != null) && (inputs.length - 2 == selector.argumentCount); |
| 1558 } | 1562 } |
| 1559 } | 1563 } |
| 1560 | 1564 |
| 1561 abstract class HInvokeDynamic extends HInvoke { | 1565 abstract class HInvokeDynamic extends HInvoke { |
| 1562 final InvokeDynamicSpecializer specializer; | 1566 final InvokeDynamicSpecializer specializer; |
| 1563 Selector selector; | 1567 Selector selector; |
| 1564 TypeMask mask; | 1568 TypeMask mask; |
| 1565 Element element; | 1569 MemberEntity element; |
| 1566 | 1570 |
| 1567 HInvokeDynamic(Selector selector, this.mask, this.element, | 1571 HInvokeDynamic(Selector selector, this.mask, this.element, |
| 1568 List<HInstruction> inputs, TypeMask type, | 1572 List<HInstruction> inputs, TypeMask type, |
| 1569 [bool isIntercepted = false]) | 1573 [bool isIntercepted = false]) |
| 1570 : super(inputs, type), | 1574 : super(inputs, type), |
| 1571 this.selector = selector, | 1575 this.selector = selector, |
| 1572 specializer = isIntercepted | 1576 specializer = isIntercepted |
| 1573 ? InvokeDynamicSpecializer.lookupSpecializer(selector) | 1577 ? InvokeDynamicSpecializer.lookupSpecializer(selector) |
| 1574 : const InvokeDynamicSpecializer(); | 1578 : const InvokeDynamicSpecializer(); |
| 1575 toString() => 'invoke dynamic: selector=$selector, mask=$mask'; | 1579 toString() => 'invoke dynamic: selector=$selector, mask=$mask'; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1608 HInvokeDynamicMethod(Selector selector, TypeMask mask, | 1612 HInvokeDynamicMethod(Selector selector, TypeMask mask, |
| 1609 List<HInstruction> inputs, TypeMask type, | 1613 List<HInstruction> inputs, TypeMask type, |
| 1610 [bool isIntercepted = false]) | 1614 [bool isIntercepted = false]) |
| 1611 : super(selector, mask, null, inputs, type, isIntercepted); | 1615 : super(selector, mask, null, inputs, type, isIntercepted); |
| 1612 | 1616 |
| 1613 String toString() => 'invoke dynamic method: selector=$selector, mask=$mask'; | 1617 String toString() => 'invoke dynamic method: selector=$selector, mask=$mask'; |
| 1614 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); | 1618 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); |
| 1615 } | 1619 } |
| 1616 | 1620 |
| 1617 abstract class HInvokeDynamicField extends HInvokeDynamic { | 1621 abstract class HInvokeDynamicField extends HInvokeDynamic { |
| 1618 HInvokeDynamicField(Selector selector, TypeMask mask, Element element, | 1622 HInvokeDynamicField(Selector selector, TypeMask mask, MemberEntity element, |
| 1619 List<HInstruction> inputs, TypeMask type) | 1623 List<HInstruction> inputs, TypeMask type) |
| 1620 : super(selector, mask, element, inputs, type); | 1624 : super(selector, mask, element, inputs, type); |
| 1621 toString() => 'invoke dynamic field: selector=$selector, mask=$mask'; | 1625 toString() => 'invoke dynamic field: selector=$selector, mask=$mask'; |
| 1622 } | 1626 } |
| 1623 | 1627 |
| 1624 class HInvokeDynamicGetter extends HInvokeDynamicField { | 1628 class HInvokeDynamicGetter extends HInvokeDynamicField { |
| 1625 HInvokeDynamicGetter(Selector selector, TypeMask mask, Element element, | 1629 HInvokeDynamicGetter(Selector selector, TypeMask mask, MemberEntity element, |
| 1626 List<HInstruction> inputs, TypeMask type) | 1630 List<HInstruction> inputs, TypeMask type) |
| 1627 : super(selector, mask, element, inputs, type); | 1631 : super(selector, mask, element, inputs, type); |
| 1628 toString() => 'invoke dynamic getter: selector=$selector, mask=$mask'; | 1632 toString() => 'invoke dynamic getter: selector=$selector, mask=$mask'; |
| 1629 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); | 1633 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); |
| 1630 | 1634 |
| 1631 bool get isTearOff => element != null && element.isFunction; | 1635 bool get isTearOff => element != null && element.isFunction; |
| 1632 | 1636 |
| 1633 // There might be an interceptor input, so `inputs.last` is the dart receiver. | 1637 // There might be an interceptor input, so `inputs.last` is the dart receiver. |
| 1634 bool canThrow() => isTearOff ? inputs.last.canBeNull() : super.canThrow(); | 1638 bool canThrow() => isTearOff ? inputs.last.canBeNull() : super.canThrow(); |
| 1635 } | 1639 } |
| 1636 | 1640 |
| 1637 class HInvokeDynamicSetter extends HInvokeDynamicField { | 1641 class HInvokeDynamicSetter extends HInvokeDynamicField { |
| 1638 HInvokeDynamicSetter(Selector selector, TypeMask mask, Element element, | 1642 HInvokeDynamicSetter(Selector selector, TypeMask mask, MemberEntity element, |
| 1639 List<HInstruction> inputs, TypeMask type) | 1643 List<HInstruction> inputs, TypeMask type) |
| 1640 : super(selector, mask, element, inputs, type); | 1644 : super(selector, mask, element, inputs, type); |
| 1641 toString() => 'invoke dynamic setter: selector=$selector, mask=$mask'; | 1645 toString() => 'invoke dynamic setter: selector=$selector, mask=$mask'; |
| 1642 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); | 1646 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); |
| 1643 } | 1647 } |
| 1644 | 1648 |
| 1645 class HInvokeStatic extends HInvoke { | 1649 class HInvokeStatic extends HInvoke { |
| 1646 final Element element; | 1650 final MemberEntity element; |
| 1647 | 1651 |
| 1648 final bool targetCanThrow; | 1652 final bool targetCanThrow; |
| 1649 | 1653 |
| 1650 bool canThrow() => targetCanThrow; | 1654 bool canThrow() => targetCanThrow; |
| 1651 | 1655 |
| 1652 /// If this instruction is a call to a constructor, [instantiatedTypes] | 1656 /// If this instruction is a call to a constructor, [instantiatedTypes] |
| 1653 /// contains the type(s) used in the (Dart) `New` expression(s). The | 1657 /// contains the type(s) used in the (Dart) `New` expression(s). The |
| 1654 /// [instructionType] of this node is not enough, because we also need the | 1658 /// [instructionType] of this node is not enough, because we also need the |
| 1655 /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations]. | 1659 /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations]. |
| 1656 List<DartType> instantiatedTypes; | 1660 List<DartType> instantiatedTypes; |
| 1657 | 1661 |
| 1658 /** The first input must be the target. */ | 1662 /** The first input must be the target. */ |
| 1659 HInvokeStatic(this.element, inputs, TypeMask type, | 1663 HInvokeStatic(this.element, inputs, TypeMask type, |
| 1660 {this.targetCanThrow: true}) | 1664 {this.targetCanThrow: true}) |
| 1661 : super(inputs, type); | 1665 : super(inputs, type); |
| 1662 | 1666 |
| 1663 toString() => 'invoke static: $element'; | 1667 toString() => 'invoke static: $element'; |
| 1664 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); | 1668 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); |
| 1665 int typeCode() => HInstruction.INVOKE_STATIC_TYPECODE; | 1669 int typeCode() => HInstruction.INVOKE_STATIC_TYPECODE; |
| 1666 } | 1670 } |
| 1667 | 1671 |
| 1668 class HInvokeSuper extends HInvokeStatic { | 1672 class HInvokeSuper extends HInvokeStatic { |
| 1669 /** The class where the call to super is being done. */ | 1673 /** The class where the call to super is being done. */ |
| 1670 final ClassElement caller; | 1674 final ClassEntity caller; |
| 1671 final bool isSetter; | 1675 final bool isSetter; |
| 1672 final Selector selector; | 1676 final Selector selector; |
| 1673 | 1677 |
| 1674 HInvokeSuper(Element element, this.caller, this.selector, inputs, type, | 1678 HInvokeSuper(MemberEntity element, this.caller, this.selector, inputs, type, |
| 1675 SourceInformation sourceInformation, | 1679 SourceInformation sourceInformation, |
| 1676 {this.isSetter}) | 1680 {this.isSetter}) |
| 1677 : super(element, inputs, type) { | 1681 : super(element, inputs, type) { |
| 1678 this.sourceInformation = sourceInformation; | 1682 this.sourceInformation = sourceInformation; |
| 1679 } | 1683 } |
| 1680 | 1684 |
| 1681 HInstruction get receiver => inputs[0]; | 1685 HInstruction get receiver => inputs[0]; |
| 1682 HInstruction getDartReceiver(Compiler compiler) { | 1686 HInstruction getDartReceiver(Compiler compiler) { |
| 1683 return isCallOnInterceptor(compiler) ? inputs[1] : inputs[0]; | 1687 return isCallOnInterceptor(compiler) ? inputs[1] : inputs[0]; |
| 1684 } | 1688 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1704 // The 'inputs' are | 1708 // The 'inputs' are |
| 1705 // [receiver, arg1, ..., argN] or | 1709 // [receiver, arg1, ..., argN] or |
| 1706 // [interceptor, receiver, arg1, ... argN]. | 1710 // [interceptor, receiver, arg1, ... argN]. |
| 1707 HInvokeConstructorBody(element, inputs, type) : super(element, inputs, type); | 1711 HInvokeConstructorBody(element, inputs, type) : super(element, inputs, type); |
| 1708 | 1712 |
| 1709 String toString() => 'invoke constructor body: ${element.name}'; | 1713 String toString() => 'invoke constructor body: ${element.name}'; |
| 1710 accept(HVisitor visitor) => visitor.visitInvokeConstructorBody(this); | 1714 accept(HVisitor visitor) => visitor.visitInvokeConstructorBody(this); |
| 1711 } | 1715 } |
| 1712 | 1716 |
| 1713 abstract class HFieldAccess extends HInstruction { | 1717 abstract class HFieldAccess extends HInstruction { |
| 1714 final Element element; | 1718 // TODO(johnniwinther): This should be a [FieldLike] but JSIndexable.length is |
| 1719 // encoded using a [HFieldGet]. |
| 1720 final MemberEntity element; |
| 1715 | 1721 |
| 1716 HFieldAccess(Element element, List<HInstruction> inputs, TypeMask type) | 1722 HFieldAccess(this.element, List<HInstruction> inputs, TypeMask type) |
| 1717 : this.element = element, | 1723 : super(inputs, type); |
| 1718 super(inputs, type); | |
| 1719 | 1724 |
| 1720 HInstruction get receiver => inputs[0]; | 1725 HInstruction get receiver => inputs[0]; |
| 1721 } | 1726 } |
| 1722 | 1727 |
| 1723 class HFieldGet extends HFieldAccess { | 1728 class HFieldGet extends HFieldAccess { |
| 1724 final bool isAssignable; | 1729 final bool isAssignable; |
| 1725 | 1730 |
| 1726 HFieldGet(Element element, HInstruction receiver, TypeMask type, | 1731 HFieldGet(MemberEntity element, HInstruction receiver, TypeMask type, |
| 1727 {bool isAssignable}) | 1732 {bool isAssignable}) |
| 1728 : this.isAssignable = | 1733 : this.isAssignable = |
| 1729 (isAssignable != null) ? isAssignable : element.isAssignable, | 1734 (isAssignable != null) ? isAssignable : element.isAssignable, |
| 1730 super(element, <HInstruction>[receiver], type) { | 1735 super(element, <HInstruction>[receiver], type) { |
| 1731 sideEffects.clearAllSideEffects(); | 1736 sideEffects.clearAllSideEffects(); |
| 1732 sideEffects.clearAllDependencies(); | 1737 sideEffects.clearAllDependencies(); |
| 1733 setUseGvn(); | 1738 setUseGvn(); |
| 1734 if (this.isAssignable) { | 1739 if (this.isAssignable) { |
| 1735 sideEffects.setDependsOnInstancePropertyStore(); | 1740 sideEffects.setDependsOnInstancePropertyStore(); |
| 1736 } | 1741 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1757 | 1762 |
| 1758 accept(HVisitor visitor) => visitor.visitFieldGet(this); | 1763 accept(HVisitor visitor) => visitor.visitFieldGet(this); |
| 1759 | 1764 |
| 1760 int typeCode() => HInstruction.FIELD_GET_TYPECODE; | 1765 int typeCode() => HInstruction.FIELD_GET_TYPECODE; |
| 1761 bool typeEquals(other) => other is HFieldGet; | 1766 bool typeEquals(other) => other is HFieldGet; |
| 1762 bool dataEquals(HFieldGet other) => element == other.element; | 1767 bool dataEquals(HFieldGet other) => element == other.element; |
| 1763 String toString() => "FieldGet $element"; | 1768 String toString() => "FieldGet $element"; |
| 1764 } | 1769 } |
| 1765 | 1770 |
| 1766 class HFieldSet extends HFieldAccess { | 1771 class HFieldSet extends HFieldAccess { |
| 1767 HFieldSet(Element element, HInstruction receiver, HInstruction value) | 1772 HFieldSet(MemberEntity element, HInstruction receiver, HInstruction value) |
| 1768 : super(element, <HInstruction>[receiver, value], | 1773 : super(element, <HInstruction>[receiver, value], |
| 1769 const TypeMask.nonNullEmpty()) { | 1774 const TypeMask.nonNullEmpty()) { |
| 1770 sideEffects.clearAllSideEffects(); | 1775 sideEffects.clearAllSideEffects(); |
| 1771 sideEffects.clearAllDependencies(); | 1776 sideEffects.clearAllDependencies(); |
| 1772 sideEffects.setChangesInstanceProperty(); | 1777 sideEffects.setChangesInstanceProperty(); |
| 1773 } | 1778 } |
| 1774 | 1779 |
| 1775 bool canThrow() => receiver.canBeNull(); | 1780 bool canThrow() => receiver.canBeNull(); |
| 1776 | 1781 |
| 1777 HInstruction getDartReceiver(Compiler compiler) => receiver; | 1782 HInstruction getDartReceiver(Compiler compiler) => receiver; |
| 1778 bool onlyThrowsNSM() => true; | 1783 bool onlyThrowsNSM() => true; |
| 1779 | 1784 |
| 1780 HInstruction get value => inputs[1]; | 1785 HInstruction get value => inputs[1]; |
| 1781 accept(HVisitor visitor) => visitor.visitFieldSet(this); | 1786 accept(HVisitor visitor) => visitor.visitFieldSet(this); |
| 1782 | 1787 |
| 1783 bool isJsStatement() => true; | 1788 bool isJsStatement() => true; |
| 1784 String toString() => "FieldSet $element"; | 1789 String toString() => "FieldSet $element"; |
| 1785 } | 1790 } |
| 1786 | 1791 |
| 1787 /** | 1792 /** |
| 1788 * HReadModifyWrite is a late stage instruction for a field (property) update | 1793 * HReadModifyWrite is a late stage instruction for a field (property) update |
| 1789 * via an assignment operation or pre- or post-increment. | 1794 * via an assignment operation or pre- or post-increment. |
| 1790 */ | 1795 */ |
| 1791 class HReadModifyWrite extends HLateInstruction { | 1796 class HReadModifyWrite extends HLateInstruction { |
| 1792 static const ASSIGN_OP = 0; | 1797 static const ASSIGN_OP = 0; |
| 1793 static const PRE_OP = 1; | 1798 static const PRE_OP = 1; |
| 1794 static const POST_OP = 2; | 1799 static const POST_OP = 2; |
| 1795 final Element element; | 1800 final FieldEntity element; |
| 1796 final String jsOp; | 1801 final String jsOp; |
| 1797 final int opKind; | 1802 final int opKind; |
| 1798 | 1803 |
| 1799 HReadModifyWrite._(Element this.element, this.jsOp, this.opKind, | 1804 HReadModifyWrite._(this.element, this.jsOp, this.opKind, |
| 1800 List<HInstruction> inputs, TypeMask type) | 1805 List<HInstruction> inputs, TypeMask type) |
| 1801 : super(inputs, type) { | 1806 : super(inputs, type) { |
| 1802 sideEffects.clearAllSideEffects(); | 1807 sideEffects.clearAllSideEffects(); |
| 1803 sideEffects.clearAllDependencies(); | 1808 sideEffects.clearAllDependencies(); |
| 1804 sideEffects.setChangesInstanceProperty(); | 1809 sideEffects.setChangesInstanceProperty(); |
| 1805 sideEffects.setDependsOnInstancePropertyStore(); | 1810 sideEffects.setDependsOnInstancePropertyStore(); |
| 1806 } | 1811 } |
| 1807 | 1812 |
| 1808 HReadModifyWrite.assignOp(Element element, String jsOp, HInstruction receiver, | 1813 HReadModifyWrite.assignOp(FieldEntity element, String jsOp, |
| 1809 HInstruction operand, TypeMask type) | 1814 HInstruction receiver, HInstruction operand, TypeMask type) |
| 1810 : this._( | 1815 : this._( |
| 1811 element, jsOp, ASSIGN_OP, <HInstruction>[receiver, operand], type); | 1816 element, jsOp, ASSIGN_OP, <HInstruction>[receiver, operand], type); |
| 1812 | 1817 |
| 1813 HReadModifyWrite.preOp( | 1818 HReadModifyWrite.preOp( |
| 1814 Element element, String jsOp, HInstruction receiver, TypeMask type) | 1819 FieldEntity element, String jsOp, HInstruction receiver, TypeMask type) |
| 1815 : this._(element, jsOp, PRE_OP, <HInstruction>[receiver], type); | 1820 : this._(element, jsOp, PRE_OP, <HInstruction>[receiver], type); |
| 1816 | 1821 |
| 1817 HReadModifyWrite.postOp( | 1822 HReadModifyWrite.postOp( |
| 1818 Element element, String jsOp, HInstruction receiver, TypeMask type) | 1823 FieldEntity element, String jsOp, HInstruction receiver, TypeMask type) |
| 1819 : this._(element, jsOp, POST_OP, <HInstruction>[receiver], type); | 1824 : this._(element, jsOp, POST_OP, <HInstruction>[receiver], type); |
| 1820 | 1825 |
| 1821 HInstruction get receiver => inputs[0]; | 1826 HInstruction get receiver => inputs[0]; |
| 1822 | 1827 |
| 1823 bool get isPreOp => opKind == PRE_OP; | 1828 bool get isPreOp => opKind == PRE_OP; |
| 1824 bool get isPostOp => opKind == POST_OP; | 1829 bool get isPostOp => opKind == POST_OP; |
| 1825 bool get isAssignOp => opKind == ASSIGN_OP; | 1830 bool get isAssignOp => opKind == ASSIGN_OP; |
| 1826 | 1831 |
| 1827 bool canThrow() => receiver.canBeNull(); | 1832 bool canThrow() => receiver.canBeNull(); |
| 1828 | 1833 |
| (...skipping 668 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2497 HThrow(HInstruction value, SourceInformation sourceInformation, | 2502 HThrow(HInstruction value, SourceInformation sourceInformation, |
| 2498 {this.isRethrow: false}) | 2503 {this.isRethrow: false}) |
| 2499 : super(<HInstruction>[value]) { | 2504 : super(<HInstruction>[value]) { |
| 2500 this.sourceInformation = sourceInformation; | 2505 this.sourceInformation = sourceInformation; |
| 2501 } | 2506 } |
| 2502 toString() => 'throw'; | 2507 toString() => 'throw'; |
| 2503 accept(HVisitor visitor) => visitor.visitThrow(this); | 2508 accept(HVisitor visitor) => visitor.visitThrow(this); |
| 2504 } | 2509 } |
| 2505 | 2510 |
| 2506 class HStatic extends HInstruction { | 2511 class HStatic extends HInstruction { |
| 2507 final Element element; | 2512 final MemberEntity element; |
| 2508 HStatic(this.element, type) : super(<HInstruction>[], type) { | 2513 HStatic(this.element, type) : super(<HInstruction>[], type) { |
| 2509 assert(element != null); | 2514 assert(element != null); |
| 2510 assert(invariant(this, element.isDeclaration)); | |
| 2511 sideEffects.clearAllSideEffects(); | 2515 sideEffects.clearAllSideEffects(); |
| 2512 sideEffects.clearAllDependencies(); | 2516 sideEffects.clearAllDependencies(); |
| 2513 if (element.isAssignable) { | 2517 if (element.isAssignable) { |
| 2514 sideEffects.setDependsOnStaticPropertyStore(); | 2518 sideEffects.setDependsOnStaticPropertyStore(); |
| 2515 } | 2519 } |
| 2516 setUseGvn(); | 2520 setUseGvn(); |
| 2517 } | 2521 } |
| 2518 toString() => 'static ${element.name}'; | 2522 toString() => 'static ${element.name}'; |
| 2519 accept(HVisitor visitor) => visitor.visitStatic(this); | 2523 accept(HVisitor visitor) => visitor.visitStatic(this); |
| 2520 | 2524 |
| 2521 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode; | 2525 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode; |
| 2522 int typeCode() => HInstruction.STATIC_TYPECODE; | 2526 int typeCode() => HInstruction.STATIC_TYPECODE; |
| 2523 bool typeEquals(other) => other is HStatic; | 2527 bool typeEquals(other) => other is HStatic; |
| 2524 bool dataEquals(HStatic other) => element == other.element; | 2528 bool dataEquals(HStatic other) => element == other.element; |
| 2525 bool isCodeMotionInvariant() => !element.isAssignable; | 2529 bool isCodeMotionInvariant() => !element.isAssignable; |
| 2526 } | 2530 } |
| 2527 | 2531 |
| 2528 class HInterceptor extends HInstruction { | 2532 class HInterceptor extends HInstruction { |
| 2529 // This field should originally be null to allow GVN'ing all | 2533 // This field should originally be null to allow GVN'ing all |
| 2530 // [HInterceptor] on the same input. | 2534 // [HInterceptor] on the same input. |
| 2531 Set<ClassElement> interceptedClasses; | 2535 Set<ClassEntity> interceptedClasses; |
| 2532 | 2536 |
| 2533 // inputs[0] is initially the only input, the receiver. | 2537 // inputs[0] is initially the only input, the receiver. |
| 2534 | 2538 |
| 2535 // inputs[1] is a constant interceptor when the interceptor is a constant | 2539 // inputs[1] is a constant interceptor when the interceptor is a constant |
| 2536 // except for a `null` receiver. This is used when the receiver can't be | 2540 // except for a `null` receiver. This is used when the receiver can't be |
| 2537 // falsy, except for `null`, allowing the generation of code like | 2541 // falsy, except for `null`, allowing the generation of code like |
| 2538 // | 2542 // |
| 2539 // (a && C.JSArray_methods).get$first(a) | 2543 // (a && C.JSArray_methods).get$first(a) |
| 2540 // | 2544 // |
| 2541 | 2545 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2572 /** | 2576 /** |
| 2573 * A "one-shot" interceptor is a call to a synthetized method that | 2577 * A "one-shot" interceptor is a call to a synthetized method that |
| 2574 * will fetch the interceptor of its first parameter, and make a call | 2578 * will fetch the interceptor of its first parameter, and make a call |
| 2575 * on a given selector with the remaining parameters. | 2579 * on a given selector with the remaining parameters. |
| 2576 * | 2580 * |
| 2577 * In order to share the same optimizations with regular interceptor | 2581 * In order to share the same optimizations with regular interceptor |
| 2578 * calls, this class extends [HInvokeDynamic] and also has the null | 2582 * calls, this class extends [HInvokeDynamic] and also has the null |
| 2579 * constant as the first input. | 2583 * constant as the first input. |
| 2580 */ | 2584 */ |
| 2581 class HOneShotInterceptor extends HInvokeDynamic { | 2585 class HOneShotInterceptor extends HInvokeDynamic { |
| 2582 Set<ClassElement> interceptedClasses; | 2586 Set<ClassEntity> interceptedClasses; |
| 2583 HOneShotInterceptor(Selector selector, TypeMask mask, | 2587 HOneShotInterceptor(Selector selector, TypeMask mask, |
| 2584 List<HInstruction> inputs, TypeMask type, this.interceptedClasses) | 2588 List<HInstruction> inputs, TypeMask type, this.interceptedClasses) |
| 2585 : super(selector, mask, null, inputs, type, true) { | 2589 : super(selector, mask, null, inputs, type, true) { |
| 2586 assert(inputs[0] is HConstant); | 2590 assert(inputs[0] is HConstant); |
| 2587 assert(inputs[0].isNull()); | 2591 assert(inputs[0].isNull()); |
| 2588 } | 2592 } |
| 2589 bool isCallOnInterceptor(Compiler compiler) => true; | 2593 bool isCallOnInterceptor(Compiler compiler) => true; |
| 2590 | 2594 |
| 2591 String toString() => 'one shot interceptor: selector=$selector, mask=$mask'; | 2595 String toString() => 'one shot interceptor: selector=$selector, mask=$mask'; |
| 2592 accept(HVisitor visitor) => visitor.visitOneShotInterceptor(this); | 2596 accept(HVisitor visitor) => visitor.visitOneShotInterceptor(this); |
| 2593 } | 2597 } |
| 2594 | 2598 |
| 2595 /** An [HLazyStatic] is a static that is initialized lazily at first read. */ | 2599 /** An [HLazyStatic] is a static that is initialized lazily at first read. */ |
| 2596 class HLazyStatic extends HInstruction { | 2600 class HLazyStatic extends HInstruction { |
| 2597 final Element element; | 2601 final FieldEntity element; |
| 2598 HLazyStatic(this.element, type) : super(<HInstruction>[], type) { | 2602 HLazyStatic(this.element, type) : super(<HInstruction>[], type) { |
| 2599 // TODO(4931): The first access has side-effects, but we afterwards we | 2603 // TODO(4931): The first access has side-effects, but we afterwards we |
| 2600 // should be able to GVN. | 2604 // should be able to GVN. |
| 2601 sideEffects.setAllSideEffects(); | 2605 sideEffects.setAllSideEffects(); |
| 2602 sideEffects.setDependsOnSomething(); | 2606 sideEffects.setDependsOnSomething(); |
| 2603 } | 2607 } |
| 2604 | 2608 |
| 2605 toString() => 'lazy static ${element.name}'; | 2609 toString() => 'lazy static ${element.name}'; |
| 2606 accept(HVisitor visitor) => visitor.visitLazyStatic(this); | 2610 accept(HVisitor visitor) => visitor.visitLazyStatic(this); |
| 2607 | 2611 |
| 2608 int typeCode() => 30; | 2612 int typeCode() => 30; |
| 2609 // TODO(4931): can we do better here? | 2613 // TODO(4931): can we do better here? |
| 2610 bool isCodeMotionInvariant() => false; | 2614 bool isCodeMotionInvariant() => false; |
| 2611 bool canThrow() => true; | 2615 bool canThrow() => true; |
| 2612 } | 2616 } |
| 2613 | 2617 |
| 2614 class HStaticStore extends HInstruction { | 2618 class HStaticStore extends HInstruction { |
| 2615 Element element; | 2619 MemberEntity element; |
| 2616 HStaticStore(this.element, HInstruction value) | 2620 HStaticStore(this.element, HInstruction value) |
| 2617 : super(<HInstruction>[value], const TypeMask.nonNullEmpty()) { | 2621 : super(<HInstruction>[value], const TypeMask.nonNullEmpty()) { |
| 2618 sideEffects.clearAllSideEffects(); | 2622 sideEffects.clearAllSideEffects(); |
| 2619 sideEffects.clearAllDependencies(); | 2623 sideEffects.clearAllDependencies(); |
| 2620 sideEffects.setChangesStaticProperty(); | 2624 sideEffects.setChangesStaticProperty(); |
| 2621 } | 2625 } |
| 2622 toString() => 'static store ${element.name}'; | 2626 toString() => 'static store ${element.name}'; |
| 2623 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2627 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
| 2624 | 2628 |
| 2625 int typeCode() => HInstruction.STATIC_STORE_TYPECODE; | 2629 int typeCode() => HInstruction.STATIC_STORE_TYPECODE; |
| (...skipping 845 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3471 class HDynamicType extends HRuntimeType { | 3475 class HDynamicType extends HRuntimeType { |
| 3472 HDynamicType(DynamicType dartType, TypeMask instructionType) | 3476 HDynamicType(DynamicType dartType, TypeMask instructionType) |
| 3473 : super(const <HInstruction>[], dartType, instructionType); | 3477 : super(const <HInstruction>[], dartType, instructionType); |
| 3474 | 3478 |
| 3475 accept(HVisitor visitor) => visitor.visitDynamicType(this); | 3479 accept(HVisitor visitor) => visitor.visitDynamicType(this); |
| 3476 | 3480 |
| 3477 int typeCode() => HInstruction.DYNAMIC_TYPE_TYPECODE; | 3481 int typeCode() => HInstruction.DYNAMIC_TYPE_TYPECODE; |
| 3478 | 3482 |
| 3479 bool typeEquals(HInstruction other) => other is HDynamicType; | 3483 bool typeEquals(HInstruction other) => other is HDynamicType; |
| 3480 } | 3484 } |
| OLD | NEW |