| 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 class SsaFunctionCompiler implements FunctionCompiler { | 7 class SsaFunctionCompiler implements FunctionCompiler { |
| 8 SsaCodeGeneratorTask generator; | 8 SsaCodeGeneratorTask generator; |
| 9 SsaBuilderTask builder; | 9 SsaBuilderTask builder; |
| 10 SsaOptimizerTask optimizer; | 10 SsaOptimizerTask optimizer; |
| (...skipping 3209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3220 * [selector]. | 3220 * [selector]. |
| 3221 */ | 3221 */ |
| 3222 void generateInstanceGetterWithCompiledReceiver(ast.Send send, | 3222 void generateInstanceGetterWithCompiledReceiver(ast.Send send, |
| 3223 Selector selector, | 3223 Selector selector, |
| 3224 HInstruction receiver) { | 3224 HInstruction receiver) { |
| 3225 assert(Elements.isInstanceSend(send, elements)); | 3225 assert(Elements.isInstanceSend(send, elements)); |
| 3226 assert(selector.isGetter); | 3226 assert(selector.isGetter); |
| 3227 pushInvokeDynamic(send, selector, [receiver]); | 3227 pushInvokeDynamic(send, selector, [receiver]); |
| 3228 } | 3228 } |
| 3229 | 3229 |
| 3230 /// Inserts a call to checkDeferredIsLoaded for [prefixElement]. |
| 3231 /// If [prefixElement] is [null] ndo nothing. |
| 3232 void generateIsDeferredLoadedCheckIfNeeded(PrefixElement prefixElement, |
| 3233 ast.Node location) { |
| 3234 if (prefixElement == null) return; |
| 3235 String loadId = |
| 3236 compiler.deferredLoadTask.importDeferName[prefixElement.deferredImport]; |
| 3237 HInstruction loadIdConstant = addConstantString(loadId); |
| 3238 String uri = prefixElement.deferredImport.uri.dartString.slowToString(); |
| 3239 HInstruction uriConstant = addConstantString(uri); |
| 3240 Element helper = backend.getCheckDeferredIsLoaded(); |
| 3241 pushInvokeStatic(location, helper, [loadIdConstant, uriConstant]); |
| 3242 pop(); |
| 3243 } |
| 3244 |
| 3230 /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that | 3245 /// Inserts a call to checkDeferredIsLoaded if the send has a prefix that |
| 3231 /// resolves to a deferred library. | 3246 /// resolves to a deferred library. |
| 3232 void generateIsDeferredLoadedCheckIfNeeded(ast.Send node) { | 3247 void generateIsDeferredLoadedCheckOfSend(ast.Send node) { |
| 3233 DeferredLoadTask deferredTask = compiler.deferredLoadTask; | 3248 generateIsDeferredLoadedCheckIfNeeded( |
| 3234 PrefixElement prefixElement = | 3249 compiler.deferredLoadTask.deferredPrefixElement(node, elements), |
| 3235 deferredTask.deferredPrefixElement(node, elements); | 3250 node); |
| 3236 if (prefixElement != null) { | |
| 3237 String loadId = | |
| 3238 deferredTask.importDeferName[prefixElement.deferredImport]; | |
| 3239 HInstruction loadIdConstant = addConstantString(loadId); | |
| 3240 String uri = prefixElement.deferredImport.uri.dartString.slowToString(); | |
| 3241 HInstruction uriConstant = addConstantString(uri); | |
| 3242 Element helper = backend.getCheckDeferredIsLoaded(); | |
| 3243 pushInvokeStatic(node, helper, [loadIdConstant, uriConstant]); | |
| 3244 pop(); | |
| 3245 } | |
| 3246 } | 3251 } |
| 3247 | 3252 |
| 3248 /// Generate read access of an unresolved static or top level entity. | 3253 /// Generate read access of an unresolved static or top level entity. |
| 3249 void generateStaticUnresolvedGet(ast.Send node, Element element) { | 3254 void generateStaticUnresolvedGet(ast.Send node, Element element) { |
| 3250 if (element is ErroneousElement) { | 3255 if (element is ErroneousElement) { |
| 3251 // An erroneous element indicates an unresolved static getter. | 3256 // An erroneous element indicates an unresolved static getter. |
| 3252 generateThrowNoSuchMethod( | 3257 generateThrowNoSuchMethod( |
| 3253 node, | 3258 node, |
| 3254 noSuchMethodTargetSymbolString(element, 'get'), | 3259 noSuchMethodTargetSymbolString(element, 'get'), |
| 3255 argumentNodes: const Link<ast.Node>()); | 3260 argumentNodes: const Link<ast.Node>()); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3287 if (!type.containsAll(compiler.world) && | 3292 if (!type.containsAll(compiler.world) && |
| 3288 !instruction.isConstantNull()) { | 3293 !instruction.isConstantNull()) { |
| 3289 // TODO(13429): The inferrer should know that an element | 3294 // TODO(13429): The inferrer should know that an element |
| 3290 // cannot be null. | 3295 // cannot be null. |
| 3291 instruction.instructionType = type.nonNullable(); | 3296 instruction.instructionType = type.nonNullable(); |
| 3292 } | 3297 } |
| 3293 } | 3298 } |
| 3294 | 3299 |
| 3295 /// Read a static or top level [field]. | 3300 /// Read a static or top level [field]. |
| 3296 void generateStaticFieldGet(ast.Send node, FieldElement field) { | 3301 void generateStaticFieldGet(ast.Send node, FieldElement field) { |
| 3297 generateIsDeferredLoadedCheckIfNeeded(node); | 3302 generateIsDeferredLoadedCheckOfSend(node); |
| 3298 | 3303 |
| 3299 ConstantExpression constant = | 3304 ConstantExpression constant = |
| 3300 backend.constants.getConstantForVariable(field); | 3305 backend.constants.getConstantForVariable(field); |
| 3301 if (constant != null) { | 3306 if (constant != null) { |
| 3302 if (!field.isAssignable) { | 3307 if (!field.isAssignable) { |
| 3303 // A static final or const. Get its constant value and inline it if | 3308 // A static final or const. Get its constant value and inline it if |
| 3304 // the value can be compiled eagerly. | 3309 // the value can be compiled eagerly. |
| 3305 generateStaticConstGet(node, field, constant); | 3310 generateStaticConstGet(node, field, constant); |
| 3306 } else { | 3311 } else { |
| 3307 // TODO(5346): Try to avoid the need for calling [declaration] before | 3312 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 3308 // creating an [HStatic]. | 3313 // creating an [HStatic]. |
| 3309 HInstruction instruction = new HStatic( | 3314 HInstruction instruction = new HStatic( |
| 3310 field.declaration, | 3315 field.declaration, |
| 3311 TypeMaskFactory.inferredTypeForElement(field, compiler)); | 3316 TypeMaskFactory.inferredTypeForElement(field, compiler)); |
| 3312 push(instruction); | 3317 push(instruction); |
| 3313 } | 3318 } |
| 3314 } else { | 3319 } else { |
| 3315 HInstruction instruction = new HLazyStatic( | 3320 HInstruction instruction = new HLazyStatic( |
| 3316 field, | 3321 field, |
| 3317 TypeMaskFactory.inferredTypeForElement(field, compiler)); | 3322 TypeMaskFactory.inferredTypeForElement(field, compiler)); |
| 3318 push(instruction); | 3323 push(instruction); |
| 3319 } | 3324 } |
| 3320 } | 3325 } |
| 3321 | 3326 |
| 3322 /// Generate a getter invocation of the static or top level [getter]. | 3327 /// Generate a getter invocation of the static or top level [getter]. |
| 3323 void generateStaticGetterGet(ast.Send node, MethodElement getter) { | 3328 void generateStaticGetterGet(ast.Send node, MethodElement getter) { |
| 3324 if (getter.isDeferredLoaderGetter) { | 3329 if (getter.isDeferredLoaderGetter) { |
| 3325 generateDeferredLoaderGet(node, getter); | 3330 generateDeferredLoaderGet(node, getter); |
| 3326 } else { | 3331 } else { |
| 3327 generateIsDeferredLoadedCheckIfNeeded(node); | 3332 generateIsDeferredLoadedCheckOfSend(node); |
| 3328 pushInvokeStatic(node, getter, <HInstruction>[]); | 3333 pushInvokeStatic(node, getter, <HInstruction>[]); |
| 3329 } | 3334 } |
| 3330 } | 3335 } |
| 3331 | 3336 |
| 3332 /// Generate a dynamic getter invocation. | 3337 /// Generate a dynamic getter invocation. |
| 3333 void generateDynamicGet(ast.Send node) { | 3338 void generateDynamicGet(ast.Send node) { |
| 3334 HInstruction receiver = generateInstanceSendReceiver(node); | 3339 HInstruction receiver = generateInstanceSendReceiver(node); |
| 3335 generateInstanceGetterWithCompiledReceiver( | 3340 generateInstanceGetterWithCompiledReceiver( |
| 3336 node, elements.getSelector(node), receiver); | 3341 node, elements.getSelector(node), receiver); |
| 3337 } | 3342 } |
| 3338 | 3343 |
| 3339 /// Generate a closurization of the static or top level [function]. | 3344 /// Generate a closurization of the static or top level [function]. |
| 3340 void generateStaticFunctionGet(ast.Send node, MethodElement function) { | 3345 void generateStaticFunctionGet(ast.Send node, MethodElement function) { |
| 3341 generateIsDeferredLoadedCheckIfNeeded(node); | 3346 generateIsDeferredLoadedCheckOfSend(node); |
| 3342 // TODO(5346): Try to avoid the need for calling [declaration] before | 3347 // TODO(5346): Try to avoid the need for calling [declaration] before |
| 3343 // creating an [HStatic]. | 3348 // creating an [HStatic]. |
| 3344 push(new HStatic(function.declaration, backend.nonNullType)); | 3349 push(new HStatic(function.declaration, backend.nonNullType)); |
| 3345 // TODO(ahe): This should be registered in codegen. | 3350 // TODO(ahe): This should be registered in codegen. |
| 3346 registry.registerGetOfStaticFunction(function.declaration); | 3351 registry.registerGetOfStaticFunction(function.declaration); |
| 3347 } | 3352 } |
| 3348 | 3353 |
| 3349 /// Read a local variable, function or parameter. | 3354 /// Read a local variable, function or parameter. |
| 3350 void handleLocalGet(LocalElement local) { | 3355 void handleLocalGet(LocalElement local) { |
| 3351 stack.add(localsHandler.readLocal(local)); | 3356 stack.add(localsHandler.readLocal(local)); |
| (...skipping 1291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4643 // The new object will now be referenced through the | 4648 // The new object will now be referenced through the |
| 4644 // `setRuntimeTypeInfo` call. We therefore set the type of that | 4649 // `setRuntimeTypeInfo` call. We therefore set the type of that |
| 4645 // instruction to be of the object's type. | 4650 // instruction to be of the object's type. |
| 4646 assert(stack.last is HInvokeStatic || stack.last == newObject); | 4651 assert(stack.last is HInvokeStatic || stack.last == newObject); |
| 4647 stack.last.instructionType = newObject.instructionType; | 4652 stack.last.instructionType = newObject.instructionType; |
| 4648 return pop(); | 4653 return pop(); |
| 4649 } | 4654 } |
| 4650 | 4655 |
| 4651 handleNewSend(ast.NewExpression node) { | 4656 handleNewSend(ast.NewExpression node) { |
| 4652 ast.Send send = node.send; | 4657 ast.Send send = node.send; |
| 4653 generateIsDeferredLoadedCheckIfNeeded(send); | 4658 generateIsDeferredLoadedCheckOfSend(send); |
| 4654 | 4659 |
| 4655 bool isFixedList = false; | 4660 bool isFixedList = false; |
| 4656 bool isFixedListConstructorCall = | 4661 bool isFixedListConstructorCall = |
| 4657 Elements.isFixedListConstructorCall(elements[send], send, compiler); | 4662 Elements.isFixedListConstructorCall(elements[send], send, compiler); |
| 4658 bool isGrowableListConstructorCall = | 4663 bool isGrowableListConstructorCall = |
| 4659 Elements.isGrowableListConstructorCall(elements[send], send, compiler); | 4664 Elements.isGrowableListConstructorCall(elements[send], send, compiler); |
| 4660 | 4665 |
| 4661 TypeMask computeType(element) { | 4666 TypeMask computeType(element) { |
| 4662 Element originalElement = elements[send]; | 4667 Element originalElement = elements[send]; |
| 4663 if (isFixedListConstructorCall | 4668 if (isFixedListConstructorCall |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4708 if (isSymbolConstructor) { | 4713 if (isSymbolConstructor) { |
| 4709 constructor = compiler.symbolValidatedConstructor; | 4714 constructor = compiler.symbolValidatedConstructor; |
| 4710 assert(invariant(send, constructor != null, | 4715 assert(invariant(send, constructor != null, |
| 4711 message: 'Constructor Symbol.validated is missing')); | 4716 message: 'Constructor Symbol.validated is missing')); |
| 4712 callStructure = compiler.symbolValidatedConstructorSelector.callStructure; | 4717 callStructure = compiler.symbolValidatedConstructorSelector.callStructure; |
| 4713 assert(invariant(send, callStructure != null, | 4718 assert(invariant(send, callStructure != null, |
| 4714 message: 'Constructor Symbol.validated is missing')); | 4719 message: 'Constructor Symbol.validated is missing')); |
| 4715 } | 4720 } |
| 4716 | 4721 |
| 4717 bool isRedirected = constructorDeclaration.isRedirectingFactory; | 4722 bool isRedirected = constructorDeclaration.isRedirectingFactory; |
| 4723 if (!constructorDeclaration.isCyclicRedirection) { |
| 4724 // Insert a check for every deferred redirection on the path to the |
| 4725 // final target. |
| 4726 ConstructorElement target = constructorDeclaration; |
| 4727 while (target.isRedirectingFactory) { |
| 4728 if (constructorDeclaration.redirectionDeferredPrefix != null) { |
| 4729 generateIsDeferredLoadedCheckIfNeeded( |
| 4730 target.redirectionDeferredPrefix, |
| 4731 node); |
| 4732 } |
| 4733 target = target.immediateRedirectionTarget; |
| 4734 } |
| 4735 } |
| 4718 InterfaceType type = elements.getType(node); | 4736 InterfaceType type = elements.getType(node); |
| 4719 InterfaceType expectedType = | 4737 InterfaceType expectedType = |
| 4720 constructorDeclaration.computeEffectiveTargetType(type); | 4738 constructorDeclaration.computeEffectiveTargetType(type); |
| 4721 expectedType = localsHandler.substInContext(expectedType); | 4739 expectedType = localsHandler.substInContext(expectedType); |
| 4722 | 4740 |
| 4723 if (compiler.elementHasCompileTimeError(constructor)) { | 4741 if (compiler.elementHasCompileTimeError(constructor)) { |
| 4724 // TODO(ahe): Do something like [generateWrongArgumentCountError]. | 4742 // TODO(ahe): Do something like [generateWrongArgumentCountError]. |
| 4725 stack.add(graph.addConstantNull(compiler)); | 4743 stack.add(graph.addConstantNull(compiler)); |
| 4726 return; | 4744 return; |
| 4727 } | 4745 } |
| (...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4901 | 4919 |
| 4902 visitStaticSend(ast.Send node) { | 4920 visitStaticSend(ast.Send node) { |
| 4903 internalError(node, "Unexpected visitStaticSend"); | 4921 internalError(node, "Unexpected visitStaticSend"); |
| 4904 } | 4922 } |
| 4905 | 4923 |
| 4906 /// Generate an invocation to the static or top level [function]. | 4924 /// Generate an invocation to the static or top level [function]. |
| 4907 void generateStaticFunctionInvoke( | 4925 void generateStaticFunctionInvoke( |
| 4908 ast.Send node, | 4926 ast.Send node, |
| 4909 FunctionElement function, | 4927 FunctionElement function, |
| 4910 CallStructure callStructure) { | 4928 CallStructure callStructure) { |
| 4911 generateIsDeferredLoadedCheckIfNeeded(node); | 4929 generateIsDeferredLoadedCheckOfSend(node); |
| 4912 | 4930 |
| 4913 List<HInstruction> inputs = makeStaticArgumentList( | 4931 List<HInstruction> inputs = makeStaticArgumentList( |
| 4914 callStructure, | 4932 callStructure, |
| 4915 node.arguments, | 4933 node.arguments, |
| 4916 function.implementation); | 4934 function.implementation); |
| 4917 | 4935 |
| 4918 if (function == compiler.identicalFunction) { | 4936 if (function == compiler.identicalFunction) { |
| 4919 pushWithPosition( | 4937 pushWithPosition( |
| 4920 new HIdentity(inputs[0], inputs[1], null, backend.boolType), node); | 4938 new HIdentity(inputs[0], inputs[1], null, backend.boolType), node); |
| 4921 return; | 4939 return; |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5116 ConstantExpression constant, | 5134 ConstantExpression constant, |
| 5117 ast.NodeList arguments, | 5135 ast.NodeList arguments, |
| 5118 CallStructure callStructure, | 5136 CallStructure callStructure, |
| 5119 _) { | 5137 _) { |
| 5120 generateConstantTypeLiteral(node); | 5138 generateConstantTypeLiteral(node); |
| 5121 generateTypeLiteralCall(node); | 5139 generateTypeLiteralCall(node); |
| 5122 } | 5140 } |
| 5123 | 5141 |
| 5124 /// Generate the constant value for a constant type literal. | 5142 /// Generate the constant value for a constant type literal. |
| 5125 void generateConstantTypeLiteral(ast.Send node) { | 5143 void generateConstantTypeLiteral(ast.Send node) { |
| 5126 generateIsDeferredLoadedCheckIfNeeded(node); | 5144 generateIsDeferredLoadedCheckOfSend(node); |
| 5127 // TODO(karlklose): add type representation | 5145 // TODO(karlklose): add type representation |
| 5128 if (node.isCall) { | 5146 if (node.isCall) { |
| 5129 // The node itself is not a constant but we register the selector (the | 5147 // The node itself is not a constant but we register the selector (the |
| 5130 // identifier that refers to the class/typedef) as a constant. | 5148 // identifier that refers to the class/typedef) as a constant. |
| 5131 stack.add(addConstant(node.selector)); | 5149 stack.add(addConstant(node.selector)); |
| 5132 } else { | 5150 } else { |
| 5133 stack.add(addConstant(node)); | 5151 stack.add(addConstant(node)); |
| 5134 } | 5152 } |
| 5135 } | 5153 } |
| 5136 | 5154 |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5440 rhs = pop(); | 5458 rhs = pop(); |
| 5441 } | 5459 } |
| 5442 visitBinarySend(receiver, rhs, | 5460 visitBinarySend(receiver, rhs, |
| 5443 elements.getOperatorSelectorInComplexSendSet(node), | 5461 elements.getOperatorSelectorInComplexSendSet(node), |
| 5444 node, | 5462 node, |
| 5445 location: node.assignmentOperator); | 5463 location: node.assignmentOperator); |
| 5446 } | 5464 } |
| 5447 | 5465 |
| 5448 @override | 5466 @override |
| 5449 handleSendSet(ast.SendSet node) { | 5467 handleSendSet(ast.SendSet node) { |
| 5450 generateIsDeferredLoadedCheckIfNeeded(node); | 5468 generateIsDeferredLoadedCheckOfSend(node); |
| 5451 Element element = elements[node]; | 5469 Element element = elements[node]; |
| 5452 if (!Elements.isUnresolved(element) && element.impliesType) { | 5470 if (!Elements.isUnresolved(element) && element.impliesType) { |
| 5453 ast.Identifier selector = node.selector; | 5471 ast.Identifier selector = node.selector; |
| 5454 generateThrowNoSuchMethod(node, selector.source, | 5472 generateThrowNoSuchMethod(node, selector.source, |
| 5455 argumentNodes: node.arguments); | 5473 argumentNodes: node.arguments); |
| 5456 return; | 5474 return; |
| 5457 } | 5475 } |
| 5458 ast.Operator op = node.assignmentOperator; | 5476 ast.Operator op = node.assignmentOperator; |
| 5459 if (node.isSuperCall) { | 5477 if (node.isSuperCall) { |
| 5460 HInstruction result; | 5478 HInstruction result; |
| (...skipping 2152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7613 if (unaliased is TypedefType) throw 'unable to unalias $type'; | 7631 if (unaliased is TypedefType) throw 'unable to unalias $type'; |
| 7614 unaliased.accept(this, builder); | 7632 unaliased.accept(this, builder); |
| 7615 } | 7633 } |
| 7616 | 7634 |
| 7617 void visitDynamicType(DynamicType type, SsaBuilder builder) { | 7635 void visitDynamicType(DynamicType type, SsaBuilder builder) { |
| 7618 JavaScriptBackend backend = builder.compiler.backend; | 7636 JavaScriptBackend backend = builder.compiler.backend; |
| 7619 ClassElement cls = backend.findHelper('DynamicRuntimeType'); | 7637 ClassElement cls = backend.findHelper('DynamicRuntimeType'); |
| 7620 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); | 7638 builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
| 7621 } | 7639 } |
| 7622 } | 7640 } |
| OLD | NEW |