| 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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |