| 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 class Interceptors { | 5 class Interceptors { |
| 6 Compiler compiler; | 6 Compiler compiler; |
| 7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
| 8 | 8 |
| 9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
| 10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 SsaBuilderTask(JavaScriptBackend backend) | 148 SsaBuilderTask(JavaScriptBackend backend) |
| 149 : interceptors = new Interceptors(backend.compiler), | 149 : interceptors = new Interceptors(backend.compiler), |
| 150 emitter = backend.emitter, | 150 emitter = backend.emitter, |
| 151 functionsCalledInLoop = new Set<FunctionElement>(), | 151 functionsCalledInLoop = new Set<FunctionElement>(), |
| 152 selectorsCalledInLoop = new Map<SourceString, Selector>(), | 152 selectorsCalledInLoop = new Map<SourceString, Selector>(), |
| 153 backend = backend, | 153 backend = backend, |
| 154 super(backend.compiler); | 154 super(backend.compiler); |
| 155 | 155 |
| 156 HGraph build(WorkItem work) { | 156 HGraph build(WorkItem work) { |
| 157 return measure(() { | 157 return measure(() { |
| 158 FunctionElement element = work.element; | 158 Element element = work.element; |
| 159 HInstruction.idCounter = 0; | 159 HInstruction.idCounter = 0; |
| 160 SsaBuilder builder = new SsaBuilder(this, work); | 160 SsaBuilder builder = new SsaBuilder(this, work); |
| 161 HGraph graph; | 161 HGraph graph; |
| 162 ElementKind kind = element.kind; | 162 ElementKind kind = element.kind; |
| 163 if (kind === ElementKind.GENERATIVE_CONSTRUCTOR) { | 163 if (kind === ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 164 graph = compileConstructor(builder, work); | 164 graph = compileConstructor(builder, work); |
| 165 } else if (kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY || | 165 } else if (kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY || |
| 166 kind === ElementKind.FUNCTION || | 166 kind === ElementKind.FUNCTION || |
| 167 kind === ElementKind.GETTER || | 167 kind === ElementKind.GETTER || |
| 168 kind === ElementKind.SETTER) { | 168 kind === ElementKind.SETTER) { |
| 169 graph = builder.buildMethod(work.element); | 169 graph = builder.buildMethod(work.element); |
| 170 } else if (kind === ElementKind.FIELD) { |
| 171 graph = builder.buildLazyInitializer(work.element); |
| 170 } | 172 } |
| 171 assert(graph.isValid()); | 173 assert(graph.isValid()); |
| 172 bool inLoop = functionsCalledInLoop.contains(element); | 174 if (kind !== ElementKind.FIELD) { |
| 173 if (!inLoop) { | 175 bool inLoop = functionsCalledInLoop.contains(element); |
| 174 Selector selector = selectorsCalledInLoop[element.name]; | 176 if (!inLoop) { |
| 175 inLoop = selector !== null && selector.applies(element, compiler); | 177 Selector selector = selectorsCalledInLoop[element.name]; |
| 178 inLoop = selector !== null && selector.applies(element, compiler); |
| 179 } |
| 180 graph.calledInLoop = inLoop; |
| 181 |
| 182 // If there is an estimate of the parameter types assume these types |
| 183 // when compiling. |
| 184 HTypeList parameterTypes = |
| 185 backend.optimisticParameterTypes( |
| 186 element); |
| 187 if (!parameterTypes.allUnknown) { |
| 188 FunctionElement functionElement = element; |
| 189 FunctionSignature signature = |
| 190 functionElement.computeSignature(compiler); |
| 191 int i = 0; |
| 192 signature.forEachParameter((Element param) { |
| 193 builder.parameters[param].guaranteedType = parameterTypes[i++]; |
| 194 }); |
| 195 } |
| 196 backend.registerParameterTypesOptimization(element, parameterTypes); |
| 176 } | 197 } |
| 177 graph.calledInLoop = inLoop; | |
| 178 | |
| 179 // If there is an estimate of the parameter types assume these types when | |
| 180 // compiling. | |
| 181 HTypeList parameterTypes = | |
| 182 backend.optimisticParameterTypes( | |
| 183 element); | |
| 184 if (!parameterTypes.allUnknown) { | |
| 185 FunctionSignature signature = element.computeSignature(compiler); | |
| 186 int i = 0; | |
| 187 signature.forEachParameter((Element param) { | |
| 188 builder.parameters[param].guaranteedType = parameterTypes[i++]; | |
| 189 }); | |
| 190 } | |
| 191 backend.registerParameterTypesOptimization(element, parameterTypes); | |
| 192 | 198 |
| 193 if (compiler.tracer.enabled) { | 199 if (compiler.tracer.enabled) { |
| 194 String name; | 200 String name; |
| 195 if (element.isMember()) { | 201 if (element.isMember()) { |
| 196 String className = element.getEnclosingClass().name.slowToString(); | 202 String className = element.getEnclosingClass().name.slowToString(); |
| 197 String memberName = element.name.slowToString(); | 203 String memberName = element.name.slowToString(); |
| 198 name = "$className.$memberName"; | 204 name = "$className.$memberName"; |
| 199 if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | 205 if (element.isGenerativeConstructorBody()) { |
| 200 name = "$name (body)"; | 206 name = "$name (body)"; |
| 201 } | 207 } |
| 202 } else { | 208 } else { |
| 203 name = "${element.name.slowToString()}"; | 209 name = "${element.name.slowToString()}"; |
| 204 } | 210 } |
| 205 compiler.tracer.traceCompilation(name, work.compilationContext); | 211 compiler.tracer.traceCompilation(name, work.compilationContext); |
| 206 compiler.tracer.traceGraph('builder', graph); | 212 compiler.tracer.traceGraph('builder', graph); |
| 207 } | 213 } |
| 208 return graph; | 214 return graph; |
| 209 }); | 215 }); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 // TODO(floitsch): Clean up this hack. Should we create a box-object by | 287 // TODO(floitsch): Clean up this hack. Should we create a box-object by |
| 282 // just creating an empty object literal? | 288 // just creating an empty object literal? |
| 283 HInstruction box = createBox(); | 289 HInstruction box = createBox(); |
| 284 // Add the box to the known locals. | 290 // Add the box to the known locals. |
| 285 directLocals[scopeData.boxElement] = box; | 291 directLocals[scopeData.boxElement] = box; |
| 286 // Make sure that accesses to the boxed locals go into the box. We also | 292 // Make sure that accesses to the boxed locals go into the box. We also |
| 287 // need to make sure that parameters are copied into the box if necessary. | 293 // need to make sure that parameters are copied into the box if necessary. |
| 288 scopeData.capturedVariableMapping.forEach((Element from, Element to) { | 294 scopeData.capturedVariableMapping.forEach((Element from, Element to) { |
| 289 // The [from] can only be a parameter for function-scopes and not | 295 // The [from] can only be a parameter for function-scopes and not |
| 290 // loop scopes. | 296 // loop scopes. |
| 291 if (from.kind == ElementKind.PARAMETER) { | 297 if (from.isParameter()) { |
| 292 // Store the captured parameter in the box. Get the current value | 298 // Store the captured parameter in the box. Get the current value |
| 293 // before we put the redirection in place. | 299 // before we put the redirection in place. |
| 294 HInstruction instruction = readLocal(from); | 300 HInstruction instruction = readLocal(from); |
| 295 redirectElement(from, to); | 301 redirectElement(from, to); |
| 296 // Now that the redirection is set up, the update to the local will | 302 // Now that the redirection is set up, the update to the local will |
| 297 // write the parameter value into the box. | 303 // write the parameter value into the box. |
| 298 updateLocal(from, instruction); | 304 updateLocal(from, instruction); |
| 299 } else { | 305 } else { |
| 300 redirectElement(from, to); | 306 redirectElement(from, to); |
| 301 } | 307 } |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 HInstruction fieldGet = new HFieldGet(redirect, receiver); | 426 HInstruction fieldGet = new HFieldGet(redirect, receiver); |
| 421 builder.add(fieldGet); | 427 builder.add(fieldGet); |
| 422 return fieldGet; | 428 return fieldGet; |
| 423 } else if (isBoxed(element)) { | 429 } else if (isBoxed(element)) { |
| 424 Element redirect = redirectionMapping[element]; | 430 Element redirect = redirectionMapping[element]; |
| 425 // In the function that declares the captured variable the box is | 431 // In the function that declares the captured variable the box is |
| 426 // accessed as direct local. Inside the nested closure the box is | 432 // accessed as direct local. Inside the nested closure the box is |
| 427 // accessed through a closure-field. | 433 // accessed through a closure-field. |
| 428 // Calling [readLocal] makes sure we generate the correct code to get | 434 // Calling [readLocal] makes sure we generate the correct code to get |
| 429 // the box. | 435 // the box. |
| 430 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); | 436 assert(redirect.enclosingElement.isVariable()); |
| 431 HInstruction box = readLocal(redirect.enclosingElement); | 437 HInstruction box = readLocal(redirect.enclosingElement); |
| 432 HInstruction lookup = new HFieldGet(redirect, box); | 438 HInstruction lookup = new HFieldGet(redirect, box); |
| 433 builder.add(lookup); | 439 builder.add(lookup); |
| 434 return lookup; | 440 return lookup; |
| 435 } else { | 441 } else { |
| 436 assert(isUsedInTry(element)); | 442 assert(isUsedInTry(element)); |
| 437 HLocalValue local = getLocal(element); | 443 HLocalValue local = getLocal(element); |
| 438 HInstruction variable = new HLocalGet(element, local); | 444 HInstruction variable = new HLocalGet(element, local); |
| 439 builder.add(variable); | 445 builder.add(variable); |
| 440 return variable; | 446 return variable; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 void updateLocal(Element element, HInstruction value) { | 486 void updateLocal(Element element, HInstruction value) { |
| 481 assert(!isStoredInClosureField(element)); | 487 assert(!isStoredInClosureField(element)); |
| 482 if (isAccessedDirectly(element)) { | 488 if (isAccessedDirectly(element)) { |
| 483 directLocals[element] = value; | 489 directLocals[element] = value; |
| 484 } else if (isBoxed(element)) { | 490 } else if (isBoxed(element)) { |
| 485 Element redirect = redirectionMapping[element]; | 491 Element redirect = redirectionMapping[element]; |
| 486 // The box itself could be captured, or be local. A local variable that | 492 // The box itself could be captured, or be local. A local variable that |
| 487 // is captured will be boxed, but the box itself will be a local. | 493 // is captured will be boxed, but the box itself will be a local. |
| 488 // Inside the closure the box is stored in a closure-field and cannot | 494 // Inside the closure the box is stored in a closure-field and cannot |
| 489 // be accessed directly. | 495 // be accessed directly. |
| 490 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); | 496 assert(redirect.enclosingElement.isVariable()); |
| 491 HInstruction box = readLocal(redirect.enclosingElement); | 497 HInstruction box = readLocal(redirect.enclosingElement); |
| 492 builder.add(new HFieldSet(redirect, box, value)); | 498 builder.add(new HFieldSet(redirect, box, value)); |
| 493 } else { | 499 } else { |
| 494 assert(isUsedInTry(element)); | 500 assert(isUsedInTry(element)); |
| 495 HLocalValue local = getLocal(element); | 501 HLocalValue local = getLocal(element); |
| 496 builder.add(new HLocalSet(element, local, value)); | 502 builder.add(new HLocalSet(element, local, value)); |
| 497 } | 503 } |
| 498 } | 504 } |
| 499 | 505 |
| 500 /** | 506 /** |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 821 | 827 |
| 822 // The current block to add instructions to. Might be null, if we are | 828 // The current block to add instructions to. Might be null, if we are |
| 823 // visiting dead code. | 829 // visiting dead code. |
| 824 HBasicBlock current; | 830 HBasicBlock current; |
| 825 // The most recently opened block. Has the same value as [current] while | 831 // The most recently opened block. Has the same value as [current] while |
| 826 // the block is open, but unlike [current], it isn't cleared when the current | 832 // the block is open, but unlike [current], it isn't cleared when the current |
| 827 // block is closed. | 833 // block is closed. |
| 828 HBasicBlock lastOpenedBlock; | 834 HBasicBlock lastOpenedBlock; |
| 829 | 835 |
| 830 LibraryElement get currentLibrary => work.element.getLibrary(); | 836 LibraryElement get currentLibrary => work.element.getLibrary(); |
| 837 Element get currentElement => work.element; |
| 831 Compiler get compiler => builder.compiler; | 838 Compiler get compiler => builder.compiler; |
| 832 CodeEmitterTask get emitter => builder.emitter; | 839 CodeEmitterTask get emitter => builder.emitter; |
| 833 | 840 |
| 834 SsaBuilder(SsaBuilderTask builder, WorkItem work) | 841 SsaBuilder(SsaBuilderTask builder, WorkItem work) |
| 835 : this.builder = builder, | 842 : this.builder = builder, |
| 836 this.work = work, | 843 this.work = work, |
| 837 interceptors = builder.interceptors, | 844 interceptors = builder.interceptors, |
| 838 methodInterceptionEnabled = true, | 845 methodInterceptionEnabled = true, |
| 839 graph = new HGraph(), | 846 graph = new HGraph(), |
| 840 stack = new List<HInstruction>(), | 847 stack = new List<HInstruction>(), |
| (...skipping 20 matching lines...) Expand all Loading... |
| 861 methodInterceptionEnabled = true; | 868 methodInterceptionEnabled = true; |
| 862 } | 869 } |
| 863 | 870 |
| 864 HGraph buildMethod(FunctionElement functionElement) { | 871 HGraph buildMethod(FunctionElement functionElement) { |
| 865 FunctionExpression function = functionElement.parseNode(compiler); | 872 FunctionExpression function = functionElement.parseNode(compiler); |
| 866 openFunction(functionElement, function); | 873 openFunction(functionElement, function); |
| 867 function.body.accept(this); | 874 function.body.accept(this); |
| 868 return closeFunction(); | 875 return closeFunction(); |
| 869 } | 876 } |
| 870 | 877 |
| 878 HGraph buildLazyInitializer(VariableElement variable) { |
| 879 HBasicBlock block = graph.addNewBlock(); |
| 880 open(graph.entry); |
| 881 close(new HGoto()).addSuccessor(block); |
| 882 open(block); |
| 883 SendSet node = variable.parseNode(compiler); |
| 884 Link<Node> link = node.arguments; |
| 885 assert(!link.isEmpty() && link.tail.isEmpty()); |
| 886 visit(link.head); |
| 887 close(new HReturn(pop())).addSuccessor(graph.exit); |
| 888 graph.finalize(); |
| 889 return graph; |
| 890 } |
| 891 |
| 871 /** | 892 /** |
| 872 * Returns the constructor body associated with the given constructor or | 893 * Returns the constructor body associated with the given constructor or |
| 873 * creates a new constructor body, if none can be found. | 894 * creates a new constructor body, if none can be found. |
| 874 * | 895 * |
| 875 * Returns [:null:] if the constructor does not have a body. | 896 * Returns [:null:] if the constructor does not have a body. |
| 876 */ | 897 */ |
| 877 ConstructorBodyElement getConstructorBody(FunctionElement constructor) { | 898 ConstructorBodyElement getConstructorBody(FunctionElement constructor) { |
| 878 assert(constructor.kind === ElementKind.GENERATIVE_CONSTRUCTOR); | 899 assert(constructor.isGenerativeConstructor()); |
| 879 if (constructor is SynthesizedConstructorElement) return null; | 900 if (constructor is SynthesizedConstructorElement) return null; |
| 880 FunctionExpression node = constructor.parseNode(compiler); | 901 FunctionExpression node = constructor.parseNode(compiler); |
| 881 // If we know the body doesn't have any code, we don't generate | 902 // If we know the body doesn't have any code, we don't generate |
| 882 // it. | 903 // it. |
| 883 if (node.body.asBlock() !== null) { | 904 if (node.body.asBlock() !== null) { |
| 884 NodeList statements = node.body.asBlock().statements; | 905 NodeList statements = node.body.asBlock().statements; |
| 885 if (statements.isEmpty()) return null; | 906 if (statements.isEmpty()) return null; |
| 886 } | 907 } |
| 887 ClassElement classElement = constructor.getEnclosingClass(); | 908 ClassElement classElement = constructor.getEnclosingClass(); |
| 888 ConstructorBodyElement bodyElement; | 909 ConstructorBodyElement bodyElement; |
| 889 for (Link<Element> backendMembers = classElement.backendMembers; | 910 for (Link<Element> backendMembers = classElement.backendMembers; |
| 890 !backendMembers.isEmpty(); | 911 !backendMembers.isEmpty(); |
| 891 backendMembers = backendMembers.tail) { | 912 backendMembers = backendMembers.tail) { |
| 892 Element backendMember = backendMembers.head; | 913 Element backendMember = backendMembers.head; |
| 893 if (backendMember.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY) { | 914 if (backendMember.isGenerativeConstructorBody()) { |
| 894 ConstructorBodyElement body = backendMember; | 915 ConstructorBodyElement body = backendMember; |
| 895 if (body.constructor == constructor) { | 916 if (body.constructor == constructor) { |
| 896 bodyElement = backendMember; | 917 bodyElement = backendMember; |
| 897 break; | 918 break; |
| 898 } | 919 } |
| 899 } | 920 } |
| 900 } | 921 } |
| 901 if (bodyElement === null) { | 922 if (bodyElement === null) { |
| 902 bodyElement = new ConstructorBodyElement(constructor); | 923 bodyElement = new ConstructorBodyElement(constructor); |
| 903 TreeElements treeElements = | 924 TreeElements treeElements = |
| 904 compiler.resolver.resolveMethodElement(constructor); | 925 compiler.resolver.resolveMethodElement(constructor); |
| 905 compiler.enqueuer.codegen.addToWorkList(bodyElement, treeElements); | 926 compiler.enqueuer.codegen.addToWorkList(bodyElement, treeElements); |
| 906 classElement.backendMembers = | 927 classElement.backendMembers = |
| 907 classElement.backendMembers.prepend(bodyElement); | 928 classElement.backendMembers.prepend(bodyElement); |
| 908 } | 929 } |
| 909 assert(bodyElement.kind === ElementKind.GENERATIVE_CONSTRUCTOR_BODY); | 930 assert(bodyElement.isGenerativeConstructorBody()); |
| 910 return bodyElement; | 931 return bodyElement; |
| 911 } | 932 } |
| 912 | 933 |
| 913 InliningState enterInlinedMethod(PartialFunctionElement function, | 934 InliningState enterInlinedMethod(PartialFunctionElement function, |
| 914 Selector selector, | 935 Selector selector, |
| 915 Link<Node> arguments) { | 936 Link<Node> arguments) { |
| 916 // Once we start to compile the arguments we must be sure that we don't | 937 // Once we start to compile the arguments we must be sure that we don't |
| 917 // abort. | 938 // abort. |
| 918 List<HInstruction> compiledArguments = new List<HInstruction>(); | 939 List<HInstruction> compiledArguments = new List<HInstruction>(); |
| 919 bool succeeded = addStaticSendArgumentsToList(selector, | 940 bool succeeded = addStaticSendArgumentsToList(selector, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 948 stack.add(localsHandler.readLocal(returnElement)); | 969 stack.add(localsHandler.readLocal(returnElement)); |
| 949 returnElement = state.oldReturnElement; | 970 returnElement = state.oldReturnElement; |
| 950 assert(stack.length == 1); | 971 assert(stack.length == 1); |
| 951 state.oldStack.add(stack[0]); | 972 state.oldStack.add(stack[0]); |
| 952 stack = state.oldStack; | 973 stack = state.oldStack; |
| 953 } | 974 } |
| 954 | 975 |
| 955 bool tryInlineMethod(Element element, | 976 bool tryInlineMethod(Element element, |
| 956 Selector selector, | 977 Selector selector, |
| 957 Link<Node> arguments) { | 978 Link<Node> arguments) { |
| 958 if (element.kind != ElementKind.FUNCTION) return false; | 979 // TODO(floitsch): we should be able to inline inside lazy initializers. |
| 980 if (!currentElement.isFunction()) return false; |
| 981 // TODO(floitsch): we should be able to inline getters, setters and |
| 982 // constructor bodies. |
| 983 if (!element.isFunction()) return false; |
| 959 // TODO(floitsch): find a cleaner way to know if the element is a function | 984 // TODO(floitsch): find a cleaner way to know if the element is a function |
| 960 // containing nodes. | 985 // containing nodes. |
| 961 // [PartialFunctionElement]s are [FunctionElement]s that have [Node]s. | 986 // [PartialFunctionElement]s are [FunctionElement]s that have [Node]s. |
| 962 if (element is !PartialFunctionElement) return false; | 987 if (element is !PartialFunctionElement) return false; |
| 963 if (inliningStack.length > MAX_INLINING_DEPTH) return false; | 988 if (inliningStack.length > MAX_INLINING_DEPTH) return false; |
| 964 // Don't inline recursive calls. We use the same elements for the inlined | 989 // Don't inline recursive calls. We use the same elements for the inlined |
| 965 // functions and would thus clobber our local variables. | 990 // functions and would thus clobber our local variables. |
| 966 if (work.element == element) return false; | 991 if (work.element == element) return false; |
| 967 for (int i = 0; i < inliningStack.length; i++) { | 992 for (int i = 0; i < inliningStack.length; i++) { |
| 968 if (inliningStack[i].function == element) return false; | 993 if (inliningStack[i].function == element) return false; |
| (...skipping 800 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1769 // TODO(ahe): This should be registered in codegen, not here. | 1794 // TODO(ahe): This should be registered in codegen, not here. |
| 1770 compiler.enqueuer.codegen.addToWorkList(callElement, elements); | 1795 compiler.enqueuer.codegen.addToWorkList(callElement, elements); |
| 1771 // TODO(ahe): This should be registered in codegen, not here. | 1796 // TODO(ahe): This should be registered in codegen, not here. |
| 1772 compiler.enqueuer.codegen.registerInstantiatedClass(closureClassElement); | 1797 compiler.enqueuer.codegen.registerInstantiatedClass(closureClassElement); |
| 1773 assert(closureClassElement.localScope.isEmpty()); | 1798 assert(closureClassElement.localScope.isEmpty()); |
| 1774 | 1799 |
| 1775 List<HInstruction> capturedVariables = <HInstruction>[]; | 1800 List<HInstruction> capturedVariables = <HInstruction>[]; |
| 1776 for (Element member in closureClassElement.backendMembers) { | 1801 for (Element member in closureClassElement.backendMembers) { |
| 1777 // The backendMembers also contains the call method(s). We are only | 1802 // The backendMembers also contains the call method(s). We are only |
| 1778 // interested in the fields. | 1803 // interested in the fields. |
| 1779 if (member.kind == ElementKind.FIELD) { | 1804 if (member.isField()) { |
| 1780 Element capturedLocal = nestedClosureData.capturedFieldMapping[member]; | 1805 Element capturedLocal = nestedClosureData.capturedFieldMapping[member]; |
| 1781 assert(capturedLocal != null); | 1806 assert(capturedLocal != null); |
| 1782 capturedVariables.add(localsHandler.readLocal(capturedLocal)); | 1807 capturedVariables.add(localsHandler.readLocal(capturedLocal)); |
| 1783 } | 1808 } |
| 1784 } | 1809 } |
| 1785 | 1810 |
| 1786 push(new HForeignNew(closureClassElement, capturedVariables)); | 1811 push(new HForeignNew(closureClassElement, capturedVariables)); |
| 1787 } | 1812 } |
| 1788 | 1813 |
| 1789 visitFunctionDeclaration(FunctionDeclaration node) { | 1814 visitFunctionDeclaration(FunctionDeclaration node) { |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1984 add(target); | 2009 add(target); |
| 1985 List<HInstruction> inputs = <HInstruction>[target, receiver]; | 2010 List<HInstruction> inputs = <HInstruction>[target, receiver]; |
| 1986 push(new HInvokeInterceptor(selector, inputs)); | 2011 push(new HInvokeInterceptor(selector, inputs)); |
| 1987 } else { | 2012 } else { |
| 1988 push(new HInvokeDynamicGetter(selector, null, receiver)); | 2013 push(new HInvokeDynamicGetter(selector, null, receiver)); |
| 1989 } | 2014 } |
| 1990 } | 2015 } |
| 1991 | 2016 |
| 1992 void generateGetter(Send send, Element element) { | 2017 void generateGetter(Send send, Element element) { |
| 1993 if (Elements.isStaticOrTopLevelField(element)) { | 2018 if (Elements.isStaticOrTopLevelField(element)) { |
| 1994 if (element.kind == ElementKind.FIELD && !element.isAssignable()) { | 2019 Constant value; |
| 1995 // A static const. Get its constant value and inline it. | 2020 if (element.isField() && !element.isAssignable()) { |
| 1996 Constant value = compiler.constantHandler.compileVariable(element); | 2021 // A static final or const. Get its constant value and inline it if |
| 2022 // the value can be compiled eagerly. |
| 2023 value = compiler.compileVariable(element); |
| 2024 } |
| 2025 if (value != null) { |
| 1997 stack.add(graph.addConstant(value)); | 2026 stack.add(graph.addConstant(value)); |
| 2027 } else if (element.isField() && compiler.isLazilyInitialized(element)) { |
| 2028 push(new HLazyStatic(element)); |
| 1998 } else { | 2029 } else { |
| 1999 push(new HStatic(element)); | 2030 push(new HStatic(element)); |
| 2000 if (element.kind == ElementKind.GETTER) { | 2031 if (element.isGetter()) { |
| 2001 push(new HInvokeStatic(<HInstruction>[pop()])); | 2032 push(new HInvokeStatic(<HInstruction>[pop()])); |
| 2002 } | 2033 } |
| 2003 } | 2034 } |
| 2004 } else if (Elements.isInstanceSend(send, elements)) { | 2035 } else if (Elements.isInstanceSend(send, elements)) { |
| 2005 HInstruction receiver = generateInstanceSendReceiver(send); | 2036 HInstruction receiver = generateInstanceSendReceiver(send); |
| 2006 generateInstanceGetterWithCompiledReceiver(send, receiver); | 2037 generateInstanceGetterWithCompiledReceiver(send, receiver); |
| 2007 } else if (Elements.isStaticOrTopLevelFunction(element)) { | 2038 } else if (Elements.isStaticOrTopLevelFunction(element)) { |
| 2008 push(new HStatic(element)); | 2039 push(new HStatic(element)); |
| 2009 // TODO(ahe): This should be registered in codegen. | 2040 // TODO(ahe): This should be registered in codegen. |
| 2010 compiler.enqueuer.codegen.registerGetOfStaticFunction(element); | 2041 compiler.enqueuer.codegen.registerGetOfStaticFunction(element); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 2030 List<HInstruction> inputs = <HInstruction>[target, receiver, value]; | 2061 List<HInstruction> inputs = <HInstruction>[target, receiver, value]; |
| 2031 add(new HInvokeInterceptor(selector, inputs)); | 2062 add(new HInvokeInterceptor(selector, inputs)); |
| 2032 } else { | 2063 } else { |
| 2033 add(new HInvokeDynamicSetter(selector, null, receiver, value)); | 2064 add(new HInvokeDynamicSetter(selector, null, receiver, value)); |
| 2034 } | 2065 } |
| 2035 stack.add(value); | 2066 stack.add(value); |
| 2036 } | 2067 } |
| 2037 | 2068 |
| 2038 void generateSetter(SendSet send, Element element, HInstruction value) { | 2069 void generateSetter(SendSet send, Element element, HInstruction value) { |
| 2039 if (Elements.isStaticOrTopLevelField(element)) { | 2070 if (Elements.isStaticOrTopLevelField(element)) { |
| 2040 if (element.kind == ElementKind.SETTER) { | 2071 if (element.isSetter()) { |
| 2041 HStatic target = new HStatic(element); | 2072 HStatic target = new HStatic(element); |
| 2042 add(target); | 2073 add(target); |
| 2043 add(new HInvokeStatic(<HInstruction>[target, value])); | 2074 add(new HInvokeStatic(<HInstruction>[target, value])); |
| 2044 } else { | 2075 } else { |
| 2045 add(new HStaticStore(element, value)); | 2076 add(new HStaticStore(element, value)); |
| 2046 } | 2077 } |
| 2047 stack.add(value); | 2078 stack.add(value); |
| 2048 } else if (element === null || Elements.isInstanceField(element)) { | 2079 } else if (element === null || Elements.isInstanceField(element)) { |
| 2049 HInstruction receiver = generateInstanceSendReceiver(send); | 2080 HInstruction receiver = generateInstanceSendReceiver(send); |
| 2050 generateInstanceSetterWithCompiledReceiver(send, receiver, value); | 2081 generateInstanceSetterWithCompiledReceiver(send, receiver, value); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2131 typeAnnotation = argument.asSend().receiver; | 2162 typeAnnotation = argument.asSend().receiver; |
| 2132 isNot = true; | 2163 isNot = true; |
| 2133 } | 2164 } |
| 2134 | 2165 |
| 2135 DartType type = elements.getType(typeAnnotation); | 2166 DartType type = elements.getType(typeAnnotation); |
| 2136 HInstruction typeInfo = null; | 2167 HInstruction typeInfo = null; |
| 2137 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { | 2168 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { |
| 2138 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); | 2169 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); |
| 2139 typeInfo = pop(); | 2170 typeInfo = pop(); |
| 2140 } | 2171 } |
| 2141 if (type.element.kind === ElementKind.TYPE_VARIABLE) { | 2172 if (type.element.isTypeVariable()) { |
| 2142 // TODO(karlklose): We emulate the behavior of the old frog | 2173 // TODO(karlklose): We emulate the behavior of the old frog |
| 2143 // compiler and answer true to any is check involving a type variable | 2174 // compiler and answer true to any is check involving a type variable |
| 2144 // -- both is T and is !T -- until we have a proper implementation of | 2175 // -- both is T and is !T -- until we have a proper implementation of |
| 2145 // reified generics. | 2176 // reified generics. |
| 2146 stack.add(graph.addConstantBool(true)); | 2177 stack.add(graph.addConstantBool(true)); |
| 2147 } else { | 2178 } else { |
| 2148 HInstruction instruction; | 2179 HInstruction instruction; |
| 2149 if (typeInfo !== null) { | 2180 if (typeInfo !== null) { |
| 2150 instruction = new HIs.withTypeInfoCall(type, expression, typeInfo); | 2181 instruction = new HIs.withTypeInfoCall(type, expression, typeInfo); |
| 2151 } else { | 2182 } else { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2222 return pop(); | 2253 return pop(); |
| 2223 } | 2254 } |
| 2224 | 2255 |
| 2225 HInstruction compileConstant(Element parameter) { | 2256 HInstruction compileConstant(Element parameter) { |
| 2226 Constant constant; | 2257 Constant constant; |
| 2227 TreeElements calleeElements = | 2258 TreeElements calleeElements = |
| 2228 compiler.enqueuer.resolution.getCachedElements(element); | 2259 compiler.enqueuer.resolution.getCachedElements(element); |
| 2229 if (calleeElements.isParameterChecked(parameter)) { | 2260 if (calleeElements.isParameterChecked(parameter)) { |
| 2230 constant = SentinelConstant.SENTINEL; | 2261 constant = SentinelConstant.SENTINEL; |
| 2231 } else { | 2262 } else { |
| 2232 constant = compiler.compileVariable(parameter); | 2263 constant = compiler.compileConstant(parameter); |
| 2233 } | 2264 } |
| 2234 return graph.addConstant(constant); | 2265 return graph.addConstant(constant); |
| 2235 } | 2266 } |
| 2236 | 2267 |
| 2237 return selector.addArgumentsToList(arguments, | 2268 return selector.addArgumentsToList(arguments, |
| 2238 list, | 2269 list, |
| 2239 element, | 2270 element, |
| 2240 compileArgument, | 2271 compileArgument, |
| 2241 compileConstant, | 2272 compileConstant, |
| 2242 compiler); | 2273 compiler); |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2498 visitSuperSend(Send node) { | 2529 visitSuperSend(Send node) { |
| 2499 Selector selector = elements.getSelector(node); | 2530 Selector selector = elements.getSelector(node); |
| 2500 Element element = elements[node]; | 2531 Element element = elements[node]; |
| 2501 if (element === null) return generateSuperNoSuchMethodSend(node); | 2532 if (element === null) return generateSuperNoSuchMethodSend(node); |
| 2502 HInstruction target = new HStatic(element); | 2533 HInstruction target = new HStatic(element); |
| 2503 HInstruction context = localsHandler.readThis(); | 2534 HInstruction context = localsHandler.readThis(); |
| 2504 add(target); | 2535 add(target); |
| 2505 var inputs = <HInstruction>[target, context]; | 2536 var inputs = <HInstruction>[target, context]; |
| 2506 if (node.isPropertyAccess) { | 2537 if (node.isPropertyAccess) { |
| 2507 push(new HInvokeSuper(inputs)); | 2538 push(new HInvokeSuper(inputs)); |
| 2508 } else if (element.kind == ElementKind.FUNCTION || | 2539 } else if (element.isFunction() || element.isGenerativeConstructor()) { |
| 2509 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | |
| 2510 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 2540 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2511 element, inputs); | 2541 element, inputs); |
| 2512 if (!succeeded) { | 2542 if (!succeeded) { |
| 2513 // TODO(ngeoffray): Match the VM behavior and throw an | 2543 // TODO(ngeoffray): Match the VM behavior and throw an |
| 2514 // exception at runtime. | 2544 // exception at runtime. |
| 2515 compiler.cancel('Unimplemented non-matching static call', node); | 2545 compiler.cancel('Unimplemented non-matching static call', node); |
| 2516 } | 2546 } |
| 2517 push(new HInvokeSuper(inputs)); | 2547 push(new HInvokeSuper(inputs)); |
| 2518 } else { | 2548 } else { |
| 2519 target = new HInvokeSuper(inputs); | 2549 target = new HInvokeSuper(inputs); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2605 pushWithPosition(newInstance, node); | 2635 pushWithPosition(newInstance, node); |
| 2606 } | 2636 } |
| 2607 | 2637 |
| 2608 visitStaticSend(Send node) { | 2638 visitStaticSend(Send node) { |
| 2609 Selector selector = elements.getSelector(node); | 2639 Selector selector = elements.getSelector(node); |
| 2610 Element element = elements[node]; | 2640 Element element = elements[node]; |
| 2611 if (element === compiler.assertMethod && !compiler.enableUserAssertions) { | 2641 if (element === compiler.assertMethod && !compiler.enableUserAssertions) { |
| 2612 stack.add(graph.addConstantNull()); | 2642 stack.add(graph.addConstantNull()); |
| 2613 return; | 2643 return; |
| 2614 } | 2644 } |
| 2615 compiler.ensure(element.kind !== ElementKind.GENERATIVE_CONSTRUCTOR); | 2645 compiler.ensure(!element.isGenerativeConstructor()); |
| 2646 if (element.isFunction()) { |
| 2647 if (tryInlineMethod(element, selector, node.arguments)) return; |
| 2616 | 2648 |
| 2617 if (tryInlineMethod(element, selector, node.arguments)) return; | 2649 HInstruction target = new HStatic(element); |
| 2618 | 2650 add(target); |
| 2619 HInstruction target = new HStatic(element); | 2651 var inputs = <HInstruction>[target]; |
| 2620 add(target); | |
| 2621 var inputs = <HInstruction>[]; | |
| 2622 inputs.add(target); | |
| 2623 if (element.kind == ElementKind.FUNCTION) { | |
| 2624 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 2652 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2625 element, inputs); | 2653 element, inputs); |
| 2626 if (!succeeded) { | 2654 if (!succeeded) { |
| 2627 // TODO(ngeoffray): Match the VM behavior and throw an | 2655 // TODO(ngeoffray): Match the VM behavior and throw an |
| 2628 // exception at runtime. | 2656 // exception at runtime. |
| 2629 compiler.cancel('Unimplemented non-matching static call', node: node); | 2657 compiler.cancel('Unimplemented non-matching static call', node: node); |
| 2630 } | 2658 } |
| 2631 HInvokeStatic instruction = new HInvokeStatic(inputs); | 2659 HInvokeStatic instruction = new HInvokeStatic(inputs); |
| 2632 // TODO(ngeoffray): Only do this if knowing the return type is | 2660 // TODO(ngeoffray): Only do this if knowing the return type is |
| 2633 // useful. | 2661 // useful. |
| 2634 HType returnType = | 2662 HType returnType = |
| 2635 builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange( | 2663 builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange( |
| 2636 work.element, element); | 2664 work.element, element); |
| 2637 if (returnType != null) instruction.guaranteedType = returnType; | 2665 if (returnType != null) instruction.guaranteedType = returnType; |
| 2638 pushWithPosition(instruction, node); | 2666 pushWithPosition(instruction, node); |
| 2639 } else { | 2667 } else { |
| 2640 if (element.kind == ElementKind.GETTER) { | 2668 generateGetter(node, element); |
| 2641 target = new HInvokeStatic(inputs); | 2669 List<HInstruction> inputs = <HInstruction>[pop()]; |
| 2642 add(target); | |
| 2643 inputs = <HInstruction>[target]; | |
| 2644 } | |
| 2645 addDynamicSendArgumentsToList(node, inputs); | 2670 addDynamicSendArgumentsToList(node, inputs); |
| 2646 pushWithPosition(new HInvokeClosure(selector, inputs), node); | 2671 pushWithPosition(new HInvokeClosure(selector, inputs), node); |
| 2647 } | 2672 } |
| 2648 } | 2673 } |
| 2649 | 2674 |
| 2650 visitGetterSend(Send node) { | 2675 visitGetterSend(Send node) { |
| 2651 generateGetter(node, elements[node]); | 2676 generateGetter(node, elements[node]); |
| 2652 } | 2677 } |
| 2653 | 2678 |
| 2654 // TODO(antonm): migrate rest of SsaBuilder to internalError. | 2679 // TODO(antonm): migrate rest of SsaBuilder to internalError. |
| (...skipping 861 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3516 else { | 3541 else { |
| 3517 VariableDefinitions declaration = catchBlock.formals.nodes.head; | 3542 VariableDefinitions declaration = catchBlock.formals.nodes.head; |
| 3518 HInstruction condition = null; | 3543 HInstruction condition = null; |
| 3519 if (declaration.type == null) { | 3544 if (declaration.type == null) { |
| 3520 condition = graph.addConstantBool(true); | 3545 condition = graph.addConstantBool(true); |
| 3521 stack.add(condition); | 3546 stack.add(condition); |
| 3522 } else { | 3547 } else { |
| 3523 // TODO(aprelev@gmail.com): Once old catch syntax is removed | 3548 // TODO(aprelev@gmail.com): Once old catch syntax is removed |
| 3524 // "if" condition above and this "else" branch should be deleted as | 3549 // "if" condition above and this "else" branch should be deleted as |
| 3525 // type of declared variable won't matter for the catch | 3550 // type of declared variable won't matter for the catch |
| 3526 // condition | 3551 // condition. |
| 3527 DartType type = elements.getType(declaration.type); | 3552 DartType type = elements.getType(declaration.type); |
| 3528 if (type == null) { | 3553 if (type == null) { |
| 3529 compiler.cancel('Catch with unresolved type', node: catchBlock); | 3554 compiler.cancel('Catch with unresolved type', node: catchBlock); |
| 3530 } | 3555 } |
| 3531 condition = new HIs(type, unwrappedException, nullOk: true); | 3556 condition = new HIs(type, unwrappedException, nullOk: true); |
| 3532 push(condition); | 3557 push(condition); |
| 3533 } | 3558 } |
| 3534 } | 3559 } |
| 3535 } | 3560 } |
| 3536 | 3561 |
| (...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4001 new HSubGraphBlockInformation(elseBranch.graph)); | 4026 new HSubGraphBlockInformation(elseBranch.graph)); |
| 4002 | 4027 |
| 4003 HBasicBlock conditionStartBlock = conditionBranch.block; | 4028 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 4004 conditionStartBlock.setBlockFlow(info, joinBlock); | 4029 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 4005 SubGraph conditionGraph = conditionBranch.graph; | 4030 SubGraph conditionGraph = conditionBranch.graph; |
| 4006 HIf branch = conditionGraph.end.last; | 4031 HIf branch = conditionGraph.end.last; |
| 4007 assert(branch is HIf); | 4032 assert(branch is HIf); |
| 4008 branch.blockInformation = conditionStartBlock.blockFlow; | 4033 branch.blockInformation = conditionStartBlock.blockFlow; |
| 4009 } | 4034 } |
| 4010 } | 4035 } |
| OLD | NEW |