| Index: pkg/fletchc/lib/src/fletch_class_builder.dart
|
| diff --git a/pkg/fletchc/lib/src/fletch_class_builder.dart b/pkg/fletchc/lib/src/fletch_class_builder.dart
|
| deleted file mode 100644
|
| index 94fda18551a785b08aec879b2c0e407894635908..0000000000000000000000000000000000000000
|
| --- a/pkg/fletchc/lib/src/fletch_class_builder.dart
|
| +++ /dev/null
|
| @@ -1,403 +0,0 @@
|
| -// Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE.md file.
|
| -
|
| -library fletchc.fletch_class_builder;
|
| -
|
| -import 'package:compiler/src/dart_types.dart';
|
| -import 'package:compiler/src/elements/elements.dart';
|
| -import 'package:compiler/src/universe/selector.dart';
|
| -import 'package:persistent/persistent.dart';
|
| -
|
| -import 'fletch_function_builder.dart';
|
| -import 'fletch_context.dart';
|
| -import 'fletch_backend.dart';
|
| -
|
| -import '../fletch_system.dart';
|
| -import '../vm_commands.dart';
|
| -
|
| -// TODO(ahe): Remove this import.
|
| -import '../incremental/fletchc_incremental.dart' show
|
| - IncrementalCompilationFailed;
|
| -
|
| -abstract class FletchClassBuilder {
|
| - int get classId;
|
| - ClassElement get element;
|
| - FletchClassBuilder get superclass;
|
| - int get fields;
|
| -
|
| - /**
|
| - * Returns the number of instance fields of all the super classes of this
|
| - * class.
|
| - *
|
| - * If this class has no super class (if it's Object), 0 is returned.
|
| - */
|
| - int get superclassFields => hasSuperClass ? superclass.fields : 0;
|
| -
|
| - bool get hasSuperClass => superclass != null;
|
| -
|
| - void addToMethodTable(int selector, FletchFunctionBase functionBase);
|
| - void removeFromMethodTable(FletchFunctionBase function);
|
| -
|
| - void addField(FieldElement field);
|
| - void removeField(FieldElement field);
|
| -
|
| - // Add a selector for is-tests. The selector is only to be hit with the
|
| - // InvokeTest bytecode, as the function is not guraranteed to be valid.
|
| - void addIsSelector(int selector);
|
| - void createIsFunctionEntry(FletchBackend backend, int arity);
|
| - void updateImplicitAccessors(FletchBackend backend);
|
| -
|
| - FletchClass finalizeClass(
|
| - FletchContext context,
|
| - List<VmCommand> commands);
|
| -
|
| - // The method table for a class is a mapping from Fletch's integer
|
| - // selectors to method ids. It contains all methods defined for a
|
| - // class including the implicit accessors. The returned map is not sorted.
|
| - // TODO(ajohnsen): Remove once not used by feature_test anymore.
|
| - PersistentMap<int, int> computeMethodTable();
|
| -
|
| - bool computeSchemaChange(List<VmCommand> commands) {
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -void forEachField(ClassElement c, void action(FieldElement field)) {
|
| - List classes = [];
|
| - while (c != null) {
|
| - classes.add(c);
|
| - c = c.superclass;
|
| - }
|
| - for (int i = classes.length - 1; i >= 0; i--) {
|
| - classes[i].implementation.forEachInstanceField((_, FieldElement field) {
|
| - action(field);
|
| - });
|
| - }
|
| -}
|
| -
|
| -class FletchNewClassBuilder extends FletchClassBuilder {
|
| - final int classId;
|
| - final ClassElement element;
|
| - final FletchClassBuilder superclass;
|
| - final bool isBuiltin;
|
| -
|
| - // The extra fields are synthetic fields not represented in any Dart source
|
| - // code. They are used for the synthetic closure classes that are introduced
|
| - // behind the scenes.
|
| - final int extraFields;
|
| -
|
| - final Map<int, int> _implicitAccessorTable = <int, int>{};
|
| - final Map<int, FletchFunctionBase> _methodTable = <int, FletchFunctionBase>{};
|
| -
|
| - FletchNewClassBuilder(
|
| - this.classId,
|
| - this.element,
|
| - this.superclass,
|
| - this.isBuiltin,
|
| - this.extraFields);
|
| -
|
| - int get fields {
|
| - int count = superclassFields + extraFields;
|
| - if (element != null) {
|
| - // TODO(kasperl): Once we change compiled class to be immutable, we
|
| - // should cache the field count.
|
| - element.implementation.forEachInstanceField((_, __) { count++; });
|
| - }
|
| - return count;
|
| - }
|
| -
|
| - void addToMethodTable(int selector, FletchFunctionBase functionBase) {
|
| - _methodTable[selector] = functionBase;
|
| - }
|
| -
|
| - void addField(FieldElement field) {
|
| - throw new StateError("Fields should not be added to a new class.");
|
| - }
|
| -
|
| - void removeField(FieldElement field) {
|
| - // TODO(ahe): Change this to a StateError when bug in incremental compiler
|
| - // is fixed (tested by super_is_parameter).
|
| - throw new IncrementalCompilationFailed(
|
| - "Can't remove a field ($field) from a new class ($element)");
|
| - }
|
| -
|
| - void removeFromMethodTable(FletchFunctionBase function) {
|
| - throw new StateError("Methods should not be removed from a new class.");
|
| - }
|
| -
|
| - void addIsSelector(int selector) {
|
| - // TODO(ajohnsen): 'null' is a placeholder. Generate dummy function?
|
| - _methodTable[selector] = null;
|
| - }
|
| -
|
| - PersistentMap<int, int> computeMethodTable() {
|
| - PersistentMap<int, int> result = new PersistentMap<int, int>();
|
| - List<int> selectors = _implicitAccessorTable.keys.toList()
|
| - ..addAll(_methodTable.keys);
|
| - for (int selector in selectors) {
|
| - if (_methodTable.containsKey(selector)) {
|
| - FletchFunctionBase function = _methodTable[selector];
|
| - int functionId = function == null ? 0 : function.functionId;
|
| - result = result.insert(selector, functionId);
|
| - } else {
|
| - result = result.insert(selector, _implicitAccessorTable[selector]);
|
| - }
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - void updateImplicitAccessors(FletchBackend backend) {
|
| - _implicitAccessorTable.clear();
|
| - // If we don't have an element (stub class), we don't have anything to
|
| - // generate accessors for.
|
| - if (element == null) return;
|
| - // TODO(ajohnsen): Don't do this once dart2js can enqueue field getters in
|
| - // CodegenEnqueuer.
|
| - int fieldIndex = superclassFields;
|
| - element.implementation.forEachInstanceField((enclosing, field) {
|
| - var getter = new Selector.getter(field.memberName);
|
| - int getterSelector = backend.context.toFletchSelector(getter);
|
| - _implicitAccessorTable[getterSelector] = backend.makeGetter(fieldIndex);
|
| -
|
| - if (!field.isFinal) {
|
| - var setter = new Selector.setter(new Name(field.name, field.library));
|
| - var setterSelector = backend.context.toFletchSelector(setter);
|
| - _implicitAccessorTable[setterSelector] = backend.makeSetter(fieldIndex);
|
| - }
|
| -
|
| - fieldIndex++;
|
| - });
|
| - }
|
| -
|
| - void createIsFunctionEntry(FletchBackend backend, int arity) {
|
| - int fletchSelector = backend.context.toFletchIsSelector(
|
| - backend.compiler.coreClasses.functionClass);
|
| - addIsSelector(fletchSelector);
|
| - fletchSelector = backend.context.toFletchIsSelector(
|
| - backend.compiler.coreClasses.functionClass, arity);
|
| - addIsSelector(fletchSelector);
|
| - }
|
| -
|
| - FletchClass finalizeClass(
|
| - FletchContext context,
|
| - List<VmCommand> commands) {
|
| - if (isBuiltin) {
|
| - int nameId = context.getSymbolId(element.name);
|
| - commands.add(new PushBuiltinClass(nameId, fields));
|
| - } else {
|
| - commands.add(new PushNewClass(fields));
|
| - }
|
| -
|
| - commands.add(const Dup());
|
| - commands.add(new PopToMap(MapId.classes, classId));
|
| -
|
| - PersistentMap<int, int> methodTable = computeMethodTable();
|
| - for (int selector in methodTable.keys.toList()..sort()) {
|
| - int functionId = methodTable[selector];
|
| - commands.add(new PushNewInteger(selector));
|
| - commands.add(new PushFromMap(MapId.methods, functionId));
|
| - }
|
| - commands.add(new ChangeMethodTable(methodTable.length));
|
| -
|
| - List<FieldElement> fieldsList = new List<FieldElement>(fields);
|
| - int index = 0;
|
| - forEachField(element, (field) {
|
| - fieldsList[index++] = field;
|
| - });
|
| -
|
| - return new FletchClass(
|
| - classId,
|
| - // TODO(ajohnsen): Take name in FletchClassBuilder constructor.
|
| - element == null ? '<internal>' : element.name,
|
| - element,
|
| - superclass == null ? -1 : superclass.classId,
|
| - superclassFields,
|
| - methodTable,
|
| - fieldsList);
|
| - }
|
| -
|
| - String toString() => "FletchClassBuilder($element, $classId)";
|
| -}
|
| -
|
| -class FletchPatchClassBuilder extends FletchClassBuilder {
|
| - final FletchClass klass;
|
| - final FletchClassBuilder superclass;
|
| -
|
| - final Map<int, int> _implicitAccessorTable = <int, int>{};
|
| - final Map<int, FletchFunctionBase> _newMethods = <int, FletchFunctionBase>{};
|
| - final Set<FletchFunctionBase> _removedMethods = new Set<FletchFunctionBase>();
|
| - final Set<FieldElement> _removedFields = new Set<FieldElement>();
|
| - final List<int> _removedAccessors = <int>[];
|
| - bool _fieldsChanged = false;
|
| -
|
| - // TODO(ajohnsen): Reconsider bookkeeping of extra fields (this is really only
|
| - // extra super-class fields).
|
| - int extraFields = 0;
|
| -
|
| - // TODO(ajohnsen): Can the element change?
|
| - FletchPatchClassBuilder(this.klass, this.superclass);
|
| -
|
| - int get classId => klass.classId;
|
| - ClassElement get element => klass.element;
|
| - int get fields => klass.fields.length;
|
| -
|
| - void addToMethodTable(int selector, FletchFunctionBase functionBase) {
|
| - _newMethods[selector] = functionBase;
|
| - }
|
| -
|
| - void removeFromMethodTable(FletchFunctionBase function) {
|
| - assert(function != null);
|
| - _removedMethods.add(function);
|
| - }
|
| -
|
| - void removeField(FieldElement field) {
|
| - if (field.enclosingClass != element) extraFields--;
|
| - _fieldsChanged = true;
|
| - _removedFields.add(field);
|
| - }
|
| -
|
| - void addField(FieldElement field) {
|
| - if (field.enclosingClass != element) extraFields++;
|
| - _fieldsChanged = true;
|
| - }
|
| -
|
| - void addIsSelector(int selector) {
|
| - // TODO(ajohnsen): Implement.
|
| - }
|
| -
|
| - void createIsFunctionEntry(FletchBackend backend, int arity) {
|
| - // TODO(ajohnsen): Implement.
|
| - }
|
| -
|
| - void updateImplicitAccessors(FletchBackend backend) {
|
| - // If we don't have an element (stub class), we don't have anything to
|
| - // generate accessors for.
|
| - if (element == null) return;
|
| - // TODO(ajohnsen): Don't do this once dart2js can enqueue field getters in
|
| - // CodegenEnqueuer.
|
| - int fieldIndex = superclassFields + extraFields;
|
| - element.implementation.forEachInstanceField((enclosing, field) {
|
| - var getter = new Selector.getter(new Name(field.name, field.library));
|
| - int getterSelector = backend.context.toFletchSelector(getter);
|
| - _implicitAccessorTable[getterSelector] = backend.makeGetter(fieldIndex);
|
| -
|
| - if (!field.isFinal) {
|
| - var setter = new Selector.setter(new Name(field.name, field.library));
|
| - var setterSelector = backend.context.toFletchSelector(setter);
|
| - _implicitAccessorTable[setterSelector] = backend.makeSetter(fieldIndex);
|
| - }
|
| -
|
| - fieldIndex++;
|
| - });
|
| -
|
| - for (FieldElement field in _removedFields) {
|
| - Selector getter =
|
| - new Selector.getter(new Name(field.name, field.library));
|
| - int getterSelector = backend.context.toFletchSelector(getter);
|
| - _removedAccessors.add(getterSelector);
|
| -
|
| - if (!field.isFinal) {
|
| - Selector setter =
|
| - new Selector.setter(new Name(field.name, field.library));
|
| - int setterSelector = backend.context.toFletchSelector(setter);
|
| - _removedAccessors.add(setterSelector);
|
| - }
|
| - }
|
| - }
|
| -
|
| - PersistentMap<int, int> computeMethodTable() {
|
| - PersistentMap<int, int> methodTable = klass.methodTable;
|
| -
|
| - for (int selector in _removedAccessors) {
|
| - methodTable = methodTable.delete(selector);
|
| - }
|
| -
|
| - for (FletchFunctionBase function in _removedMethods) {
|
| - methodTable.forEachKeyValue((int selector, int functionId) {
|
| - if (functionId == function.functionId) {
|
| - methodTable = methodTable.delete(selector);
|
| - }
|
| - });
|
| - }
|
| -
|
| - // TODO(ajohnsen): Generate this from add/remove field operations.
|
| - _implicitAccessorTable.forEach((int selector, int functionId) {
|
| - methodTable = methodTable.insert(selector, functionId);
|
| - });
|
| -
|
| - _newMethods.forEach((int selector, FletchFunctionBase function) {
|
| - methodTable = methodTable.insert(selector, function.functionId);
|
| - });
|
| -
|
| - return methodTable;
|
| - }
|
| -
|
| - FletchClass finalizeClass(
|
| - FletchContext context,
|
| - List<VmCommand> commands) {
|
| - // TODO(ajohnsen): We need to figure out when to do this. It should be after
|
| - // we have updated class fields, but before we hit 'computeSystem'.
|
| - updateImplicitAccessors(context.backend);
|
| -
|
| - commands.add(new PushFromMap(MapId.classes, classId));
|
| -
|
| - PersistentMap<int, int> methodTable = computeMethodTable();
|
| - for (int selector in methodTable.keys.toList()..sort()) {
|
| - int functionId = methodTable[selector];
|
| - commands.add(new PushNewInteger(selector));
|
| - commands.add(new PushFromMap(MapId.methods, functionId));
|
| - }
|
| - commands.add(new ChangeMethodTable(methodTable.length));
|
| -
|
| - List<FieldElement> fieldsList = <FieldElement>[];
|
| - forEachField(element, (field) { fieldsList.add(field); });
|
| -
|
| - return new FletchClass(
|
| - classId,
|
| - // TODO(ajohnsen): Take name in FletchClassBuilder constructor.
|
| - element == null ? '<internal>' : element.name,
|
| - element,
|
| - superclass == null ? -1 : superclass.classId,
|
| - superclassFields + extraFields,
|
| - methodTable,
|
| - fieldsList);
|
| - }
|
| -
|
| - bool computeSchemaChange(List<VmCommand> commands) {
|
| - if (!_fieldsChanged) return false;
|
| -
|
| - // TODO(ajohnsen): Don't recompute this list.
|
| - List<FieldElement> afterFields = <FieldElement>[];
|
| - forEachField(element, (field) { afterFields.add(field); });
|
| -
|
| - // TODO(ajohnsen): Handle sub/super classes.
|
| - int numberOfClasses = 1;
|
| - commands.add(new PushFromMap(MapId.classes, classId));
|
| -
|
| - // Then we push a transformation mapping that tells the runtime system how
|
| - // to build the values for the first part of all instances of the classes.
|
| - // Pre-existing fields that fall after the mapped part will be copied with
|
| - // no changes.
|
| - const VALUE_FROM_ELSEWHERE = 0;
|
| - const VALUE_FROM_OLD_INSTANCE = 1;
|
| - for (int i = 0; i < afterFields.length; i++) {
|
| - FieldElement field = afterFields[i];
|
| - int beforeIndex = klass.fields.indexOf(field);
|
| - if (beforeIndex >= 0) {
|
| - commands.add(const PushNewInteger(VALUE_FROM_OLD_INSTANCE));
|
| - commands.add(new PushNewInteger(beforeIndex));
|
| - } else {
|
| - commands.add(const PushNewInteger(VALUE_FROM_ELSEWHERE));
|
| - commands.add(const PushNull());
|
| - }
|
| - }
|
| - commands.add(new PushNewArray(afterFields.length * 2));
|
| -
|
| - // Finally, ask the runtime to change the schemas!
|
| - int fieldCountDelta = afterFields.length - klass.fields.length;
|
| - commands.add(new ChangeSchemas(numberOfClasses, fieldCountDelta));
|
| -
|
| - return true;
|
| - }
|
| -}
|
|
|