Chromium Code Reviews| 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 739 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 750 | 750 |
| 751 final List<HInstruction> inputs; | 751 final List<HInstruction> inputs; |
| 752 final List<HInstruction> usedBy; | 752 final List<HInstruction> usedBy; |
| 753 | 753 |
| 754 HBasicBlock block; | 754 HBasicBlock block; |
| 755 HInstruction previous = null; | 755 HInstruction previous = null; |
| 756 HInstruction next = null; | 756 HInstruction next = null; |
| 757 int flags = 0; | 757 int flags = 0; |
| 758 | 758 |
| 759 // Changes flags. | 759 // Changes flags. |
| 760 static const int FLAG_CHANGES_SOMETHING = 0; | 760 static const int FLAG_CHANGES_INDEX = 0; |
| 761 static const int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1; | 761 static const int FLAG_CHANGES_PROPERTY = FLAG_CHANGES_INDEX + 1; |
| 762 static const int FLAG_CHANGES_STATIC = FLAG_CHANGES_PROPERTY + 1; | |
|
Søren Gjesse
2012/10/01 07:22:20
How about FLAG_CHANGES_STATIC_PROPERTY (and then m
ngeoffray
2012/10/04 10:41:42
Done.
| |
| 763 static const int FLAG_CHANGES_SOMETHING = FLAG_CHANGES_STATIC + 1; | |
| 764 static const int FLAG_CHANGES_COUNT = FLAG_CHANGES_SOMETHING + 1; | |
| 762 | 765 |
| 763 // Depends flags (one for each changes flag). | 766 // Depends flags (one for each changes flag). |
| 764 static const int FLAG_DEPENDS_ON_SOMETHING = FLAG_CHANGES_COUNT; | 767 static const int FLAG_DEPENDS_ON_INDEX_STORE = FLAG_CHANGES_COUNT; |
| 768 static const int FLAG_DEPENDS_ON_PROPERTY_STORE = | |
| 769 FLAG_DEPENDS_ON_INDEX_STORE + 1; | |
| 770 static const int FLAG_DEPENDS_ON_STATIC = FLAG_DEPENDS_ON_PROPERTY_STORE + 1; | |
| 771 static const int FLAG_DEPENDS_ON_SOMETHING = FLAG_DEPENDS_ON_STATIC + 1; | |
| 765 | 772 |
| 766 // Other flags. | 773 // Other flags. |
| 767 static const int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1; | 774 static const int FLAG_USE_GVN = FLAG_DEPENDS_ON_SOMETHING + 1; |
| 768 | 775 |
| 769 // Type codes. | 776 // Type codes. |
| 770 static const int UNDEFINED_TYPECODE = -1; | 777 static const int UNDEFINED_TYPECODE = -1; |
| 771 static const int BOOLIFY_TYPECODE = 0; | 778 static const int BOOLIFY_TYPECODE = 0; |
| 772 static const int TYPE_GUARD_TYPECODE = 1; | 779 static const int TYPE_GUARD_TYPECODE = 1; |
| 773 static const int BOUNDS_CHECK_TYPECODE = 2; | 780 static const int BOUNDS_CHECK_TYPECODE = 2; |
| 774 static const int INTEGER_CHECK_TYPECODE = 3; | 781 static const int INTEGER_CHECK_TYPECODE = 3; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 793 static const int GREATER_EQUAL_TYPECODE = 22; | 800 static const int GREATER_EQUAL_TYPECODE = 22; |
| 794 static const int LESS_TYPECODE = 23; | 801 static const int LESS_TYPECODE = 23; |
| 795 static const int LESS_EQUAL_TYPECODE = 24; | 802 static const int LESS_EQUAL_TYPECODE = 24; |
| 796 static const int STATIC_TYPECODE = 25; | 803 static const int STATIC_TYPECODE = 25; |
| 797 static const int STATIC_STORE_TYPECODE = 26; | 804 static const int STATIC_STORE_TYPECODE = 26; |
| 798 static const int FIELD_GET_TYPECODE = 27; | 805 static const int FIELD_GET_TYPECODE = 27; |
| 799 static const int TYPE_CONVERSION_TYPECODE = 28; | 806 static const int TYPE_CONVERSION_TYPECODE = 28; |
| 800 static const int BAILOUT_TARGET_TYPECODE = 29; | 807 static const int BAILOUT_TARGET_TYPECODE = 29; |
| 801 static const int INVOKE_STATIC_TYPECODE = 30; | 808 static const int INVOKE_STATIC_TYPECODE = 30; |
| 802 static const int INVOKE_DYNAMIC_GETTER_TYPECODE = 31; | 809 static const int INVOKE_DYNAMIC_GETTER_TYPECODE = 31; |
| 810 static const int INDEX_TYPECODE = 32; | |
| 803 | 811 |
| 804 HInstruction(this.inputs) | 812 HInstruction(this.inputs) |
| 805 : id = idCounter++, | 813 : id = idCounter++, |
| 806 usedBy = <HInstruction>[]; | 814 usedBy = <HInstruction>[]; |
| 807 | 815 |
| 808 int hashCode() => id; | 816 int hashCode() => id; |
| 809 | 817 |
| 810 bool getFlag(int position) => (flags & (1 << position)) != 0; | 818 bool getFlag(int position) => (flags & (1 << position)) != 0; |
| 811 void setFlag(int position) { flags |= (1 << position); } | 819 void setFlag(int position) { flags |= (1 << position); } |
| 812 void clearFlag(int position) { flags &= ~(1 << position); } | 820 void clearFlag(int position) { flags &= ~(1 << position); } |
| 813 | 821 |
| 814 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; | 822 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; |
| 815 | 823 |
| 816 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); | 824 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); |
| 817 bool hasSideEffects(HTypeMap types) => getChangesFlags() != 0; | 825 bool hasSideEffects(HTypeMap types) => getChangesFlags() != 0; |
| 818 void prepareGvn(HTypeMap types) { setAllSideEffects(); } | 826 void prepareGvn(HTypeMap types) { setAllSideEffects(); } |
| 819 | 827 |
| 820 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } | 828 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } |
| 821 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } | 829 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } |
| 822 | 830 |
| 823 bool dependsOnSomething() => getFlag(FLAG_DEPENDS_ON_SOMETHING); | 831 bool dependsOnSomething() => getFlag(FLAG_DEPENDS_ON_SOMETHING); |
| 824 void setDependsOnSomething() { setFlag(FLAG_DEPENDS_ON_SOMETHING); } | 832 void setDependsOnSomething() { setFlag(FLAG_DEPENDS_ON_SOMETHING); } |
| 825 | 833 |
| 834 bool dependsOnStatic() => getFlag(FLAG_DEPENDS_ON_STATIC); | |
|
Søren Gjesse
2012/10/01 07:22:20
dependsOnStaticPropertyStore?
ngeoffray
2012/10/04 10:41:42
Done.
| |
| 835 void setDependsOnStatic() { setFlag(FLAG_DEPENDS_ON_STATIC); } | |
| 836 void setChangesStatic() { setFlag(FLAG_CHANGES_STATIC); } | |
| 837 | |
| 838 bool dependsOnIndexStore() => getFlag(FLAG_DEPENDS_ON_INDEX_STORE); | |
| 839 void setDependsOnIndexStore() { setFlag(FLAG_DEPENDS_ON_INDEX_STORE); } | |
| 840 void setChangesIndex() { setFlag(FLAG_CHANGES_INDEX); } | |
| 841 | |
| 842 bool dependsOnPropertyStore() => getFlag(FLAG_DEPENDS_ON_PROPERTY_STORE); | |
| 843 void setDependsOnPropertyStore() { setFlag(FLAG_DEPENDS_ON_PROPERTY_STORE); } | |
| 844 void setChangesProperty() { setFlag(FLAG_CHANGES_PROPERTY); } | |
| 845 | |
| 826 bool useGvn() => getFlag(FLAG_USE_GVN); | 846 bool useGvn() => getFlag(FLAG_USE_GVN); |
| 827 void setUseGvn() { setFlag(FLAG_USE_GVN); } | 847 void setUseGvn() { setFlag(FLAG_USE_GVN); } |
| 828 // Does this node potentially affect control flow. | 848 // Does this node potentially affect control flow. |
| 829 bool isControlFlow() => false; | 849 bool isControlFlow() => false; |
| 830 | 850 |
| 831 // All isFunctions work on the propagated types. | 851 // All isFunctions work on the propagated types. |
| 832 bool isArray(HTypeMap types) => types[this].isArray(); | 852 bool isArray(HTypeMap types) => types[this].isArray(); |
| 833 bool isReadableArray(HTypeMap types) => types[this].isReadableArray(); | 853 bool isReadableArray(HTypeMap types) => types[this].isReadableArray(); |
| 834 bool isMutableArray(HTypeMap types) => types[this].isMutableArray(); | 854 bool isMutableArray(HTypeMap types) => types[this].isMutableArray(); |
| 835 bool isExtendableArray(HTypeMap types) => types[this].isExtendableArray(); | 855 bool isExtendableArray(HTypeMap types) => types[this].isExtendableArray(); |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1291 } | 1311 } |
| 1292 | 1312 |
| 1293 class HInvokeDynamicMethod extends HInvokeDynamic { | 1313 class HInvokeDynamicMethod extends HInvokeDynamic { |
| 1294 HInvokeDynamicMethod(Selector selector, List<HInstruction> inputs) | 1314 HInvokeDynamicMethod(Selector selector, List<HInstruction> inputs) |
| 1295 : super(selector, null, inputs); | 1315 : super(selector, null, inputs); |
| 1296 toString() => 'invoke dynamic method: $selector'; | 1316 toString() => 'invoke dynamic method: $selector'; |
| 1297 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); | 1317 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); |
| 1298 } | 1318 } |
| 1299 | 1319 |
| 1300 class HInvokeDynamicField extends HInvokeDynamic { | 1320 class HInvokeDynamicField extends HInvokeDynamic { |
| 1301 HInvokeDynamicField(Selector selector, Element element, | 1321 final bool isSideEffectFree; |
| 1302 List<HInstruction> inputs) | 1322 HInvokeDynamicField( |
| 1323 Selector selector, Element element, List<HInstruction> inputs, | |
| 1324 this.isSideEffectFree) | |
| 1303 : super(selector, element, inputs); | 1325 : super(selector, element, inputs); |
| 1304 toString() => 'invoke dynamic field: $selector'; | 1326 toString() => 'invoke dynamic field: $selector'; |
| 1305 | 1327 |
| 1306 // TODO(floitsch): make class abstract instead of adding an abstract method. | 1328 // TODO(floitsch): make class abstract instead of adding an abstract method. |
| 1307 abstract accept(HVisitor visitor); | 1329 abstract accept(HVisitor visitor); |
| 1308 } | 1330 } |
| 1309 | 1331 |
| 1310 class HInvokeDynamicGetter extends HInvokeDynamicField { | 1332 class HInvokeDynamicGetter extends HInvokeDynamicField { |
| 1311 final bool isSideEffectFree; | |
| 1312 HInvokeDynamicGetter( | 1333 HInvokeDynamicGetter( |
| 1313 selector, element, receiver, this.isSideEffectFree) | 1334 selector, element, receiver, isSideEffectFree) |
| 1314 : super(selector, element,[receiver]); | 1335 : super(selector, element, [receiver], isSideEffectFree); |
| 1315 toString() => 'invoke dynamic getter: $selector'; | 1336 toString() => 'invoke dynamic getter: $selector'; |
| 1316 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); | 1337 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); |
| 1317 | 1338 |
| 1318 void prepareGvn(HTypeMap types) { | 1339 void prepareGvn(HTypeMap types) { |
| 1319 if (isSideEffectFree) { | 1340 if (isSideEffectFree) { |
| 1320 setUseGvn(); | 1341 setUseGvn(); |
| 1321 clearAllSideEffects(); | 1342 clearAllSideEffects(); |
| 1322 setDependsOnSomething(); | 1343 setDependsOnPropertyStore(); |
| 1323 } else { | 1344 } else { |
| 1324 setAllSideEffects(); | 1345 setAllSideEffects(); |
| 1325 } | 1346 } |
| 1326 } | 1347 } |
| 1327 | 1348 |
| 1328 int typeCode() => HInstruction.INVOKE_DYNAMIC_GETTER_TYPECODE; | 1349 int typeCode() => HInstruction.INVOKE_DYNAMIC_GETTER_TYPECODE; |
| 1329 bool typeEquals(other) => other is HInvokeDynamicGetter; | 1350 bool typeEquals(other) => other is HInvokeDynamicGetter; |
| 1330 bool dataEquals(HInvokeDynamicGetter other) => selector == other.selector; | 1351 bool dataEquals(HInvokeDynamicGetter other) => selector == other.selector; |
| 1331 } | 1352 } |
| 1332 | 1353 |
| 1333 class HInvokeDynamicSetter extends HInvokeDynamicField { | 1354 class HInvokeDynamicSetter extends HInvokeDynamicField { |
| 1334 HInvokeDynamicSetter(selector, element, receiver, value) | 1355 HInvokeDynamicSetter(selector, element, receiver, value, isSideEffectFree) |
| 1335 : super(selector, element, [receiver, value]); | 1356 : super(selector, element, [receiver, value], isSideEffectFree); |
| 1336 toString() => 'invoke dynamic setter: $selector'; | 1357 toString() => 'invoke dynamic setter: $selector'; |
| 1337 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); | 1358 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); |
| 1359 | |
| 1360 void prepareGvn(HTypeMap types) { | |
| 1361 if (isSideEffectFree) { | |
| 1362 setChangesProperty(); | |
| 1363 } else { | |
| 1364 setAllSideEffects(); | |
| 1365 } | |
| 1366 } | |
| 1338 } | 1367 } |
| 1339 | 1368 |
| 1340 class HInvokeStatic extends HInvoke { | 1369 class HInvokeStatic extends HInvoke { |
| 1341 /** The first input must be the target. */ | 1370 /** The first input must be the target. */ |
| 1342 HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) { | 1371 HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) { |
| 1343 guaranteedType = knownType; | 1372 guaranteedType = knownType; |
| 1344 } | 1373 } |
| 1345 | 1374 |
| 1346 toString() => 'invoke static: ${element.name}'; | 1375 toString() => 'invoke static: ${element.name}'; |
| 1347 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); | 1376 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1429 } | 1458 } |
| 1430 | 1459 |
| 1431 void prepareGvn(HTypeMap types) { | 1460 void prepareGvn(HTypeMap types) { |
| 1432 if (isLengthGetterOnStringOrArray(types)) { | 1461 if (isLengthGetterOnStringOrArray(types)) { |
| 1433 setUseGvn(); | 1462 setUseGvn(); |
| 1434 clearAllSideEffects(); | 1463 clearAllSideEffects(); |
| 1435 // If the input is a string, we know the length cannot change. | 1464 // If the input is a string, we know the length cannot change. |
| 1436 // We cannot do the same thing for non-extendable array because | 1465 // We cannot do the same thing for non-extendable array because |
| 1437 // we don't express that type yet: a mutable array might be | 1466 // we don't express that type yet: a mutable array might be |
| 1438 // extendable. | 1467 // extendable. |
| 1439 if (!inputs[1].isString(types)) setDependsOnSomething(); | 1468 if (!inputs[1].isString(types)) setDependsOnPropertyStore(); |
| 1440 } else if (isSideEffectFree) { | 1469 } else if (isSideEffectFree) { |
| 1441 setUseGvn(); | 1470 setUseGvn(); |
| 1442 clearAllSideEffects(); | 1471 clearAllSideEffects(); |
| 1443 setDependsOnSomething(); | 1472 setDependsOnSomething(); |
| 1473 } else if (selector.isGetter()) { | |
| 1474 // Getter interceptors do not have side effects. | |
|
floitsch
2012/10/01 08:40:30
I don't think this is true.
o.length is an HInvoke
ngeoffray
2012/10/01 21:56:10
Right, I was only thinking about getters on primit
| |
| 1475 setUseGvn(); | |
| 1476 clearAllSideEffects(); | |
| 1477 setDependsOnPropertyStore(); | |
| 1444 } else { | 1478 } else { |
| 1445 setAllSideEffects(); | 1479 setAllSideEffects(); |
| 1446 } | 1480 } |
| 1447 } | 1481 } |
| 1448 | 1482 |
| 1449 int typeCode() => HInstruction.INVOKE_INTERCEPTOR_TYPECODE; | 1483 int typeCode() => HInstruction.INVOKE_INTERCEPTOR_TYPECODE; |
| 1450 bool typeEquals(other) => other is HInvokeInterceptor; | 1484 bool typeEquals(other) => other is HInvokeInterceptor; |
| 1451 bool dataEquals(HInvokeInterceptor other) => selector == other.selector; | 1485 bool dataEquals(HInvokeInterceptor other) => selector == other.selector; |
| 1452 } | 1486 } |
| 1453 | 1487 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1468 : element.isAssignable(), | 1502 : element.isAssignable(), |
| 1469 super(element, <HInstruction>[receiver]); | 1503 super(element, <HInstruction>[receiver]); |
| 1470 | 1504 |
| 1471 HInstruction get receiver => inputs[0]; | 1505 HInstruction get receiver => inputs[0]; |
| 1472 | 1506 |
| 1473 accept(HVisitor visitor) => visitor.visitFieldGet(this); | 1507 accept(HVisitor visitor) => visitor.visitFieldGet(this); |
| 1474 | 1508 |
| 1475 void prepareGvn(HTypeMap types) { | 1509 void prepareGvn(HTypeMap types) { |
| 1476 setUseGvn(); | 1510 setUseGvn(); |
| 1477 clearAllSideEffects(); | 1511 clearAllSideEffects(); |
| 1478 if (isAssignable) setDependsOnSomething(); | 1512 if (isAssignable) { |
| 1513 setDependsOnPropertyStore(); | |
| 1514 } | |
| 1479 } | 1515 } |
| 1480 | 1516 |
| 1481 int typeCode() => HInstruction.FIELD_GET_TYPECODE; | 1517 int typeCode() => HInstruction.FIELD_GET_TYPECODE; |
| 1482 bool typeEquals(other) => other is HFieldGet; | 1518 bool typeEquals(other) => other is HFieldGet; |
| 1483 bool dataEquals(HFieldGet other) => element == other.element; | 1519 bool dataEquals(HFieldGet other) => element == other.element; |
| 1484 String toString() => "FieldGet $element"; | 1520 String toString() => "FieldGet $element"; |
| 1485 } | 1521 } |
| 1486 | 1522 |
| 1487 class HFieldSet extends HFieldAccess { | 1523 class HFieldSet extends HFieldAccess { |
| 1488 HFieldSet(Element element, | 1524 HFieldSet(Element element, |
| 1489 HInstruction receiver, | 1525 HInstruction receiver, |
| 1490 HInstruction value) | 1526 HInstruction value) |
| 1491 : super(element, <HInstruction>[receiver, value]); | 1527 : super(element, <HInstruction>[receiver, value]); |
| 1492 | 1528 |
| 1493 HInstruction get receiver => inputs[0]; | 1529 HInstruction get receiver => inputs[0]; |
| 1494 HInstruction get value => inputs[1]; | 1530 HInstruction get value => inputs[1]; |
| 1495 accept(HVisitor visitor) => visitor.visitFieldSet(this); | 1531 accept(HVisitor visitor) => visitor.visitFieldSet(this); |
| 1496 | 1532 |
| 1497 void prepareGvn(HTypeMap types) { | 1533 void prepareGvn(HTypeMap types) { |
| 1498 // TODO(ngeoffray): implement more fine grained side effects. | 1534 setChangesProperty(); |
| 1499 setAllSideEffects(); | |
| 1500 } | 1535 } |
| 1501 | 1536 |
| 1502 bool isJsStatement(HTypeMap types) => true; | 1537 bool isJsStatement(HTypeMap types) => true; |
| 1503 String toString() => "FieldSet $element"; | 1538 String toString() => "FieldSet $element"; |
| 1504 } | 1539 } |
| 1505 | 1540 |
| 1506 class HLocalGet extends HFieldGet { | 1541 class HLocalGet extends HFieldGet { |
| 1507 HLocalGet(Element element, HLocalValue local) : super(element, local); | 1542 HLocalGet(Element element, HLocalValue local) : super(element, local); |
| 1508 | 1543 |
| 1509 accept(HVisitor visitor) => visitor.visitLocalGet(this); | 1544 accept(HVisitor visitor) => visitor.visitLocalGet(this); |
| 1510 | 1545 |
| 1511 HLocalValue get local => inputs[0]; | 1546 HLocalValue get local => inputs[0]; |
| 1512 | |
| 1513 void prepareGvn(HTypeMap types) { | |
| 1514 setUseGvn(); | |
| 1515 // TODO(floitsch): if the variable is not captured then it only depends | |
| 1516 // on assignments to the same variable. Otherwise we need to see if the | |
| 1517 // variable is mutated inside closures. | |
| 1518 setDependsOnSomething(); | |
| 1519 } | |
| 1520 } | 1547 } |
| 1521 | 1548 |
| 1522 class HLocalSet extends HFieldSet { | 1549 class HLocalSet extends HFieldSet { |
| 1523 HLocalSet(Element element, HLocalValue local, HInstruction value) | 1550 HLocalSet(Element element, HLocalValue local, HInstruction value) |
| 1524 : super(element, local, value); | 1551 : super(element, local, value); |
| 1525 | 1552 |
| 1526 accept(HVisitor visitor) => visitor.visitLocalSet(this); | 1553 accept(HVisitor visitor) => visitor.visitLocalSet(this); |
| 1527 | 1554 |
| 1528 HLocalValue get local => inputs[0]; | 1555 HLocalValue get local => inputs[0]; |
| 1529 | |
| 1530 void prepareGvn(HTypeMap types) { | |
| 1531 // TODO(floitsch): implement more fine grained side effects. | |
| 1532 setAllSideEffects(); | |
| 1533 } | |
| 1534 } | 1556 } |
| 1535 | 1557 |
| 1536 class HForeign extends HInstruction { | 1558 class HForeign extends HInstruction { |
| 1537 final DartString code; | 1559 final DartString code; |
| 1538 final HType foreignType; | 1560 final HType foreignType; |
| 1539 final bool _isStatement; | 1561 final bool _isStatement; |
| 1540 | 1562 |
| 1541 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) | 1563 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) |
| 1542 : foreignType = computeTypeFromDeclaredType(declaredType), | 1564 : foreignType = computeTypeFromDeclaredType(declaredType), |
| 1543 _isStatement = false, | 1565 _isStatement = false, |
| (...skipping 827 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2371 class HStatic extends HInstruction { | 2393 class HStatic extends HInstruction { |
| 2372 final Element element; | 2394 final Element element; |
| 2373 HStatic(this.element) : super(<HInstruction>[]) { | 2395 HStatic(this.element) : super(<HInstruction>[]) { |
| 2374 assert(element !== null); | 2396 assert(element !== null); |
| 2375 assert(invariant(this, element.isDeclaration)); | 2397 assert(invariant(this, element.isDeclaration)); |
| 2376 } | 2398 } |
| 2377 | 2399 |
| 2378 void prepareGvn(HTypeMap types) { | 2400 void prepareGvn(HTypeMap types) { |
| 2379 if (!element.isAssignable()) { | 2401 if (!element.isAssignable()) { |
| 2380 clearAllSideEffects(); | 2402 clearAllSideEffects(); |
| 2381 setUseGvn(); | 2403 } else { |
| 2404 setDependsOnStatic(); | |
| 2382 } | 2405 } |
| 2406 setUseGvn(); | |
| 2383 } | 2407 } |
| 2384 toString() => 'static ${element.name}'; | 2408 toString() => 'static ${element.name}'; |
| 2385 accept(HVisitor visitor) => visitor.visitStatic(this); | 2409 accept(HVisitor visitor) => visitor.visitStatic(this); |
| 2386 | 2410 |
| 2387 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); | 2411 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode(); |
| 2388 int typeCode() => HInstruction.STATIC_TYPECODE; | 2412 int typeCode() => HInstruction.STATIC_TYPECODE; |
| 2389 bool typeEquals(other) => other is HStatic; | 2413 bool typeEquals(other) => other is HStatic; |
| 2390 bool dataEquals(HStatic other) => element == other.element; | 2414 bool dataEquals(HStatic other) => element == other.element; |
| 2391 bool isCodeMotionInvariant() => !element.isAssignable(); | 2415 bool isCodeMotionInvariant() => !element.isAssignable(); |
| 2392 } | 2416 } |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 2412 class HStaticStore extends HInstruction { | 2436 class HStaticStore extends HInstruction { |
| 2413 Element element; | 2437 Element element; |
| 2414 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); | 2438 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); |
| 2415 toString() => 'static store ${element.name}'; | 2439 toString() => 'static store ${element.name}'; |
| 2416 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2440 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
| 2417 | 2441 |
| 2418 int typeCode() => HInstruction.STATIC_STORE_TYPECODE; | 2442 int typeCode() => HInstruction.STATIC_STORE_TYPECODE; |
| 2419 bool typeEquals(other) => other is HStaticStore; | 2443 bool typeEquals(other) => other is HStaticStore; |
| 2420 bool dataEquals(HStaticStore other) => element == other.element; | 2444 bool dataEquals(HStaticStore other) => element == other.element; |
| 2421 bool isJsStatement(HTypeMap types) => true; | 2445 bool isJsStatement(HTypeMap types) => true; |
| 2446 | |
| 2447 void prepareGvn(HTypeMap types) { | |
| 2448 setChangesStatic(); | |
| 2449 } | |
| 2422 } | 2450 } |
| 2423 | 2451 |
| 2424 class HLiteralList extends HInstruction { | 2452 class HLiteralList extends HInstruction { |
| 2425 HLiteralList(inputs) : super(inputs); | 2453 HLiteralList(inputs) : super(inputs); |
| 2426 toString() => 'literal list'; | 2454 toString() => 'literal list'; |
| 2427 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2455 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
| 2428 | 2456 |
| 2429 HType get guaranteedType => HType.EXTENDABLE_ARRAY; | 2457 HType get guaranteedType => HType.EXTENDABLE_ARRAY; |
| 2430 | 2458 |
| 2431 void prepareGvn(HTypeMap types) { | 2459 void prepareGvn(HTypeMap types) { |
| 2432 assert(!hasSideEffects(types)); | 2460 assert(!hasSideEffects(types)); |
| 2433 } | 2461 } |
| 2434 } | 2462 } |
| 2435 | 2463 |
| 2436 class HIndex extends HInvokeStatic { | 2464 class HIndex extends HInvokeStatic { |
| 2437 HIndex(HStatic target, HInstruction receiver, HInstruction index) | 2465 HIndex(HStatic target, HInstruction receiver, HInstruction index) |
| 2438 : super(<HInstruction>[target, receiver, index]); | 2466 : super(<HInstruction>[target, receiver, index]); |
| 2439 toString() => 'index operator'; | 2467 toString() => 'index operator'; |
| 2440 accept(HVisitor visitor) => visitor.visitIndex(this); | 2468 accept(HVisitor visitor) => visitor.visitIndex(this); |
| 2441 | 2469 |
| 2442 void prepareGvn(HTypeMap types) { | 2470 void prepareGvn(HTypeMap types) { |
| 2443 if (isBuiltin(types)) { | 2471 if (isBuiltin(types)) { |
| 2444 clearAllSideEffects(); | 2472 clearAllSideEffects(); |
| 2473 setDependsOnIndexStore(); | |
| 2474 setUseGvn(); | |
| 2445 } else { | 2475 } else { |
| 2446 setAllSideEffects(); | 2476 setAllSideEffects(); |
| 2447 } | 2477 } |
| 2448 } | 2478 } |
| 2449 | 2479 |
| 2450 HInstruction get receiver => inputs[1]; | 2480 HInstruction get receiver => inputs[1]; |
| 2451 HInstruction get index => inputs[2]; | 2481 HInstruction get index => inputs[2]; |
| 2452 | 2482 |
| 2453 HType computeDesiredTypeForNonTargetInput(HInstruction input, | 2483 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2454 HTypeMap types) { | 2484 HTypeMap types) { |
| 2455 if (input == receiver && | 2485 if (input == receiver && |
| 2456 (index.isTypeUnknown(types) || index.isNumber(types))) { | 2486 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 2457 return HType.INDEXABLE_PRIMITIVE; | 2487 return HType.INDEXABLE_PRIMITIVE; |
| 2458 } | 2488 } |
| 2459 // The index should be an int when the receiver is a string or array. | 2489 // 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 | 2490 // However it turns out that inserting an integer check in the optimized |
| 2461 // version is cheaper than having another bailout case. This is true, | 2491 // version is cheaper than having another bailout case. This is true, |
| 2462 // because the integer check will simply throw if it fails. | 2492 // because the integer check will simply throw if it fails. |
| 2463 return HType.UNKNOWN; | 2493 return HType.UNKNOWN; |
| 2464 } | 2494 } |
| 2465 | 2495 |
| 2466 bool isBuiltin(HTypeMap types) | 2496 bool isBuiltin(HTypeMap types) |
| 2467 => receiver.isIndexablePrimitive(types) && index.isInteger(types); | 2497 => receiver.isIndexablePrimitive(types) && index.isInteger(types); |
| 2498 | |
| 2499 int typeCode() => HInstruction.INDEX_TYPECODE; | |
| 2500 bool typeEquals(HInstruction other) => other is HIndex; | |
| 2501 bool dataEquals(HIndex other) => true; | |
| 2468 } | 2502 } |
| 2469 | 2503 |
| 2470 class HIndexAssign extends HInvokeStatic { | 2504 class HIndexAssign extends HInvokeStatic { |
| 2471 HIndexAssign(HStatic target, | 2505 HIndexAssign(HStatic target, |
| 2472 HInstruction receiver, | 2506 HInstruction receiver, |
| 2473 HInstruction index, | 2507 HInstruction index, |
| 2474 HInstruction value) | 2508 HInstruction value) |
| 2475 : super(<HInstruction>[target, receiver, index, value]); | 2509 : super(<HInstruction>[target, receiver, index, value]); |
| 2476 toString() => 'index assign operator'; | 2510 toString() => 'index assign operator'; |
| 2477 accept(HVisitor visitor) => visitor.visitIndexAssign(this); | 2511 accept(HVisitor visitor) => visitor.visitIndexAssign(this); |
| 2478 | 2512 |
| 2479 HInstruction get receiver => inputs[1]; | 2513 HInstruction get receiver => inputs[1]; |
| 2480 HInstruction get index => inputs[2]; | 2514 HInstruction get index => inputs[2]; |
| 2481 HInstruction get value => inputs[3]; | 2515 HInstruction get value => inputs[3]; |
| 2482 | 2516 |
| 2517 void prepareGvn(HTypeMap types) { | |
| 2518 if (isBuiltin(types)) { | |
| 2519 setChangesIndex(); | |
| 2520 } else { | |
| 2521 setAllSideEffects(); | |
| 2522 } | |
| 2523 } | |
| 2524 | |
| 2483 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] | 2525 // Note, that we don't have a computeTypeFromInputTypes, since [HIndexAssign] |
| 2484 // is never used as input. | 2526 // is never used as input. |
| 2485 | 2527 |
| 2486 HType computeDesiredTypeForNonTargetInput(HInstruction input, | 2528 HType computeDesiredTypeForNonTargetInput(HInstruction input, |
| 2487 HTypeMap types) { | 2529 HTypeMap types) { |
| 2488 if (input == receiver && | 2530 if (input == receiver && |
| 2489 (index.isTypeUnknown(types) || index.isNumber(types))) { | 2531 (index.isTypeUnknown(types) || index.isNumber(types))) { |
| 2490 return HType.MUTABLE_ARRAY; | 2532 return HType.MUTABLE_ARRAY; |
| 2491 } | 2533 } |
| 2492 // The index should be an int when the receiver is a string or array. | 2534 // 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; | 2959 HBasicBlock get start => expression.start; |
| 2918 HBasicBlock get end { | 2960 HBasicBlock get end { |
| 2919 // We don't create a switch block if there are no cases. | 2961 // We don't create a switch block if there are no cases. |
| 2920 assert(!statements.isEmpty()); | 2962 assert(!statements.isEmpty()); |
| 2921 return statements.last().end; | 2963 return statements.last().end; |
| 2922 } | 2964 } |
| 2923 | 2965 |
| 2924 bool accept(HStatementInformationVisitor visitor) => | 2966 bool accept(HStatementInformationVisitor visitor) => |
| 2925 visitor.visitSwitchInfo(this); | 2967 visitor.visitSwitchInfo(this); |
| 2926 } | 2968 } |
| OLD | NEW |