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

Side by Side Diff: pkg/fletchc/lib/src/fletch_class_builder.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
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.fletch_class_builder;
6
7 import 'package:compiler/src/dart_types.dart';
8 import 'package:compiler/src/elements/elements.dart';
9 import 'package:compiler/src/universe/selector.dart';
10 import 'package:persistent/persistent.dart';
11
12 import 'fletch_function_builder.dart';
13 import 'fletch_context.dart';
14 import 'fletch_backend.dart';
15
16 import '../fletch_system.dart';
17 import '../vm_commands.dart';
18
19 // TODO(ahe): Remove this import.
20 import '../incremental/fletchc_incremental.dart' show
21 IncrementalCompilationFailed;
22
23 abstract class FletchClassBuilder {
24 int get classId;
25 ClassElement get element;
26 FletchClassBuilder get superclass;
27 int get fields;
28
29 /**
30 * Returns the number of instance fields of all the super classes of this
31 * class.
32 *
33 * If this class has no super class (if it's Object), 0 is returned.
34 */
35 int get superclassFields => hasSuperClass ? superclass.fields : 0;
36
37 bool get hasSuperClass => superclass != null;
38
39 void addToMethodTable(int selector, FletchFunctionBase functionBase);
40 void removeFromMethodTable(FletchFunctionBase function);
41
42 void addField(FieldElement field);
43 void removeField(FieldElement field);
44
45 // Add a selector for is-tests. The selector is only to be hit with the
46 // InvokeTest bytecode, as the function is not guraranteed to be valid.
47 void addIsSelector(int selector);
48 void createIsFunctionEntry(FletchBackend backend, int arity);
49 void updateImplicitAccessors(FletchBackend backend);
50
51 FletchClass finalizeClass(
52 FletchContext context,
53 List<VmCommand> commands);
54
55 // The method table for a class is a mapping from Fletch's integer
56 // selectors to method ids. It contains all methods defined for a
57 // class including the implicit accessors. The returned map is not sorted.
58 // TODO(ajohnsen): Remove once not used by feature_test anymore.
59 PersistentMap<int, int> computeMethodTable();
60
61 bool computeSchemaChange(List<VmCommand> commands) {
62 return false;
63 }
64 }
65
66 void forEachField(ClassElement c, void action(FieldElement field)) {
67 List classes = [];
68 while (c != null) {
69 classes.add(c);
70 c = c.superclass;
71 }
72 for (int i = classes.length - 1; i >= 0; i--) {
73 classes[i].implementation.forEachInstanceField((_, FieldElement field) {
74 action(field);
75 });
76 }
77 }
78
79 class FletchNewClassBuilder extends FletchClassBuilder {
80 final int classId;
81 final ClassElement element;
82 final FletchClassBuilder superclass;
83 final bool isBuiltin;
84
85 // The extra fields are synthetic fields not represented in any Dart source
86 // code. They are used for the synthetic closure classes that are introduced
87 // behind the scenes.
88 final int extraFields;
89
90 final Map<int, int> _implicitAccessorTable = <int, int>{};
91 final Map<int, FletchFunctionBase> _methodTable = <int, FletchFunctionBase>{};
92
93 FletchNewClassBuilder(
94 this.classId,
95 this.element,
96 this.superclass,
97 this.isBuiltin,
98 this.extraFields);
99
100 int get fields {
101 int count = superclassFields + extraFields;
102 if (element != null) {
103 // TODO(kasperl): Once we change compiled class to be immutable, we
104 // should cache the field count.
105 element.implementation.forEachInstanceField((_, __) { count++; });
106 }
107 return count;
108 }
109
110 void addToMethodTable(int selector, FletchFunctionBase functionBase) {
111 _methodTable[selector] = functionBase;
112 }
113
114 void addField(FieldElement field) {
115 throw new StateError("Fields should not be added to a new class.");
116 }
117
118 void removeField(FieldElement field) {
119 // TODO(ahe): Change this to a StateError when bug in incremental compiler
120 // is fixed (tested by super_is_parameter).
121 throw new IncrementalCompilationFailed(
122 "Can't remove a field ($field) from a new class ($element)");
123 }
124
125 void removeFromMethodTable(FletchFunctionBase function) {
126 throw new StateError("Methods should not be removed from a new class.");
127 }
128
129 void addIsSelector(int selector) {
130 // TODO(ajohnsen): 'null' is a placeholder. Generate dummy function?
131 _methodTable[selector] = null;
132 }
133
134 PersistentMap<int, int> computeMethodTable() {
135 PersistentMap<int, int> result = new PersistentMap<int, int>();
136 List<int> selectors = _implicitAccessorTable.keys.toList()
137 ..addAll(_methodTable.keys);
138 for (int selector in selectors) {
139 if (_methodTable.containsKey(selector)) {
140 FletchFunctionBase function = _methodTable[selector];
141 int functionId = function == null ? 0 : function.functionId;
142 result = result.insert(selector, functionId);
143 } else {
144 result = result.insert(selector, _implicitAccessorTable[selector]);
145 }
146 }
147 return result;
148 }
149
150 void updateImplicitAccessors(FletchBackend backend) {
151 _implicitAccessorTable.clear();
152 // If we don't have an element (stub class), we don't have anything to
153 // generate accessors for.
154 if (element == null) return;
155 // TODO(ajohnsen): Don't do this once dart2js can enqueue field getters in
156 // CodegenEnqueuer.
157 int fieldIndex = superclassFields;
158 element.implementation.forEachInstanceField((enclosing, field) {
159 var getter = new Selector.getter(field.memberName);
160 int getterSelector = backend.context.toFletchSelector(getter);
161 _implicitAccessorTable[getterSelector] = backend.makeGetter(fieldIndex);
162
163 if (!field.isFinal) {
164 var setter = new Selector.setter(new Name(field.name, field.library));
165 var setterSelector = backend.context.toFletchSelector(setter);
166 _implicitAccessorTable[setterSelector] = backend.makeSetter(fieldIndex);
167 }
168
169 fieldIndex++;
170 });
171 }
172
173 void createIsFunctionEntry(FletchBackend backend, int arity) {
174 int fletchSelector = backend.context.toFletchIsSelector(
175 backend.compiler.coreClasses.functionClass);
176 addIsSelector(fletchSelector);
177 fletchSelector = backend.context.toFletchIsSelector(
178 backend.compiler.coreClasses.functionClass, arity);
179 addIsSelector(fletchSelector);
180 }
181
182 FletchClass finalizeClass(
183 FletchContext context,
184 List<VmCommand> commands) {
185 if (isBuiltin) {
186 int nameId = context.getSymbolId(element.name);
187 commands.add(new PushBuiltinClass(nameId, fields));
188 } else {
189 commands.add(new PushNewClass(fields));
190 }
191
192 commands.add(const Dup());
193 commands.add(new PopToMap(MapId.classes, classId));
194
195 PersistentMap<int, int> methodTable = computeMethodTable();
196 for (int selector in methodTable.keys.toList()..sort()) {
197 int functionId = methodTable[selector];
198 commands.add(new PushNewInteger(selector));
199 commands.add(new PushFromMap(MapId.methods, functionId));
200 }
201 commands.add(new ChangeMethodTable(methodTable.length));
202
203 List<FieldElement> fieldsList = new List<FieldElement>(fields);
204 int index = 0;
205 forEachField(element, (field) {
206 fieldsList[index++] = field;
207 });
208
209 return new FletchClass(
210 classId,
211 // TODO(ajohnsen): Take name in FletchClassBuilder constructor.
212 element == null ? '<internal>' : element.name,
213 element,
214 superclass == null ? -1 : superclass.classId,
215 superclassFields,
216 methodTable,
217 fieldsList);
218 }
219
220 String toString() => "FletchClassBuilder($element, $classId)";
221 }
222
223 class FletchPatchClassBuilder extends FletchClassBuilder {
224 final FletchClass klass;
225 final FletchClassBuilder superclass;
226
227 final Map<int, int> _implicitAccessorTable = <int, int>{};
228 final Map<int, FletchFunctionBase> _newMethods = <int, FletchFunctionBase>{};
229 final Set<FletchFunctionBase> _removedMethods = new Set<FletchFunctionBase>();
230 final Set<FieldElement> _removedFields = new Set<FieldElement>();
231 final List<int> _removedAccessors = <int>[];
232 bool _fieldsChanged = false;
233
234 // TODO(ajohnsen): Reconsider bookkeeping of extra fields (this is really only
235 // extra super-class fields).
236 int extraFields = 0;
237
238 // TODO(ajohnsen): Can the element change?
239 FletchPatchClassBuilder(this.klass, this.superclass);
240
241 int get classId => klass.classId;
242 ClassElement get element => klass.element;
243 int get fields => klass.fields.length;
244
245 void addToMethodTable(int selector, FletchFunctionBase functionBase) {
246 _newMethods[selector] = functionBase;
247 }
248
249 void removeFromMethodTable(FletchFunctionBase function) {
250 assert(function != null);
251 _removedMethods.add(function);
252 }
253
254 void removeField(FieldElement field) {
255 if (field.enclosingClass != element) extraFields--;
256 _fieldsChanged = true;
257 _removedFields.add(field);
258 }
259
260 void addField(FieldElement field) {
261 if (field.enclosingClass != element) extraFields++;
262 _fieldsChanged = true;
263 }
264
265 void addIsSelector(int selector) {
266 // TODO(ajohnsen): Implement.
267 }
268
269 void createIsFunctionEntry(FletchBackend backend, int arity) {
270 // TODO(ajohnsen): Implement.
271 }
272
273 void updateImplicitAccessors(FletchBackend backend) {
274 // If we don't have an element (stub class), we don't have anything to
275 // generate accessors for.
276 if (element == null) return;
277 // TODO(ajohnsen): Don't do this once dart2js can enqueue field getters in
278 // CodegenEnqueuer.
279 int fieldIndex = superclassFields + extraFields;
280 element.implementation.forEachInstanceField((enclosing, field) {
281 var getter = new Selector.getter(new Name(field.name, field.library));
282 int getterSelector = backend.context.toFletchSelector(getter);
283 _implicitAccessorTable[getterSelector] = backend.makeGetter(fieldIndex);
284
285 if (!field.isFinal) {
286 var setter = new Selector.setter(new Name(field.name, field.library));
287 var setterSelector = backend.context.toFletchSelector(setter);
288 _implicitAccessorTable[setterSelector] = backend.makeSetter(fieldIndex);
289 }
290
291 fieldIndex++;
292 });
293
294 for (FieldElement field in _removedFields) {
295 Selector getter =
296 new Selector.getter(new Name(field.name, field.library));
297 int getterSelector = backend.context.toFletchSelector(getter);
298 _removedAccessors.add(getterSelector);
299
300 if (!field.isFinal) {
301 Selector setter =
302 new Selector.setter(new Name(field.name, field.library));
303 int setterSelector = backend.context.toFletchSelector(setter);
304 _removedAccessors.add(setterSelector);
305 }
306 }
307 }
308
309 PersistentMap<int, int> computeMethodTable() {
310 PersistentMap<int, int> methodTable = klass.methodTable;
311
312 for (int selector in _removedAccessors) {
313 methodTable = methodTable.delete(selector);
314 }
315
316 for (FletchFunctionBase function in _removedMethods) {
317 methodTable.forEachKeyValue((int selector, int functionId) {
318 if (functionId == function.functionId) {
319 methodTable = methodTable.delete(selector);
320 }
321 });
322 }
323
324 // TODO(ajohnsen): Generate this from add/remove field operations.
325 _implicitAccessorTable.forEach((int selector, int functionId) {
326 methodTable = methodTable.insert(selector, functionId);
327 });
328
329 _newMethods.forEach((int selector, FletchFunctionBase function) {
330 methodTable = methodTable.insert(selector, function.functionId);
331 });
332
333 return methodTable;
334 }
335
336 FletchClass finalizeClass(
337 FletchContext context,
338 List<VmCommand> commands) {
339 // TODO(ajohnsen): We need to figure out when to do this. It should be after
340 // we have updated class fields, but before we hit 'computeSystem'.
341 updateImplicitAccessors(context.backend);
342
343 commands.add(new PushFromMap(MapId.classes, classId));
344
345 PersistentMap<int, int> methodTable = computeMethodTable();
346 for (int selector in methodTable.keys.toList()..sort()) {
347 int functionId = methodTable[selector];
348 commands.add(new PushNewInteger(selector));
349 commands.add(new PushFromMap(MapId.methods, functionId));
350 }
351 commands.add(new ChangeMethodTable(methodTable.length));
352
353 List<FieldElement> fieldsList = <FieldElement>[];
354 forEachField(element, (field) { fieldsList.add(field); });
355
356 return new FletchClass(
357 classId,
358 // TODO(ajohnsen): Take name in FletchClassBuilder constructor.
359 element == null ? '<internal>' : element.name,
360 element,
361 superclass == null ? -1 : superclass.classId,
362 superclassFields + extraFields,
363 methodTable,
364 fieldsList);
365 }
366
367 bool computeSchemaChange(List<VmCommand> commands) {
368 if (!_fieldsChanged) return false;
369
370 // TODO(ajohnsen): Don't recompute this list.
371 List<FieldElement> afterFields = <FieldElement>[];
372 forEachField(element, (field) { afterFields.add(field); });
373
374 // TODO(ajohnsen): Handle sub/super classes.
375 int numberOfClasses = 1;
376 commands.add(new PushFromMap(MapId.classes, classId));
377
378 // Then we push a transformation mapping that tells the runtime system how
379 // to build the values for the first part of all instances of the classes.
380 // Pre-existing fields that fall after the mapped part will be copied with
381 // no changes.
382 const VALUE_FROM_ELSEWHERE = 0;
383 const VALUE_FROM_OLD_INSTANCE = 1;
384 for (int i = 0; i < afterFields.length; i++) {
385 FieldElement field = afterFields[i];
386 int beforeIndex = klass.fields.indexOf(field);
387 if (beforeIndex >= 0) {
388 commands.add(const PushNewInteger(VALUE_FROM_OLD_INSTANCE));
389 commands.add(new PushNewInteger(beforeIndex));
390 } else {
391 commands.add(const PushNewInteger(VALUE_FROM_ELSEWHERE));
392 commands.add(const PushNull());
393 }
394 }
395 commands.add(new PushNewArray(afterFields.length * 2));
396
397 // Finally, ask the runtime to change the schemas!
398 int fieldCountDelta = afterFields.length - klass.fields.length;
399 commands.add(new ChangeSchemas(numberOfClasses, fieldCountDelta));
400
401 return true;
402 }
403 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/src/fletch_backend.dart ('k') | pkg/fletchc/lib/src/fletch_compiler_implementation.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698