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 } | |
230 return node; | 214 return node; |
231 } | 215 } |
232 | 216 |
233 bool isFixedSizeListConstructor(HInvokeStatic node) { | 217 bool isFixedSizeListConstructor(HInvokeStatic node) { |
234 Element element = node.target.element; | 218 Element element = node.target.element; |
235 return element.getEnclosingClass() == compiler.listClass | 219 return element.getEnclosingClass() == compiler.listClass |
236 && node.inputs.length == 2 | 220 && node.inputs.length == 2 |
237 && node.inputs[1].isInteger(types); | 221 && node.inputs[1].isInteger(types); |
238 } | 222 } |
239 | 223 |
(...skipping 19 matching lines...) Expand all Loading... |
259 node.element = element; | 243 node.element = element; |
260 } | 244 } |
261 // TODO(ngeoffray): If the method has optional parameters, | 245 // TODO(ngeoffray): If the method has optional parameters, |
262 // we should pass the default values here. | 246 // we should pass the default values here. |
263 } | 247 } |
264 } | 248 } |
265 } | 249 } |
266 return node; | 250 return node; |
267 } | 251 } |
268 | 252 |
269 HInstruction fromNativeToDynamicInvocation(HInvokeStatic node, | 253 HInstruction fromInterceptorToDynamicInvocation(HInvokeStatic node, |
270 Selector selector) { | 254 Selector selector) { |
271 HBoundedType type = types[node.inputs[1]]; | 255 HBoundedType type = types[node.inputs[1]]; |
272 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 256 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
273 selector, | 257 selector, |
274 node.inputs.getRange(1, node.inputs.length - 1)); | 258 node.inputs.getRange(1, node.inputs.length - 1)); |
275 if (type.isExact()) { | 259 if (type.isExact()) { |
276 HBoundedType concrete = type; | 260 HBoundedType concrete = type; |
277 result.element = concrete.lookupMember(selector.name); | 261 result.element = concrete.lookupMember(selector.name); |
278 } | 262 } |
279 return result; | 263 return result; |
280 } | 264 } |
281 | 265 |
282 HInstruction visitIntegerCheck(HIntegerCheck node) { | 266 HInstruction visitIntegerCheck(HIntegerCheck node) { |
283 HInstruction value = node.value; | 267 HInstruction value = node.value; |
284 if (value.isInteger(types)) return value; | 268 if (value.isInteger(types)) return value; |
285 if (value.isConstant()) { | 269 if (value.isConstant()) { |
286 HConstant constantInstruction = value; | 270 HConstant constantInstruction = value; |
287 assert(!constantInstruction.constant.isInt()); | 271 assert(!constantInstruction.constant.isInt()); |
288 if (!constantSystem.isInt(constantInstruction.constant)) { | 272 if (!constantSystem.isInt(constantInstruction.constant)) { |
289 // -0.0 is a double but will pass the runtime integer check. | 273 // -0.0 is a double but will pass the runtime integer check. |
290 node.alwaysFalse = true; | 274 node.alwaysFalse = true; |
291 } | 275 } |
292 } | 276 } |
293 return node; | 277 return node; |
294 } | 278 } |
295 | 279 |
296 | 280 |
297 HInstruction visitIndex(HIndex node) { | 281 HInstruction visitIndex(HIndex node) { |
298 if (!node.receiver.canBePrimitive(types)) { | 282 if (!node.receiver.canBePrimitive(types)) { |
299 Selector selector = new Selector.index(); | 283 Selector selector = new Selector.index(); |
300 return fromNativeToDynamicInvocation(node, selector); | 284 return fromInterceptorToDynamicInvocation(node, selector); |
301 } | 285 } |
302 return node; | 286 return node; |
303 } | 287 } |
304 | 288 |
305 HInstruction visitIndexAssign(HIndexAssign node) { | 289 HInstruction visitIndexAssign(HIndexAssign node) { |
306 if (!node.receiver.canBePrimitive(types)) { | 290 if (!node.receiver.canBePrimitive(types)) { |
307 Selector selector = new Selector.indexSet(); | 291 Selector selector = new Selector.indexSet(); |
308 return fromNativeToDynamicInvocation(node, selector); | 292 return fromInterceptorToDynamicInvocation(node, selector); |
309 } | 293 } |
310 return node; | 294 return node; |
311 } | 295 } |
312 | 296 |
313 HInstruction visitInvokeBinary(HInvokeBinary node) { | 297 HInstruction visitInvokeBinary(HInvokeBinary node) { |
314 HInstruction left = node.left; | 298 HInstruction left = node.left; |
315 HInstruction right = node.right; | 299 HInstruction right = node.right; |
316 BinaryOperation operation = node.operation(constantSystem); | 300 BinaryOperation operation = node.operation(constantSystem); |
317 if (left is HConstant && right is HConstant) { | 301 if (left is HConstant && right is HConstant) { |
318 HConstant op1 = left; | 302 HConstant op1 = left; |
319 HConstant op2 = right; | 303 HConstant op2 = right; |
320 Constant folded = operation.fold(op1.constant, op2.constant); | 304 Constant folded = operation.fold(op1.constant, op2.constant); |
321 if (folded != null) return graph.addConstant(folded); | 305 if (folded != null) return graph.addConstant(folded); |
322 } | 306 } |
323 | 307 |
324 if (!left.canBePrimitive(types) | 308 if (!left.canBePrimitive(types) |
325 && operation.isUserDefinable() | 309 && operation.isUserDefinable() |
326 // The equals operation is being optimized in visitEquals. | 310 // The equals operation is being optimized in visitEquals. |
327 && node is! HEquals) { | 311 && node is! HEquals) { |
328 Selector selector = new Selector.binaryOperator(operation.name); | 312 Selector selector = new Selector.binaryOperator(operation.name); |
329 return fromNativeToDynamicInvocation(node, selector); | 313 return fromInterceptorToDynamicInvocation(node, selector); |
330 } | 314 } |
331 return node; | 315 return node; |
332 } | 316 } |
333 | 317 |
334 bool allUsersAreBoolifies(HInstruction instruction) { | 318 bool allUsersAreBoolifies(HInstruction instruction) { |
335 List<HInstruction> users = instruction.usedBy; | 319 List<HInstruction> users = instruction.usedBy; |
336 int length = users.length; | 320 int length = users.length; |
337 for (int i = 0; i < length; i++) { | 321 for (int i = 0; i < length; i++) { |
338 if (users[i] is! HBoolify) return false; | 322 if (users[i] is! HBoolify) return false; |
339 } | 323 } |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 for (int i = 0; i < node.inputs.length; i++) { | 649 for (int i = 0; i < node.inputs.length; i++) { |
666 HInstruction part = node.inputs[i]; | 650 HInstruction part = node.inputs[i]; |
667 if (!part.isConstant()) return node; | 651 if (!part.isConstant()) return node; |
668 HConstant constant = part; | 652 HConstant constant = part; |
669 if (!constant.constant.isPrimitive()) return node; | 653 if (!constant.constant.isPrimitive()) return node; |
670 PrimitiveConstant primitive = constant.constant; | 654 PrimitiveConstant primitive = constant.constant; |
671 folded = new DartString.concat(folded, primitive.toDartString()); | 655 folded = new DartString.concat(folded, primitive.toDartString()); |
672 } | 656 } |
673 return graph.addConstant(constantSystem.createString(folded, node.node)); | 657 return graph.addConstant(constantSystem.createString(folded, node.node)); |
674 } | 658 } |
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 } | |
707 } | 659 } |
708 | 660 |
709 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { | 661 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { |
710 final HTypeMap types; | 662 final HTypeMap types; |
711 final ConstantSystem constantSystem; | 663 final ConstantSystem constantSystem; |
712 final Set<HInstruction> boundsChecked; | 664 final Set<HInstruction> boundsChecked; |
713 final WorkItem work; | 665 final WorkItem work; |
714 final String name = "SsaCheckInserter"; | 666 final String name = "SsaCheckInserter"; |
715 HGraph graph; | 667 HGraph graph; |
716 Element lengthInterceptor; | 668 Element lengthInterceptor; |
(...skipping 684 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1401 } | 1353 } |
1402 | 1354 |
1403 // For other fields having setters in the generative constructor body, set | 1355 // For other fields having setters in the generative constructor body, set |
1404 // the type to UNKNOWN to avoid relying on the type set in the initializer | 1356 // the type to UNKNOWN to avoid relying on the type set in the initializer |
1405 // list. | 1357 // list. |
1406 allSetters.forEach((Element element) { | 1358 allSetters.forEach((Element element) { |
1407 backend.registerFieldConstructor(element, HType.UNKNOWN); | 1359 backend.registerFieldConstructor(element, HType.UNKNOWN); |
1408 }); | 1360 }); |
1409 } | 1361 } |
1410 } | 1362 } |
OLD | NEW |