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 library dart2js.ir_builder_task; | 5 library dart2js.ir_builder_task; |
6 | 6 |
7 import '../closure.dart' as closurelib; | 7 import '../closure.dart' as closurelib; |
8 import '../closure.dart' hide ClosureScope; | 8 import '../closure.dart' hide ClosureScope; |
9 import '../common.dart'; | 9 import '../common.dart'; |
10 import '../common/names.dart' show | 10 import '../common/names.dart' show |
(...skipping 2259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2270 } | 2270 } |
2271 | 2271 |
2272 dynamic giveup(ast.Node node, [String reason]) { | 2272 dynamic giveup(ast.Node node, [String reason]) { |
2273 bailoutMessage = '($node): $reason'; | 2273 bailoutMessage = '($node): $reason'; |
2274 throw ABORT_IRNODE_BUILDER; | 2274 throw ABORT_IRNODE_BUILDER; |
2275 } | 2275 } |
2276 } | 2276 } |
2277 | 2277 |
2278 final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | 2278 final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
2279 | 2279 |
2280 /// Determines which local variables should be boxed in a mutable variable | 2280 /// Classifies local variables and local functions as captured, if they |
2281 /// inside a given try block. | 2281 /// are accessed from within a nested function. |
2282 class TryBoxedVariables extends ast.Visitor { | 2282 /// |
| 2283 /// This class is specific to the [DartIrBuilder], in that it gives up if it |
| 2284 /// sees a feature that is currently unsupport by that builder. In particular, |
| 2285 /// loop variables captured in a for-loop initializer, condition, or update |
| 2286 /// expression are unsupported. |
| 2287 class DartCapturedVariables extends ast.Visitor { |
2283 final TreeElements elements; | 2288 final TreeElements elements; |
2284 TryBoxedVariables(this.elements); | 2289 DartCapturedVariables(this.elements); |
2285 | 2290 |
2286 FunctionElement currentFunction; | 2291 FunctionElement currentFunction; |
2287 bool insideInitializer = false; | 2292 bool insideInitializer = false; |
2288 Set<Local> capturedVariables = new Set<Local>(); | 2293 Set<Local> capturedVariables = new Set<Local>(); |
2289 | 2294 |
2290 /// A map containing variables boxed inside try blocks. | 2295 /// A map containing variables boxed inside try blocks. |
2291 /// | 2296 /// |
2292 /// The map is keyed by the [NodeList] of catch clauses for try/catch and | 2297 /// The map is keyed by the [NodeList] of catch clauses for try/catch and |
2293 /// by the finally block for try/finally. try/catch/finally is treated | 2298 /// by the finally block for try/finally. try/catch/finally is treated |
2294 /// as a try/catch nested in the try block of a try/finally. | 2299 /// as a try/catch nested in the try block of a try/finally. |
(...skipping 25 matching lines...) Expand all Loading... |
2320 info.boxedOnEntry.removeAll(capturedVariables); | 2325 info.boxedOnEntry.removeAll(capturedVariables); |
2321 } | 2326 } |
2322 } | 2327 } |
2323 | 2328 |
2324 visit(ast.Node node) => node.accept(this); | 2329 visit(ast.Node node) => node.accept(this); |
2325 | 2330 |
2326 visitNode(ast.Node node) { | 2331 visitNode(ast.Node node) { |
2327 node.visitChildren(this); | 2332 node.visitChildren(this); |
2328 } | 2333 } |
2329 | 2334 |
| 2335 visitFor(ast.For node) { |
| 2336 if (node.initializer != null) visit(node.initializer); |
| 2337 if (node.condition != null) visit(node.condition); |
| 2338 if (node.update != null) visit(node.update); |
| 2339 |
| 2340 // Give up if a variable was captured outside of the loop body. |
| 2341 if (node.initializer is ast.VariableDefinitions) { |
| 2342 ast.VariableDefinitions definitions = node.initializer; |
| 2343 for (ast.Node node in definitions.definitions.nodes) { |
| 2344 LocalElement loopVariable = elements[node]; |
| 2345 if (capturedVariables.contains(loopVariable)) { |
| 2346 return giveup(node, 'For-loop variable captured in loop header'); |
| 2347 } |
| 2348 } |
| 2349 } |
| 2350 |
| 2351 if (node.body != null) visit(node.body); |
| 2352 } |
| 2353 |
2330 void handleSend(ast.Send node) { | 2354 void handleSend(ast.Send node) { |
2331 Element element = elements[node]; | 2355 Element element = elements[node]; |
2332 if (Elements.isLocal(element) && | 2356 if (Elements.isLocal(element) && |
2333 !element.isConst && | 2357 !element.isConst && |
2334 element.enclosingElement != currentFunction) { | 2358 element.enclosingElement != currentFunction) { |
2335 LocalElement local = element; | 2359 LocalElement local = element; |
2336 markAsCaptured(local); | 2360 markAsCaptured(local); |
2337 } | 2361 } |
2338 } | 2362 } |
2339 | 2363 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2377 node.visitChildren(this); | 2401 node.visitChildren(this); |
2378 } | 2402 } |
2379 | 2403 |
2380 visitFunctionExpression(ast.FunctionExpression node) { | 2404 visitFunctionExpression(ast.FunctionExpression node) { |
2381 FunctionElement savedFunction = currentFunction; | 2405 FunctionElement savedFunction = currentFunction; |
2382 currentFunction = elements[node]; | 2406 currentFunction = elements[node]; |
2383 | 2407 |
2384 if (currentFunction.asyncMarker != AsyncMarker.SYNC && | 2408 if (currentFunction.asyncMarker != AsyncMarker.SYNC && |
2385 currentFunction.asyncMarker != AsyncMarker.SYNC_STAR && | 2409 currentFunction.asyncMarker != AsyncMarker.SYNC_STAR && |
2386 currentFunction.asyncMarker != AsyncMarker.ASYNC) { | 2410 currentFunction.asyncMarker != AsyncMarker.ASYNC) { |
2387 giveup(node, "cannot handle async* functions"); | 2411 giveup(node, "cannot handle sync*/async* functions"); |
2388 } | 2412 } |
2389 | 2413 |
| 2414 bool savedInsideInitializer = insideInitializer; |
2390 if (node.initializers != null) { | 2415 if (node.initializers != null) { |
| 2416 insideInitializer = true; |
2391 visit(node.initializers); | 2417 visit(node.initializers); |
2392 } | 2418 } |
| 2419 insideInitializer = false; |
2393 visit(node.body); | 2420 visit(node.body); |
2394 currentFunction = savedFunction; | 2421 currentFunction = savedFunction; |
| 2422 insideInitializer = savedInsideInitializer; |
2395 } | 2423 } |
2396 | 2424 |
2397 visitTryStatement(ast.TryStatement node) { | 2425 visitTryStatement(ast.TryStatement node) { |
2398 // Try/catch/finally is treated as two simpler constructs: try/catch and | 2426 // Try/catch/finally is treated as two simpler constructs: try/catch and |
2399 // try/finally. The encoding is: | 2427 // try/finally. The encoding is: |
2400 // | 2428 // |
2401 // try S0 catch (ex, st) S1 finally S2 | 2429 // try S0 catch (ex, st) S1 finally S2 |
2402 // ==> | 2430 // ==> |
2403 // try { try S0 catch (ex, st) S1 } finally S2 | 2431 // try { try S0 catch (ex, st) S1 } finally S2 |
2404 // | 2432 // |
(...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3092 body.functionSignature.orderedForEachParameter((ParameterElement param) { | 3120 body.functionSignature.orderedForEachParameter((ParameterElement param) { |
3093 if (scope != null && scope.capturedVariables.containsKey(param)) { | 3121 if (scope != null && scope.capturedVariables.containsKey(param)) { |
3094 // Do not pass this parameter; the box will carry its value. | 3122 // Do not pass this parameter; the box will carry its value. |
3095 } else { | 3123 } else { |
3096 parameters.add(param); | 3124 parameters.add(param); |
3097 } | 3125 } |
3098 }); | 3126 }); |
3099 return parameters; | 3127 return parameters; |
3100 } | 3128 } |
3101 | 3129 |
3102 TryBoxedVariables _analyzeTryBoxedVariables(ast.Node node) { | 3130 DartCapturedVariables _analyzeCapturedVariables(ast.Node node) { |
3103 TryBoxedVariables variables = new TryBoxedVariables(elements); | 3131 DartCapturedVariables variables = new DartCapturedVariables(elements); |
3104 try { | 3132 try { |
3105 variables.analyze(node); | 3133 variables.analyze(node); |
3106 } catch (e) { | 3134 } catch (e) { |
3107 bailoutMessage = variables.bailoutMessage; | 3135 bailoutMessage = variables.bailoutMessage; |
3108 rethrow; | 3136 rethrow; |
3109 } | 3137 } |
3110 return variables; | 3138 return variables; |
3111 } | 3139 } |
3112 | 3140 |
3113 /// Builds the IR for the body of a constructor. | 3141 /// Builds the IR for the body of a constructor. |
3114 /// | 3142 /// |
3115 /// This function is invoked from one or more "factory" constructors built by | 3143 /// This function is invoked from one or more "factory" constructors built by |
3116 /// [buildConstructor]. | 3144 /// [buildConstructor]. |
3117 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) { | 3145 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) { |
3118 ConstructorElement constructor = body.constructor; | 3146 ConstructorElement constructor = body.constructor; |
3119 ast.FunctionExpression node = constructor.node; | 3147 ast.FunctionExpression node = constructor.node; |
3120 closureClassMap = | 3148 closureClassMap = |
3121 compiler.closureToClassMapper.computeClosureToClassMapping( | 3149 compiler.closureToClassMapper.computeClosureToClassMapping( |
3122 constructor, | 3150 constructor, |
3123 node, | 3151 node, |
3124 elements); | 3152 elements); |
3125 | 3153 |
3126 // We compute variables boxed in mutable variables on entry to each try | 3154 // We compute variables boxed in mutable variables on entry to each try |
3127 // block, not including variables captured by a closure (which are boxed | 3155 // block, not including variables captured by a closure (which are boxed |
3128 // in the heap). This duplicates some of the work of closure conversion | 3156 // in the heap). This duplicates some of the work of closure conversion |
3129 // without directly using the results. This duplication is wasteful and | 3157 // without directly using the results. This duplication is wasteful and |
3130 // error-prone. | 3158 // error-prone. |
3131 // TODO(kmillikin): We should combine closure conversion and try/catch | 3159 // TODO(kmillikin): We should combine closure conversion and try/catch |
3132 // variable analysis in some way. | 3160 // variable analysis in some way. |
3133 TryBoxedVariables variables = _analyzeTryBoxedVariables(node); | 3161 DartCapturedVariables variables = _analyzeCapturedVariables(node); |
3134 tryStatements = variables.tryStatements; | 3162 tryStatements = variables.tryStatements; |
3135 IrBuilder builder = getBuilderFor(body); | 3163 IrBuilder builder = getBuilderFor(body); |
3136 | 3164 |
3137 return withBuilder(builder, () { | 3165 return withBuilder(builder, () { |
3138 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body), | 3166 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body), |
3139 getClosureScopeForNode(node)); | 3167 getClosureScopeForNode(node)); |
3140 visit(node.body); | 3168 visit(node.body); |
3141 return irBuilder.makeFunctionDefinition(); | 3169 return irBuilder.makeFunctionDefinition(); |
3142 }); | 3170 }); |
3143 } | 3171 } |
3144 | 3172 |
3145 ir.FunctionDefinition buildFunction(FunctionElement element) { | 3173 ir.FunctionDefinition buildFunction(FunctionElement element) { |
3146 assert(invariant(element, element.isImplementation)); | 3174 assert(invariant(element, element.isImplementation)); |
3147 ast.FunctionExpression node = element.node; | 3175 ast.FunctionExpression node = element.node; |
3148 | 3176 |
3149 assert(!element.isSynthesized); | 3177 assert(!element.isSynthesized); |
3150 assert(node != null); | 3178 assert(node != null); |
3151 assert(elements[node] != null); | 3179 assert(elements[node] != null); |
3152 | 3180 |
3153 closureClassMap = | 3181 closureClassMap = |
3154 compiler.closureToClassMapper.computeClosureToClassMapping( | 3182 compiler.closureToClassMapper.computeClosureToClassMapping( |
3155 element, | 3183 element, |
3156 node, | 3184 node, |
3157 elements); | 3185 elements); |
3158 TryBoxedVariables variables = _analyzeTryBoxedVariables(node); | 3186 DartCapturedVariables variables = _analyzeCapturedVariables(node); |
3159 tryStatements = variables.tryStatements; | 3187 tryStatements = variables.tryStatements; |
3160 IrBuilder builder = getBuilderFor(element); | 3188 IrBuilder builder = getBuilderFor(element); |
3161 return withBuilder(builder, () => _makeFunctionBody(element, node)); | 3189 return withBuilder(builder, () => _makeFunctionBody(element, node)); |
3162 } | 3190 } |
3163 | 3191 |
3164 /// Creates a primitive for the default value of [parameter]. | 3192 /// Creates a primitive for the default value of [parameter]. |
3165 ir.Primitive translateDefaultValue(ParameterElement parameter) { | 3193 ir.Primitive translateDefaultValue(ParameterElement parameter) { |
3166 if (parameter.initializer == null) { | 3194 if (parameter.initializer == null) { |
3167 return irBuilder.buildNullConstant(); | 3195 return irBuilder.buildNullConstant(); |
3168 } else { | 3196 } else { |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3551 if (compiler.backend.isForeign(function)) { | 3579 if (compiler.backend.isForeign(function)) { |
3552 return handleForeignCode(node, function, argumentList, callStructure); | 3580 return handleForeignCode(node, function, argumentList, callStructure); |
3553 } else { | 3581 } else { |
3554 return irBuilder.buildStaticFunctionInvocation(function, callStructure, | 3582 return irBuilder.buildStaticFunctionInvocation(function, callStructure, |
3555 translateStaticArguments(argumentList, function, callStructure), | 3583 translateStaticArguments(argumentList, function, callStructure), |
3556 sourceInformation: | 3584 sourceInformation: |
3557 sourceInformationBuilder.buildCall(node, node.selector)); | 3585 sourceInformationBuilder.buildCall(node, node.selector)); |
3558 } | 3586 } |
3559 } | 3587 } |
3560 } | 3588 } |
OLD | NEW |