| 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 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 258 } | 258 } |
| 259 | 259 |
| 260 // Try converting the instruction to a builtin instruction. | 260 // Try converting the instruction to a builtin instruction. |
| 261 HInstruction instruction = | 261 HInstruction instruction = |
| 262 node.specializer.tryConvertToBuiltin(node, compiler); | 262 node.specializer.tryConvertToBuiltin(node, compiler); |
| 263 if (instruction != null) return instruction; | 263 if (instruction != null) return instruction; |
| 264 | 264 |
| 265 Selector selector = node.selector; | 265 Selector selector = node.selector; |
| 266 HInstruction input = node.inputs[1]; | 266 HInstruction input = node.inputs[1]; |
| 267 | 267 |
| 268 if (selector.isCall() || selector.isOperator()) { | 268 if (selector.isCall || selector.isOperator) { |
| 269 Element target; | 269 Element target; |
| 270 if (input.isExtendableArray(compiler)) { | 270 if (input.isExtendableArray(compiler)) { |
| 271 if (selector.applies(backend.jsArrayRemoveLast, compiler)) { | 271 if (selector.applies(backend.jsArrayRemoveLast, compiler)) { |
| 272 target = backend.jsArrayRemoveLast; | 272 target = backend.jsArrayRemoveLast; |
| 273 } else if (selector.applies(backend.jsArrayAdd, compiler)) { | 273 } else if (selector.applies(backend.jsArrayAdd, compiler)) { |
| 274 // The codegen special cases array calls, but does not | 274 // The codegen special cases array calls, but does not |
| 275 // inline argument type checks. | 275 // inline argument type checks. |
| 276 if (!compiler.enableTypeAssertions) { | 276 if (!compiler.enableTypeAssertions) { |
| 277 target = backend.jsArrayAdd; | 277 target = backend.jsArrayAdd; |
| 278 } | 278 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 305 // HInvokeDynamicMethod and not create a HForeign because | 305 // HInvokeDynamicMethod and not create a HForeign because |
| 306 // HForeign is too opaque for the SsaCheckInserter (that adds a | 306 // HForeign is too opaque for the SsaCheckInserter (that adds a |
| 307 // bounds check on removeLast). Once we start inlining, the | 307 // bounds check on removeLast). Once we start inlining, the |
| 308 // bounds check will become explicit, so we won't need this | 308 // bounds check will become explicit, so we won't need this |
| 309 // optimization. | 309 // optimization. |
| 310 HInvokeDynamicMethod result = new HInvokeDynamicMethod( | 310 HInvokeDynamicMethod result = new HInvokeDynamicMethod( |
| 311 node.selector, node.inputs.sublist(1), node.instructionType); | 311 node.selector, node.inputs.sublist(1), node.instructionType); |
| 312 result.element = target; | 312 result.element = target; |
| 313 return result; | 313 return result; |
| 314 } | 314 } |
| 315 } else if (selector.isGetter()) { | 315 } else if (selector.isGetter) { |
| 316 if (selector.asUntyped.applies(backend.jsIndexableLength, compiler)) { | 316 if (selector.asUntyped.applies(backend.jsIndexableLength, compiler)) { |
| 317 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); | 317 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); |
| 318 if (optimized != null) return optimized; | 318 if (optimized != null) return optimized; |
| 319 } | 319 } |
| 320 } | 320 } |
| 321 | 321 |
| 322 return node; | 322 return node; |
| 323 } | 323 } |
| 324 | 324 |
| 325 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 325 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
| 326 if (node.isInterceptedCall) { | 326 if (node.isInterceptedCall) { |
| 327 HInstruction folded = handleInterceptedCall(node); | 327 HInstruction folded = handleInterceptedCall(node); |
| 328 if (folded != node) return folded; | 328 if (folded != node) return folded; |
| 329 } | 329 } |
| 330 | 330 |
| 331 TypeMask receiverType = node.getDartReceiver(compiler).instructionType; | 331 TypeMask receiverType = node.getDartReceiver(compiler).instructionType; |
| 332 Selector selector = new TypedSelector(receiverType, node.selector); | 332 Selector selector = new TypedSelector(receiverType, node.selector); |
| 333 Element element = compiler.world.locateSingleElement(selector); | 333 Element element = compiler.world.locateSingleElement(selector); |
| 334 // TODO(ngeoffray): Also fold if it's a getter or variable. | 334 // TODO(ngeoffray): Also fold if it's a getter or variable. |
| 335 if (element != null | 335 if (element != null |
| 336 && element.isFunction() | 336 && element.isFunction |
| 337 // If we found out that the only target is a [:noSuchMethod:], | 337 // If we found out that the only target is a [:noSuchMethod:], |
| 338 // we just ignore it. | 338 // we just ignore it. |
| 339 && element.name == selector.name) { | 339 && element.name == selector.name) { |
| 340 FunctionElement method = element; | 340 FunctionElement method = element; |
| 341 | 341 |
| 342 if (method.isNative()) { | 342 if (method.isNative) { |
| 343 HInstruction folded = tryInlineNativeMethod(node, method); | 343 HInstruction folded = tryInlineNativeMethod(node, method); |
| 344 if (folded != null) return folded; | 344 if (folded != null) return folded; |
| 345 } else { | 345 } else { |
| 346 // TODO(ngeoffray): If the method has optional parameters, | 346 // TODO(ngeoffray): If the method has optional parameters, |
| 347 // we should pass the default values. | 347 // we should pass the default values. |
| 348 FunctionSignature parameters = method.functionSignature; | 348 FunctionSignature parameters = method.functionSignature; |
| 349 if (parameters.optionalParameterCount == 0 | 349 if (parameters.optionalParameterCount == 0 |
| 350 || parameters.parameterCount == node.selector.argumentCount) { | 350 || parameters.parameterCount == node.selector.argumentCount) { |
| 351 node.element = element; | 351 node.element = element; |
| 352 } | 352 } |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 570 simplifyCondition(node.elseBlock, condition, isNegated); | 570 simplifyCondition(node.elseBlock, condition, isNegated); |
| 571 return node; | 571 return node; |
| 572 } | 572 } |
| 573 | 573 |
| 574 HInstruction visitIs(HIs node) { | 574 HInstruction visitIs(HIs node) { |
| 575 DartType type = node.typeExpression; | 575 DartType type = node.typeExpression; |
| 576 Element element = type.element; | 576 Element element = type.element; |
| 577 | 577 |
| 578 if (!node.isRawCheck) { | 578 if (!node.isRawCheck) { |
| 579 return node; | 579 return node; |
| 580 } else if (element.isTypedef()) { | 580 } else if (element.isTypedef) { |
| 581 return node; | 581 return node; |
| 582 } else if (element == compiler.functionClass) { | 582 } else if (element == compiler.functionClass) { |
| 583 return node; | 583 return node; |
| 584 } | 584 } |
| 585 | 585 |
| 586 if (element == compiler.objectClass || type.treatAsDynamic) { | 586 if (element == compiler.objectClass || type.treatAsDynamic) { |
| 587 return graph.addConstantBool(true, compiler); | 587 return graph.addConstantBool(true, compiler); |
| 588 } | 588 } |
| 589 | 589 |
| 590 HInstruction expression = node.expression; | 590 HInstruction expression = node.expression; |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 736 Element field = findConcreteFieldForDynamicAccess(receiver, node.selector); | 736 Element field = findConcreteFieldForDynamicAccess(receiver, node.selector); |
| 737 if (field == null) return node; | 737 if (field == null) return node; |
| 738 return directFieldGet(receiver, field); | 738 return directFieldGet(receiver, field); |
| 739 } | 739 } |
| 740 | 740 |
| 741 HInstruction directFieldGet(HInstruction receiver, Element field) { | 741 HInstruction directFieldGet(HInstruction receiver, Element field) { |
| 742 ast.Modifiers modifiers = field.modifiers; | 742 ast.Modifiers modifiers = field.modifiers; |
| 743 bool isAssignable = !compiler.world.fieldNeverChanges(field); | 743 bool isAssignable = !compiler.world.fieldNeverChanges(field); |
| 744 | 744 |
| 745 TypeMask type; | 745 TypeMask type; |
| 746 if (field.getEnclosingClass().isNative()) { | 746 if (field.enclosingClass.isNative) { |
| 747 type = TypeMaskFactory.fromNativeBehavior( | 747 type = TypeMaskFactory.fromNativeBehavior( |
| 748 native.NativeBehavior.ofFieldLoad(field, compiler), | 748 native.NativeBehavior.ofFieldLoad(field, compiler), |
| 749 compiler); | 749 compiler); |
| 750 } else { | 750 } else { |
| 751 type = TypeMaskFactory.inferredTypeForElement(field, compiler); | 751 type = TypeMaskFactory.inferredTypeForElement(field, compiler); |
| 752 } | 752 } |
| 753 | 753 |
| 754 return new HFieldGet( | 754 return new HFieldGet( |
| 755 field, receiver, type, isAssignable: isAssignable); | 755 field, receiver, type, isAssignable: isAssignable); |
| 756 } | 756 } |
| 757 | 757 |
| 758 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 758 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
| 759 if (node.isInterceptedCall) { | 759 if (node.isInterceptedCall) { |
| 760 HInstruction folded = handleInterceptedCall(node); | 760 HInstruction folded = handleInterceptedCall(node); |
| 761 if (folded != node) return folded; | 761 if (folded != node) return folded; |
| 762 } | 762 } |
| 763 | 763 |
| 764 HInstruction receiver = node.getDartReceiver(compiler); | 764 HInstruction receiver = node.getDartReceiver(compiler); |
| 765 VariableElement field = | 765 VariableElement field = |
| 766 findConcreteFieldForDynamicAccess(receiver, node.selector); | 766 findConcreteFieldForDynamicAccess(receiver, node.selector); |
| 767 if (field == null || !field.isAssignable()) return node; | 767 if (field == null || !field.isAssignable) return node; |
| 768 // Use [:node.inputs.last:] in case the call follows the | 768 // Use [:node.inputs.last:] in case the call follows the |
| 769 // interceptor calling convention, but is not a call on an | 769 // interceptor calling convention, but is not a call on an |
| 770 // interceptor. | 770 // interceptor. |
| 771 HInstruction value = node.inputs.last; | 771 HInstruction value = node.inputs.last; |
| 772 if (compiler.enableTypeAssertions) { | 772 if (compiler.enableTypeAssertions) { |
| 773 DartType type = field.type; | 773 DartType type = field.type; |
| 774 if (!type.treatAsRaw || type.kind == TypeKind.TYPE_VARIABLE) { | 774 if (!type.treatAsRaw || type.kind == TypeKind.TYPE_VARIABLE) { |
| 775 // We cannot generate the correct type representation here, so don't | 775 // We cannot generate the correct type representation here, so don't |
| 776 // inline this access. | 776 // inline this access. |
| 777 return node; | 777 return node; |
| (...skipping 819 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1597 dominatedUsers.forEach((HInstruction user) { | 1597 dominatedUsers.forEach((HInstruction user) { |
| 1598 user.changeUse(input, newInput); | 1598 user.changeUse(input, newInput); |
| 1599 }); | 1599 }); |
| 1600 } | 1600 } |
| 1601 | 1601 |
| 1602 void visitIs(HIs instruction) { | 1602 void visitIs(HIs instruction) { |
| 1603 DartType type = instruction.typeExpression; | 1603 DartType type = instruction.typeExpression; |
| 1604 Element element = type.element; | 1604 Element element = type.element; |
| 1605 if (!instruction.isRawCheck) { | 1605 if (!instruction.isRawCheck) { |
| 1606 return; | 1606 return; |
| 1607 } else if (element.isTypedef()) { | 1607 } else if (element.isTypedef) { |
| 1608 return; | 1608 return; |
| 1609 } | 1609 } |
| 1610 | 1610 |
| 1611 List<HInstruction> ifUsers = <HInstruction>[]; | 1611 List<HInstruction> ifUsers = <HInstruction>[]; |
| 1612 List<HInstruction> notIfUsers = <HInstruction>[]; | 1612 List<HInstruction> notIfUsers = <HInstruction>[]; |
| 1613 | 1613 |
| 1614 collectIfUsers(instruction, ifUsers, notIfUsers); | 1614 collectIfUsers(instruction, ifUsers, notIfUsers); |
| 1615 | 1615 |
| 1616 if (ifUsers.isEmpty && notIfUsers.isEmpty) return; | 1616 if (ifUsers.isEmpty && notIfUsers.isEmpty) return; |
| 1617 | 1617 |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1904 nonEscapingReceivers.add(instruction); | 1904 nonEscapingReceivers.add(instruction); |
| 1905 } | 1905 } |
| 1906 | 1906 |
| 1907 /** | 1907 /** |
| 1908 * Sets `receiver.element` to contain [value]. Kills all potential | 1908 * Sets `receiver.element` to contain [value]. Kills all potential |
| 1909 * places that may be affected by this update. | 1909 * places that may be affected by this update. |
| 1910 */ | 1910 */ |
| 1911 void registerFieldValueUpdate(Element element, | 1911 void registerFieldValueUpdate(Element element, |
| 1912 HInstruction receiver, | 1912 HInstruction receiver, |
| 1913 HInstruction value) { | 1913 HInstruction value) { |
| 1914 if (element.isNative()) return; // TODO(14955): Remove this restriction? | 1914 if (element.isNative) return; // TODO(14955): Remove this restriction? |
| 1915 // [value] is being set in some place in memory, we remove it from | 1915 // [value] is being set in some place in memory, we remove it from |
| 1916 // the non-escaping set. | 1916 // the non-escaping set. |
| 1917 nonEscapingReceivers.remove(value); | 1917 nonEscapingReceivers.remove(value); |
| 1918 Map<HInstruction, HInstruction> map = fieldValues.putIfAbsent( | 1918 Map<HInstruction, HInstruction> map = fieldValues.putIfAbsent( |
| 1919 element, () => <HInstruction, HInstruction> {}); | 1919 element, () => <HInstruction, HInstruction> {}); |
| 1920 map.forEach((key, value) { | 1920 map.forEach((key, value) { |
| 1921 if (mayAlias(receiver, key)) map[key] = null; | 1921 if (mayAlias(receiver, key)) map[key] = null; |
| 1922 }); | 1922 }); |
| 1923 map[receiver] = value; | 1923 map[receiver] = value; |
| 1924 } | 1924 } |
| 1925 | 1925 |
| 1926 /** | 1926 /** |
| 1927 * Registers that `receiver.element` is now [value]. | 1927 * Registers that `receiver.element` is now [value]. |
| 1928 */ | 1928 */ |
| 1929 void registerFieldValue(Element element, | 1929 void registerFieldValue(Element element, |
| 1930 HInstruction receiver, | 1930 HInstruction receiver, |
| 1931 HInstruction value) { | 1931 HInstruction value) { |
| 1932 if (element.isNative()) return; // TODO(14955): Remove this restriction? | 1932 if (element.isNative) return; // TODO(14955): Remove this restriction? |
| 1933 Map<HInstruction, HInstruction> map = fieldValues.putIfAbsent( | 1933 Map<HInstruction, HInstruction> map = fieldValues.putIfAbsent( |
| 1934 element, () => <HInstruction, HInstruction> {}); | 1934 element, () => <HInstruction, HInstruction> {}); |
| 1935 map[receiver] = value; | 1935 map[receiver] = value; |
| 1936 } | 1936 } |
| 1937 | 1937 |
| 1938 /** | 1938 /** |
| 1939 * Returns the value stored in `receiver.element`. Returns null if | 1939 * Returns the value stored in `receiver.element`. Returns null if |
| 1940 * we don't know. | 1940 * we don't know. |
| 1941 */ | 1941 */ |
| 1942 HInstruction lookupFieldValue(Element element, HInstruction receiver) { | 1942 HInstruction lookupFieldValue(Element element, HInstruction receiver) { |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2116 | 2116 |
| 2117 keyedValues.forEach((receiver, values) { | 2117 keyedValues.forEach((receiver, values) { |
| 2118 result.keyedValues[receiver] = | 2118 result.keyedValues[receiver] = |
| 2119 new Map<HInstruction, HInstruction>.from(values); | 2119 new Map<HInstruction, HInstruction>.from(values); |
| 2120 }); | 2120 }); |
| 2121 | 2121 |
| 2122 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2122 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
| 2123 return result; | 2123 return result; |
| 2124 } | 2124 } |
| 2125 } | 2125 } |
| OLD | NEW |