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 '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 final TreeElements elements; | 104 final TreeElements elements; |
105 final Compiler compiler; | 105 final Compiler compiler; |
106 final SourceInformationBuilder sourceInformationBuilder; | 106 final SourceInformationBuilder sourceInformationBuilder; |
107 | 107 |
108 /// A map from try statements in the source to analysis information about | 108 /// A map from try statements in the source to analysis information about |
109 /// them. | 109 /// them. |
110 /// | 110 /// |
111 /// The analysis information includes the set of variables that must be | 111 /// The analysis information includes the set of variables that must be |
112 /// copied into [ir.MutableVariable]s on entry to the try and copied out on | 112 /// copied into [ir.MutableVariable]s on entry to the try and copied out on |
113 /// exit. | 113 /// exit. |
114 Map<ast.TryStatement, TryStatementInfo> tryStatements = null; | 114 Map<ast.Node, TryStatementInfo> tryStatements = null; |
115 | 115 |
116 // In SSA terms, join-point continuation parameters are the phis and the | 116 // In SSA terms, join-point continuation parameters are the phis and the |
117 // continuation invocation arguments are the corresponding phi inputs. To | 117 // continuation invocation arguments are the corresponding phi inputs. To |
118 // support name introduction and renaming for source level variables, we use | 118 // support name introduction and renaming for source level variables, we use |
119 // nested (delimited) visitors for constructing subparts of the IR that will | 119 // nested (delimited) visitors for constructing subparts of the IR that will |
120 // need renaming. Each source variable is assigned an index. | 120 // need renaming. Each source variable is assigned an index. |
121 // | 121 // |
122 // Each nested visitor maintains a list of free variable uses in the body. | 122 // Each nested visitor maintains a list of free variable uses in the body. |
123 // These are implemented as a list of parameters, each with their own use | 123 // These are implemented as a list of parameters, each with their own use |
124 // list of references. When the delimited subexpression is plugged into the | 124 // list of references. When the delimited subexpression is plugged into the |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
424 } | 424 } |
425 ir.Primitive value = visit(node.expression); | 425 ir.Primitive value = visit(node.expression); |
426 JumpTarget target = elements.getTargetDefinition(node); | 426 JumpTarget target = elements.getTargetDefinition(node); |
427 Element error = | 427 Element error = |
428 (compiler.backend as JavaScriptBackend).getFallThroughError(); | 428 (compiler.backend as JavaScriptBackend).getFallThroughError(); |
429 irBuilder.buildSimpleSwitch(target, value, cases, defaultCase, error, | 429 irBuilder.buildSimpleSwitch(target, value, cases, defaultCase, error, |
430 sourceInformationBuilder.buildGeneric(node)); | 430 sourceInformationBuilder.buildGeneric(node)); |
431 } | 431 } |
432 | 432 |
433 visitTryStatement(ast.TryStatement node) { | 433 visitTryStatement(ast.TryStatement node) { |
434 // Try/catch/finally is not yet implemented. | |
435 if (!node.catchBlocks.isEmpty && node.finallyBlock != null) { | |
436 return giveup(node, 'try/catch/finally'); | |
437 } | |
438 | |
439 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; | 434 List<CatchClauseInfo> catchClauseInfos = <CatchClauseInfo>[]; |
440 for (ast.CatchBlock catchClause in node.catchBlocks.nodes) { | 435 for (ast.CatchBlock catchClause in node.catchBlocks.nodes) { |
441 assert(catchClause.exception != null); | 436 assert(catchClause.exception != null); |
442 LocalVariableElement exceptionVariable = elements[catchClause.exception]; | 437 LocalVariableElement exceptionVariable = elements[catchClause.exception]; |
443 LocalVariableElement stackTraceVariable; | 438 LocalVariableElement stackTraceVariable; |
444 if (catchClause.trace != null) { | 439 if (catchClause.trace != null) { |
445 stackTraceVariable = elements[catchClause.trace]; | 440 stackTraceVariable = elements[catchClause.trace]; |
446 } | 441 } |
447 DartType type; | 442 DartType type; |
448 if (catchClause.onKeyword != null) { | 443 if (catchClause.onKeyword != null) { |
449 type = elements.getType(catchClause.type); | 444 type = elements.getType(catchClause.type); |
450 } | 445 } |
451 catchClauseInfos.add(new CatchClauseInfo( | 446 catchClauseInfos.add(new CatchClauseInfo( |
452 type: type, | 447 type: type, |
453 exceptionVariable: exceptionVariable, | 448 exceptionVariable: exceptionVariable, |
454 stackTraceVariable: stackTraceVariable, | 449 stackTraceVariable: stackTraceVariable, |
455 buildCatchBlock: subbuild(catchClause.block))); | 450 buildCatchBlock: subbuild(catchClause.block))); |
456 } | 451 } |
457 | 452 |
458 SubbuildFunction buildFinallyBlock = | 453 assert(!node.catchBlocks.isEmpty || node.finallyBlock != null); |
459 node.finallyBlock == null ? null : subbuild(node.finallyBlock); | 454 if (!node.catchBlocks.isEmpty && node.finallyBlock != null) { |
460 irBuilder.buildTry( | 455 // Try/catch/finally is encoded in terms of try/catch and try/finally: |
461 tryStatementInfo: tryStatements[node], | 456 // |
462 buildTryBlock: subbuild(node.tryBlock), | 457 // try tryBlock catch (ex, st) catchBlock finally finallyBlock |
463 catchClauseInfos: catchClauseInfos, | 458 // ==> |
464 buildFinallyBlock: buildFinallyBlock, | 459 // try { try tryBlock catch (ex, st) catchBlock } finally finallyBlock |
465 closureClassMap: closureClassMap); | 460 irBuilder.buildTryFinally(tryStatements[node.finallyBlock], |
| 461 (IrBuilder inner) { |
| 462 inner.buildTryCatch(tryStatements[node.catchBlocks], |
| 463 subbuild(node.tryBlock), |
| 464 catchClauseInfos); |
| 465 }, |
| 466 subbuild(node.finallyBlock)); |
| 467 } else if (!node.catchBlocks.isEmpty) { |
| 468 irBuilder.buildTryCatch(tryStatements[node.catchBlocks], |
| 469 subbuild(node.tryBlock), |
| 470 catchClauseInfos); |
| 471 } else { |
| 472 irBuilder.buildTryFinally(tryStatements[node.finallyBlock], |
| 473 subbuild(node.tryBlock), |
| 474 subbuild(node.finallyBlock)); |
| 475 } |
466 } | 476 } |
467 | 477 |
468 // ## Expressions ## | 478 // ## Expressions ## |
469 ir.Primitive visitConditional(ast.Conditional node) { | 479 ir.Primitive visitConditional(ast.Conditional node) { |
470 return irBuilder.buildConditional( | 480 return irBuilder.buildConditional( |
471 build(node.condition), | 481 build(node.condition), |
472 subbuild(node.thenExpression), | 482 subbuild(node.thenExpression), |
473 subbuild(node.elseExpression)); | 483 subbuild(node.elseExpression)); |
474 } | 484 } |
475 | 485 |
(...skipping 1478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1954 /// loop variables captured in a for-loop initializer, condition, or update | 1964 /// loop variables captured in a for-loop initializer, condition, or update |
1955 /// expression are unsupported. | 1965 /// expression are unsupported. |
1956 class DartCapturedVariables extends ast.Visitor { | 1966 class DartCapturedVariables extends ast.Visitor { |
1957 final TreeElements elements; | 1967 final TreeElements elements; |
1958 DartCapturedVariables(this.elements); | 1968 DartCapturedVariables(this.elements); |
1959 | 1969 |
1960 FunctionElement currentFunction; | 1970 FunctionElement currentFunction; |
1961 bool insideInitializer = false; | 1971 bool insideInitializer = false; |
1962 Set<Local> capturedVariables = new Set<Local>(); | 1972 Set<Local> capturedVariables = new Set<Local>(); |
1963 | 1973 |
1964 Map<ast.TryStatement, TryStatementInfo> tryStatements = | 1974 /// A map containing variables boxed inside try blocks. |
1965 <ast.TryStatement, TryStatementInfo>{}; | 1975 /// |
| 1976 /// The map is keyed by the [NodeList] of catch clauses for try/catch and |
| 1977 /// by the finally block for try/finally. try/catch/finally is treated |
| 1978 /// as a try/catch nested in the try block of a try/finally. |
| 1979 Map<ast.Node, TryStatementInfo> tryStatements = |
| 1980 <ast.Node, TryStatementInfo>{}; |
1966 | 1981 |
1967 List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[]; | 1982 List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[]; |
1968 bool get inTryStatement => tryNestingStack.isNotEmpty; | 1983 bool get inTryStatement => tryNestingStack.isNotEmpty; |
1969 | 1984 |
1970 String bailoutMessage = null; | 1985 String bailoutMessage = null; |
1971 | 1986 |
1972 giveup(ast.Node node, [String reason]) { | 1987 giveup(ast.Node node, [String reason]) { |
1973 bailoutMessage = '($node): $reason'; | 1988 bailoutMessage = '($node): $reason'; |
1974 throw ABORT_IRNODE_BUILDER; | 1989 throw ABORT_IRNODE_BUILDER; |
1975 } | 1990 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2072 if (node.initializers != null) { | 2087 if (node.initializers != null) { |
2073 insideInitializer = true; | 2088 insideInitializer = true; |
2074 visit(node.initializers); | 2089 visit(node.initializers); |
2075 insideInitializer = false; | 2090 insideInitializer = false; |
2076 } | 2091 } |
2077 visit(node.body); | 2092 visit(node.body); |
2078 currentFunction = oldFunction; | 2093 currentFunction = oldFunction; |
2079 } | 2094 } |
2080 | 2095 |
2081 visitTryStatement(ast.TryStatement node) { | 2096 visitTryStatement(ast.TryStatement node) { |
2082 TryStatementInfo info = new TryStatementInfo(); | 2097 // Try/catch/finally is treated as two simpler constructs: try/catch and |
2083 tryStatements[node] = info; | 2098 // try/finally. The encoding is: |
2084 tryNestingStack.add(info); | 2099 // |
| 2100 // try S0 catch (ex, st) S1 finally S2 |
| 2101 // ==> |
| 2102 // try { try S0 catch (ex, st) S1 } finally S2 |
| 2103 // |
| 2104 // The analysis associates variables assigned in S0 with the catch clauses |
| 2105 // and variables assigned in S0 and S1 with the finally block. |
| 2106 TryStatementInfo enterTryFor(ast.Node node) { |
| 2107 TryStatementInfo info = new TryStatementInfo(); |
| 2108 tryStatements[node] = info; |
| 2109 tryNestingStack.add(info); |
| 2110 return info; |
| 2111 } |
| 2112 void leaveTryFor(TryStatementInfo info) { |
| 2113 assert(tryNestingStack.last == info); |
| 2114 tryNestingStack.removeLast(); |
| 2115 } |
| 2116 bool hasCatch = !node.catchBlocks.isEmpty; |
| 2117 bool hasFinally = node.finallyBlock != null; |
| 2118 TryStatementInfo catchInfo, finallyInfo; |
| 2119 // There is a nesting stack of try blocks, so the outer try/finally block |
| 2120 // is added first. |
| 2121 if (hasFinally) finallyInfo = enterTryFor(node.finallyBlock); |
| 2122 if (hasCatch) catchInfo = enterTryFor(node.catchBlocks); |
2085 visit(node.tryBlock); | 2123 visit(node.tryBlock); |
2086 assert(tryNestingStack.last == info); | |
2087 tryNestingStack.removeLast(); | |
2088 | 2124 |
2089 visit(node.catchBlocks); | 2125 if (hasCatch) { |
2090 if (node.finallyBlock != null) visit(node.finallyBlock); | 2126 leaveTryFor(catchInfo); |
| 2127 visit(node.catchBlocks); |
| 2128 } |
| 2129 if (hasFinally) { |
| 2130 leaveTryFor(finallyInfo); |
| 2131 visit(node.finallyBlock); |
| 2132 } |
2091 } | 2133 } |
2092 | 2134 |
2093 visitVariableDefinitions(ast.VariableDefinitions node) { | 2135 visitVariableDefinitions(ast.VariableDefinitions node) { |
2094 if (inTryStatement) { | 2136 if (inTryStatement) { |
2095 for (ast.Node definition in node.definitions.nodes) { | 2137 for (ast.Node definition in node.definitions.nodes) { |
2096 LocalVariableElement local = elements[definition]; | 2138 LocalVariableElement local = elements[definition]; |
2097 assert(local != null); | 2139 assert(local != null); |
2098 // In the closure conversion pass we check for isInitializingFormal, | 2140 // In the closure conversion pass we check for isInitializingFormal, |
2099 // but I'm not sure it can arise. | 2141 // but I'm not sure it can arise. |
2100 assert(!local.isInitializingFormal); | 2142 assert(!local.isInitializingFormal); |
(...skipping 1085 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3186 } | 3228 } |
3187 | 3229 |
3188 processSetStatic(ir.SetStatic node) { | 3230 processSetStatic(ir.SetStatic node) { |
3189 node.body = replacementFor(node.body); | 3231 node.body = replacementFor(node.body); |
3190 } | 3232 } |
3191 | 3233 |
3192 processContinuation(ir.Continuation node) { | 3234 processContinuation(ir.Continuation node) { |
3193 node.body = replacementFor(node.body); | 3235 node.body = replacementFor(node.body); |
3194 } | 3236 } |
3195 } | 3237 } |
OLD | NEW |