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

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: Created 5 years, 10 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 th
floitsch 2015/02/16 14:54:07 the
502 // variables are unboxed in the catch block and at the join point.
floitsch 2015/02/16 14:54:07 I guess they are also unboxed before calls to "con
Kevin Millikin (Google) 2015/02/24 11:59:25 It does require an update to the comment, and a fi
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 entry
508 // to any try block. They are only removed here because we cannot
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 tryInfo.boxedOnEntry.removeAll(tryCatchBuilder.mutableCapturedVariables);
floitsch 2015/02/16 14:54:07 I'm not a fan of these kind of side-effects in a b
Kevin Millikin (Google) 2015/02/24 11:59:25 Hmmm. The other approach that we use a lot is to
513 for (LocalVariableElement variable in tryInfo.boxedOnEntry) {
514 assert(!tryCatchBuilder.isInMutableVariable(variable));
515 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable);
516 tryCatchBuilder.makeMutableVariable(variable);
517 tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
518 }
519
520 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
521 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
522 List<ir.Parameter> joinParameters =
523 new List<ir.Parameter>.generate(irBuilder.environment.length, (i) {
524 return new ir.Parameter(irBuilder.environment.index2variable[i]);
525 });
526 ir.Continuation joinContinuation = new ir.Continuation(joinParameters);
527 withBuilder(tryBuilder, () {
528 visit(node.tryBlock);
529 });
530 if (tryBuilder.isOpen) {
531 for (LocalVariableElement variable in tryInfo.boxedOnEntry) {
532 assert(tryBuilder.isInMutableVariable(variable));
533 ir.Primitive value = tryBuilder.buildLocalGet(variable);
534 tryBuilder.environment.update(variable, value);
535 }
536 assert(tryBuilder.environment.length >= irBuilder.environment.length);
537 ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized();
538 jump.continuation = new ir.Reference(joinContinuation);
539 jump.arguments = new List<ir.Reference>.generate(
540 irBuilder.environment.length, (i) {
541 return new ir.Reference(tryBuilder.environment[i]);
542 });
543 tryBuilder.add(jump);
544 tryBuilder._current = null;
asgerf 2015/02/20 10:10:07 Would it make sense to extract these 8 lines into
Kevin Millikin (Google) 2015/02/24 11:59:25 Yes. It also occurs when breaking from a labeled
545 }
546
547 for (LocalVariableElement variable in tryInfo.boxedOnEntry) {
548 assert(catchBuilder.isInMutableVariable(variable));
549 ir.Primitive value = catchBuilder.buildLocalGet(variable);
550 // Note that we remove the variable from the set of mutable variables
551 // here (and not above for the try body). This is because the set of
552 // mutable variables is global for the whole function and not local to
553 // a delimited builder.
554 catchBuilder.removeMutableVariable(variable);
555 catchBuilder.environment.update(variable, value);
556 }
557 ast.CatchBlock catchClause = node.catchBlocks.nodes.head;
558 assert(catchClause.exception != null);
559 List<ir.Parameter> catchParameters =
560 <ir.Parameter>[new ir.Parameter(elements[catchClause.exception])];
561 catchBuilder.environment.extend(elements[catchClause.exception] as Local,
karlklose 2015/02/16 10:15:48 Why do you cast to Local here and below?
Kevin Millikin (Google) 2015/02/24 11:59:25 Otherwise the editor reports "The argument type 'E
562 catchParameters[0]);
563 if (catchClause.trace != null) {
564 catchParameters.add(new ir.Parameter(elements[catchClause.trace]));
565 catchBuilder.environment.extend(elements[catchClause.trace] as Local,
566 catchParameters[1]);
567 }
568 withBuilder(catchBuilder, () {
569 visit(catchClause.block);
570 });
571 if (catchBuilder.isOpen) {
572 assert(catchBuilder.environment.length >= irBuilder.environment.length);
573 ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized();
574 jump.continuation = new ir.Reference(joinContinuation);
575 jump.arguments = new List<ir.Reference>.generate(
576 irBuilder.environment.length, (i) {
577 return new ir.Reference(catchBuilder.environment[i]);
578 });
579 catchBuilder.add(jump);
580 catchBuilder._current = null;
581 }
582 ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
583 catchContinuation.body = catchBuilder._root;
584
585 tryCatchBuilder.add(new ir.LetHandler(catchContinuation, tryBuilder._root));
586 tryCatchBuilder._current = null;
587
588 irBuilder.add(new ir.LetCont(joinContinuation, tryCatchBuilder._root));
589 for (int i = 0; i < irBuilder.environment.length; ++i) {
590 irBuilder.environment.index2value[i] = joinParameters[i];
591 }
592 return null;
593 }
594
454 // ==== Expressions ==== 595 // ==== Expressions ====
455 ir.Primitive visitConditional(ast.Conditional node) { 596 ir.Primitive visitConditional(ast.Conditional node) {
456 return irBuilder.buildConditional( 597 return irBuilder.buildConditional(
457 build(node.condition), 598 build(node.condition),
458 subbuild(node.thenExpression), 599 subbuild(node.thenExpression),
459 subbuild(node.elseExpression)); 600 subbuild(node.elseExpression));
460 } 601 }
461 602
462 // For all simple literals: 603 // For all simple literals:
463 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x] 604 // Build(Literal(c), C) = C[let val x = Constant(c) in [], x]
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after
953 throw ABORT_IRNODE_BUILDER; 1094 throw ABORT_IRNODE_BUILDER;
954 } 1095 }
955 1096
956 /// Classifies local variables and local functions as captured, if they 1097 /// Classifies local variables and local functions as captured, if they
957 /// are accessed from within a nested function. 1098 /// are accessed from within a nested function.
958 /// 1099 ///
959 /// This class is specific to the [DartIrBuilder], in that it gives up if it 1100 /// This class is specific to the [DartIrBuilder], in that it gives up if it
960 /// sees a feature that is currently unsupport by that builder. In particular, 1101 /// sees a feature that is currently unsupport by that builder. In particular,
961 /// loop variables captured in a for-loop initializer, condition, or update 1102 /// loop variables captured in a for-loop initializer, condition, or update
962 /// expression are unsupported. 1103 /// expression are unsupported.
963 class DartCapturedVariables extends ast.Visitor 1104 class DartCapturedVariables extends ast.Visitor {
964 implements DartCapturedVariableInfo {
965 final TreeElements elements; 1105 final TreeElements elements;
966 DartCapturedVariables(this.elements); 1106 DartCapturedVariables(this.elements);
967 1107
968 FunctionElement currentFunction; 1108 FunctionElement currentFunction;
969 bool insideInitializer = false; 1109 bool insideInitializer = false;
970 Set<Local> capturedVariables = new Set<Local>(); 1110 Set<Local> capturedVariables = new Set<Local>();
971 1111
1112 Map<ast.TryStatement, TryStatementInfo> tryStatements =
1113 <ast.TryStatement, TryStatementInfo>{};
1114
1115 TryStatementInfo currentTryInfo;
1116 bool get inTryStatement => currentTryInfo != null;
1117
972 void markAsCaptured(Local local) { 1118 void markAsCaptured(Local local) {
973 capturedVariables.add(local); 1119 capturedVariables.add(local);
974 } 1120 }
975 1121
976 visit(ast.Node node) => node.accept(this); 1122 visit(ast.Node node) => node.accept(this);
977 1123
978 visitNode(ast.Node node) { 1124 visitNode(ast.Node node) {
979 node.visitChildren(this); 1125 node.visitChildren(this);
980 } 1126 }
981 1127
(...skipping 27 matching lines...) Expand all
1009 } 1155 }
1010 1156
1011 visitSend(ast.Send node) { 1157 visitSend(ast.Send node) {
1012 handleSend(node); 1158 handleSend(node);
1013 node.visitChildren(this); 1159 node.visitChildren(this);
1014 } 1160 }
1015 1161
1016 visitSendSet(ast.SendSet node) { 1162 visitSendSet(ast.SendSet node) {
1017 handleSend(node); 1163 handleSend(node);
1018 Element element = elements[node]; 1164 Element element = elements[node];
1019 // Initializers in an initializer-list can communicate via parameters. 1165 if (Elements.isLocal(element)) {
1020 // If a parameter is stored in an initializer list we box it.
1021 if (insideInitializer &&
1022 Elements.isLocal(element) &&
1023 element.isParameter) {
1024 LocalElement local = element; 1166 LocalElement local = element;
1025 // TODO(sigurdm): Fix this. 1167 if (insideInitializer) {
1026 // Though these variables do not outlive the activation of the function, 1168 assert(local.isParameter);
1027 // they still need to be boxed. As a simplification, we treat them as if 1169 // Initializers in an initializer-list can communicate via parameters.
1028 // they are captured by a closure (i.e., they do outlive the activation of 1170 // If a parameter is stored in an initializer list we box it.
1029 // the function). 1171 // TODO(sigurdm): Fix this.
1030 markAsCaptured(local); 1172 // Though these variables do not outlive the activation of the
1173 // function, they still need to be boxed. As a simplification, we
1174 // treat them as if they are captured by a closure (i.e., they do
1175 // outlive the activation of the function).
1176 markAsCaptured(local);
1177 } else if (inTryStatement) {
1178 assert(local.isParameter || local.isVariable);
1179 if (!currentTryInfo.declared.contains(local)) {
1180 // If a variable is assigned in a try and not declared in that try
1181 // then it has to be boxed on entry to the try.
1182 // Later we will remove such variables that will be boxed in an
1183 // enclosing try.
1184 currentTryInfo.boxedOnEntry.add(local);
1185 }
1186 }
1031 } 1187 }
1032 node.visitChildren(this); 1188 node.visitChildren(this);
1033 } 1189 }
1034 1190
1035 visitFunctionExpression(ast.FunctionExpression node) { 1191 visitFunctionExpression(ast.FunctionExpression node) {
1036 FunctionElement oldFunction = currentFunction; 1192 FunctionElement oldFunction = currentFunction;
1037 currentFunction = elements[node]; 1193 currentFunction = elements[node];
1038 if (currentFunction.asyncMarker != AsyncMarker.SYNC) { 1194 if (currentFunction.asyncMarker != AsyncMarker.SYNC) {
1039 giveup(node, "cannot handle async/sync*/async* functions"); 1195 giveup(node, "cannot handle async/sync*/async* functions");
1040 } 1196 }
1041 if (node.initializers != null) { 1197 if (node.initializers != null) {
1042 insideInitializer = true; 1198 insideInitializer = true;
1043 visit(node.initializers); 1199 visit(node.initializers);
1044 insideInitializer = false; 1200 insideInitializer = false;
1045 } 1201 }
1046 visit(node.body); 1202 visit(node.body);
1047 currentFunction = oldFunction; 1203 currentFunction = oldFunction;
1048 } 1204 }
1205
1206 visitTryStatement(ast.TryStatement node) {
1207 TryStatementInfo outer = currentTryInfo;
1208 tryStatements[node] = currentTryInfo = new TryStatementInfo(outer);
1209 visit(node.tryBlock);
1210 if (outer == null) {
1211 // For each top-level try, compute the variables boxed on entry to it
1212 // and each nested try in a top-down manner.
1213 currentTryInfo.computeVariablesBoxedOnEntry(null);
1214 }
1215 currentTryInfo = outer;
1216
1217 visit(node.catchBlocks);
1218 if (node.finallyBlock != null) visit(node.finallyBlock);
1219 }
1220
1221 visitVariableDefinitions(ast.VariableDefinitions node) {
1222 if (inTryStatement) {
1223 for (ast.Node definition in node.definitions.nodes) {
1224 LocalVariableElement local = elements[definition];
1225 assert(local != null);
1226 // In the closure conversion pass we check for isInitializingFormal,
1227 // but I'm not sure it can arise.
1228 assert(!local.isInitializingFormal);
1229 currentTryInfo.declared.add(local);
1230 }
1231 }
1232 node.visitChildren(this);
1233 }
1049 } 1234 }
1050 1235
1051 /// IR builder specific to the Dart backend, coupled to the [DartIrBuilder]. 1236 /// IR builder specific to the Dart backend, coupled to the [DartIrBuilder].
1052 class DartIrBuilderVisitor extends IrBuilderVisitor { 1237 class DartIrBuilderVisitor extends IrBuilderVisitor {
1053 /// Promote the type of [irBuilder] to [DartIrBuilder]. 1238 /// Promote the type of [irBuilder] to [DartIrBuilder].
1054 DartIrBuilder get irBuilder => super.irBuilder; 1239 DartIrBuilder get irBuilder => super.irBuilder;
1055 1240
1056 DartIrBuilderVisitor(TreeElements elements, 1241 DartIrBuilderVisitor(TreeElements elements,
1057 Compiler compiler, 1242 Compiler compiler,
1058 SourceFile sourceFile) 1243 SourceFile sourceFile)
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after
1683 for (String argName in selector.getOrderedNamedArguments()) { 1868 for (String argName in selector.getOrderedNamedArguments()) {
1684 int nameIndex = selector.namedArguments.indexOf(argName); 1869 int nameIndex = selector.namedArguments.indexOf(argName);
1685 int translatedIndex = selector.positionalArgumentCount + nameIndex; 1870 int translatedIndex = selector.positionalArgumentCount + nameIndex;
1686 result.add(arguments[translatedIndex]); 1871 result.add(arguments[translatedIndex]);
1687 } 1872 }
1688 return result; 1873 return result;
1689 } 1874 }
1690 1875
1691 } 1876 }
1692 1877
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698