Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(240)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart

Issue 923013002: dart2dart: Implementation of simple try/catch. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fixed break/continue, incorporated comments. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 // where (C', x) = Build(e, C) 444 // where (C', x) = Build(e, C)
445 // 445 //
446 // Return without a subexpression is translated as if it were return null. 446 // Return without a subexpression is translated as if it were return null.
447 ir.Primitive visitReturn(ast.Return node) { 447 ir.Primitive visitReturn(ast.Return node) {
448 assert(irBuilder.isOpen); 448 assert(irBuilder.isOpen);
449 assert(invariant(node, node.beginToken.value != 'native')); 449 assert(invariant(node, node.beginToken.value != 'native'));
450 irBuilder.buildReturn(build(node.expression)); 450 irBuilder.buildReturn(build(node.expression));
451 return null; 451 return null;
452 } 452 }
453 453
454 ir.Primitive visitTryStatement(ast.TryStatement node) {
455 assert(this.irBuilder.isOpen);
456 // Try/catch is not yet implemented in the JS backend.
457 if (this.irBuilder.tryStatements == null) {
458 return giveup(node, 'try/catch in the JS backend');
459 }
460 // Multiple catch blocks are not yet implemented.
461 if (node.catchBlocks.isEmpty ||
462 node.catchBlocks.nodes.tail == null) {
463 return giveup(node, 'not exactly one catch block');
464 }
465 // 'on T' catch blocks are not yet implemented.
466 if ((node.catchBlocks.nodes.head as ast.CatchBlock).onKeyword != null) {
467 return giveup(node, '"on T" catch block');
468 }
469 // Finally blocks are not yet implemented.
470 if (node.finallyBlock != null) {
471 return giveup(node, 'try/finally');
472 }
473
474 // Catch handlers are in scope for their body. The CPS translation of
475 // [[try tryBlock catch (e) catchBlock; successor]] is:
476 //
477 // let cont join(v0, v1, ...) = [[successor]] in
478 // let mutable m0 = x0 in
479 // let mutable m1 = x1 in
480 // ...
481 // let handler catch_(e) =
482 // let prim p0 = GetMutable(m0) in
483 // let prim p1 = GetMutable(m1) in
484 // ...
485 // [[catchBlock]]
486 // join(p0, p1, ...)
487 // in
488 // [[tryBlock]]
489 // let prim p0' = GetMutable(m0) in
490 // let prim p1' = GetMutable(m1) in
491 // ...
492 // join(p0', p1', ...)
493 //
494 // In other words, both the try and catch block are in the scope of the
495 // join-point continuation, and they are both in the scope of a sequence
496 // of mutable bindings for the variables assigned in the try. The join-
497 // point continuation is not in the scope of these mutable bindings.
498 // The tryBlock is in the scope of a binding for the catch handler. Each
499 // instruction (specifically, each call) in the tryBlock is in the dynamic
500 // scope of the handler. The mutable bindings are dereferenced at the end
501 // of the try block and at the beginning of the catch block, so the
502 // variables are unboxed in the catch block and at the join point.
503
504 IrBuilder tryCatchBuilder = irBuilder.makeDelimitedBuilder();
505 TryStatementInfo tryInfo = tryCatchBuilder.tryStatements[node];
506 // Variables that are boxed due to being captured in a closure are boxed
507 // for their entire lifetime, and so they do not need to be boxed on
508 // entry to any try block. We check for them here because we can not
509 // identify all of them in the same pass where we identify the variables
510 // assigned in the try (the may be captured by a closure after the try
511 // statement).
512 Iterable<LocalVariableElement> boxedOnEntry =
513 tryInfo.boxedOnEntry.where((LocalVariableElement variable) {
514 return !tryCatchBuilder.mutableCapturedVariables.contains(variable);
515 });
516 for (LocalVariableElement variable in boxedOnEntry) {
517 assert(!tryCatchBuilder.isInMutableVariable(variable));
518 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable);
519 tryCatchBuilder.makeMutableVariable(variable);
520 tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
521 }
522
523 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
524 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
525 List<ir.Parameter> joinParameters =
526 new List<ir.Parameter>.generate(irBuilder.environment.length, (i) {
527 return new ir.Parameter(irBuilder.environment.index2variable[i]);
528 });
529 ir.Continuation joinContinuation = new ir.Continuation(joinParameters);
530
531 void interceptJumps(JumpCollector collector) {
532 collector.enterTry(boxedOnEntry);
533 }
534 void restoreJumps(JumpCollector collector) {
535 collector.leaveTry();
536 }
537 tryBuilder.state.breakCollectors.forEach(interceptJumps);
538 tryBuilder.state.continueCollectors.forEach(interceptJumps);
539 withBuilder(tryBuilder, () {
540 visit(node.tryBlock);
541 });
542 tryBuilder.state.breakCollectors.forEach(restoreJumps);
543 tryBuilder.state.continueCollectors.forEach(restoreJumps);
544 if (tryBuilder.isOpen) {
545 for (LocalVariableElement variable in boxedOnEntry) {
546 assert(tryBuilder.isInMutableVariable(variable));
547 ir.Primitive value = tryBuilder.buildLocalGet(variable);
548 tryBuilder.environment.update(variable, value);
549 }
550 tryBuilder.jumpTo(joinContinuation);
551 }
552
553 for (LocalVariableElement variable in boxedOnEntry) {
554 assert(catchBuilder.isInMutableVariable(variable));
555 ir.Primitive value = catchBuilder.buildLocalGet(variable);
556 // Note that we remove the variable from the set of mutable variables
557 // here (and not above for the try body). This is because the set of
558 // mutable variables is global for the whole function and not local to
559 // a delimited builder.
560 catchBuilder.removeMutableVariable(variable);
561 catchBuilder.environment.update(variable, value);
562 }
563 ast.CatchBlock catchClause = node.catchBlocks.nodes.head;
564 assert(catchClause.exception != null);
565 LocalVariableElement exceptionElement = elements[catchClause.exception];
566 ir.Parameter exceptionParameter = new ir.Parameter(exceptionElement);
567 catchBuilder.environment.extend(exceptionElement, exceptionParameter);
568 ir.Parameter traceParameter;
569 if (catchClause.trace != null) {
570 LocalVariableElement traceElement = elements[catchClause.trace];
571 traceParameter = new ir.Parameter(traceElement);
572 catchBuilder.environment.extend(traceElement, traceParameter);
573 } else {
574 // Use a dummy continuation parameter for the stack trace parameter.
575 // This will ensure that all handlers have two parameters and so they
576 // can be treated uniformly.
577 traceParameter = new ir.Parameter(null);
578 }
579 withBuilder(catchBuilder, () {
580 visit(catchClause.block);
581 });
582 if (catchBuilder.isOpen) {
583 catchBuilder.jumpTo(joinContinuation);
584 }
585 List<ir.Parameter> catchParameters =
586 <ir.Parameter>[exceptionParameter, traceParameter];
587 ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
588 catchContinuation.body = catchBuilder._root;
589
590 tryCatchBuilder.add(new ir.LetHandler(catchContinuation, tryBuilder._root));
591 tryCatchBuilder._current = null;
592
593 irBuilder.add(new ir.LetCont(joinContinuation, tryCatchBuilder._root));
594 for (int i = 0; i < irBuilder.environment.length; ++i) {
595 irBuilder.environment.index2value[i] = joinParameters[i];
596 }
597 return null;
598 }
599
454 // ==== Expressions ==== 600 // ==== Expressions ====
455 ir.Primitive visitConditional(ast.Conditional node) { 601 ir.Primitive visitConditional(ast.Conditional node) {
456 return irBuilder.buildConditional( 602 return irBuilder.buildConditional(
457 build(node.condition), 603 build(node.condition),
458 subbuild(node.thenExpression), 604 subbuild(node.thenExpression),
459 subbuild(node.elseExpression)); 605 subbuild(node.elseExpression));
460 } 606 }
461 607
462 // For all simple literals: 608 // For all simple literals:
463 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] 609 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x]
(...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after
977 throw ABORT_IRNODE_BUILDER; 1123 throw ABORT_IRNODE_BUILDER;
978 } 1124 }
979 1125
980 /// Classifies local variables and local functions as captured, if they 1126 /// Classifies local variables and local functions as captured, if they
981 /// are accessed from within a nested function. 1127 /// are accessed from within a nested function.
982 /// 1128 ///
983 /// This class is specific to the [DartIrBuilder], in that it gives up if it 1129 /// This class is specific to the [DartIrBuilder], in that it gives up if it
984 /// sees a feature that is currently unsupport by that builder. In particular, 1130 /// sees a feature that is currently unsupport by that builder. In particular,
985 /// loop variables captured in a for-loop initializer, condition, or update 1131 /// loop variables captured in a for-loop initializer, condition, or update
986 /// expression are unsupported. 1132 /// expression are unsupported.
987 class DartCapturedVariables extends ast.Visitor 1133 class DartCapturedVariables extends ast.Visitor {
988 implements DartCapturedVariableInfo {
989 final TreeElements elements; 1134 final TreeElements elements;
990 DartCapturedVariables(this.elements); 1135 DartCapturedVariables(this.elements);
991 1136
992 FunctionElement currentFunction; 1137 FunctionElement currentFunction;
993 bool insideInitializer = false; 1138 bool insideInitializer = false;
994 Set<Local> capturedVariables = new Set<Local>(); 1139 Set<Local> capturedVariables = new Set<Local>();
995 1140
1141 Map<ast.TryStatement, TryStatementInfo> tryStatements =
1142 <ast.TryStatement, TryStatementInfo>{};
1143
1144 List<TryStatementInfo> tryNestingStack = <TryStatementInfo>[];
1145 bool get inTryStatement => tryNestingStack.isNotEmpty;
1146
996 void markAsCaptured(Local local) { 1147 void markAsCaptured(Local local) {
997 capturedVariables.add(local); 1148 capturedVariables.add(local);
998 } 1149 }
999 1150
1000 visit(ast.Node node) => node.accept(this); 1151 visit(ast.Node node) => node.accept(this);
1001 1152
1002 visitNode(ast.Node node) { 1153 visitNode(ast.Node node) {
1003 node.visitChildren(this); 1154 node.visitChildren(this);
1004 } 1155 }
1005 1156
(...skipping 27 matching lines...) Expand all
1033 } 1184 }
1034 1185
1035 visitSend(ast.Send node) { 1186 visitSend(ast.Send node) {
1036 handleSend(node); 1187 handleSend(node);
1037 node.visitChildren(this); 1188 node.visitChildren(this);
1038 } 1189 }
1039 1190
1040 visitSendSet(ast.SendSet node) { 1191 visitSendSet(ast.SendSet node) {
1041 handleSend(node); 1192 handleSend(node);
1042 Element element = elements[node]; 1193 Element element = elements[node];
1043 // Initializers in an initializer-list can communicate via parameters. 1194 if (Elements.isLocal(element)) {
1044 // If a parameter is stored in an initializer list we box it.
1045 if (insideInitializer &&
1046 Elements.isLocal(element) &&
1047 element.isParameter) {
1048 LocalElement local = element; 1195 LocalElement local = element;
1049 // TODO(sigurdm): Fix this. 1196 if (insideInitializer) {
1050 // Though these variables do not outlive the activation of the function, 1197 assert(local.isParameter);
1051 // they still need to be boxed. As a simplification, we treat them as if 1198 // Initializers in an initializer-list can communicate via parameters.
1052 // they are captured by a closure (i.e., they do outlive the activation of 1199 // If a parameter is stored in an initializer list we box it.
1053 // the function). 1200 // TODO(sigurdm): Fix this.
1054 markAsCaptured(local); 1201 // Though these variables do not outlive the activation of the
1202 // function, they still need to be boxed. As a simplification, we
1203 // treat them as if they are captured by a closure (i.e., they do
1204 // outlive the activation of the function).
1205 markAsCaptured(local);
1206 } else if (inTryStatement) {
1207 assert(local.isParameter || local.isVariable);
1208 // Search for the position of the try block containing the variable
1209 // declaration, or -1 if it is declared outside the outermost try.
1210 int i = tryNestingStack.length - 1;
1211 while (i >= 0 && !tryNestingStack[i].declared.contains(local)) {
1212 --i;
1213 }
1214 // If there is a next inner try, then the variable should be boxed on
1215 // entry to it.
1216 if (i + 1 < tryNestingStack.length) {
1217 tryNestingStack[i + 1].boxedOnEntry.add(local);
1218 }
1219 }
1055 } 1220 }
1056 node.visitChildren(this); 1221 node.visitChildren(this);
1057 } 1222 }
1058 1223
1059 visitFunctionExpression(ast.FunctionExpression node) { 1224 visitFunctionExpression(ast.FunctionExpression node) {
1060 FunctionElement oldFunction = currentFunction; 1225 FunctionElement oldFunction = currentFunction;
1061 currentFunction = elements[node]; 1226 currentFunction = elements[node];
1062 if (currentFunction.asyncMarker != AsyncMarker.SYNC) { 1227 if (currentFunction.asyncMarker != AsyncMarker.SYNC) {
1063 giveup(node, "cannot handle async/sync*/async* functions"); 1228 giveup(node, "cannot handle async/sync*/async* functions");
1064 } 1229 }
1065 if (node.initializers != null) { 1230 if (node.initializers != null) {
1066 insideInitializer = true; 1231 insideInitializer = true;
1067 visit(node.initializers); 1232 visit(node.initializers);
1068 insideInitializer = false; 1233 insideInitializer = false;
1069 } 1234 }
1070 visit(node.body); 1235 visit(node.body);
1071 currentFunction = oldFunction; 1236 currentFunction = oldFunction;
1072 } 1237 }
1238
1239 visitTryStatement(ast.TryStatement node) {
1240 TryStatementInfo info = new TryStatementInfo();
1241 tryStatements[node] = info;
1242 tryNestingStack.add(info);
1243 visit(node.tryBlock);
1244 assert(tryNestingStack.last == info);
1245 tryNestingStack.removeLast();
1246
1247 visit(node.catchBlocks);
1248 if (node.finallyBlock != null) visit(node.finallyBlock);
1249 }
1250
1251 visitVariableDefinitions(ast.VariableDefinitions node) {
1252 if (inTryStatement) {
1253 for (ast.Node definition in node.definitions.nodes) {
1254 LocalVariableElement local = elements[definition];
1255 assert(local != null);
1256 // In the closure conversion pass we check for isInitializingFormal,
1257 // but I'm not sure it can arise.
1258 assert(!local.isInitializingFormal);
1259 tryNestingStack.last.declared.add(local);
1260 }
1261 }
1262 node.visitChildren(this);
1263 }
1073 } 1264 }
1074 1265
1075 /// IR builder specific to the Dart backend, coupled to the [DartIrBuilder]. 1266 /// IR builder specific to the Dart backend, coupled to the [DartIrBuilder].
1076 class DartIrBuilderVisitor extends IrBuilderVisitor { 1267 class DartIrBuilderVisitor extends IrBuilderVisitor {
1077 /// Promote the type of [irBuilder] to [DartIrBuilder]. 1268 /// Promote the type of [irBuilder] to [DartIrBuilder].
1078 DartIrBuilder get irBuilder => super.irBuilder; 1269 DartIrBuilder get irBuilder => super.irBuilder;
1079 1270
1080 DartIrBuilderVisitor(TreeElements elements, 1271 DartIrBuilderVisitor(TreeElements elements,
1081 Compiler compiler, 1272 Compiler compiler,
1082 SourceFile sourceFile) 1273 SourceFile sourceFile)
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after
1707 for (String argName in selector.getOrderedNamedArguments()) { 1898 for (String argName in selector.getOrderedNamedArguments()) {
1708 int nameIndex = selector.namedArguments.indexOf(argName); 1899 int nameIndex = selector.namedArguments.indexOf(argName);
1709 int translatedIndex = selector.positionalArgumentCount + nameIndex; 1900 int translatedIndex = selector.positionalArgumentCount + nameIndex;
1710 result.add(arguments[translatedIndex]); 1901 result.add(arguments[translatedIndex]);
1711 } 1902 }
1712 return result; 1903 return result;
1713 } 1904 }
1714 1905
1715 } 1906 }
1716 1907
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698