| Index: pkg/compiler/lib/src/serialization/serialization.dart
|
| diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
|
| index 0379b6ad5fd67fc196b40c822198a3a11c436157..6050388ffc6431774e9fa87d1cf5684c822de29a 100644
|
| --- a/pkg/compiler/lib/src/serialization/serialization.dart
|
| +++ b/pkg/compiler/lib/src/serialization/serialization.dart
|
| @@ -4,15 +4,12 @@
|
|
|
| library dart2js.serialization;
|
|
|
| -import '../common/backend_api.dart';
|
| import '../elements/elements.dart';
|
| import '../constants/expressions.dart';
|
| import '../dart_types.dart';
|
| -import '../universe/world_impact.dart';
|
|
|
| import 'constant_serialization.dart';
|
| import 'element_serialization.dart';
|
| -import 'impact_serialization.dart';
|
| import 'json_serializer.dart';
|
| import 'keys.dart';
|
| import 'type_serialization.dart';
|
| @@ -91,6 +88,13 @@ abstract class AbstractEncoder<K> {
|
| }
|
| }
|
|
|
| + /// Maps the [key] entry to the [value] in the encoded object.
|
| + void setValue(K key, Value value) {
|
| + _checkKey(key);
|
| + _map[key] = value;
|
| + }
|
| +
|
| +
|
| /// Maps the [key] entry to the enum [value] in the encoded object.
|
| void setEnum(K key, var value) {
|
| _checkKey(key);
|
| @@ -581,6 +585,11 @@ class DataObject {
|
| Map<Key, Value> get map => objectValue.map;
|
| }
|
|
|
| +/// Function used to filter which element serialized.
|
| +typedef bool ElementMatcher(Element element);
|
| +
|
| +bool includeAllElements(Element element) => true;
|
| +
|
| /// Serializer for the transitive closure of a collection of libraries.
|
| ///
|
| /// The serializer creates an [ObjectValue] model of the [Element], [DartType]
|
| @@ -607,26 +616,27 @@ class DataObject {
|
| /// ],
|
| /// }
|
| ///
|
| -// TODO(johnniwinther): Support per-library serialization and dependencies
|
| -// between serialized subcomponent.
|
| +// TODO(johnniwinther): Support dependencies between serialized subcomponent.
|
| class Serializer {
|
| - final SerializationEncoder _encoder;
|
| List<SerializerPlugin> plugins = <SerializerPlugin>[];
|
|
|
| + Map<Uri, dynamic> _dependencyMap = <Uri, dynamic>{};
|
| Map<Element, DataObject> _elementMap = <Element, DataObject>{};
|
| Map<ConstantExpression, DataObject> _constantMap =
|
| <ConstantExpression, DataObject>{};
|
| Map<DartType, DataObject> _typeMap = <DartType, DataObject>{};
|
| List _pendingList = [];
|
| + ElementMatcher shouldInclude;
|
|
|
| - Serializer(this._encoder);
|
| + // TODO(johnniwinther): Replace [includeElement] with a general strategy.
|
| + Serializer({this.shouldInclude: includeAllElements});
|
|
|
| /// Add the transitive closure of [library] to this serializer.
|
| void serialize(LibraryElement library) {
|
| - // Call [_getElementDataObject] for its side-effect: To create a
|
| + // Call [_getElementId] for its side-effect: To create a
|
| // [DataObject] for [library]. If not already created, this will
|
| // put the serialization of [library] in the work queue.
|
| - _getElementDataObject(library);
|
| + _getElementId(library);
|
| }
|
|
|
| void _emptyWorklist() {
|
| @@ -635,41 +645,75 @@ class Serializer {
|
| }
|
| }
|
|
|
| - /// Returns the [DataObject] for [element].
|
| + /// Returns the id [Value] for [element].
|
| ///
|
| - /// If [constant] has no [DataObject], a new [DataObject] is created and
|
| - /// encoding the [ObjectValue] for [constant] is put into the work queue of
|
| + /// If [element] has no [DataObject], a new [DataObject] is created and
|
| + /// encoding the [ObjectValue] for [element] is put into the work queue of
|
| /// this serializer.
|
| - DataObject _getElementDataObject(Element element) {
|
| + Value _getElementId(Element element) {
|
| if (element == null) {
|
| throw new ArgumentError('Serializer._getElementDataObject(null)');
|
| }
|
| DataObject dataObject = _elementMap[element];
|
| if (dataObject == null) {
|
| - // Run through [ELEMENT_SERIALIZERS] sequentially to find the one that
|
| - // deals with [element].
|
| - for (ElementSerializer serializer in ELEMENT_SERIALIZERS) {
|
| - SerializedElementKind kind = serializer.getSerializedKind(element);
|
| - if (kind != null) {
|
| - dataObject = new DataObject(
|
| - new IntValue(_elementMap.length), new EnumValue(kind));
|
| - _elementMap[element] = dataObject;
|
| - // Delay the serialization of the element itself to avoid loops, and
|
| - // to keep the call stack small.
|
| - _pendingList.add(() {
|
| - ObjectEncoder encoder = new ObjectEncoder(this, dataObject.map);
|
| - serializer.serialize(element, encoder, kind);
|
| -
|
| - MapEncoder pluginData;
|
| - for (SerializerPlugin plugin in plugins) {
|
| - plugin.onElement(element, (String tag) {
|
| - if (pluginData == null) {
|
| - pluginData = encoder.createMap(Key.DATA);
|
| - }
|
| - return pluginData.createObject(tag);
|
| - });
|
| - }
|
| - });
|
| + if (!shouldInclude(element)) {
|
| + if (element.isLibrary) {
|
| + LibraryElement library = element;
|
| + _elementMap[element] = dataObject = new DataObject(
|
| + new IntValue(_elementMap.length),
|
| + new EnumValue(SerializedElementKind.EXTERNAL_LIBRARY));
|
| + ObjectEncoder encoder = new ObjectEncoder(this, dataObject.map);
|
| + encoder.setUri(Key.URI, library.canonicalUri, library.canonicalUri);
|
| + } else if (element.isStatic) {
|
| + Value classId =_getElementId(element.enclosingClass);
|
| + _elementMap[element] = dataObject = new DataObject(
|
| + new IntValue(_elementMap.length),
|
| + new EnumValue(SerializedElementKind.EXTERNAL_STATIC_MEMBER));
|
| + ObjectEncoder encoder = new ObjectEncoder(this, dataObject.map);
|
| + encoder.setValue(Key.CLASS, classId);
|
| + encoder.setString(Key.NAME, element.name);
|
| + } else if (element.isConstructor) {
|
| + Value classId =_getElementId(element.enclosingClass);
|
| + _elementMap[element] = dataObject = new DataObject(
|
| + new IntValue(_elementMap.length),
|
| + new EnumValue(SerializedElementKind.EXTERNAL_CONSTRUCTOR));
|
| + ObjectEncoder encoder = new ObjectEncoder(this, dataObject.map);
|
| + encoder.setValue(Key.CLASS, classId);
|
| + encoder.setString(Key.NAME, element.name);
|
| + } else {
|
| + Value libraryId =_getElementId(element.library);
|
| + _elementMap[element] = dataObject = new DataObject(
|
| + new IntValue(_elementMap.length),
|
| + new EnumValue(SerializedElementKind.EXTERNAL_LIBRARY_MEMBER));
|
| + ObjectEncoder encoder = new ObjectEncoder(this, dataObject.map);
|
| + encoder.setValue(Key.LIBRARY, libraryId);
|
| + encoder.setString(Key.NAME, element.name);
|
| + }
|
| + } else {
|
| + // Run through [ELEMENT_SERIALIZERS] sequentially to find the one that
|
| + // deals with [element].
|
| + for (ElementSerializer serializer in ELEMENT_SERIALIZERS) {
|
| + SerializedElementKind kind = serializer.getSerializedKind(element);
|
| + if (kind != null) {
|
| + _elementMap[element] = dataObject = new DataObject(
|
| + new IntValue(_elementMap.length), new EnumValue(kind));
|
| + // Delay the serialization of the element itself to avoid loops, and
|
| + // to keep the call stack small.
|
| + _pendingList.add(() {
|
| + ObjectEncoder encoder = new ObjectEncoder(this, dataObject.map);
|
| + serializer.serialize(element, encoder, kind);
|
| +
|
| + MapEncoder pluginData;
|
| + for (SerializerPlugin plugin in plugins) {
|
| + plugin.onElement(element, (String tag) {
|
| + if (pluginData == null) {
|
| + pluginData = encoder.createMap(Key.DATA);
|
| + }
|
| + return pluginData.createObject(tag);
|
| + });
|
| + }
|
| + });
|
| + }
|
| }
|
| }
|
| }
|
| @@ -677,7 +721,7 @@ class Serializer {
|
| throw new UnsupportedError(
|
| 'Unsupported element: $element (${element.kind})');
|
| }
|
| - return dataObject;
|
| + return dataObject.id;
|
| }
|
|
|
| /// Creates the [ElementValue] for [element].
|
| @@ -685,15 +729,15 @@ class Serializer {
|
| /// If [element] has not already been serialized, it is added to the work
|
| /// queue of this serializer.
|
| ElementValue createElementValue(Element element) {
|
| - return new ElementValue(element, _getElementDataObject(element).id);
|
| + return new ElementValue(element, _getElementId(element));
|
| }
|
|
|
| - /// Returns the [DataObject] for [constant].
|
| + /// Returns the id [Value] for [constant].
|
| ///
|
| /// If [constant] has no [DataObject], a new [DataObject] is created and
|
| /// encoding the [ObjectValue] for [constant] is put into the work queue of
|
| /// this serializer.
|
| - DataObject _getConstantDataObject(ConstantExpression constant) {
|
| + Value _getConstantId(ConstantExpression constant) {
|
| return _constantMap.putIfAbsent(constant, () {
|
| DataObject dataObject = new DataObject(
|
| new IntValue(_constantMap.length), new EnumValue(constant.kind));
|
| @@ -701,7 +745,7 @@ class Serializer {
|
| // keep the call stack small.
|
| _pendingList.add(() => _encodeConstant(constant, dataObject));
|
| return dataObject;
|
| - });
|
| + }).id;
|
| }
|
|
|
| /// Encodes [constant] into the [ObjectValue] of [dataObject].
|
| @@ -715,23 +759,24 @@ class Serializer {
|
| /// If [constant] has not already been serialized, it is added to the work
|
| /// queue of this serializer.
|
| ConstantValue createConstantValue(ConstantExpression constant) {
|
| - return new ConstantValue(constant, _getConstantDataObject(constant).id);
|
| + return new ConstantValue(constant, _getConstantId(constant));
|
| }
|
|
|
| - /// Returns the [DataObject] for [type].
|
| + /// Returns the id [Value] for [type].
|
| ///
|
| /// If [type] has no [DataObject], a new [DataObject] is created and
|
| /// encoding the [ObjectValue] for [type] is put into the work queue of this
|
| /// serializer.
|
| - DataObject _getTypeDataObject(DartType type) {
|
| - return _typeMap.putIfAbsent(type, () {
|
| - DataObject dataObject = new DataObject(
|
| + Value _getTypeId(DartType type) {
|
| + DataObject dataObject = _typeMap[type];
|
| + if (dataObject == null) {
|
| + _typeMap[type] = dataObject = new DataObject(
|
| new IntValue(_typeMap.length), new EnumValue(type.kind));
|
| // Delay the serialization of the type itself to avoid loops, and to keep
|
| // the call stack small.
|
| _pendingList.add(() => _encodeType(type, dataObject));
|
| - return dataObject;
|
| - });
|
| + }
|
| + return dataObject.id;
|
| }
|
|
|
| /// Encodes [type] into the [ObjectValue] of [dataObject].
|
| @@ -744,7 +789,7 @@ class Serializer {
|
| /// If [type] has not already been serialized, it is added to the work
|
| /// queue of this serializer.
|
| TypeValue createTypeValue(DartType type) {
|
| - return new TypeValue(type, _getTypeDataObject(type).id);
|
| + return new TypeValue(type, _getTypeId(type));
|
| }
|
|
|
| ObjectValue get objectValue {
|
| @@ -764,8 +809,8 @@ class Serializer {
|
| return new ObjectValue(map);
|
| }
|
|
|
| - String toText() {
|
| - return _encoder.encode(objectValue);
|
| + String toText(SerializationEncoder encoder) {
|
| + return encoder.encode(objectValue);
|
| }
|
|
|
| String prettyPrint() {
|
| @@ -796,10 +841,29 @@ class DeserializerPlugin {
|
| void onElement(Element element, ObjectDecoder getDecoder(String tag)) {}
|
| }
|
|
|
| +/// Context for parallel deserialization.
|
| +class DeserializationContext {
|
| + Map<Uri, LibraryElement> _uriMap = <Uri, LibraryElement>{};
|
| + List<Deserializer> deserializers = <Deserializer>[];
|
| +
|
| + LibraryElement lookupLibrary(Uri uri) {
|
| + return _uriMap.putIfAbsent(uri, () {
|
| + for (Deserializer deserializer in deserializers) {
|
| + LibraryElement library = deserializer.lookupLibrary(uri);
|
| + if (library != null) {
|
| + return library;
|
| + }
|
| + }
|
| + return null;
|
| + });
|
| + }
|
| +}
|
| +
|
| /// Deserializer for a closed collection of libraries.
|
| // TODO(johnniwinther): Support per-library deserialization and dependencies
|
| // between deserialized subcomponent.
|
| class Deserializer {
|
| + final DeserializationContext context;
|
| final SerializationDecoder decoder;
|
| List<DeserializerPlugin> plugins = <DeserializerPlugin>[];
|
| ObjectDecoder _headerObject;
|
| @@ -810,8 +874,9 @@ class Deserializer {
|
| Map<int, DartType> _typeMap = {};
|
| Map<int, ConstantExpression> _constantMap = {};
|
|
|
| - Deserializer.fromText(String text, this.decoder) {
|
| + Deserializer.fromText(this.context, String text, this.decoder) {
|
| _headerObject = new ObjectDecoder(this, decoder.decode(text));
|
| + context.deserializers.add(this);
|
| }
|
|
|
| /// Returns the [ListDecoder] for the [Element]s in this deserializer.
|
| @@ -863,7 +928,38 @@ class Deserializer {
|
| Element element = _elementMap[id];
|
| if (element == null) {
|
| ObjectDecoder decoder = elements.getObject(id);
|
| - element = ElementDeserializer.deserialize(decoder);
|
| + SerializedElementKind elementKind =
|
| + decoder.getEnum(Key.KIND, SerializedElementKind.values);
|
| + if (elementKind == SerializedElementKind.EXTERNAL_LIBRARY) {
|
| + Uri uri = decoder.getUri(Key.URI);
|
| + element = context.lookupLibrary(uri);
|
| + if (element == null) {
|
| + throw new StateError("Missing library for $uri.");
|
| + }
|
| + } else if (elementKind == SerializedElementKind.EXTERNAL_LIBRARY_MEMBER) {
|
| + LibraryElement library = decoder.getElement(Key.LIBRARY);
|
| + String name = decoder.getString(Key.NAME);
|
| + element = library.find(name);
|
| + if (element == null) {
|
| + throw new StateError("Missing library member for $name in $library.");
|
| + }
|
| + } else if (elementKind == SerializedElementKind.EXTERNAL_STATIC_MEMBER) {
|
| + ClassElement cls = decoder.getElement(Key.CLASS);
|
| + String name = decoder.getString(Key.NAME);
|
| + element = cls.lookupLocalMember(name);
|
| + if (element == null) {
|
| + throw new StateError("Missing static member for $name in $cls.");
|
| + }
|
| + } else if (elementKind == SerializedElementKind.EXTERNAL_CONSTRUCTOR) {
|
| + ClassElement cls = decoder.getElement(Key.CLASS);
|
| + String name = decoder.getString(Key.NAME);
|
| + element = cls.lookupConstructor(name);
|
| + if (element == null) {
|
| + throw new StateError("Missing constructor for $name in $cls.");
|
| + }
|
| + } else {
|
| + element = ElementDeserializer.deserialize(decoder, elementKind);
|
| + }
|
| _elementMap[id] = element;
|
|
|
| MapDecoder pluginData = decoder.getMap(Key.DATA, isOptional: true);
|
|
|