| 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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   199     HInstruction operand = node.operand; |   199     HInstruction operand = node.operand; | 
|   200     if (operand is HConstant) { |   200     if (operand is HConstant) { | 
|   201       UnaryOperation operation = node.operation(constantSystem); |   201       UnaryOperation operation = node.operation(constantSystem); | 
|   202       HConstant receiver = operand; |   202       HConstant receiver = operand; | 
|   203       Constant folded = operation.fold(receiver.constant); |   203       Constant folded = operation.fold(receiver.constant); | 
|   204       if (folded != null) return graph.addConstant(folded); |   204       if (folded != null) return graph.addConstant(folded); | 
|   205     } |   205     } | 
|   206     return node; |   206     return node; | 
|   207   } |   207   } | 
|   208  |   208  | 
|   209   HInstruction handleInterceptorCall(HInvokeDynamic node) { |   209   HInstruction handleInterceptorCall(HInvokeDynamicMethod node) { | 
|   210     if (node is !HInvokeDynamicMethod) return null; |  | 
|   211     HInstruction input = node.inputs[1]; |   210     HInstruction input = node.inputs[1]; | 
|   212     if (input.isString(types) |   211     if (input.isString(types) | 
|   213         && node.selector.name == const SourceString('toString')) { |   212         && node.selector.name == const SourceString('toString')) { | 
|   214       return node.inputs[1]; |   213       return node.inputs[1]; | 
|   215     } |   214     } | 
|   216     // Check if this call does not need to be intercepted. |   215     // Check if this call does not need to be intercepted. | 
|   217     HType type = types[input]; |   216     HType type = types[input]; | 
|   218     var interceptor = node.inputs[0]; |   217     var interceptor = node.inputs[0]; | 
|   219     if (interceptor is !HThis && !type.canBePrimitive()) { |   218     if (interceptor is !HThis && !type.canBePrimitive()) { | 
|   220       // If the type can be null, and the intercepted method can be in |   219       // If the type can be null, and the intercepted method can be in | 
|   221       // the object class, keep the interceptor. |   220       // the object class, keep the interceptor. | 
|   222       if (type.canBeNull() |   221       if (type.canBeNull() | 
|   223           && interceptor.interceptedClasses.contains(compiler.objectClass)) { |   222           && interceptor.interceptedClasses.contains(compiler.objectClass)) { | 
|   224         return node; |   223         return node; | 
|   225       } |   224       } | 
|   226       // Change the call to a regular invoke dynamic call. |   225       // Change the call to a regular invoke dynamic call. | 
|   227       return new HInvokeDynamicMethod( |   226       return new HInvokeDynamicMethod( | 
|   228           node.selector, node.inputs.getRange(1, node.inputs.length - 1)); |   227           node.selector, node.inputs.getRange(1, node.inputs.length - 1)); | 
|   229     } |   228     } | 
|   230  |   229  | 
|   231     Selector selector = node.selector; |   230     Selector selector = node.selector; | 
 |   231  | 
 |   232     if (node.isIndexOperatorOnIndexablePrimitive(types)) { | 
 |   233       return new HIndex(node.inputs[1], node.inputs[2]); | 
 |   234     } | 
 |   235  | 
|   232     SourceString selectorName = selector.name; |   236     SourceString selectorName = selector.name; | 
|   233     Element target; |   237     Element target; | 
|   234     if (input.isExtendableArray(types)) { |   238     if (input.isExtendableArray(types)) { | 
|   235       if (selectorName == backend.jsArrayRemoveLast.name |   239       if (selectorName == backend.jsArrayRemoveLast.name | 
|   236           && selector.argumentCount == 0) { |   240           && selector.argumentCount == 0) { | 
|   237         target = backend.jsArrayRemoveLast; |   241         target = backend.jsArrayRemoveLast; | 
|   238       } else if (selectorName == backend.jsArrayAdd.name |   242       } else if (selectorName == backend.jsArrayAdd.name | 
|   239                  && selector.argumentCount == 1 |   243                  && selector.argumentCount == 1 | 
|   240                  && selector.namedArgumentCount == 0 |   244                  && selector.namedArgumentCount == 0 | 
|   241                  && !compiler.enableTypeAssertions) { |   245                  && !compiler.enableTypeAssertions) { | 
| (...skipping 28 matching lines...) Expand all  Loading... | 
|   270         && node.inputs[1].isInteger(types); |   274         && node.inputs[1].isInteger(types); | 
|   271   } |   275   } | 
|   272  |   276  | 
|   273   HInstruction visitInvokeStatic(HInvokeStatic node) { |   277   HInstruction visitInvokeStatic(HInvokeStatic node) { | 
|   274     if (isFixedSizeListConstructor(node)) { |   278     if (isFixedSizeListConstructor(node)) { | 
|   275       node.guaranteedType = HType.FIXED_ARRAY; |   279       node.guaranteedType = HType.FIXED_ARRAY; | 
|   276     } |   280     } | 
|   277     return node; |   281     return node; | 
|   278   } |   282   } | 
|   279  |   283  | 
|   280   HInstruction visitInvokeDynamic(HInvokeDynamic node) { |   284   HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 
|   281     if (node.isInterceptorCall) return handleInterceptorCall(node); |   285     if (node.isInterceptorCall) return handleInterceptorCall(node); | 
|   282     HType receiverType = types[node.receiver]; |   286     HType receiverType = types[node.receiver]; | 
|   283     if (receiverType.isExact()) { |   287     if (receiverType.isExact()) { | 
|   284       HBoundedType type = receiverType; |   288       HBoundedType type = receiverType; | 
|   285       Element element = type.lookupMember(node.selector.name); |   289       Element element = type.lookupMember(node.selector.name); | 
|   286       // TODO(ngeoffray): Also fold if it's a getter or variable. |   290       // TODO(ngeoffray): Also fold if it's a getter or variable. | 
|   287       if (element != null && element.isFunction()) { |   291       if (element != null && element.isFunction()) { | 
|   288         if (node.selector.applies(element, compiler)) { |   292         if (node.selector.applies(element, compiler)) { | 
|   289           FunctionElement method = element; |   293           FunctionElement method = element; | 
|   290           FunctionSignature parameters = method.computeSignature(compiler); |   294           FunctionSignature parameters = method.computeSignature(compiler); | 
|   291           if (parameters.optionalParameterCount == 0) { |   295           if (parameters.optionalParameterCount == 0) { | 
|   292             node.element = element; |   296             node.element = element; | 
|   293           } |   297           } | 
|   294           // TODO(ngeoffray): If the method has optional parameters, |   298           // TODO(ngeoffray): If the method has optional parameters, | 
|   295           // we should pass the default values here. |   299           // we should pass the default values here. | 
|   296         } |   300         } | 
|   297       } |   301       } | 
|   298     } |   302     } | 
|   299     return node; |   303     return node; | 
|   300   } |   304   } | 
|   301  |   305  | 
|   302   /** |   306   /** | 
|   303    * Turns a primitive instruction (e.g. [HIndex], [HAdd], ...) into a |   307    * Turns a primitive instruction (e.g. [HIndex], [HAdd], ...) into a | 
|   304    * [HInvokeDynamic] because we know the receiver is not a JS |   308    * [HInvokeDynamic] because we know the receiver is not a JS | 
|   305    * primitive object. |   309    * primitive object. | 
|   306    */ |   310    */ | 
|   307   HInstruction fromPrimitiveInstructionToDynamicInvocation(HInvokeStatic node, |   311   HInstruction fromPrimitiveInstructionToDynamicInvocation(HInstruction node, | 
|   308                                                            Selector selector) { |   312                                                            Selector selector) { | 
|   309     HBoundedType type = types[node.inputs[1]]; |   313     HBoundedType type = types[node.inputs[1]]; | 
|   310     HInvokeDynamicMethod result = new HInvokeDynamicMethod( |   314     HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 
|   311         selector, |   315         selector, | 
|   312         node.inputs.getRange(1, node.inputs.length - 1)); |   316         node.inputs.getRange(1, node.inputs.length - 1)); | 
|   313     if (type.isExact()) { |   317     if (type.isExact()) { | 
|   314       HBoundedType concrete = type; |   318       HBoundedType concrete = type; | 
|   315       result.element = concrete.lookupMember(selector.name); |   319       result.element = concrete.lookupMember(selector.name); | 
|   316     } |   320     } | 
|   317     return result; |   321     return result; | 
|   318   } |   322   } | 
|   319  |   323  | 
|   320   HInstruction visitIntegerCheck(HIntegerCheck node) { |   324   HInstruction visitIntegerCheck(HIntegerCheck node) { | 
|   321     HInstruction value = node.value; |   325     HInstruction value = node.value; | 
|   322     if (value.isInteger(types)) return value; |   326     if (value.isInteger(types)) return value; | 
|   323     if (value.isConstant()) { |   327     if (value.isConstant()) { | 
|   324       HConstant constantInstruction = value; |   328       HConstant constantInstruction = value; | 
|   325       assert(!constantInstruction.constant.isInt()); |   329       assert(!constantInstruction.constant.isInt()); | 
|   326       if (!constantSystem.isInt(constantInstruction.constant)) { |   330       if (!constantSystem.isInt(constantInstruction.constant)) { | 
|   327         // -0.0 is a double but will pass the runtime integer check. |   331         // -0.0 is a double but will pass the runtime integer check. | 
|   328         node.alwaysFalse = true; |   332         node.alwaysFalse = true; | 
|   329       } |   333       } | 
|   330     } |   334     } | 
|   331     return node; |   335     return node; | 
|   332   } |   336   } | 
|   333  |   337  | 
|   334  |  | 
|   335   HInstruction visitIndex(HIndex node) { |  | 
|   336     if (!node.receiver.canBePrimitive(types)) { |  | 
|   337       Selector selector = new Selector.index(); |  | 
|   338       return fromPrimitiveInstructionToDynamicInvocation(node, selector); |  | 
|   339     } |  | 
|   340     return node; |  | 
|   341   } |  | 
|   342  |  | 
|   343   HInstruction visitIndexAssign(HIndexAssign node) { |   338   HInstruction visitIndexAssign(HIndexAssign node) { | 
|   344     if (!node.receiver.canBePrimitive(types)) { |   339     if (!node.receiver.canBePrimitive(types)) { | 
|   345       Selector selector = new Selector.indexSet(); |   340       Selector selector = new Selector.indexSet(); | 
|   346       return fromPrimitiveInstructionToDynamicInvocation(node, selector); |   341       return fromPrimitiveInstructionToDynamicInvocation(node, selector); | 
|   347     } |   342     } | 
|   348     return node; |   343     return node; | 
|   349   } |   344   } | 
|   350  |   345  | 
|   351   HInstruction visitInvokeBinary(HInvokeBinary node) { |   346   HInstruction visitInvokeBinary(HInvokeBinary node) { | 
|   352     HInstruction left = node.left; |   347     HInstruction left = node.left; | 
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   796     HIntegerCheck check = new HIntegerCheck(value); |   791     HIntegerCheck check = new HIntegerCheck(value); | 
|   797     node.block.addBefore(node, check); |   792     node.block.addBefore(node, check); | 
|   798     Set<HInstruction> dominatedUsers = value.dominatedUsers(node); |   793     Set<HInstruction> dominatedUsers = value.dominatedUsers(node); | 
|   799     for (HInstruction user in dominatedUsers) { |   794     for (HInstruction user in dominatedUsers) { | 
|   800       user.changeUse(value, check); |   795       user.changeUse(value, check); | 
|   801     } |   796     } | 
|   802     return check; |   797     return check; | 
|   803   } |   798   } | 
|   804  |   799  | 
|   805   void visitIndex(HIndex node) { |   800   void visitIndex(HIndex node) { | 
|   806     if (!node.receiver.isIndexablePrimitive(types)) return; |  | 
|   807     if (boundsChecked.contains(node)) return; |   801     if (boundsChecked.contains(node)) return; | 
|   808     HInstruction index = node.index; |   802     HInstruction index = node.index; | 
|   809     if (!node.index.isInteger(types)) { |   803     if (!node.index.isInteger(types)) { | 
|   810       index = insertIntegerCheck(node, index); |   804       index = insertIntegerCheck(node, index); | 
|   811     } |   805     } | 
|   812     index = insertBoundsCheck(node, node.receiver, index); |   806     index = insertBoundsCheck(node, node.receiver, index); | 
|   813     node.changeUse(node.index, index); |   807     node.changeUse(node.index, index); | 
|   814     assert(node.isBuiltin(types)); |  | 
|   815   } |   808   } | 
|   816  |   809  | 
|   817   void visitIndexAssign(HIndexAssign node) { |   810   void visitIndexAssign(HIndexAssign node) { | 
|   818     if (!node.receiver.isMutableArray(types)) return; |   811     if (!node.receiver.isMutableArray(types)) return; | 
|   819     if (boundsChecked.contains(node)) return; |   812     if (boundsChecked.contains(node)) return; | 
|   820     HInstruction index = node.index; |   813     HInstruction index = node.index; | 
|   821     if (!node.index.isInteger(types)) { |   814     if (!node.index.isInteger(types)) { | 
|   822       index = insertIntegerCheck(node, index); |   815       index = insertIntegerCheck(node, index); | 
|   823     } |   816     } | 
|   824     index = insertBoundsCheck(node, node.receiver, index); |   817     index = insertBoundsCheck(node, node.receiver, index); | 
| (...skipping 652 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1477     HInstruction receiver = interceptor.receiver; |  1470     HInstruction receiver = interceptor.receiver; | 
|  1478     for (var user in receiver.usedBy) { |  1471     for (var user in receiver.usedBy) { | 
|  1479       if (user is HInterceptor && interceptor.dominates(user)) { |  1472       if (user is HInterceptor && interceptor.dominates(user)) { | 
|  1480         user.interceptedClasses = interceptor.interceptedClasses; |  1473         user.interceptedClasses = interceptor.interceptedClasses; | 
|  1481       } |  1474       } | 
|  1482     } |  1475     } | 
|  1483   } |  1476   } | 
|  1484  |  1477  | 
|  1485   // TODO(ngeoffray): Also implement it for non-intercepted calls. |  1478   // TODO(ngeoffray): Also implement it for non-intercepted calls. | 
|  1486 } |  1479 } | 
| OLD | NEW |