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

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

Issue 12385076: Infer types of catpured variables and use the types in the SSA builder. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 9 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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 // [readLocal] uses the [boxElement] to find its box. By replacing it 230 // [readLocal] uses the [boxElement] to find its box. By replacing it
231 // behind its back we can still get to the old values. 231 // behind its back we can still get to the old values.
232 updateLocal(boxElement, oldBox); 232 updateLocal(boxElement, oldBox);
233 HInstruction oldValue = readLocal(boxedVariable); 233 HInstruction oldValue = readLocal(boxedVariable);
234 updateLocal(boxElement, newBox); 234 updateLocal(boxElement, newBox);
235 updateLocal(boxedVariable, oldValue); 235 updateLocal(boxedVariable, oldValue);
236 } 236 }
237 updateLocal(boxElement, newBox); 237 updateLocal(boxElement, newBox);
238 } 238 }
239 239
240 HType cachedTypeOfThis;
241
242 HType getTypeOfThis() {
243 HType result = cachedTypeOfThis;
244 if (result == null) {
245 Element element = closureData.thisElement;
246 ClassElement cls = element.enclosingElement.getEnclosingClass();
247 Compiler compiler = builder.compiler;
248 // Use the raw type because we don't have the type context for the
249 // type parameters.
250 DartType type = cls.rawType;
251 if (compiler.world.isUsedAsMixin(cls)) {
252 // If the enclosing class is used as a mixin, [:this:] can be
253 // of the class that mixins the enclosing class. These two
254 // classes do not have a subclass relationship, so, for
255 // simplicity, we mark the type as an interface type.
256 result = new HType.nonNullSubtype(type, compiler);
257 } else {
258 result = new HType.nonNullSubclass(type, compiler);
259 }
260 cachedTypeOfThis = result;
261 }
262 return result;
263 }
264
265 /** 240 /**
266 * Documentation wanted -- johnniwinther 241 * Documentation wanted -- johnniwinther
267 * 242 *
268 * Invariant: [function] must be an implementation element. 243 * Invariant: [function] must be an implementation element.
269 */ 244 */
270 void startFunction(Element element, Expression node) { 245 void startFunction(Element element, Expression node) {
271 assert(invariant(node, element.isImplementation)); 246 assert(invariant(node, element.isImplementation));
272 Compiler compiler = builder.compiler; 247 Compiler compiler = builder.compiler;
273 closureData = compiler.closureToClassMapper.computeClosureToClassMapping( 248 closureData = compiler.closureToClassMapper.computeClosureToClassMapping(
274 element, node, builder.elements); 249 element, node, builder.elements);
275 250
276 if (element is FunctionElement) { 251 if (element is FunctionElement) {
277 FunctionElement functionElement = element; 252 FunctionElement functionElement = element;
278 FunctionSignature params = functionElement.computeSignature(compiler); 253 FunctionSignature params = functionElement.computeSignature(compiler);
279 params.orderedForEachParameter((Element parameterElement) { 254 params.orderedForEachParameter((Element parameterElement) {
280 if (element.isGenerativeConstructorBody()) { 255 if (element.isGenerativeConstructorBody()) {
281 ClosureScope scopeData = closureData.capturingScopes[node]; 256 ClosureScope scopeData = closureData.capturingScopes[node];
282 if (scopeData != null 257 if (scopeData != null
283 && scopeData.capturedVariableMapping.containsKey( 258 && scopeData.capturedVariableMapping.containsKey(
284 parameterElement)) { 259 parameterElement)) {
285 // The parameter will be a field in the box passed as the 260 // The parameter will be a field in the box passed as the
286 // last parameter. So no need to have it. 261 // last parameter. So no need to have it.
287 return; 262 return;
288 } 263 }
289 } 264 }
290 HInstruction parameter = builder.addParameter(parameterElement); 265 HInstruction parameter = builder.addParameter(parameterElement);
291 builder.parameters[parameterElement] = parameter; 266 builder.parameters[parameterElement] = parameter;
292 directLocals[parameterElement] = parameter; 267 directLocals[parameterElement] = parameter;
293 parameter.instructionType = 268 parameter.instructionType =
294 new HType.inferredForElement(parameterElement, compiler); 269 new HType.inferredTypeForElement(parameterElement, compiler);
295 }); 270 });
296 } 271 }
297 272
298 enterScope(node, element); 273 enterScope(node, element);
299 274
300 // If the freeVariableMapping is not empty, then this function was a 275 // If the freeVariableMapping is not empty, then this function was a
301 // nested closure that captures variables. Redirect the captured 276 // nested closure that captures variables. Redirect the captured
302 // variables to fields in the closure. 277 // variables to fields in the closure.
303 closureData.freeVariableMapping.forEach((Element from, Element to) { 278 closureData.freeVariableMapping.forEach((Element from, Element to) {
304 redirectElement(from, to); 279 redirectElement(from, to);
305 }); 280 });
306 if (closureData.isClosure()) { 281 if (closureData.isClosure()) {
307 // Inside closure redirect references to itself to [:this:]. 282 // Inside closure redirect references to itself to [:this:].
308 HThis thisInstruction = new HThis(closureData.thisElement); 283 HThis thisInstruction = new HThis(closureData.thisElement);
309 builder.graph.thisInstruction = thisInstruction; 284 builder.graph.thisInstruction = thisInstruction;
310 builder.graph.entry.addAtEntry(thisInstruction); 285 builder.graph.entry.addAtEntry(thisInstruction);
311 updateLocal(closureData.closureElement, thisInstruction); 286 updateLocal(closureData.closureElement, thisInstruction);
312 } else if (element.isInstanceMember() 287 } else if (element.isInstanceMember()
313 || element.isGenerativeConstructor()) { 288 || element.isGenerativeConstructor()) {
314 // Once closures have been mapped to classes their instance members might 289 // Once closures have been mapped to classes their instance members might
315 // not have any thisElement if the closure was created inside a static 290 // not have any thisElement if the closure was created inside a static
316 // context. 291 // context.
317 HThis thisInstruction = new HThis( 292 HThis thisInstruction = new HThis(
318 closureData.thisElement, getTypeOfThis()); 293 closureData.thisElement, builder.getTypeOfThis());
319 builder.graph.thisInstruction = thisInstruction; 294 builder.graph.thisInstruction = thisInstruction;
320 builder.graph.entry.addAtEntry(thisInstruction); 295 builder.graph.entry.addAtEntry(thisInstruction);
321 directLocals[closureData.thisElement] = thisInstruction; 296 directLocals[closureData.thisElement] = thisInstruction;
322 } 297 }
323 298
324 // If this method is an intercepted method, add the extra 299 // If this method is an intercepted method, add the extra
325 // parameter to it, that is the actual receiver for intercepted 300 // parameter to it, that is the actual receiver for intercepted
326 // classes, or the same as [:this:] for non-intercepted classes. 301 // classes, or the same as [:this:] for non-intercepted classes.
327 ClassElement cls = element.getEnclosingClass(); 302 ClassElement cls = element.getEnclosingClass();
328 if (builder.backend.isInterceptedMethod(element)) { 303 if (builder.backend.isInterceptedMethod(element)) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 if (isAccessedDirectly(element)) { 383 if (isAccessedDirectly(element)) {
409 if (directLocals[element] == null) { 384 if (directLocals[element] == null) {
410 builder.compiler.internalError("Cannot find value $element", 385 builder.compiler.internalError("Cannot find value $element",
411 element: element); 386 element: element);
412 } 387 }
413 return directLocals[element]; 388 return directLocals[element];
414 } else if (isStoredInClosureField(element)) { 389 } else if (isStoredInClosureField(element)) {
415 Element redirect = redirectionMapping[element]; 390 Element redirect = redirectionMapping[element];
416 HInstruction receiver = readLocal(closureData.closureElement); 391 HInstruction receiver = readLocal(closureData.closureElement);
417 HInstruction fieldGet = new HFieldGet(redirect, receiver); 392 HInstruction fieldGet = new HFieldGet(redirect, receiver);
393 fieldGet.instructionType = builder.getTypeOfCapturedVariable(element);
418 builder.add(fieldGet); 394 builder.add(fieldGet);
419 return fieldGet; 395 return fieldGet;
420 } else if (isBoxed(element)) { 396 } else if (isBoxed(element)) {
421 Element redirect = redirectionMapping[element]; 397 Element redirect = redirectionMapping[element];
422 // In the function that declares the captured variable the box is 398 // In the function that declares the captured variable the box is
423 // accessed as direct local. Inside the nested closure the box is 399 // accessed as direct local. Inside the nested closure the box is
424 // accessed through a closure-field. 400 // accessed through a closure-field.
425 // Calling [readLocal] makes sure we generate the correct code to get 401 // Calling [readLocal] makes sure we generate the correct code to get
426 // the box. 402 // the box.
427 assert(redirect.enclosingElement.isVariable()); 403 assert(redirect.enclosingElement.isVariable());
428 HInstruction box = readLocal(redirect.enclosingElement); 404 HInstruction box = readLocal(redirect.enclosingElement);
429 HInstruction lookup = new HFieldGet(redirect, box); 405 HInstruction lookup = new HFieldGet(redirect, box);
406 lookup.instructionType = builder.getTypeOfCapturedVariable(element);
430 builder.add(lookup); 407 builder.add(lookup);
431 return lookup; 408 return lookup;
432 } else { 409 } else {
433 assert(isUsedInTry(element)); 410 assert(isUsedInTry(element));
434 HLocalValue local = getLocal(element); 411 HLocalValue local = getLocal(element);
435 HInstruction variable = new HLocalGet(element, local); 412 HInstruction variable = new HLocalGet(element, local);
436 builder.add(variable); 413 builder.add(variable);
437 return variable; 414 return variable;
438 } 415 }
439 } 416 }
440 417
441 HInstruction readThis() { 418 HInstruction readThis() {
442 HInstruction res = readLocal(closureData.thisElement); 419 HInstruction res = readLocal(closureData.thisElement);
443 if (res.instructionType == null) { 420 if (res.instructionType == null) {
444 res.instructionType = getTypeOfThis(); 421 res.instructionType = builder.getTypeOfThis();
445 } 422 }
446 return res; 423 return res;
447 } 424 }
448 425
449 HLocalValue getLocal(Element element) { 426 HLocalValue getLocal(Element element) {
450 // If the element is a parameter, we already have a 427 // If the element is a parameter, we already have a
451 // HParameterValue for it. We cannot create another one because 428 // HParameterValue for it. We cannot create another one because
452 // it could then have another name than the real parameter. And 429 // it could then have another name than the real parameter. And
453 // the other one would not know it is just a copy of the real 430 // the other one would not know it is just a copy of the real
454 // parameter. 431 // parameter.
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after
879 856
880 Constant compileVariable(VariableElement element) { 857 Constant compileVariable(VariableElement element) {
881 return compiler.constantHandler.compileVariable(element); 858 return compiler.constantHandler.compileVariable(element);
882 } 859 }
883 860
884 bool isLazilyInitialized(VariableElement element) { 861 bool isLazilyInitialized(VariableElement element) {
885 Constant initialValue = compileVariable(element); 862 Constant initialValue = compileVariable(element);
886 return initialValue == null; 863 return initialValue == null;
887 } 864 }
888 865
866 HType cachedTypeOfThis;
867
868 HType getTypeOfThis() {
869 HType result = cachedTypeOfThis;
870 if (result == null) {
871 Element element = localsHandler.closureData.thisElement;
872 ClassElement cls = element.enclosingElement.getEnclosingClass();
873 // Use the raw type because we don't have the type context for the
874 // type parameters.
875 DartType type = cls.rawType;
876 if (compiler.world.isUsedAsMixin(cls)) {
877 // If the enclosing class is used as a mixin, [:this:] can be
878 // of the class that mixins the enclosing class. These two
879 // classes do not have a subclass relationship, so, for
880 // simplicity, we mark the type as an interface type.
881 result = new HType.nonNullSubtype(type, compiler);
882 } else {
883 result = new HType.nonNullSubclass(type, compiler);
884 }
885 cachedTypeOfThis = result;
886 }
887 return result;
888 }
889
890 Map<Element, HType> cachedTypesOfCapturedVariables =
891 new Map<Element, HType>();
892
893 HType getTypeOfCapturedVariable(Element element) {
894 return cachedTypesOfCapturedVariables.putIfAbsent(element, () {
895 return new HType.inferredTypeForElement(element, compiler);
896 });
897 }
898
889 /** 899 /**
890 * Documentation wanted -- johnniwinther 900 * Documentation wanted -- johnniwinther
891 * 901 *
892 * Invariant: [functionElement] must be an implementation element. 902 * Invariant: [functionElement] must be an implementation element.
893 */ 903 */
894 HGraph buildMethod(FunctionElement functionElement) { 904 HGraph buildMethod(FunctionElement functionElement) {
895 assert(invariant(functionElement, functionElement.isImplementation)); 905 assert(invariant(functionElement, functionElement.isImplementation));
896 FunctionExpression function = functionElement.parseNode(compiler); 906 FunctionExpression function = functionElement.parseNode(compiler);
897 assert(function != null); 907 assert(function != null);
898 assert(!function.modifiers.isExternal()); 908 assert(!function.modifiers.isExternal());
(...skipping 1899 matching lines...) Expand 10 before | Expand all | Expand 10 after
2798 } 2808 }
2799 2809
2800 visitDynamicSend(Send node, {bool inline: true}) { 2810 visitDynamicSend(Send node, {bool inline: true}) {
2801 Selector selector = elements.getSelector(node); 2811 Selector selector = elements.getSelector(node);
2802 2812
2803 // TODO(kasperl): It would be much better to try to get the 2813 // TODO(kasperl): It would be much better to try to get the
2804 // guaranteed type of the receiver after we've evaluated it, but 2814 // guaranteed type of the receiver after we've evaluated it, but
2805 // because of the way inlining currently works that is hard to do 2815 // because of the way inlining currently works that is hard to do
2806 // with re-evaluating the receiver. 2816 // with re-evaluating the receiver.
2807 if (isThisSend(node)) { 2817 if (isThisSend(node)) {
2808 HType receiverType = localsHandler.getTypeOfThis(); 2818 HType receiverType = getTypeOfThis();
2809 selector = receiverType.refine(selector, compiler); 2819 selector = receiverType.refine(selector, compiler);
2810 } 2820 }
2811 2821
2812 Element element = compiler.world.locateSingleElement(selector); 2822 Element element = compiler.world.locateSingleElement(selector);
2813 bool isClosureCall = false; 2823 bool isClosureCall = false;
2814 if (inline && element != null) { 2824 if (inline && element != null) {
2815 if (tryInlineMethod(element, selector, node.arguments, node)) { 2825 if (tryInlineMethod(element, selector, node.arguments, node)) {
2816 if (element.isGetter()) { 2826 if (element.isGetter()) {
2817 // If the element is a getter, we are doing a closure call 2827 // If the element is a getter, we are doing a closure call
2818 // on what this getter returns. 2828 // on what this getter returns.
(...skipping 551 matching lines...) Expand 10 before | Expand all | Expand 10 after
3370 generateWrongArgumentCountError(node, element, node.arguments); 3380 generateWrongArgumentCountError(node, element, node.arguments);
3371 return; 3381 return;
3372 } 3382 }
3373 3383
3374 if (isIdenticalFunction) { 3384 if (isIdenticalFunction) {
3375 pushWithPosition(new HIdentity(inputs[1], inputs[2]), node); 3385 pushWithPosition(new HIdentity(inputs[1], inputs[2]), node);
3376 return; 3386 return;
3377 } 3387 }
3378 3388
3379 HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN); 3389 HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN);
3380 HType returnType = new HType.inferredForElement(element, compiler); 3390 HType returnType =
3391 new HType.inferredReturnTypeForElement(element, compiler);
3381 if (returnType.isUnknown()) { 3392 if (returnType.isUnknown()) {
3382 // TODO(ngeoffray): Only do this if knowing the return type is 3393 // TODO(ngeoffray): Only do this if knowing the return type is
3383 // useful. 3394 // useful.
3384 returnType = 3395 returnType =
3385 builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange( 3396 builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange(
3386 currentElement, element); 3397 currentElement, element);
3387 } 3398 }
3388 if (returnType != null) instruction.instructionType = returnType; 3399 if (returnType != null) instruction.instructionType = returnType;
3389 pushWithPosition(instruction, node); 3400 pushWithPosition(instruction, node);
3390 } else { 3401 } else {
(...skipping 1644 matching lines...) Expand 10 before | Expand all | Expand 10 after
5035 new HSubGraphBlockInformation(elseBranch.graph)); 5046 new HSubGraphBlockInformation(elseBranch.graph));
5036 5047
5037 HBasicBlock conditionStartBlock = conditionBranch.block; 5048 HBasicBlock conditionStartBlock = conditionBranch.block;
5038 conditionStartBlock.setBlockFlow(info, joinBlock); 5049 conditionStartBlock.setBlockFlow(info, joinBlock);
5039 SubGraph conditionGraph = conditionBranch.graph; 5050 SubGraph conditionGraph = conditionBranch.graph;
5040 HIf branch = conditionGraph.end.last; 5051 HIf branch = conditionGraph.end.last;
5041 assert(branch is HIf); 5052 assert(branch is HIf);
5042 branch.blockInformation = conditionStartBlock.blockFlow; 5053 branch.blockInformation = conditionStartBlock.blockFlow;
5043 } 5054 }
5044 } 5055 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698