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 part of ssa; | 5 part of ssa; |
6 | 6 |
7 abstract class HVisitor<R> { | 7 abstract class HVisitor<R> { |
8 R visitAdd(HAdd node); | 8 R visitAdd(HAdd node); |
9 R visitBailoutTarget(HBailoutTarget node); | 9 R visitBailoutTarget(HBailoutTarget node); |
10 R visitBitAnd(HBitAnd node); | 10 R visitBitAnd(HBitAnd node); |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
296 => visitInvokeDynamic(node); | 296 => visitInvokeDynamic(node); |
297 visitInvokeDynamicMethod(HInvokeDynamicMethod node) | 297 visitInvokeDynamicMethod(HInvokeDynamicMethod node) |
298 => visitInvokeDynamic(node); | 298 => visitInvokeDynamic(node); |
299 visitInvokeDynamicGetter(HInvokeDynamicGetter node) | 299 visitInvokeDynamicGetter(HInvokeDynamicGetter node) |
300 => visitInvokeDynamicField(node); | 300 => visitInvokeDynamicField(node); |
301 visitInvokeDynamicSetter(HInvokeDynamicSetter node) | 301 visitInvokeDynamicSetter(HInvokeDynamicSetter node) |
302 => visitInvokeDynamicField(node); | 302 => visitInvokeDynamicField(node); |
303 visitInvokeStatic(HInvokeStatic node) => visitInvoke(node); | 303 visitInvokeStatic(HInvokeStatic node) => visitInvoke(node); |
304 visitInvokeSuper(HInvokeSuper node) => visitInvoke(node); | 304 visitInvokeSuper(HInvokeSuper node) => visitInvoke(node); |
305 visitJump(HJump node) => visitControlFlow(node); | 305 visitJump(HJump node) => visitControlFlow(node); |
306 visitLazyStatic(HLazyStatic node) => visitStatic(node); | 306 visitLazyStatic(HLazyStatic node) => visitInstruction(node); |
307 visitLess(HLess node) => visitRelational(node); | 307 visitLess(HLess node) => visitRelational(node); |
308 visitLessEqual(HLessEqual node) => visitRelational(node); | 308 visitLessEqual(HLessEqual node) => visitRelational(node); |
309 visitLiteralList(HLiteralList node) => visitInstruction(node); | 309 visitLiteralList(HLiteralList node) => visitInstruction(node); |
310 visitLocalGet(HLocalGet node) => visitFieldGet(node); | 310 visitLocalGet(HLocalGet node) => visitFieldAccess(node); |
311 visitLocalSet(HLocalSet node) => visitFieldSet(node); | 311 visitLocalSet(HLocalSet node) => visitFieldAccess(node); |
312 visitLocalValue(HLocalValue node) => visitInstruction(node); | 312 visitLocalValue(HLocalValue node) => visitInstruction(node); |
313 visitLoopBranch(HLoopBranch node) => visitConditionalBranch(node); | 313 visitLoopBranch(HLoopBranch node) => visitConditionalBranch(node); |
314 visitNegate(HNegate node) => visitInvokeUnary(node); | 314 visitNegate(HNegate node) => visitInvokeUnary(node); |
315 visitNot(HNot node) => visitInstruction(node); | 315 visitNot(HNot node) => visitInstruction(node); |
316 visitPhi(HPhi node) => visitInstruction(node); | 316 visitPhi(HPhi node) => visitInstruction(node); |
317 visitMultiply(HMultiply node) => visitBinaryArithmetic(node); | 317 visitMultiply(HMultiply node) => visitBinaryArithmetic(node); |
318 visitParameterValue(HParameterValue node) => visitLocalValue(node); | 318 visitParameterValue(HParameterValue node) => visitLocalValue(node); |
319 visitRangeConversion(HRangeConversion node) => visitCheck(node); | 319 visitRangeConversion(HRangeConversion node) => visitCheck(node); |
320 visitReturn(HReturn node) => visitControlFlow(node); | 320 visitReturn(HReturn node) => visitControlFlow(node); |
321 visitShiftLeft(HShiftLeft node) => visitBinaryBitOp(node); | 321 visitShiftLeft(HShiftLeft node) => visitBinaryBitOp(node); |
(...skipping 463 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
785 static const int LESS_EQUAL_TYPECODE = 24; | 785 static const int LESS_EQUAL_TYPECODE = 24; |
786 static const int STATIC_TYPECODE = 25; | 786 static const int STATIC_TYPECODE = 25; |
787 static const int STATIC_STORE_TYPECODE = 26; | 787 static const int STATIC_STORE_TYPECODE = 26; |
788 static const int FIELD_GET_TYPECODE = 27; | 788 static const int FIELD_GET_TYPECODE = 27; |
789 static const int TYPE_CONVERSION_TYPECODE = 28; | 789 static const int TYPE_CONVERSION_TYPECODE = 28; |
790 static const int BAILOUT_TARGET_TYPECODE = 29; | 790 static const int BAILOUT_TARGET_TYPECODE = 29; |
791 static const int INVOKE_STATIC_TYPECODE = 30; | 791 static const int INVOKE_STATIC_TYPECODE = 30; |
792 static const int INVOKE_DYNAMIC_GETTER_TYPECODE = 31; | 792 static const int INVOKE_DYNAMIC_GETTER_TYPECODE = 31; |
793 static const int INDEX_TYPECODE = 32; | 793 static const int INDEX_TYPECODE = 32; |
794 | 794 |
795 HInstruction(this.inputs) | 795 HInstruction(this.inputs) : id = idCounter++, usedBy = <HInstruction>[]; |
796 : id = idCounter++, | |
797 usedBy = <HInstruction>[]; | |
798 | 796 |
799 int get hashCode => id; | 797 int get hashCode => id; |
800 | 798 |
801 bool getFlag(int position) => (flags & (1 << position)) != 0; | 799 bool getFlag(int position) => (flags & (1 << position)) != 0; |
802 void setFlag(int position) { flags |= (1 << position); } | 800 void setFlag(int position) { flags |= (1 << position); } |
803 void clearFlag(int position) { flags &= ~(1 << position); } | 801 void clearFlag(int position) { flags &= ~(1 << position); } |
804 | 802 |
805 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; | 803 static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT; |
806 | 804 |
807 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); | 805 int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1); |
808 int getDependsOnFlags() { | 806 int getDependsOnFlags() { |
809 return (flags & ((1 << FLAG_DEPENDS_ON_COUNT) - 1)) >> FLAG_CHANGES_COUNT; | 807 return (flags & ((1 << FLAG_DEPENDS_ON_COUNT) - 1)) >> FLAG_CHANGES_COUNT; |
810 } | 808 } |
811 | 809 |
812 bool hasSideEffects() => getChangesFlags() != 0; | 810 bool hasSideEffects() => getChangesFlags() != 0; |
813 bool dependsOnSomething() => getDependsOnFlags() != 0; | 811 bool dependsOnSomething() => getDependsOnFlags() != 0; |
814 | 812 |
815 void prepareGvn(HTypeMap types) { | |
816 setAllSideEffects(); | |
817 setDependsOnSomething(); | |
818 } | |
819 | |
820 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } | 813 void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); } |
821 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } | 814 void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); } |
822 | 815 |
823 void setDependsOnSomething() { | 816 void setDependsOnSomething() { |
824 int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT; | 817 int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT; |
825 flags |= (((1 << count) - 1) << FLAG_CHANGES_COUNT); | 818 flags |= (((1 << count) - 1) << FLAG_CHANGES_COUNT); |
826 } | 819 } |
| 820 void clearAllDependencies() { |
| 821 int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT; |
| 822 flags &= ~(((1 << count) - 1) << FLAG_CHANGES_COUNT); |
| 823 } |
827 | 824 |
828 bool dependsOnStaticPropertyStore() { | 825 bool dependsOnStaticPropertyStore() { |
829 return getFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE); | 826 return getFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE); |
830 } | 827 } |
831 void setDependsOnStaticPropertyStore() { | 828 void setDependsOnStaticPropertyStore() { |
832 setFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE); | 829 setFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE); |
833 } | 830 } |
834 void setChangesStaticProperty() { setFlag(FLAG_CHANGES_STATIC_PROPERTY); } | 831 void setChangesStaticProperty() { setFlag(FLAG_CHANGES_STATIC_PROPERTY); } |
835 | 832 |
836 bool dependsOnIndexStore() => getFlag(FLAG_DEPENDS_ON_INDEX_STORE); | 833 bool dependsOnIndexStore() => getFlag(FLAG_DEPENDS_ON_INDEX_STORE); |
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1154 // [convertedType] as a bound. | 1151 // [convertedType] as a bound. |
1155 if (this.guaranteedType == convertedType) { | 1152 if (this.guaranteedType == convertedType) { |
1156 return this; | 1153 return this; |
1157 } | 1154 } |
1158 | 1155 |
1159 return new HTypeConversion(convertedType, this, kind); | 1156 return new HTypeConversion(convertedType, this, kind); |
1160 } | 1157 } |
1161 } | 1158 } |
1162 | 1159 |
1163 class HBoolify extends HInstruction { | 1160 class HBoolify extends HInstruction { |
1164 HBoolify(HInstruction value) : super(<HInstruction>[value]); | 1161 HBoolify(HInstruction value) : super(<HInstruction>[value]) { |
1165 void prepareGvn(HTypeMap types) { | |
1166 assert(!hasSideEffects()); | 1162 assert(!hasSideEffects()); |
1167 setUseGvn(); | 1163 setUseGvn(); |
1168 } | 1164 } |
1169 | 1165 |
1170 HType get guaranteedType => HType.BOOLEAN; | 1166 HType get guaranteedType => HType.BOOLEAN; |
1171 | 1167 |
1172 accept(HVisitor visitor) => visitor.visitBoolify(this); | 1168 accept(HVisitor visitor) => visitor.visitBoolify(this); |
1173 int typeCode() => HInstruction.BOOLIFY_TYPECODE; | 1169 int typeCode() => HInstruction.BOOLIFY_TYPECODE; |
1174 bool typeEquals(other) => other is HBoolify; | 1170 bool typeEquals(other) => other is HBoolify; |
1175 bool dataEquals(HInstruction other) => true; | 1171 bool dataEquals(HInstruction other) => true; |
1176 } | 1172 } |
1177 | 1173 |
1178 /** | 1174 /** |
1179 * A [HCheck] instruction is an instruction that might do a dynamic | 1175 * A [HCheck] instruction is an instruction that might do a dynamic |
1180 * check at runtime on another instruction. To have proper instruction | 1176 * check at runtime on another instruction. To have proper instruction |
1181 * dependencies in the graph, instructions that depend on the check | 1177 * dependencies in the graph, instructions that depend on the check |
1182 * being done reference the [HCheck] instruction instead of the | 1178 * being done reference the [HCheck] instruction instead of the |
1183 * instruction itself. | 1179 * instruction itself. |
1184 */ | 1180 */ |
1185 abstract class HCheck extends HInstruction { | 1181 abstract class HCheck extends HInstruction { |
1186 HCheck(inputs) : super(inputs); | 1182 HCheck(inputs) : super(inputs) { |
1187 HInstruction get checkedInput => inputs[0]; | |
1188 bool isJsStatement() => true; | |
1189 void prepareGvn(HTypeMap types) { | |
1190 assert(!hasSideEffects()); | 1183 assert(!hasSideEffects()); |
1191 setUseGvn(); | 1184 setUseGvn(); |
1192 } | 1185 } |
| 1186 HInstruction get checkedInput => inputs[0]; |
| 1187 bool isJsStatement() => true; |
1193 bool canThrow() => true; | 1188 bool canThrow() => true; |
1194 } | 1189 } |
1195 | 1190 |
1196 class HBailoutTarget extends HInstruction { | 1191 class HBailoutTarget extends HInstruction { |
1197 final int state; | 1192 final int state; |
1198 bool isEnabled = true; | 1193 bool isEnabled = true; |
1199 HBailoutTarget(this.state) : super(<HInstruction>[]); | 1194 HBailoutTarget(this.state) : super(<HInstruction>[]) { |
1200 void prepareGvn(HTypeMap types) { | |
1201 assert(!hasSideEffects()); | 1195 assert(!hasSideEffects()); |
1202 setUseGvn(); | 1196 setUseGvn(); |
1203 } | 1197 } |
1204 | 1198 |
1205 bool isControlFlow() => isEnabled; | 1199 bool isControlFlow() => isEnabled; |
1206 bool isJsStatement() => isEnabled; | 1200 bool isJsStatement() => isEnabled; |
1207 | 1201 |
1208 accept(HVisitor visitor) => visitor.visitBailoutTarget(this); | 1202 accept(HVisitor visitor) => visitor.visitBailoutTarget(this); |
1209 int typeCode() => HInstruction.BAILOUT_TARGET_TYPECODE; | 1203 int typeCode() => HInstruction.BAILOUT_TARGET_TYPECODE; |
1210 bool typeEquals(other) => other is HBailoutTarget; | 1204 bool typeEquals(other) => other is HBailoutTarget; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1293 | 1287 |
1294 abstract class HConditionalBranch extends HControlFlow { | 1288 abstract class HConditionalBranch extends HControlFlow { |
1295 HConditionalBranch(inputs) : super(inputs); | 1289 HConditionalBranch(inputs) : super(inputs); |
1296 HInstruction get condition => inputs[0]; | 1290 HInstruction get condition => inputs[0]; |
1297 HBasicBlock get trueBranch => block.successors[0]; | 1291 HBasicBlock get trueBranch => block.successors[0]; |
1298 HBasicBlock get falseBranch => block.successors[1]; | 1292 HBasicBlock get falseBranch => block.successors[1]; |
1299 } | 1293 } |
1300 | 1294 |
1301 abstract class HControlFlow extends HInstruction { | 1295 abstract class HControlFlow extends HInstruction { |
1302 HControlFlow(inputs) : super(inputs); | 1296 HControlFlow(inputs) : super(inputs); |
1303 void prepareGvn(HTypeMap types) { | |
1304 // Control flow does not have side-effects. | |
1305 } | |
1306 bool isControlFlow() => true; | 1297 bool isControlFlow() => true; |
1307 bool isJsStatement() => true; | 1298 bool isJsStatement() => true; |
1308 } | 1299 } |
1309 | 1300 |
1310 abstract class HInvoke extends HInstruction { | 1301 abstract class HInvoke extends HInstruction { |
1311 /** | 1302 /** |
1312 * The first argument must be the target: either an [HStatic] node, or | 1303 * The first argument must be the target: either an [HStatic] node, or |
1313 * the receiver of a method-call. The remaining inputs are the arguments | 1304 * the receiver of a method-call. The remaining inputs are the arguments |
1314 * to the invocation. | 1305 * to the invocation. |
1315 */ | 1306 */ |
1316 HInvoke(List<HInstruction> inputs) : super(inputs); | 1307 HInvoke(List<HInstruction> inputs) : super(inputs) { |
| 1308 setAllSideEffects(); |
| 1309 setDependsOnSomething(); |
| 1310 } |
1317 static const int ARGUMENTS_OFFSET = 1; | 1311 static const int ARGUMENTS_OFFSET = 1; |
1318 bool canThrow() => true; | 1312 bool canThrow() => true; |
1319 } | 1313 } |
1320 | 1314 |
1321 abstract class HInvokeDynamic extends HInvoke { | 1315 abstract class HInvokeDynamic extends HInvoke { |
1322 final Selector selector; | 1316 final Selector selector; |
1323 Element element; | 1317 Element element; |
1324 | 1318 |
1325 HInvokeDynamic(this.selector, this.element, List<HInstruction> inputs) | 1319 HInvokeDynamic(this.selector, this.element, List<HInstruction> inputs) |
1326 : super(inputs); | 1320 : super(inputs); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1376 abstract class HInvokeDynamicField extends HInvokeDynamic { | 1370 abstract class HInvokeDynamicField extends HInvokeDynamic { |
1377 final bool isSideEffectFree; | 1371 final bool isSideEffectFree; |
1378 HInvokeDynamicField( | 1372 HInvokeDynamicField( |
1379 Selector selector, Element element, List<HInstruction> inputs, | 1373 Selector selector, Element element, List<HInstruction> inputs, |
1380 this.isSideEffectFree) | 1374 this.isSideEffectFree) |
1381 : super(selector, element, inputs); | 1375 : super(selector, element, inputs); |
1382 toString() => 'invoke dynamic field: $selector'; | 1376 toString() => 'invoke dynamic field: $selector'; |
1383 } | 1377 } |
1384 | 1378 |
1385 class HInvokeDynamicGetter extends HInvokeDynamicField { | 1379 class HInvokeDynamicGetter extends HInvokeDynamicField { |
1386 HInvokeDynamicGetter( | 1380 HInvokeDynamicGetter(selector, element, receiver, isSideEffectFree) |
1387 selector, element, receiver, isSideEffectFree) | 1381 : super(selector, element, [receiver], isSideEffectFree) { |
1388 : super(selector, element, [receiver], isSideEffectFree); | |
1389 toString() => 'invoke dynamic getter: $selector'; | |
1390 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); | |
1391 | |
1392 void prepareGvn(HTypeMap types) { | |
1393 clearAllSideEffects(); | 1382 clearAllSideEffects(); |
1394 if (isSideEffectFree) { | 1383 if (isSideEffectFree) { |
1395 setUseGvn(); | 1384 setUseGvn(); |
1396 setDependsOnInstancePropertyStore(); | 1385 setDependsOnInstancePropertyStore(); |
1397 } else { | 1386 } else { |
1398 setDependsOnSomething(); | 1387 setDependsOnSomething(); |
1399 setAllSideEffects(); | 1388 setAllSideEffects(); |
1400 } | 1389 } |
1401 } | 1390 } |
| 1391 toString() => 'invoke dynamic getter: $selector'; |
| 1392 accept(HVisitor visitor) => visitor.visitInvokeDynamicGetter(this); |
1402 | 1393 |
1403 int typeCode() => HInstruction.INVOKE_DYNAMIC_GETTER_TYPECODE; | 1394 int typeCode() => HInstruction.INVOKE_DYNAMIC_GETTER_TYPECODE; |
1404 bool typeEquals(other) => other is HInvokeDynamicGetter; | 1395 bool typeEquals(other) => other is HInvokeDynamicGetter; |
1405 bool dataEquals(HInvokeDynamicGetter other) => selector == other.selector; | 1396 bool dataEquals(HInvokeDynamicGetter other) => selector == other.selector; |
1406 } | 1397 } |
1407 | 1398 |
1408 class HInvokeDynamicSetter extends HInvokeDynamicField { | 1399 class HInvokeDynamicSetter extends HInvokeDynamicField { |
1409 HInvokeDynamicSetter(selector, element, receiver, value, isSideEffectFree) | 1400 HInvokeDynamicSetter(selector, element, receiver, value, isSideEffectFree) |
1410 : super(selector, element, [receiver, value], isSideEffectFree); | 1401 : super(selector, element, [receiver, value], isSideEffectFree) { |
1411 toString() => 'invoke dynamic setter: $selector'; | |
1412 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); | |
1413 | |
1414 void prepareGvn(HTypeMap types) { | |
1415 clearAllSideEffects(); | 1402 clearAllSideEffects(); |
1416 if (isSideEffectFree) { | 1403 if (isSideEffectFree) { |
1417 setChangesInstanceProperty(); | 1404 setChangesInstanceProperty(); |
1418 } else { | 1405 } else { |
1419 setAllSideEffects(); | 1406 setAllSideEffects(); |
1420 setDependsOnSomething(); | 1407 setDependsOnSomething(); |
1421 } | 1408 } |
1422 } | 1409 } |
| 1410 toString() => 'invoke dynamic setter: $selector'; |
| 1411 accept(HVisitor visitor) => visitor.visitInvokeDynamicSetter(this); |
1423 } | 1412 } |
1424 | 1413 |
1425 class HInvokeStatic extends HInvoke { | 1414 class HInvokeStatic extends HInvoke { |
1426 /** The first input must be the target. */ | 1415 /** The first input must be the target. */ |
1427 HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) { | 1416 HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) { |
1428 guaranteedType = knownType; | 1417 guaranteedType = knownType; |
1429 } | 1418 } |
1430 | 1419 |
1431 toString() => 'invoke static: ${element.name}'; | 1420 toString() => 'invoke static: ${element.name}'; |
1432 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); | 1421 accept(HVisitor visitor) => visitor.visitInvokeStatic(this); |
1433 int typeCode() => HInstruction.INVOKE_STATIC_TYPECODE; | 1422 int typeCode() => HInstruction.INVOKE_STATIC_TYPECODE; |
1434 Element get element => target.element; | 1423 Element get element => target.element; |
1435 HStatic get target => inputs[0]; | 1424 HStatic get target => inputs[0]; |
1436 | |
1437 HType computeDesiredTypeForInput(HInstruction input, | |
1438 HTypeMap types, | |
1439 Compiler compiler) { | |
1440 // TODO(floitsch): we want the target to be a function. | |
1441 if (input == target) return HType.UNKNOWN; | |
1442 return computeDesiredTypeForNonTargetInput(input, types, compiler); | |
1443 } | |
1444 | |
1445 HType computeDesiredTypeForNonTargetInput(HInstruction input, | |
1446 HTypeMap types, | |
1447 Compiler compiler) { | |
1448 return HType.UNKNOWN; | |
1449 } | |
1450 } | 1425 } |
1451 | 1426 |
1452 class HInvokeSuper extends HInvokeStatic { | 1427 class HInvokeSuper extends HInvokeStatic { |
1453 final bool isSetter; | 1428 final bool isSetter; |
1454 HInvokeSuper(inputs, {this.isSetter: false}) : super(inputs); | 1429 HInvokeSuper(inputs, {this.isSetter: false}) : super(inputs); |
1455 toString() => 'invoke super: ${element.name}'; | 1430 toString() => 'invoke super: ${element.name}'; |
1456 accept(HVisitor visitor) => visitor.visitInvokeSuper(this); | 1431 accept(HVisitor visitor) => visitor.visitInvokeSuper(this); |
1457 | 1432 |
1458 HInstruction get value { | 1433 HInstruction get value { |
1459 assert(isSetter); | 1434 assert(isSetter); |
1460 // Index 0: the element, index 1: 'this'. | 1435 // Index 0: the element, index 1: 'this'. |
1461 return inputs[2]; | 1436 return inputs[2]; |
1462 } | 1437 } |
1463 } | 1438 } |
1464 | 1439 |
1465 abstract class HFieldAccess extends HInstruction { | 1440 abstract class HFieldAccess extends HInstruction { |
1466 final Element element; | 1441 final Element element; |
1467 | 1442 |
1468 HFieldAccess(Element element, List<HInstruction> inputs) | 1443 HFieldAccess(Element element, List<HInstruction> inputs) |
1469 : this.element = element, | 1444 : this.element = element, super(inputs); |
1470 super(inputs); | |
1471 | 1445 |
1472 // TODO(ngeoffray): Only if input can be null. | 1446 HInstruction get receiver => inputs[0]; |
1473 bool canThrow() => true; | |
1474 } | 1447 } |
1475 | 1448 |
1476 class HFieldGet extends HFieldAccess { | 1449 class HFieldGet extends HFieldAccess { |
1477 final bool isAssignable; | 1450 final bool isAssignable; |
1478 | 1451 |
1479 HFieldGet(Element element, HInstruction receiver, {bool isAssignable}) | 1452 HFieldGet(Element element, HInstruction receiver, {bool isAssignable}) |
1480 : this.isAssignable = (isAssignable != null) | 1453 : this.isAssignable = (isAssignable != null) |
1481 ? isAssignable | 1454 ? isAssignable |
1482 : element.isAssignable(), | 1455 : element.isAssignable(), |
1483 super(element, <HInstruction>[receiver]); | 1456 super(element, <HInstruction>[receiver]) { |
1484 | |
1485 HInstruction get receiver => inputs[0]; | |
1486 | |
1487 accept(HVisitor visitor) => visitor.visitFieldGet(this); | |
1488 | |
1489 void prepareGvn(HTypeMap types) { | |
1490 clearAllSideEffects(); | 1457 clearAllSideEffects(); |
1491 setUseGvn(); | 1458 setUseGvn(); |
1492 if (isAssignable) { | 1459 if (this.isAssignable) { |
1493 setDependsOnInstancePropertyStore(); | 1460 setDependsOnInstancePropertyStore(); |
1494 } | 1461 } |
1495 } | 1462 } |
1496 | 1463 |
| 1464 // TODO(ngeoffray): Only if input can be null. |
| 1465 bool canThrow() => true; |
| 1466 |
| 1467 accept(HVisitor visitor) => visitor.visitFieldGet(this); |
| 1468 |
1497 int typeCode() => HInstruction.FIELD_GET_TYPECODE; | 1469 int typeCode() => HInstruction.FIELD_GET_TYPECODE; |
1498 bool typeEquals(other) => other is HFieldGet; | 1470 bool typeEquals(other) => other is HFieldGet; |
1499 bool dataEquals(HFieldGet other) => element == other.element; | 1471 bool dataEquals(HFieldGet other) => element == other.element; |
1500 String toString() => "FieldGet $element"; | 1472 String toString() => "FieldGet $element"; |
1501 } | 1473 } |
1502 | 1474 |
1503 class HFieldSet extends HFieldAccess { | 1475 class HFieldSet extends HFieldAccess { |
1504 HFieldSet(Element element, | 1476 HFieldSet(Element element, |
1505 HInstruction receiver, | 1477 HInstruction receiver, |
1506 HInstruction value) | 1478 HInstruction value) |
1507 : super(element, <HInstruction>[receiver, value]); | 1479 : super(element, <HInstruction>[receiver, value]) { |
1508 | |
1509 HInstruction get receiver => inputs[0]; | |
1510 HInstruction get value => inputs[1]; | |
1511 accept(HVisitor visitor) => visitor.visitFieldSet(this); | |
1512 | |
1513 void prepareGvn(HTypeMap types) { | |
1514 clearAllSideEffects(); | 1480 clearAllSideEffects(); |
1515 setChangesInstanceProperty(); | 1481 setChangesInstanceProperty(); |
1516 } | 1482 } |
1517 | 1483 |
| 1484 // TODO(ngeoffray): Only if input can be null. |
| 1485 bool canThrow() => true; |
| 1486 |
| 1487 HInstruction get value => inputs[1]; |
| 1488 accept(HVisitor visitor) => visitor.visitFieldSet(this); |
| 1489 |
1518 bool isJsStatement() => true; | 1490 bool isJsStatement() => true; |
1519 String toString() => "FieldSet $element"; | 1491 String toString() => "FieldSet $element"; |
1520 } | 1492 } |
1521 | 1493 |
1522 class HLocalGet extends HFieldGet { | 1494 class HLocalGet extends HFieldAccess { |
1523 HLocalGet(Element element, HLocalValue local) : super(element, local); | 1495 // No need to use GVN for a [HLocalGet], it is just a local |
| 1496 // access. |
| 1497 HLocalGet(Element element, HLocalValue local) |
| 1498 : super(element, <HInstruction>[local]); |
1524 | 1499 |
1525 accept(HVisitor visitor) => visitor.visitLocalGet(this); | 1500 accept(HVisitor visitor) => visitor.visitLocalGet(this); |
1526 | 1501 |
1527 HLocalValue get local => inputs[0]; | 1502 HLocalValue get local => inputs[0]; |
1528 | |
1529 void prepareGvn(HTypeMap types) { | |
1530 // No need to use GVN for a [HLocalGet], it is just a local | |
1531 // access. | |
1532 clearAllSideEffects(); | |
1533 } | |
1534 } | 1503 } |
1535 | 1504 |
1536 class HLocalSet extends HFieldSet { | 1505 class HLocalSet extends HFieldAccess { |
1537 HLocalSet(Element element, HLocalValue local, HInstruction value) | 1506 HLocalSet(Element element, HLocalValue local, HInstruction value) |
1538 : super(element, local, value); | 1507 : super(element, <HInstruction>[local, value]); |
1539 | 1508 |
1540 accept(HVisitor visitor) => visitor.visitLocalSet(this); | 1509 accept(HVisitor visitor) => visitor.visitLocalSet(this); |
1541 | 1510 |
1542 HLocalValue get local => inputs[0]; | 1511 HLocalValue get local => inputs[0]; |
| 1512 HInstruction get value => inputs[1]; |
| 1513 bool isJsStatement() => true; |
1543 } | 1514 } |
1544 | 1515 |
1545 class HForeign extends HInstruction { | 1516 class HForeign extends HInstruction { |
1546 final DartString code; | 1517 final DartString code; |
1547 final HType foreignType; | 1518 final HType foreignType; |
1548 final bool _isStatement; | 1519 final bool isStatement; |
1549 | 1520 |
1550 HForeign(this.code, DartString declaredType, List<HInstruction> inputs) | 1521 HForeign(this.code, |
| 1522 DartString declaredType, |
| 1523 List<HInstruction> inputs, |
| 1524 {this.isStatement: false}) |
1551 : foreignType = computeTypeFromDeclaredType(declaredType), | 1525 : foreignType = computeTypeFromDeclaredType(declaredType), |
1552 _isStatement = false, | 1526 super(inputs) { |
1553 super(inputs); | 1527 setAllSideEffects(); |
1554 HForeign.statement(this.code, List<HInstruction> inputs) | 1528 setDependsOnSomething(); |
1555 : foreignType = HType.UNKNOWN, | 1529 } |
1556 _isStatement = true, | 1530 |
1557 super(inputs); | 1531 HForeign.statement(code, List<HInstruction> inputs) |
| 1532 : this(code, const LiteralDartString('var'), input, isStatement: true); |
| 1533 |
1558 accept(HVisitor visitor) => visitor.visitForeign(this); | 1534 accept(HVisitor visitor) => visitor.visitForeign(this); |
1559 | 1535 |
1560 static HType computeTypeFromDeclaredType(DartString declaredType) { | 1536 static HType computeTypeFromDeclaredType(DartString declaredType) { |
1561 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; | 1537 if (declaredType.slowToString() == 'bool') return HType.BOOLEAN; |
1562 if (declaredType.slowToString() == 'int') return HType.INTEGER; | 1538 if (declaredType.slowToString() == 'int') return HType.INTEGER; |
1563 if (declaredType.slowToString() == 'double') return HType.DOUBLE; | 1539 if (declaredType.slowToString() == 'double') return HType.DOUBLE; |
1564 if (declaredType.slowToString() == 'num') return HType.NUMBER; | 1540 if (declaredType.slowToString() == 'num') return HType.NUMBER; |
1565 if (declaredType.slowToString() == 'String') return HType.STRING; | 1541 if (declaredType.slowToString() == 'String') return HType.STRING; |
1566 if (declaredType.slowToString() == '=List') return HType.READABLE_ARRAY; | 1542 if (declaredType.slowToString() == '=List') return HType.READABLE_ARRAY; |
1567 return HType.UNKNOWN; | 1543 return HType.UNKNOWN; |
1568 } | 1544 } |
1569 | 1545 |
1570 HType get guaranteedType => foreignType; | 1546 HType get guaranteedType => foreignType; |
1571 | 1547 |
1572 bool isJsStatement() => _isStatement; | 1548 bool isJsStatement() => isStatement; |
1573 bool canThrow() => true; | 1549 bool canThrow() => true; |
1574 | 1550 |
1575 } | 1551 } |
1576 | 1552 |
1577 class HForeignNew extends HForeign { | 1553 class HForeignNew extends HForeign { |
1578 ClassElement element; | 1554 ClassElement element; |
1579 HForeignNew(this.element, List<HInstruction> inputs) | 1555 HForeignNew(this.element, List<HInstruction> inputs) |
1580 : super(const LiteralDartString("new"), | 1556 : super(const LiteralDartString("new"), |
1581 const LiteralDartString("Object"), inputs); | 1557 const LiteralDartString("Object"), inputs); |
1582 accept(HVisitor visitor) => visitor.visitForeignNew(this); | 1558 accept(HVisitor visitor) => visitor.visitForeignNew(this); |
1583 } | 1559 } |
1584 | 1560 |
1585 abstract class HInvokeBinary extends HInstruction { | 1561 abstract class HInvokeBinary extends HInstruction { |
1586 HInvokeBinary(HInstruction left, HInstruction right) | 1562 HInvokeBinary(HInstruction left, HInstruction right) |
1587 : super(<HInstruction>[left, right]); | 1563 : super(<HInstruction>[left, right]) { |
1588 | |
1589 void prepareGvn(HTypeMap types) { | |
1590 clearAllSideEffects(); | 1564 clearAllSideEffects(); |
1591 setUseGvn(); | 1565 setUseGvn(); |
1592 } | 1566 } |
1593 | 1567 |
1594 HInstruction get left => inputs[0]; | 1568 HInstruction get left => inputs[0]; |
1595 HInstruction get right => inputs[1]; | 1569 HInstruction get right => inputs[1]; |
1596 | 1570 |
1597 BinaryOperation operation(ConstantSystem constantSystem); | 1571 BinaryOperation operation(ConstantSystem constantSystem); |
1598 } | 1572 } |
1599 | 1573 |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1723 accept(HVisitor visitor) => visitor.visitBitXor(this); | 1697 accept(HVisitor visitor) => visitor.visitBitXor(this); |
1724 | 1698 |
1725 BinaryOperation operation(ConstantSystem constantSystem) | 1699 BinaryOperation operation(ConstantSystem constantSystem) |
1726 => constantSystem.bitXor; | 1700 => constantSystem.bitXor; |
1727 int typeCode() => HInstruction.BIT_XOR_TYPECODE; | 1701 int typeCode() => HInstruction.BIT_XOR_TYPECODE; |
1728 bool typeEquals(other) => other is HBitXor; | 1702 bool typeEquals(other) => other is HBitXor; |
1729 bool dataEquals(HInstruction other) => true; | 1703 bool dataEquals(HInstruction other) => true; |
1730 } | 1704 } |
1731 | 1705 |
1732 abstract class HInvokeUnary extends HInstruction { | 1706 abstract class HInvokeUnary extends HInstruction { |
1733 HInvokeUnary(HInstruction input) : super(<HInstruction>[input]); | 1707 HInvokeUnary(HInstruction input) : super(<HInstruction>[input]) { |
1734 | |
1735 HInstruction get operand => inputs[0]; | |
1736 | |
1737 void prepareGvn(HTypeMap types) { | |
1738 clearAllSideEffects(); | 1708 clearAllSideEffects(); |
1739 setUseGvn(); | 1709 setUseGvn(); |
1740 } | 1710 } |
1741 | 1711 |
| 1712 HInstruction get operand => inputs[0]; |
| 1713 |
1742 UnaryOperation operation(ConstantSystem constantSystem); | 1714 UnaryOperation operation(ConstantSystem constantSystem); |
1743 } | 1715 } |
1744 | 1716 |
1745 class HNegate extends HInvokeUnary { | 1717 class HNegate extends HInvokeUnary { |
1746 HNegate(HInstruction input) : super(input); | 1718 HNegate(HInstruction input) : super(input); |
1747 accept(HVisitor visitor) => visitor.visitNegate(this); | 1719 accept(HVisitor visitor) => visitor.visitNegate(this); |
1748 | 1720 |
1749 HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { | 1721 HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { |
1750 return types[operand]; | 1722 return types[operand]; |
1751 } | 1723 } |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1858 return identical(kind, DO_WHILE_LOOP); | 1830 return identical(kind, DO_WHILE_LOOP); |
1859 } | 1831 } |
1860 } | 1832 } |
1861 | 1833 |
1862 class HConstant extends HInstruction { | 1834 class HConstant extends HInstruction { |
1863 final Constant constant; | 1835 final Constant constant; |
1864 final HType constantType; | 1836 final HType constantType; |
1865 HConstant.internal(this.constant, HType this.constantType) | 1837 HConstant.internal(this.constant, HType this.constantType) |
1866 : super(<HInstruction>[]); | 1838 : super(<HInstruction>[]); |
1867 | 1839 |
1868 void prepareGvn(HTypeMap types) { | |
1869 assert(!hasSideEffects()); | |
1870 } | |
1871 | |
1872 toString() => 'literal: $constant'; | 1840 toString() => 'literal: $constant'; |
1873 accept(HVisitor visitor) => visitor.visitConstant(this); | 1841 accept(HVisitor visitor) => visitor.visitConstant(this); |
1874 | 1842 |
1875 HType get guaranteedType => constantType; | 1843 HType get guaranteedType => constantType; |
1876 | 1844 |
1877 bool isConstant() => true; | 1845 bool isConstant() => true; |
1878 bool isConstantBoolean() => constant.isBool(); | 1846 bool isConstantBoolean() => constant.isBool(); |
1879 bool isConstantNull() => constant.isNull(); | 1847 bool isConstantNull() => constant.isNull(); |
1880 bool isConstantNumber() => constant.isNum(); | 1848 bool isConstantNumber() => constant.isNum(); |
1881 bool isConstantInteger() => constant.isInt(); | 1849 bool isConstantInteger() => constant.isInt(); |
1882 bool isConstantString() => constant.isString(); | 1850 bool isConstantString() => constant.isString(); |
1883 bool isConstantList() => constant.isList(); | 1851 bool isConstantList() => constant.isList(); |
1884 bool isConstantMap() => constant.isMap(); | 1852 bool isConstantMap() => constant.isMap(); |
1885 bool isConstantFalse() => constant.isFalse(); | 1853 bool isConstantFalse() => constant.isFalse(); |
1886 bool isConstantTrue() => constant.isTrue(); | 1854 bool isConstantTrue() => constant.isTrue(); |
1887 bool isConstantSentinel() => constant.isSentinel(); | 1855 bool isConstantSentinel() => constant.isSentinel(); |
1888 | 1856 |
1889 // Maybe avoid this if the literal is big? | 1857 // Maybe avoid this if the literal is big? |
1890 bool isCodeMotionInvariant() => true; | 1858 bool isCodeMotionInvariant() => true; |
1891 } | 1859 } |
1892 | 1860 |
1893 class HNot extends HInstruction { | 1861 class HNot extends HInstruction { |
1894 HNot(HInstruction value) : super(<HInstruction>[value]); | 1862 HNot(HInstruction value) : super(<HInstruction>[value]) { |
1895 void prepareGvn(HTypeMap types) { | |
1896 assert(!hasSideEffects()); | |
1897 setUseGvn(); | 1863 setUseGvn(); |
1898 } | 1864 } |
1899 | 1865 |
1900 HType get guaranteedType => HType.BOOLEAN; | 1866 HType get guaranteedType => HType.BOOLEAN; |
1901 | 1867 |
1902 // 'Not' only works on booleans. That's what we want as input. | 1868 // 'Not' only works on booleans. That's what we want as input. |
1903 HType computeDesiredTypeForInput(HInstruction input, | 1869 HType computeDesiredTypeForInput(HInstruction input, |
1904 HTypeMap types, | 1870 HTypeMap types, |
1905 Compiler compiler) { | 1871 Compiler compiler) { |
1906 return HType.BOOLEAN; | 1872 return HType.BOOLEAN; |
1907 } | 1873 } |
1908 | 1874 |
1909 accept(HVisitor visitor) => visitor.visitNot(this); | 1875 accept(HVisitor visitor) => visitor.visitNot(this); |
1910 int typeCode() => HInstruction.NOT_TYPECODE; | 1876 int typeCode() => HInstruction.NOT_TYPECODE; |
1911 bool typeEquals(other) => other is HNot; | 1877 bool typeEquals(other) => other is HNot; |
1912 bool dataEquals(HInstruction other) => true; | 1878 bool dataEquals(HInstruction other) => true; |
1913 } | 1879 } |
1914 | 1880 |
1915 /** | 1881 /** |
1916 * An [HLocalValue] represents a local. Unlike [HParameterValue]s its | 1882 * An [HLocalValue] represents a local. Unlike [HParameterValue]s its |
1917 * first use must be in an HLocalSet. That is, [HParameterValue]s have a | 1883 * first use must be in an HLocalSet. That is, [HParameterValue]s have a |
1918 * value from the start, whereas [HLocalValue]s need to be initialized first. | 1884 * value from the start, whereas [HLocalValue]s need to be initialized first. |
1919 */ | 1885 */ |
1920 class HLocalValue extends HInstruction { | 1886 class HLocalValue extends HInstruction { |
1921 HLocalValue(Element element) : super(<HInstruction>[]) { | 1887 HLocalValue(Element element) : super(<HInstruction>[]) { |
1922 sourceElement = element; | 1888 sourceElement = element; |
1923 } | 1889 } |
1924 | 1890 |
1925 void prepareGvn(HTypeMap types) { | |
1926 assert(!hasSideEffects()); | |
1927 } | |
1928 toString() => 'local ${sourceElement.name}'; | 1891 toString() => 'local ${sourceElement.name}'; |
1929 accept(HVisitor visitor) => visitor.visitLocalValue(this); | 1892 accept(HVisitor visitor) => visitor.visitLocalValue(this); |
1930 } | 1893 } |
1931 | 1894 |
1932 class HParameterValue extends HLocalValue { | 1895 class HParameterValue extends HLocalValue { |
1933 HParameterValue(Element element) : super(element); | 1896 HParameterValue(Element element) : super(element); |
1934 | 1897 |
1935 toString() => 'parameter ${sourceElement.name.slowToString()}'; | 1898 toString() => 'parameter ${sourceElement.name.slowToString()}'; |
1936 accept(HVisitor visitor) => visitor.visitParameterValue(this); | 1899 accept(HVisitor visitor) => visitor.visitParameterValue(this); |
1937 } | 1900 } |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2107 HThrow(value, {this.isRethrow: false}) : super(<HInstruction>[value]); | 2070 HThrow(value, {this.isRethrow: false}) : super(<HInstruction>[value]); |
2108 toString() => 'throw'; | 2071 toString() => 'throw'; |
2109 accept(HVisitor visitor) => visitor.visitThrow(this); | 2072 accept(HVisitor visitor) => visitor.visitThrow(this); |
2110 } | 2073 } |
2111 | 2074 |
2112 class HStatic extends HInstruction { | 2075 class HStatic extends HInstruction { |
2113 final Element element; | 2076 final Element element; |
2114 HStatic(this.element) : super(<HInstruction>[]) { | 2077 HStatic(this.element) : super(<HInstruction>[]) { |
2115 assert(element != null); | 2078 assert(element != null); |
2116 assert(invariant(this, element.isDeclaration)); | 2079 assert(invariant(this, element.isDeclaration)); |
2117 } | |
2118 | |
2119 void prepareGvn(HTypeMap types) { | |
2120 clearAllSideEffects(); | 2080 clearAllSideEffects(); |
2121 if (element.isAssignable()) { | 2081 if (element.isAssignable()) { |
2122 setDependsOnStaticPropertyStore(); | 2082 setDependsOnStaticPropertyStore(); |
2123 } | 2083 } |
2124 setUseGvn(); | 2084 setUseGvn(); |
2125 } | 2085 } |
2126 toString() => 'static ${element.name}'; | 2086 toString() => 'static ${element.name}'; |
2127 accept(HVisitor visitor) => visitor.visitStatic(this); | 2087 accept(HVisitor visitor) => visitor.visitStatic(this); |
2128 | 2088 |
2129 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode; | 2089 int gvnHashCode() => super.gvnHashCode() ^ element.hashCode; |
2130 int typeCode() => HInstruction.STATIC_TYPECODE; | 2090 int typeCode() => HInstruction.STATIC_TYPECODE; |
2131 bool typeEquals(other) => other is HStatic; | 2091 bool typeEquals(other) => other is HStatic; |
2132 bool dataEquals(HStatic other) => element == other.element; | 2092 bool dataEquals(HStatic other) => element == other.element; |
2133 bool isCodeMotionInvariant() => !element.isAssignable(); | 2093 bool isCodeMotionInvariant() => !element.isAssignable(); |
2134 } | 2094 } |
2135 | 2095 |
2136 class HInterceptor extends HInstruction { | 2096 class HInterceptor extends HInstruction { |
2137 Set<ClassElement> interceptedClasses; | 2097 Set<ClassElement> interceptedClasses; |
2138 HInterceptor(this.interceptedClasses, HInstruction receiver) | 2098 HInterceptor(this.interceptedClasses, HInstruction receiver) |
2139 : super(<HInstruction>[receiver]); | 2099 : super(<HInstruction>[receiver]) { |
| 2100 clearAllSideEffects(); |
| 2101 setUseGvn(); |
| 2102 } |
2140 String toString() => 'interceptor on $interceptedClasses'; | 2103 String toString() => 'interceptor on $interceptedClasses'; |
2141 accept(HVisitor visitor) => visitor.visitInterceptor(this); | 2104 accept(HVisitor visitor) => visitor.visitInterceptor(this); |
2142 HInstruction get receiver => inputs[0]; | 2105 HInstruction get receiver => inputs[0]; |
2143 | 2106 |
2144 void prepareGvn(HTypeMap types) { | |
2145 clearAllSideEffects(); | |
2146 setUseGvn(); | |
2147 } | |
2148 | |
2149 HType computeDesiredTypeForInput(HInstruction input, | 2107 HType computeDesiredTypeForInput(HInstruction input, |
2150 HTypeMap types, | 2108 HTypeMap types, |
2151 Compiler compiler) { | 2109 Compiler compiler) { |
2152 if (interceptedClasses.length != 1) return HType.UNKNOWN; | 2110 if (interceptedClasses.length != 1) return HType.UNKNOWN; |
2153 // If the only class being intercepted is of type number, we | 2111 // If the only class being intercepted is of type number, we |
2154 // make this interceptor call say it wants that class as input. | 2112 // make this interceptor call say it wants that class as input. |
2155 Element interceptor = interceptedClasses.toList()[0]; | 2113 Element interceptor = interceptedClasses.toList()[0]; |
2156 JavaScriptBackend backend = compiler.backend; | 2114 JavaScriptBackend backend = compiler.backend; |
2157 if (interceptor == backend.jsNumberClass) { | 2115 if (interceptor == backend.jsNumberClass) { |
2158 return HType.NUMBER; | 2116 return HType.NUMBER; |
2159 } else if (interceptor == backend.jsIntClass) { | 2117 } else if (interceptor == backend.jsIntClass) { |
2160 return HType.INTEGER; | 2118 return HType.INTEGER; |
2161 } else if (interceptor == backend.jsDoubleClass) { | 2119 } else if (interceptor == backend.jsDoubleClass) { |
2162 return HType.DOUBLE; | 2120 return HType.DOUBLE; |
2163 } | 2121 } |
2164 return HType.UNKNOWN; | 2122 return HType.UNKNOWN; |
2165 } | 2123 } |
2166 | 2124 |
2167 int typeCode() => HInstruction.INTERCEPTOR_TYPECODE; | 2125 int typeCode() => HInstruction.INTERCEPTOR_TYPECODE; |
2168 bool typeEquals(other) => other is HInterceptor; | 2126 bool typeEquals(other) => other is HInterceptor; |
2169 bool dataEquals(HInterceptor other) { | 2127 bool dataEquals(HInterceptor other) { |
2170 return interceptedClasses == other.interceptedClasses | 2128 return interceptedClasses == other.interceptedClasses |
2171 || (interceptedClasses.length == other.interceptedClasses.length | 2129 || (interceptedClasses.length == other.interceptedClasses.length |
2172 && interceptedClasses.containsAll(other.interceptedClasses)); | 2130 && interceptedClasses.containsAll(other.interceptedClasses)); |
2173 } | 2131 } |
2174 } | 2132 } |
2175 | 2133 |
2176 /** An [HLazyStatic] is a static that is initialized lazily at first read. */ | 2134 /** An [HLazyStatic] is a static that is initialized lazily at first read. */ |
2177 class HLazyStatic extends HStatic { | 2135 class HLazyStatic extends HInstruction { |
2178 HLazyStatic(Element element) : super(element); | 2136 final Element element; |
2179 | 2137 HLazyStatic(this.element) : super(<HInstruction>[]) { |
2180 void prepareGvn(HTypeMap types) { | |
2181 // TODO(4931): The first access has side-effects, but we afterwards we | 2138 // TODO(4931): The first access has side-effects, but we afterwards we |
2182 // should be able to GVN. | 2139 // should be able to GVN. |
2183 setAllSideEffects(); | 2140 setAllSideEffects(); |
2184 setDependsOnSomething(); | 2141 setDependsOnSomething(); |
2185 } | 2142 } |
2186 | 2143 |
2187 toString() => 'lazy static ${element.name}'; | 2144 toString() => 'lazy static ${element.name}'; |
2188 accept(HVisitor visitor) => visitor.visitLazyStatic(this); | 2145 accept(HVisitor visitor) => visitor.visitLazyStatic(this); |
2189 | 2146 |
2190 int typeCode() => 30; | 2147 int typeCode() => 30; |
2191 // TODO(4931): can we do better here? | 2148 // TODO(4931): can we do better here? |
2192 bool isCodeMotionInvariant() => false; | 2149 bool isCodeMotionInvariant() => false; |
2193 bool canThrow() => true; | 2150 bool canThrow() => true; |
2194 } | 2151 } |
2195 | 2152 |
2196 class HStaticStore extends HInstruction { | 2153 class HStaticStore extends HInstruction { |
2197 Element element; | 2154 Element element; |
2198 HStaticStore(this.element, HInstruction value) : super(<HInstruction>[value]); | 2155 HStaticStore(this.element, HInstruction value) |
| 2156 : super(<HInstruction>[value]) { |
| 2157 clearAllSideEffects(); |
| 2158 setChangesStaticProperty(); |
| 2159 } |
2199 toString() => 'static store ${element.name}'; | 2160 toString() => 'static store ${element.name}'; |
2200 accept(HVisitor visitor) => visitor.visitStaticStore(this); | 2161 accept(HVisitor visitor) => visitor.visitStaticStore(this); |
2201 | 2162 |
2202 int typeCode() => HInstruction.STATIC_STORE_TYPECODE; | 2163 int typeCode() => HInstruction.STATIC_STORE_TYPECODE; |
2203 bool typeEquals(other) => other is HStaticStore; | 2164 bool typeEquals(other) => other is HStaticStore; |
2204 bool dataEquals(HStaticStore other) => element == other.element; | 2165 bool dataEquals(HStaticStore other) => element == other.element; |
2205 bool isJsStatement() => true; | 2166 bool isJsStatement() => true; |
2206 | |
2207 void prepareGvn(HTypeMap types) { | |
2208 clearAllSideEffects(); | |
2209 setChangesStaticProperty(); | |
2210 } | |
2211 } | 2167 } |
2212 | 2168 |
2213 class HLiteralList extends HInstruction { | 2169 class HLiteralList extends HInstruction { |
2214 HLiteralList(inputs) : super(inputs); | 2170 HLiteralList(inputs) : super(inputs); |
2215 toString() => 'literal list'; | 2171 toString() => 'literal list'; |
2216 accept(HVisitor visitor) => visitor.visitLiteralList(this); | 2172 accept(HVisitor visitor) => visitor.visitLiteralList(this); |
2217 | 2173 |
2218 HType get guaranteedType => HType.EXTENDABLE_ARRAY; | 2174 HType get guaranteedType => HType.EXTENDABLE_ARRAY; |
2219 | |
2220 void prepareGvn(HTypeMap types) { | |
2221 assert(!hasSideEffects()); | |
2222 } | |
2223 } | 2175 } |
2224 | 2176 |
2225 /** | 2177 /** |
2226 * The primitive array indexing operation. Note that this instruction | 2178 * The primitive array indexing operation. Note that this instruction |
2227 * does not throw because we generate the checks explicitly. | 2179 * does not throw because we generate the checks explicitly. |
2228 */ | 2180 */ |
2229 class HIndex extends HInstruction { | 2181 class HIndex extends HInstruction { |
2230 HIndex(HInstruction receiver, HInstruction index) | 2182 HIndex(HInstruction receiver, HInstruction index) |
2231 : super(<HInstruction>[receiver, index]); | 2183 : super(<HInstruction>[receiver, index]) { |
2232 String toString() => 'index operator'; | |
2233 accept(HVisitor visitor) => visitor.visitIndex(this); | |
2234 | |
2235 void prepareGvn(HTypeMap types) { | |
2236 clearAllSideEffects(); | 2184 clearAllSideEffects(); |
2237 setDependsOnIndexStore(); | 2185 setDependsOnIndexStore(); |
2238 setUseGvn(); | 2186 setUseGvn(); |
2239 } | 2187 } |
2240 | 2188 |
| 2189 String toString() => 'index operator'; |
| 2190 accept(HVisitor visitor) => visitor.visitIndex(this); |
| 2191 |
2241 HInstruction get receiver => inputs[0]; | 2192 HInstruction get receiver => inputs[0]; |
2242 HInstruction get index => inputs[1]; | 2193 HInstruction get index => inputs[1]; |
2243 | 2194 |
2244 int typeCode() => HInstruction.INDEX_TYPECODE; | 2195 int typeCode() => HInstruction.INDEX_TYPECODE; |
2245 bool typeEquals(HInstruction other) => other is HIndex; | 2196 bool typeEquals(HInstruction other) => other is HIndex; |
2246 bool dataEquals(HIndex other) => true; | 2197 bool dataEquals(HIndex other) => true; |
2247 } | 2198 } |
2248 | 2199 |
2249 /** | 2200 /** |
2250 * The primitive array assignment operation. Note that this instruction | 2201 * The primitive array assignment operation. Note that this instruction |
2251 * does not throw because we generate the checks explicitly. | 2202 * does not throw because we generate the checks explicitly. |
2252 */ | 2203 */ |
2253 class HIndexAssign extends HInstruction { | 2204 class HIndexAssign extends HInstruction { |
2254 HIndexAssign(HInstruction receiver, | 2205 HIndexAssign(HInstruction receiver, |
2255 HInstruction index, | 2206 HInstruction index, |
2256 HInstruction value) | 2207 HInstruction value) |
2257 : super(<HInstruction>[receiver, index, value]); | 2208 : super(<HInstruction>[receiver, index, value]) { |
| 2209 clearAllSideEffects(); |
| 2210 setChangesIndex(); |
| 2211 } |
2258 String toString() => 'index assign operator'; | 2212 String toString() => 'index assign operator'; |
2259 accept(HVisitor visitor) => visitor.visitIndexAssign(this); | 2213 accept(HVisitor visitor) => visitor.visitIndexAssign(this); |
2260 | 2214 |
2261 HInstruction get receiver => inputs[0]; | 2215 HInstruction get receiver => inputs[0]; |
2262 HInstruction get index => inputs[1]; | 2216 HInstruction get index => inputs[1]; |
2263 HInstruction get value => inputs[2]; | 2217 HInstruction get value => inputs[2]; |
2264 | |
2265 void prepareGvn(HTypeMap types) { | |
2266 clearAllSideEffects(); | |
2267 setChangesIndex(); | |
2268 } | |
2269 } | 2218 } |
2270 | 2219 |
2271 class HIs extends HInstruction { | 2220 class HIs extends HInstruction { |
2272 final DartType typeExpression; | 2221 final DartType typeExpression; |
2273 final bool nullOk; | 2222 final bool nullOk; |
2274 | 2223 |
2275 HIs.withArgumentChecks(this.typeExpression, | 2224 HIs(this.typeExpression, List<HInstruction> inputs, {this.nullOk: false}) |
2276 HInstruction expression, | 2225 : super(inputs) { |
2277 List<HInstruction> checks, | 2226 setUseGvn(); |
2278 [this.nullOk = false]) | 2227 } |
2279 : super(<HInstruction>[expression]..addAll(checks)); | |
2280 | |
2281 HIs(this.typeExpression, HInstruction expression, {this.nullOk: false}) | |
2282 : super(<HInstruction>[expression]); | |
2283 | 2228 |
2284 HInstruction get expression => inputs[0]; | 2229 HInstruction get expression => inputs[0]; |
2285 HInstruction getCheck(int index) => inputs[index + 1]; | 2230 HInstruction getCheck(int index) => inputs[index + 1]; |
2286 int get checkCount => inputs.length - 1; | 2231 int get checkCount => inputs.length - 1; |
2287 | 2232 |
2288 bool hasArgumentChecks() => inputs.length > 1; | 2233 bool hasArgumentChecks() => inputs.length > 1; |
2289 | 2234 |
2290 HType get guaranteedType => HType.BOOLEAN; | 2235 HType get guaranteedType => HType.BOOLEAN; |
2291 | 2236 |
2292 accept(HVisitor visitor) => visitor.visitIs(this); | 2237 accept(HVisitor visitor) => visitor.visitIs(this); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2345 } | 2290 } |
2346 accept(HVisitor visitor) => visitor.visitRangeConversion(this); | 2291 accept(HVisitor visitor) => visitor.visitRangeConversion(this); |
2347 | 2292 |
2348 // We currently only do range analysis for integers. | 2293 // We currently only do range analysis for integers. |
2349 HType get guaranteedType => HType.INTEGER; | 2294 HType get guaranteedType => HType.INTEGER; |
2350 } | 2295 } |
2351 | 2296 |
2352 class HStringConcat extends HInstruction { | 2297 class HStringConcat extends HInstruction { |
2353 final Node node; | 2298 final Node node; |
2354 HStringConcat(HInstruction left, HInstruction right, this.node) | 2299 HStringConcat(HInstruction left, HInstruction right, this.node) |
2355 : super(<HInstruction>[left, right]); | 2300 : super(<HInstruction>[left, right]) { |
| 2301 setAllSideEffects(); |
| 2302 setDependsOnSomething(); |
| 2303 } |
2356 HType get guaranteedType => HType.STRING; | 2304 HType get guaranteedType => HType.STRING; |
2357 | 2305 |
2358 HInstruction get left => inputs[0]; | 2306 HInstruction get left => inputs[0]; |
2359 HInstruction get right => inputs[1]; | 2307 HInstruction get right => inputs[1]; |
2360 | 2308 |
2361 accept(HVisitor visitor) => visitor.visitStringConcat(this); | 2309 accept(HVisitor visitor) => visitor.visitStringConcat(this); |
2362 toString() => "string concat"; | 2310 toString() => "string concat"; |
2363 } | 2311 } |
2364 | 2312 |
2365 /** Non-block-based (aka. traditional) loop information. */ | 2313 /** Non-block-based (aka. traditional) loop information. */ |
(...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2687 HBasicBlock get start => expression.start; | 2635 HBasicBlock get start => expression.start; |
2688 HBasicBlock get end { | 2636 HBasicBlock get end { |
2689 // We don't create a switch block if there are no cases. | 2637 // We don't create a switch block if there are no cases. |
2690 assert(!statements.isEmpty); | 2638 assert(!statements.isEmpty); |
2691 return statements.last.end; | 2639 return statements.last.end; |
2692 } | 2640 } |
2693 | 2641 |
2694 bool accept(HStatementInformationVisitor visitor) => | 2642 bool accept(HStatementInformationVisitor visitor) => |
2695 visitor.visitSwitchInfo(this); | 2643 visitor.visitSwitchInfo(this); |
2696 } | 2644 } |
OLD | NEW |