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 /** |
254 Selector selector) { | 270 * Turns a primitive instruction (e.g. [HIndex], [HAdd], ...) into a |
| 271 * [HInvokeDynamic] because we know the receiver is not a JS |
| 272 * primitive object. |
| 273 */ |
| 274 HInstruction fromPrimitiveInstructionToDynamicInvocation(HInvokeStatic node, |
| 275 Selector selector) { |
255 HBoundedType type = types[node.inputs[1]]; | 276 HBoundedType type = types[node.inputs[1]]; |
256 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 277 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
257 selector, | 278 selector, |
258 node.inputs.getRange(1, node.inputs.length - 1)); | 279 node.inputs.getRange(1, node.inputs.length - 1)); |
259 if (type.isExact()) { | 280 if (type.isExact()) { |
260 HBoundedType concrete = type; | 281 HBoundedType concrete = type; |
261 result.element = concrete.lookupMember(selector.name); | 282 result.element = concrete.lookupMember(selector.name); |
262 } | 283 } |
263 return result; | 284 return result; |
264 } | 285 } |
265 | 286 |
266 HInstruction visitIntegerCheck(HIntegerCheck node) { | 287 HInstruction visitIntegerCheck(HIntegerCheck node) { |
267 HInstruction value = node.value; | 288 HInstruction value = node.value; |
268 if (value.isInteger(types)) return value; | 289 if (value.isInteger(types)) return value; |
269 if (value.isConstant()) { | 290 if (value.isConstant()) { |
270 HConstant constantInstruction = value; | 291 HConstant constantInstruction = value; |
271 assert(!constantInstruction.constant.isInt()); | 292 assert(!constantInstruction.constant.isInt()); |
272 if (!constantSystem.isInt(constantInstruction.constant)) { | 293 if (!constantSystem.isInt(constantInstruction.constant)) { |
273 // -0.0 is a double but will pass the runtime integer check. | 294 // -0.0 is a double but will pass the runtime integer check. |
274 node.alwaysFalse = true; | 295 node.alwaysFalse = true; |
275 } | 296 } |
276 } | 297 } |
277 return node; | 298 return node; |
278 } | 299 } |
279 | 300 |
280 | 301 |
281 HInstruction visitIndex(HIndex node) { | 302 HInstruction visitIndex(HIndex node) { |
282 if (!node.receiver.canBePrimitive(types)) { | 303 if (!node.receiver.canBePrimitive(types)) { |
283 Selector selector = new Selector.index(); | 304 Selector selector = new Selector.index(); |
284 return fromInterceptorToDynamicInvocation(node, selector); | 305 return fromPrimitiveInstructionToDynamicInvocation(node, selector); |
285 } | 306 } |
286 return node; | 307 return node; |
287 } | 308 } |
288 | 309 |
289 HInstruction visitIndexAssign(HIndexAssign node) { | 310 HInstruction visitIndexAssign(HIndexAssign node) { |
290 if (!node.receiver.canBePrimitive(types)) { | 311 if (!node.receiver.canBePrimitive(types)) { |
291 Selector selector = new Selector.indexSet(); | 312 Selector selector = new Selector.indexSet(); |
292 return fromInterceptorToDynamicInvocation(node, selector); | 313 return fromPrimitiveInstructionToDynamicInvocation(node, selector); |
293 } | 314 } |
294 return node; | 315 return node; |
295 } | 316 } |
296 | 317 |
297 HInstruction visitInvokeBinary(HInvokeBinary node) { | 318 HInstruction visitInvokeBinary(HInvokeBinary node) { |
298 HInstruction left = node.left; | 319 HInstruction left = node.left; |
299 HInstruction right = node.right; | 320 HInstruction right = node.right; |
300 BinaryOperation operation = node.operation(constantSystem); | 321 BinaryOperation operation = node.operation(constantSystem); |
301 if (left is HConstant && right is HConstant) { | 322 if (left is HConstant && right is HConstant) { |
302 HConstant op1 = left; | 323 HConstant op1 = left; |
303 HConstant op2 = right; | 324 HConstant op2 = right; |
304 Constant folded = operation.fold(op1.constant, op2.constant); | 325 Constant folded = operation.fold(op1.constant, op2.constant); |
305 if (folded != null) return graph.addConstant(folded); | 326 if (folded != null) return graph.addConstant(folded); |
306 } | 327 } |
307 | 328 |
308 if (!left.canBePrimitive(types) | 329 if (!left.canBePrimitive(types) |
309 && operation.isUserDefinable() | 330 && operation.isUserDefinable() |
310 // The equals operation is being optimized in visitEquals. | 331 // The equals operation is being optimized in visitEquals. |
311 && node is! HEquals) { | 332 && node is! HEquals) { |
312 Selector selector = new Selector.binaryOperator(operation.name); | 333 Selector selector = new Selector.binaryOperator(operation.name); |
313 return fromInterceptorToDynamicInvocation(node, selector); | 334 return fromPrimitiveInstructionToDynamicInvocation(node, selector); |
314 } | 335 } |
315 return node; | 336 return node; |
316 } | 337 } |
317 | 338 |
318 bool allUsersAreBoolifies(HInstruction instruction) { | 339 bool allUsersAreBoolifies(HInstruction instruction) { |
319 List<HInstruction> users = instruction.usedBy; | 340 List<HInstruction> users = instruction.usedBy; |
320 int length = users.length; | 341 int length = users.length; |
321 for (int i = 0; i < length; i++) { | 342 for (int i = 0; i < length; i++) { |
322 if (users[i] is! HBoolify) return false; | 343 if (users[i] is! HBoolify) return false; |
323 } | 344 } |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
649 for (int i = 0; i < node.inputs.length; i++) { | 670 for (int i = 0; i < node.inputs.length; i++) { |
650 HInstruction part = node.inputs[i]; | 671 HInstruction part = node.inputs[i]; |
651 if (!part.isConstant()) return node; | 672 if (!part.isConstant()) return node; |
652 HConstant constant = part; | 673 HConstant constant = part; |
653 if (!constant.constant.isPrimitive()) return node; | 674 if (!constant.constant.isPrimitive()) return node; |
654 PrimitiveConstant primitive = constant.constant; | 675 PrimitiveConstant primitive = constant.constant; |
655 folded = new DartString.concat(folded, primitive.toDartString()); | 676 folded = new DartString.concat(folded, primitive.toDartString()); |
656 } | 677 } |
657 return graph.addConstant(constantSystem.createString(folded, node.node)); | 678 return graph.addConstant(constantSystem.createString(folded, node.node)); |
658 } | 679 } |
| 680 |
| 681 HInstruction visitInterceptor(HInterceptor node) { |
| 682 if (node.isConstant()) return node; |
| 683 HType type = types[node.inputs[0]]; |
| 684 Element constantInterceptor; |
| 685 if (type.isInteger()) { |
| 686 constantInterceptor = backend.intInterceptor; |
| 687 } else if (type.isDouble()) { |
| 688 constantInterceptor = backend.doubleInterceptor; |
| 689 } else if (type.isBoolean()) { |
| 690 constantInterceptor = backend.boolInterceptor; |
| 691 } else if (type.isString()) { |
| 692 constantInterceptor = backend.stringInterceptor; |
| 693 } else if (type.isArray()) { |
| 694 constantInterceptor = backend.arrayInterceptor; |
| 695 } else if (type.isNull()) { |
| 696 constantInterceptor = backend.nullInterceptor; |
| 697 } else if (type.isNumber()) { |
| 698 Set<ClassElement> intercepted = node.interceptedClasses; |
| 699 // If the method being intercepted is not defined in [int] or |
| 700 // [double] we can safely use the number interceptor. |
| 701 if (!intercepted.contains(compiler.intClass) |
| 702 && !intercepted.contains(compiler.doubleClass)) { |
| 703 constantInterceptor = backend.numberInterceptor; |
| 704 } |
| 705 } |
| 706 |
| 707 if (constantInterceptor == null) return node; |
| 708 |
| 709 ConstantHandler handler = compiler.constantHandler; |
| 710 return graph.addConstant(handler.compileVariable(constantInterceptor)); |
| 711 } |
659 } | 712 } |
660 | 713 |
661 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 714 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
662 final HTypeMap types; | 715 final HTypeMap types; |
663 final ConstantSystem constantSystem; | 716 final ConstantSystem constantSystem; |
664 final Set<HInstruction> boundsChecked; | 717 final Set<HInstruction> boundsChecked; |
665 final WorkItem work; | 718 final WorkItem work; |
666 final String name = "SsaCheckInserter"; | 719 final String name = "SsaCheckInserter"; |
667 HGraph graph; | 720 HGraph graph; |
668 Element lengthInterceptor; | 721 Element lengthInterceptor; |
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1353 } | 1406 } |
1354 | 1407 |
1355 // For other fields having setters in the generative constructor body, set | 1408 // 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 | 1409 // the type to UNKNOWN to avoid relying on the type set in the initializer |
1357 // list. | 1410 // list. |
1358 allSetters.forEach((Element element) { | 1411 allSetters.forEach((Element element) { |
1359 backend.registerFieldConstructor(element, HType.UNKNOWN); | 1412 backend.registerFieldConstructor(element, HType.UNKNOWN); |
1360 }); | 1413 }); |
1361 } | 1414 } |
1362 } | 1415 } |
OLD | NEW |