| 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 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 392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 403 | 403 |
| 404 // Build(ExpressionStatement(e), C) = C' | 404 // Build(ExpressionStatement(e), C) = C' |
| 405 // where (C', _) = Build(e, C) | 405 // where (C', _) = Build(e, C) |
| 406 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) { | 406 ir.Primitive visitExpressionStatement(ast.ExpressionStatement node) { |
| 407 assert(irBuilder.isOpen); | 407 assert(irBuilder.isOpen); |
| 408 visit(node.expression); | 408 visit(node.expression); |
| 409 return null; | 409 return null; |
| 410 } | 410 } |
| 411 | 411 |
| 412 visitFor(ast.For node) { | 412 visitFor(ast.For node) { |
| 413 // TODO(asgerf): Handle closure variables declared in a for-loop. | 413 List<LocalElement> loopVariables = <LocalElement>[]; |
| 414 if (!isJavaScriptBackend && node.initializer is ast.VariableDefinitions) { | 414 if (node.initializer is ast.VariableDefinitions) { |
| 415 ast.VariableDefinitions definitions = node.initializer; | 415 ast.VariableDefinitions definitions = node.initializer; |
| 416 for (ast.Node definition in definitions.definitions.nodes) { | 416 for (ast.Node node in definitions.definitions.nodes) { |
| 417 LocalElement element = elements[definition]; | 417 LocalElement loopVariable = elements[node]; |
| 418 DartIrBuilder dartIrBuilder = irBuilder; | 418 loopVariables.add(loopVariable); |
| 419 if (dartIrBuilder.isInClosureVariable(element)) { | |
| 420 return giveup(definition, 'Closure variable in for loop initializer'); | |
| 421 } | |
| 422 } | 419 } |
| 423 } | 420 } |
| 424 | 421 |
| 425 JumpTarget target = elements.getTargetDefinition(node); | 422 JumpTarget target = elements.getTargetDefinition(node); |
| 426 irBuilder.buildFor( | 423 irBuilder.buildFor( |
| 427 buildInitializer: subbuild(node.initializer), | 424 buildInitializer: subbuild(node.initializer), |
| 428 buildCondition: subbuild(node.condition), | 425 buildCondition: subbuild(node.condition), |
| 429 buildBody: subbuild(node.body), | 426 buildBody: subbuild(node.body), |
| 430 buildUpdate: subbuildSequence(node.update), | 427 buildUpdate: subbuildSequence(node.update), |
| 431 closureScope: getClosureScope(node), | 428 closureScope: getClosureScope(node), |
| 429 loopVariables: loopVariables, |
| 432 target: target); | 430 target: target); |
| 433 } | 431 } |
| 434 | 432 |
| 435 visitIf(ast.If node) { | 433 visitIf(ast.If node) { |
| 436 irBuilder.buildIf( | 434 irBuilder.buildIf( |
| 437 build(node.condition), | 435 build(node.condition), |
| 438 subbuild(node.thenPart), | 436 subbuild(node.thenPart), |
| 439 subbuild(node.elsePart)); | 437 subbuild(node.elsePart)); |
| 440 } | 438 } |
| 441 | 439 |
| (...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1038 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { | 1036 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) { |
| 1039 return irBuilder.buildFunctionExpression(makeSubFunction(node)); | 1037 return irBuilder.buildFunctionExpression(makeSubFunction(node)); |
| 1040 } | 1038 } |
| 1041 | 1039 |
| 1042 visitFunctionDeclaration(ast.FunctionDeclaration node) { | 1040 visitFunctionDeclaration(ast.FunctionDeclaration node) { |
| 1043 LocalFunctionElement element = elements[node.function]; | 1041 LocalFunctionElement element = elements[node.function]; |
| 1044 Object inner = makeSubFunction(node.function); | 1042 Object inner = makeSubFunction(node.function); |
| 1045 irBuilder.declareLocalFunction(element, inner); | 1043 irBuilder.declareLocalFunction(element, inner); |
| 1046 } | 1044 } |
| 1047 | 1045 |
| 1048 static final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; | |
| 1049 | |
| 1050 dynamic giveup(ast.Node node, [String reason]) { | |
| 1051 throw ABORT_IRNODE_BUILDER; | |
| 1052 } | |
| 1053 | |
| 1054 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { | 1046 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { |
| 1055 try { | 1047 try { |
| 1056 return action(); | 1048 return action(); |
| 1057 } catch(e, tr) { | 1049 } catch(e, tr) { |
| 1058 if (e == ABORT_IRNODE_BUILDER) { | 1050 if (e == ABORT_IRNODE_BUILDER) { |
| 1059 return null; | 1051 return null; |
| 1060 } | 1052 } |
| 1061 rethrow; | 1053 rethrow; |
| 1062 } | 1054 } |
| 1063 } | 1055 } |
| 1064 | 1056 |
| 1065 void internalError(String reason, {ast.Node node}) { | 1057 void internalError(String reason, {ast.Node node}) { |
| 1066 giveup(node); | 1058 giveup(node); |
| 1067 } | 1059 } |
| 1068 } | 1060 } |
| 1069 | 1061 |
| 1070 /// Classifies local variables and local functions as 'closure variables'. | 1062 final String ABORT_IRNODE_BUILDER = "IrNode builder aborted"; |
| 1071 /// A closure variable is one that is accessed from an inner function nested | 1063 |
| 1072 /// one or more levels inside the one that declares it. | 1064 dynamic giveup(ast.Node node, [String reason]) { |
| 1065 throw ABORT_IRNODE_BUILDER; |
| 1066 } |
| 1067 |
| 1068 /// Classifies local variables and local functions as captured, if they |
| 1069 /// are accessed from within a nested function. |
| 1070 /// |
| 1071 /// This class is specific to the [DartIrBuilder], in that it gives up if it |
| 1072 /// sees a feature that is currently unsupport by that builder. In particular, |
| 1073 /// loop variables captured in a for-loop initializer, condition, or update |
| 1074 /// expression are unsupported. |
| 1073 class DetectClosureVariables extends ast.Visitor | 1075 class DetectClosureVariables extends ast.Visitor |
| 1074 implements ClosureVariableInfo { | 1076 implements ClosureVariableInfo { |
| 1075 final TreeElements elements; | 1077 final TreeElements elements; |
| 1076 DetectClosureVariables(this.elements); | 1078 DetectClosureVariables(this.elements); |
| 1077 | 1079 |
| 1078 FunctionElement currentFunction; | 1080 FunctionElement currentFunction; |
| 1079 bool insideInitializer = false; | 1081 bool insideInitializer = false; |
| 1080 Set<Local> capturedVariables = new Set<Local>(); | 1082 Set<Local> capturedVariables = new Set<Local>(); |
| 1081 | 1083 |
| 1082 void markAsClosureVariable(Local local) { | 1084 void markAsClosureVariable(Local local) { |
| 1083 capturedVariables.add(local); | 1085 capturedVariables.add(local); |
| 1084 } | 1086 } |
| 1085 | 1087 |
| 1086 visit(ast.Node node) => node.accept(this); | 1088 visit(ast.Node node) => node.accept(this); |
| 1087 | 1089 |
| 1088 visitNode(ast.Node node) { | 1090 visitNode(ast.Node node) { |
| 1089 node.visitChildren(this); | 1091 node.visitChildren(this); |
| 1090 } | 1092 } |
| 1091 | 1093 |
| 1094 visitFor(ast.For node) { |
| 1095 if (node.initializer != null) visit(node.initializer); |
| 1096 if (node.condition != null) visit(node.condition); |
| 1097 if (node.update != null) visit(node.update); |
| 1098 |
| 1099 // Give up if a variable was captured outside of the loop body. |
| 1100 if (node.initializer is ast.VariableDefinitions) { |
| 1101 ast.VariableDefinitions definitions = node.initializer; |
| 1102 for (ast.Node node in definitions.definitions.nodes) { |
| 1103 LocalElement loopVariable = elements[node]; |
| 1104 if (capturedVariables.contains(loopVariable)) { |
| 1105 return giveup(node, 'For-loop variable captured in loop header'); |
| 1106 } |
| 1107 } |
| 1108 } |
| 1109 |
| 1110 if (node.body != null) visit(node.body); |
| 1111 } |
| 1112 |
| 1092 void handleSend(ast.Send node) { | 1113 void handleSend(ast.Send node) { |
| 1093 Element element = elements[node]; | 1114 Element element = elements[node]; |
| 1094 if (Elements.isLocal(element) && | 1115 if (Elements.isLocal(element) && |
| 1095 !element.isConst && | 1116 !element.isConst && |
| 1096 element.enclosingElement != currentFunction) { | 1117 element.enclosingElement != currentFunction) { |
| 1097 LocalElement local = element; | 1118 LocalElement local = element; |
| 1098 markAsClosureVariable(local); | 1119 markAsClosureVariable(local); |
| 1099 } | 1120 } |
| 1100 } | 1121 } |
| 1101 | 1122 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1128 currentFunction = elements[node]; | 1149 currentFunction = elements[node]; |
| 1129 if (node.initializers != null) { | 1150 if (node.initializers != null) { |
| 1130 insideInitializer = true; | 1151 insideInitializer = true; |
| 1131 visit(node.initializers); | 1152 visit(node.initializers); |
| 1132 insideInitializer = false; | 1153 insideInitializer = false; |
| 1133 } | 1154 } |
| 1134 visit(node.body); | 1155 visit(node.body); |
| 1135 currentFunction = oldFunction; | 1156 currentFunction = oldFunction; |
| 1136 } | 1157 } |
| 1137 } | 1158 } |
| OLD | NEW |