Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/builder.dart

Issue 15818003: - Inline iterator calls made for a "for in". (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698