| 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 748 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1717 // TODO(ahe): This should be registered in codegen, not here. | 1742 // TODO(ahe): This should be registered in codegen, not here. |
| 1718 compiler.enqueuer.codegen.addToWorkList(callElement, elements); | 1743 compiler.enqueuer.codegen.addToWorkList(callElement, elements); |
| 1719 // TODO(ahe): This should be registered in codegen, not here. | 1744 // TODO(ahe): This should be registered in codegen, not here. |
| 1720 compiler.enqueuer.codegen.registerInstantiatedClass(closureClassElement); | 1745 compiler.enqueuer.codegen.registerInstantiatedClass(closureClassElement); |
| 1721 assert(closureClassElement.localScope.isEmpty()); | 1746 assert(closureClassElement.localScope.isEmpty()); |
| 1722 | 1747 |
| 1723 List<HInstruction> capturedVariables = <HInstruction>[]; | 1748 List<HInstruction> capturedVariables = <HInstruction>[]; |
| 1724 for (Element member in closureClassElement.backendMembers) { | 1749 for (Element member in closureClassElement.backendMembers) { |
| 1725 // The backendMembers also contains the call method(s). We are only | 1750 // The backendMembers also contains the call method(s). We are only |
| 1726 // interested in the fields. | 1751 // interested in the fields. |
| 1727 if (member.kind == ElementKind.FIELD) { | 1752 if (member.isField()) { |
| 1728 Element capturedLocal = nestedClosureData.capturedFieldMapping[member]; | 1753 Element capturedLocal = nestedClosureData.capturedFieldMapping[member]; |
| 1729 assert(capturedLocal != null); | 1754 assert(capturedLocal != null); |
| 1730 capturedVariables.add(localsHandler.readLocal(capturedLocal)); | 1755 capturedVariables.add(localsHandler.readLocal(capturedLocal)); |
| 1731 } | 1756 } |
| 1732 } | 1757 } |
| 1733 | 1758 |
| 1734 push(new HForeignNew(closureClassElement, capturedVariables)); | 1759 push(new HForeignNew(closureClassElement, capturedVariables)); |
| 1735 } | 1760 } |
| 1736 | 1761 |
| 1737 visitFunctionDeclaration(FunctionDeclaration node) { | 1762 visitFunctionDeclaration(FunctionDeclaration node) { |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1927 add(target); | 1952 add(target); |
| 1928 List<HInstruction> inputs = <HInstruction>[target, receiver]; | 1953 List<HInstruction> inputs = <HInstruction>[target, receiver]; |
| 1929 push(new HInvokeInterceptor(selector, inputs)); | 1954 push(new HInvokeInterceptor(selector, inputs)); |
| 1930 } else { | 1955 } else { |
| 1931 push(new HInvokeDynamicGetter(selector, null, receiver)); | 1956 push(new HInvokeDynamicGetter(selector, null, receiver)); |
| 1932 } | 1957 } |
| 1933 } | 1958 } |
| 1934 | 1959 |
| 1935 void generateGetter(Send send, Element element) { | 1960 void generateGetter(Send send, Element element) { |
| 1936 if (Elements.isStaticOrTopLevelField(element)) { | 1961 if (Elements.isStaticOrTopLevelField(element)) { |
| 1937 if (element.kind == ElementKind.FIELD && !element.isAssignable()) { | 1962 Constant value; |
| 1938 // A static const. Get its constant value and inline it. | 1963 if (element.isField() && !element.isAssignable()) { |
| 1939 Constant value = compiler.constantHandler.compileVariable(element); | 1964 // A static final or const. Get its constant value and inline it if |
| 1965 // the value can be compiled eagerly. |
| 1966 value = compiler.compileVariable(element); |
| 1967 } |
| 1968 if (value != null) { |
| 1940 stack.add(graph.addConstant(value)); | 1969 stack.add(graph.addConstant(value)); |
| 1970 } else if (element.isField() && compiler.isLazilyInitialized(element)) { |
| 1971 push(new HLazyStatic(element)); |
| 1941 } else { | 1972 } else { |
| 1942 push(new HStatic(element)); | 1973 push(new HStatic(element)); |
| 1943 if (element.kind == ElementKind.GETTER) { | 1974 if (element.isGetter()) { |
| 1944 push(new HInvokeStatic(<HInstruction>[pop()])); | 1975 push(new HInvokeStatic(<HInstruction>[pop()])); |
| 1945 } | 1976 } |
| 1946 } | 1977 } |
| 1947 } else if (Elements.isInstanceSend(send, elements)) { | 1978 } else if (Elements.isInstanceSend(send, elements)) { |
| 1948 HInstruction receiver = generateInstanceSendReceiver(send); | 1979 HInstruction receiver = generateInstanceSendReceiver(send); |
| 1949 generateInstanceGetterWithCompiledReceiver(send, receiver); | 1980 generateInstanceGetterWithCompiledReceiver(send, receiver); |
| 1950 } else if (Elements.isStaticOrTopLevelFunction(element)) { | 1981 } else if (Elements.isStaticOrTopLevelFunction(element)) { |
| 1951 push(new HStatic(element)); | 1982 push(new HStatic(element)); |
| 1952 // TODO(ahe): This should be registered in codegen. | 1983 // TODO(ahe): This should be registered in codegen. |
| 1953 compiler.enqueuer.codegen.registerGetOfStaticFunction(element); | 1984 compiler.enqueuer.codegen.registerGetOfStaticFunction(element); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1973 List<HInstruction> inputs = <HInstruction>[target, receiver, value]; | 2004 List<HInstruction> inputs = <HInstruction>[target, receiver, value]; |
| 1974 add(new HInvokeInterceptor(selector, inputs)); | 2005 add(new HInvokeInterceptor(selector, inputs)); |
| 1975 } else { | 2006 } else { |
| 1976 add(new HInvokeDynamicSetter(selector, null, receiver, value)); | 2007 add(new HInvokeDynamicSetter(selector, null, receiver, value)); |
| 1977 } | 2008 } |
| 1978 stack.add(value); | 2009 stack.add(value); |
| 1979 } | 2010 } |
| 1980 | 2011 |
| 1981 void generateSetter(SendSet send, Element element, HInstruction value) { | 2012 void generateSetter(SendSet send, Element element, HInstruction value) { |
| 1982 if (Elements.isStaticOrTopLevelField(element)) { | 2013 if (Elements.isStaticOrTopLevelField(element)) { |
| 1983 if (element.kind == ElementKind.SETTER) { | 2014 if (element.isSetter()) { |
| 1984 HStatic target = new HStatic(element); | 2015 HStatic target = new HStatic(element); |
| 1985 add(target); | 2016 add(target); |
| 1986 add(new HInvokeStatic(<HInstruction>[target, value])); | 2017 add(new HInvokeStatic(<HInstruction>[target, value])); |
| 1987 } else { | 2018 } else { |
| 1988 add(new HStaticStore(element, value)); | 2019 add(new HStaticStore(element, value)); |
| 1989 } | 2020 } |
| 1990 stack.add(value); | 2021 stack.add(value); |
| 1991 } else if (element === null || Elements.isInstanceField(element)) { | 2022 } else if (element === null || Elements.isInstanceField(element)) { |
| 1992 HInstruction receiver = generateInstanceSendReceiver(send); | 2023 HInstruction receiver = generateInstanceSendReceiver(send); |
| 1993 generateInstanceSetterWithCompiledReceiver(send, receiver, value); | 2024 generateInstanceSetterWithCompiledReceiver(send, receiver, value); |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2074 typeAnnotation = argument.asSend().receiver; | 2105 typeAnnotation = argument.asSend().receiver; |
| 2075 isNot = true; | 2106 isNot = true; |
| 2076 } | 2107 } |
| 2077 | 2108 |
| 2078 DartType type = elements.getType(typeAnnotation); | 2109 DartType type = elements.getType(typeAnnotation); |
| 2079 HInstruction typeInfo = null; | 2110 HInstruction typeInfo = null; |
| 2080 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { | 2111 if (compiler.codegenWorld.rti.hasTypeArguments(type)) { |
| 2081 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); | 2112 pushInvokeHelper1(interceptors.getGetRuntimeTypeInfo(), expression); |
| 2082 typeInfo = pop(); | 2113 typeInfo = pop(); |
| 2083 } | 2114 } |
| 2084 if (type.element.kind === ElementKind.TYPE_VARIABLE) { | 2115 if (type.element.isTypeVariable()) { |
| 2085 // TODO(karlklose): We emulate the behavior of the old frog | 2116 // TODO(karlklose): We emulate the behavior of the old frog |
| 2086 // compiler and answer true to any is check involving a type variable | 2117 // compiler and answer true to any is check involving a type variable |
| 2087 // -- both is T and is !T -- until we have a proper implementation of | 2118 // -- both is T and is !T -- until we have a proper implementation of |
| 2088 // reified generics. | 2119 // reified generics. |
| 2089 stack.add(graph.addConstantBool(true)); | 2120 stack.add(graph.addConstantBool(true)); |
| 2090 } else { | 2121 } else { |
| 2091 HInstruction instruction; | 2122 HInstruction instruction; |
| 2092 if (typeInfo !== null) { | 2123 if (typeInfo !== null) { |
| 2093 instruction = new HIs.withTypeInfoCall(type, expression, typeInfo); | 2124 instruction = new HIs.withTypeInfoCall(type, expression, typeInfo); |
| 2094 } else { | 2125 } else { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2159 bool addStaticSendArgumentsToList(Selector selector, | 2190 bool addStaticSendArgumentsToList(Selector selector, |
| 2160 Link<Node> arguments, | 2191 Link<Node> arguments, |
| 2161 FunctionElement element, | 2192 FunctionElement element, |
| 2162 List<HInstruction> list) { | 2193 List<HInstruction> list) { |
| 2163 HInstruction compileArgument(Node argument) { | 2194 HInstruction compileArgument(Node argument) { |
| 2164 visit(argument); | 2195 visit(argument); |
| 2165 return pop(); | 2196 return pop(); |
| 2166 } | 2197 } |
| 2167 | 2198 |
| 2168 HInstruction compileConstant(Element constantElement) { | 2199 HInstruction compileConstant(Element constantElement) { |
| 2169 Constant constant = compiler.compileVariable(constantElement); | 2200 Constant constant = compiler.compileConstant(constantElement); |
| 2170 return graph.addConstant(constant); | 2201 return graph.addConstant(constant); |
| 2171 } | 2202 } |
| 2172 | 2203 |
| 2173 return selector.addArgumentsToList(arguments, | 2204 return selector.addArgumentsToList(arguments, |
| 2174 list, | 2205 list, |
| 2175 element, | 2206 element, |
| 2176 compileArgument, | 2207 compileArgument, |
| 2177 compileConstant, | 2208 compileConstant, |
| 2178 compiler); | 2209 compiler); |
| 2179 } | 2210 } |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2434 visitSuperSend(Send node) { | 2465 visitSuperSend(Send node) { |
| 2435 Selector selector = elements.getSelector(node); | 2466 Selector selector = elements.getSelector(node); |
| 2436 Element element = elements[node]; | 2467 Element element = elements[node]; |
| 2437 if (element === null) return generateSuperNoSuchMethodSend(node); | 2468 if (element === null) return generateSuperNoSuchMethodSend(node); |
| 2438 HInstruction target = new HStatic(element); | 2469 HInstruction target = new HStatic(element); |
| 2439 HInstruction context = localsHandler.readThis(); | 2470 HInstruction context = localsHandler.readThis(); |
| 2440 add(target); | 2471 add(target); |
| 2441 var inputs = <HInstruction>[target, context]; | 2472 var inputs = <HInstruction>[target, context]; |
| 2442 if (node.isPropertyAccess) { | 2473 if (node.isPropertyAccess) { |
| 2443 push(new HInvokeSuper(inputs)); | 2474 push(new HInvokeSuper(inputs)); |
| 2444 } else if (element.kind == ElementKind.FUNCTION || | 2475 } else if (element.isFunction() || element.isGenerativeConstructor()) { |
| 2445 element.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { | |
| 2446 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 2476 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2447 element, inputs); | 2477 element, inputs); |
| 2448 if (!succeeded) { | 2478 if (!succeeded) { |
| 2449 // TODO(ngeoffray): Match the VM behavior and throw an | 2479 // TODO(ngeoffray): Match the VM behavior and throw an |
| 2450 // exception at runtime. | 2480 // exception at runtime. |
| 2451 compiler.cancel('Unimplemented non-matching static call', node); | 2481 compiler.cancel('Unimplemented non-matching static call', node); |
| 2452 } | 2482 } |
| 2453 push(new HInvokeSuper(inputs)); | 2483 push(new HInvokeSuper(inputs)); |
| 2454 } else { | 2484 } else { |
| 2455 target = new HInvokeSuper(inputs); | 2485 target = new HInvokeSuper(inputs); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2541 pushWithPosition(newInstance, node); | 2571 pushWithPosition(newInstance, node); |
| 2542 } | 2572 } |
| 2543 | 2573 |
| 2544 visitStaticSend(Send node) { | 2574 visitStaticSend(Send node) { |
| 2545 Selector selector = elements.getSelector(node); | 2575 Selector selector = elements.getSelector(node); |
| 2546 Element element = elements[node]; | 2576 Element element = elements[node]; |
| 2547 if (element === compiler.assertMethod && !compiler.enableUserAssertions) { | 2577 if (element === compiler.assertMethod && !compiler.enableUserAssertions) { |
| 2548 stack.add(graph.addConstantNull()); | 2578 stack.add(graph.addConstantNull()); |
| 2549 return; | 2579 return; |
| 2550 } | 2580 } |
| 2551 compiler.ensure(element.kind !== ElementKind.GENERATIVE_CONSTRUCTOR); | 2581 compiler.ensure(!element.isGenerativeConstructor()); |
| 2582 if (element.isFunction()) { |
| 2583 if (tryInlineMethod(element, selector, node.arguments)) return; |
| 2552 | 2584 |
| 2553 if (tryInlineMethod(element, selector, node.arguments)) return; | 2585 HInstruction target = new HStatic(element); |
| 2554 | 2586 add(target); |
| 2555 HInstruction target = new HStatic(element); | 2587 var inputs = <HInstruction>[target]; |
| 2556 add(target); | |
| 2557 var inputs = <HInstruction>[]; | |
| 2558 inputs.add(target); | |
| 2559 if (element.kind == ElementKind.FUNCTION) { | |
| 2560 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, | 2588 bool succeeded = addStaticSendArgumentsToList(selector, node.arguments, |
| 2561 element, inputs); | 2589 element, inputs); |
| 2562 if (!succeeded) { | 2590 if (!succeeded) { |
| 2563 // TODO(ngeoffray): Match the VM behavior and throw an | 2591 // TODO(ngeoffray): Match the VM behavior and throw an |
| 2564 // exception at runtime. | 2592 // exception at runtime. |
| 2565 compiler.cancel('Unimplemented non-matching static call', node: node); | 2593 compiler.cancel('Unimplemented non-matching static call', node: node); |
| 2566 } | 2594 } |
| 2567 HInvokeStatic instruction = new HInvokeStatic(inputs); | 2595 HInvokeStatic instruction = new HInvokeStatic(inputs); |
| 2568 // TODO(ngeoffray): Only do this if knowing the return type is | 2596 // TODO(ngeoffray): Only do this if knowing the return type is |
| 2569 // useful. | 2597 // useful. |
| 2570 HType returnType = | 2598 HType returnType = |
| 2571 builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange( | 2599 builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange( |
| 2572 work.element, element); | 2600 work.element, element); |
| 2573 if (returnType != null) instruction.guaranteedType = returnType; | 2601 if (returnType != null) instruction.guaranteedType = returnType; |
| 2574 pushWithPosition(instruction, node); | 2602 pushWithPosition(instruction, node); |
| 2575 } else { | 2603 } else { |
| 2576 if (element.kind == ElementKind.GETTER) { | 2604 generateGetter(node, element); |
| 2577 target = new HInvokeStatic(inputs); | 2605 List<HInstruction> inputs = <HInstruction>[pop()]; |
| 2578 add(target); | |
| 2579 inputs = <HInstruction>[target]; | |
| 2580 } | |
| 2581 addDynamicSendArgumentsToList(node, inputs); | 2606 addDynamicSendArgumentsToList(node, inputs); |
| 2582 pushWithPosition(new HInvokeClosure(selector, inputs), node); | 2607 pushWithPosition(new HInvokeClosure(selector, inputs), node); |
| 2583 } | 2608 } |
| 2584 } | 2609 } |
| 2585 | 2610 |
| 2586 visitGetterSend(Send node) { | 2611 visitGetterSend(Send node) { |
| 2587 generateGetter(node, elements[node]); | 2612 generateGetter(node, elements[node]); |
| 2588 } | 2613 } |
| 2589 | 2614 |
| 2590 // TODO(antonm): migrate rest of SsaBuilder to internalError. | 2615 // TODO(antonm): migrate rest of SsaBuilder to internalError. |
| (...skipping 861 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3452 else { | 3477 else { |
| 3453 VariableDefinitions declaration = catchBlock.formals.nodes.head; | 3478 VariableDefinitions declaration = catchBlock.formals.nodes.head; |
| 3454 HInstruction condition = null; | 3479 HInstruction condition = null; |
| 3455 if (declaration.type == null) { | 3480 if (declaration.type == null) { |
| 3456 condition = graph.addConstantBool(true); | 3481 condition = graph.addConstantBool(true); |
| 3457 stack.add(condition); | 3482 stack.add(condition); |
| 3458 } else { | 3483 } else { |
| 3459 // TODO(aprelev@gmail.com): Once old catch syntax is removed | 3484 // TODO(aprelev@gmail.com): Once old catch syntax is removed |
| 3460 // "if" condition above and this "else" branch should be deleted as | 3485 // "if" condition above and this "else" branch should be deleted as |
| 3461 // type of declared variable won't matter for the catch | 3486 // type of declared variable won't matter for the catch |
| 3462 // condition | 3487 // condition. |
| 3463 DartType type = elements.getType(declaration.type); | 3488 DartType type = elements.getType(declaration.type); |
| 3464 if (type == null) { | 3489 if (type == null) { |
| 3465 compiler.cancel('Catch with unresolved type', node: catchBlock); | 3490 compiler.cancel('Catch with unresolved type', node: catchBlock); |
| 3466 } | 3491 } |
| 3467 condition = new HIs(type, unwrappedException, nullOk: true); | 3492 condition = new HIs(type, unwrappedException, nullOk: true); |
| 3468 push(condition); | 3493 push(condition); |
| 3469 } | 3494 } |
| 3470 } | 3495 } |
| 3471 } | 3496 } |
| 3472 | 3497 |
| (...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3933 new HSubGraphBlockInformation(elseBranch.graph)); | 3958 new HSubGraphBlockInformation(elseBranch.graph)); |
| 3934 | 3959 |
| 3935 HBasicBlock conditionStartBlock = conditionBranch.block; | 3960 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 3936 conditionStartBlock.setBlockFlow(info, joinBlock); | 3961 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 3937 SubGraph conditionGraph = conditionBranch.graph; | 3962 SubGraph conditionGraph = conditionBranch.graph; |
| 3938 HIf branch = conditionGraph.end.last; | 3963 HIf branch = conditionGraph.end.last; |
| 3939 assert(branch is HIf); | 3964 assert(branch is HIf); |
| 3940 branch.blockInformation = conditionStartBlock.blockFlow; | 3965 branch.blockInformation = conditionStartBlock.blockFlow; |
| 3941 } | 3966 } |
| 3942 } | 3967 } |
| OLD | NEW |