| 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 interface OptimizationPhase { | 5 interface OptimizationPhase { |
| 6 String get name(); | 6 String get name(); |
| 7 void visitGraph(HGraph graph); | 7 void visitGraph(HGraph graph); |
| 8 } | 8 } |
| 9 | 9 |
| 10 class SsaOptimizerTask extends CompilerTask { | 10 class SsaOptimizerTask extends CompilerTask { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 if (!input.canBePrimitive() && !node.getter && !node.setter) { | 199 if (!input.canBePrimitive() && !node.getter && !node.setter) { |
| 200 bool transformToDynamicInvocation = true; | 200 bool transformToDynamicInvocation = true; |
| 201 if (input.canBeNull()) { | 201 if (input.canBeNull()) { |
| 202 // Check if the method exists on Null. If yes we must not transform | 202 // Check if the method exists on Null. If yes we must not transform |
| 203 // the static interceptor call to a dynamic invocation. | 203 // the static interceptor call to a dynamic invocation. |
| 204 // TODO(floitsch): get a list of methods that exist on 'null' and only | 204 // TODO(floitsch): get a list of methods that exist on 'null' and only |
| 205 // bail out on them. | 205 // bail out on them. |
| 206 transformToDynamicInvocation = false; | 206 transformToDynamicInvocation = false; |
| 207 } | 207 } |
| 208 if (transformToDynamicInvocation) { | 208 if (transformToDynamicInvocation) { |
| 209 return fromInterceptorToDynamicInvocation(node, node.name); | 209 return fromInterceptorToDynamicInvocation(node, node.selector); |
| 210 } | 210 } |
| 211 } | 211 } |
| 212 | 212 |
| 213 return node; | 213 return node; |
| 214 } | 214 } |
| 215 | 215 |
| 216 HInstruction visitInvokeDynamic(HInvokeDynamic node) { | 216 HInstruction visitInvokeDynamic(HInvokeDynamic node) { |
| 217 HType receiverType = node.receiver.propagatedType; | 217 HType receiverType = node.receiver.propagatedType; |
| 218 if (receiverType.isExact()) { | 218 if (receiverType.isExact()) { |
| 219 HBoundedType type = receiverType; | 219 HBoundedType type = receiverType; |
| 220 Element element = type.lookupMember(node.name); | 220 Element element = type.lookupMember(node.name); |
| 221 // TODO(ngeoffray): Also fold if it's a getter or variable. | 221 // TODO(ngeoffray): Also fold if it's a getter or variable. |
| 222 if (element != null && element.isFunction()) { | 222 if (element != null && element.isFunction()) { |
| 223 if (node.selector.applies(element, compiler)) { | 223 if (node.selector.applies(element, compiler)) { |
| 224 FunctionElement method = element; | 224 FunctionElement method = element; |
| 225 FunctionSignature parameters = method.computeSignature(compiler); | 225 FunctionSignature parameters = method.computeSignature(compiler); |
| 226 if (parameters.optionalParameterCount == 0) { | 226 if (parameters.optionalParameterCount == 0) { |
| 227 node.element = element; | 227 node.element = element; |
| 228 } | 228 } |
| 229 // TODO(ngeoffray): If the method has optional parameters, | 229 // TODO(ngeoffray): If the method has optional parameters, |
| 230 // we should pass the default values here. | 230 // we should pass the default values here. |
| 231 } | 231 } |
| 232 } | 232 } |
| 233 } | 233 } |
| 234 return node; | 234 return node; |
| 235 } | 235 } |
| 236 | 236 |
| 237 HInstruction fromInterceptorToDynamicInvocation( | 237 HInstruction fromInterceptorToDynamicInvocation(HInvokeStatic node, |
| 238 HInvokeStatic node, SourceString methodName) { | 238 Selector selector) { |
| 239 HBoundedType type = node.inputs[1].propagatedType; | 239 HBoundedType type = node.inputs[1].propagatedType; |
| 240 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 240 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
| 241 node.selector, | 241 selector, |
| 242 methodName, | 242 selector.name, |
| 243 node.inputs.getRange(1, node.inputs.length - 1)); | 243 node.inputs.getRange(1, node.inputs.length - 1)); |
| 244 if (type.isExact()) { | 244 if (type.isExact()) { |
| 245 HBoundedType concrete = type; | 245 HBoundedType concrete = type; |
| 246 result.element = concrete.lookupMember(methodName); | 246 result.element = concrete.lookupMember(selector.name); |
| 247 } | 247 } |
| 248 return result; | 248 return result; |
| 249 } | 249 } |
| 250 | 250 |
| 251 HInstruction visitBoundsCheck(HBoundsCheck node) { | 251 HInstruction visitBoundsCheck(HBoundsCheck node) { |
| 252 int tryGetIntConstantValue(HInstruction instruction, String errorMessage) { | 252 int tryGetIntConstantValue(HInstruction instruction, String errorMessage) { |
| 253 // Tests whether an [HInstruction] is a constant. | 253 // Tests whether an [HInstruction] is a constant. |
| 254 // If it is a constant, and not an int constant, it fails. | 254 // If it is a constant, and not an int constant, it fails. |
| 255 // If it's an int constant it returns the value. | 255 // If it's an int constant it returns the value. |
| 256 // Otherwise it's not a constant, and this function returns null. | 256 // Otherwise it's not a constant, and this function returns null. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 return !constantInstruction.constant.isInt(); | 295 return !constantInstruction.constant.isInt(); |
| 296 }); | 296 }); |
| 297 node.alwaysFalse = true; | 297 node.alwaysFalse = true; |
| 298 } | 298 } |
| 299 return node; | 299 return node; |
| 300 } | 300 } |
| 301 | 301 |
| 302 | 302 |
| 303 HInstruction visitIndex(HIndex node) { | 303 HInstruction visitIndex(HIndex node) { |
| 304 if (!node.receiver.canBePrimitive()) { | 304 if (!node.receiver.canBePrimitive()) { |
| 305 SourceString methodName = Elements.constructOperatorName( | 305 Selector selector = new Selector.index(); |
| 306 const SourceString('operator'), const SourceString('[]')); | 306 return fromInterceptorToDynamicInvocation(node, selector); |
| 307 return fromInterceptorToDynamicInvocation(node, methodName); | |
| 308 } | 307 } |
| 309 return node; | 308 return node; |
| 310 } | 309 } |
| 311 | 310 |
| 312 HInstruction visitIndexAssign(HIndexAssign node) { | 311 HInstruction visitIndexAssign(HIndexAssign node) { |
| 313 if (!node.receiver.canBePrimitive()) { | 312 if (!node.receiver.canBePrimitive()) { |
| 314 SourceString methodName = Elements.constructOperatorName( | 313 Selector selector = new Selector.indexSet(); |
| 315 const SourceString('operator'), const SourceString('[]=')); | 314 return fromInterceptorToDynamicInvocation(node, selector); |
| 316 return fromInterceptorToDynamicInvocation(node, methodName); | |
| 317 } | 315 } |
| 318 return node; | 316 return node; |
| 319 } | 317 } |
| 320 | 318 |
| 321 HInstruction visitInvokeBinary(HInvokeBinary node) { | 319 HInstruction visitInvokeBinary(HInvokeBinary node) { |
| 322 HInstruction left = node.left; | 320 HInstruction left = node.left; |
| 323 HInstruction right = node.right; | 321 HInstruction right = node.right; |
| 324 if (left is HConstant && right is HConstant) { | 322 if (left is HConstant && right is HConstant) { |
| 325 BinaryOperation operation = node.operation; | 323 BinaryOperation operation = node.operation; |
| 326 HConstant op1 = left; | 324 HConstant op1 = left; |
| 327 HConstant op2 = right; | 325 HConstant op2 = right; |
| 328 Constant folded = operation.fold(op1.constant, op2.constant); | 326 Constant folded = operation.fold(op1.constant, op2.constant); |
| 329 if (folded !== null) return graph.addConstant(folded); | 327 if (folded !== null) return graph.addConstant(folded); |
| 330 } | 328 } |
| 331 | 329 |
| 332 if (!left.canBePrimitive() | 330 if (!left.canBePrimitive() |
| 333 && node.operation.isUserDefinable() | 331 && node.operation.isUserDefinable() |
| 334 // The equals operation is being optimized in visitEquals. | 332 // The equals operation is being optimized in visitEquals. |
| 335 && node.operation !== const EqualsOperation()) { | 333 && node.operation !== const EqualsOperation()) { |
| 336 SourceString methodName = Elements.constructOperatorName( | 334 Selector selector = new Selector.binaryOperator(node.operation.name); |
| 337 const SourceString('operator'), node.operation.name); | 335 return fromInterceptorToDynamicInvocation(node, selector); |
| 338 return fromInterceptorToDynamicInvocation(node, methodName); | |
| 339 } | 336 } |
| 340 return node; | 337 return node; |
| 341 } | 338 } |
| 342 | 339 |
| 343 bool allUsersAreBoolifies(HInstruction instruction) { | 340 bool allUsersAreBoolifies(HInstruction instruction) { |
| 344 List<HInstruction> users = instruction.usedBy; | 341 List<HInstruction> users = instruction.usedBy; |
| 345 int length = users.length; | 342 int length = users.length; |
| 346 for (int i = 0; i < length; i++) { | 343 for (int i = 0; i < length; i++) { |
| 347 if (users[i] is! HBoolify) return false; | 344 if (users[i] is! HBoolify) return false; |
| 348 } | 345 } |
| (...skipping 293 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 instruction = instruction.accept(this); | 639 instruction = instruction.accept(this); |
| 643 instruction = next; | 640 instruction = next; |
| 644 } | 641 } |
| 645 } | 642 } |
| 646 | 643 |
| 647 HBoundsCheck insertBoundsCheck(HInstruction node, | 644 HBoundsCheck insertBoundsCheck(HInstruction node, |
| 648 HInstruction receiver, | 645 HInstruction receiver, |
| 649 HInstruction index) { | 646 HInstruction index) { |
| 650 HStatic interceptor = new HStatic(lengthInterceptor); | 647 HStatic interceptor = new HStatic(lengthInterceptor); |
| 651 node.block.addBefore(node, interceptor); | 648 node.block.addBefore(node, interceptor); |
| 649 Selector selector = new Selector.call( |
| 650 lengthInterceptor.name, |
| 651 lengthInterceptor.getLibrary(), // TODO(kasperl): Wrong. |
| 652 0); |
| 652 HInvokeInterceptor length = new HInvokeInterceptor( | 653 HInvokeInterceptor length = new HInvokeInterceptor( |
| 653 Selector.INVOCATION_0, | 654 selector, |
| 654 const SourceString("length"), | 655 const SourceString("length"), |
| 655 <HInstruction>[interceptor, receiver], | 656 <HInstruction>[interceptor, receiver], |
| 656 getter: true); | 657 getter: true); |
| 657 length.propagatedType = HType.INTEGER; | 658 length.propagatedType = HType.INTEGER; |
| 658 node.block.addBefore(node, length); | 659 node.block.addBefore(node, length); |
| 659 | 660 |
| 660 HBoundsCheck check = new HBoundsCheck(index, length); | 661 HBoundsCheck check = new HBoundsCheck(index, length); |
| 661 node.block.addBefore(node, check); | 662 node.block.addBefore(node, check); |
| 662 return check; | 663 return check; |
| 663 } | 664 } |
| (...skipping 641 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1305 // this type for the field is still a strong signal | 1306 // this type for the field is still a strong signal |
| 1306 // indicating the expected type of the field. | 1307 // indicating the expected type of the field. |
| 1307 field.propagatedType = type; | 1308 field.propagatedType = type; |
| 1308 } else { | 1309 } else { |
| 1309 // If there are no invoked setters we know the type of | 1310 // If there are no invoked setters we know the type of |
| 1310 // this field for sure. | 1311 // this field for sure. |
| 1311 field.guaranteedType = type; | 1312 field.guaranteedType = type; |
| 1312 } | 1313 } |
| 1313 } | 1314 } |
| 1314 } | 1315 } |
| OLD | NEW |