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 1302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1313 } | 1313 } |
1314 } | 1314 } |
1315 | 1315 |
1316 class HInvokeClosure extends HInvokeDynamic { | 1316 class HInvokeClosure extends HInvokeDynamic { |
1317 HInvokeClosure(Selector selector, List<HInstruction> inputs) | 1317 HInvokeClosure(Selector selector, List<HInstruction> inputs) |
1318 : super(selector, null, inputs); | 1318 : super(selector, null, inputs); |
1319 accept(HVisitor visitor) => visitor.visitInvokeClosure(this); | 1319 accept(HVisitor visitor) => visitor.visitInvokeClosure(this); |
1320 } | 1320 } |
1321 | 1321 |
1322 class HInvokeDynamicMethod extends HInvokeDynamic { | 1322 class HInvokeDynamicMethod extends HInvokeDynamic { |
1323 HInvokeDynamicMethod(Selector selector, List<HInstruction> inputs) | 1323 final InvokeDynamicSpecializer specializer; |
1324 : super(selector, null, inputs); | 1324 HInvokeDynamicMethod(Selector selector, |
| 1325 List<HInstruction> inputs, |
| 1326 [bool isIntercepted = false]) |
| 1327 : super(selector, null, inputs), |
| 1328 specializer = isIntercepted |
| 1329 ? InvokeDynamicSpecializer.lookupSpecializer(selector) |
| 1330 : const InvokeDynamicSpecializer(); |
1325 String toString() => 'invoke dynamic method: $selector'; | 1331 String toString() => 'invoke dynamic method: $selector'; |
1326 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); | 1332 accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this); |
1327 | 1333 |
1328 bool isIndexOperatorOnIndexablePrimitive(HTypeMap types) { | 1334 bool isIndexOperatorOnIndexablePrimitive(HTypeMap types) { |
1329 return isInterceptorCall | 1335 return isInterceptorCall |
1330 && selector.kind == SelectorKind.INDEX | 1336 && selector.kind == SelectorKind.INDEX |
1331 && selector.name == const SourceString('[]') | 1337 && selector.name == const SourceString('[]') |
1332 && inputs[1].isIndexablePrimitive(types); | 1338 && inputs[1].isIndexablePrimitive(types); |
1333 } | 1339 } |
1334 | 1340 |
1335 HType computeDesiredTypeForInput(HInstruction input, | 1341 HType computeDesiredTypeForInput(HInstruction input, |
1336 HTypeMap types, | 1342 HTypeMap types, |
1337 Compiler compiler) { | 1343 Compiler compiler) { |
1338 // TODO(ngeoffray): Move this logic into a different class that | 1344 return specializer.computeDesiredTypeForInput(this, input, types, compiler); |
1339 // will know what type it wants for a given selector. | |
1340 if (!isInterceptorCall) return HType.UNKNOWN; | |
1341 | |
1342 if (selector.kind == SelectorKind.INDEX) { | |
1343 HInstruction index = inputs[2]; | |
1344 if (input == inputs[1] && | |
1345 (index.isTypeUnknown(types) || index.isNumber(types))) { | |
1346 return selector.name == const SourceString('[]') | |
1347 ? HType.INDEXABLE_PRIMITIVE | |
1348 : HType.MUTABLE_ARRAY; | |
1349 } | |
1350 // The index should be an int when the receiver is a string or array. | |
1351 // However it turns out that inserting an integer check in the optimized | |
1352 // version is cheaper than having another bailout case. This is true, | |
1353 // because the integer check will simply throw if it fails. | |
1354 return HType.UNKNOWN; | |
1355 } else if (selector.kind == SelectorKind.OPERATOR) { | |
1356 HType propagatedType = types[this]; | |
1357 if (selector.name == const SourceString('unary-') && input == inputs[1]) { | |
1358 // If the outgoing type should be a number (integer, double or both) we | |
1359 // want the outgoing type to be the input too. | |
1360 // If we don't know the outgoing type we try to make it a number. | |
1361 if (propagatedType.isNumber()) return propagatedType; | |
1362 if (propagatedType.isUnknown()) return HType.NUMBER; | |
1363 } else if (selector.name == const SourceString('~') | |
1364 && input == inputs[1]) { | |
1365 if (propagatedType.isUnknown() || propagatedType.isNumber()) { | |
1366 return HType.INTEGER; | |
1367 } | |
1368 } | |
1369 return HType.UNKNOWN; | |
1370 } | |
1371 return HType.UNKNOWN; | |
1372 } | 1345 } |
1373 | 1346 |
1374 HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { | 1347 HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) { |
1375 // TODO(ngeoffray): Move this logic into a different class that | 1348 return specializer.computeTypeFromInputTypes(this, types, compiler); |
1376 // will know what type it has for a given selector. | |
1377 if (!isInterceptorCall) return HType.UNKNOWN; | |
1378 | |
1379 if (selector.kind == SelectorKind.OPERATOR) { | |
1380 if (selector.name == const SourceString('unary-')) { | |
1381 HType operandType = types[inputs[1]]; | |
1382 if (operandType.isNumber()) return operandType; | |
1383 } else if (selector.name == const SourceString('~')) { | |
1384 // All bitwise operations on primitive types either produce an | |
1385 // integer or throw an error. | |
1386 if (inputs[1].isPrimitive(types)) return HType.INTEGER; | |
1387 } | |
1388 } | |
1389 return HType.UNKNOWN; | |
1390 } | 1349 } |
1391 } | 1350 } |
1392 | 1351 |
1393 abstract class HInvokeDynamicField extends HInvokeDynamic { | 1352 abstract class HInvokeDynamicField extends HInvokeDynamic { |
1394 final bool isSideEffectFree; | 1353 final bool isSideEffectFree; |
1395 HInvokeDynamicField( | 1354 HInvokeDynamicField( |
1396 Selector selector, Element element, List<HInstruction> inputs, | 1355 Selector selector, Element element, List<HInstruction> inputs, |
1397 this.isSideEffectFree) | 1356 this.isSideEffectFree) |
1398 : super(selector, element, inputs); | 1357 : super(selector, element, inputs); |
1399 toString() => 'invoke dynamic field: $selector'; | 1358 toString() => 'invoke dynamic field: $selector'; |
(...skipping 1532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2932 HBasicBlock get start => expression.start; | 2891 HBasicBlock get start => expression.start; |
2933 HBasicBlock get end { | 2892 HBasicBlock get end { |
2934 // We don't create a switch block if there are no cases. | 2893 // We don't create a switch block if there are no cases. |
2935 assert(!statements.isEmpty); | 2894 assert(!statements.isEmpty); |
2936 return statements.last.end; | 2895 return statements.last.end; |
2937 } | 2896 } |
2938 | 2897 |
2939 bool accept(HStatementInformationVisitor visitor) => | 2898 bool accept(HStatementInformationVisitor visitor) => |
2940 visitor.visitSwitchInfo(this); | 2899 visitor.visitSwitchInfo(this); |
2941 } | 2900 } |
OLD | NEW |