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

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: Removed obsolete TODO 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 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 ir.Primitive receiver; 99 ir.Primitive receiver;
98 100
99 _GetterElements({this.result, this.index, this.receiver}) ; 101 _GetterElements({this.result, this.index, this.receiver}) ;
100 } 102 }
101 103
102 /** 104 /**
103 * A tree visitor that builds [IrNodes]. The visit methods add statements using 105 * 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 106 * to the [builder] and return the last added statement for trees that represent
105 * an expression. 107 * an expression.
106 */ 108 */
107 class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive> 109 abstract class IrBuilderVisitor extends ResolvedVisitor<ir.Primitive>
108 with IrBuilderMixin<ast.Node> { 110 with IrBuilderMixin<ast.Node> {
109 final Compiler compiler; 111 final Compiler compiler;
110 final SourceFile sourceFile; 112 final SourceFile sourceFile;
111 ClosureClassMap closureMap;
112 113
113 // In SSA terms, join-point continuation parameters are the phis and the 114 // In SSA terms, join-point continuation parameters are the phis and the
114 // continuation invocation arguments are the corresponding phi inputs. To 115 // continuation invocation arguments are the corresponding phi inputs. To
115 // support name introduction and renaming for source level variables, we use 116 // support name introduction and renaming for source level variables, we use
116 // nested (delimited) visitors for constructing subparts of the IR that will 117 // nested (delimited) visitors for constructing subparts of the IR that will
117 // need renaming. Each source variable is assigned an index. 118 // need renaming. Each source variable is assigned an index.
118 // 119 //
119 // Each nested visitor maintains a list of free variable uses in the body. 120 // 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 121 // 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 122 // list of references. When the delimited subexpression is plugged into the
122 // surrounding context, the free occurrences can be captured or become free 123 // surrounding context, the free occurrences can be captured or become free
123 // occurrences in the next outer delimited subexpression. 124 // occurrences in the next outer delimited subexpression.
124 // 125 //
125 // Each nested visitor maintains a list that maps indexes of variables 126 // Each nested visitor maintains a list that maps indexes of variables
126 // assigned in the delimited subexpression to their reaching definition --- 127 // assigned in the delimited subexpression to their reaching definition ---
127 // that is, the definition in effect at the hole in 'current'. These are 128 // 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 129 // used to determine if a join-point continuation needs to be passed
129 // arguments, and what the arguments are. 130 // arguments, and what the arguments are.
130 131
131 /// Construct a top-level visitor. 132 /// Construct a top-level visitor.
132 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile) 133 IrBuilderVisitor(TreeElements elements, this.compiler, this.sourceFile)
133 : super(elements); 134 : super(elements);
134 135
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 /** 136 /**
140 * Builds the [ir.ExecutableDefinition] for an executable element. In case the 137 * Builds the [ir.ExecutableDefinition] for an executable element. In case the
141 * function uses features that cannot be expressed in the IR, this element 138 * function uses features that cannot be expressed in the IR, this element
142 * returns `null`. 139 * returns `null`.
143 */ 140 */
144 ir.ExecutableDefinition buildExecutable(ExecutableElement element) { 141 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 142
156 Map mapValues(Map map, dynamic fn(dynamic)) { 143 ClosureScope getClosureScope(ast.Node node);
157 Map result = {}; 144 ClosureEnvironment getClosureEnvironment();
158 map.forEach((key,value) {
159 result[key] = fn(value);
160 });
161 return result;
162 }
163 145
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 146
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 147
249 ir.FunctionDefinition _makeFunctionBody(FunctionElement element, 148 ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
250 ast.FunctionExpression node) { 149 ast.FunctionExpression node) {
251 FunctionSignature signature = element.functionSignature; 150 FunctionSignature signature = element.functionSignature;
252 List<ParameterElement> parameters = []; 151 List<ParameterElement> parameters = [];
253 signature.orderedForEachParameter(parameters.add); 152 signature.orderedForEachParameter(parameters.add);
254 153
255 irBuilder.buildFunctionHeader(parameters, 154 irBuilder.buildFunctionHeader(parameters,
256 closureScope: getClosureScope(node), 155 closureScope: getClosureScope(node),
257 closureEnvironment: getClosureEnvironment()); 156 closureEnvironment: getClosureEnvironment());
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 "No default constructor available."); 244 "No default constructor available.");
346 } 245 }
347 result.add(irBuilder.makeSuperInitializer(target, 246 result.add(irBuilder.makeSuperInitializer(target,
348 <ir.RunnableBody>[], 247 <ir.RunnableBody>[],
349 selector)); 248 selector));
350 } 249 }
351 } 250 }
352 return result; 251 return result;
353 } 252 }
354 253
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); 254 ir.Primitive visit(ast.Node node) => node.accept(this);
378 255
379 // ==== Statements ==== 256 // ==== Statements ====
380 visitBlock(ast.Block node) { 257 visitBlock(ast.Block node) {
381 irBuilder.buildBlock(node.statements.nodes, build); 258 irBuilder.buildBlock(node.statements.nodes, build);
382 } 259 }
383 260
384 ir.Primitive visitBreakStatement(ast.BreakStatement node) { 261 ir.Primitive visitBreakStatement(ast.BreakStatement node) {
385 if (!irBuilder.buildBreak(elements.getTargetOf(node))) { 262 if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
386 compiler.internalError(node, "'break' target not found"); 263 compiler.internalError(node, "'break' target not found");
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after
1011 } 888 }
1012 889
1013 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) { 890 ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) {
1014 assert(irBuilder.isOpen); 891 assert(irBuilder.isOpen);
1015 if (constant == null) { 892 if (constant == null) {
1016 constant = getConstantForNode(node); 893 constant = getConstantForNode(node);
1017 } 894 }
1018 return irBuilder.buildConstantLiteral(constant); 895 return irBuilder.buildConstantLiteral(constant);
1019 } 896 }
1020 897
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()) { 898 ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) {
1049 try { 899 try {
1050 return action(); 900 return action();
1051 } catch(e, tr) { 901 } catch(e, tr) {
1052 if (e == ABORT_IRNODE_BUILDER) { 902 if (e == ABORT_IRNODE_BUILDER) {
1053 return null; 903 return null;
1054 } 904 }
1055 rethrow; 905 rethrow;
1056 } 906 }
1057 } 907 }
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1151 currentFunction = elements[node]; 1001 currentFunction = elements[node];
1152 if (node.initializers != null) { 1002 if (node.initializers != null) {
1153 insideInitializer = true; 1003 insideInitializer = true;
1154 visit(node.initializers); 1004 visit(node.initializers);
1155 insideInitializer = false; 1005 insideInitializer = false;
1156 } 1006 }
1157 visit(node.body); 1007 visit(node.body);
1158 currentFunction = oldFunction; 1008 currentFunction = oldFunction;
1159 } 1009 }
1160 } 1010 }
1011
1012 /// IR builder specific to the Dart backend, coupled to the [DartIrBuilder].
1013 class DartIrBuilderVisitor extends IrBuilderVisitor {
1014 /// Promote the type of [irBuilder] to [DartIrBuilder].
1015 DartIrBuilder get irBuilder => super.irBuilder;
1016
1017 DartIrBuilderVisitor(TreeElements elements,
1018 Compiler compiler,
1019 SourceFile sourceFile)
1020 : super(elements, compiler, sourceFile);
1021
1022 DartIrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
1023 DetectClosureVariables closures = new DetectClosureVariables(elements);
1024 if (!element.isSynthesized) {
1025 closures.visit(node);
1026 }
1027 return new DartIrBuilder(compiler.backend.constantSystem,
1028 element,
1029 closures);
1030 }
1031
1032 /// Returns the backend-specific representation of an inner function.
floitsch 2015/01/20 17:26:27 That comment can be updated.
1033 ir.FunctionDefinition makeSubFunction(ast.FunctionExpression node) {
1034 FunctionElement element = elements[node];
1035 assert(invariant(element, element.isImplementation));
1036
1037 IrBuilder builder = irBuilder.makeInnerFunctionBuilder(element);
1038
1039 return withBuilder(builder, () => _makeFunctionBody(element, node));
1040 }
1041
1042 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
1043 return irBuilder.buildFunctionExpression(makeSubFunction(node));
1044 }
1045
1046 visitFunctionDeclaration(ast.FunctionDeclaration node) {
1047 LocalFunctionElement element = elements[node.function];
1048 Object inner = makeSubFunction(node.function);
1049 irBuilder.declareLocalFunction(element, inner);
1050 }
1051
1052 ClosureScope getClosureScope(ast.Node node) => null;
1053 ClosureEnvironment getClosureEnvironment() => null;
1054
1055 ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
1056 return nullIfGiveup(() {
1057 if (element is FieldElement) {
1058 return buildField(element);
1059 } else if (element is FunctionElement) {
1060 return buildFunction(element);
1061 } else {
1062 compiler.internalError(element, "Unexpected element type $element");
1063 }
1064 });
1065 }
1066
1067 /// Returns a [ir.FieldDefinition] describing the initializer of [element].
1068 ir.FieldDefinition buildField(FieldElement element) {
1069 assert(invariant(element, element.isImplementation));
1070 ast.VariableDefinitions definitions = element.node;
1071 ast.Node fieldDefinition =
floitsch 2015/01/20 17:26:27 should fit on one line, no?
1072 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 JsIrBuilderVisitor(TreeElements elements,
1120 Compiler compiler,
1121 SourceFile sourceFile)
1122 : super(elements, compiler, sourceFile);
1123
1124 JsIrBuilder makeIRBuilder(ast.Node node, ExecutableElement element) {
1125 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
1126 element,
1127 node,
1128 elements);
1129 return new JsIrBuilder(compiler.backend.constantSystem, element);
1130 }
1131
1132 /// Returns the backend-specific representation of an inner function.
floitsch 2015/01/20 17:26:27 Update comment.
1133 ClosureClassElement makeSubFunction(ast.FunctionExpression node) {
1134 ClosureClassMap innerMap =
1135 compiler.closureToClassMapper.getMappingForNestedFunction(node);
1136 ClosureClassElement closureClass = innerMap.closureClassElement;
1137 return closureClass;
1138 }
1139
1140 ir.Primitive visitFunctionExpression(ast.FunctionExpression node) {
1141 return irBuilder.buildFunctionExpression(makeSubFunction(node));
1142 }
1143
1144 visitFunctionDeclaration(ast.FunctionDeclaration node) {
1145 LocalFunctionElement element = elements[node.function];
1146 Object inner = makeSubFunction(node.function);
1147 irBuilder.declareLocalFunction(element, inner);
1148 }
1149
1150 Map mapValues(Map map, dynamic fn(dynamic)) {
1151 Map result = {};
1152 map.forEach((key,value) {
1153 result[key] = fn(value);
1154 });
1155 return result;
1156 }
1157
1158 // Converts closure.dart's CapturedVariable into a ClosureLocation.
floitsch 2015/01/20 17:26:27 Make a dartdoc.
1159 // There is a 1:1 corresponce between these; we do this because the IR builder
1160 // should not depend on synthetic elements.
1161 ClosureLocation getLocation(CapturedVariable v) {
1162 if (v is BoxFieldElement) {
1163 return new ClosureLocation(v.box, v);
1164 } else {
1165 ClosureFieldElement field = v;
1166 return new ClosureLocation(null, field);
1167 }
1168 }
1169
1170 /// If the current function is a nested function with free variables (or a
1171 /// captured reference to `this`), this returns a [ClosureEnvironment]
1172 /// indicating how to access these.
1173 ClosureEnvironment getClosureEnvironment() {
1174 if (closureMap.closureElement == null) return null;
1175 return new ClosureEnvironment(
1176 closureMap.closureElement,
1177 closureMap.thisLocal,
1178 mapValues(closureMap.freeVariableMap, getLocation));
1179 }
1180
1181 /// If [node] has declarations for variables that should be boxed, this
1182 /// returns a [ClosureScope] naming a box to create, and enumerating the
1183 /// variables that should be stored in the box.
1184 ///
1185 /// Also see [ClosureScope].
1186 ClosureScope getClosureScope(ast.Node node) {
1187 closurelib.ClosureScope scope = closureMap.capturingScopes[node];
1188 if (scope == null) return null;
1189 // We translate a ClosureScope from closure.dart into IR builder's variant
1190 // because the IR builder should not depend on the synthetic elements
1191 // created in closure.dart.
1192 return new ClosureScope(scope.boxElement,
1193 mapValues(scope.capturedVariables, getLocation),
1194 scope.boxedLoopVariables);
1195 }
1196
1197 /// Returns the [ClosureScope] for any function, possibly different from the
1198 /// one currently being built.
1199 ClosureScope getFunctionScope(FunctionElement function) {
1200 ClosureClassMap map =
1201 compiler.closureToClassMapper.computeClosureToClassMapping(
1202 function,
1203 function.node,
1204 elements);
1205 closurelib.ClosureScope scope = map.capturingScopes[function.node];
1206 if (scope == null) return null;
1207 return new ClosureScope(scope.boxElement,
1208 mapValues(scope.capturedVariables, getLocation),
1209 scope.boxedLoopVariables);
1210 }
1211
1212 ir.ExecutableDefinition buildExecutable(ExecutableElement element) {
1213 return nullIfGiveup(() {
1214 switch (element.kind) {
1215 case ElementKind.GENERATIVE_CONSTRUCTOR:
1216 return buildConstructor(element);
1217
1218 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY:
1219 return buildConstructorBody(element);
1220
1221 case ElementKind.FUNCTION:
1222 case ElementKind.GETTER:
1223 case ElementKind.SETTER:
1224 return buildFunction(element);
1225
1226 default:
1227 compiler.internalError(element, "Unexpected element type $element");
1228 }
1229 });
1230 }
1231
1232 /// During construction of a constructor factory, [fieldValues] maps fields
floitsch 2015/01/20 17:26:27 Move it up to the locals.
1233 /// to the primitive containing their initial value.
1234 Map<FieldElement, ir.Primitive> fieldValues = {};
floitsch 2015/01/20 17:26:27 type the map.
1235
1236 /// Builds the IR for a given constructor. The performs the following tasks:
1237 ///
1238 /// 1. Evaluate all own or inherited field initializers.
1239 /// 2. Create the object and assign its fields.
1240 /// 3. Call constructor body and super constructor bodies.
1241 /// 4. Return the created object.
1242 ir.FunctionDefinition buildConstructor(ConstructorElement constructor) {
1243 constructor = constructor.implementation;
1244 ClassElement classElement = constructor.enclosingClass.implementation;
1245
1246 closureMap = compiler.closureToClassMapper.computeClosureToClassMapping(
1247 constructor,
1248 constructor.node,
1249 elements);
1250 ClosureScope closureScope = getClosureScope(constructor.node);
1251
1252 JsIrBuilder builder =
1253 new JsIrBuilder(compiler.backend.constantSystem, constructor);
1254
1255 return withBuilder(builder, () {
1256 // Setup parameters and create a box if anything is captured.
1257 List<ParameterElement> parameters = [];
1258 constructor.functionSignature.orderedForEachParameter(parameters.add);
1259 List<ir.Primitive> constructorParams =
1260 builder.buildFunctionHeader(parameters, closureScope: closureScope);
1261
1262 // -- Step 1: evaluate field initializers ---
1263 // Evaluate all initializers on from field declarations.
floitsch 2015/01/20 17:26:27 -on-
1264 // For some reason, these should ALL be evaluated first, even before
floitsch 2015/01/20 17:26:27 I'm pretty sure this is not true. I tried it with
asgerf 2015/01/21 09:55:58 You are right. The SSA builder had me confused, an
1265 // field initializer lists from super constructors.
1266 classElement.forEachInstanceField(
1267 (ClassElement classElement, FieldElement field) {
1268 if (compiler.elementHasCompileTimeError(field)) return;
1269 if (field.initializer != null) {
1270 fieldValues[field] = visit(field.initializer);
1271 } else {
1272 if (Elements.isNativeOrExtendsNative(classElement)) {
1273 // Native field is initialized elsewhere.
1274 } else {
1275 // Fields without an initializer default to null.
1276 // This value will be overwritten later if an initializer
1277 // is found on one of the constructors.
1278 fieldValues[field] = irBuilder.buildNullLiteral();
1279 }
1280 }
1281 }, includeSuperAndInjectedMembers: true);
1282
1283 // Evaluate field initializers in constructor and super constructors.
1284 List<ConstructorElement> constructorList = <ConstructorElement>[];
1285 evaluateConstructorFieldInitializers(constructor, constructorList);
1286
1287 // All parameters in all constructors are now bound in the environment.
1288 // BoxLocals for captured parameters are also in the environment.
1289 // The initial value of all fields are now bound in [fieldValues].
1290
1291 // --- Step 2: create the object ---
1292 // Get the initial field values in the canonical order.
1293 List<ir.Primitive> instanceArguments = <ir.Primitive>[];
1294 classElement.forEachInstanceField(
1295 (ClassElement classElement, FieldElement field) {
1296 ir.Primitive value = fieldValues[field];
1297 if (value != null) {
1298 instanceArguments.add(fieldValues[field]);
1299 } else {
1300 // Native fields are initialized elsewhere.
1301 }
1302 }, includeSuperAndInjectedMembers: true);
1303 ir.Primitive instance =
1304 new ir.CreateInstance(classElement, instanceArguments);
1305 irBuilder.add(new ir.LetPrim(instance));
1306
1307 // --- Step 3: call constructor bodies ---
1308 for (ConstructorElement target in constructorList) {
1309 ConstructorBodyElement bodyElement = getConstructorBody(target);
1310 if (bodyElement == null) continue;
1311 List<ir.Primitive> bodyArguments = <ir.Primitive>[];
1312 for (Local param in getConstructorBodyParameters(bodyElement)) {
1313 bodyArguments.add(irBuilder.environment.lookup(param));
1314 }
1315 irBuilder.buildInvokeDirectly(bodyElement, instance, bodyArguments);
1316 }
1317
1318 // --- step 4: return the created object ----
1319 irBuilder.buildReturn(instance);
1320
1321 return irBuilder.makeFunctionDefinition([]);
1322 });
1323 }
1324
1325 /// Evaluates all field initializers on [constructor] and all constructors
1326 /// invoked through `this()` or `super()` ("superconstructors").
1327 ///
1328 /// The resulting field values will be available in [fieldValues]. The values
1329 /// are not stored in any fields.
1330 ///
1331 /// This procedure assumes that the parameters to [constructor] are available
1332 /// in the IR builder's environment.
1333 ///
1334 /// The parameters to superconstructors are, however, assumed NOT to be in
1335 /// the environment, but will be put there by this procedure.
1336 ///
1337 /// All constructors will be added to [supers], with superconstructors first.
1338 void evaluateConstructorFieldInitializers(ConstructorElement constructor,
1339 List<ConstructorElement> supers) {
1340 // Evaluate initializing parameters, e.g. `Foo(this.x)`.
1341 constructor.functionSignature.orderedForEachParameter(
1342 (ParameterElement parameter) {
1343 if (parameter.isInitializingFormal) {
1344 InitializingFormalElement fieldParameter = parameter;
1345 fieldValues[fieldParameter.fieldElement] =
1346 irBuilder.buildLocalGet(parameter);
1347 }
1348 });
1349 // Evaluate constructor initializers, e.g. `Foo() : x = 50`.
1350 ast.FunctionExpression node = constructor.node;
1351 bool hasConstructorCall = false; // Has this() or super() initializer?
1352 if (node != null && node.initializers != null) {
1353 for(ast.Node initializer in node.initializers) {
1354 if (initializer is ast.SendSet) {
1355 // Field initializer.
1356 FieldElement field = elements[initializer];
1357 fieldValues[field] = visit(initializer.arguments.head);
1358 } else if (initializer is ast.Send) {
1359 // Super or this initializer.
1360 ConstructorElement target = elements[initializer].implementation;
1361 Selector selector = elements.getSelector(initializer);
1362 List<ir.Primitive> arguments =
1363 initializer.arguments.mapToList(visit);
1364 loadArguments(target, selector, arguments);
1365 evaluateConstructorFieldInitializers(target, supers);
1366 hasConstructorCall = true;
1367 } else {
1368 compiler.internalError(initializer,
1369 "Unexpected initializer type $initializer");
1370 }
1371 }
1372 }
1373 // If no super() or this() was found, also call default superconstructor.
1374 ClassElement enclosingClass = constructor.enclosingClass.implementation;
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;
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;
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.
floitsch 2015/01/20 17:26:27 `null`
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);
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.
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(
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