| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 dart2js.ir_builder; | 5 part of dart2js.ir_builder; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * This task iterates through all resolved elements and builds [ir.Node]s. The | 8 * This task iterates through all resolved elements and builds [ir.Node]s. The |
| 9 * nodes are stored in the [nodes] map and accessible through [hasIr] and | 9 * nodes are stored in the [nodes] map and accessible through [hasIr] and |
| 10 * [getIr]. | 10 * [getIr]. |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 }); | 59 }); |
| 60 } | 60 } |
| 61 | 61 |
| 62 bool canBuild(Element element) { | 62 bool canBuild(Element element) { |
| 63 if (element is TypedefElement) return false; | 63 if (element is TypedefElement) return false; |
| 64 if (element is FunctionElement) { | 64 if (element is FunctionElement) { |
| 65 // TODO(sigurdm): Support native functions for dart2js. | 65 // TODO(sigurdm): Support native functions for dart2js. |
| 66 assert(invariant(element, !element.isNative)); | 66 assert(invariant(element, !element.isNative)); |
| 67 | 67 |
| 68 // TODO(kmillikin,sigurdm): Support constructors. | 68 // TODO(kmillikin,sigurdm): Support constructors. |
| 69 if (element is ConstructorElement) return false; | 69 if (element is ConstructorElement && !element.isGenerativeConstructor) { |
| 70 return false; |
| 71 } |
| 70 | 72 |
| 71 } else if (element is! FieldElement) { | 73 } else if (element is! FieldElement) { |
| 72 compiler.internalError(element, "Unexpected elementtype $element"); | 74 compiler.internalError(element, "Unexpected elementtype $element"); |
| 73 } | 75 } |
| 74 return compiler.backend.shouldOutput(element); | 76 return compiler.backend.shouldOutput(element); |
| 75 } | 77 } |
| 76 | 78 |
| 77 bool get inCheckedMode { | 79 bool get inCheckedMode { |
| 78 bool result = false; | 80 bool result = false; |
| 79 assert((result = true)); | 81 assert((result = true)); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 FunctionSignature signature = element.functionSignature; | 182 FunctionSignature signature = element.functionSignature; |
| 181 signature.orderedForEachParameter((ParameterElement parameterElement) { | 183 signature.orderedForEachParameter((ParameterElement parameterElement) { |
| 182 irBuilder.createFunctionParameter(parameterElement); | 184 irBuilder.createFunctionParameter(parameterElement); |
| 183 }); | 185 }); |
| 184 | 186 |
| 185 List<ConstantExpression> defaults = new List<ConstantExpression>(); | 187 List<ConstantExpression> defaults = new List<ConstantExpression>(); |
| 186 signature.orderedOptionalParameters.forEach((ParameterElement element) { | 188 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
| 187 defaults.add(getConstantForVariable(element)); | 189 defaults.add(getConstantForVariable(element)); |
| 188 }); | 190 }); |
| 189 | 191 |
| 190 visit(node.body); | 192 List<ir.Initializer> initializers; |
| 193 if (element.isGenerativeConstructor) { |
| 194 initializers = buildConstructorInitializers(node, element); |
| 195 visit(node.body); |
| 196 return irBuilder.makeConstructorDefinition(defaults, initializers); |
| 197 } else { |
| 198 visit(node.body); |
| 199 return irBuilder.makeFunctionDefinition(defaults); |
| 200 } |
| 201 } |
| 191 | 202 |
| 192 return irBuilder.makeFunctionDefinition(defaults); | 203 List<ir.Initializer> buildConstructorInitializers( |
| 204 ast.FunctionExpression function, ConstructorElement element) { |
| 205 List<ir.Initializer> result = <ir.Initializer>[]; |
| 206 FunctionSignature signature = element.functionSignature; |
| 207 |
| 208 void tryAddInitializingFormal(ParameterElement parameterElement) { |
| 209 if (parameterElement.isInitializingFormal) { |
| 210 InitializingFormalElement initializingFormal = parameterElement; |
| 211 withBuilder(new IrBuilder.delimited(irBuilder), () { |
| 212 ir.Primitive value = irBuilder.buildLocalGet(parameterElement); |
| 213 result.add(irBuilder.makeFieldInitializer( |
| 214 initializingFormal.fieldElement, |
| 215 irBuilder.makeRunnableBody(value))); |
| 216 }); |
| 217 } |
| 218 } |
| 219 |
| 220 // TODO(sigurdm): Preserve initializing formals as initializing formals. |
| 221 signature.orderedForEachParameter(tryAddInitializingFormal); |
| 222 |
| 223 if (function.initializers == null) return result; |
| 224 bool explicitSuperInitializer = false; |
| 225 for(ast.Node initializer in function.initializers) { |
| 226 if (initializer is ast.SendSet) { |
| 227 // Field initializer. |
| 228 FieldElement field = elements[initializer]; |
| 229 withBuilder(new IrBuilder.delimited(irBuilder), () { |
| 230 ir.Primitive value = visit(initializer.arguments.head); |
| 231 ir.RunnableBody body = irBuilder.makeRunnableBody(value); |
| 232 result.add(irBuilder.makeFieldInitializer(field, body)); |
| 233 }); |
| 234 } else if (initializer is ast.Send) { |
| 235 // Super or this initializer. |
| 236 if (ast.Initializers.isConstructorRedirect(initializer)) { |
| 237 giveup(initializer, "constructor redirect (this) initializer"); |
| 238 } |
| 239 ConstructorElement constructor = elements[initializer].implementation; |
| 240 Selector selector = elements.getSelector(initializer); |
| 241 List<ir.RunnableBody> arguments = |
| 242 initializer.arguments.mapToList((ast.Node argument) { |
| 243 return withBuilder(new IrBuilder.delimited(irBuilder), () { |
| 244 ir.Primitive value = visit(argument); |
| 245 return irBuilder.makeRunnableBody(value); |
| 246 }); |
| 247 }); |
| 248 result.add(irBuilder.makeSuperInitializer(constructor, |
| 249 arguments, |
| 250 selector)); |
| 251 explicitSuperInitializer = true; |
| 252 } else { |
| 253 compiler.internalError(initializer, |
| 254 "Unexpected initializer type $initializer"); |
| 255 } |
| 256 |
| 257 } |
| 258 if (!explicitSuperInitializer) { |
| 259 // No super initializer found. Try to find the default constructor if |
| 260 // the class is not Object. |
| 261 ClassElement enclosingClass = element.enclosingClass; |
| 262 if (!enclosingClass.isObject) { |
| 263 ClassElement superClass = enclosingClass.superclass; |
| 264 Selector selector = |
| 265 new Selector.callDefaultConstructor(enclosingClass.library); |
| 266 FunctionElement target = superClass.lookupConstructor(selector); |
| 267 if (target == null) { |
| 268 compiler.internalError(superClass, |
| 269 "No default constructor available."); |
| 270 } |
| 271 result.add(irBuilder.makeSuperInitializer(target, |
| 272 <ir.RunnableBody>[], |
| 273 selector)); |
| 274 } |
| 275 } |
| 276 return result; |
| 193 } | 277 } |
| 194 | 278 |
| 195 ir.FunctionDefinition buildFunction(FunctionElement element) { | 279 ir.FunctionDefinition buildFunction(FunctionElement element) { |
| 196 assert(invariant(element, element.isImplementation)); | 280 assert(invariant(element, element.isImplementation)); |
| 197 ast.FunctionExpression node = element.node; | 281 ast.FunctionExpression node = element.node; |
| 198 assert(node != null); | 282 assert(node != null); |
| 199 assert(elements[node] != null); | 283 assert(elements[node] != null); |
| 200 | 284 |
| 201 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); | 285 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); |
| 202 closureLocals.visit(node); | 286 closureLocals.visit(node); |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 } | 974 } |
| 891 | 975 |
| 892 /// Classifies local variables and local functions as 'closure variables'. | 976 /// Classifies local variables and local functions as 'closure variables'. |
| 893 /// A closure variable is one that is accessed from an inner function nested | 977 /// A closure variable is one that is accessed from an inner function nested |
| 894 /// one or more levels inside the one that declares it. | 978 /// one or more levels inside the one that declares it. |
| 895 class DetectClosureVariables extends ast.Visitor { | 979 class DetectClosureVariables extends ast.Visitor { |
| 896 final TreeElements elements; | 980 final TreeElements elements; |
| 897 DetectClosureVariables(this.elements); | 981 DetectClosureVariables(this.elements); |
| 898 | 982 |
| 899 FunctionElement currentFunction; | 983 FunctionElement currentFunction; |
| 984 bool insideInitializer = false; |
| 900 Set<Local> usedFromClosure = new Set<Local>(); | 985 Set<Local> usedFromClosure = new Set<Local>(); |
| 901 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); | 986 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); |
| 902 | 987 |
| 903 bool isClosureVariable(Entity entity) => usedFromClosure.contains(entity); | 988 bool isClosureVariable(Entity entity) => usedFromClosure.contains(entity); |
| 904 | 989 |
| 905 void markAsClosureVariable(Local local) { | 990 void markAsClosureVariable(Local local) { |
| 906 usedFromClosure.add(local); | 991 usedFromClosure.add(local); |
| 907 } | 992 } |
| 908 | 993 |
| 909 visit(ast.Node node) => node.accept(this); | 994 visit(ast.Node node) => node.accept(this); |
| 910 | 995 |
| 911 visitNode(ast.Node node) { | 996 visitNode(ast.Node node) { |
| 912 node.visitChildren(this); | 997 node.visitChildren(this); |
| 913 } | 998 } |
| 914 | 999 |
| 915 visitSend(ast.Send node) { | 1000 void handleSend(ast.Send node) { |
| 916 Element element = elements[node]; | 1001 Element element = elements[node]; |
| 917 if (Elements.isLocal(element) && | 1002 if (Elements.isLocal(element) && |
| 918 !element.isConst && | 1003 !element.isConst && |
| 919 element.enclosingElement != currentFunction) { | 1004 element.enclosingElement != currentFunction) { |
| 920 LocalElement local = element; | 1005 LocalElement local = element; |
| 921 markAsClosureVariable(local); | 1006 markAsClosureVariable(local); |
| 922 } | 1007 } |
| 1008 } |
| 1009 |
| 1010 visitSend(ast.Send node) { |
| 1011 handleSend(node); |
| 1012 node.visitChildren(this); |
| 1013 } |
| 1014 |
| 1015 visitSendSet(ast.SendSet node) { |
| 1016 handleSend(node); |
| 1017 Element element = elements[node]; |
| 1018 // Initializers in an initializer-list can communicate via parameters. |
| 1019 // If a parameter is stored in an initializer list we box it. |
| 1020 if (insideInitializer && |
| 1021 Elements.isLocal(element) && |
| 1022 element.isParameter) { |
| 1023 LocalElement local = element; |
| 1024 // TODO(sigurdm): Fix this. |
| 1025 // Though these variables do not outlive the activation of the function, |
| 1026 // they still need to be boxed. As a simplification, we treat them as if |
| 1027 // they are captured by a closure (i.e., they do outlive the activation of |
| 1028 // the function). |
| 1029 markAsClosureVariable(local); |
| 1030 } |
| 923 node.visitChildren(this); | 1031 node.visitChildren(this); |
| 924 } | 1032 } |
| 925 | 1033 |
| 926 visitFunctionExpression(ast.FunctionExpression node) { | 1034 visitFunctionExpression(ast.FunctionExpression node) { |
| 927 FunctionElement oldFunction = currentFunction; | 1035 FunctionElement oldFunction = currentFunction; |
| 928 currentFunction = elements[node]; | 1036 currentFunction = elements[node]; |
| 1037 if (node.initializers != null) { |
| 1038 insideInitializer = true; |
| 1039 visit(node.initializers); |
| 1040 insideInitializer = false; |
| 1041 } |
| 929 visit(node.body); | 1042 visit(node.body); |
| 930 currentFunction = oldFunction; | 1043 currentFunction = oldFunction; |
| 931 } | 1044 } |
| 932 } | 1045 } |
| OLD | NEW |