Chromium Code Reviews| 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 |
| 192 List<ir.Initializer> initializers; | |
| 193 if (element.isGenerativeConstructor) { | |
|
floitsch
2014/12/08 17:45:02
Make only one `if`
if (element.isGenerativeConstr
sigurdm
2014/12/09 09:57:10
Done.
| |
| 194 initializers = buildConstructorInitializers(node, element); | |
| 195 } | |
| 196 | |
| 190 visit(node.body); | 197 visit(node.body); |
| 198 if (element.isGenerativeConstructor) { | |
| 199 return irBuilder.makeConstructorDefinition(defaults, initializers); | |
| 200 } else { | |
| 201 return irBuilder.makeFunctionDefinition(defaults); | |
| 202 } | |
| 203 } | |
| 191 | 204 |
| 192 return irBuilder.makeFunctionDefinition(defaults); | 205 List<ir.Initializer> buildConstructorInitializers( |
| 206 ast.FunctionExpression function, ConstructorElement element) { | |
| 207 List<ir.Initializer> result = new List<ir.Initializer>(); | |
| 208 FunctionSignature signature = element.functionSignature; | |
| 209 | |
| 210 void tryAddInitializingFormal(ParameterElement parameterElement) { | |
| 211 if (parameterElement.isInitializingFormal) { | |
| 212 InitializingFormalElement initializingFormal = parameterElement; | |
| 213 withBuilder(new IrBuilder.delimited(irBuilder), () { | |
| 214 ir.Primitive value = irBuilder.buildLocalGet(parameterElement); | |
| 215 result.add(irBuilder.makeFieldInitializer( | |
| 216 initializingFormal.fieldElement, | |
| 217 irBuilder.makeRunnableBody(value))); | |
| 218 }); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 // TODO(sigurdm): Preserve initializing formals as initializing formals. | |
| 223 signature.orderedForEachParameter(tryAddInitializingFormal); | |
| 224 | |
| 225 if (function.initializers == null) return result; | |
| 226 bool explicitSuperInitializer = false; | |
| 227 for(ast.Node initializer in function.initializers) { | |
| 228 if (initializer is ast.SendSet) { | |
| 229 // Field initializer. | |
| 230 FieldElement field = elements[initializer]; | |
| 231 withBuilder(new IrBuilder.delimited(irBuilder), () { | |
| 232 ir.Primitive value = visit(initializer.arguments.head); | |
| 233 ir.RunnableBody body = irBuilder.makeRunnableBody(value); | |
| 234 result.add(irBuilder.makeFieldInitializer(field, body)); | |
| 235 }); | |
| 236 } else if (initializer is ast.Send) { | |
| 237 // Super or this initializer. | |
| 238 if (ast.Initializers.isConstructorRedirect(initializer)) { | |
| 239 giveup(initializer, "constructor redirect (this) initializer"); | |
| 240 } | |
| 241 ConstructorElement constructor = elements[initializer].implementation; | |
| 242 Selector selector = elements.getSelector(initializer); | |
| 243 List<ir.RunnableBody> arguments = | |
| 244 initializer.arguments.mapToList((ast.Node argument) { | |
| 245 return withBuilder(new IrBuilder.delimited(irBuilder), () { | |
| 246 ir.Primitive value = visit(argument); | |
| 247 return irBuilder.makeRunnableBody(value); | |
| 248 }); | |
| 249 }); | |
| 250 result.add(irBuilder.makeSuperInitializer(constructor, | |
| 251 selector, | |
| 252 arguments)); | |
| 253 explicitSuperInitializer = true; | |
| 254 } else { | |
| 255 compiler.internalError(initializer, | |
| 256 "Unexpected initializer type $initializer"); | |
| 257 } | |
| 258 | |
| 259 } | |
| 260 if (!explicitSuperInitializer) { | |
| 261 // No super initializer found. Try to find the default constructor if | |
| 262 // the class is not Object. | |
| 263 ClassElement enclosingClass = element.enclosingClass; | |
| 264 if (!enclosingClass.isObject) { | |
| 265 ClassElement superClass = enclosingClass.superclass; | |
| 266 Selector selector = | |
| 267 new Selector.callDefaultConstructor(enclosingClass.library); | |
| 268 FunctionElement target = superClass.lookupConstructor(selector); | |
| 269 if (target == null) { | |
| 270 compiler.internalError(superClass, | |
| 271 "No default constructor available."); | |
| 272 } | |
| 273 result.add(irBuilder.makeSuperInitializer(target, | |
| 274 selector, | |
| 275 <ir.RunnableBody>[])); | |
| 276 } | |
| 277 } | |
| 278 return result; | |
| 193 } | 279 } |
| 194 | 280 |
| 195 ir.FunctionDefinition buildFunction(FunctionElement element) { | 281 ir.FunctionDefinition buildFunction(FunctionElement element) { |
| 196 assert(invariant(element, element.isImplementation)); | 282 assert(invariant(element, element.isImplementation)); |
| 197 ast.FunctionExpression node = element.node; | 283 ast.FunctionExpression node = element.node; |
| 198 assert(node != null); | 284 assert(node != null); |
| 199 assert(elements[node] != null); | 285 assert(elements[node] != null); |
| 200 | 286 |
| 201 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); | 287 DetectClosureVariables closureLocals = new DetectClosureVariables(elements); |
| 202 closureLocals.visit(node); | 288 closureLocals.visit(node); |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 890 } | 976 } |
| 891 | 977 |
| 892 /// Classifies local variables and local functions as 'closure variables'. | 978 /// Classifies local variables and local functions as 'closure variables'. |
| 893 /// A closure variable is one that is accessed from an inner function nested | 979 /// A closure variable is one that is accessed from an inner function nested |
| 894 /// one or more levels inside the one that declares it. | 980 /// one or more levels inside the one that declares it. |
| 895 class DetectClosureVariables extends ast.Visitor { | 981 class DetectClosureVariables extends ast.Visitor { |
| 896 final TreeElements elements; | 982 final TreeElements elements; |
| 897 DetectClosureVariables(this.elements); | 983 DetectClosureVariables(this.elements); |
| 898 | 984 |
| 899 FunctionElement currentFunction; | 985 FunctionElement currentFunction; |
| 986 bool insideInitializer = false; | |
| 900 Set<Local> usedFromClosure = new Set<Local>(); | 987 Set<Local> usedFromClosure = new Set<Local>(); |
| 901 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); | 988 Set<FunctionElement> recursiveFunctions = new Set<FunctionElement>(); |
| 902 | 989 |
| 903 bool isClosureVariable(Entity entity) => usedFromClosure.contains(entity); | 990 bool isClosureVariable(Entity entity) => usedFromClosure.contains(entity); |
| 904 | 991 |
| 905 void markAsClosureVariable(Local local) { | 992 void markAsClosureVariable(Local local) { |
| 906 usedFromClosure.add(local); | 993 usedFromClosure.add(local); |
| 907 } | 994 } |
| 908 | 995 |
| 909 visit(ast.Node node) => node.accept(this); | 996 visit(ast.Node node) => node.accept(this); |
| 910 | 997 |
| 911 visitNode(ast.Node node) { | 998 visitNode(ast.Node node) { |
| 912 node.visitChildren(this); | 999 node.visitChildren(this); |
| 913 } | 1000 } |
| 914 | 1001 |
| 915 visitSend(ast.Send node) { | 1002 visitSend(ast.Send node) { |
| 916 Element element = elements[node]; | 1003 Element element = elements[node]; |
| 917 if (Elements.isLocal(element) && | 1004 if (Elements.isLocal(element) && |
| 918 !element.isConst && | 1005 !element.isConst && |
| 919 element.enclosingElement != currentFunction) { | 1006 element.enclosingElement != currentFunction) { |
| 920 LocalElement local = element; | 1007 LocalElement local = element; |
| 921 markAsClosureVariable(local); | 1008 markAsClosureVariable(local); |
| 922 } | 1009 } |
| 923 node.visitChildren(this); | 1010 node.visitChildren(this); |
| 924 } | 1011 } |
| 925 | 1012 |
| 1013 visitSendSet(ast.SendSet node) { | |
| 1014 visitSend(node); | |
| 1015 Element element = elements[node]; | |
| 1016 // Initializers in an initializer-list can communicate via parameters. | |
| 1017 // If a parameter is stored to in an initializer list we box it. | |
|
floitsch
2014/12/08 17:45:03
-to-
sigurdm
2014/12/09 09:57:10
Done.
| |
| 1018 if (insideInitializer && | |
| 1019 Elements.isLocal(element) && | |
| 1020 element.isParameter) { | |
| 1021 LocalElement local = element; | |
| 1022 markAsClosureVariable(local); | |
| 1023 } | |
| 1024 node.visitChildren(this); | |
| 1025 } | |
| 1026 | |
| 926 visitFunctionExpression(ast.FunctionExpression node) { | 1027 visitFunctionExpression(ast.FunctionExpression node) { |
| 927 FunctionElement oldFunction = currentFunction; | 1028 FunctionElement oldFunction = currentFunction; |
| 928 currentFunction = elements[node]; | 1029 currentFunction = elements[node]; |
| 1030 if (node.initializers != null) { | |
| 1031 insideInitializer = true; | |
| 1032 visit(node.initializers); | |
| 1033 insideInitializer = false; | |
| 1034 } | |
| 929 visit(node.body); | 1035 visit(node.body); |
| 930 currentFunction = oldFunction; | 1036 currentFunction = oldFunction; |
| 931 } | 1037 } |
| 932 } | 1038 } |
| OLD | NEW |