| 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; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import '../constants/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_types.dart'; | 9 import '../dart_types.dart'; |
| 10 import '../dart2jslib.dart'; | 10 import '../dart2jslib.dart'; |
| 11 import '../elements/elements.dart'; | 11 import '../elements/elements.dart'; |
| 12 import '../io/source_file.dart'; | 12 import '../io/source_file.dart'; |
| 13 import '../io/source_information.dart'; | 13 import '../io/source_information.dart'; |
| 14 import '../tree/tree.dart' as ast; | 14 import '../tree/tree.dart' as ast; |
| 15 import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator; | 15 import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator; |
| 16 import '../universe/universe.dart' show SelectorKind; | 16 import '../universe/universe.dart' show SelectorKind; |
| 17 import 'cps_ir_nodes.dart' as ir; | 17 import 'cps_ir_nodes.dart' as ir; |
| 18 import '../elements/modelx.dart' show SynthesizedConstructorElementX, | 18 import '../elements/modelx.dart' show SynthesizedConstructorElementX, |
| 19 ConstructorBodyElementX, FunctionSignatureX; | 19 ConstructorBodyElementX, FunctionSignatureX; |
| 20 import '../closure.dart' hide ClosureScope; | 20 import '../closure.dart' hide ClosureScope; |
| 21 import '../closure.dart' as closurelib; | 21 import '../closure.dart' as closurelib; |
| 22 import '../js_backend/js_backend.dart' show JavaScriptBackend; | 22 import '../js_backend/js_backend.dart' show JavaScriptBackend; |
| 23 import '../util/util.dart' show Link; |
| 23 | 24 |
| 24 part 'cps_ir_builder_visitor.dart'; | 25 part 'cps_ir_builder_visitor.dart'; |
| 25 | 26 |
| 26 /// A mapping from variable elements to their compile-time values. | 27 /// A mapping from variable elements to their compile-time values. |
| 27 /// | 28 /// |
| 28 /// Map elements denoted by parameters and local variables to the | 29 /// Map elements denoted by parameters and local variables to the |
| 29 /// [ir.Primitive] that is their value. Parameters and locals are | 30 /// [ir.Primitive] that is their value. Parameters and locals are |
| 30 /// assigned indexes which can be used to refer to them. | 31 /// assigned indexes which can be used to refer to them. |
| 31 class Environment { | 32 class Environment { |
| 32 /// A map from locals to their environment index. | 33 /// A map from locals to their environment index. |
| (...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 IrBuilderDelimitedState(this.constantSystem, this.currentElement); | 234 IrBuilderDelimitedState(this.constantSystem, this.currentElement); |
| 234 } | 235 } |
| 235 | 236 |
| 236 /// A factory for building the cps IR. | 237 /// A factory for building the cps IR. |
| 237 /// | 238 /// |
| 238 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured | 239 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured |
| 239 /// variables in different ways. | 240 /// variables in different ways. |
| 240 abstract class IrBuilder { | 241 abstract class IrBuilder { |
| 241 IrBuilder _makeInstance(); | 242 IrBuilder _makeInstance(); |
| 242 | 243 |
| 244 // TODO(johnniwinther): Remove this from the [IrBuilder]. |
| 243 /// A map from TryStatements in the AST to their analysis information. | 245 /// A map from TryStatements in the AST to their analysis information. |
| 244 /// | 246 /// |
| 245 /// This includes which variables should be copied into [ir.MutableVariable]s | 247 /// This includes which variables should be copied into [ir.MutableVariable]s |
| 246 /// on entry to the try and copied out on exit. | 248 /// on entry to the try and copied out on exit. |
| 247 Map<ast.TryStatement, TryStatementInfo> get tryStatements; | 249 Map<ast.TryStatement, TryStatementInfo> get tryStatements; |
| 248 | 250 |
| 249 /// The set of local variables that will spend their lifetime as | 251 /// The set of local variables that will spend their lifetime as |
| 250 /// [ir.MutableVariable]s due to being captured by a nested function. | 252 /// [ir.MutableVariable]s due to being captured by a nested function. |
| 251 Set<Local> get mutableCapturedVariables; | 253 Set<Local> get mutableCapturedVariables; |
| 252 | 254 |
| (...skipping 1024 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1277 breakCollector.addJump(this); | 1279 breakCollector.addJump(this); |
| 1278 letJoin.continuations = | 1280 letJoin.continuations = |
| 1279 <ir.Continuation>[createJoin(environment.length, breakCollector)]; | 1281 <ir.Continuation>[createJoin(environment.length, breakCollector)]; |
| 1280 _current = letJoin; | 1282 _current = letJoin; |
| 1281 } else { | 1283 } else { |
| 1282 _current = condBuilder._current; | 1284 _current = condBuilder._current; |
| 1283 environment = condBuilder.environment; | 1285 environment = condBuilder.environment; |
| 1284 } | 1286 } |
| 1285 } | 1287 } |
| 1286 | 1288 |
| 1289 /// Creates a try-statement. |
| 1290 /// |
| 1291 /// [tryInfo] provides information on local variables declared and boxed |
| 1292 /// within this try statement. |
| 1293 /// [buildTryBlock] builds the try block. |
| 1294 /// [catchClauseInfos] provides access to the catch type, exception variable, |
| 1295 /// and stack trace variable, and a function for building the catch block. |
| 1296 void buildTry( |
| 1297 {TryStatementInfo tryStatementInfo, |
| 1298 SubbuildFunction buildTryBlock, |
| 1299 List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[]}) { |
| 1300 assert(isOpen); |
| 1301 |
| 1302 // Catch handlers are in scope for their body. The CPS translation of |
| 1303 // [[try tryBlock catch (e) catchBlock; successor]] is: |
| 1304 // |
| 1305 // let cont join(v0, v1, ...) = [[successor]] in |
| 1306 // let mutable m0 = x0 in |
| 1307 // let mutable m1 = x1 in |
| 1308 // ... |
| 1309 // let handler catch_(e) = |
| 1310 // let prim p0 = GetMutable(m0) in |
| 1311 // let prim p1 = GetMutable(m1) in |
| 1312 // ... |
| 1313 // [[catchBlock]] |
| 1314 // join(p0, p1, ...) |
| 1315 // in |
| 1316 // [[tryBlock]] |
| 1317 // let prim p0' = GetMutable(m0) in |
| 1318 // let prim p1' = GetMutable(m1) in |
| 1319 // ... |
| 1320 // join(p0', p1', ...) |
| 1321 // |
| 1322 // In other words, both the try and catch block are in the scope of the |
| 1323 // join-point continuation, and they are both in the scope of a sequence |
| 1324 // of mutable bindings for the variables assigned in the try. The join- |
| 1325 // point continuation is not in the scope of these mutable bindings. |
| 1326 // The tryBlock is in the scope of a binding for the catch handler. Each |
| 1327 // instruction (specifically, each call) in the tryBlock is in the dynamic |
| 1328 // scope of the handler. The mutable bindings are dereferenced at the end |
| 1329 // of the try block and at the beginning of the catch block, so the |
| 1330 // variables are unboxed in the catch block and at the join point. |
| 1331 |
| 1332 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); |
| 1333 // Variables that are boxed due to being captured in a closure are boxed |
| 1334 // for their entire lifetime, and so they do not need to be boxed on |
| 1335 // entry to any try block. We check for them here because we can not |
| 1336 // identify all of them in the same pass where we identify the variables |
| 1337 // assigned in the try (the may be captured by a closure after the try |
| 1338 // statement). |
| 1339 Iterable<LocalVariableElement> boxedOnEntry = |
| 1340 tryStatementInfo.boxedOnEntry.where((LocalVariableElement variable) { |
| 1341 return !tryCatchBuilder.mutableCapturedVariables.contains(variable); |
| 1342 }); |
| 1343 for (LocalVariableElement variable in boxedOnEntry) { |
| 1344 assert(!tryCatchBuilder.isInMutableVariable(variable)); |
| 1345 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable); |
| 1346 tryCatchBuilder.makeMutableVariable(variable); |
| 1347 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); |
| 1348 } |
| 1349 |
| 1350 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); |
| 1351 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); |
| 1352 List<ir.Parameter> joinParameters = |
| 1353 new List<ir.Parameter>.generate(environment.length, (i) { |
| 1354 return new ir.Parameter(environment.index2variable[i]); |
| 1355 }); |
| 1356 ir.Continuation joinContinuation = new ir.Continuation(joinParameters); |
| 1357 |
| 1358 void interceptJumps(JumpCollector collector) { |
| 1359 collector.enterTry(boxedOnEntry); |
| 1360 } |
| 1361 void restoreJumps(JumpCollector collector) { |
| 1362 collector.leaveTry(); |
| 1363 } |
| 1364 tryBuilder.state.breakCollectors.forEach(interceptJumps); |
| 1365 tryBuilder.state.continueCollectors.forEach(interceptJumps); |
| 1366 buildTryBlock(tryBuilder); |
| 1367 tryBuilder.state.breakCollectors.forEach(restoreJumps); |
| 1368 tryBuilder.state.continueCollectors.forEach(restoreJumps); |
| 1369 if (tryBuilder.isOpen) { |
| 1370 for (LocalVariableElement variable in boxedOnEntry) { |
| 1371 assert(tryBuilder.isInMutableVariable(variable)); |
| 1372 ir.Primitive value = tryBuilder.buildLocalGet(variable); |
| 1373 tryBuilder.environment.update(variable, value); |
| 1374 } |
| 1375 tryBuilder.jumpTo(joinContinuation); |
| 1376 } |
| 1377 |
| 1378 for (LocalVariableElement variable in boxedOnEntry) { |
| 1379 assert(catchBuilder.isInMutableVariable(variable)); |
| 1380 ir.Primitive value = catchBuilder.buildLocalGet(variable); |
| 1381 // Note that we remove the variable from the set of mutable variables |
| 1382 // here (and not above for the try body). This is because the set of |
| 1383 // mutable variables is global for the whole function and not local to |
| 1384 // a delimited builder. |
| 1385 catchBuilder.removeMutableVariable(variable); |
| 1386 catchBuilder.environment.update(variable, value); |
| 1387 } |
| 1388 |
| 1389 // TODO(kmillikin): Handle multiple catch clauses. |
| 1390 assert(catchClauseInfos.length == 1); |
| 1391 for (CatchClauseInfo catchClauseInfo in catchClauseInfos) { |
| 1392 LocalVariableElement exceptionVariable = |
| 1393 catchClauseInfo.exceptionVariable; |
| 1394 ir.Parameter exceptionParameter = new ir.Parameter(exceptionVariable); |
| 1395 catchBuilder.environment.extend(exceptionVariable, exceptionParameter); |
| 1396 ir.Parameter traceParameter; |
| 1397 LocalVariableElement stackTraceVariable = |
| 1398 catchClauseInfo.stackTraceVariable; |
| 1399 if (stackTraceVariable != null) { |
| 1400 traceParameter = new ir.Parameter(stackTraceVariable); |
| 1401 catchBuilder.environment.extend(stackTraceVariable, traceParameter); |
| 1402 } else { |
| 1403 // Use a dummy continuation parameter for the stack trace parameter. |
| 1404 // This will ensure that all handlers have two parameters and so they |
| 1405 // can be treated uniformly. |
| 1406 traceParameter = new ir.Parameter(null); |
| 1407 } |
| 1408 catchClauseInfo.buildCatchBlock(catchBuilder); |
| 1409 if (catchBuilder.isOpen) { |
| 1410 catchBuilder.jumpTo(joinContinuation); |
| 1411 } |
| 1412 List<ir.Parameter> catchParameters = |
| 1413 <ir.Parameter>[exceptionParameter, traceParameter]; |
| 1414 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); |
| 1415 catchContinuation.body = catchBuilder._root; |
| 1416 |
| 1417 tryCatchBuilder.add( |
| 1418 new ir.LetHandler(catchContinuation, tryBuilder._root)); |
| 1419 tryCatchBuilder._current = null; |
| 1420 } |
| 1421 |
| 1422 add(new ir.LetCont(joinContinuation, tryCatchBuilder._root)); |
| 1423 for (int i = 0; i < environment.length; ++i) { |
| 1424 environment.index2value[i] = joinParameters[i]; |
| 1425 } |
| 1426 } |
| 1427 |
| 1287 /// Create a return statement `return value;` or `return;` if [value] is | 1428 /// Create a return statement `return value;` or `return;` if [value] is |
| 1288 /// null. | 1429 /// null. |
| 1289 void buildReturn([ir.Primitive value]) { | 1430 void buildReturn([ir.Primitive value]) { |
| 1290 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 1431 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 1291 // where (C', x) = Build(e, C) | 1432 // where (C', x) = Build(e, C) |
| 1292 // | 1433 // |
| 1293 // Return without a subexpression is translated as if it were return null. | 1434 // Return without a subexpression is translated as if it were return null. |
| 1294 assert(isOpen); | 1435 assert(isOpen); |
| 1295 if (value == null) { | 1436 if (value == null) { |
| 1296 value = buildNullLiteral(); | 1437 value = buildNullLiteral(); |
| (...skipping 814 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2111 final Map<Local, ClosureLocation> freeVariables; | 2252 final Map<Local, ClosureLocation> freeVariables; |
| 2112 | 2253 |
| 2113 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables); | 2254 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables); |
| 2114 } | 2255 } |
| 2115 | 2256 |
| 2116 class TryStatementInfo { | 2257 class TryStatementInfo { |
| 2117 final Set<LocalVariableElement> declared = new Set<LocalVariableElement>(); | 2258 final Set<LocalVariableElement> declared = new Set<LocalVariableElement>(); |
| 2118 final Set<LocalVariableElement> boxedOnEntry = | 2259 final Set<LocalVariableElement> boxedOnEntry = |
| 2119 new Set<LocalVariableElement>(); | 2260 new Set<LocalVariableElement>(); |
| 2120 } | 2261 } |
| 2262 |
| 2263 // TODO(johnniwinther): Support passing of [DartType] for the exception. |
| 2264 class CatchClauseInfo { |
| 2265 final LocalVariableElement exceptionVariable; |
| 2266 final LocalVariableElement stackTraceVariable; |
| 2267 final SubbuildFunction buildCatchBlock; |
| 2268 |
| 2269 CatchClauseInfo({this.exceptionVariable, |
| 2270 this.stackTraceVariable, |
| 2271 this.buildCatchBlock}); |
| 2272 } |
| OLD | NEW |