Chromium Code Reviews| 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 b4b1524f94dcd43e10e04be641a5121c9906586c..868705d5b1342bdb90519a28ae4176eebd48af7a 100644 |
| --- a/pkg/compiler/lib/src/serialization/serialization.dart |
| +++ b/pkg/compiler/lib/src/serialization/serialization.dart |
| @@ -88,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); |
| @@ -578,6 +585,11 @@ class DataObject { |
| Map<Key, Value> get map => objectValue.map; |
| } |
| +/// Function used to filter which element serialized. |
| +typedef bool IncludeElementFunction(Element element); |
|
Siggi Cherem (dart-lang)
2016/03/18 20:00:20
IncludeElementFunction => ElementMatcher
Johnni Winther
2016/03/29 09:05:54
Done.
|
| + |
| +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] |
| @@ -604,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 = []; |
| + IncludeElementFunction includeElement; |
|
Siggi Cherem (dart-lang)
2016/03/18 20:00:20
rename to `shouldInclude`:
ElementMatcher shoul
Johnni Winther
2016/03/29 09:05:54
Done.
|
| - Serializer(this._encoder); |
| + // TODO(johnniwinther): Replace [includeElement] with a general strategy. |
| + Serializer({this.includeElement: 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() { |
| @@ -632,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 (!includeElement(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); |
|
Siggi Cherem (dart-lang)
2016/03/18 20:00:20
Just to check: does the classId include the librar
Johnni Winther
2016/03/29 09:05:54
The class will be an EXTERNAL_LIBRARY_MEMBER, whic
|
| + 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); |
| + }); |
| + } |
| + }); |
| + } |
| } |
| } |
| } |
| @@ -674,7 +721,7 @@ class Serializer { |
| throw new UnsupportedError( |
| 'Unsupported element: $element (${element.kind})'); |
| } |
| - return dataObject; |
| + return dataObject.id; |
| } |
| /// Creates the [ElementValue] for [element]. |
| @@ -682,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)); |
| @@ -698,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]. |
| @@ -712,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]. |
| @@ -741,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 { |
| @@ -761,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() { |
| @@ -793,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; |
| @@ -807,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. |
| @@ -860,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); |