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 OptimizationPhase { | 7 abstract class OptimizationPhase { |
8 String get name; | 8 String get name; |
9 void visitGraph(HGraph graph); | 9 void visitGraph(HGraph graph); |
10 } | 10 } |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 } | 204 } |
205 return node; | 205 return node; |
206 } | 206 } |
207 | 207 |
208 HInstruction handleInterceptorCall(HInvokeDynamic node) { | 208 HInstruction handleInterceptorCall(HInvokeDynamic node) { |
209 HInstruction input = node.inputs[1]; | 209 HInstruction input = node.inputs[1]; |
210 if (input.isString(types) | 210 if (input.isString(types) |
211 && node.selector.name == const SourceString('toString')) { | 211 && node.selector.name == const SourceString('toString')) { |
212 return node.inputs[1]; | 212 return node.inputs[1]; |
213 } | 213 } |
| 214 // Check if this call does not need to be intercepted. |
| 215 HType type = types[input]; |
| 216 var interceptor = node.inputs[0]; |
| 217 if (node is HInvokeDynamicMethod |
| 218 && interceptor is !HThis |
| 219 && !type.canBePrimitive()) { |
| 220 // If the type can be null, and the intercepted method can be in |
| 221 // the object class, keep the interceptor. |
| 222 if (type.canBeNull() |
| 223 && interceptor.interceptedClasses.contains(compiler.objectClass)) { |
| 224 return node; |
| 225 } |
| 226 // Change the call to a regular invoke dynamic call. |
| 227 return new HInvokeDynamicMethod( |
| 228 node.selector, node.inputs.getRange(1, node.inputs.length - 1)); |
| 229 } |
214 return node; | 230 return node; |
215 } | 231 } |
216 | 232 |
217 bool isFixedSizeListConstructor(HInvokeStatic node) { | 233 bool isFixedSizeListConstructor(HInvokeStatic node) { |
218 Element element = node.target.element; | 234 Element element = node.target.element; |
219 return element.getEnclosingClass() == compiler.listClass | 235 return element.getEnclosingClass() == compiler.listClass |
220 && node.inputs.length == 2 | 236 && node.inputs.length == 2 |
221 && node.inputs[1].isInteger(types); | 237 && node.inputs[1].isInteger(types); |
222 } | 238 } |
223 | 239 |
(...skipping 19 matching lines...) Expand all Loading... |
243 node.element = element; | 259 node.element = element; |
244 } | 260 } |
245 // TODO(ngeoffray): If the method has optional parameters, | 261 // TODO(ngeoffray): If the method has optional parameters, |
246 // we should pass the default values here. | 262 // we should pass the default values here. |
247 } | 263 } |
248 } | 264 } |
249 } | 265 } |
250 return node; | 266 return node; |
251 } | 267 } |
252 | 268 |
253 HInstruction fromInterceptorToDynamicInvocation(HInvokeStatic node, | 269 HInstruction fromNativeToDynamicInvocation(HInvokeStatic node, |
254 Selector selector) { | 270 Selector selector) { |
255 HBoundedType type = types[node.inputs[1]]; | 271 HBoundedType type = types[node.inputs[1]]; |
256 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 272 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
257 selector, | 273 selector, |
258 node.inputs.getRange(1, node.inputs.length - 1)); | 274 node.inputs.getRange(1, node.inputs.length - 1)); |
259 if (type.isExact()) { | 275 if (type.isExact()) { |
260 HBoundedType concrete = type; | 276 HBoundedType concrete = type; |
261 result.element = concrete.lookupMember(selector.name); | 277 result.element = concrete.lookupMember(selector.name); |
262 } | 278 } |
263 return result; | 279 return result; |
264 } | 280 } |
265 | 281 |
266 HInstruction visitIntegerCheck(HIntegerCheck node) { | 282 HInstruction visitIntegerCheck(HIntegerCheck node) { |
267 HInstruction value = node.value; | 283 HInstruction value = node.value; |
268 if (value.isInteger(types)) return value; | 284 if (value.isInteger(types)) return value; |
269 if (value.isConstant()) { | 285 if (value.isConstant()) { |
270 HConstant constantInstruction = value; | 286 HConstant constantInstruction = value; |
271 assert(!constantInstruction.constant.isInt()); | 287 assert(!constantInstruction.constant.isInt()); |
272 if (!constantSystem.isInt(constantInstruction.constant)) { | 288 if (!constantSystem.isInt(constantInstruction.constant)) { |
273 // -0.0 is a double but will pass the runtime integer check. | 289 // -0.0 is a double but will pass the runtime integer check. |
274 node.alwaysFalse = true; | 290 node.alwaysFalse = true; |
275 } | 291 } |
276 } | 292 } |
277 return node; | 293 return node; |
278 } | 294 } |
279 | 295 |
280 | 296 |
281 HInstruction visitIndex(HIndex node) { | 297 HInstruction visitIndex(HIndex node) { |
282 if (!node.receiver.canBePrimitive(types)) { | 298 if (!node.receiver.canBePrimitive(types)) { |
283 Selector selector = new Selector.index(); | 299 Selector selector = new Selector.index(); |
284 return fromInterceptorToDynamicInvocation(node, selector); | 300 return fromNativeToDynamicInvocation(node, selector); |
285 } | 301 } |
286 return node; | 302 return node; |
287 } | 303 } |
288 | 304 |
289 HInstruction visitIndexAssign(HIndexAssign node) { | 305 HInstruction visitIndexAssign(HIndexAssign node) { |
290 if (!node.receiver.canBePrimitive(types)) { | 306 if (!node.receiver.canBePrimitive(types)) { |
291 Selector selector = new Selector.indexSet(); | 307 Selector selector = new Selector.indexSet(); |
292 return fromInterceptorToDynamicInvocation(node, selector); | 308 return fromNativeToDynamicInvocation(node, selector); |
293 } | 309 } |
294 return node; | 310 return node; |
295 } | 311 } |
296 | 312 |
297 HInstruction visitInvokeBinary(HInvokeBinary node) { | 313 HInstruction visitInvokeBinary(HInvokeBinary node) { |
298 HInstruction left = node.left; | 314 HInstruction left = node.left; |
299 HInstruction right = node.right; | 315 HInstruction right = node.right; |
300 BinaryOperation operation = node.operation(constantSystem); | 316 BinaryOperation operation = node.operation(constantSystem); |
301 if (left is HConstant && right is HConstant) { | 317 if (left is HConstant && right is HConstant) { |
302 HConstant op1 = left; | 318 HConstant op1 = left; |
303 HConstant op2 = right; | 319 HConstant op2 = right; |
304 Constant folded = operation.fold(op1.constant, op2.constant); | 320 Constant folded = operation.fold(op1.constant, op2.constant); |
305 if (folded != null) return graph.addConstant(folded); | 321 if (folded != null) return graph.addConstant(folded); |
306 } | 322 } |
307 | 323 |
308 if (!left.canBePrimitive(types) | 324 if (!left.canBePrimitive(types) |
309 && operation.isUserDefinable() | 325 && operation.isUserDefinable() |
310 // The equals operation is being optimized in visitEquals. | 326 // The equals operation is being optimized in visitEquals. |
311 && node is! HEquals) { | 327 && node is! HEquals) { |
312 Selector selector = new Selector.binaryOperator(operation.name); | 328 Selector selector = new Selector.binaryOperator(operation.name); |
313 return fromInterceptorToDynamicInvocation(node, selector); | 329 return fromNativeToDynamicInvocation(node, selector); |
314 } | 330 } |
315 return node; | 331 return node; |
316 } | 332 } |
317 | 333 |
318 bool allUsersAreBoolifies(HInstruction instruction) { | 334 bool allUsersAreBoolifies(HInstruction instruction) { |
319 List<HInstruction> users = instruction.usedBy; | 335 List<HInstruction> users = instruction.usedBy; |
320 int length = users.length; | 336 int length = users.length; |
321 for (int i = 0; i < length; i++) { | 337 for (int i = 0; i < length; i++) { |
322 if (users[i] is! HBoolify) return false; | 338 if (users[i] is! HBoolify) return false; |
323 } | 339 } |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
649 for (int i = 0; i < node.inputs.length; i++) { | 665 for (int i = 0; i < node.inputs.length; i++) { |
650 HInstruction part = node.inputs[i]; | 666 HInstruction part = node.inputs[i]; |
651 if (!part.isConstant()) return node; | 667 if (!part.isConstant()) return node; |
652 HConstant constant = part; | 668 HConstant constant = part; |
653 if (!constant.constant.isPrimitive()) return node; | 669 if (!constant.constant.isPrimitive()) return node; |
654 PrimitiveConstant primitive = constant.constant; | 670 PrimitiveConstant primitive = constant.constant; |
655 folded = new DartString.concat(folded, primitive.toDartString()); | 671 folded = new DartString.concat(folded, primitive.toDartString()); |
656 } | 672 } |
657 return graph.addConstant(constantSystem.createString(folded, node.node)); | 673 return graph.addConstant(constantSystem.createString(folded, node.node)); |
658 } | 674 } |
| 675 |
| 676 HInstruction visitInterceptor(HInterceptor node) { |
| 677 if (node.isConstant()) return node; |
| 678 HType type = types[node.inputs[0]]; |
| 679 Element constantInterceptor; |
| 680 if (type.isInteger()) { |
| 681 constantInterceptor = backend.intInterceptor; |
| 682 } else if (type.isDouble()) { |
| 683 constantInterceptor = backend.doubleInterceptor; |
| 684 } else if (type.isBoolean()) { |
| 685 constantInterceptor = backend.boolInterceptor; |
| 686 } else if (type.isString()) { |
| 687 constantInterceptor = backend.stringInterceptor; |
| 688 } else if (type.isArray()) { |
| 689 constantInterceptor = backend.arrayInterceptor; |
| 690 } else if (type.isNull()) { |
| 691 constantInterceptor = backend.nullInterceptor; |
| 692 } else if (type.isNumber()) { |
| 693 Set<ClassElement> intercepted = node.interceptedClasses; |
| 694 // If the method being intercepted is not defined in [int] or |
| 695 // [double] we can safely use the number interceptor. |
| 696 if (!intercepted.contains(compiler.intClass) |
| 697 && !intercepted.contains(compiler.doubleClass)) { |
| 698 constantInterceptor = backend.numberInterceptor; |
| 699 } |
| 700 } |
| 701 |
| 702 if (constantInterceptor == null) return node; |
| 703 |
| 704 ConstantHandler handler = compiler.constantHandler; |
| 705 return graph.addConstant(handler.compileVariable(constantInterceptor)); |
| 706 } |
659 } | 707 } |
660 | 708 |
661 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 709 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
662 final HTypeMap types; | 710 final HTypeMap types; |
663 final ConstantSystem constantSystem; | 711 final ConstantSystem constantSystem; |
664 final Set<HInstruction> boundsChecked; | 712 final Set<HInstruction> boundsChecked; |
665 final WorkItem work; | 713 final WorkItem work; |
666 final String name = "SsaCheckInserter"; | 714 final String name = "SsaCheckInserter"; |
667 HGraph graph; | 715 HGraph graph; |
668 Element lengthInterceptor; | 716 Element lengthInterceptor; |
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1353 } | 1401 } |
1354 | 1402 |
1355 // For other fields having setters in the generative constructor body, set | 1403 // For other fields having setters in the generative constructor body, set |
1356 // the type to UNKNOWN to avoid relying on the type set in the initializer | 1404 // the type to UNKNOWN to avoid relying on the type set in the initializer |
1357 // list. | 1405 // list. |
1358 allSetters.forEach((Element element) { | 1406 allSetters.forEach((Element element) { |
1359 backend.registerFieldConstructor(element, HType.UNKNOWN); | 1407 backend.registerFieldConstructor(element, HType.UNKNOWN); |
1360 }); | 1408 }); |
1361 } | 1409 } |
1362 } | 1410 } |
OLD | NEW |