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