 Chromium Code Reviews
 Chromium Code Reviews Issue 1811173003:
  Support per-library serialization.  (Closed) 
  Base URL: https://github.com/dart-lang/sdk.git@master
    
  
    Issue 1811173003:
  Support per-library serialization.  (Closed) 
  Base URL: https://github.com/dart-lang/sdk.git@master| 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); |