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

Side by Side Diff: pkg/fletchc/lib/src/constructor_codegen.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 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
« no previous file with comments | « pkg/fletchc/lib/src/console_print.dart ('k') | pkg/fletchc/lib/src/debug_info.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
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.md file.
4
5 library fletchc.constructor_codegen;
6
7 import 'package:compiler/src/elements/elements.dart';
8 import 'package:compiler/src/resolution/tree_elements.dart' show
9 TreeElements;
10 import 'package:compiler/src/tree/tree.dart';
11 import 'package:compiler/src/universe/call_structure.dart' show
12 CallStructure;
13 import 'package:compiler/src/dart_types.dart';
14
15 import 'fletch_context.dart';
16
17 import 'fletch_function_builder.dart' show
18 FletchFunctionBuilder;
19
20 import 'fletch_class_builder.dart' show
21 FletchClassBuilder;
22
23 import 'closure_environment.dart';
24
25 import 'lazy_field_initializer_codegen.dart';
26
27 import 'codegen_visitor.dart';
28
29 import 'fletch_registry.dart' show
30 FletchRegistry;
31
32 class ConstructorCodegen extends CodegenVisitor with FletchRegistryMixin {
33 final FletchRegistry registry;
34
35 final FletchClassBuilder classBuilder;
36
37 final Map<FieldElement, LocalValue> fieldScope = <FieldElement, LocalValue>{};
38
39 final List<ConstructorElement> constructors = <ConstructorElement>[];
40
41 ClosureEnvironment initializerClosureEnvironment;
42
43 ConstructorCodegen(FletchFunctionBuilder functionBuilder,
44 FletchContext context,
45 TreeElements elements,
46 this.registry,
47 ClosureEnvironment closureEnvironment,
48 ConstructorElement constructor,
49 this.classBuilder)
50 : super(functionBuilder, context, elements,
51 closureEnvironment, constructor);
52
53 ConstructorElement get constructor => element;
54
55 BytecodeAssembler get assembler => functionBuilder.assembler;
56
57 ClosureEnvironment get closureEnvironment {
58 if (initializerClosureEnvironment != null) {
59 return initializerClosureEnvironment;
60 }
61 return super.closureEnvironment;
62 }
63
64 void compile() {
65 // Push all initial field values (including super-classes).
66 pushInitialFieldValues(classBuilder);
67 // The stack is now:
68 // Value for field-0
69 // ...
70 // Value for field-n
71 //
72 FunctionSignature signature = constructor.functionSignature;
73 int parameterCount = signature.parameterCount;
74
75 // Visit constructor and evaluate initializers and super calls. The
76 // arguments to the constructor are located before the return address.
77 inlineInitializers(constructor, -parameterCount - 1);
78
79 handleAllocationAndBodyCall();
80 }
81
82 LazyFieldInitializerCodegen lazyFieldInitializerCodegenFor(
83 FletchFunctionBuilder function,
84 FieldElement field) {
85 TreeElements elements = field.resolvedAst.elements;
86 return new LazyFieldInitializerCodegen(
87 function,
88 context,
89 elements,
90 registry,
91 context.backend.createClosureEnvironment(field, elements),
92 field);
93 }
94
95 void handleAllocationAndBodyCall() {
96 // TODO(ajohnsen): Let allocate take an offset to the field stack, so we
97 // don't have to copy all the fields?
98 // Copy all the fields to the end of the stack.
99 int fields = classBuilder.fields;
100 for (int i = 0; i < fields; i++) {
101 assembler.loadSlot(i);
102 }
103
104 // The stack is now:
105 // Value for field-0
106 // ...
107 // Value for field-n
108 // [super arguments]
109 // Value for field-0
110 // ...
111 // Value for field-n
112
113 // Create the actual instance.
114 int classConstant = functionBuilder.allocateConstantFromClass(
115 classBuilder.classId);
116 // TODO(ajohnsen): Set immutable for all-final classes.
117 assembler.allocate(classConstant, fields, immutable: element.isConst);
118
119 // The stack is now:
120 // Value for field-0
121 // ...
122 // Value for field-n
123 // [super arguments]
124 // instance
125
126 // Call constructor bodies in reverse order.
127 for (int i = constructors.length - 1; i >= 0; i--) {
128 callConstructorBody(constructors[i]);
129 }
130
131 // Return the instance.
132 assembler
133 ..ret()
134 ..methodEnd();
135 }
136
137 /**
138 * Visit [constructor] and inline initializers and super calls, recursively.
139 */
140 void inlineInitializers(
141 ConstructorElement constructor,
142 int firstParameterSlot) {
143 if (checkCompileError(constructor) ||
144 checkCompileError(constructor.enclosingClass)) {
145 return;
146 }
147
148 if (constructors.indexOf(constructor) >= 0) {
149 internalError(constructor.node,
150 "Multiple visits to the same constructor");
151 }
152
153 if (constructor.isSynthesized) {
154 // If the constructor is implicit, invoke the defining constructor.
155 if (constructor.functionSignature.parameterCount == 0) {
156 ConstructorElement defining = constructor.definingConstructor;
157 int initSlot = assembler.stackSize;
158 loadArguments(defining, new NodeList.empty(), CallStructure.NO_ARGS);
159 inlineInitializers(defining, initSlot);
160 return;
161 }
162
163 // Otherwise the constructor is synthesized in the context of mixin
164 // applications, use the defining constructor.
165 do {
166 constructor = constructor.definingConstructor;
167 } while (constructor.isSynthesized);
168 }
169
170 constructors.add(constructor);
171 FunctionSignature signature = constructor.functionSignature;
172 int parameterIndex = 0;
173
174 initializerElements = constructor.resolvedAst.elements;
175 initializerClosureEnvironment = context.backend.createClosureEnvironment(
176 constructor, initializerElements);
177
178 // Visit parameters and add them to scope. Note the scope is the scope of
179 // locals, in VisitingCodegen.
180 signature.orderedForEachParameter((ParameterElement parameter) {
181 LocalValue value = firstParameterSlot < 0
182 ? createLocalValueForParameter(
183 parameter,
184 parameterIndex,
185 isCapturedValueBoxed: false)
186 : createLocalValueFor(
187 parameter,
188 slot: firstParameterSlot + parameterIndex,
189 isCapturedValueBoxed: false);
190 scope[parameter] = value;
191 if (parameter.isInitializingFormal) {
192 // If it's a initializing formal, store the value into initial
193 // field value.
194 InitializingFormalElement formal = parameter;
195 value.load(assembler);
196 fieldScope[formal.fieldElement].store(assembler);
197 assembler.pop();
198 }
199 parameterIndex++;
200 });
201
202 visitInitializers(constructor.node, null);
203 }
204
205 void doFieldInitializerSet(Send node, FieldElement field) {
206 fieldScope[field].store(assembler);
207 applyVisitState();
208 }
209
210 // This is called for each initializer list assignment.
211 void visitFieldInitializer(
212 SendSet node,
213 FieldElement field,
214 Node initializer,
215 _) {
216 // We only want the value of the actual initializer, not the usual
217 // 'body'.
218 visitForValue(initializer);
219 doFieldInitializerSet(node, field);
220 }
221
222 void visitSuperConstructorInvoke(
223 Send node,
224 ConstructorElement superConstructor,
225 InterfaceType type,
226 NodeList arguments,
227 CallStructure callStructure,
228 _) {
229 // Load all parameters to the constructor, onto the stack.
230 loadArguments(superConstructor, arguments, callStructure);
231 int initSlot = assembler.stackSize -
232 superConstructor.functionSignature.parameterCount;
233 var previousElements = initializerElements;
234 var previousClosureEnvironment = initializerClosureEnvironment;
235 inlineInitializers(superConstructor, initSlot);
236 initializerElements = previousElements;
237 initializerClosureEnvironment = previousClosureEnvironment;
238 }
239
240 void visitThisConstructorInvoke(
241 Send node,
242 ConstructorElement thisConstructor,
243 NodeList arguments,
244 CallStructure callStructure,
245 _) {
246 // TODO(ajohnsen): Is this correct behavior?
247 thisConstructor = thisConstructor.implementation;
248 // Load all parameters to the constructor, onto the stack.
249 loadArguments(thisConstructor, arguments, callStructure);
250 int initSlot = assembler.stackSize -
251 thisConstructor.functionSignature.parameterCount;
252 inlineInitializers(thisConstructor, initSlot);
253 }
254
255 void visitImplicitSuperConstructorInvoke(
256 FunctionExpression node,
257 ConstructorElement superConstructor,
258 InterfaceType type,
259 _) {
260 int initSlot = assembler.stackSize;
261 // Always load arguments, as the super-constructor may have optional
262 // parameters.
263 loadArguments(
264 superConstructor, new NodeList.empty(), CallStructure.NO_ARGS);
265 inlineInitializers(superConstructor, initSlot);
266 }
267
268 /**
269 * Load the [arguments] for caling [constructor].
270 *
271 * Return the number of arguments pushed onto the stack.
272 */
273 int loadArguments(
274 ConstructorElement constructor,
275 NodeList arguments,
276 CallStructure callStructure) {
277 FunctionSignature signature = constructor.functionSignature;
278 if (!signature.hasOptionalParameters ||
279 !signature.optionalParametersAreNamed ||
280 callStructure.namedArgumentCount == 0) {
281 return loadPositionalArguments(arguments, signature, constructor.name);
282 }
283
284 int argumentCount = callStructure.argumentCount;
285 int namedArgumentCount = callStructure.namedArgumentCount;
286
287 Iterator<Node> it = arguments.iterator;
288 int unnamedArguments = argumentCount - namedArgumentCount;
289 for (int i = 0; i < unnamedArguments; i++) {
290 it.moveNext();
291 visitForValue(it.current);
292 }
293
294 bool directMatch = namedArgumentCount == signature.optionalParameterCount;
295 Map<String, int> namedArguments = <String, int>{};
296 for (int i = 0; i < namedArgumentCount; i++) {
297 String name = callStructure.namedArguments[i];
298 namedArguments[name] = assembler.stackSize;
299 it.moveNext();
300 visitForValue(it.current);
301 if (signature.orderedOptionalParameters[i].name != name) {
302 directMatch = false;
303 }
304 }
305 if (directMatch) return argumentCount;
306
307 // There was no direct match. Push all unnamed arguments and all named
308 // arguments that have already been evaluated, in signature order.
309 for (int i = 0; i < unnamedArguments; i++) {
310 assembler.loadLocal(argumentCount - 1);
311 }
312
313 for (ParameterElement parameter in signature.orderedOptionalParameters) {
314 int slot = namedArguments[parameter.name];
315 if (slot != null) {
316 assembler.loadSlot(slot);
317 } else {
318 doParameterInitializer(parameter);
319 }
320 }
321
322 // Some parameters may have defaulted to default value, making the
323 // parameter count larger than the argument count.
324 return argumentCount + signature.parameterCount;
325 }
326
327 void callConstructorBody(ConstructorElement constructor) {
328 FunctionExpression node = constructor.node;
329 if (node == null || node.body.asEmptyStatement() != null) return;
330
331 int functionId = requireFunction(constructor.declaration).functionId;
332 int constructorId =
333 functionBuilder.allocateConstantFromFunction(functionId);
334
335 FunctionSignature signature = constructor.functionSignature;
336
337 // Prepare for constructor body invoke.
338 assembler.dup();
339 signature.orderedForEachParameter((FormalElement parameter) {
340 // Boxed parameters are passed as boxed objects, not as the values
341 // contained within like we do for ordinary invokes
342 scope[parameter].loadRaw(assembler);
343 });
344
345 assembler
346 ..invokeStatic(constructorId, 1 + signature.parameterCount)
347 ..pop();
348 }
349
350 void pushInitialFieldValues(FletchClassBuilder classBuilder) {
351 if (classBuilder.hasSuperClass) {
352 pushInitialFieldValues(classBuilder.superclass);
353 }
354 int fieldIndex = classBuilder.superclassFields;
355 ClassElement classElement = classBuilder.element.implementation;
356 classElement.forEachInstanceField((_, FieldElement field) {
357 fieldScope[field] = new UnboxedLocalValue(fieldIndex++, field);
358 Expression initializer = field.initializer;
359 if (initializer == null) {
360 assembler.loadLiteralNull();
361 } else {
362 // Create a LazyFieldInitializerCodegen for compiling the initializer.
363 // Note that we reuse the functionBuilder, to inline it into the
364 // constructor.
365 LazyFieldInitializerCodegen codegen =
366 lazyFieldInitializerCodegenFor(functionBuilder, field);
367
368 // We only want the value of the actual initializer, not the usual
369 // 'body'.
370 codegen.visitForValue(initializer);
371 }
372 });
373 assert(fieldIndex <= classBuilder.fields);
374 }
375 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/src/console_print.dart ('k') | pkg/fletchc/lib/src/debug_info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698