| 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 /** | 7 /** |
| 8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
| 9 * methods. We need to override [Element.computeType] because our | 9 * methods. We need to override [Element.computeType] because our |
| 10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
| (...skipping 1113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1124 return result; | 1124 return result; |
| 1125 } | 1125 } |
| 1126 | 1126 |
| 1127 /** | 1127 /** |
| 1128 * Documentation wanted -- johnniwinther | 1128 * Documentation wanted -- johnniwinther |
| 1129 * | 1129 * |
| 1130 * Invariant: [function] must be an implementation element. | 1130 * Invariant: [function] must be an implementation element. |
| 1131 */ | 1131 */ |
| 1132 InliningState enterInlinedMethod(FunctionElement function, | 1132 InliningState enterInlinedMethod(FunctionElement function, |
| 1133 Selector selector, | 1133 Selector selector, |
| 1134 Link<Node> argumentsNodes, | |
| 1135 List<HInstruction> providedArguments, | 1134 List<HInstruction> providedArguments, |
| 1136 Node currentNode) { | 1135 Node currentNode) { |
| 1137 assert(invariant(function, function.isImplementation)); | 1136 assert(invariant(function, function.isImplementation)); |
| 1138 | 1137 |
| 1139 List<HInstruction> compiledArguments; | 1138 List<HInstruction> compiledArguments; |
| 1140 bool isInstanceMember = function.isInstanceMember(); | 1139 bool isInstanceMember = function.isInstanceMember(); |
| 1141 | 1140 |
| 1142 if (isInstanceMember && !function.isGenerativeConstructorBody()) { | 1141 if (currentNode == null |
| 1142 || currentNode.asForIn() != null |
| 1143 || !isInstanceMember |
| 1144 || function.isGenerativeConstructorBody()) { |
| 1145 // For these cases, the provided arguments must match the |
| 1146 // expected parameters. |
| 1147 assert(providedArguments != null); |
| 1148 compiledArguments = providedArguments; |
| 1149 } else { |
| 1150 Send send = currentNode.asSend(); |
| 1143 assert(providedArguments != null); | 1151 assert(providedArguments != null); |
| 1144 compiledArguments = new List<HInstruction>(); | 1152 compiledArguments = new List<HInstruction>(); |
| 1145 compiledArguments.add(providedArguments[0]); | 1153 compiledArguments.add(providedArguments[0]); |
| 1146 // [providedArguments] contains the arguments given in our | 1154 // [providedArguments] contains the arguments given in our |
| 1147 // internal order (see [addDynamicSendArgumentsToList]). So we | 1155 // internal order (see [addDynamicSendArgumentsToList]). So we |
| 1148 // call [Selector.addArgumentsToList] only for getting the | 1156 // call [Selector.addArgumentsToList] only for getting the |
| 1149 // default values of the optional parameters. | 1157 // default values of the optional parameters. |
| 1150 bool succeeded = selector.addArgumentsToList( | 1158 bool succeeded = selector.addArgumentsToList( |
| 1151 argumentsNodes, | 1159 send.isPropertyAccess ? null : send.arguments, |
| 1152 compiledArguments, | 1160 compiledArguments, |
| 1153 function, | 1161 function, |
| 1154 (node) => null, | 1162 (node) => null, |
| 1155 handleConstantForOptionalParameter, | 1163 handleConstantForOptionalParameter, |
| 1156 compiler); | 1164 compiler); |
| 1157 int argumentIndex = 1; // Skip receiver. | 1165 int argumentIndex = 1; // Skip receiver. |
| 1158 // [compiledArguments] now only contains the default values of | 1166 // [compiledArguments] now only contains the default values of |
| 1159 // the optional parameters that were not provided by | 1167 // the optional parameters that were not provided by |
| 1160 // [argumentsNodes]. So we iterate over [providedArguments] to fill | 1168 // [argumentsNodes]. So we iterate over [providedArguments] to fill |
| 1161 // in all the arguments. | 1169 // in all the arguments. |
| 1162 for (int i = 1; i < compiledArguments.length; i++) { | 1170 for (int i = 1; i < compiledArguments.length; i++) { |
| 1163 if (compiledArguments[i] == null) { | 1171 if (compiledArguments[i] == null) { |
| 1164 compiledArguments[i] = providedArguments[argumentIndex++]; | 1172 compiledArguments[i] = providedArguments[argumentIndex++]; |
| 1165 } | 1173 } |
| 1166 } | 1174 } |
| 1167 // The caller of [enterInlinedMethod] has ensured the selector | 1175 // The caller of [enterInlinedMethod] has ensured the selector |
| 1168 // matches the element. | 1176 // matches the element. |
| 1169 assert(succeeded); | 1177 assert(succeeded); |
| 1170 } else { | |
| 1171 assert(providedArguments != null); | |
| 1172 compiledArguments = providedArguments; | |
| 1173 } | 1178 } |
| 1174 | 1179 |
| 1175 // Create the inlining state after evaluating the arguments, that | 1180 // Create the inlining state after evaluating the arguments, that |
| 1176 // may have an impact on the state of the current method. | 1181 // may have an impact on the state of the current method. |
| 1177 InliningState state = new InliningState( | 1182 InliningState state = new InliningState( |
| 1178 function, returnElement, returnType, elements, stack, localsHandler); | 1183 function, returnElement, returnType, elements, stack, localsHandler); |
| 1179 LocalsHandler newLocalsHandler = new LocalsHandler(this); | 1184 LocalsHandler newLocalsHandler = new LocalsHandler(this); |
| 1180 newLocalsHandler.closureData = | 1185 newLocalsHandler.closureData = |
| 1181 compiler.closureToClassMapper.computeClosureToClassMapping( | 1186 compiler.closureToClassMapper.computeClosureToClassMapping( |
| 1182 function, function.parseNode(compiler), elements); | 1187 function, function.parseNode(compiler), elements); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1229 stack = state.oldStack; | 1234 stack = state.oldStack; |
| 1230 localsHandler = state.oldLocalsHandler; | 1235 localsHandler = state.oldLocalsHandler; |
| 1231 } | 1236 } |
| 1232 | 1237 |
| 1233 /** | 1238 /** |
| 1234 * Try to inline [element] within the currect context of the | 1239 * Try to inline [element] within the currect context of the |
| 1235 * builder. The insertion point is the state of the builder. | 1240 * builder. The insertion point is the state of the builder. |
| 1236 */ | 1241 */ |
| 1237 bool tryInlineMethod(Element element, | 1242 bool tryInlineMethod(Element element, |
| 1238 Selector selector, | 1243 Selector selector, |
| 1239 Link<Node> argumentsNodes, | |
| 1240 List<HInstruction> providedArguments, | 1244 List<HInstruction> providedArguments, |
| 1241 Node currentNode) { | 1245 Node currentNode) { |
| 1242 // We cannot inline a method from a deferred library into a method | 1246 // We cannot inline a method from a deferred library into a method |
| 1243 // which isn't deferred. | 1247 // which isn't deferred. |
| 1244 // TODO(ahe): But we should still inline into the same | 1248 // TODO(ahe): But we should still inline into the same |
| 1245 // connected-component of the deferred library. | 1249 // connected-component of the deferred library. |
| 1246 if (compiler.deferredLoadTask.isDeferred(element)) return false; | 1250 if (compiler.deferredLoadTask.isDeferred(element)) return false; |
| 1251 if (compiler.disableInlining) return false; |
| 1252 if (inliningStack.length > MAX_INLINING_DEPTH) return false; |
| 1247 | 1253 |
| 1248 if (compiler.disableInlining) return false; | |
| 1249 // Ensure that [element] is an implementation element. | 1254 // Ensure that [element] is an implementation element. |
| 1250 element = element.implementation; | 1255 element = element.implementation; |
| 1251 // TODO(floitsch): find a cleaner way to know if the element is a function | |
| 1252 // containing nodes. | |
| 1253 // [PartialFunctionElement]s are [FunctionElement]s that have [Node]s. | |
| 1254 if (element is !PartialFunctionElement | |
| 1255 && !element.isGenerativeConstructorBody()) { | |
| 1256 return false; | |
| 1257 } | |
| 1258 if (inliningStack.length > MAX_INLINING_DEPTH) return false; | |
| 1259 // Don't inline recursive calls. We use the same elements for the inlined | |
| 1260 // functions and would thus clobber our local variables. | |
| 1261 // Use [:element.declaration:] since [work.element] is always a declaration. | |
| 1262 if (currentElement == element.declaration) return false; | |
| 1263 for (int i = 0; i < inliningStack.length; i++) { | |
| 1264 if (inliningStack[i].function == element) return false; | |
| 1265 } | |
| 1266 | |
| 1267 FunctionElement function = element; | 1256 FunctionElement function = element; |
| 1268 bool canBeInlined = backend.canBeInlined[function]; | 1257 bool canBeInlined = backend.canBeInlined[function]; |
| 1269 if (canBeInlined == false) return false; | 1258 if (canBeInlined == false) return false; |
| 1270 assert(selector != null | 1259 assert(selector != null |
| 1271 || Elements.isStaticOrTopLevel(element) | 1260 || Elements.isStaticOrTopLevel(element) |
| 1272 || element.isGenerativeConstructorBody()); | 1261 || element.isGenerativeConstructorBody()); |
| 1273 if (selector != null && !selector.applies(function, compiler)) return false; | 1262 if (selector != null && !selector.applies(function, compiler)) return false; |
| 1274 | 1263 |
| 1275 // Don't inline operator== methods if the parameter can be null. | 1264 // Don't inline operator== methods if the parameter can be null. |
| 1276 if (element.name == const SourceString('==')) { | 1265 if (element.name == const SourceString('==')) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1297 // Add an explicit null check on the receiver before doing the | 1286 // Add an explicit null check on the receiver before doing the |
| 1298 // inlining. We use [element] to get the same name in the NoSuchMethodError | 1287 // inlining. We use [element] to get the same name in the NoSuchMethodError |
| 1299 // message as if we had called it. | 1288 // message as if we had called it. |
| 1300 if (element.isInstanceMember() | 1289 if (element.isInstanceMember() |
| 1301 && !element.isGenerativeConstructorBody() | 1290 && !element.isGenerativeConstructorBody() |
| 1302 && (selector.mask == null || selector.mask.isNullable)) { | 1291 && (selector.mask == null || selector.mask.isNullable)) { |
| 1303 addWithPosition( | 1292 addWithPosition( |
| 1304 new HFieldGet(element, providedArguments[0]), currentNode); | 1293 new HFieldGet(element, providedArguments[0]), currentNode); |
| 1305 } | 1294 } |
| 1306 InliningState state = enterInlinedMethod( | 1295 InliningState state = enterInlinedMethod( |
| 1307 function, selector, argumentsNodes, providedArguments, currentNode); | 1296 function, selector, providedArguments, currentNode); |
| 1308 | 1297 |
| 1309 inlinedFrom(element, () { | 1298 inlinedFrom(element, () { |
| 1310 FunctionElement function = element; | 1299 FunctionElement function = element; |
| 1311 FunctionSignature signature = function.computeSignature(compiler); | 1300 FunctionSignature signature = function.computeSignature(compiler); |
| 1312 signature.orderedForEachParameter((Element parameter) { | 1301 signature.orderedForEachParameter((Element parameter) { |
| 1313 HInstruction argument = localsHandler.readLocal(parameter); | 1302 HInstruction argument = localsHandler.readLocal(parameter); |
| 1314 potentiallyCheckType(argument, parameter.computeType(compiler)); | 1303 potentiallyCheckType(argument, parameter.computeType(compiler)); |
| 1315 }); | 1304 }); |
| 1316 element.isGenerativeConstructor() | 1305 element.isGenerativeConstructor() |
| 1317 ? buildFactory(element) | 1306 ? buildFactory(element) |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1666 }); | 1655 }); |
| 1667 } | 1656 } |
| 1668 | 1657 |
| 1669 // If there are locals that escape (ie mutated in closures), we | 1658 // If there are locals that escape (ie mutated in closures), we |
| 1670 // pass the box to the constructor. | 1659 // pass the box to the constructor. |
| 1671 ClosureScope scopeData = parameterClosureData.capturingScopes[node]; | 1660 ClosureScope scopeData = parameterClosureData.capturingScopes[node]; |
| 1672 if (scopeData != null) { | 1661 if (scopeData != null) { |
| 1673 bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); | 1662 bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); |
| 1674 } | 1663 } |
| 1675 | 1664 |
| 1676 if (tryInlineMethod(body, null, null, bodyCallInputs, function)) { | 1665 if (tryInlineMethod(body, null, bodyCallInputs, function)) { |
| 1677 pop(); | 1666 pop(); |
| 1678 } else { | 1667 } else { |
| 1679 HInvokeConstructorBody invoke = | 1668 HInvokeConstructorBody invoke = |
| 1680 new HInvokeConstructorBody(body, bodyCallInputs); | 1669 new HInvokeConstructorBody(body, bodyCallInputs); |
| 1681 invoke.sideEffects = | 1670 invoke.sideEffects = |
| 1682 compiler.world.getSideEffectsOfElement(constructor); | 1671 compiler.world.getSideEffectsOfElement(constructor); |
| 1683 add(invoke); | 1672 add(invoke); |
| 1684 } | 1673 } |
| 1685 } | 1674 } |
| 1686 if (inliningStack.isEmpty) { | 1675 if (inliningStack.isEmpty) { |
| (...skipping 1991 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3678 return type.isIndexable(compiler); | 3667 return type.isIndexable(compiler); |
| 3679 } else if (selector.isIndexSet()) { | 3668 } else if (selector.isIndexSet()) { |
| 3680 DartType classType = element.getEnclosingClass().computeType(compiler); | 3669 DartType classType = element.getEnclosingClass().computeType(compiler); |
| 3681 HType type = new HType.nonNullExact(classType, compiler); | 3670 HType type = new HType.nonNullExact(classType, compiler); |
| 3682 return type.isMutableIndexable(compiler); | 3671 return type.isMutableIndexable(compiler); |
| 3683 } else { | 3672 } else { |
| 3684 return false; | 3673 return false; |
| 3685 } | 3674 } |
| 3686 } | 3675 } |
| 3687 | 3676 |
| 3688 bool isOptimizableOperation(Send node, Selector selector, Element element) { | 3677 bool isOptimizableOperation(Selector selector, Element element) { |
| 3689 ClassElement cls = element.getEnclosingClass(); | 3678 ClassElement cls = element.getEnclosingClass(); |
| 3690 if (isOptimizableOperationOnIndexable(selector, element)) return true; | 3679 if (isOptimizableOperationOnIndexable(selector, element)) return true; |
| 3691 if (!backend.interceptedClasses.contains(cls)) return false; | 3680 if (!backend.interceptedClasses.contains(cls)) return false; |
| 3692 if (selector.isOperator()) return true; | 3681 if (selector.isOperator()) return true; |
| 3693 if (selector.isSetter()) return true; | 3682 if (selector.isSetter()) return true; |
| 3694 if (selector.isIndex()) return true; | 3683 if (selector.isIndex()) return true; |
| 3695 if (selector.isIndexSet()) return true; | 3684 if (selector.isIndexSet()) return true; |
| 3696 if (element == backend.jsArrayAdd | 3685 if (element == backend.jsArrayAdd |
| 3697 || element == backend.jsArrayRemoveLast | 3686 || element == backend.jsArrayRemoveLast |
| 3698 || element == backend.jsStringSplit) { | 3687 || element == backend.jsStringSplit) { |
| 3699 return true; | 3688 return true; |
| 3700 } | 3689 } |
| 3701 return false; | 3690 return false; |
| 3702 } | 3691 } |
| 3703 | 3692 |
| 3704 Element element = compiler.world.locateSingleElement(selector); | 3693 Element element = compiler.world.locateSingleElement(selector); |
| 3705 if (element != null | 3694 if (element != null |
| 3706 // TODO(ngeoffray): Handle non-send nodes. | 3695 && !element.isField() |
| 3707 && (node.asSend() != null) | |
| 3708 && !(element.isGetter() && selector.isCall()) | 3696 && !(element.isGetter() && selector.isCall()) |
| 3709 && !(element.isFunction() && selector.isGetter()) | 3697 && !(element.isFunction() && selector.isGetter()) |
| 3710 && !isOptimizableOperation(node, selector, element)) { | 3698 && !isOptimizableOperation(selector, element)) { |
| 3711 Send send = node.asSend(); | 3699 if (tryInlineMethod(element, selector, arguments, node)) { |
| 3712 Link<Node> nodes = send.isPropertyAccess ? null : send.arguments; | |
| 3713 if (tryInlineMethod(element, selector, nodes, arguments, node)) { | |
| 3714 return; | 3700 return; |
| 3715 } | 3701 } |
| 3716 } | 3702 } |
| 3717 | 3703 |
| 3718 HInstruction receiver = arguments[0]; | 3704 HInstruction receiver = arguments[0]; |
| 3719 List<HInstruction> inputs = <HInstruction>[]; | 3705 List<HInstruction> inputs = <HInstruction>[]; |
| 3720 bool isIntercepted = backend.isInterceptedSelector(selector); | 3706 bool isIntercepted = backend.isInterceptedSelector(selector); |
| 3721 if (isIntercepted) { | 3707 if (isIntercepted) { |
| 3722 inputs.add(invokeInterceptor(receiver)); | 3708 inputs.add(invokeInterceptor(receiver)); |
| 3723 } | 3709 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 3736 pushWithPosition( | 3722 pushWithPosition( |
| 3737 new HInvokeDynamicMethod(selector, inputs, isIntercepted), | 3723 new HInvokeDynamicMethod(selector, inputs, isIntercepted), |
| 3738 location); | 3724 location); |
| 3739 } | 3725 } |
| 3740 } | 3726 } |
| 3741 | 3727 |
| 3742 void pushInvokeStatic(Node location, | 3728 void pushInvokeStatic(Node location, |
| 3743 Element element, | 3729 Element element, |
| 3744 List<HInstruction> arguments, | 3730 List<HInstruction> arguments, |
| 3745 [HType type = null]) { | 3731 [HType type = null]) { |
| 3746 if (tryInlineMethod(element, null, null, arguments, location)) { | 3732 if (tryInlineMethod(element, null, arguments, location)) { |
| 3747 return; | 3733 return; |
| 3748 } | 3734 } |
| 3749 | 3735 |
| 3750 if (type == null) { | 3736 if (type == null) { |
| 3751 type = new HType.inferredReturnTypeForElement(element, compiler); | 3737 type = new HType.inferredReturnTypeForElement(element, compiler); |
| 3752 if (type.isUnknown()) { | 3738 if (type.isUnknown()) { |
| 3753 // TODO(ngeoffray): Only do this if knowing the return type is | 3739 // TODO(ngeoffray): Only do this if knowing the return type is |
| 3754 // useful. | 3740 // useful. |
| 3755 type = | 3741 type = |
| 3756 builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange( | 3742 builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange( |
| (...skipping 431 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4188 // Generate a structure equivalent to: | 4174 // Generate a structure equivalent to: |
| 4189 // Iterator<E> $iter = <iterable>.iterator; | 4175 // Iterator<E> $iter = <iterable>.iterator; |
| 4190 // while ($iter.moveNext()) { | 4176 // while ($iter.moveNext()) { |
| 4191 // E <declaredIdentifier> = $iter.current; | 4177 // E <declaredIdentifier> = $iter.current; |
| 4192 // <body> | 4178 // <body> |
| 4193 // } | 4179 // } |
| 4194 | 4180 |
| 4195 // The iterator is shared between initializer, condition and body. | 4181 // The iterator is shared between initializer, condition and body. |
| 4196 HInstruction iterator; | 4182 HInstruction iterator; |
| 4197 void buildInitializer() { | 4183 void buildInitializer() { |
| 4198 Selector selector = compiler.iteratorSelector; | 4184 Selector selector = elements.getIteratorSelector(node); |
| 4199 visit(node.expression); | 4185 visit(node.expression); |
| 4200 HInstruction receiver = pop(); | 4186 HInstruction receiver = pop(); |
| 4201 pushInvokeDynamic(node, selector, [receiver]); | 4187 pushInvokeDynamic(node, selector, [receiver]); |
| 4202 iterator = pop(); | 4188 iterator = pop(); |
| 4203 } | 4189 } |
| 4204 HInstruction buildCondition() { | 4190 HInstruction buildCondition() { |
| 4205 Selector selector = compiler.moveNextSelector; | 4191 Selector selector = elements.getMoveNextSelector(node); |
| 4206 pushInvokeDynamic(node, selector, [iterator]); | 4192 pushInvokeDynamic(node, selector, [iterator]); |
| 4207 return popBoolified(); | 4193 return popBoolified(); |
| 4208 } | 4194 } |
| 4209 void buildBody() { | 4195 void buildBody() { |
| 4210 Selector call = compiler.currentSelector; | 4196 Selector call = elements.getCurrentSelector(node); |
| 4211 pushInvokeDynamic(node, call, [iterator]); | 4197 pushInvokeDynamic(node, call, [iterator]); |
| 4212 | 4198 |
| 4213 Node identifier = node.declaredIdentifier; | 4199 Node identifier = node.declaredIdentifier; |
| 4214 Element variable = elements[identifier]; | 4200 Element variable = elements[identifier]; |
| 4215 Selector selector = elements.getSelector(identifier); | 4201 Selector selector = elements.getSelector(identifier); |
| 4216 | 4202 |
| 4217 HInstruction value = pop(); | 4203 HInstruction value = pop(); |
| 4218 if (identifier.asSend() != null | 4204 if (identifier.asSend() != null |
| 4219 && Elements.isInstanceSend(identifier, elements)) { | 4205 && Elements.isInstanceSend(identifier, elements)) { |
| 4220 HInstruction receiver = generateInstanceSendReceiver(identifier); | 4206 HInstruction receiver = generateInstanceSendReceiver(identifier); |
| (...skipping 1157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5378 new HSubGraphBlockInformation(elseBranch.graph)); | 5364 new HSubGraphBlockInformation(elseBranch.graph)); |
| 5379 | 5365 |
| 5380 HBasicBlock conditionStartBlock = conditionBranch.block; | 5366 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 5381 conditionStartBlock.setBlockFlow(info, joinBlock); | 5367 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 5382 SubGraph conditionGraph = conditionBranch.graph; | 5368 SubGraph conditionGraph = conditionBranch.graph; |
| 5383 HIf branch = conditionGraph.end.last; | 5369 HIf branch = conditionGraph.end.last; |
| 5384 assert(branch is HIf); | 5370 assert(branch is HIf); |
| 5385 branch.blockInformation = conditionStartBlock.blockFlow; | 5371 branch.blockInformation = conditionStartBlock.blockFlow; |
| 5386 } | 5372 } |
| 5387 } | 5373 } |
| OLD | NEW |