| 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 abstract class HVisitor<R> { | 5 abstract class HVisitor<R> { |
| 6 R visitAdd(HAdd node); | 6 R visitAdd(HAdd node); |
| 7 R visitBailoutTarget(HBailoutTarget node); | 7 R visitBailoutTarget(HBailoutTarget node); |
| 8 R visitBitAnd(HBitAnd node); | 8 R visitBitAnd(HBitAnd node); |
| 9 R visitBitNot(HBitNot node); | 9 R visitBitNot(HBitNot node); |
| 10 R visitBitOr(HBitOr node); | 10 R visitBitOr(HBitOr node); |
| (...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 | 582 |
| 583 void addSuccessor(HBasicBlock block) { | 583 void addSuccessor(HBasicBlock block) { |
| 584 if (successors.isEmpty()) { | 584 if (successors.isEmpty()) { |
| 585 successors = [block]; | 585 successors = [block]; |
| 586 } else { | 586 } else { |
| 587 successors.add(block); | 587 successors.add(block); |
| 588 } | 588 } |
| 589 block.predecessors.add(this); | 589 block.predecessors.add(this); |
| 590 } | 590 } |
| 591 | 591 |
| 592 void removeSuccessor(HBasicBlock successor) { |
| 593 successors.removeAt(successors.indexOf(successor)); |
| 594 successor.predecessors.removeAt(successors.predecessors.indexOf(this)); |
| 595 } |
| 596 |
| 592 void postProcessLoopHeader() { | 597 void postProcessLoopHeader() { |
| 593 assert(isLoopHeader()); | 598 assert(isLoopHeader()); |
| 594 // Only the first entry into the loop is from outside the | 599 // Only the first entry into the loop is from outside the |
| 595 // loop. All other entries must be back edges. | 600 // loop. All other entries must be back edges. |
| 596 for (int i = 1, length = predecessors.length; i < length; i++) { | 601 for (int i = 1, length = predecessors.length; i < length; i++) { |
| 597 loopInformation.addBackEdge(predecessors[i]); | 602 loopInformation.addBackEdge(predecessors[i]); |
| 598 } | 603 } |
| 599 } | 604 } |
| 600 | 605 |
| 601 /** | 606 /** |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 | 755 |
| 751 final List<HInstruction> inputs; | 756 final List<HInstruction> inputs; |
| 752 final List<HInstruction> usedBy; | 757 final List<HInstruction> usedBy; |
| 753 | 758 |
| 754 HBasicBlock block; | 759 HBasicBlock block; |
| 755 HInstruction previous = null; | 760 HInstruction previous = null; |
| 756 HInstruction next = null; | 761 HInstruction next = null; |
| 757 int flags = 0; | 762 int flags = 0; |
| 758 | 763 |
| 759 // Changes flags. | 764 // Changes flags. |
| 760 static const int FLAG_CHANGES_SOMETHING = 0; | 765 static const int FLAG_CHANGES_INDEX = 0; |
| 761 static const int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1; | 766 static const int FLAG_CHANGES_INSTANCE_PROPERTY = FLAG_CHANGES_INDEX + 1; |
| 767 static const int FLAG_CHANGES_STATIC_PROPERTY |
| 768 = FLAG_CHANGES_INSTANCE_PROPERTY + 1; |
| 769 static const int FLAG_CHANGES_SOMETHING = FLAG_CHANGES_STATIC_PROPERTY + 1; |
| 770 static const int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1; |
| 762 | 771 |
| 763 // Depends flags (one for each changes flag). | 772 // Depends flags (one for each changes flag). |
| 764 static const int FLAG_DEPENDS_ON_SOMETHING = FLAG_CHANGES_COUNT; | 773 static const int FLAG_DEPENDS_ON_INDEX_STORE = FLAG_CHANGES_COUNT; |
| 774 static const int FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE = |
| 775 FLAG_DEPENDS_ON_INDEX_STORE + 1; |
| 776 static const int FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE = |
| 777 FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE + 1; |
| 778 static const int FLAG_DEPENDS_ON_SOMETHING = |
| 779 FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE + 1; |
| 765 | 780 |
| 766 // Other flags. | 781 // Other flags. |
| 767 static const int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1; | 782 static const int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1; |
| 768 | 783 |
| 769 // Type codes. | 784 // Type codes. |
| 770 static const int UNDEFINED_TYPECODE = -1; | 785 static const int UNDEFINED_TYPECODE = -1; |
| 771 static const int BOOLIFY_TYPECODE = 0; | 786 static const int BOOLIFY_TYPECODE = 0; |
| 772 static const int TYPE_GUARD_TYPECODE = 1; | 787 static const int TYPE_GUARD_TYPECODE = 1; |
| 773 static const int BOUNDS_CHECK_TYPECODE = 2; | 788 static const int BOUNDS_CHECK_TYPECODE = 2; |
| 774 static const int INTEGER_CHECK_TYPECODE = 3; | 789 static const int INTEGER_CHECK_TYPECODE = 3; |
| 775 static const int INVOKE_INTERCEPTOR_TYPECODE = 4; | 790 static const int INVOKE_INTERCEPTOR_TYPECODE = 4; |
| 776 static const int ADD_TYPECODE = 5; | 791 static const int ADD_TYPECODE = 5; |
| 777 static const int DIVIDE_TYPECODE = 6; | 792 static const int DIVIDE_TYPECODE = 6; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 793 static const int GREATER_EQUAL_TYPECODE = 22; | 808 static const int GREATER_EQUAL_TYPECODE = 22; |
| 794 static const int LESS_TYPECODE = 23; | 809 static const int LESS_TYPECODE = 23; |
| 795 static const int LESS_EQUAL_TYPECODE = 24; | 810 static const int LESS_EQUAL_TYPECODE = 24; |
| 796 static const int STATIC_TYPECODE = 25; | 811 static const int STATIC_TYPECODE = 25; |
| 797 static const int STATIC_STORE_TYPECODE = 26; | 812 static const int STATIC_STORE_TYPECODE = 26; |
| 798 static const int FIELD_GET_TYPECODE = 27; | 813 static const int FIELD_GET_TYPECODE = 27; |
| 799 static const int TYPE_CONVERSION_TYPECODE = 28; | 814 static const int TYPE_CONVERSION_TYPECODE = 28; |
| 800 static const int BAILOUT_TARGET_TYPECODE = 29; | 815 static const int BAILOUT_TARGET_TYPECODE = 29; |
| 801 static const int INVOKE_STATIC_TYPECODE = 30; | 816 static const int INVOKE_STATIC_TYPECODE = 30; |
| 802 static const int INVOKE_DYNAMIC_GETTER_TYPECODE = 31; | 817 static const int INVOKE_DYNAMIC_GETTER_TYPECODE = 31; |
| 818 static const int INDEX_TYPECODE = 32; |
| 803 | 819 |
| 804 HInstruction(this.inputs) | 820 HInstruction(this.inputs) |
| 805 : id = idCounter++, | 821 : id = idCounter++, |
| 806 usedBy = <HInstruction>[]; | 822 usedBy = <HInstruction>[]; |
| 807 | 823 |
| 808 int hashCode() => id; | 824 int hashCode() => id; |
| 809 | 825 |
| 810 bool getFlag(int position) => (flags & (1 << position)) != 0; | 826 bool getFlag(int position) => (flags & (1 << position)) != 0; |
| 811 void setFlag(int position) { flags |= (1 << position); } | 827 void setFlag(int position) { flags |= (1 << position); } |
| 812 void clearFlag(int position) { flags &= ~(1 << position); } | 828 void clearFlag(int position) { flags &= ~(1 << position); } |
| 813 | 829 |
| 814 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; | 830 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; |
| 815 | 831 |
| 816 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); | 832 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); |
| 817 bool hasSideEffects(HTypeMap types) => getChangesFlags() != 0; | 833 bool hasSideEffects(HTypeMap types) => getChangesFlags() != 0; |
| 818 void prepareGvn(HTypeMap types) { setAllSideEffects(); } | 834 void prepareGvn(HTypeMap types) { setAllSideEffects(); } |
| 819 | 835 |
| 820 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } | 836 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } |
| 821 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } | 837 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } |
| 822 | 838 |
| 823 bool dependsOnSomething() => getFlag(FLAG_DEPENDS_ON_SOMETHING); | 839 bool dependsOnSomething() => getFlag(FLAG_DEPENDS_ON_SOMETHING); |
| 824 void setDependsOnSomething() { setFlag(FLAG_DEPENDS_ON_SOMETHING); } | 840 void setDependsOnSomething() { setFlag(FLAG_DEPENDS_ON_SOMETHING); } |
| 825 | 841 |
| 842 bool dependsOnStaticPropertyStore() { |
| 843 return getFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE); |
| 844 } |
| 845 void setDependsOnStaticPropertyStore() { |
| 846 setFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE); |
| 847 } |
| 848 void setChangesStaticProperty() { setFlag(FLAG_CHANGES_STATIC_PROPERTY); } |
| 849 |
| 850 bool dependsOnIndexStore() => getFlag(FLAG_DEPENDS_ON_INDEX_STORE); |
| 851 void setDependsOnIndexStore() { setFlag(FLAG_DEPENDS_ON_INDEX_STORE); } |
| 852 void setChangesIndex() { setFlag(FLAG_CHANGES_INDEX); } |
| 853 |
| 854 bool dependsOnInstancePropertyStore() { |
| 855 return getFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE); |
| 856 } |
| 857 void setDependsOnInstancePropertyStore() { |
| 858 setFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE); |
| 859 } |
| 860 void setChangesInstanceProperty() { setFlag(FLAG_CHANGES_INSTANCE_PROPERTY); } |
| 861 |
| 826 bool useGvn() => getFlag(FLAG_USE_GVN); | 862 bool useGvn() => getFlag(FLAG_USE_GVN); |
| 827 void setUseGvn() { setFlag(FLAG_USE_GVN); } | 863 void setUseGvn() { setFlag(FLAG_USE_GVN); } |
| 828 // Does this node potentially affect control flow. | 864 // Does this node potentially affect control flow. |
| 829 bool isControlFlow() => false; | 865 bool isControlFlow() => false; |
| 830 | 866 |
| 831 // All isFunctions work on the propagated types. | 867 // All isFunctions work on the propagated types. |
| 832 bool isArray(HTypeMap types) => types[this].isArray(); | 868 bool isArray(HTypeMap types) => types[this].isArray(); |
| 833 bool isReadableArray(HTypeMap types) => types[this].isReadableArray(); | 869 bool isReadableArray(HTypeMap types) => types[this].isReadableArray(); |
| 834 bool isMutableArray(HTypeMap types) => types[this].isMutableArray(); | 870 bool isMutableArray(HTypeMap types) => types[this].isMutableArray(); |
| 835 bool isExtendableArray(HTypeMap types) => types[this].isExtendableArray(); | 871 bool isExtendableArray(HTypeMap types) => types[this].isExtendableArray(); |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1292 } | 1328 } |
| 1293 | 1329 |
| 1294 class HInvokeDynamicMethod extends HInvokeDynamic { | 1330 class HInvokeDynamicMethod extends HInvokeDynamic { |
| 1295 HInvokeDynamicMethod(Selector selector, List<HInstruction> inputs) | 1331 HInvokeDynamicMethod(Selector selector, List<HInstruction> inputs) |
| 1296 : super(selector, null, inputs); | 1332 : super(selector, null, inputs); |
| 1297 toString() => 'invoke dynamic method: $selector'; | 1333 toString() => 'invoke dynamic method: $selector'; |
| 1298 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); | 1334 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); |
| 1299 } | 1335 } |
| 1300 | 1336 |
| 1301 abstract class HInvokeDynamicField extends HInvokeDynamic { | 1337 abstract class HInvokeDynamicField extends HInvokeDynamic { |
| 1302 HInvokeDynamicField(Selector selector, Element element, | 1338 final bool isSideEffectFree; |
| 1303 List<HInstruction> inputs) | 1339 HInvokeDynamicField( |
| 1340 Selector selector, Element element, List<HInstruction> inputs, |
| 1341 this.isSideEffectFree) |
| 1304 : super(selector, element, inputs); | 1342 : super(selector, element, inputs); |
| 1305 toString() => 'invoke dynamic field: $selector'; | 1343 toString() => 'invoke dynamic field: $selector'; |
| 1306 | 1344 |
| 1307 // TODO(floitsch): make class abstract instead of adding an abstract method. | 1345 // TODO(floitsch): make class abstract instead of adding an abstract method. |
| 1308 abstract accept(HVisitor visitor); | 1346 abstract accept(HVisitor visitor); |
| 1309 } | 1347 } |
| 1310 | 1348 |
| 1311 class HInvokeDynamicGetter extends HInvokeDynamicField { | 1349 class HInvokeDynamicGetter extends HInvokeDynamicField { |
| 1312 final bool isSideEffectFree; | |
| 1313 HInvokeDynamicGetter( | 1350 HInvokeDynamicGetter( |
| 1314 selector, element, receiver, this.isSideEffectFree) | 1351 selector, element, receiver, isSideEffectFree) |
| 1315 : super(selector, element,[receiver]); | 1352 : super(selector, element, [receiver], isSideEffectFree); |
| 1316 toString() => 'invoke dynamic getter: $selector'; | 1353 toString() => 'invoke dynamic getter: $selector'; |
| 1317 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); | 1354 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); |
| 1318 | 1355 |
| 1319 void prepareGvn(HTypeMap types) { | 1356 void prepareGvn(HTypeMap types) { |
| 1357 clearAllSideEffects(); |
| 1320 if (isSideEffectFree) { | 1358 if (isSideEffectFree) { |
| 1321 setUseGvn(); | 1359 setUseGvn(); |
| 1322 clearAllSideEffects(); | 1360 setDependsOnInstancePropertyStore(); |
| 1323 setDependsOnSomething(); | |
| 1324 } else { | 1361 } else { |
| 1325 setAllSideEffects(); | 1362 setAllSideEffects(); |
| 1326 } | 1363 } |
| 1327 } | 1364 } |
| 1328 | 1365 |
| 1329 int typeCode() => HInstruction.INVOKE_DYNAMIC_GETTER_TYPECODE; | 1366 int typeCode() => HInstruction.INVOKE_DYNAMIC_GETTER_TYPECODE; |
| 1330 bool typeEquals(other) => other is HInvokeDynamicGetter; | 1367 bool typeEquals(other) => other is HInvokeDynamicGetter; |
| 1331 bool dataEquals(HInvokeDynamicGetter other) => selector == other.selector; | 1368 bool dataEquals(HInvokeDynamicGetter other) => selector == other.selector; |
| 1332 } | 1369 } |
| 1333 | 1370 |
| 1334 class HInvokeDynamicSetter extends HInvokeDynamicField { | 1371 class HInvokeDynamicSetter extends HInvokeDynamicField { |
| 1335 HInvokeDynamicSetter(selector, element, receiver, value) | 1372 HInvokeDynamicSetter(selector, element, receiver, value, isSideEffectFree) |
| 1336 : super(selector, element, [receiver, value]); | 1373 : super(selector, element, [receiver, value], isSideEffectFree); |
| 1337 toString() => 'invoke dynamic setter: $selector'; | 1374 toString() => 'invoke dynamic setter: $selector'; |
| 1338 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); | 1375 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); |
| 1376 |
| 1377 void prepareGvn(HTypeMap types) { |
| 1378 clearAllSideEffects(); |
| 1379 if (isSideEffectFree) { |
| 1380 setChangesInstanceProperty(); |
| 1381 } else { |
| 1382 setAllSideEffects(); |
| 1383 } |
| 1384 } |
| 1339 } | 1385 } |
| 1340 | 1386 |
| 1341 class HInvokeStatic extends HInvoke { | 1387 class HInvokeStatic extends HInvoke { |
| 1342 /** The first input must be the target. */ | 1388 /** The first input must be the target. */ |
| 1343 HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) { | 1389 HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) { |
| 1344 guaranteedType = knownType; | 1390 guaranteedType = knownType; |
| 1345 } | 1391 } |
| 1346 | 1392 |
| 1347 toString() => 'invoke static: ${element.name}'; | 1393 toString() => 'invoke static: ${element.name}'; |
| 1348 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); | 1394 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1423 // TODO(kasperl): Should we check that the selector is a call selector? | 1469 // TODO(kasperl): Should we check that the selector is a call selector? |
| 1424 if (selector.name == const SourceString('add') | 1470 if (selector.name == const SourceString('add') |
| 1425 || selector.name == const SourceString('removeLast')) { | 1471 || selector.name == const SourceString('removeLast')) { |
| 1426 return HType.MUTABLE_ARRAY; | 1472 return HType.MUTABLE_ARRAY; |
| 1427 } | 1473 } |
| 1428 } | 1474 } |
| 1429 return HType.UNKNOWN; | 1475 return HType.UNKNOWN; |
| 1430 } | 1476 } |
| 1431 | 1477 |
| 1432 void prepareGvn(HTypeMap types) { | 1478 void prepareGvn(HTypeMap types) { |
| 1479 clearAllSideEffects(); |
| 1433 if (isLengthGetterOnStringOrArray(types)) { | 1480 if (isLengthGetterOnStringOrArray(types)) { |
| 1434 setUseGvn(); | 1481 setUseGvn(); |
| 1435 clearAllSideEffects(); | |
| 1436 // If the input is a string, we know the length cannot change. | 1482 // If the input is a string, we know the length cannot change. |
| 1437 // We cannot do the same thing for non-extendable array because | 1483 // We cannot do the same thing for non-extendable array because |
| 1438 // we don't express that type yet: a mutable array might be | 1484 // we don't express that type yet: a mutable array might be |
| 1439 // extendable. | 1485 // extendable. |
| 1440 if (!inputs[1].isString(types)) setDependsOnSomething(); | 1486 if (!inputs[1].isString(types)) setDependsOnInstancePropertyStore(); |
| 1441 } else if (isSideEffectFree) { | 1487 } else if (isSideEffectFree) { |
| 1442 setUseGvn(); | 1488 setUseGvn(); |
| 1443 clearAllSideEffects(); | |
| 1444 setDependsOnSomething(); | 1489 setDependsOnSomething(); |
| 1445 } else { | 1490 } else { |
| 1446 setAllSideEffects(); | 1491 setAllSideEffects(); |
| 1447 } | 1492 } |
| 1448 } | 1493 } |
| 1449 | 1494 |
| 1450 int typeCode() => HInstruction.INVOKE_INTERCEPTOR_TYPECODE; | 1495 int typeCode() => HInstruction.INVOKE_INTERCEPTOR_TYPECODE; |
| 1451 bool typeEquals(other) => other is HInvokeInterceptor; | 1496 bool typeEquals(other) => other is HInvokeInterceptor; |
| 1452 bool dataEquals(HInvokeInterceptor other) => selector == other.selector; | 1497 bool dataEquals(HInvokeInterceptor other) => selector == other.selector; |
| 1453 } | 1498 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1467 : this.isAssignable = (isAssignable !== null) | 1512 : this.isAssignable = (isAssignable !== null) |
| 1468 ? isAssignable | 1513 ? isAssignable |
| 1469 : element.isAssignable(), | 1514 : element.isAssignable(), |
| 1470 super(element, <HInstruction>[receiver]); | 1515 super(element, <HInstruction>[receiver]); |
| 1471 | 1516 |
| 1472 HInstruction get receiver => inputs[0]; | 1517 HInstruction get receiver => inputs[0]; |
| 1473 | 1518 |
| 1474 accept(HVisitor visitor) => visitor.visitFieldGet(this); | 1519 accept(HVisitor visitor) => visitor.visitFieldGet(this); |
| 1475 | 1520 |
| 1476 void prepareGvn(HTypeMap types) { | 1521 void prepareGvn(HTypeMap types) { |
| 1522 clearAllSideEffects(); |
| 1477 setUseGvn(); | 1523 setUseGvn(); |
| 1478 clearAllSideEffects(); | 1524 if (isAssignable) { |
| 1479 if (isAssignable) setDependsOnSomething(); | 1525 setDependsOnInstancePropertyStore(); |
| 1526 } |
| 1480 } | 1527 } |
| 1481 | 1528 |
| 1482 int typeCode() => HInstruction.FIELD_GET_TYPECODE; | 1529 int typeCode() => HInstruction.FIELD_GET_TYPECODE; |
| 1483 bool typeEquals(other) => other is HFieldGet; | 1530 bool typeEquals(other) => other is HFieldGet; |
| 1484 bool dataEquals(HFieldGet other) => element == other.element; | 1531 bool dataEquals(HFieldGet other) => element == other.element; |
| 1485 String toString() => "FieldGet $element"; | 1532 String toString() => "FieldGet $element"; |
| 1486 } | 1533 } |
| 1487 | 1534 |
| 1488 class HFieldSet extends HFieldAccess { | 1535 class HFieldSet extends HFieldAccess { |
| 1489 HFieldSet(Element element, | 1536 HFieldSet(Element element, |
| 1490 HInstruction receiver, | 1537 HInstruction receiver, |
| 1491 HInstruction value) | 1538 HInstruction value) |
| 1492 : super(element, <HInstruction>[receiver, value]); | 1539 : super(element, <HInstruction>[receiver, value]); |
| 1493 | 1540 |
| 1494 HInstruction get receiver => inputs[0]; | 1541 HInstruction get receiver => inputs[0]; |
| 1495 HInstruction get value => inputs[1]; | 1542 HInstruction get value => inputs[1]; |
| 1496 accept(HVisitor visitor) => visitor.visitFieldSet(this); | 1543 accept(HVisitor visitor) => visitor.visitFieldSet(this); |
| 1497 | 1544 |
| 1498 void prepareGvn(HTypeMap types) { | 1545 void prepareGvn(HTypeMap types) { |
| 1499 // TODO(ngeoffray): implement more fine grained side effects. | 1546 clearAllSideEffects(); |
| 1500 setAllSideEffects(); | 1547 setChangesInstanceProperty(); |
| 1501 } | 1548 } |
| 1502 | 1549 |
| 1503 bool isJsStatement(HTypeMap types) => true; | 1550 bool isJsStatement(HTypeMap types) => true; |
| 1504 String toString() => "FieldSet $element"; | 1551 String toString() => "FieldSet $element"; |
| 1505 } | 1552 } |
| 1506 | 1553 |
| 1507 class HLocalGet extends HFieldGet { | 1554 class HLocalGet extends HFieldGet { |
| 1508 HLocalGet(Element element, HLocalValue local) : super(element, local); | 1555 HLocalGet(Element element, HLocalValue local) : super(element, local); |
| 1509 | 1556 |
| 1510 accept(HVisitor visitor) => visitor.visitLocalGet(this); | 1557 accept(HVisitor visitor) => visitor.visitLocalGet(this); |
| 1511 | 1558 |
| 1512 HLocalValue get local => inputs[0]; | 1559 HLocalValue get local => inputs[0]; |
| 1513 | |
| 1514 void prepareGvn(HTypeMap types) { | |
| 1515 setUseGvn(); | |
| 1516 // TODO(floitsch): if the variable is not captured then it only depends | |
| 1517 // on assignments to the same variable. Otherwise we need to see if the | |
| 1518 // variable is mutated inside closures. | |
| 1519 setDependsOnSomething(); | |
| 1520 } | |
| 1521 } | 1560 } |
| 1522 | 1561 |
| 1523 class HLocalSet extends HFieldSet { | 1562 class HLocalSet extends HFieldSet { |
| 1524 HLocalSet(Element element, HLocalValue local, HInstruction value) | 1563 HLocalSet(Element element, HLocalValue local, HInstruction value) |
| 1525 : super(element, local, value); | 1564 : super(element, local, value); |
| 1526 | 1565 |
| 1527 accept(HVisitor visitor) => visitor.visitLocalSet(this); | 1566 accept(HVisitor visitor) => visitor.visitLocalSet(this); |
| 1528 | 1567 |
| 1529 HLocalValue get local => inputs[0]; | 1568 HLocalValue get local => inputs[0]; |
| 1530 | |
| 1531 void prepareGvn(HTypeMap types) { | |
| 1532 // TODO(floitsch): implement more fine grained side effects. | |
| 1533 setAllSideEffects(); | |
| 1534 } | |
| 1535 } | 1569 } |
| 1536 | 1570 |
| 1537 class HForeign extends HInstruction { | 1571 class HForeign extends HInstruction { |
| 1538 final DartString code; | 1572 final DartString code; |
| 1539 final HType foreignType; | 1573 final HType foreignType; |
| 1540 final bool _isStatement; | 1574 final bool _isStatement; |
| 1541 | 1575 |
| 1542 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) | 1576 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) |
| 1543 : foreignType = computeTypeFromDeclaredType(declaredType), | 1577 : foreignType = computeTypeFromDeclaredType(declaredType), |
| 1544 _isStatement = false, | 1578 _isStatement = false, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1580 | 1614 |
| 1581 abstract BinaryOperation operation(ConstantSystem constantSystem); | 1615 abstract BinaryOperation operation(ConstantSystem constantSystem); |
| 1582 abstract isBuiltin(HTypeMap types); | 1616 abstract isBuiltin(HTypeMap types); |
| 1583 } | 1617 } |
| 1584 | 1618 |
| 1585 abstract class HBinaryArithmetic extends HInvokeBinary { | 1619 abstract class HBinaryArithmetic extends HInvokeBinary { |
| 1586 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) | 1620 HBinaryArithmetic(HStatic target, HInstruction left, HInstruction right) |
| 1587 : super(target, left, right); | 1621 : super(target, left, right); |
| 1588 | 1622 |
| 1589 void prepareGvn(HTypeMap types) { | 1623 void prepareGvn(HTypeMap types) { |
| 1624 clearAllSideEffects(); |
| 1590 // An arithmetic expression can take part in global value | 1625 // An arithmetic expression can take part in global value |
| 1591 // numbering and do not have any side-effects if we know that all | 1626 // numbering and do not have any side-effects if we know that all |
| 1592 // inputs are numbers. | 1627 // inputs are numbers. |
| 1593 if (isBuiltin(types)) { | 1628 if (isBuiltin(types)) { |
| 1594 clearAllSideEffects(); | |
| 1595 setUseGvn(); | 1629 setUseGvn(); |
| 1596 } else { | 1630 } else { |
| 1597 setAllSideEffects(); | 1631 setAllSideEffects(); |
| 1598 } | 1632 } |
| 1599 } | 1633 } |
| 1600 | 1634 |
| 1601 bool isBuiltin(HTypeMap types) | 1635 bool isBuiltin(HTypeMap types) |
| 1602 => left.isNumber(types) && right.isNumber(types); | 1636 => left.isNumber(types) && right.isNumber(types); |
| 1603 | 1637 |
| 1604 HType computeTypeFromInputTypes(HTypeMap types) { | 1638 HType computeTypeFromInputTypes(HTypeMap types) { |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1856 bool dataEquals(HInstruction other) => true; | 1890 bool dataEquals(HInstruction other) => true; |
| 1857 } | 1891 } |
| 1858 | 1892 |
| 1859 abstract class HInvokeUnary extends HInvokeStatic { | 1893 abstract class HInvokeUnary extends HInvokeStatic { |
| 1860 HInvokeUnary(HStatic target, HInstruction input) | 1894 HInvokeUnary(HStatic target, HInstruction input) |
| 1861 : super(<HInstruction>[target, input]); | 1895 : super(<HInstruction>[target, input]); |
| 1862 | 1896 |
| 1863 HInstruction get operand => inputs[1]; | 1897 HInstruction get operand => inputs[1]; |
| 1864 | 1898 |
| 1865 void prepareGvn(HTypeMap types) { | 1899 void prepareGvn(HTypeMap types) { |
| 1900 clearAllSideEffects(); |
| 1866 // A unary arithmetic expression can take part in global value | 1901 // A unary arithmetic expression can take part in global value |
| 1867 // numbering and does not have any side-effects if its input is a | 1902 // numbering and does not have any side-effects if its input is a |
| 1868 // number. | 1903 // number. |
| 1869 if (isBuiltin(types)) { | 1904 if (isBuiltin(types)) { |
| 1870 clearAllSideEffects(); | |
| 1871 setUseGvn(); | 1905 setUseGvn(); |
| 1872 } else { | 1906 } else { |
| 1873 setAllSideEffects(); | 1907 setAllSideEffects(); |
| 1874 } | 1908 } |
| 1875 } | 1909 } |
| 1876 | 1910 |
| 1877 bool isBuiltin(HTypeMap types) => operand.isNumber(types); | 1911 bool isBuiltin(HTypeMap types) => operand.isNumber(types); |
| 1878 | 1912 |
| 1879 HType computeTypeFromInputTypes(HTypeMap types) { | 1913 HType computeTypeFromInputTypes(HTypeMap types) { |
| 1880 HType operandType = types[operand]; | 1914 HType operandType = types[operand]; |
| (...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2185 toString() => 'phi'; | 2219 toString() => 'phi'; |
| 2186 accept(HVisitor visitor) => visitor.visitPhi(this); | 2220 accept(HVisitor visitor) => visitor.visitPhi(this); |
| 2187 } | 2221 } |
| 2188 | 2222 |
| 2189 abstract class HRelational extends HInvokeBinary { | 2223 abstract class HRelational extends HInvokeBinary { |
| 2190 bool usesBoolifiedInterceptor = false; | 2224 bool usesBoolifiedInterceptor = false; |
| 2191 HRelational(HStatic target, HInstruction left, HInstruction right) | 2225 HRelational(HStatic target, HInstruction left, HInstruction right) |
| 2192 : super(target, left, right); | 2226 : super(target, left, right); |
| 2193 | 2227 |
| 2194 void prepareGvn(HTypeMap types) { | 2228 void prepareGvn(HTypeMap types) { |
| 2229 clearAllSideEffects(); |
| 2195 // Relational expressions can take part in global value numbering | 2230 // Relational expressions can take part in global value numbering |
| 2196 // and do not have any side-effects if we know all the inputs are | 2231 // and do not have any side-effects if we know all the inputs are |
| 2197 // numbers. This can be improved for at least equality. | 2232 // numbers. This can be improved for at least equality. |
| 2198 if (isBuiltin(types)) { | 2233 if (isBuiltin(types)) { |
| 2199 clearAllSideEffects(); | |
| 2200 setUseGvn(); | 2234 setUseGvn(); |
| 2201 } else { | 2235 } else { |
| 2202 setAllSideEffects(); | 2236 setAllSideEffects(); |
| 2203 } | 2237 } |
| 2204 } | 2238 } |
| 2205 | 2239 |
| 2206 HType computeTypeFromInputTypes(HTypeMap types) { | 2240 HType computeTypeFromInputTypes(HTypeMap types) { |
| 2207 if (left.isNumber(types) || usesBoolifiedInterceptor) return HType.BOOLEAN; | 2241 if (left.isNumber(types) || usesBoolifiedInterceptor) return HType.BOOLEAN; |
| 2208 return HType.UNKNOWN; | 2242 return HType.UNKNOWN; |
| 2209 } | 2243 } |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2369 } | 2403 } |
| 2370 | 2404 |
| 2371 class HStatic extends HInstruction { | 2405 class HStatic extends HInstruction { |
| 2372 final Element element; | 2406 final Element element; |
| 2373 HStatic(this.element) : super(<HInstruction>[]) { | 2407 HStatic(this.element) : super(<HInstruction>[]) { |
| 2374 assert(element !== null); | 2408 assert(element !== null); |
| 2375 assert(invariant(this, element.isDeclaration)); | 2409 assert(invariant(this, element.isDeclaration)); |
| 2376 } | 2410 } |
| 2377 | 2411 |
| 2378 void prepareGvn(HTypeMap types) { | 2412 void prepareGvn(HTypeMap types) { |
| 2379 if (!element.isAssignable()) { | 2413 clearAllSideEffects(); |
| 2380 clearAllSideEffects(); | 2414 if (element.isAssignable()) { |
| 2381 setUseGvn(); | 2415 setDependsOnStaticPropertyStore(); |
| 2382 } | 2416 } |
| 2417 setUseGvn(); |
| 2383 } | 2418 } |
| 2384 toString() => 'static ${element.name}'; | 2419 toString() => 'static ${element.name}'; |
| 2385 accept(HVisitor visitor) => visitor.visitStatic(this); | 2420 accept(HVisitor visitor) => visitor.visitStatic(this); |
| 2386 | 2421 |
| 2387 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); | 2422 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); |
| 2388 int typeCode() => HInstruction.STATIC_TYPECODE; | 2423 int typeCode() => HInstruction.STATIC_TYPECODE; |
| 2389 bool typeEquals(other) => other is HStatic; | 2424 bool typeEquals(other) => other is HStatic; |
| 2390 bool dataEquals(HStatic other) => element == other.element; | 2425 bool dataEquals(HStatic other) => element == other.element; |
| 2391 bool isCodeMotionInvariant() => !element.isAssignable(); | 2426 bool isCodeMotionInvariant() => !element.isAssignable(); |
| 2392 } | 2427 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2412 class HStaticStore extends HInstruction { | 2447 class HStaticStore extends HInstruction { |
| 2413 Element element; | 2448 Element element; |
| 2414 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); | 2449 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); |
| 2415 toString() => 'static store ${element.name}'; | 2450 toString() => 'static store ${element.name}'; |
| 2416 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2451 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
| 2417 | 2452 |
| 2418 int typeCode() => HInstruction.STATIC_STORE_TYPECODE; | 2453 int typeCode() => HInstruction.STATIC_STORE_TYPECODE; |
| 2419 bool typeEquals(other) => other is HStaticStore; | 2454 bool typeEquals(other) => other is HStaticStore; |
| 2420 bool dataEquals(HStaticStore other) => element == other.element; | 2455 bool dataEquals(HStaticStore other) => element == other.element; |
| 2421 bool isJsStatement(HTypeMap types) => true; | 2456 bool isJsStatement(HTypeMap types) => true; |
| 2457 |
| 2458 void prepareGvn(HTypeMap types) { |
| 2459 clearAllSideEffects(); |
| 2460 setChangesStaticProperty(); |
| 2461 } |
| 2422 } | 2462 } |
| 2423 | 2463 |
| 2424 class HLiteralList extends HInstruction { | 2464 class HLiteralList extends HInstruction { |
| 2425 HLiteralList(inputs) : super(inputs); | 2465 HLiteralList(inputs) : super(inputs); |
| 2426 toString() => 'literal list'; | 2466 toString() => 'literal list'; |
| 2427 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2467 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
| 2428 | 2468 |
| 2429 HType get guaranteedType => HType.EXTENDABLE_ARRAY; | 2469 HType get guaranteedType => HType.EXTENDABLE_ARRAY; |
| 2430 | 2470 |
| 2431 void prepareGvn(HTypeMap types) { | 2471 void prepareGvn(HTypeMap types) { |
| 2432 assert(!hasSideEffects(types)); | 2472 assert(!hasSideEffects(types)); |
| 2433 } | 2473 } |
| 2434 } | 2474 } |
| 2435 | 2475 |
| 2436 class HIndex extends HInvokeStatic { | 2476 class HIndex extends HInvokeStatic { |
| 2437 HIndex(HStatic target, HInstruction receiver, HInstruction index) | 2477 HIndex(HStatic target, HInstruction receiver, HInstruction index) |
| 2438 : super(<HInstruction>[target, receiver, index]); | 2478 : super(<HInstruction>[target, receiver, index]); |
| 2439 toString() => 'index operator'; | 2479 toString() => 'index operator'; |
| 2440 accept(HVisitor visitor) => visitor.visitIndex(this); | 2480 accept(HVisitor visitor) => visitor.visitIndex(this); |
| 2441 | 2481 |
| 2442 void prepareGvn(HTypeMap types) { | 2482 void prepareGvn(HTypeMap types) { |
| 2483 clearAllSideEffects(); |
| 2443 if (isBuiltin(types)) { | 2484 if (isBuiltin(types)) { |
| 2444 clearAllSideEffects(); | 2485 setDependsOnIndexStore(); |
| 2486 setUseGvn(); |
| 2445 } else { | 2487 } else { |
| 2446 setAllSideEffects(); | 2488 setAllSideEffects(); |
| 2447 } | 2489 } |
| 2448 } | 2490 } |
| 2449 | 2491 |
| 2450 HInstruction get receiver => inputs[1]; | 2492 HInstruction get receiver => inputs[1]; |
| 2451 HInstruction get index => inputs[2]; | 2493 HInstruction get index => inputs[2]; |
| 2452 | 2494 |
| 2453 HType computeDesiredTypeForNonTargetInput(HInstruction input, | 2495 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2454 HTypeMap types) { | 2496 HTypeMap types) { |
| 2455 if (input == receiver && | 2497 if (input == receiver && |
| 2456 (index.isTypeUnknown(types) || index.isNumber(types))) { | 2498 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 2457 return HType.INDEXABLE_PRIMITIVE; | 2499 return HType.INDEXABLE_PRIMITIVE; |
| 2458 } | 2500 } |
| 2459 // The index should be an int when the receiver is a string or array. | 2501 // The index should be an int when the receiver is a string or array. |
| 2460 // However it turns out that inserting an integer check in the optimized | 2502 // However it turns out that inserting an integer check in the optimized |
| 2461 // version is cheaper than having another bailout case. This is true, | 2503 // version is cheaper than having another bailout case. This is true, |
| 2462 // because the integer check will simply throw if it fails. | 2504 // because the integer check will simply throw if it fails. |
| 2463 return HType.UNKNOWN; | 2505 return HType.UNKNOWN; |
| 2464 } | 2506 } |
| 2465 | 2507 |
| 2466 bool isBuiltin(HTypeMap types) | 2508 bool isBuiltin(HTypeMap types) |
| 2467 => receiver.isIndexablePrimitive(types) && index.isInteger(types); | 2509 => receiver.isIndexablePrimitive(types) && index.isInteger(types); |
| 2510 |
| 2511 int typeCode() => HInstruction.INDEX_TYPECODE; |
| 2512 bool typeEquals(HInstruction other) => other is HIndex; |
| 2513 bool dataEquals(HIndex other) => true; |
| 2468 } | 2514 } |
| 2469 | 2515 |
| 2470 class HIndexAssign extends HInvokeStatic { | 2516 class HIndexAssign extends HInvokeStatic { |
| 2471 HIndexAssign(HStatic target, | 2517 HIndexAssign(HStatic target, |
| 2472 HInstruction receiver, | 2518 HInstruction receiver, |
| 2473 HInstruction index, | 2519 HInstruction index, |
| 2474 HInstruction value) | 2520 HInstruction value) |
| 2475 : super(<HInstruction>[target, receiver, index, value]); | 2521 : super(<HInstruction>[target, receiver, index, value]); |
| 2476 toString() => 'index assign operator'; | 2522 toString() => 'index assign operator'; |
| 2477 accept(HVisitor visitor) => visitor.visitIndexAssign(this); | 2523 accept(HVisitor visitor) => visitor.visitIndexAssign(this); |
| 2478 | 2524 |
| 2479 HInstruction get receiver => inputs[1]; | 2525 HInstruction get receiver => inputs[1]; |
| 2480 HInstruction get index => inputs[2]; | 2526 HInstruction get index => inputs[2]; |
| 2481 HInstruction get value => inputs[3]; | 2527 HInstruction get value => inputs[3]; |
| 2482 | 2528 |
| 2529 void prepareGvn(HTypeMap types) { |
| 2530 clearAllSideEffects(); |
| 2531 if (isBuiltin(types)) { |
| 2532 setChangesIndex(); |
| 2533 } else { |
| 2534 setAllSideEffects(); |
| 2535 } |
| 2536 } |
| 2537 |
| 2483 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] | 2538 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] |
| 2484 // is never used as input. | 2539 // is never used as input. |
| 2485 | 2540 |
| 2486 HType computeDesiredTypeForNonTargetInput(HInstruction input, | 2541 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2487 HTypeMap types) { | 2542 HTypeMap types) { |
| 2488 if (input == receiver && | 2543 if (input == receiver && |
| 2489 (index.isTypeUnknown(types) || index.isNumber(types))) { | 2544 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 2490 return HType.MUTABLE_ARRAY; | 2545 return HType.MUTABLE_ARRAY; |
| 2491 } | 2546 } |
| 2492 // The index should be an int when the receiver is a string or array. | 2547 // The index should be an int when the receiver is a string or array. |
| (...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2917 HBasicBlock get start => expression.start; | 2972 HBasicBlock get start => expression.start; |
| 2918 HBasicBlock get end { | 2973 HBasicBlock get end { |
| 2919 // We don't create a switch block if there are no cases. | 2974 // We don't create a switch block if there are no cases. |
| 2920 assert(!statements.isEmpty()); | 2975 assert(!statements.isEmpty()); |
| 2921 return statements.last().end; | 2976 return statements.last().end; |
| 2922 } | 2977 } |
| 2923 | 2978 |
| 2924 bool accept(HStatementInformationVisitor visitor) => | 2979 bool accept(HStatementInformationVisitor visitor) => |
| 2925 visitor.visitSwitchInfo(this); | 2980 visitor.visitSwitchInfo(this); |
| 2926 } | 2981 } |
| OLD | NEW |