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

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

Issue 862703002: Implement constructor bodies and initializers in CPS->JS backend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix test case Created 5 years, 11 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 24 matching lines...) Expand all
35 return nodes[element.implementation]; 35 return nodes[element.implementation];
36 } 36 }
37 37
38 ir.ExecutableDefinition buildNode(AstElement element) { 38 ir.ExecutableDefinition buildNode(AstElement element) {
39 if (!canBuild(element)) return null; 39 if (!canBuild(element)) return null;
40 TreeElements elementsMapping = element.resolvedAst.elements; 40 TreeElements elementsMapping = element.resolvedAst.elements;
41 element = element.implementation; 41 element = element.implementation;
42 return compiler.withCurrentElement(element, () { 42 return compiler.withCurrentElement(element, () {
43 SourceFile sourceFile = elementSourceFile(element); 43 SourceFile sourceFile = elementSourceFile(element);
44 IrBuilderVisitor builder = 44 IrBuilderVisitor builder =
45 new IrBuilderVisitor(elementsMapping, compiler, sourceFile); 45 compiler.backend is JavaScriptBackend
46 ? new JsIrBuilderVisitor(elementsMapping, compiler, sourceFile)
47 : new DartIrBuilderVisitor(elementsMapping, compiler, sourceFile);
46 return builder.buildExecutable(element); 48 return builder.buildExecutable(element);
47 }); 49 });
48 } 50 }
49 51
50 void buildNodes() { 52 void buildNodes() {
51 measure(() { 53 measure(() {
52 Set<Element> resolved = compiler.enqueuer.resolution.resolvedElements; 54 Set<Element> resolved = compiler.enqueuer.resolution.resolvedElements;
53 resolved.forEach((AstElement element) { 55 resolved.forEach((AstElement element) {
54 ir.ExecutableDefinition definition = buildNode(element); 56 ir.ExecutableDefinition definition = buildNode(element);
55 if (definition != null) { 57 if (definition != null) {
(...skipping 19 matching lines...) Expand all
75 } 77 }
76 return compiler.backend.shouldOutput(element); 78 return compiler.backend.shouldOutput(element);
77 } 79 }
78 80
79 bool get inCheckedMode { 81 bool get inCheckedMode {
80 bool result = false; 82 bool result = false;
81 assert((result = true)); 83 assert((result = true));
82 return result; 84 return result;
83 } 85 }
84 86
85 SourceFile elementSourceFile(Element element) { 87 }
86 if (element is FunctionElement) { 88
87 FunctionElement functionElement = element; 89 SourceFile elementSourceFile(Element element) {
88 if (functionElement.patch != null) element = functionElement.patch; 90 if (element is FunctionElement) {
89 } 91 FunctionElement functionElement = element;
90 return element.compilationUnit.script.file; 92 if (functionElement.patch != null) element = functionElement.patch;
91 } 93 }
94 return element.compilationUnit.script.file;
92 } 95 }
93 96
94 class _GetterElements { 97 class _GetterElements {
95 ir.Primitive result; 98 ir.Primitive result;
96 ir.Primitive index; 99 ir.Primitive index;
97 ir.Primitive receiver; 100 ir.Primitive receiver;
98 101
99 _GetterElements({this.result, this.index, this.receiver}) ; 102 _GetterElements({this.result, this.index, this.receiver}) ;
100 } 103 }
101 104
102 /** 105 /**
103 * A tree visitor that builds [IrNodes]. The visit methods add statements using 106 * A tree visitor that builds [IrNodes]. The visit methods add statements using
104 * to the [builder] and return the last added statement for trees that represent 107 * to the [builder] and return the last added statement for trees that represent
105 * an expression. 108 * an expression.
106 */ 109 */
107 class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive> 110 abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
108 with IrBuilderMixin<ast.Node> { 111 with IrBuilderMixin<ast.Node> {
109 final Compiler compiler; 112 final Compiler compiler;
110 final SourceFile sourceFile; 113 final SourceFile sourceFile;
111 ClosureClassMap closureMap;
112 114
113 // In SSA terms, join-point continuation parameters are the phis and the 115 // In SSA terms, join-point continuation parameters are the phis and the
114 // continuation invocation arguments are the corresponding phi inputs. To 116 // continuation invocation arguments are the corresponding phi inputs. To
115 // support name introduction and renaming for source level variables, we use 117 // support name introduction and renaming for source level variables, we use
116 // nested (delimited) visitors for constructing subparts of the IR that will 118 // nested (delimited) visitors for constructing subparts of the IR that will
117 // need renaming. Each source variable is assigned an index. 119 // need renaming. Each source variable is assigned an index.
118 // 120 //
119 // Each nested visitor maintains a list of free variable uses in the body. 121 // Each nested visitor maintains a list of free variable uses in the body.
120 // These are implemented as a list of parameters, each with their own use 122 // These are implemented as a list of parameters, each with their own use
121 // list of references. When the delimited subexpression is plugged into the 123 // list of references. When the delimited subexpression is plugged into the
122 // surrounding context, the free occurrences can be captured or become free 124 // surrounding context, the free occurrences can be captured or become free
123 // occurrences in the next outer delimited subexpression. 125 // occurrences in the next outer delimited subexpression.
124 // 126 //
125 // Each nested visitor maintains a list that maps indexes of variables 127 // Each nested visitor maintains a list that maps indexes of variables
126 // assigned in the delimited subexpression to their reaching definition --- 128 // assigned in the delimited subexpression to their reaching definition ---
127 // that is, the definition in effect at the hole in 'current'. These are 129 // that is, the definition in effect at the hole in 'current'. These are
128 // used to determine if a join-point continuation needs to be passed 130 // used to determine if a join-point continuation needs to be passed
129 // arguments, and what the arguments are. 131 // arguments, and what the arguments are.
130 132
131 /// Construct a top-level visitor. 133 /// Construct a top-level visitor.
132 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) 134 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile)
133 : super(elements); 135 : super(elements);
134 136
135 /// True if using the JavaScript backend; we use this to determine how
136 /// closures should be translated.
137 bool get isJavaScriptBackend => compiler.backend is JavaScriptBackend;
138
139 /** 137 /**
140 * Builds the [ir.ExecutableDefinition] for an executable element. In case the 138 * Builds the [ir.ExecutableDefinition] for an executable element. In case the
141 * function uses features that cannot be expressed in the IR, this element 139 * function uses features that cannot be expressed in the IR, this element
142 * returns `null`. 140 * returns `null`.
143 */ 141 */
144 ir.ExecutableDefinition buildExecutable(ExecutableElement element) { 142 ir.ExecutableDefinition buildExecutable(ExecutableElement element);
145 return nullIfGiveup(() {
146 if (element is FieldElement) {
147 return buildField(element);
148 } else if (element is FunctionElement) {
149 return buildFunction(element);
150 } else {
151 compiler.internalError(element, "Unexpected element type $element");
152 }
153 });
154 }
155 143
156 Map mapValues(Map map, dynamic fn(dynamic)) { 144 ClosureScope getClosureScope(ast.Node node);
157 Map result = {}; 145 ClosureEnvironment getClosureEnvironment();
158 map.forEach((key,value) {
159 result[key] = fn(value);
160 });
161 return result;
162 }
163 146
164 // Converts closure.dart's CapturedVariable into a ClosureLocation.
165 // There is a 1:1 corresponce between these; we do this because the IR builder
166 // should not depend on synthetic elements.
167 ClosureLocation getLocation(CapturedVariable v) {
168 if (v is BoxFieldElement) {
169 return new ClosureLocation(v.box, v);
170 } else {
171 ClosureFieldElement field = v;
172 return new ClosureLocation(null, field);
173 }
174 }
175 147
176 /// If the current function is a nested function with free variables (or a
177 /// captured reference to `this`), this returns a [ClosureEnvironment]
178 /// indicating how to access these.
179 ClosureEnvironment getClosureEnvironment() {
180 if (closureMap == null) return null; // dart2dart does not use closureMap.
181 if (closureMap.closureElement == null) return null;
182 return new ClosureEnvironment(
183 closureMap.closureElement,
184 closureMap.thisLocal,
185 mapValues(closureMap.freeVariableMap, getLocation));
186 }
187
188 /// If [node] has declarations for variables that should be boxed, this
189 /// returns a [ClosureScope] naming a box to create, and enumerating the
190 /// variables that should be stored in the box.
191 ///
192 /// Also see [ClosureScope].
193 ClosureScope getClosureScope(ast.Node node) {
194 if (closureMap == null) return null; // dart2dart does not use closureMap.
195 closurelib.ClosureScope scope = closureMap.capturingScopes[node];
196 if (scope == null) return null;
197 // We translate a ClosureScope from closure.dart into IR builder's variant
198 // because the IR builder should not depend on the synthetic elements
199 // created in closure.dart.
200 return new ClosureScope(scope.boxElement,
201 mapValues(scope.capturedVariables, getLocation),
202 scope.boxedLoopVariables);
203 }
204
205 IrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
206 if (isJavaScriptBackend) {
207 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
208 element,
209 node,
210 elements);
211 return new JsIrBuilder(compiler.backend.constantSystem, element);
212 } else {
213 DetectClosureVariables closures = new DetectClosureVariables(elements);
214 if (!element.isSynthesized) {
215 closures.visit(node);
216 }
217 return new DartIrBuilder(compiler.backend.constantSystem,
218 element,
219 closures);
220 }
221 }
222
223 /// Returns a [ir.FieldDefinition] describing the initializer of [element].
224 ir.FieldDefinition buildField(FieldElement element) {
225 assert(invariant(element, element.isImplementation));
226 ast.VariableDefinitions definitions = element.node;
227 ast.Node fieldDefinition =
228 definitions.definitions.nodes.first;
229 if (definitions.modifiers.isConst) {
230 // TODO(sigurdm): Just return const value.
231 }
232 assert(fieldDefinition != null);
233 assert(elements[fieldDefinition] != null);
234
235 IrBuilder builder = makeIRBuilder(fieldDefinition, element);
236
237 return withBuilder(builder, () {
238 builder.buildFieldInitializerHeader(
239 closureScope: getClosureScope(fieldDefinition));
240 ir.Primitive initializer;
241 if (fieldDefinition is ast.SendSet) {
242 ast.SendSet sendSet = fieldDefinition;
243 initializer = visit(sendSet.arguments.first);
244 }
245 return builder.makeFieldDefinition(initializer);
246 });
247 }
248 148
249 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, 149 ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
250 ast.FunctionExpression node) { 150 ast.FunctionExpression node) {
251 FunctionSignature signature = element.functionSignature; 151 FunctionSignature signature = element.functionSignature;
252 List<ParameterElement> parameters = []; 152 List<ParameterElement> parameters = [];
253 signature.orderedForEachParameter(parameters.add); 153 signature.orderedForEachParameter(parameters.add);
254 154
255 irBuilder.buildFunctionHeader(parameters, 155 irBuilder.buildFunctionHeader(parameters,
256 closureScope: getClosureScope(node), 156 closureScope: getClosureScope(node),
257 closureEnvironment: getClosureEnvironment()); 157 env: getClosureEnvironment());
258 158
259 List<ConstantExpression> defaults = new List<ConstantExpression>(); 159 List<ConstantExpression> defaults = new List<ConstantExpression>();
260 signature.orderedOptionalParameters.forEach((ParameterElement element) { 160 signature.orderedOptionalParameters.forEach((ParameterElement element) {
261 defaults.add(getConstantForVariable(element)); 161 defaults.add(getConstantForVariable(element));
262 }); 162 });
263 163
264 List<ir.Initializer> initializers; 164 List<ir.Initializer> initializers;
265 if (element.isSynthesized) { 165 if (element.isSynthesized) {
266 assert(element is ConstructorElement); 166 assert(element is ConstructorElement);
267 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[], 167 return irBuilder.makeConstructorDefinition(const <ConstantExpression>[],
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 "No default constructor available."); 245 "No default constructor available.");
346 } 246 }
347 result.add(irBuilder.makeSuperInitializer(target, 247 result.add(irBuilder.makeSuperInitializer(target,
348 <ir.RunnableBody>[], 248 <ir.RunnableBody>[],
349 selector)); 249 selector));
350 } 250 }
351 } 251 }
352 return result; 252 return result;
353 } 253 }
354 254
355 ir.FunctionDefinition buildFunction(FunctionElement element) {
356 assert(invariant(element, element.isImplementation));
357 ast.FunctionExpression node = element.node;
358
359 Iterable<Entity> usedFromClosure;
360 if (!element.isSynthesized) {
361 assert(node != null);
362 assert(elements[node] != null);
363 } else {
364 SynthesizedConstructorElementX constructor = element;
365 if (!constructor.isDefaultConstructor) {
366 giveup(null, 'cannot handle synthetic forwarding constructors');
367 }
368
369 usedFromClosure = <Entity>[];
370 }
371
372 IrBuilder builder = makeIRBuilder(node, element);
373
374 return withBuilder(builder, () => _makeFunctionBody(element, node));
375 }
376
377 ir.Primitive visit(ast.Node node) => node.accept(this); 255 ir.Primitive visit(ast.Node node) => node.accept(this);
378 256
379 // ==== Statements ==== 257 // ==== Statements ====
380 visitBlock(ast.Block node) { 258 visitBlock(ast.Block node) {
381 irBuilder.buildBlock(node.statements.nodes, build); 259 irBuilder.buildBlock(node.statements.nodes, build);
382 } 260 }
383 261
384 ir.Primitive visitBreakStatement(ast.BreakStatement node) { 262 ir.Primitive visitBreakStatement(ast.BreakStatement node) {
385 if (!irBuilder.buildBreak(elements.getTargetOf(node))) { 263 if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
386 compiler.internalError(node, "'break' target not found"); 264 compiler.internalError(node, "'break' target not found");
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after
1011 } 889 }
1012 890
1013 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { 891 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) {
1014 assert(irBuilder.isOpen); 892 assert(irBuilder.isOpen);
1015 if (constant == null) { 893 if (constant == null) {
1016 constant = getConstantForNode(node); 894 constant = getConstantForNode(node);
1017 } 895 }
1018 return irBuilder.buildConstantLiteral(constant); 896 return irBuilder.buildConstantLiteral(constant);
1019 } 897 }
1020 898
1021 /// Returns the backend-specific representation of an inner function.
1022 Object makeSubFunction(ast.FunctionExpression node) {
1023 if (isJavaScriptBackend) {
1024 ClosureClassMap innerMap =
1025 compiler.closureToClassMapper.getMappingForNestedFunction(node);
1026 ClosureClassElement closureClass = innerMap.closureClassElement;
1027 return closureClass;
1028 } else {
1029 FunctionElement element = elements[node];
1030 assert(invariant(element, element.isImplementation));
1031
1032 IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element);
1033
1034 return withBuilder(builder, () => _makeFunctionBody(element, node));
1035 }
1036 }
1037
1038 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
1039 return irBuilder.buildFunctionExpression(makeSubFunction(node));
1040 }
1041
1042 visitFunctionDeclaration(ast.FunctionDeclaration node) {
1043 LocalFunctionElement element = elements[node.function];
1044 Object inner = makeSubFunction(node.function);
1045 irBuilder.declareLocalFunction(element, inner);
1046 }
1047
1048 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) { 899 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) {
1049 try { 900 try {
1050 return action(); 901 return action();
1051 } catch(e, tr) { 902 } catch(e, tr) {
1052 if (e == ABORT_IRNODE_BUILDER) { 903 if (e == ABORT_IRNODE_BUILDER) {
1053 return null; 904 return null;
1054 } 905 }
1055 rethrow; 906 rethrow;
1056 } 907 }
1057 } 908 }
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1151 currentFunction = elements[node]; 1002 currentFunction = elements[node];
1152 if (node.initializers != null) { 1003 if (node.initializers != null) {
1153 insideInitializer = true; 1004 insideInitializer = true;
1154 visit(node.initializers); 1005 visit(node.initializers);
1155 insideInitializer = false; 1006 insideInitializer = false;
1156 } 1007 }
1157 visit(node.body); 1008 visit(node.body);
1158 currentFunction = oldFunction; 1009 currentFunction = oldFunction;
1159 } 1010 }
1160 } 1011 }
1012
1013 /// IR builder specific to the Dart backend, coupled to the [DartIrBuilder].
1014 class DartIrBuilderVisitor extends IrBuilderVisitor {
1015 /// Promote the type of [irBuilder] to [DartIrBuilder].
1016 DartIrBuilder get irBuilder => super.irBuilder;
1017
1018 DartIrBuilderVisitor(TreeElements elements,
1019 Compiler compiler,
1020 SourceFile sourceFile)
1021 : super(elements, compiler, sourceFile);
1022
1023 DartIrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
1024 DetectClosureVariables closures = new DetectClosureVariables(elements);
floitsch 2015/01/21 16:29:34 This does not sound like a class name. Is this a C
asgerf 2015/01/22 10:18:58 I don't really buy into the "classes are nouns, me
1025 if (!element.isSynthesized) {
1026 closures.visit(node);
1027 }
1028 return new DartIrBuilder(compiler.backend.constantSystem,
1029 element,
1030 closures);
1031 }
1032
1033 /// Recursively builds the IR for the given nested function.
1034 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) {
1035 FunctionElement element = elements[node];
1036 assert(invariant(element, element.isImplementation));
1037
1038 IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element);
1039
1040 return withBuilder(builder, () => _makeFunctionBody(element, node));
1041 }
1042
1043 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
1044 return irBuilder.buildFunctionExpression(makeSubFunction(node));
1045 }
1046
1047 visitFunctionDeclaration(ast.FunctionDeclaration node) {
1048 LocalFunctionElement element = elements[node.function];
1049 Object inner = makeSubFunction(node.function);
1050 irBuilder.declareLocalFunction(element, inner);
1051 }
1052
1053 ClosureScope getClosureScope(ast.Node node) => null;
1054 ClosureEnvironment getClosureEnvironment() => null;
1055
1056 ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
1057 return nullIfGiveup(() {
1058 if (element is FieldElement) {
1059 return buildField(element);
1060 } else if (element is FunctionElement) {
1061 return buildFunction(element);
1062 } else {
1063 compiler.internalError(element, "Unexpected element type $element");
1064 }
1065 });
1066 }
1067
1068 /// Returns a [ir.FieldDefinition] describing the initializer of [element].
1069 ir.FieldDefinition buildField(FieldElement element) {
1070 assert(invariant(element, element.isImplementation));
1071 ast.VariableDefinitions definitions = element.node;
1072 ast.Node fieldDefinition = definitions.definitions.nodes.first;
1073 if (definitions.modifiers.isConst) {
1074 // TODO(sigurdm): Just return const value.
1075 }
1076 assert(fieldDefinition != null);
1077 assert(elements[fieldDefinition] != null);
1078
1079 IrBuilder builder = makeIRBuilder(fieldDefinition, element);
1080
1081 return withBuilder(builder, () {
1082 builder.buildFieldInitializerHeader(
1083 closureScope: getClosureScope(fieldDefinition));
1084 ir.Primitive initializer;
1085 if (fieldDefinition is ast.SendSet) {
1086 ast.SendSet sendSet = fieldDefinition;
1087 initializer = visit(sendSet.arguments.first);
1088 }
1089 return builder.makeFieldDefinition(initializer);
1090 });
1091 }
1092
1093 ir.FunctionDefinition buildFunction(FunctionElement element) {
1094 assert(invariant(element, element.isImplementation));
1095 ast.FunctionExpression node = element.node;
1096
1097 if (!element.isSynthesized) {
1098 assert(node != null);
1099 assert(elements[node] != null);
1100 } else {
1101 SynthesizedConstructorElementX constructor = element;
1102 if (!constructor.isDefaultConstructor) {
1103 giveup(null, 'cannot handle synthetic forwarding constructors');
1104 }
1105 }
1106
1107 IrBuilder builder = makeIRBuilder(node, element);
1108
1109 return withBuilder(builder, () => _makeFunctionBody(element, node));
1110 }
1111 }
1112
1113 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
1114 class JsIrBuilderVisitor extends IrBuilderVisitor {
1115 /// Promote the type of [irBuilder] to [JsIrBuilder].
1116 JsIrBuilder get irBuilder => super.irBuilder;
1117 ClosureClassMap closureMap;
1118
1119 /// During construction of a constructor factory, [fieldValues] maps fields
1120 /// to the primitive containing their initial value.
1121 Map<FieldElement, ir.Primitive> fieldValues = <FieldElement, ir.Primitive>{};
1122
1123 JsIrBuilderVisitor(TreeElements elements,
1124 Compiler compiler,
floitsch 2015/01/21 16:29:35 indentation.
asgerf 2015/01/22 10:18:57 Done.
1125 SourceFile sourceFile)
1126 : super(elements, compiler, sourceFile);
1127
1128 JsIrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
1129 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
floitsch 2015/01/21 16:29:35 This requires comments, and potentially a refactor
asgerf 2015/01/22 10:18:57 It's a leftover from before the separate subclasse
1130 element,
1131 node,
1132 elements);
1133 return new JsIrBuilder(compiler.backend.constantSystem, element);
1134 }
1135
1136 /// Builds the IR for creating an instance of the closure class corresponding
1137 /// to the given nested function.
1138 ClosureClassElement makeSubFunction(ast.FunctionExpression node) {
1139 ClosureClassMap innerMap =
1140 compiler.closureToClassMapper.getMappingForNestedFunction(node);
1141 ClosureClassElement closureClass = innerMap.closureClassElement;
1142 return closureClass;
1143 }
1144
1145 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
1146 return irBuilder.buildFunctionExpression(makeSubFunction(node));
1147 }
1148
1149 visitFunctionDeclaration(ast.FunctionDeclaration node) {
1150 LocalFunctionElement element = elements[node.function];
1151 Object inner = makeSubFunction(node.function);
1152 irBuilder.declareLocalFunction(element, inner);
1153 }
1154
1155 Map mapValues(Map map, dynamic fn(dynamic)) {
1156 Map result = {};
1157 map.forEach((key,value) {
floitsch 2015/01/21 16:29:34 space after ','
asgerf 2015/01/22 10:18:58 Done.
1158 result[key] = fn(value);
1159 });
1160 return result;
1161 }
1162
1163 /// Converts closure.dart's CapturedVariable into a ClosureLocation.
1164 /// There is a 1:1 corresponce between these; we do this because the
1165 /// IR builder should not depend on synthetic elements.
1166 ClosureLocation getLocation(CapturedVariable v) {
1167 if (v is BoxFieldElement) {
1168 return new ClosureLocation(v.box, v);
1169 } else {
1170 ClosureFieldElement field = v;
1171 return new ClosureLocation(null, field);
1172 }
1173 }
1174
1175 /// If the current function is a nested function with free variables (or a
1176 /// captured reference to `this`), this returns a [ClosureEnvironment]
floitsch 2015/01/21 16:29:34 -this-
asgerf 2015/01/22 10:18:58 Done.
1177 /// indicating how to access these.
1178 ClosureEnvironment getClosureEnvironment() {
1179 if (closureMap.closureElement == null) return null;
1180 return new ClosureEnvironment(
1181 closureMap.closureElement,
1182 closureMap.thisLocal,
1183 mapValues(closureMap.freeVariableMap, getLocation));
1184 }
1185
1186 /// If [node] has declarations for variables that should be boxed, this
floitsch 2015/01/21 16:29:35 -this-
asgerf 2015/01/22 10:18:58 Done.
1187 /// returns a [ClosureScope] naming a box to create, and enumerating the
1188 /// variables that should be stored in the box.
1189 ///
1190 /// Also see [ClosureScope].
1191 ClosureScope getClosureScope(ast.Node node) {
1192 closurelib.ClosureScope scope = closureMap.capturingScopes[node];
floitsch 2015/01/21 16:29:34 This is weird: there is an import without the pref
asgerf 2015/01/22 10:18:57 Done.
1193 if (scope == null) return null;
1194 // We translate a ClosureScope from closure.dart into IR builder's variant
1195 // because the IR builder should not depend on the synthetic elements
1196 // created in closure.dart.
1197 return new ClosureScope(scope.boxElement,
1198 mapValues(scope.capturedVariables, getLocation),
1199 scope.boxedLoopVariables);
1200 }
1201
1202 /// Returns the [ClosureScope] for any function, possibly different from the
1203 /// one currently being built.
1204 ClosureScope getFunctionScope(FunctionElement function) {
floitsch 2015/01/21 16:29:35 Naming feels weird. I would have a tendency to ca
asgerf 2015/01/22 10:18:58 Yes the naming wasn't that great. Changed to the n
1205 ClosureClassMap map =
1206 compiler.closureToClassMapper.computeClosureToClassMapping(
1207 function,
1208 function.node,
1209 elements);
1210 closurelib.ClosureScope scope = map.capturingScopes[function.node];
1211 if (scope == null) return null;
1212 return new ClosureScope(scope.boxElement,
1213 mapValues(scope.capturedVariables, getLocation),
1214 scope.boxedLoopVariables);
1215 }
1216
1217 ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
1218 return nullIfGiveup(() {
1219 switch (element.kind) {
1220 case ElementKind.GENERATIVE_CONSTRUCTOR:
1221 return buildConstructor(element);
1222
1223 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY:
1224 return buildConstructorBody(element);
1225
1226 case ElementKind.FUNCTION:
1227 case ElementKind.GETTER:
1228 case ElementKind.SETTER:
1229 return buildFunction(element);
1230
1231 default:
1232 compiler.internalError(element, "Unexpected element type $element");
1233 }
1234 });
1235 }
1236
1237 /// Builds the IR for an [expression] taken from a different [context].
1238 ///
1239 /// Such expressions need to be compiled with a different [sourceFile] and
1240 /// [elements] mapping.
1241 ir.Primitive inlineExpression(AstElement context, ast.Expression expression) {
1242 JsIrBuilderVisitor visitor = new JsIrBuilderVisitor(
1243 context.resolvedAst.elements,
1244 compiler,
1245 elementSourceFile(context));
1246 return visitor.withBuilder(irBuilder, () => visitor.visit(expression));
1247 }
1248
1249 /// Builds the IR for a given constructor. The performs the following tasks:
floitsch 2015/01/21 16:29:35 Remove the part after the "." (It's pretty clear
asgerf 2015/01/22 10:18:57 Done.
1250 ///
1251 /// 1. Evaluate all own or inherited field initializers.
floitsch 2015/01/21 16:29:35 Evaluates
asgerf 2015/01/22 10:18:58 Done.
1252 /// 2. Create the object and assign its fields.
floitsch 2015/01/21 16:29:34 Creates ... assigns
asgerf 2015/01/22 10:18:58 Done.
1253 /// 3. Call constructor body and super constructor bodies.
floitsch 2015/01/21 16:29:35 Calls
asgerf 2015/01/22 10:18:57 Done.
1254 /// 4. Return the created object.
floitsch 2015/01/21 16:29:35 Returns
asgerf 2015/01/22 10:18:57 Done.
1255 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) {
1256 constructor = constructor.implementation;
1257 ClassElement classElement = constructor.enclosingClass.implementation;
1258
1259 JsIrBuilder builder =
1260 new JsIrBuilder(compiler.backend.constantSystem, constructor);
1261
1262 return withBuilder(builder, () {
1263 // Setup parameters and create a box if anything is captured.
1264 List<ParameterElement> parameters = [];
1265 constructor.functionSignature.orderedForEachParameter(parameters.add);
1266 builder.buildFunctionHeader(parameters,
1267 closureScope: getFunctionScope(constructor));
1268
1269 // -- Step 1: evaluate field initializers ---
1270 // Evaluate field initializers in constructor and super constructors.
1271 List<ConstructorElement> constructorList = <ConstructorElement>[];
1272 evaluateConstructorFieldInitializers(constructor, constructorList);
1273
1274 // All parameters in all constructors are now bound in the environment.
1275 // BoxLocals for captured parameters are also in the environment.
1276 // The initial value of all fields are now bound in [fieldValues].
1277
1278 // --- Step 2: create the object ---
1279 // Get the initial field values in the canonical order.
1280 List<ir.Primitive> instanceArguments = <ir.Primitive>[];
1281 classElement.forEachInstanceField((ClassElement _, FieldElement field) {
1282 ir.Primitive value = fieldValues[field];
1283 if (value != null) {
1284 instanceArguments.add(fieldValues[field]);
1285 } else {
1286 // Native fields are initialized elsewhere.
floitsch 2015/01/21 16:29:34 can we assert that the field comes from a native c
asgerf 2015/01/22 10:18:57 Done.
1287 }
1288 }, includeSuperAndInjectedMembers: true);
1289 ir.Primitive instance =
1290 new ir.CreateInstance(classElement, instanceArguments);
1291 irBuilder.add(new ir.LetPrim(instance));
1292
1293 // --- Step 3: call constructor bodies ---
1294 for (ConstructorElement target in constructorList) {
1295 ConstructorBodyElement bodyElement = getConstructorBody(target);
1296 if (bodyElement == null) continue;
floitsch 2015/01/21 16:29:34 Comment when this can happen. I'm guessing when t
asgerf 2015/01/22 10:18:58 Done.
1297 List<ir.Primitive> bodyArguments = <ir.Primitive>[];
1298 for (Local param in getConstructorBodyParameters(bodyElement)) {
1299 bodyArguments.add(irBuilder.environment.lookup(param));
1300 }
1301 irBuilder.buildInvokeDirectly(bodyElement, instance, bodyArguments);
1302 }
1303
1304 // --- step 4: return the created object ----
1305 irBuilder.buildReturn(instance);
1306
1307 return irBuilder.makeFunctionDefinition([]);
1308 });
1309 }
1310
1311 /// Evaluates all field initializers on [constructor] and all constructors
1312 /// invoked through `this()` or `super()` ("superconstructors").
1313 ///
1314 /// The resulting field values will be available in [fieldValues]. The values
1315 /// are not stored in any fields.
1316 ///
1317 /// This procedure assumes that the parameters to [constructor] are available
1318 /// in the IR builder's environment.
1319 ///
1320 /// The parameters to superconstructors are, however, assumed NOT to be in
floitsch 2015/01/21 16:29:35 *not*
asgerf 2015/01/22 10:18:58 Done.
1321 /// the environment, but will be put there by this procedure.
1322 ///
1323 /// All constructors will be added to [supers], with superconstructors first.
1324 void evaluateConstructorFieldInitializers(ConstructorElement constructor,
1325 List<ConstructorElement> supers) {
1326 // Evaluate declaration-site field initializers.
1327 ClassElement enclosingClass = constructor.enclosingClass.implementation;
1328 enclosingClass.forEachInstanceField((ClassElement _, FieldElement field) {
1329 if (field.initializer != null) {
1330 fieldValues[field] = inlineExpression(field, field.initializer);
1331 } else {
1332 if (Elements.isNativeOrExtendsNative(enclosingClass)) {
1333 // Native field is initialized elsewhere.
1334 } else {
1335 // Fields without an initializer default to null.
1336 // This value will be overwritten below if an initializer is found.
1337 fieldValues[field] = irBuilder.buildNullLiteral();
1338 }
1339 }
1340 });
1341 // Evaluate initializing parameters, e.g. `Foo(this.x)`.
1342 constructor.functionSignature.orderedForEachParameter(
1343 (ParameterElement parameter) {
1344 if (parameter.isInitializingFormal) {
1345 InitializingFormalElement fieldParameter = parameter;
1346 fieldValues[fieldParameter.fieldElement] =
1347 irBuilder.buildLocalGet(parameter);
1348 }
1349 });
1350 // Evaluate constructor initializers, e.g. `Foo() : x = 50`.
1351 ast.FunctionExpression node = constructor.node;
1352 bool hasConstructorCall = false; // Has this() or super() initializer?
1353 if (node != null && node.initializers != null) {
1354 for(ast.Node initializer in node.initializers) {
1355 if (initializer is ast.SendSet) {
1356 // Field initializer.
1357 FieldElement field = elements[initializer];
1358 fieldValues[field] =
1359 inlineExpression(constructor, initializer.arguments.head);
1360 } else if (initializer is ast.Send) {
1361 // Super or this initializer.
1362 ConstructorElement target = elements[initializer].implementation;
1363 Selector selector = elements.getSelector(initializer);
1364 List<ir.Primitive> arguments = initializer.arguments.mapToList(visit);
1365 loadArguments(target, selector, arguments);
1366 evaluateConstructorFieldInitializers(target, supers);
1367 hasConstructorCall = true;
1368 } else {
1369 compiler.internalError(initializer,
1370 "Unexpected initializer type $initializer");
1371 }
1372 }
1373 }
1374 // If no super() or this() was found, also call default superconstructor.
1375 if (!hasConstructorCall && !enclosingClass.isObject) {
1376 ClassElement superClass = enclosingClass.superclass;
1377 Selector selector =
1378 new Selector.callDefaultConstructor(enclosingClass.library);
1379 FunctionElement target = superClass.lookupConstructor(selector);
1380 if (target == null) {
1381 compiler.internalError(superClass, "No default constructor available.");
1382 }
1383 evaluateConstructorFieldInitializers(target, supers);
1384 }
1385 // Add this constructor after the superconstructors.
1386 supers.add(constructor);
1387 }
1388
1389 /// In preparation of inlining (part of) [target], the [arguments] are moved
1390 /// into the environment bindings for the corresponding parameters.
1391 ///
1392 /// Defaults for optional arguments are evaluated in order to ensure
1393 /// all parameters are available in the environment.
1394 void loadArguments(FunctionElement target,
1395 Selector selector,
1396 List<ir.Primitive> arguments) {
1397 target = target.implementation;
1398 FunctionSignature signature = target.functionSignature;
1399
1400 // Establish a scope in case parameters are captured.
1401 ClosureScope scope = getFunctionScope(target);
1402 irBuilder._enterScope(scope);
1403
1404 // Load required parameters
1405 int index = 0;
1406 signature.forEachRequiredParameter((ParameterElement param) {
1407 irBuilder.declareLocalVariable(param, initialValue: arguments[index]);
1408 ++index;
floitsch 2015/01/21 16:29:34 tiny nit: we generally use index++.
asgerf 2015/01/22 10:18:58 I prefer that too, but have been told the exact op
1409 });
1410
1411 // Load optional parameters, evaluating default values for omitted ones.
1412 signature.forEachOptionalParameter((ParameterElement param) {
1413 ir.Primitive value;
1414 // Load argument if provided.
1415 if (signature.optionalParametersAreNamed) {
1416 int translatedIndex = selector.namedArguments.indexOf(param.name);
1417 if (translatedIndex != -1) {
1418 value = arguments[translatedIndex];
1419 }
1420 } else if (index < arguments.length) {
1421 value = arguments[index];
1422 }
1423 // Load default if argument was not provided.
1424 if (value == null) {
1425 if (param.initializer != null) {
1426 value = visit(param.initializer);
1427 } else {
1428 value = irBuilder.buildNullLiteral();
1429 }
1430 }
1431 irBuilder.declareLocalVariable(param, initialValue: value);
1432 ++index;
floitsch 2015/01/21 16:29:34 ditto.
asgerf 2015/01/22 10:18:57 Done.
1433 });
1434 }
1435
1436 /**
1437 * Returns the constructor body associated with the given constructor or
1438 * creates a new constructor body, if none can be found.
1439 *
1440 * Returns `null` if the constructor does not have a body.
1441 */
1442 ConstructorBodyElement getConstructorBody(FunctionElement constructor) {
1443 // TODO(asgerf): This is largely inherited from the SSA builder.
1444 // The ConstructorBodyElement has an invalid function signature, but we
1445 // cannot add a BoxLocal as parameter, because BoxLocal is not an element.
1446 // Instead of forging ParameterElements to forge a FunctionSignature, we
1447 // need a way to create backend methods without creating more fake elements.
1448
1449 assert(constructor.isGenerativeConstructor);
1450 assert(invariant(constructor, constructor.isImplementation));
1451 if (constructor.isSynthesized) return null;
1452 ast.FunctionExpression node = constructor.node;
1453 // If we know the body doesn't have any code, we don't generate it.
1454 if (!node.hasBody()) return null;
1455 if (node.hasEmptyBody()) return null;
1456 ClassElement classElement = constructor.enclosingClass;
1457 ConstructorBodyElement bodyElement;
1458 classElement.forEachBackendMember((Element backendMember) {
1459 if (backendMember.isGenerativeConstructorBody) {
1460 ConstructorBodyElement body = backendMember;
1461 if (body.constructor == constructor) {
1462 bodyElement = backendMember;
1463 }
1464 }
1465 });
1466 if (bodyElement == null) {
1467 List<Local> parameters = getConstructorBodyParameters(constructor);
floitsch 2015/01/21 16:29:34 leftover? getConstructorBodyParameters shouldn't
asgerf 2015/01/22 10:18:57 You are right, it was a leftover (I previously sto
1468
1469 bodyElement = new ConstructorBodyElementX(constructor);
1470 classElement.addBackendMember(bodyElement);
1471
1472 if (constructor.isPatch) {
1473 // Create origin body element for patched constructors.
1474 ConstructorBodyElementX patch = bodyElement;
1475 ConstructorBodyElementX origin =
1476 new ConstructorBodyElementX(constructor.origin);
1477 origin.applyPatch(patch);
1478 classElement.origin.addBackendMember(bodyElement.origin);
1479 }
1480 }
1481 assert(bodyElement.isGenerativeConstructorBody);
1482 return bodyElement;
1483 }
1484
1485 /// The list of parameters to send from the generative constructor
1486 /// to the generative constructor body.
floitsch 2015/01/21 16:29:34 Maybe add note that the returned list may contain
asgerf 2015/01/22 10:18:57 Done. I also changed the parameter to Constructor
1487 List<Local> getConstructorBodyParameters(FunctionElement constructor) {
1488 List<Local> parameters = <Local>[];
1489 ClosureScope scope = getFunctionScope(constructor);
1490 if (scope != null) {
1491 parameters.add(scope.box);
1492 }
1493 constructor.functionSignature.orderedForEachParameter(
1494 (ParameterElement param) {
1495 if (scope != null && scope.capturedVariables.containsKey(param)) {
1496 // Do not pass this parameter; the box will carry its value.
1497 } else {
1498 parameters.add(param);
1499 }
1500 });
1501 return parameters;
1502 }
1503
1504 /// Builds the IR for the body of a constructor.
1505 ///
1506 /// This function is invoked from one or more "factory" constructors built by
1507 /// [buildConstructor].
1508 ir.FunctionDefinition buildConstructorBody(ConstructorBodyElement body) {
1509 ConstructorElement constructor = body.constructor;
1510 ast.FunctionExpression node = constructor.node;
1511 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
1512 constructor,
1513 node,
1514 elements);
1515
1516 JsIrBuilder builder = new JsIrBuilder(
floitsch 2015/01/21 16:29:35 nit: I prefer not to break expressions: JsIrBuild
asgerf 2015/01/22 10:18:57 Done.
1517 compiler.backend.constantSystem, body);
1518
1519 return withBuilder(builder, () {
1520 irBuilder.buildConstructorBodyHeader(getConstructorBodyParameters(body),
1521 getClosureScope(node));
1522 visit(node.body);
1523 return irBuilder.makeFunctionDefinition([]);
1524 });
1525 }
1526
1527 ir.FunctionDefinition buildFunction(FunctionElement element) {
1528 assert(invariant(element, element.isImplementation));
1529 ast.FunctionExpression node = element.node;
1530
1531 assert(!element.isSynthesized);
1532 assert(node != null);
1533 assert(elements[node] != null);
1534
1535 IrBuilder builder = makeIRBuilder(node, element);
1536 return withBuilder(builder, () => _makeFunctionBody(element, node));
1537 }
1538
1539 }
1540
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698