Support post-inference serialization/deserialization
Currently handling Swarm in-memory serialization/deserialization.
Change-Id: I4b01f70d1e42d7462ed079ece227d6c2ed4de597
Reviewed-on: https://dart-review.googlesource.com/c/80445
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Auto-Submit: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/compiler/lib/src/backend_strategy.dart b/pkg/compiler/lib/src/backend_strategy.dart
index 6b2e8f0..c3aefb1 100644
--- a/pkg/compiler/lib/src/backend_strategy.dart
+++ b/pkg/compiler/lib/src/backend_strategy.dart
@@ -13,7 +13,6 @@
import 'js_backend/inferred_data.dart';
import 'js_backend/js_backend.dart';
import 'js_backend/native_data.dart';
-import 'js_emitter/sorter.dart';
import 'ssa/ssa.dart';
import 'types/types.dart';
import 'universe/world_builder.dart';
@@ -26,8 +25,11 @@
JClosedWorld createJClosedWorld(
KClosedWorld closedWorld, OutputUnitData outputUnitData);
- /// The [Sorter] used for sorting elements in the generated code.
- Sorter get sorter;
+ /// Registers [closedWorld] as the current closed world used by this backend
+ /// strategy.
+ ///
+ /// This is used to support serialization after type inference.
+ void registerJClosedWorld(JClosedWorld closedWorld);
/// Creates the [CodegenWorldBuilder] used by the codegen enqueuer.
CodegenWorldBuilder createCodegenWorldBuilder(
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 8006d88..22b3fc7 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -7,6 +7,9 @@
import 'common.dart';
import 'elements/entities.dart';
import 'elements/types.dart';
+import 'js_model/closure.dart';
+import 'js_model/element_map.dart';
+import 'serialization/serialization.dart';
abstract class ClosureConversionTask extends CompilerTask {
ClosureConversionTask(Measurer measurer) : super(measurer);
@@ -17,6 +20,14 @@
/// node to look up, it returns a information about the internal representation
/// of how closure conversion is implemented. T is an ir.Node or Node.
abstract class ClosureData {
+ /// Deserializes a [ClosureData] object from [source].
+ factory ClosureData.readFromDataSource(
+ JsToElementMap elementMap, DataSource source) =
+ ClosureDataImpl.readFromDataSource;
+
+ /// Serializes this [ClosureData] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Look up information about the variables that have been mutated and are
/// used inside the scope of [node].
ScopeInfo getScopeInfo(MemberEntity member);
@@ -32,6 +43,14 @@
CapturedScope getCapturedScope(MemberEntity entity);
}
+/// Enum used for identifying [ScopeInfo] subclasses in serialization.
+enum ScopeInfoKind {
+ scopeInfo,
+ capturedScope,
+ capturedLoopScope,
+ closureRepresentationInfo,
+}
+
/// Class that represents one level of scoping information, whether this scope
/// is a closure or not. This is specifically used to store information
/// about the usage of variables in try or sync blocks, because they need to be
@@ -44,6 +63,27 @@
class ScopeInfo {
const ScopeInfo();
+ /// Deserializes a [ScopeInfo] object from [source].
+ factory ScopeInfo.readFromDataSource(DataSource source) {
+ ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
+ switch (kind) {
+ case ScopeInfoKind.scopeInfo:
+ return new JsScopeInfo.readFromDataSource(source);
+ case ScopeInfoKind.capturedScope:
+ return new JsCapturedScope.readFromDataSource(source);
+ case ScopeInfoKind.capturedLoopScope:
+ return new JsCapturedLoopScope.readFromDataSource(source);
+ case ScopeInfoKind.closureRepresentationInfo:
+ return new KernelClosureClassInfo.readFromDataSource(source);
+ }
+ throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
+ }
+
+ /// Serializes this [ScopeInfo] to [sink].
+ void writeToDataSink(DataSink sink) {
+ throw new UnsupportedError('${runtimeType}.writeToDataSink');
+ }
+
/// Convenience reference pointer to the element representing `this`.
/// If this scope is not in an instance member, it will be null.
Local get thisLocal => null;
@@ -81,6 +121,21 @@
class CapturedScope extends ScopeInfo {
const CapturedScope();
+ /// Deserializes a [CapturedScope] object from [source].
+ factory CapturedScope.readFromDataSource(DataSource source) {
+ ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
+ switch (kind) {
+ case ScopeInfoKind.scopeInfo:
+ case ScopeInfoKind.closureRepresentationInfo:
+ throw new UnsupportedError('Unexpected CapturedScope kind $kind');
+ case ScopeInfoKind.capturedScope:
+ return new JsCapturedScope.readFromDataSource(source);
+ case ScopeInfoKind.capturedLoopScope:
+ return new JsCapturedLoopScope.readFromDataSource(source);
+ }
+ throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
+ }
+
/// If true, this closure accesses a variable that was defined in an outside
/// scope and this variable gets modified at some point (sometimes we say that
/// variable has been "captured"). In this situation, access to this variable
@@ -113,6 +168,20 @@
class CapturedLoopScope extends CapturedScope {
const CapturedLoopScope();
+ /// Deserializes a [CapturedLoopScope] object from [source].
+ factory CapturedLoopScope.readFromDataSource(DataSource source) {
+ ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
+ switch (kind) {
+ case ScopeInfoKind.scopeInfo:
+ case ScopeInfoKind.closureRepresentationInfo:
+ case ScopeInfoKind.capturedScope:
+ throw new UnsupportedError('Unexpected CapturedLoopScope kind $kind');
+ case ScopeInfoKind.capturedLoopScope:
+ return new JsCapturedLoopScope.readFromDataSource(source);
+ }
+ throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
+ }
+
/// True if this loop scope declares in the first part of the loop
/// `for (<here>;...;...)` any variables that need to be boxed.
bool get hasBoxedLoopVariables => false;
@@ -166,6 +235,21 @@
class ClosureRepresentationInfo extends ScopeInfo {
const ClosureRepresentationInfo();
+ /// Deserializes a [ClosureRepresentationInfo] object from [source].
+ factory ClosureRepresentationInfo.readFromDataSource(DataSource source) {
+ ScopeInfoKind kind = source.readEnum(ScopeInfoKind.values);
+ switch (kind) {
+ case ScopeInfoKind.scopeInfo:
+ case ScopeInfoKind.capturedScope:
+ case ScopeInfoKind.capturedLoopScope:
+ throw new UnsupportedError(
+ 'Unexpected ClosureRepresentationInfo kind $kind');
+ case ScopeInfoKind.closureRepresentationInfo:
+ return new KernelClosureClassInfo.readFromDataSource(source);
+ }
+ throw new UnsupportedError('Unexpected ScopeInfoKind $kind');
+ }
+
/// The original local function before any translation.
///
/// Will be null for methods.
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 7f23c57..9140c04 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -360,6 +360,7 @@
void generateJavaScriptCode(
GlobalTypeInferenceResults globalInferenceResults) {
JClosedWorld closedWorld = globalInferenceResults.closedWorld;
+ backendStrategy.registerJClosedWorld(closedWorld);
FunctionEntity mainFunction = closedWorld.elementEnvironment.mainFunction;
reporter.log('Compiling...');
phase = PHASE_COMPILING;
@@ -402,7 +403,7 @@
enqueuer.createCodegenEnqueuer(closedWorld, globalInferenceResults);
_codegenWorldBuilder = codegenEnqueuer.worldBuilder;
codegenEnqueuer.applyImpact(backend.onCodegenStart(
- closedWorld, _codegenWorldBuilder, backendStrategy.sorter));
+ closedWorld, _codegenWorldBuilder, closedWorld.sorter));
return codegenEnqueuer;
}
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 95f65bf..7243452 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -22,6 +22,7 @@
import 'elements/entities.dart';
import 'kernel/kelements.dart' show KLocalFunction;
import 'library_loader.dart';
+import 'serialization/serialization.dart';
import 'universe/use.dart';
import 'universe/world_impact.dart'
show ImpactUseCase, WorldImpact, WorldImpactVisitorImpl;
@@ -1271,6 +1272,10 @@
// TODO(sigmund): consider moving here every piece of data used as a result of
// deferred loading (including hunksToLoad, etc).
class OutputUnitData {
+ /// Tag used for identifying serialized [OutputUnitData] objects in a
+ /// debugging data stream.
+ static const String tag = 'output-unit-data';
+
final bool isProgramSplit;
final OutputUnit mainOutputUnit;
final Map<ClassEntity, OutputUnit> _classToUnit;
@@ -1288,6 +1293,7 @@
this._constantToUnit,
this.outputUnits);
+ // Creates J-world data from the K-world data.
OutputUnitData.from(
OutputUnitData other,
Map<ClassEntity, OutputUnit> Function(
@@ -1305,9 +1311,90 @@
convertMemberMap(other._memberToUnit, other._localFunctionToUnit),
_classToUnit =
convertClassMap(other._classToUnit, other._localFunctionToUnit),
+ // Local functions only make sense in the K-world model.
_localFunctionToUnit = const <Local, OutputUnit>{},
_constantToUnit = convertConstantMap(other._constantToUnit);
+ /// Deserializes an [OutputUnitData] object from [source].
+ factory OutputUnitData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ bool isProgramSplit = source.readBool();
+ List<ImportEntity> imports = source.readList(() {
+ String name = source.readString();
+ Uri uri = source.readUri();
+ Uri enclosingLibraryUri = source.readUri();
+ bool isDeferred = source.readBool();
+ return new ImportEntity(isDeferred, name, uri, enclosingLibraryUri);
+ });
+ List<OutputUnit> outputUnits = source.readList(() {
+ bool isMainOutput = source.readBool();
+ String name = source.readString();
+ Set<ImportEntity> importSet = source.readList(() {
+ return imports[source.readInt()];
+ }).toSet();
+ return new OutputUnit(isMainOutput, name, importSet);
+ });
+ OutputUnit mainOutputUnit = outputUnits[source.readInt()];
+
+ Map<ClassEntity, OutputUnit> classToUnit = source.readClassMap(() {
+ return outputUnits[source.readInt()];
+ });
+ Map<MemberEntity, OutputUnit> memberToUnit = source.readMemberMap(() {
+ return outputUnits[source.readInt()];
+ });
+ Map<ConstantValue, OutputUnit> constantToUnit = source.readConstantMap(() {
+ return outputUnits[source.readInt()];
+ });
+ source.end(tag);
+ return new OutputUnitData(
+ isProgramSplit,
+ mainOutputUnit,
+ classToUnit,
+ memberToUnit,
+ // Local functions only make sense in the K-world model.
+ const <Local, OutputUnit>{},
+ constantToUnit,
+ outputUnits);
+ }
+
+ /// Serializes this [OutputUnitData] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeBool(isProgramSplit);
+ Map<ImportEntity, int> importIndex = {};
+ for (OutputUnit outputUnit in outputUnits) {
+ for (ImportEntity import in outputUnit._imports) {
+ importIndex[import] ??= importIndex.length;
+ }
+ }
+ sink.writeList(importIndex.keys, (ImportEntity import) {
+ sink.writeString(import.name);
+ sink.writeUri(import.uri);
+ sink.writeUri(import.enclosingLibraryUri);
+ sink.writeBool(import.isDeferred);
+ });
+ Map<OutputUnit, int> outputUnitIndices = {};
+ sink.writeList(outputUnits, (OutputUnit outputUnit) {
+ outputUnitIndices[outputUnit] = outputUnitIndices.length;
+ sink.writeBool(outputUnit.isMainOutput);
+ sink.writeString(outputUnit.name);
+ sink.writeList(outputUnit._imports, (ImportEntity import) {
+ sink.writeInt(importIndex[import]);
+ });
+ });
+ sink.writeInt(outputUnitIndices[mainOutputUnit]);
+ sink.writeClassMap(_classToUnit, (OutputUnit outputUnit) {
+ sink.writeInt(outputUnitIndices[outputUnit]);
+ });
+ sink.writeMemberMap(_memberToUnit, (OutputUnit outputUnit) {
+ sink.writeInt(outputUnitIndices[outputUnit]);
+ });
+ sink.writeConstantMap(_constantToUnit, (OutputUnit outputUnit) {
+ sink.writeInt(outputUnitIndices[outputUnit]);
+ });
+ sink.end(tag);
+ }
+
/// Returns the [OutputUnit] where [cls] belongs.
OutputUnit outputUnitForClass(ClassEntity cls) {
if (!isProgramSplit) return mainOutputUnit;
diff --git a/pkg/compiler/lib/src/elements/entities.dart b/pkg/compiler/lib/src/elements/entities.dart
index 2304b62..0adff08 100644
--- a/pkg/compiler/lib/src/elements/entities.dart
+++ b/pkg/compiler/lib/src/elements/entities.dart
@@ -7,6 +7,7 @@
import 'package:front_end/src/api_unstable/dart2js.dart' show AsyncModifier;
import '../common.dart';
+import '../serialization/serialization.dart';
import '../universe/call_structure.dart' show CallStructure;
import '../util/util.dart';
import 'names.dart';
@@ -258,6 +259,10 @@
/// The structure of function parameters.
class ParameterStructure {
+ /// Tag used for identifying serialized [ParameterStructure] objects in a
+ /// debugging data stream.
+ static const String tag = 'parameter-structure';
+
/// The number of required (positional) parameters.
final int requiredParameters;
@@ -285,6 +290,28 @@
type.typeVariables.length);
}
+ /// Deserializes a [ParameterStructure] object from [source].
+ factory ParameterStructure.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ int requiredParameters = source.readInt();
+ int positionalParameters = source.readInt();
+ List<String> namedParameters = source.readStrings();
+ int typeParameters = source.readInt();
+ source.end(tag);
+ return new ParameterStructure(requiredParameters, positionalParameters,
+ namedParameters, typeParameters);
+ }
+
+ /// Serializes this [ParameterStructure] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeInt(requiredParameters);
+ sink.writeInt(positionalParameters);
+ sink.writeStrings(namedParameters);
+ sink.writeInt(typeParameters);
+ sink.end(tag);
+ }
+
/// The number of optional parameters (positional or named).
int get optionalParameters =>
positionalParameters - requiredParameters + namedParameters.length;
diff --git a/pkg/compiler/lib/src/elements/indexed.dart b/pkg/compiler/lib/src/elements/indexed.dart
index f20a4ffab..56defb0 100644
--- a/pkg/compiler/lib/src/elements/indexed.dart
+++ b/pkg/compiler/lib/src/elements/indexed.dart
@@ -53,12 +53,16 @@
/// Base implementation for an index based map of entities of type [E].
abstract class EntityMapBase<E extends _Indexed> {
+ int _size = 0;
List<E> _list = <E>[];
/// Returns the [index]th entity in the map.
E getEntity(int index) => _list[index];
- /// Returns the number entities in the map.
+ /// Returns the number of non-null entities in the map.
+ int get size => _size;
+
+ /// Returns the number (null and non-null) entities in the map.
int get length => _list.length;
}
@@ -73,8 +77,26 @@
assert(entity._index == null);
entity._index = _list.length;
_list.add(entity);
+ _size++;
return entity;
}
+
+ /// Registers a new [entity] by the given [index].
+ E0 registerByIndex<E0 extends E>(int index, E0 entity) {
+ assert(index >= _list.length);
+ _list.length = index;
+ return register(entity);
+ }
+
+ /// Calls [f] for each non-null entity.
+ void forEach<E0 extends E>(void f(E0 entity)) {
+ for (int index = 0; index < _list.length; index++) {
+ E entity = _list[index];
+ if (entity != null) {
+ f(entity);
+ }
+ }
+ }
}
/// Base implementation of an index based map of entities of type [E] with a
@@ -86,7 +108,7 @@
/// Returns the data object stored for the [index]th entity.
D getData(E entity) {
int index = entity._index;
- if (index < length && index >= _data.length) {
+ if (index < _list.length && index >= _data.length) {
throw new StateError(
'Data is in the process of being created for ${_list[index]}.');
}
@@ -111,12 +133,39 @@
E0 register<E0 extends E, D0 extends D>(E0 entity, D0 data) {
assert(entity != null);
assert(entity._index == null);
+ assert(
+ _list.length == _data.length,
+ 'Data list length ${_data.length} inconsistent '
+ 'with entity list length ${_list.length}.');
entity._index = _list.length;
_list.add(entity);
+ _size++;
assert(data != null);
_data.add(data);
return entity;
}
+
+ /// Registers a new [entity] with an associated [data] object by the given
+ /// [index].
+ E0 registerByIndex<E0 extends E, D0 extends D>(
+ int index, E0 entity, D0 data) {
+ assert(index >= _list.length);
+ _list.length = _data.length = index;
+ return register(entity, data);
+ }
+
+ /// Calls [f] for each non-null entity with its corresponding data object.
+ void forEach<E0 extends E, D0 extends D>(void f(E0 entity, D0 data)) {
+ if (_list.length != _data.length) {
+ throw new StateError('Data is in the process of being created.');
+ }
+ for (int index = 0; index < _list.length; index++) {
+ E entity = _list[index];
+ if (entity != null) {
+ f(entity, _data[index]);
+ }
+ }
+ }
}
/// Base implementation for an index based of entities of type [E] with a
@@ -128,7 +177,7 @@
/// Returns the environment object stored for the [index]th entity.
V getEnv(E entity) {
int index = entity._index;
- if (index < length && index >= _env.length) {
+ if (index < _list.length && index >= _env.length) {
throw new StateError(
'Env is in the process of being created for ${_list[index]}.');
}
@@ -149,12 +198,48 @@
E0 entity, D0 data, V0 env) {
assert(entity != null);
assert(entity._index == null);
+ assert(
+ _list.length == _data.length,
+ 'Data list length ${_data.length} inconsistent '
+ 'with entity list length ${_list.length}.');
+ assert(
+ _list.length == _env.length,
+ 'Env list length ${_env.length} inconsistent '
+ 'with entity list length ${_list.length}.');
entity._index = _list.length;
_list.add(entity);
+ _size++;
assert(data != null);
_data.add(data);
assert(env != null);
_env.add(env);
return entity;
}
+
+ /// Registers a new [entity] with an associated [data] object and environment
+ /// [env] by the given [index].
+ E0 registerByIndex<E0 extends E, D0 extends D, V0 extends V>(
+ int index, E0 entity, D0 data, V0 env) {
+ assert(index >= _list.length);
+ _list.length = _data.length = _env.length = index;
+ return register(entity, data, env);
+ }
+
+ /// Calls [f] for each non-null entity with its corresponding data object and
+ /// environment.
+ void forEach<E0 extends E, D0 extends D, V0 extends V>(
+ void f(E0 entity, D0 data, V0 env)) {
+ if (_list.length != _data.length) {
+ throw new StateError('Data is in the process of being created.');
+ }
+ if (_list.length != _env.length) {
+ throw new StateError('Env is in the process of being created.');
+ }
+ for (int index = 0; index < _list.length; index++) {
+ E entity = _list[index];
+ if (entity != null) {
+ f(entity, _data[index], _env[index]);
+ }
+ }
+ }
}
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
index c608983..5ce0f07 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_engine.dart
@@ -16,12 +16,12 @@
import '../elements/types.dart';
import '../js_backend/inferred_data.dart';
import '../js_backend/no_such_method_registry.dart';
-import '../js_emitter/sorter.dart';
import '../js_model/element_map.dart';
import '../js_model/js_strategy.dart';
import '../js_model/locals.dart';
import '../native/behavior.dart' as native;
import '../options.dart';
+import '../serialization/serialization.dart';
import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../universe/call_structure.dart';
@@ -288,8 +288,6 @@
final NoSuchMethodRegistry noSuchMethodRegistry;
- final Sorter sorter;
-
InferrerEngineImpl(
this.options,
this.progress,
@@ -298,7 +296,6 @@
this.closedWorld,
this.noSuchMethodRegistry,
this.mainElement,
- this.sorter,
this.inferredDataBuilder)
: this.types = new TypeSystem(
closedWorld, new KernelTypeSystemStrategy(closedWorld));
@@ -1365,6 +1362,10 @@
class KernelGlobalTypeInferenceElementData
implements GlobalTypeInferenceElementData {
+ /// Tag used for identifying serialized [GlobalTypeInferenceElementData]
+ /// objects in a debugging data stream.
+ static const String tag = 'global-type-inference-element-data';
+
// TODO(johnniwinther): Rename this together with [typeOfSend].
Map<ir.TreeNode, AbstractValue> _sendMap;
@@ -1372,6 +1373,86 @@
Map<ir.ForInStatement, AbstractValue> _currentMap;
Map<ir.ForInStatement, AbstractValue> _moveNextMap;
+ KernelGlobalTypeInferenceElementData();
+
+ KernelGlobalTypeInferenceElementData.internal(
+ this._sendMap, this._iteratorMap, this._currentMap, this._moveNextMap);
+
+ /// Deserializes a [GlobalTypeInferenceElementData] object from [source].
+ factory KernelGlobalTypeInferenceElementData.readFromDataSource(
+ DataSource source, AbstractValueDomain abstractValueDomain) {
+ source.begin(tag);
+ Map<ir.TreeNode, AbstractValue> sendMap = source.readTreeNodeMap(
+ () => abstractValueDomain.readAbstractValueFromDataSource(source),
+ emptyAsNull: true);
+ Map<ir.ForInStatement, AbstractValue> iteratorMap = source.readTreeNodeMap(
+ () => abstractValueDomain.readAbstractValueFromDataSource(source),
+ emptyAsNull: true);
+ Map<ir.ForInStatement, AbstractValue> currentMap = source.readTreeNodeMap(
+ () => abstractValueDomain.readAbstractValueFromDataSource(source),
+ emptyAsNull: true);
+ Map<ir.ForInStatement, AbstractValue> moveNextMap = source.readTreeNodeMap(
+ () => abstractValueDomain.readAbstractValueFromDataSource(source),
+ emptyAsNull: true);
+ source.end(tag);
+ return new KernelGlobalTypeInferenceElementData.internal(
+ sendMap, iteratorMap, currentMap, moveNextMap);
+ }
+
+ /// Serializes this [GlobalTypeInferenceElementData] to [sink].
+ void writeToDataSink(DataSink sink, AbstractValueDomain abstractValueDomain) {
+ sink.begin(tag);
+ sink.writeTreeNodeMap(
+ _sendMap,
+ (AbstractValue value) =>
+ abstractValueDomain.writeAbstractValueToDataSink(sink, value),
+ allowNull: true);
+ sink.writeTreeNodeMap(
+ _iteratorMap,
+ (AbstractValue value) =>
+ abstractValueDomain.writeAbstractValueToDataSink(sink, value),
+ allowNull: true);
+ sink.writeTreeNodeMap(
+ _currentMap,
+ (AbstractValue value) =>
+ abstractValueDomain.writeAbstractValueToDataSink(sink, value),
+ allowNull: true);
+ sink.writeTreeNodeMap(
+ _moveNextMap,
+ (AbstractValue value) =>
+ abstractValueDomain.writeAbstractValueToDataSink(sink, value),
+ allowNull: true);
+ sink.end(tag);
+ }
+
+ @override
+ void compress() {
+ if (_sendMap != null) {
+ _sendMap.removeWhere(_mapsToNull);
+ if (_sendMap.isEmpty) {
+ _sendMap = null;
+ }
+ }
+ if (_iteratorMap != null) {
+ _iteratorMap.removeWhere(_mapsToNull);
+ if (_iteratorMap.isEmpty) {
+ _iteratorMap = null;
+ }
+ }
+ if (_currentMap != null) {
+ _currentMap.removeWhere(_mapsToNull);
+ if (_currentMap.isEmpty) {
+ _currentMap = null;
+ }
+ }
+ if (_moveNextMap != null) {
+ _moveNextMap.removeWhere(_mapsToNull);
+ if (_moveNextMap.isEmpty) {
+ _moveNextMap = null;
+ }
+ }
+ }
+
@override
AbstractValue typeOfSend(ir.TreeNode node) {
if (_sendMap == null) return null;
@@ -1429,3 +1510,5 @@
return _sendMap[node];
}
}
+
+bool _mapsToNull(ir.TreeNode node, AbstractValue value) => value == null;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 827f0f4..c8c20c2 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -79,7 +79,6 @@
closedWorld,
_compiler.backend.noSuchMethodRegistry,
main,
- _compiler.backendStrategy.sorter,
_inferredDataBuilder);
}
@@ -109,6 +108,7 @@
void createMemberResults(
MemberEntity member, MemberTypeInformation typeInformation) {
GlobalTypeInferenceElementData data = inferrer.dataOfMember(member);
+ data.compress();
bool isJsInterop = closedWorld.nativeData.isJsInteropMember(member);
AbstractValue returnType;
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
index a0280dc..4b27265 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/container_type_mask.dart
@@ -8,6 +8,10 @@
/// site of a container (currently only List) that will get specialized
/// once the [TypeGraphInferrer] phase finds an element type for it.
class ContainerTypeMask extends AllocationTypeMask {
+ /// Tag used for identifying serialized [ContainerTypeMask] objects in a
+ /// debugging data stream.
+ static const String tag = 'container-type-mask';
+
final TypeMask forwardTo;
// The [Node] where this type mask was created.
@@ -25,6 +29,32 @@
ContainerTypeMask(this.forwardTo, this.allocationNode, this.allocationElement,
this.elementType, this.length);
+ /// Deserializes a [ContainerTypeMask] object from [source].
+ factory ContainerTypeMask.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ source.begin(tag);
+ TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
+ ir.TreeNode allocationNode = source.readTreeNodeOrNull();
+ MemberEntity allocationElement = source.readMemberOrNull();
+ TypeMask elementType = new TypeMask.readFromDataSource(source, closedWorld);
+ int length = source.readIntOrNull();
+ source.end(tag);
+ return new ContainerTypeMask(
+ forwardTo, allocationNode, allocationElement, elementType, length);
+ }
+
+ /// Serializes this [ContainerTypeMask] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(TypeMaskKind.container);
+ sink.begin(tag);
+ forwardTo.writeToDataSink(sink);
+ sink.writeTreeNodeOrNull(allocationNode);
+ sink.writeMemberOrNull(allocationElement);
+ elementType.writeToDataSink(sink);
+ sink.writeIntOrNull(length);
+ sink.end(tag);
+ }
+
TypeMask nullable() {
return isNullable
? this
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
index c6e3950..9a64845 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/dictionary_type_mask.dart
@@ -13,6 +13,10 @@
* the more general [MapTypeMask] is used.
*/
class DictionaryTypeMask extends MapTypeMask {
+ /// Tag used for identifying serialized [DictionaryTypeMask] objects in a
+ /// debugging data stream.
+ static const String tag = 'dictionary-type-mask';
+
// The underlying key/value map of this dictionary.
final Map<String, AbstractValue> _typeMap;
@@ -25,6 +29,38 @@
this._typeMap)
: super(forwardTo, allocationNode, allocationElement, keyType, valueType);
+ /// Deserializes a [DictionaryTypeMask] object from [source].
+ factory DictionaryTypeMask.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ source.begin(tag);
+ TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
+ ir.TreeNode allocationNode = source.readTreeNode();
+ MemberEntity allocationElement = source.readMember();
+ TypeMask keyType = new TypeMask.readFromDataSource(source, closedWorld);
+ TypeMask valueType = new TypeMask.readFromDataSource(source, closedWorld);
+ Map<String, AbstractValue> typeMap = source.readStringMap(
+ () => new TypeMask.readFromDataSource(source, closedWorld));
+ source.end(tag);
+ return new DictionaryTypeMask(forwardTo, allocationNode, allocationElement,
+ keyType, valueType, typeMap);
+ }
+
+ /// Serializes this [DictionaryTypeMask] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(TypeMaskKind.dictionary);
+ sink.begin(tag);
+ forwardTo.writeToDataSink(sink);
+ sink.writeTreeNode(allocationNode);
+ sink.writeMember(allocationElement);
+ valueType.writeToDataSink(sink);
+ keyType.writeToDataSink(sink);
+ sink.writeStringMap(_typeMap, (AbstractValue value) {
+ TypeMask typeMask = value;
+ typeMask.writeToDataSink(sink);
+ });
+ sink.end(tag);
+ }
+
TypeMask nullable() {
return isNullable
? this
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
index 20150d5..c74600a 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
@@ -9,6 +9,10 @@
* base type.
*/
class FlatTypeMask implements TypeMask {
+ /// Tag used for identifying serialized [FlatTypeMask] objects in a
+ /// debugging data stream.
+ static const String tag = 'flat-type-mask';
+
static const int EMPTY = 0;
static const int EXACT = 1;
static const int SUBCLASS = 2;
@@ -39,10 +43,6 @@
FlatTypeMask.nonNullSubtype(ClassEntity base)
: this.internal(base, SUBTYPE << 1);
- ClassQuery get _classQuery => isExact
- ? ClassQuery.EXACT
- : (isSubclass ? ClassQuery.SUBCLASS : ClassQuery.SUBTYPE);
-
FlatTypeMask.internal(this.base, this.flags);
/**
@@ -69,6 +69,31 @@
base, flags, () => new FlatTypeMask.internal(base, flags));
}
+ /// Deserializes a [FlatTypeMask] object from [source].
+ factory FlatTypeMask.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ source.begin(tag);
+ ClassEntity base = source.readClassOrNull();
+ int flags = source.readInt();
+ source.end(tag);
+ CommonMasks commonMasks = closedWorld.abstractValueDomain;
+ return commonMasks.getCachedMask(
+ base, flags, () => new FlatTypeMask.internal(base, flags));
+ }
+
+ /// Serializes this [FlatTypeMask] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(TypeMaskKind.flat);
+ sink.begin(tag);
+ sink.writeClassOrNull(base);
+ sink.writeInt(flags);
+ sink.end(tag);
+ }
+
+ ClassQuery get _classQuery => isExact
+ ? ClassQuery.EXACT
+ : (isSubclass ? ClassQuery.SUBCLASS : ClassQuery.SUBTYPE);
+
bool get isEmpty => isEmptyOrNull && !isNullable;
bool get isNull => isEmptyOrNull && isNullable;
bool get isEmptyOrNull => (flags >> 1) == EMPTY;
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
index f7b2866..5e6e2fb 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/map_type_mask.dart
@@ -10,6 +10,10 @@
* once the [TypeGraphInferrer] phase finds a key and/or value type for it.
*/
class MapTypeMask extends AllocationTypeMask {
+ /// Tag used for identifying serialized [MapTypeMask] objects in a
+ /// debugging data stream.
+ static const String tag = 'map-type-mask';
+
final TypeMask forwardTo;
// The [Node] where this type mask was created.
@@ -27,6 +31,32 @@
MapTypeMask(this.forwardTo, this.allocationNode, this.allocationElement,
this.keyType, this.valueType);
+ /// Deserializes a [MapTypeMask] object from [source].
+ factory MapTypeMask.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ source.begin(tag);
+ TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
+ ir.TreeNode allocationNode = source.readTreeNode();
+ MemberEntity allocationElement = source.readMember();
+ TypeMask keyType = new TypeMask.readFromDataSource(source, closedWorld);
+ TypeMask valueType = new TypeMask.readFromDataSource(source, closedWorld);
+ source.end(tag);
+ return new MapTypeMask(
+ forwardTo, allocationNode, allocationElement, keyType, valueType);
+ }
+
+ /// Serializes this [MapTypeMask] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(TypeMaskKind.map);
+ sink.begin(tag);
+ forwardTo.writeToDataSink(sink);
+ sink.writeTreeNode(allocationNode);
+ sink.writeMember(allocationElement);
+ valueType.writeToDataSink(sink);
+ keyType.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
TypeMask nullable() {
return isNullable
? this
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index 5b0e920..6987117 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -8,8 +8,9 @@
import '../../common.dart';
import '../../common_elements.dart' show CommonElements;
-import '../../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
+import '../../constants/values.dart';
import '../../elements/entities.dart';
+import '../../serialization/serialization.dart';
import '../../types/abstract_value_domain.dart';
import '../../universe/class_hierarchy.dart';
import '../../universe/selector.dart' show Selector;
@@ -718,6 +719,16 @@
String getCompactText(AbstractValue value) {
return formatType(value);
}
+
+ @override
+ TypeMask readAbstractValueFromDataSource(DataSource source) {
+ return new TypeMask.readFromDataSource(source, _closedWorld);
+ }
+
+ @override
+ void writeAbstractValueToDataSink(DataSink sink, covariant TypeMask value) {
+ value.writeToDataSink(sink);
+ }
}
/// Convert the given TypeMask to a compact string format.
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
index 225f21c..a08d320 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/type_mask.dart
@@ -91,6 +91,16 @@
}
}
+/// Enum used for identifying [TypeMask] subclasses in serialization.
+enum TypeMaskKind {
+ flat,
+ union,
+ container,
+ map,
+ dictionary,
+ value,
+}
+
/**
* A type mask represents a set of contained classes, but the
* operations on it are not guaranteed to be precise and they may
@@ -209,6 +219,30 @@
return UnionTypeMask.unionOf(masks, closedWorld);
}
+ /// Deserializes a [TypeMask] object from [source].
+ factory TypeMask.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ TypeMaskKind kind = source.readEnum(TypeMaskKind.values);
+ switch (kind) {
+ case TypeMaskKind.flat:
+ return new FlatTypeMask.readFromDataSource(source, closedWorld);
+ case TypeMaskKind.union:
+ return new UnionTypeMask.readFromDataSource(source, closedWorld);
+ case TypeMaskKind.container:
+ return new ContainerTypeMask.readFromDataSource(source, closedWorld);
+ case TypeMaskKind.map:
+ return new MapTypeMask.readFromDataSource(source, closedWorld);
+ case TypeMaskKind.dictionary:
+ return new DictionaryTypeMask.readFromDataSource(source, closedWorld);
+ case TypeMaskKind.value:
+ return new ValueTypeMask.readFromDataSource(source, closedWorld);
+ }
+ throw new UnsupportedError("Unexpected TypeMaskKind $kind.");
+ }
+
+ /// Serializes this [TypeMask] to [sink].
+ void writeToDataSink(DataSink sink);
+
/**
* If [mask] is forwarding, returns the first non-forwarding [TypeMask] in
* [mask]'s forwarding chain.
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
index 0da519c..aba7ea6 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/union_type_mask.dart
@@ -5,7 +5,9 @@
part of masks;
class UnionTypeMask implements TypeMask {
- final Iterable<FlatTypeMask> disjointMasks;
+ /// Tag used for identifying serialized [UnionTypeMask] objects in a
+ /// debugging data stream.
+ static const String tag = 'union-type-mask';
static const int MAX_UNION_LENGTH = 4;
@@ -14,11 +16,32 @@
// helpful in debugging.
static const bool PERFORM_EXTRA_CONTAINS_CHECK = false;
+ final Iterable<FlatTypeMask> disjointMasks;
+
UnionTypeMask._internal(this.disjointMasks) {
assert(disjointMasks.length > 1);
assert(disjointMasks.every((TypeMask mask) => !mask.isUnion));
}
+ /// Deserializes a [UnionTypeMask] object from [source].
+ factory UnionTypeMask.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ source.begin(tag);
+ List<FlatTypeMask> disjointMasks = source
+ .readList(() => new TypeMask.readFromDataSource(source, closedWorld));
+ source.end(tag);
+ return new UnionTypeMask._internal(disjointMasks);
+ }
+
+ /// Serializes this [UnionTypeMask] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(TypeMaskKind.union);
+ sink.begin(tag);
+ sink.writeList(
+ disjointMasks, (FlatTypeMask mask) => mask.writeToDataSink(sink));
+ sink.end(tag);
+ }
+
static TypeMask unionOf(Iterable<TypeMask> masks, JClosedWorld closedWorld) {
assert(
masks.every((mask) => TypeMask.assertIsNormalized(mask, closedWorld)));
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/value_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/value_type_mask.dart
index ebeda52..45c1300 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/value_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/value_type_mask.dart
@@ -5,11 +5,34 @@
part of masks;
class ValueTypeMask extends ForwardingTypeMask {
+ /// Tag used for identifying serialized [ValueTypeMask] objects in a
+ /// debugging data stream.
+ static const String tag = 'value-type-mask';
+
final TypeMask forwardTo;
final PrimitiveConstantValue value;
ValueTypeMask(this.forwardTo, this.value);
+ /// Deserializes a [ValueTypeMask] object from [source].
+ factory ValueTypeMask.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ source.begin(tag);
+ TypeMask forwardTo = new TypeMask.readFromDataSource(source, closedWorld);
+ ConstantValue constant = source.readConstant();
+ source.end(tag);
+ return new ValueTypeMask(forwardTo, constant);
+ }
+
+ /// Serializes this [ValueTypeMask] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(TypeMaskKind.value);
+ sink.begin(tag);
+ forwardTo.writeToDataSink(sink);
+ sink.writeConstant(value);
+ sink.end(tag);
+ }
+
TypeMask nullable() {
return isNullable ? this : new ValueTypeMask(forwardTo.nullable(), value);
}
diff --git a/pkg/compiler/lib/src/js_backend/allocator_analysis.dart b/pkg/compiler/lib/src/js_backend/allocator_analysis.dart
index 7415322..6e15c77 100644
--- a/pkg/compiler/lib/src/js_backend/allocator_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/allocator_analysis.dart
@@ -10,6 +10,7 @@
import '../kernel/kernel_strategy.dart';
import '../kernel/kelements.dart' show KClass, KField;
import '../options.dart';
+import '../serialization/serialization.dart';
abstract class AllocatorAnalysis {}
@@ -70,6 +71,10 @@
}
class JAllocatorAnalysis implements AllocatorAnalysis {
+ /// Tag used for identifying serialized [JAllocatorAnalysis] objects in a
+ /// debugging data stream.
+ static const String tag = 'allocator-analysis';
+
// --csp and --fast-startup have different constraints to the generated code.
final CompilerOptions _options;
final Map<JField, ConstantValue> _fixedInitializers =
@@ -77,6 +82,34 @@
JAllocatorAnalysis._(this._options);
+ /// Deserializes a [JAllocatorAnalysis] object from [source].
+ factory JAllocatorAnalysis.readFromDataSource(
+ DataSource source, CompilerOptions options) {
+ source.begin(tag);
+ JAllocatorAnalysis analysis = new JAllocatorAnalysis._(options);
+ int fieldCount = source.readInt();
+ for (int i = 0; i < fieldCount; i++) {
+ JField field = source.readMember();
+ // TODO(sra): Deserialize constant, when non-null is supported.
+ ConstantValue value = const NullConstantValue();
+ analysis._fixedInitializers[field] = value;
+ }
+ source.end(tag);
+ return analysis;
+ }
+
+ /// Serializes this [JAllocatorAnalysis] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeInt(_fixedInitializers.length);
+ _fixedInitializers.forEach((JField field, ConstantValue value) {
+ sink.writeMember(field);
+ // TODO(sra): Serialize constant, when non-null is supported.
+ assert(value.isNull);
+ });
+ sink.end(tag);
+ }
+
static JAllocatorAnalysis from(KAllocatorAnalysis kAnalysis,
JsToFrontendMap map, CompilerOptions options) {
var result = new JAllocatorAnalysis._(options);
diff --git a/pkg/compiler/lib/src/js_backend/annotations.dart b/pkg/compiler/lib/src/js_backend/annotations.dart
index 5f66d8f..025f6d8 100644
--- a/pkg/compiler/lib/src/js_backend/annotations.dart
+++ b/pkg/compiler/lib/src/js_backend/annotations.dart
@@ -10,6 +10,7 @@
import '../diagnostics/messages.dart';
import '../elements/entities.dart';
import '../native/native.dart' as native;
+import '../serialization/serialization.dart';
/// Returns `true` if parameter and returns types should be trusted for
/// [element].
@@ -179,6 +180,13 @@
}
abstract class AnnotationsData {
+ /// Deserializes a [AnnotationsData] object from [source].
+ factory AnnotationsData.readFromDataSource(DataSource source) =
+ AnnotationsDataImpl.readFromDataSource;
+
+ /// Serializes this [AnnotationsData] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Functions with a `@NoInline()` or `@noInline` annotation.
Iterable<FunctionEntity> get nonInlinableFunctions;
@@ -199,6 +207,10 @@
}
class AnnotationsDataImpl implements AnnotationsData {
+ /// Tag used for identifying serialized [AnnotationsData] objects in a
+ /// debugging data stream.
+ static const String tag = 'annotations-data';
+
final Iterable<FunctionEntity> nonInlinableFunctions;
final Iterable<FunctionEntity> tryInlineFunctions;
final Iterable<FunctionEntity> cannotThrowFunctions;
@@ -213,6 +225,35 @@
this.sideEffectFreeFunctions,
this.trustTypeAnnotationsMembers,
this.assumeDynamicMembers);
+
+ factory AnnotationsDataImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Iterable<FunctionEntity> nonInlinableFunctions = source.readMembers();
+ Iterable<FunctionEntity> tryInlineFunctions = source.readMembers();
+ Iterable<FunctionEntity> cannotThrowFunctions = source.readMembers();
+ Iterable<FunctionEntity> sideEffectFreeFunctions = source.readMembers();
+ Iterable<MemberEntity> trustTypeAnnotationsMembers = source.readMembers();
+ Iterable<MemberEntity> assumeDynamicMembers = source.readMembers();
+ source.end(tag);
+ return new AnnotationsDataImpl(
+ nonInlinableFunctions,
+ tryInlineFunctions,
+ cannotThrowFunctions,
+ sideEffectFreeFunctions,
+ trustTypeAnnotationsMembers,
+ assumeDynamicMembers);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeMembers(nonInlinableFunctions);
+ sink.writeMembers(tryInlineFunctions);
+ sink.writeMembers(cannotThrowFunctions);
+ sink.writeMembers(sideEffectFreeFunctions);
+ sink.writeMembers(trustTypeAnnotationsMembers);
+ sink.writeMembers(assumeDynamicMembers);
+ sink.end(tag);
+ }
}
class AnnotationsDataBuilder implements AnnotationsData {
@@ -255,4 +296,8 @@
Iterable<MemberEntity> get trustTypeAnnotationsMembers =>
_trustTypeAnnotationsMembers;
Iterable<MemberEntity> get assumeDynamicMembers => _assumeDynamicMembers;
+
+ void writeToDataSink(DataSink sink) {
+ throw new UnsupportedError('AnnotationsDataBuilder.writeToDataSink');
+ }
}
diff --git a/pkg/compiler/lib/src/js_backend/backend_usage.dart b/pkg/compiler/lib/src/js_backend/backend_usage.dart
index b3e02ac..efe00d9 100644
--- a/pkg/compiler/lib/src/js_backend/backend_usage.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_usage.dart
@@ -7,11 +7,19 @@
import '../elements/entities.dart';
import '../elements/types.dart';
import '../frontend_strategy.dart';
+import '../serialization/serialization.dart';
import '../universe/feature.dart';
import '../util/util.dart' show Setlet;
import 'backend_impact.dart';
abstract class BackendUsage {
+ /// Deserializes a [BackendUsage] object from [source].
+ factory BackendUsage.readFromDataSource(DataSource source) =
+ BackendUsageImpl.readFromDataSource;
+
+ /// Serializes this [BackendUsage] to [sink].
+ void writeToDataSink(DataSink sink);
+
bool needToInitializeIsolateAffinityTag;
bool needToInitializeDispatchProperty;
@@ -262,6 +270,10 @@
}
class BackendUsageImpl implements BackendUsage {
+ /// Tag used for identifying serialized [BackendUsage] objects in a
+ /// debugging data stream.
+ static const String tag = 'backend-usage';
+
// TODO(johnniwinther): Remove the need for these.
final Set<FunctionEntity> _globalFunctionDependencies;
final Set<ClassEntity> _globalClassDependencies;
@@ -307,6 +319,61 @@
this._helperClassesUsed = helperClassesUsed,
this._runtimeTypeUses = runtimeTypeUses;
+ factory BackendUsageImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Set<FunctionEntity> globalFunctionDependencies =
+ source.readMembers<FunctionEntity>().toSet();
+ Set<ClassEntity> globalClassDependencies = source.readClasses().toSet();
+ Set<FunctionEntity> helperFunctionsUsed =
+ source.readMembers<FunctionEntity>().toSet();
+ Set<ClassEntity> helperClassesUsed = source.readClasses().toSet();
+ Set<RuntimeTypeUse> runtimeTypeUses = source.readList(() {
+ RuntimeTypeUseKind kind = source.readEnum(RuntimeTypeUseKind.values);
+ DartType receiverType = source.readDartType();
+ DartType argumentType = source.readDartType(allowNull: true);
+ return new RuntimeTypeUse(kind, receiverType, argumentType);
+ }).toSet();
+ bool needToInitializeIsolateAffinityTag = source.readBool();
+ bool needToInitializeDispatchProperty = source.readBool();
+ bool requiresPreamble = source.readBool();
+ bool isFunctionApplyUsed = source.readBool();
+ bool isMirrorsUsed = source.readBool();
+ bool isNoSuchMethodUsed = source.readBool();
+ source.end(tag);
+ return new BackendUsageImpl(
+ globalFunctionDependencies: globalFunctionDependencies,
+ globalClassDependencies: globalClassDependencies,
+ helperFunctionsUsed: helperFunctionsUsed,
+ helperClassesUsed: helperClassesUsed,
+ runtimeTypeUses: runtimeTypeUses,
+ needToInitializeIsolateAffinityTag: needToInitializeIsolateAffinityTag,
+ needToInitializeDispatchProperty: needToInitializeDispatchProperty,
+ requiresPreamble: requiresPreamble,
+ isFunctionApplyUsed: isFunctionApplyUsed,
+ isMirrorsUsed: isMirrorsUsed,
+ isNoSuchMethodUsed: isNoSuchMethodUsed);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeMembers(_globalFunctionDependencies);
+ sink.writeClasses(_globalClassDependencies);
+ sink.writeMembers(_helperFunctionsUsed);
+ sink.writeClasses(_helperClassesUsed);
+ sink.writeList(runtimeTypeUses, (RuntimeTypeUse runtimeTypeUse) {
+ sink.writeEnum(runtimeTypeUse.kind);
+ sink.writeDartType(runtimeTypeUse.receiverType);
+ sink.writeDartType(runtimeTypeUse.argumentType, allowNull: true);
+ });
+ sink.writeBool(needToInitializeIsolateAffinityTag);
+ sink.writeBool(needToInitializeDispatchProperty);
+ sink.writeBool(requiresPreamble);
+ sink.writeBool(isFunctionApplyUsed);
+ sink.writeBool(isMirrorsUsed);
+ sink.writeBool(isNoSuchMethodUsed);
+ sink.end(tag);
+ }
+
@override
bool isFunctionUsedByBackend(FunctionEntity element) {
return _helperFunctionsUsed.contains(element);
diff --git a/pkg/compiler/lib/src/js_backend/inferred_data.dart b/pkg/compiler/lib/src/js_backend/inferred_data.dart
index 1f1f272..73bb493 100644
--- a/pkg/compiler/lib/src/js_backend/inferred_data.dart
+++ b/pkg/compiler/lib/src/js_backend/inferred_data.dart
@@ -6,6 +6,7 @@
import '../common.dart';
import '../elements/entities.dart';
+import '../serialization/serialization.dart';
import '../types/abstract_value_domain.dart';
import '../universe/selector.dart';
import '../universe/side_effects.dart';
@@ -13,6 +14,20 @@
import 'annotations.dart';
abstract class InferredData {
+ /// Deserializes a [InferredData] object from [source].
+ factory InferredData.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ bool isTrivial = source.readBool();
+ if (isTrivial) {
+ return new TrivialInferredData();
+ } else {
+ return new InferredDataImpl.readFromDataSource(source, closedWorld);
+ }
+ }
+
+ /// Serializes this [InferredData] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Returns the side effects of executing [element].
SideEffects getSideEffectsOfElement(FunctionEntity element);
@@ -62,6 +77,10 @@
}
class InferredDataImpl implements InferredData {
+ /// Tag used for identifying serialized [InferredData] objects in a
+ /// debugging data stream.
+ static const String tag = 'inferred-data';
+
final JClosedWorld _closedWorld;
final Set<MemberEntity> _functionsCalledInLoop;
final Map<FunctionEntity, SideEffects> _sideEffects;
@@ -80,6 +99,40 @@
this._elementsThatCannotThrow,
this._functionsThatMightBePassedToApply);
+ factory InferredDataImpl.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld) {
+ source.begin(tag);
+ Set<MemberEntity> functionsCalledInLoop = source.readMembers().toSet();
+ Map<FunctionEntity, SideEffects> sideEffects =
+ source.readMemberMap(() => new SideEffects.readFromDataSource(source));
+ Set<FunctionEntity> sideEffectsFreeElements =
+ source.readMembers<FunctionEntity>().toSet();
+ Set<FunctionEntity> elementsThatCannotThrow =
+ source.readMembers<FunctionEntity>().toSet();
+ Set<FunctionEntity> functionsThatMightBePassedToApply =
+ source.readMembers<FunctionEntity>().toSet();
+ source.end(tag);
+ return new InferredDataImpl(
+ closedWorld,
+ functionsCalledInLoop,
+ sideEffects,
+ sideEffectsFreeElements,
+ elementsThatCannotThrow,
+ functionsThatMightBePassedToApply);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeBool(false); // Is _not_ trivial.
+ sink.begin(tag);
+ sink.writeMembers(_functionsCalledInLoop);
+ sink.writeMemberMap(_sideEffects,
+ (SideEffects sideEffects) => sideEffects.writeToDataSink(sink));
+ sink.writeMembers(_sideEffectsFreeElements);
+ sink.writeMembers(_elementsThatCannotThrow);
+ sink.writeMembers(_functionsThatMightBePassedToApply);
+ sink.end(tag);
+ }
+
@override
SideEffects getSideEffectsOfSelector(
Selector selector, AbstractValue receiver) {
@@ -251,6 +304,11 @@
final SideEffects _allSideEffects = new SideEffects();
@override
+ void writeToDataSink(DataSink sink) {
+ sink.writeBool(true); // Is trivial.
+ }
+
+ @override
SideEffects getSideEffectsOfElement(FunctionEntity element) {
return _allSideEffects;
}
diff --git a/pkg/compiler/lib/src/js_backend/interceptor_data.dart b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
index f4db4d7..833c7c7 100644
--- a/pkg/compiler/lib/src/js_backend/interceptor_data.dart
+++ b/pkg/compiler/lib/src/js_backend/interceptor_data.dart
@@ -10,6 +10,7 @@
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js/js.dart' as jsAst;
+import '../serialization/serialization.dart';
import '../types/abstract_value_domain.dart';
import '../universe/selector.dart';
import '../world.dart' show JClosedWorld;
@@ -17,6 +18,15 @@
import 'native_data.dart';
abstract class InterceptorData {
+ /// Deserializes a [InterceptorData] object from [source].
+ factory InterceptorData.readFromDataSource(
+ DataSource source,
+ NativeData nativeData,
+ CommonElements commonElements) = InterceptorDataImpl.readFromDataSource;
+
+ /// Serializes this [InterceptorData] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Returns `true` if [cls] is an intercepted class.
bool isInterceptedClass(ClassEntity element);
@@ -49,6 +59,10 @@
}
class InterceptorDataImpl implements InterceptorData {
+ /// Tag used for identifying serialized [InterceptorData] objects in a
+ /// debugging data stream.
+ static const String tag = 'interceptor-data';
+
final NativeBasicData _nativeData;
final CommonElements _commonElements;
@@ -89,6 +103,40 @@
this.interceptedClasses,
this.classesMixedIntoInterceptedClasses);
+ factory InterceptorDataImpl.readFromDataSource(
+ DataSource source, NativeData nativeData, CommonElements commonElements) {
+ source.begin(tag);
+ int interceptedMembersCount = source.readInt();
+ Map<String, Set<MemberEntity>> interceptedMembers = {};
+ for (int i = 0; i < interceptedMembersCount; i++) {
+ String name = source.readString();
+ Set<MemberEntity> members = source.readMembers().toSet();
+ interceptedMembers[name] = members;
+ }
+ Set<ClassEntity> interceptedClasses = source.readClasses().toSet();
+ Set<ClassEntity> classesMixedIntoInterceptedClasses =
+ source.readClasses().toSet();
+ source.end(tag);
+ return new InterceptorDataImpl(
+ nativeData,
+ commonElements,
+ interceptedMembers,
+ interceptedClasses,
+ classesMixedIntoInterceptedClasses);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeInt(interceptedMembers.length);
+ interceptedMembers.forEach((String name, Set<MemberEntity> members) {
+ sink.writeString(name);
+ sink.writeMembers(members);
+ });
+ sink.writeClasses(interceptedClasses);
+ sink.writeClasses(classesMixedIntoInterceptedClasses);
+ sink.end(tag);
+ }
+
bool isInterceptedMethod(MemberEntity element) {
if (!element.isInstanceMember) return false;
// TODO(johnniwinther): Avoid this hack.
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index 40c3d28..e41e541 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -8,12 +8,21 @@
import '../common_elements.dart' show ElementEnvironment;
import '../elements/entities.dart';
import '../native/behavior.dart' show NativeBehavior;
+import '../serialization/serialization.dart';
import '../util/util.dart';
/// Basic information for native classes and js-interop libraries and classes.
///
/// This information is computed during loading using [NativeBasicDataBuilder].
abstract class NativeBasicData {
+ /// Deserializes a [NativeBasicData] object from [source].
+ factory NativeBasicData.readFromDataSource(
+ DataSource source, ElementEnvironment elementEnvironment) =
+ NativeBasicDataImpl.readFromDataSource;
+
+ /// Serializes this [NativeBasicData] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Returns `true` if [cls] corresponds to a native JavaScript class.
///
/// A class is marked as native either through the `@Native(...)` annotation
@@ -48,6 +57,14 @@
///
/// This information is computed during resolution using [NativeDataBuilder].
abstract class NativeData extends NativeBasicData {
+ /// Deserializes a [NativeData] object from [source].
+ factory NativeData.readFromDataSource(
+ DataSource source, ElementEnvironment elementEnvironment) =
+ NativeDataImpl.readFromDataSource;
+
+ /// Serializes this [NativeData] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Returns `true` if [element] corresponds to a native JavaScript member.
///
/// A member is marked as native either through the native mechanism
@@ -267,6 +284,10 @@
}
class NativeBasicDataImpl implements NativeBasicData {
+ /// Tag used for identifying serialized [NativeBasicData] objects in a
+ /// debugging data stream.
+ static const String tag = 'native-basic-data';
+
final ElementEnvironment _env;
/// Tag info for native JavaScript classes names. See
@@ -293,6 +314,45 @@
this.anonymousJsInteropClasses,
this.jsInteropMembers);
+ factory NativeBasicDataImpl.readFromDataSource(
+ DataSource source, ElementEnvironment elementEnvironment) {
+ source.begin(tag);
+ Map<ClassEntity, NativeClassTag> nativeClassTagInfo =
+ source.readClassMap(() {
+ List<String> names = source.readStrings();
+ bool isNonLeaf = source.readBool();
+ return new NativeClassTag.internal(names, isNonLeaf);
+ });
+ Map<LibraryEntity, String> jsInteropLibraries =
+ source.readLibraryMap(source.readString);
+ Map<ClassEntity, String> jsInteropClasses =
+ source.readLibraryMap(source.readString);
+ Set<ClassEntity> anonymousJsInteropClasses = source.readClasses().toSet();
+ Map<MemberEntity, String> jsInteropMembers =
+ source.readLibraryMap(source.readString);
+ source.end(tag);
+ return new NativeBasicDataImpl(
+ elementEnvironment,
+ nativeClassTagInfo,
+ jsInteropLibraries,
+ jsInteropClasses,
+ anonymousJsInteropClasses,
+ jsInteropMembers);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeClassMap(nativeClassTagInfo, (NativeClassTag tag) {
+ sink.writeStrings(tag.names);
+ sink.writeBool(tag.isNonLeaf);
+ });
+ sink.writeLibraryMap(jsInteropLibraries, sink.writeString);
+ sink.writeClassMap(jsInteropClasses, sink.writeString);
+ sink.writeClasses(anonymousJsInteropClasses);
+ sink.writeMemberMap(jsInteropMembers, sink.writeString);
+ sink.end(tag);
+ }
+
@override
bool isNativeClass(ClassEntity element) {
if (isJsInteropClass(element)) return true;
@@ -480,7 +540,13 @@
jsInteropMembers);
}
+// TODO(johnniwinther): Remove fields that overlap with [NativeBasicData], like
+// [anonymousJsInteropClasses].
class NativeDataImpl implements NativeData, NativeBasicDataImpl {
+ /// Tag used for identifying serialized [NativeData] objects in a
+ /// debugging data stream.
+ static const String tag = 'native-data';
+
/// Prefix used to escape JS names that are not valid Dart names
/// when using JSInterop.
static const String _jsInteropEscapePrefix = r'JS$';
@@ -525,6 +591,63 @@
this.jsInteropClasses,
this.jsInteropMembers);
+ factory NativeDataImpl.readFromDataSource(
+ DataSource source, ElementEnvironment elementEnvironment) {
+ source.begin(tag);
+ NativeBasicData nativeBasicData =
+ new NativeBasicData.readFromDataSource(source, elementEnvironment);
+ Map<MemberEntity, String> nativeMemberName =
+ source.readMemberMap(source.readString);
+ Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = source
+ .readMemberMap(() => new NativeBehavior.readFromDataSource(source));
+ Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = source
+ .readMemberMap(() => new NativeBehavior.readFromDataSource(source));
+ Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = source
+ .readMemberMap(() => new NativeBehavior.readFromDataSource(source));
+ Map<LibraryEntity, String> jsInteropLibraries =
+ source.readLibraryMap(source.readString);
+ Set<ClassEntity> anonymousJsInteropClasses = source.readClasses().toSet();
+ Map<ClassEntity, String> jsInteropClasses =
+ source.readClassMap(source.readString);
+ Map<MemberEntity, String> jsInteropMembers =
+ source.readMemberMap(source.readString);
+ source.end(tag);
+ return new NativeDataImpl(
+ nativeBasicData,
+ nativeMemberName,
+ nativeMethodBehavior,
+ nativeFieldLoadBehavior,
+ nativeFieldStoreBehavior,
+ jsInteropLibraries,
+ anonymousJsInteropClasses,
+ jsInteropClasses,
+ jsInteropMembers);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ _nativeBasicData.writeToDataSink(sink);
+
+ sink.writeMemberMap(nativeMemberName, sink.writeString);
+
+ sink.writeMemberMap(nativeMethodBehavior, (NativeBehavior behavior) {
+ behavior.writeToDataSink(sink);
+ });
+
+ sink.writeMemberMap(nativeFieldLoadBehavior, (NativeBehavior behavior) {
+ behavior.writeToDataSink(sink);
+ });
+ sink.writeMemberMap(nativeFieldStoreBehavior, (NativeBehavior behavior) {
+ behavior.writeToDataSink(sink);
+ });
+
+ sink.writeLibraryMap(jsInteropLibraries, sink.writeString);
+ sink.writeClasses(anonymousJsInteropClasses);
+ sink.writeClassMap(jsInteropClasses, sink.writeString);
+ sink.writeMemberMap(jsInteropMembers, sink.writeString);
+ sink.end(tag);
+ }
+
@override
bool isAnonymousJsInteropClass(ClassEntity element) {
return anonymousJsInteropClasses.contains(element);
diff --git a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
index 4c47390..e997b3e 100644
--- a/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
+++ b/pkg/compiler/lib/src/js_backend/no_such_method_registry.dart
@@ -6,6 +6,7 @@
import '../common_elements.dart' show CommonElements;
import '../common/names.dart' show Identifiers, Selectors;
import '../elements/entities.dart';
+import '../serialization/serialization.dart';
import '../types/types.dart';
/// [NoSuchMethodRegistry] and [NoSuchMethodData] categorizes `noSuchMethod`
@@ -171,6 +172,13 @@
/// Post inference collected category `D` methods are into subcategories `D1`
/// and `D2`.
abstract class NoSuchMethodData {
+ /// Deserializes a [NoSuchMethodData] object from [source].
+ factory NoSuchMethodData.readFromDataSource(DataSource source) =
+ NoSuchMethodDataImpl.readFromDataSource;
+
+ /// Serializes this [NoSuchMethodData] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Returns [true] if the given element is a complex [noSuchMethod]
/// implementation. An implementation is complex if it falls into
/// category D, as described above.
@@ -186,6 +194,10 @@
}
class NoSuchMethodDataImpl implements NoSuchMethodData {
+ /// Tag used for identifying serialized [NoSuchMethodData] objects in a
+ /// debugging data stream.
+ static const String tag = 'no-such-method-data';
+
/// The implementations that fall into category B, described above.
final Set<FunctionEntity> throwingImpls;
@@ -203,6 +215,35 @@
NoSuchMethodDataImpl(
this.throwingImpls, this.otherImpls, this.forwardingSyntaxImpls);
+ factory NoSuchMethodDataImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Set<FunctionEntity> throwingImpls =
+ source.readMembers<FunctionEntity>().toSet();
+ Set<FunctionEntity> otherImpls =
+ source.readMembers<FunctionEntity>().toSet();
+ Set<FunctionEntity> forwardingSyntaxImpls =
+ source.readMembers<FunctionEntity>().toSet();
+ List<FunctionEntity> complexNoReturnImpls =
+ source.readMembers<FunctionEntity>();
+ List<FunctionEntity> complexReturningImpls =
+ source.readMembers<FunctionEntity>();
+ source.end(tag);
+ return new NoSuchMethodDataImpl(
+ throwingImpls, otherImpls, forwardingSyntaxImpls)
+ ..complexNoReturnImpls.addAll(complexNoReturnImpls)
+ ..complexReturningImpls.addAll(complexReturningImpls);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeMembers(throwingImpls);
+ sink.writeMembers(otherImpls);
+ sink.writeMembers(forwardingSyntaxImpls);
+ sink.writeMembers(complexNoReturnImpls);
+ sink.writeMembers(complexReturningImpls);
+ sink.end(tag);
+ }
+
/// Now that type inference is complete, split category D into two
/// subcategories: D1, those that have no return type, and D2, those
/// that have a return type.
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index daa1915..3329424 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -19,6 +19,7 @@
import '../js/js.dart' show js;
import '../js_emitter/js_emitter.dart' show Emitter;
import '../options.dart';
+import '../serialization/serialization.dart';
import '../universe/class_hierarchy.dart';
import '../universe/feature.dart';
import '../universe/selector.dart';
@@ -42,6 +43,20 @@
/// Interface for the classes and methods that need runtime types.
abstract class RuntimeTypesNeed {
+ /// Deserializes a [RuntimeTypesNeed] object from [source].
+ factory RuntimeTypesNeed.readFromDataSource(
+ DataSource source, ElementEnvironment elementEnvironment) {
+ bool isTrivial = source.readBool();
+ if (isTrivial) {
+ return const TrivialRuntimeTypesNeed();
+ }
+ return new RuntimeTypesNeedImpl.readFromDataSource(
+ source, elementEnvironment);
+ }
+
+ /// Serializes this [RuntimeTypesNeed] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Returns `true` if [cls] needs type arguments at runtime type.
///
/// This is for instance the case for generic classes used in a type test:
@@ -106,6 +121,10 @@
class TrivialRuntimeTypesNeed implements RuntimeTypesNeed {
const TrivialRuntimeTypesNeed();
+ void writeToDataSink(DataSink sink) {
+ sink.writeBool(true); // Is trivial.
+ }
+
@override
bool classNeedsTypeArguments(ClassEntity cls) => true;
@@ -718,6 +737,10 @@
}
class RuntimeTypesNeedImpl implements RuntimeTypesNeed {
+ /// Tag used for identifying serialized [RuntimeTypesNeed] objects in a
+ /// debugging data stream.
+ static const String tag = 'runtime-types-need';
+
final ElementEnvironment _elementEnvironment;
final Set<ClassEntity> classesNeedingTypeArguments;
final Set<FunctionEntity> methodsNeedingSignature;
@@ -737,6 +760,45 @@
this.selectorsNeedingTypeArguments,
this.instantiationsNeedingTypeArguments);
+ factory RuntimeTypesNeedImpl.readFromDataSource(
+ DataSource source, ElementEnvironment elementEnvironment) {
+ source.begin(tag);
+ Set<ClassEntity> classesNeedingTypeArguments =
+ source.readClasses<ClassEntity>().toSet();
+ Set<FunctionEntity> methodsNeedingSignature =
+ source.readMembers<FunctionEntity>().toSet();
+ Set<FunctionEntity> methodsNeedingTypeArguments =
+ source.readMembers<FunctionEntity>().toSet();
+ Set<Selector> selectorsNeedingTypeArguments =
+ source.readList(() => new Selector.readFromDataSource(source)).toSet();
+ Set<int> instantiationsNeedingTypeArguments =
+ source.readList(source.readInt).toSet();
+ source.end(tag);
+ return new RuntimeTypesNeedImpl(
+ elementEnvironment,
+ classesNeedingTypeArguments,
+ methodsNeedingSignature,
+ methodsNeedingTypeArguments,
+ null,
+ null,
+ selectorsNeedingTypeArguments,
+ instantiationsNeedingTypeArguments);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeBool(false); // Is _not_ trivial.
+ sink.begin(tag);
+ sink.writeClasses(classesNeedingTypeArguments);
+ sink.writeMembers(methodsNeedingSignature);
+ sink.writeMembers(methodsNeedingTypeArguments);
+ assert(localFunctionsNeedingSignature == null);
+ assert(localFunctionsNeedingTypeArguments == null);
+ sink.writeList(selectorsNeedingTypeArguments,
+ (Selector selector) => selector.writeToDataSink(sink));
+ sink.writeList(instantiationsNeedingTypeArguments, sink.writeInt);
+ sink.end(tag);
+ }
+
bool checkClass(covariant ClassEntity cls) => true;
bool classNeedsTypeArguments(ClassEntity cls) {
diff --git a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
index cc96103..063d03f 100644
--- a/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
+++ b/pkg/compiler/lib/src/js_emitter/code_emitter_task.dart
@@ -201,7 +201,7 @@
closedWorld.allocatorAnalysis,
inferredData,
backend.sourceInformationStrategy,
- compiler.backendStrategy.sorter,
+ closedWorld.sorter,
typeTestRegistry.rtiNeededClasses,
closedWorld.elementEnvironment.mainFunction);
int size = emitter.emitProgram(programBuilder);
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 0a0c184..a500d9d 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -18,6 +18,7 @@
import '../js_model/env.dart';
import '../ordered_typeset.dart';
import '../options.dart';
+import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
import '../universe/selector.dart';
import 'elements.dart';
@@ -66,6 +67,8 @@
}
class ClosureDataImpl implements ClosureData {
+ /// Tag used for identifying serialized [ClosureData] objects in a
+ /// debugging data stream.
static const String tag = 'closure-data';
final JsToElementMap _elementMap;
@@ -84,6 +87,42 @@
ClosureDataImpl(this._elementMap, this._scopeMap, this._capturedScopesMap,
this._capturedScopeForSignatureMap, this._localClosureRepresentationMap);
+ /// Deserializes a [ClosureData] object from [source].
+ factory ClosureDataImpl.readFromDataSource(
+ JsToElementMap elementMap, DataSource source) {
+ source.begin(tag);
+ // TODO(johnniwinther): Support shared [ScopeInfo].
+ Map<MemberEntity, ScopeInfo> scopeMap =
+ source.readMemberMap(() => new ScopeInfo.readFromDataSource(source));
+ Map<ir.TreeNode, CapturedScope> capturedScopesMap = source
+ .readTreeNodeMap(() => new CapturedScope.readFromDataSource(source));
+ Map<MemberEntity, CapturedScope> capturedScopeForSignatureMap = source
+ .readMemberMap(() => new CapturedScope.readFromDataSource(source));
+ Map<ir.TreeNode, ClosureRepresentationInfo> localClosureRepresentationMap =
+ source.readTreeNodeMap(
+ () => new ClosureRepresentationInfo.readFromDataSource(source));
+ source.end(tag);
+ return new ClosureDataImpl(elementMap, scopeMap, capturedScopesMap,
+ capturedScopeForSignatureMap, localClosureRepresentationMap);
+ }
+
+ /// Serializes this [ClosureData] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeMemberMap(
+ _scopeMap, (ScopeInfo info) => info.writeToDataSink(sink));
+ sink.writeTreeNodeMap(_capturedScopesMap, (CapturedScope scope) {
+ scope.writeToDataSink(sink);
+ });
+ sink.writeMemberMap(_capturedScopeForSignatureMap,
+ (CapturedScope scope) => scope.writeToDataSink(sink));
+ sink.writeTreeNodeMap(_localClosureRepresentationMap,
+ (ClosureRepresentationInfo info) {
+ info.writeToDataSink(sink);
+ });
+ sink.end(tag);
+ }
+
@override
ScopeInfo getScopeInfo(MemberEntity entity) {
// TODO(johnniwinther): Remove this check when constructor bodies a created
@@ -659,7 +698,11 @@
}
class JsScopeInfo extends ScopeInfo {
- final Set<Local> localsUsedInTryOrSync;
+ /// Tag used for identifying serialized [JsScopeInfo] objects in a
+ /// debugging data stream.
+ static const String tag = 'scope-info';
+
+ final Iterable<Local> localsUsedInTryOrSync;
final Local thisLocal;
final Map<Local, JRecordField> boxedVariables;
@@ -702,6 +745,29 @@
}
bool isBoxed(Local variable) => boxedVariables.containsKey(variable);
+
+ factory JsScopeInfo.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Iterable<Local> localsUsedInTryOrSync = source.readLocals();
+ Local thisLocal = source.readLocalOrNull();
+ Map<Local, JRecordField> boxedVariables =
+ source.readLocalMap<Local, JRecordField>(() => source.readMember());
+ Set<Local> freeVariables = source.readLocals().toSet();
+ source.end(tag);
+ return new JsScopeInfo.internal(
+ localsUsedInTryOrSync, thisLocal, boxedVariables, freeVariables);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(ScopeInfoKind.scopeInfo);
+ sink.begin(tag);
+ sink.writeLocals(localsUsedInTryOrSync);
+ sink.writeLocalOrNull(thisLocal);
+ sink.writeLocalMap(boxedVariables, sink.writeMember);
+ sink.writeLocals(freeVariables);
+ sink.end(tag);
+ }
}
class KernelCapturedScope extends KernelScopeInfo {
@@ -746,8 +812,21 @@
}
class JsCapturedScope extends JsScopeInfo implements CapturedScope {
+ /// Tag used for identifying serialized [JsCapturedScope] objects in a
+ /// debugging data stream.
+ static const String tag = 'captured-scope';
+
final Local context;
+ JsCapturedScope.internal(
+ Iterable<Local> localsUsedInTryOrSync,
+ Local thisLocal,
+ Map<Local, JRecordField> boxedVariables,
+ Set<Local> freeVariables,
+ this.context)
+ : super.internal(
+ localsUsedInTryOrSync, thisLocal, boxedVariables, freeVariables);
+
JsCapturedScope.from(
Map<Local, JRecordField> boxedVariables,
KernelCapturedScope capturedScope,
@@ -758,6 +837,31 @@
super.from(boxedVariables, capturedScope, localsMap, elementMap);
bool get requiresContextBox => boxedVariables.isNotEmpty;
+
+ factory JsCapturedScope.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Iterable<Local> localsUsedInTryOrSync = source.readLocals();
+ Local thisLocal = source.readLocalOrNull();
+ Map<Local, JRecordField> boxedVariables =
+ source.readLocalMap<Local, JRecordField>(() => source.readMember());
+ Set<Local> freeVariables = source.readLocals().toSet();
+ Local context = source.readLocalOrNull();
+ source.end(tag);
+ return new JsCapturedScope.internal(localsUsedInTryOrSync, thisLocal,
+ boxedVariables, freeVariables, context);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(ScopeInfoKind.capturedScope);
+ sink.begin(tag);
+ sink.writeLocals(localsUsedInTryOrSync);
+ sink.writeLocalOrNull(thisLocal);
+ sink.writeLocalMap(boxedVariables, sink.writeMember);
+ sink.writeLocals(freeVariables);
+ sink.writeLocalOrNull(context);
+ sink.end(tag);
+ }
}
class KernelCapturedLoopScope extends KernelCapturedScope {
@@ -788,8 +892,22 @@
}
class JsCapturedLoopScope extends JsCapturedScope implements CapturedLoopScope {
+ /// Tag used for identifying serialized [JsCapturedLoopScope] objects in a
+ /// debugging data stream.
+ static const String tag = 'captured-loop-scope';
+
final List<Local> boxedLoopVariables;
+ JsCapturedLoopScope.internal(
+ Iterable<Local> localsUsedInTryOrSync,
+ Local thisLocal,
+ Map<Local, JRecordField> boxedVariables,
+ Set<Local> freeVariables,
+ Local context,
+ this.boxedLoopVariables)
+ : super.internal(localsUsedInTryOrSync, thisLocal, boxedVariables,
+ freeVariables, context);
+
JsCapturedLoopScope.from(
Map<Local, JRecordField> boxedVariables,
KernelCapturedLoopScope capturedScope,
@@ -801,11 +919,43 @@
super.from(boxedVariables, capturedScope, localsMap, elementMap);
bool get hasBoxedLoopVariables => boxedLoopVariables.isNotEmpty;
+
+ factory JsCapturedLoopScope.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Iterable<Local> localsUsedInTryOrSync = source.readLocals();
+ Local thisLocal = source.readLocalOrNull();
+ Map<Local, JRecordField> boxedVariables =
+ source.readLocalMap<Local, JRecordField>(() => source.readMember());
+ Set<Local> freeVariables = source.readLocals().toSet();
+ Local context = source.readLocalOrNull();
+ List<Local> boxedLoopVariables = source.readLocals();
+ source.end(tag);
+ return new JsCapturedLoopScope.internal(localsUsedInTryOrSync, thisLocal,
+ boxedVariables, freeVariables, context, boxedLoopVariables);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(ScopeInfoKind.capturedLoopScope);
+ sink.begin(tag);
+ sink.writeLocals(localsUsedInTryOrSync);
+ sink.writeLocalOrNull(thisLocal);
+ sink.writeLocalMap(boxedVariables, sink.writeMember);
+ sink.writeLocals(freeVariables);
+ sink.writeLocalOrNull(context);
+ sink.writeLocals(boxedLoopVariables);
+ sink.end(tag);
+ }
}
+// TODO(johnniwinther): Rename this class.
// TODO(johnniwinther): Add unittest for the computed [ClosureClass].
class KernelClosureClassInfo extends JsScopeInfo
implements ClosureRepresentationInfo {
+ /// Tag used for identifying serialized [KernelClosureClassInfo] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-representation-info';
+
JFunction callMethod;
JSignatureMethod signatureMethod;
final Local closureEntity;
@@ -839,6 +989,47 @@
: localToFieldMap = new Map<Local, JField>(),
super.from(boxedVariables, info, localsMap, elementMap);
+ factory KernelClosureClassInfo.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Iterable<Local> localsUsedInTryOrSync = source.readLocals();
+ Local thisLocal = source.readLocalOrNull();
+ Map<Local, JRecordField> boxedVariables =
+ source.readLocalMap<Local, JRecordField>(() => source.readMember());
+ Set<Local> freeVariables = source.readLocals().toSet();
+ JFunction callMethod = source.readMember();
+ JSignatureMethod signatureMethod = source.readMemberOrNull();
+ Local closureEntity = source.readLocalOrNull();
+ JClass closureClassEntity = source.readClass();
+ Map<Local, JField> localToFieldMap =
+ source.readLocalMap(() => source.readMember());
+ source.end(tag);
+ return new KernelClosureClassInfo.internal(
+ localsUsedInTryOrSync,
+ thisLocal,
+ boxedVariables,
+ freeVariables,
+ callMethod,
+ signatureMethod,
+ closureEntity,
+ closureClassEntity,
+ localToFieldMap);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(ScopeInfoKind.closureRepresentationInfo);
+ sink.begin(tag);
+ sink.writeLocals(localsUsedInTryOrSync);
+ sink.writeLocalOrNull(thisLocal);
+ sink.writeLocalMap(boxedVariables, sink.writeMember);
+ sink.writeLocals(freeVariables);
+ sink.writeMember(callMethod);
+ sink.writeMemberOrNull(signatureMethod);
+ sink.writeLocalOrNull(closureEntity);
+ sink.writeClass(closureClassEntity);
+ sink.writeLocalMap(localToFieldMap, sink.writeMember);
+ sink.end(tag);
+ }
+
List<Local> get createdFieldEntities => localToFieldMap.keys.toList();
@override
@@ -880,9 +1071,29 @@
}
class JClosureClass extends JClass {
+ /// Tag used for identifying serialized [JClosureClass] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-class';
+
JClosureClass(JLibrary library, String name)
: super(library, name, isAbstract: false);
+ factory JClosureClass.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JLibrary library = source.readLibrary();
+ String name = source.readString();
+ source.end(tag);
+ return new JClosureClass(library, name);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassKind.closure);
+ sink.begin(tag);
+ sink.writeLibrary(library);
+ sink.writeString(name);
+ sink.end(tag);
+ }
+
@override
bool get isClosure => true;
@@ -909,6 +1120,10 @@
}
class JClosureField extends JField implements PrivatelyNamedJSEntity {
+ /// Tag used for identifying serialized [JClosureClass] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-field';
+
final String declaredName;
JClosureField(
@@ -927,12 +1142,40 @@
: super(library, enclosingClass, memberName,
isAssignable: isAssignable, isConst: isConst, isStatic: false);
+ factory JClosureField.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JClass cls = source.readClass();
+ String name = source.readString();
+ String declaredName = source.readString();
+ bool isConst = source.readBool();
+ bool isAssignable = source.readBool();
+ source.end(tag);
+ return new JClosureField.internal(
+ cls.library, cls, new Name(name, cls.library), declaredName,
+ isAssignable: isAssignable, isConst: isConst);
+ }
+
@override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.closureField);
+ sink.begin(tag);
+ sink.writeClass(enclosingClass);
+ sink.writeString(name);
+ sink.writeString(declaredName);
+ sink.writeBool(isConst);
+ sink.writeBool(isAssignable);
+ sink.end(tag);
+ }
+
@override
Entity get rootOfScope => enclosingClass;
}
class RecordClassData implements JClassData {
+ /// Tag used for identifying serialized [RecordClassData] objects in a
+ /// debugging data stream.
+ static const String tag = 'record-class-data';
+
@override
final ClassDefinition definition;
@@ -948,6 +1191,28 @@
RecordClassData(
this.definition, this.thisType, this.supertype, this.orderedTypeSet);
+ factory RecordClassData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ClassDefinition definition = new ClassDefinition.readFromDataSource(source);
+ InterfaceType thisType = source.readDartType();
+ InterfaceType supertype = source.readDartType();
+ OrderedTypeSet orderedTypeSet =
+ new OrderedTypeSet.readFromDataSource(source);
+ source.end(tag);
+ return new RecordClassData(definition, thisType, supertype, orderedTypeSet);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassDataKind.record);
+ sink.begin(tag);
+ definition.writeToDataSink(sink);
+ sink.writeDartType(thisType);
+ sink.writeDartType(supertype);
+ orderedTypeSet.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
@override
bool get isMixinApplication => false;
@@ -969,12 +1234,32 @@
/// A container for variables declared in a particular scope that are accessed
/// elsewhere.
-// TODO(efortuna, johnniwinther): Don't implement JClass. This isn't actually a
+// TODO(johnniwinther): Don't implement JClass. This isn't actually a
// class.
class JRecord extends JClass {
+ /// Tag used for identifying serialized [JRecord] objects in a
+ /// debugging data stream.
+ static const String tag = 'record';
+
JRecord(LibraryEntity library, String name)
: super(library, name, isAbstract: false);
+ factory JRecord.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JLibrary library = source.readLibrary();
+ String name = source.readString();
+ source.end(tag);
+ return new JRecord(library, name);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassKind.record);
+ sink.begin(tag);
+ sink.writeLibrary(library);
+ sink.writeString(name);
+ sink.end(tag);
+ }
+
bool get isClosure => false;
String toString() => '${jsElementPrefix}record_container($name)';
@@ -986,6 +1271,10 @@
/// This corresponds to BoxFieldElement; we reuse BoxLocal from the original
/// algorithm to correspond to the actual name of the variable.
class JRecordField extends JField {
+ /// Tag used for identifying serialized [JRecordField] objects in a
+ /// debugging data stream.
+ static const String tag = 'record-field';
+
final BoxLocal box;
JRecordField(String name, this.box, {bool isConst})
@@ -993,24 +1282,92 @@
new Name(name, box.container.library),
isStatic: false, isAssignable: true, isConst: isConst);
+ factory JRecordField.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ String name = source.readString();
+ JClass enclosingClass = source.readClass();
+ bool isConst = source.readBool();
+ source.end(tag);
+ return new JRecordField(name, new BoxLocal(enclosingClass),
+ isConst: isConst);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.recordField);
+ sink.begin(tag);
+ sink.writeString(name);
+ sink.writeClass(enclosingClass);
+ sink.writeBool(isConst);
+ sink.end(tag);
+ }
+
@override
bool get isInstanceMember => false;
}
class ClosureClassData extends RecordClassData {
+ /// Tag used for identifying serialized [ClosureClassData] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-class-data';
+
@override
FunctionType callType;
ClosureClassData(ClassDefinition definition, InterfaceType thisType,
InterfaceType supertype, OrderedTypeSet orderedTypeSet)
: super(definition, thisType, supertype, orderedTypeSet);
+
+ factory ClosureClassData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ClassDefinition definition = new ClassDefinition.readFromDataSource(source);
+ InterfaceType thisType = source.readDartType();
+ InterfaceType supertype = source.readDartType();
+ OrderedTypeSet orderedTypeSet =
+ new OrderedTypeSet.readFromDataSource(source);
+ FunctionType callType = source.readDartType();
+ source.end(tag);
+ return new ClosureClassData(definition, thisType, supertype, orderedTypeSet)
+ ..callType = callType;
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassDataKind.closure);
+ sink.begin(tag);
+ definition.writeToDataSink(sink);
+ sink.writeDartType(thisType);
+ sink.writeDartType(supertype);
+ orderedTypeSet.writeToDataSink(sink);
+ sink.writeDartType(callType);
+ sink.end(tag);
+ }
}
class ClosureClassDefinition implements ClassDefinition {
+ /// Tag used for identifying serialized [ClosureClassDefinition] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-class-definition';
+
final SourceSpan location;
ClosureClassDefinition(this.location);
+ factory ClosureClassDefinition.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ SourceSpan location = source.readSourceSpan();
+ source.end(tag);
+ return new ClosureClassDefinition(location);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(ClassKind.closure);
+ sink.begin(tag);
+ sink.writeSourceSpan(location);
+ sink.end(tag);
+ }
+
ClassKind get kind => ClassKind.closure;
ir.Node get node =>
@@ -1034,6 +1391,10 @@
class ClosureFunctionData extends ClosureMemberData
with FunctionDataMixin
implements FunctionData {
+ /// Tag used for identifying serialized [ClosureFunctionData] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-function-data';
+
final FunctionType functionType;
final ir.FunctionNode functionNode;
final ClassTypeVariableAccess classTypeVariableAccess;
@@ -1046,6 +1407,31 @@
this.classTypeVariableAccess)
: super(definition, memberThisType);
+ factory ClosureFunctionData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ClosureMemberDefinition definition =
+ new MemberDefinition.readFromDataSource(source);
+ InterfaceType memberThisType = source.readDartType(allowNull: true);
+ FunctionType functionType = source.readDartType();
+ ir.FunctionNode functionNode = source.readTreeNode();
+ ClassTypeVariableAccess classTypeVariableAccess =
+ source.readEnum(ClassTypeVariableAccess.values);
+ source.end(tag);
+ return new ClosureFunctionData(definition, memberThisType, functionType,
+ functionNode, classTypeVariableAccess);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberDataKind.closureFunction);
+ sink.begin(tag);
+ definition.writeToDataSink(sink);
+ sink.writeDartType(memberThisType, allowNull: true);
+ sink.writeDartType(functionType);
+ sink.writeTreeNode(functionNode);
+ sink.writeEnum(classTypeVariableAccess);
+ sink.end(tag);
+ }
+
void forEachParameter(JsToElementMap elementMap,
void f(DartType type, String name, ConstantValue defaultValue)) {
void handleParameter(ir.VariableDeclaration node, {bool isOptional: true}) {
@@ -1078,10 +1464,32 @@
}
class ClosureFieldData extends ClosureMemberData implements JFieldData {
+ /// Tag used for identifying serialized [ClosureFieldData] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-field-data';
+
DartType _type;
+
ClosureFieldData(MemberDefinition definition, InterfaceType memberThisType)
: super(definition, memberThisType);
+ factory ClosureFieldData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ MemberDefinition definition =
+ new MemberDefinition.readFromDataSource(source);
+ InterfaceType memberThisType = source.readDartType(allowNull: true);
+ source.end(tag);
+ return new ClosureFieldData(definition, memberThisType);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberDataKind.closureField);
+ sink.begin(tag);
+ definition.writeToDataSink(sink);
+ sink.writeDartType(memberThisType, allowNull: true);
+ sink.end(tag);
+ }
+
@override
DartType getFieldType(IrToElementMap elementMap) {
if (_type != null) return _type;
@@ -1142,6 +1550,10 @@
}
class ClosureMemberDefinition implements MemberDefinition {
+ /// Tag used for identifying serialized [ClosureMemberDefinition] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-member-definition';
+
final SourceSpan location;
final MemberKind kind;
final ir.TreeNode node;
@@ -1150,14 +1562,50 @@
: assert(
kind == MemberKind.closureCall || kind == MemberKind.closureField);
+ factory ClosureMemberDefinition.readFromDataSource(
+ DataSource source, MemberKind kind) {
+ source.begin(tag);
+ SourceSpan location = source.readSourceSpan();
+ ir.TreeNode node = source.readTreeNode();
+ source.end(tag);
+ return new ClosureMemberDefinition(location, kind, node);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(kind);
+ sink.begin(tag);
+ sink.writeSourceSpan(location);
+ sink.writeTreeNode(node);
+ sink.end(tag);
+ }
+
String toString() => 'ClosureMemberDefinition(kind:$kind,location:$location)';
}
class RecordContainerDefinition implements ClassDefinition {
+ /// Tag used for identifying serialized [RecordContainerDefinition] objects in
+ /// a debugging data stream.
+ static const String tag = 'record-definition';
+
final SourceSpan location;
RecordContainerDefinition(this.location);
+ factory RecordContainerDefinition.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ SourceSpan location = source.readSourceSpan();
+ source.end(tag);
+ return new RecordContainerDefinition(location);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(ClassKind.record);
+ sink.begin(tag);
+ sink.writeSourceSpan(location);
+ sink.end(tag);
+ }
+
ClassKind get kind => ClassKind.record;
ir.Node get node => throw new UnsupportedError(
diff --git a/pkg/compiler/lib/src/js_model/element_map.dart b/pkg/compiler/lib/src/js_model/element_map.dart
index 13a6bea..22a306b 100644
--- a/pkg/compiler/lib/src/js_model/element_map.dart
+++ b/pkg/compiler/lib/src/js_model/element_map.dart
@@ -18,11 +18,13 @@
import '../js_model/closure.dart' show JRecordField, KernelScopeInfo;
import '../js_model/elements.dart' show JGeneratorBody;
import '../native/native.dart' as native;
+import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
import '../types/abstract_value_domain.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import '../world.dart';
+import 'closure.dart';
/// Interface that translates between Kernel IR nodes and entities used for
/// global type inference and building the SSA graph for members.
@@ -273,6 +275,9 @@
/// Returns the [JumpTarget] defined by the while statement [node] or `null`
/// if [node] is not a jump target.
JumpTarget getJumpTargetForWhile(ir.WhileStatement node);
+
+ /// Serializes this [KernelToLocalsMap] to [sink].
+ void writeToDataSink(DataSink sink);
}
/// Returns the [ir.FunctionNode] that defines [member] or `null` if [member]
@@ -346,6 +351,27 @@
/// The canonical location of [member]. This is used for sorting the members
/// in the emitted code.
SourceSpan get location;
+
+ /// Deserializes a [MemberDefinition] object from [source].
+ factory MemberDefinition.readFromDataSource(DataSource source) {
+ MemberKind kind = source.readEnum(MemberKind.values);
+ switch (kind) {
+ case MemberKind.regular:
+ return new RegularMemberDefinition.readFromDataSource(source);
+ case MemberKind.constructor:
+ case MemberKind.constructorBody:
+ case MemberKind.signature:
+ case MemberKind.generatorBody:
+ return new SpecialMemberDefinition.readFromDataSource(source, kind);
+ case MemberKind.closureCall:
+ case MemberKind.closureField:
+ return new ClosureMemberDefinition.readFromDataSource(source, kind);
+ }
+ throw new UnsupportedError("Unexpected MemberKind $kind");
+ }
+
+ /// Serializes this [MemberDefinition] to [sink].
+ void writeToDataSink(DataSink sink);
}
enum ClassKind {
@@ -358,10 +384,29 @@
/// A member directly defined by its [ir.Member] node.
class RegularMemberDefinition implements MemberDefinition {
+ /// Tag used for identifying serialized [RegularMemberDefinition] objects in a
+ /// debugging data stream.
+ static const String tag = 'regular-member-definition';
+
final ir.Member node;
RegularMemberDefinition(this.node);
+ factory RegularMemberDefinition.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Member node = source.readMemberNode();
+ source.end(tag);
+ return new RegularMemberDefinition(node);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(MemberKind.regular);
+ sink.begin(tag);
+ sink.writeMemberNode(node);
+ sink.end(tag);
+ }
+
SourceSpan get location => computeSourceSpanFromTreeNode(node);
MemberKind get kind => MemberKind.regular;
@@ -372,11 +417,31 @@
/// The definition of a special kind of member
class SpecialMemberDefinition implements MemberDefinition {
+ /// Tag used for identifying serialized [SpecialMemberDefinition] objects in a
+ /// debugging data stream.
+ static const String tag = 'special-member-definition';
+
final ir.TreeNode node;
final MemberKind kind;
SpecialMemberDefinition(this.node, this.kind);
+ factory SpecialMemberDefinition.readFromDataSource(
+ DataSource source, MemberKind kind) {
+ source.begin(tag);
+ ir.TreeNode node = source.readTreeNode();
+ source.end(tag);
+ return new SpecialMemberDefinition(node, kind);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(kind);
+ sink.begin(tag);
+ sink.writeTreeNode(node);
+ sink.end(tag);
+ }
+
SourceSpan get location => computeSourceSpanFromTreeNode(node);
String toString() => 'SpecialMemberDefinition(kind:$kind,'
@@ -394,14 +459,49 @@
/// The canonical location of [cls]. This is used for sorting the classes
/// in the emitted code.
SourceSpan get location;
+
+ /// Deserializes a [ClassDefinition] object from [source].
+ factory ClassDefinition.readFromDataSource(DataSource source) {
+ ClassKind kind = source.readEnum(ClassKind.values);
+ switch (kind) {
+ case ClassKind.regular:
+ return new RegularClassDefinition.readFromDataSource(source);
+ case ClassKind.closure:
+ return new ClosureClassDefinition.readFromDataSource(source);
+ case ClassKind.record:
+ return new RecordContainerDefinition.readFromDataSource(source);
+ }
+ throw new UnsupportedError("Unexpected ClassKind $kind");
+ }
+
+ /// Serializes this [ClassDefinition] to [sink].
+ void writeToDataSink(DataSink sink);
}
/// A class directly defined by its [ir.Class] node.
class RegularClassDefinition implements ClassDefinition {
+ /// Tag used for identifying serialized [RegularClassDefinition] objects in a
+ /// debugging data stream.
+ static const String tag = 'regular-class-definition';
+
final ir.Class node;
RegularClassDefinition(this.node);
+ factory RegularClassDefinition.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Class node = source.readClassNode();
+ source.end(tag);
+ return new RegularClassDefinition(node);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(kind);
+ sink.begin(tag);
+ sink.writeClassNode(node);
+ sink.end(tag);
+ }
+
SourceSpan get location => computeSourceSpanFromTreeNode(node);
ClassKind get kind => ClassKind.regular;
diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart
index bc3122a..dccda12 100644
--- a/pkg/compiler/lib/src/js_model/element_map_impl.dart
+++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart
@@ -43,6 +43,7 @@
import '../native/native.dart' as native;
import '../options.dart';
import '../ordered_typeset.dart';
+import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
@@ -1442,6 +1443,23 @@
class JsKernelToElementMap extends JsToElementMapBase
with JsElementCreatorMixin
implements JsToWorldBuilder, JsToElementMap {
+ /// Tag used for identifying serialized [JsKernelToElementMap] objects in a
+ /// debugging data stream.
+ static const String tag = 'js-kernel-to-element-map';
+
+ /// Tags used for identifying serialized subsections of a
+ /// [JsKernelToElementMap] object in a debugging data stream.
+ static const String libraryTag = 'libraries';
+ static const String classTag = 'classes';
+ static const String typedefTag = 'typedefs';
+ static const String memberTag = 'members';
+ static const String typeVariableTag = 'type-variables';
+ static const String libraryDataTag = 'library-data';
+ static const String classDataTag = 'class-data';
+ static const String typedefDataTag = 'typedef-data';
+ static const String memberDataTag = 'member-data';
+ static const String typeVariableDataTag = 'type-variable-data';
+
final Map<ir.Library, IndexedLibrary> libraryMap = {};
final Map<ir.Class, IndexedClass> classMap = {};
final Map<ir.Typedef, IndexedTypedef> typedefMap = {};
@@ -1574,7 +1592,6 @@
assert(newTypeVariable.typeVariableIndex ==
oldTypeVariable.typeVariableIndex);
}
- //typeVariableMap.keys.forEach((n) => print(n.parent));
// TODO(johnniwinther): We should close the environment in the beginning of
// this constructor but currently we need the [MemberEntity] to query if the
// member is live, thus potentially creating the [MemberEntity] in the
@@ -1582,6 +1599,207 @@
_elementMap.envIsClosed = true;
}
+ JsKernelToElementMap.readFromDataSource(
+ CompilerOptions options,
+ DiagnosticReporter reporter,
+ Environment environment,
+ ir.Component component,
+ DataSource source)
+ : super(options, reporter, environment) {
+ source.registerComponentLookup(new ComponentLookup(component));
+ _EntityLookup entityLookup = new _EntityLookup();
+ source.registerEntityLookup(entityLookup);
+
+ source.begin(tag);
+ source.begin(libraryTag);
+ int libraryCount = source.readInt();
+ for (int i = 0; i < libraryCount; i++) {
+ int index = source.readInt();
+ JLibrary library = new JLibrary.readFromDataSource(source);
+ entityLookup.registerLibrary(index, library);
+ }
+ source.end(libraryTag);
+
+ source.begin(classTag);
+ int classCount = source.readInt();
+ for (int i = 0; i < classCount; i++) {
+ int index = source.readInt();
+ JClass cls = new JClass.readFromDataSource(source);
+ entityLookup.registerClass(index, cls);
+ }
+ source.end(classTag);
+
+ source.begin(typedefTag);
+ int typedefCount = source.readInt();
+ for (int i = 0; i < typedefCount; i++) {
+ int index = source.readInt();
+ JTypedef typedef = new JTypedef.readFromDataSource(source);
+ entityLookup.registerTypedef(index, typedef);
+ }
+ source.end(typedefTag);
+
+ source.begin(memberTag);
+ int memberCount = source.readInt();
+ for (int i = 0; i < memberCount; i++) {
+ int index = source.readInt();
+ JMember member = new JMember.readFromDataSource(source);
+ entityLookup.registerMember(index, member);
+ }
+ source.end(memberTag);
+
+ source.begin(typeVariableTag);
+ int typeVariableCount = source.readInt();
+ for (int i = 0; i < typeVariableCount; i++) {
+ int index = source.readInt();
+ JTypeVariable typeVariable = new JTypeVariable.readFromDataSource(source);
+ entityLookup.registerTypeVariable(index, typeVariable);
+ }
+ source.end(typeVariableTag);
+
+ programEnv = new JProgramEnv([component]);
+ source.begin(libraryDataTag);
+ entityLookup.forEachLibrary((int index, JLibrary library) {
+ JLibraryEnv env = new JLibraryEnv.readFromDataSource(source);
+ JLibraryData data = new JLibraryData.readFromDataSource(source);
+ libraryMap[env.library] =
+ libraries.registerByIndex(index, library, data, env);
+ programEnv.registerLibrary(env);
+ assert(index == library.libraryIndex);
+ });
+ source.end(libraryDataTag);
+
+ source.begin(classDataTag);
+ entityLookup.forEachClass((int index, JClass cls) {
+ JClassEnv env = new JClassEnv.readFromDataSource(source);
+ JClassData data = new JClassData.readFromDataSource(source);
+ classMap[env.cls] = classes.registerByIndex(index, cls, data, env);
+ libraries.getEnv(cls.library).registerClass(cls.name, env);
+ assert(index == cls.classIndex);
+ });
+ source.end(classDataTag);
+
+ source.begin(typedefDataTag);
+ entityLookup.forEachTypedef((int index, JTypedef typedef) {
+ JTypedefData data = new JTypedefData.readFromDataSource(source);
+ typedefs.registerByIndex(index, typedef, data);
+ assert(index == typedef.typedefIndex);
+ });
+ source.end(typedefDataTag);
+
+ source.begin(memberDataTag);
+ entityLookup.forEachMember((int index, IndexedMember member) {
+ JMemberData data = new JMemberData.readFromDataSource(source);
+ members.registerByIndex(index, member, data);
+ switch (data.definition.kind) {
+ case MemberKind.regular:
+ case MemberKind.constructor:
+ ir.Member node = data.definition.node;
+ if (member.isField) {
+ fieldMap[node] = member;
+ } else if (member.isConstructor) {
+ constructorMap[node] = member;
+ } else {
+ methodMap[node] = member;
+ }
+ break;
+ default:
+ }
+ assert(index == member.memberIndex);
+ });
+ source.end(memberDataTag);
+
+ source.begin(typeVariableDataTag);
+ entityLookup.forEachTypeVariable((int index, JTypeVariable typeVariable) {
+ JTypeVariableData data = new JTypeVariableData.readFromDataSource(source);
+ typeVariableMap[data.node] =
+ typeVariables.registerByIndex(index, typeVariable, data);
+ assert(index == typeVariable.typeVariableIndex);
+ });
+ source.end(typeVariableDataTag);
+ source.end(tag);
+ }
+
+ /// Serializes this [JsToElementMap] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+
+ // Serialize the entities before serializing the data.
+ sink.begin(libraryTag);
+ sink.writeInt(libraries.size);
+ libraries.forEach((JLibrary library, _, __) {
+ sink.writeInt(library.libraryIndex);
+ library.writeToDataSink(sink);
+ });
+ sink.end(libraryTag);
+
+ sink.begin(classTag);
+ sink.writeInt(classes.size);
+ classes.forEach((JClass cls, _, __) {
+ sink.writeInt(cls.classIndex);
+ cls.writeToDataSink(sink);
+ });
+ sink.end(classTag);
+
+ sink.begin(typedefTag);
+ sink.writeInt(typedefs.size);
+ typedefs.forEach((JTypedef typedef, _) {
+ sink.writeInt(typedef.typedefIndex);
+ typedef.writeToDataSink(sink);
+ });
+ sink.end(typedefTag);
+
+ sink.begin(memberTag);
+ sink.writeInt(members.size);
+ members.forEach((JMember member, _) {
+ sink.writeInt(member.memberIndex);
+ member.writeToDataSink(sink);
+ });
+ sink.end(memberTag);
+
+ sink.begin(typeVariableTag);
+ sink.writeInt(typeVariables.size);
+ typeVariables.forEach((JTypeVariable typeVariable, _) {
+ sink.writeInt(typeVariable.typeVariableIndex);
+ typeVariable.writeToDataSink(sink);
+ });
+ sink.end(typeVariableTag);
+
+ // Serialize the entity data after having serialized the entities.
+ sink.begin(libraryDataTag);
+ libraries.forEach((_, JLibraryData data, JLibraryEnv env) {
+ env.writeToDataSink(sink);
+ data.writeToDataSink(sink);
+ });
+ sink.end(libraryDataTag);
+
+ sink.begin(classDataTag);
+ classes.forEach((_, JClassData data, JClassEnv env) {
+ env.writeToDataSink(sink);
+ data.writeToDataSink(sink);
+ });
+ sink.end(classDataTag);
+
+ sink.begin(typedefDataTag);
+ typedefs.forEach((_, JTypedefData data) {
+ data.writeToDataSink(sink);
+ });
+ sink.end(typedefDataTag);
+
+ sink.begin(memberDataTag);
+ members.forEach((_, JMemberData data) {
+ data.writeToDataSink(sink);
+ });
+ sink.end(memberDataTag);
+
+ sink.begin(typeVariableDataTag);
+ typeVariables.forEach((_, JTypeVariableData data) {
+ data.writeToDataSink(sink);
+ });
+ sink.end(typeVariableDataTag);
+
+ sink.end(tag);
+ }
+
@override
void forEachNestedClosure(
MemberEntity member, void f(FunctionEntity closure)) {
@@ -2223,3 +2441,101 @@
.getEntity(indexedTypeVariable.typeVariableIndex);
}
}
+
+/// [EntityLookup] implementation used to deserialize [JsKernelToElementMap].
+///
+/// Since data objects and environments are registered together with their
+/// entity we need to have a separate lookup-by-index mechanism to allow for
+/// index-based reference within data objects and environments.
+class _EntityLookup implements EntityLookup {
+ final Map<int, JLibrary> _libraries = {};
+ final Map<int, JClass> _classes = {};
+ final Map<int, JTypedef> _typedefs = {};
+ final Map<int, JMember> _members = {};
+ final Map<int, JTypeVariable> _typeVariables = {};
+
+ void registerLibrary(int index, JLibrary library) {
+ assert(!_libraries.containsKey(index),
+ "Library for index $index has already been defined.");
+ _libraries[index] = library;
+ }
+
+ void registerClass(int index, JClass cls) {
+ assert(!_classes.containsKey(index),
+ "Class for index $index has already been defined.");
+ _classes[index] = cls;
+ }
+
+ void registerTypedef(int index, JTypedef typedef) {
+ assert(!_typedefs.containsKey(index),
+ "Typedef for index $index has already been defined.");
+ _typedefs[index] = typedef;
+ }
+
+ void registerMember(int index, JMember member) {
+ assert(!_members.containsKey(index),
+ "Member for index $index has already been defined.");
+ _members[index] = member;
+ }
+
+ void registerTypeVariable(int index, JTypeVariable typeVariable) {
+ assert(!_typeVariables.containsKey(index),
+ "Type variable for index $index has already been defined.");
+ _typeVariables[index] = typeVariable;
+ }
+
+ void forEachLibrary(void f(int index, JLibrary library)) {
+ _libraries.forEach(f);
+ }
+
+ void forEachClass(void f(int index, JClass cls)) {
+ _classes.forEach(f);
+ }
+
+ void forEachTypedef(void f(int index, JTypedef typedef)) {
+ _typedefs.forEach(f);
+ }
+
+ void forEachMember(void f(int index, JMember member)) {
+ _members.forEach(f);
+ }
+
+ void forEachTypeVariable(void f(int index, JTypeVariable typeVariable)) {
+ _typeVariables.forEach(f);
+ }
+
+ @override
+ IndexedLibrary getLibraryByIndex(int index) {
+ IndexedLibrary library = _libraries[index];
+ assert(library != null, "No library found for index $index");
+ return library;
+ }
+
+ @override
+ IndexedClass getClassByIndex(int index) {
+ IndexedClass cls = _classes[index];
+ assert(cls != null, "No class found for index $index");
+ return cls;
+ }
+
+ @override
+ IndexedTypedef getTypedefByIndex(int index) {
+ IndexedTypedef typedef = _typedefs[index];
+ assert(typedef != null, "No typedef found for index $index");
+ return typedef;
+ }
+
+ @override
+ IndexedMember getMemberByIndex(int index) {
+ IndexedMember member = _members[index];
+ assert(member != null, "No member found for index $index");
+ return member;
+ }
+
+ @override
+ IndexedTypeVariable getTypeVariableByIndex(int index) {
+ IndexedTypeVariable typeVariable = _typeVariables[index];
+ assert(typeVariable != null, "No type variable found for index $index");
+ return typeVariable;
+ }
+}
diff --git a/pkg/compiler/lib/src/js_model/elements.dart b/pkg/compiler/lib/src/js_model/elements.dart
index c357702..f964ef9 100644
--- a/pkg/compiler/lib/src/js_model/elements.dart
+++ b/pkg/compiler/lib/src/js_model/elements.dart
@@ -9,7 +9,9 @@
import '../elements/indexed.dart';
import '../elements/names.dart';
import '../elements/types.dart';
+import '../serialization/serialization.dart';
import '../universe/class_set.dart' show ClassHierarchyNodesMapKey;
+import 'closure.dart';
/// Map from 'frontend' to 'backend' elements.
///
@@ -318,15 +320,43 @@
const String jsElementPrefix = 'j:';
class JLibrary extends IndexedLibrary {
+ /// Tag used for identifying serialized [JLibrary] objects in a
+ /// debugging data stream.
+ static const String tag = 'library';
+
final String name;
final Uri canonicalUri;
JLibrary(this.name, this.canonicalUri);
+ /// Deserializes a [JLibrary] object from [source].
+ factory JLibrary.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ String name = source.readString();
+ Uri canonicalUri = source.readUri();
+ source.end(tag);
+ return new JLibrary(name, canonicalUri);
+ }
+
+ /// Serializes this [JLibrary] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeString(name);
+ sink.writeUri(canonicalUri);
+ sink.end(tag);
+ }
+
String toString() => '${jsElementPrefix}library($name)';
}
+/// Enum used for identifying [JClass] subclasses in serialization.
+enum JClassKind { node, closure, record }
+
class JClass extends IndexedClass with ClassHierarchyNodesMapKey {
+ /// Tag used for identifying serialized [JClass] objects in a
+ /// debugging data stream.
+ static const String tag = 'class';
+
final JLibrary library;
final String name;
@@ -334,6 +364,35 @@
JClass(this.library, this.name, {this.isAbstract});
+ /// Deserializes a [JClass] object from [source].
+ factory JClass.readFromDataSource(DataSource source) {
+ JClassKind kind = source.readEnum(JClassKind.values);
+ switch (kind) {
+ case JClassKind.node:
+ source.begin(tag);
+ JLibrary library = source.readLibrary();
+ String name = source.readString();
+ bool isAbstract = source.readBool();
+ source.end(tag);
+ return new JClass(library, name, isAbstract: isAbstract);
+ case JClassKind.closure:
+ return new JClosureClass.readFromDataSource(source);
+ case JClassKind.record:
+ return new JRecord.readFromDataSource(source);
+ }
+ throw new UnsupportedError("Unexpected ClassKind $kind");
+ }
+
+ /// Serializes this [JClass] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassKind.node);
+ sink.begin(tag);
+ sink.writeLibrary(library);
+ sink.writeString(name);
+ sink.writeBool(isAbstract);
+ sink.end(tag);
+ }
+
@override
bool get isClosure => false;
@@ -341,15 +400,52 @@
}
class JTypedef extends IndexedTypedef {
+ /// Tag used for identifying serialized [JTypedef] objects in a
+ /// debugging data stream.
+ static const String tag = 'typedef';
+
final JLibrary library;
final String name;
JTypedef(this.library, this.name);
+ /// Deserializes a [JTypedef] object from [source].
+ factory JTypedef.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JLibrary library = source.readLibrary();
+ String name = source.readString();
+ source.end(tag);
+ return new JTypedef(library, name);
+ }
+
+ /// Serializes this [JTypedef] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeLibrary(library);
+ sink.writeString(name);
+ sink.end(tag);
+ }
+
String toString() => '${jsElementPrefix}typedef($name)';
}
+/// Enum used for identifying [JMember] subclasses in serialization.
+enum JMemberKind {
+ generativeConstructor,
+ factoryConstructor,
+ constructorBody,
+ field,
+ getter,
+ setter,
+ method,
+ closureField,
+ closureCallMethod,
+ generatorBody,
+ signatureMethod,
+ recordField,
+}
+
abstract class JMember extends IndexedMember {
final JLibrary library;
final JClass enclosingClass;
@@ -359,6 +455,41 @@
JMember(this.library, this.enclosingClass, this._name, {bool isStatic: false})
: _isStatic = isStatic;
+ /// Deserializes a [JMember] object from [source].
+ factory JMember.readFromDataSource(DataSource source) {
+ JMemberKind kind = source.readEnum(JMemberKind.values);
+ switch (kind) {
+ case JMemberKind.generativeConstructor:
+ return new JGenerativeConstructor.readFromDataSource(source);
+ case JMemberKind.factoryConstructor:
+ return new JFactoryConstructor.readFromDataSource(source);
+ case JMemberKind.constructorBody:
+ return new JConstructorBody.readFromDataSource(source);
+ case JMemberKind.field:
+ return new JField.readFromDataSource(source);
+ case JMemberKind.getter:
+ return new JGetter.readFromDataSource(source);
+ case JMemberKind.setter:
+ return new JSetter.readFromDataSource(source);
+ case JMemberKind.method:
+ return new JMethod.readFromDataSource(source);
+ case JMemberKind.closureField:
+ return new JClosureField.readFromDataSource(source);
+ case JMemberKind.closureCallMethod:
+ return new JClosureCallMethod.readFromDataSource(source);
+ case JMemberKind.generatorBody:
+ return new JGeneratorBody.readFromDataSource(source);
+ case JMemberKind.signatureMethod:
+ return new JSignatureMethod.readFromDataSource(source);
+ case JMemberKind.recordField:
+ return new JRecordField.readFromDataSource(source);
+ }
+ throw new UnsupportedError("Unexpected JMemberKind $kind");
+ }
+
+ /// Serializes this [JMember] to [sink].
+ void writeToDataSink(DataSink sink);
+
String get name => _name.text;
Name get memberName => _name;
@@ -444,12 +575,42 @@
}
class JGenerativeConstructor extends JConstructor {
+ /// Tag used for identifying serialized [JGenerativeConstructor] objects in a
+ /// debugging data stream.
+ static const String tag = 'generative-constructor';
+
JGenerativeConstructor(
JClass enclosingClass, Name name, ParameterStructure parameterStructure,
{bool isExternal, bool isConst})
: super(enclosingClass, name, parameterStructure,
isExternal: isExternal, isConst: isConst);
+ factory JGenerativeConstructor.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JClass enclosingClass = source.readClass();
+ String name = source.readString();
+ ParameterStructure parameterStructure =
+ new ParameterStructure.readFromDataSource(source);
+ bool isExternal = source.readBool();
+ bool isConst = source.readBool();
+ source.end(tag);
+ return new JGenerativeConstructor(enclosingClass,
+ new Name(name, enclosingClass.library), parameterStructure,
+ isExternal: isExternal, isConst: isConst);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.generativeConstructor);
+ sink.begin(tag);
+ sink.writeClass(enclosingClass);
+ sink.writeString(name);
+ parameterStructure.writeToDataSink(sink);
+ sink.writeBool(isExternal);
+ sink.writeBool(isConst);
+ sink.end(tag);
+ }
+
@override
bool get isFactoryConstructor => false;
@@ -458,6 +619,10 @@
}
class JFactoryConstructor extends JConstructor {
+ /// Tag used for identifying serialized [JFactoryConstructor] objects in a
+ /// debugging data stream.
+ static const String tag = 'factory-constructor';
+
@override
final bool isFromEnvironmentConstructor;
@@ -467,6 +632,36 @@
: super(enclosingClass, name, parameterStructure,
isExternal: isExternal, isConst: isConst);
+ factory JFactoryConstructor.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JClass enclosingClass = source.readClass();
+ String name = source.readString();
+ ParameterStructure parameterStructure =
+ new ParameterStructure.readFromDataSource(source);
+ bool isExternal = source.readBool();
+ bool isConst = source.readBool();
+ bool isFromEnvironmentConstructor = source.readBool();
+ source.end(tag);
+ return new JFactoryConstructor(enclosingClass,
+ new Name(name, enclosingClass.library), parameterStructure,
+ isExternal: isExternal,
+ isConst: isConst,
+ isFromEnvironmentConstructor: isFromEnvironmentConstructor);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.factoryConstructor);
+ sink.begin(tag);
+ sink.writeClass(enclosingClass);
+ sink.writeString(name);
+ parameterStructure.writeToDataSink(sink);
+ sink.writeBool(isExternal);
+ sink.writeBool(isConst);
+ sink.writeBool(isFromEnvironmentConstructor);
+ sink.end(tag);
+ }
+
@override
bool get isFactoryConstructor => true;
@@ -475,7 +670,11 @@
}
class JConstructorBody extends JFunction implements ConstructorBodyEntity {
- final ConstructorEntity constructor;
+ /// Tag used for identifying serialized [JConstructorBody] objects in a
+ /// debugging data stream.
+ static const String tag = 'constructor-body';
+
+ final JConstructor constructor;
JConstructorBody(this.constructor)
: super(
@@ -487,10 +686,29 @@
isStatic: false,
isExternal: false);
+ factory JConstructorBody.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JConstructor constructor = source.readMember();
+ source.end(tag);
+ return new JConstructorBody(constructor);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.constructorBody);
+ sink.begin(tag);
+ sink.writeMember(constructor);
+ sink.end(tag);
+ }
+
String get _kind => 'constructor_body';
}
class JMethod extends JFunction {
+ /// Tag used for identifying serialized [JMethod] objects in a
+ /// debugging data stream.
+ static const String tag = 'method';
+
final bool isAbstract;
JMethod(JLibrary library, JClass enclosingClass, Name name,
@@ -499,6 +717,53 @@
: super(library, enclosingClass, name, parameterStructure, asyncMarker,
isStatic: isStatic, isExternal: isExternal);
+ factory JMethod.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ MemberContextKind kind = source.readEnum(MemberContextKind.values);
+ JLibrary library;
+ JClass enclosingClass;
+ switch (kind) {
+ case MemberContextKind.library:
+ library = source.readLibrary();
+ break;
+ case MemberContextKind.cls:
+ enclosingClass = source.readClass();
+ library = enclosingClass.library;
+ break;
+ }
+ String name = source.readString();
+ ParameterStructure parameterStructure =
+ new ParameterStructure.readFromDataSource(source);
+ AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
+ bool isStatic = source.readBool();
+ bool isExternal = source.readBool();
+ bool isAbstract = source.readBool();
+ source.end(tag);
+ return new JMethod(library, enclosingClass, new Name(name, library),
+ parameterStructure, asyncMarker,
+ isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.method);
+ sink.begin(tag);
+ if (enclosingClass != null) {
+ sink.writeEnum(MemberContextKind.cls);
+ sink.writeClass(enclosingClass);
+ } else {
+ sink.writeEnum(MemberContextKind.library);
+ sink.writeLibrary(library);
+ }
+ sink.writeString(name);
+ parameterStructure.writeToDataSink(sink);
+ sink.writeEnum(asyncMarker);
+ sink.writeBool(isStatic);
+ sink.writeBool(isExternal);
+ sink.writeBool(isAbstract);
+ sink.end(tag);
+ }
+
@override
bool get isFunction => true;
@@ -506,7 +771,11 @@
}
class JGeneratorBody extends JFunction {
- final FunctionEntity function;
+ /// Tag used for identifying serialized [JGeneratorBody] objects in a
+ /// debugging data stream.
+ static const String tag = 'generator-body';
+
+ final JFunction function;
final DartType elementType;
final int hashCode;
@@ -516,10 +785,31 @@
function.parameterStructure, function.asyncMarker,
isStatic: function.isStatic, isExternal: false);
+ factory JGeneratorBody.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JFunction function = source.readMember();
+ DartType elementType = source.readDartType();
+ source.end(tag);
+ return new JGeneratorBody(function, elementType);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.generatorBody);
+ sink.begin(tag);
+ sink.writeMember(function);
+ sink.writeDartType(elementType);
+ sink.end(tag);
+ }
+
String get _kind => 'generator_body';
}
class JGetter extends JFunction {
+ /// Tag used for identifying serialized [JGetter] objects in a
+ /// debugging data stream.
+ static const String tag = 'getter';
+
final bool isAbstract;
JGetter(JLibrary library, JClass enclosingClass, Name name,
@@ -529,6 +819,50 @@
asyncMarker,
isStatic: isStatic, isExternal: isExternal);
+ factory JGetter.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ MemberContextKind kind = source.readEnum(MemberContextKind.values);
+ JLibrary library;
+ JClass enclosingClass;
+ switch (kind) {
+ case MemberContextKind.library:
+ library = source.readLibrary();
+ break;
+ case MemberContextKind.cls:
+ enclosingClass = source.readClass();
+ library = enclosingClass.library;
+ break;
+ }
+ String name = source.readString();
+ AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
+ bool isStatic = source.readBool();
+ bool isExternal = source.readBool();
+ bool isAbstract = source.readBool();
+ source.end(tag);
+ return new JGetter(
+ library, enclosingClass, new Name(name, library), asyncMarker,
+ isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.getter);
+ sink.begin(tag);
+ if (enclosingClass != null) {
+ sink.writeEnum(MemberContextKind.cls);
+ sink.writeClass(enclosingClass);
+ } else {
+ sink.writeEnum(MemberContextKind.library);
+ sink.writeLibrary(library);
+ }
+ sink.writeString(name);
+ sink.writeEnum(asyncMarker);
+ sink.writeBool(isStatic);
+ sink.writeBool(isExternal);
+ sink.writeBool(isAbstract);
+ sink.end(tag);
+ }
+
@override
bool get isGetter => true;
@@ -536,6 +870,10 @@
}
class JSetter extends JFunction {
+ /// Tag used for identifying serialized [JSetter] objects in a
+ /// debugging data stream.
+ static const String tag = 'setter';
+
final bool isAbstract;
JSetter(JLibrary library, JClass enclosingClass, Name name,
@@ -544,6 +882,47 @@
AsyncMarker.SYNC,
isStatic: isStatic, isExternal: isExternal);
+ factory JSetter.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ MemberContextKind kind = source.readEnum(MemberContextKind.values);
+ JLibrary library;
+ JClass enclosingClass;
+ switch (kind) {
+ case MemberContextKind.library:
+ library = source.readLibrary();
+ break;
+ case MemberContextKind.cls:
+ enclosingClass = source.readClass();
+ library = enclosingClass.library;
+ break;
+ }
+ String name = source.readString();
+ bool isStatic = source.readBool();
+ bool isExternal = source.readBool();
+ bool isAbstract = source.readBool();
+ source.end(tag);
+ return new JSetter(library, enclosingClass, new Name(name, library),
+ isStatic: isStatic, isExternal: isExternal, isAbstract: isAbstract);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.setter);
+ sink.begin(tag);
+ if (enclosingClass != null) {
+ sink.writeEnum(MemberContextKind.cls);
+ sink.writeClass(enclosingClass);
+ } else {
+ sink.writeEnum(MemberContextKind.library);
+ sink.writeLibrary(library);
+ }
+ sink.writeString(name);
+ sink.writeBool(isStatic);
+ sink.writeBool(isExternal);
+ sink.writeBool(isAbstract);
+ sink.end(tag);
+ }
+
@override
bool get isAssignable => true;
@@ -554,6 +933,10 @@
}
class JField extends JMember implements FieldEntity, IndexedField {
+ /// Tag used for identifying serialized [JField] objects in a
+ /// debugging data stream.
+ static const String tag = 'field';
+
final bool isAssignable;
final bool isConst;
@@ -561,6 +944,47 @@
{bool isStatic, this.isAssignable, this.isConst})
: super(library, enclosingClass, name, isStatic: isStatic);
+ factory JField.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ MemberContextKind kind = source.readEnum(MemberContextKind.values);
+ JLibrary library;
+ JClass enclosingClass;
+ switch (kind) {
+ case MemberContextKind.library:
+ library = source.readLibrary();
+ break;
+ case MemberContextKind.cls:
+ enclosingClass = source.readClass();
+ library = enclosingClass.library;
+ break;
+ }
+ String name = source.readString();
+ bool isStatic = source.readBool();
+ bool isAssignable = source.readBool();
+ bool isConst = source.readBool();
+ source.end(tag);
+ return new JField(library, enclosingClass, new Name(name, library),
+ isStatic: isStatic, isAssignable: isAssignable, isConst: isConst);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.field);
+ sink.begin(tag);
+ if (enclosingClass != null) {
+ sink.writeEnum(MemberContextKind.cls);
+ sink.writeClass(enclosingClass);
+ } else {
+ sink.writeEnum(MemberContextKind.library);
+ sink.writeLibrary(library);
+ }
+ sink.writeString(name);
+ sink.writeBool(isStatic);
+ sink.writeBool(isAssignable);
+ sink.writeBool(isConst);
+ sink.end(tag);
+ }
+
@override
bool get isField => true;
@@ -568,33 +992,137 @@
}
class JClosureCallMethod extends JMethod {
+ /// Tag used for identifying serialized [JClosureCallMethod] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-call-method';
+
JClosureCallMethod(ClassEntity enclosingClass,
ParameterStructure parameterStructure, AsyncMarker asyncMarker)
: super(enclosingClass.library, enclosingClass, Names.call,
parameterStructure, asyncMarker,
isStatic: false, isExternal: false, isAbstract: false);
+ factory JClosureCallMethod.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JClass enclosingClass = source.readClass();
+ ParameterStructure parameterStructure =
+ new ParameterStructure.readFromDataSource(source);
+ AsyncMarker asyncMarker = source.readEnum(AsyncMarker.values);
+ source.end(tag);
+ return new JClosureCallMethod(
+ enclosingClass, parameterStructure, asyncMarker);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.closureCallMethod);
+ sink.begin(tag);
+ sink.writeClass(enclosingClass);
+ parameterStructure.writeToDataSink(sink);
+ sink.writeEnum(asyncMarker);
+ sink.end(tag);
+ }
+
String get _kind => 'closure_call';
}
/// A method that returns the signature of the Dart closure/tearoff that this
/// method's parent class is representing.
class JSignatureMethod extends JMethod {
+ /// Tag used for identifying serialized [JSignatureMethod] objects in a
+ /// debugging data stream.
+ static const String tag = 'signature-method';
+
JSignatureMethod(ClassEntity enclosingClass)
: super(enclosingClass.library, enclosingClass, Names.signature,
const ParameterStructure(0, 0, const [], 0), AsyncMarker.SYNC,
isStatic: false, isExternal: false, isAbstract: false);
+ factory JSignatureMethod.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JClass cls = source.readClass();
+ source.end(tag);
+ return new JSignatureMethod(cls);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberKind.signatureMethod);
+ sink.begin(tag);
+ sink.writeClass(enclosingClass);
+ sink.end(tag);
+ }
+
String get _kind => 'signature';
}
+/// Enum used for identifying [JTypeVariable] variants in serialization.
+enum JTypeVariableKind { cls, member, typedef, local }
+
class JTypeVariable extends IndexedTypeVariable {
+ /// Tag used for identifying serialized [JTypeVariable] objects in a
+ /// debugging data stream.
+ static const String tag = 'type-variable';
+
final Entity typeDeclaration;
final String name;
final int index;
JTypeVariable(this.typeDeclaration, this.name, this.index);
+ /// Deserializes a [JTypeVariable] object from [source].
+ factory JTypeVariable.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ JTypeVariableKind kind = source.readEnum(JTypeVariableKind.values);
+ Entity typeDeclaration;
+ switch (kind) {
+ case JTypeVariableKind.cls:
+ typeDeclaration = source.readClass();
+ break;
+ case JTypeVariableKind.member:
+ typeDeclaration = source.readMember();
+ break;
+ case JTypeVariableKind.typedef:
+ typeDeclaration = source.readTypedef();
+ break;
+ case JTypeVariableKind.local:
+ // Type variables declared by local functions don't point to their
+ // declaration, since the corresponding closure call methods is created
+ // after the type variable.
+ // TODO(johnniwinther): Fix this.
+ break;
+ }
+ String name = source.readString();
+ int index = source.readInt();
+ source.end(tag);
+ return new JTypeVariable(typeDeclaration, name, index);
+ }
+
+ /// Serializes this [JTypeVariable] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ if (typeDeclaration is IndexedClass) {
+ IndexedClass cls = typeDeclaration;
+ sink.writeEnum(JTypeVariableKind.cls);
+ sink.writeClass(cls);
+ } else if (typeDeclaration is IndexedMember) {
+ IndexedMember member = typeDeclaration;
+ sink.writeEnum(JTypeVariableKind.member);
+ sink.writeMember(member);
+ } else if (typeDeclaration is IndexedTypedef) {
+ IndexedTypedef typedef = typeDeclaration;
+ sink.writeEnum(JTypeVariableKind.typedef);
+ sink.writeTypedef(typedef);
+ } else if (typeDeclaration == null) {
+ sink.writeEnum(JTypeVariableKind.local);
+ } else {
+ throw new UnsupportedError(
+ "Unexpected type variable declarer $typeDeclaration.");
+ }
+ sink.writeString(name);
+ sink.writeInt(index);
+ sink.end(tag);
+ }
+
String toString() =>
'${jsElementPrefix}type_variable(${typeDeclaration.name}.$name)';
}
diff --git a/pkg/compiler/lib/src/js_model/env.dart b/pkg/compiler/lib/src/js_model/env.dart
index d2e4f8c..876106a 100644
--- a/pkg/compiler/lib/src/js_model/env.dart
+++ b/pkg/compiler/lib/src/js_model/env.dart
@@ -18,14 +18,16 @@
import '../ir/util.dart';
import '../js_model/element_map.dart';
import '../ordered_typeset.dart';
+import '../serialization/serialization.dart';
import '../ssa/type_builder.dart';
+import 'closure.dart';
import 'element_map.dart';
import 'element_map_impl.dart';
import 'elements.dart';
/// Environment for fast lookup of component libraries.
class JProgramEnv {
- final Set<ir.Component> _components;
+ final Iterable<ir.Component> _components;
final Map<Uri, JLibraryEnv> _libraryMap = {};
JProgramEnv(this._components);
@@ -57,6 +59,10 @@
/// Environment for fast lookup of library classes and members.
class JLibraryEnv {
+ /// Tag used for identifying serialized [JLibraryEnv] objects in a
+ /// debugging data stream.
+ static const String tag = 'library-env';
+
final ir.Library library;
final Map<String, JClassEnv> _classMap = {};
final Map<String, ir.Member> _memberMap;
@@ -64,6 +70,27 @@
JLibraryEnv(this.library, this._memberMap, this._setterMap);
+ /// Deserializes a [JLibraryEnv] object from [source].
+ factory JLibraryEnv.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Library library = source.readLibraryNode();
+ Map<String, ir.Member> memberMap =
+ source.readStringMap(source.readMemberNode);
+ Map<String, ir.Member> setterMap =
+ source.readStringMap(source.readMemberNode);
+ source.end(tag);
+ return new JLibraryEnv(library, memberMap, setterMap);
+ }
+
+ /// Serializes this [JLibraryEnv] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeLibraryNode(library);
+ sink.writeStringMap(_memberMap, sink.writeMemberNode);
+ sink.writeStringMap(_setterMap, sink.writeMemberNode);
+ sink.end(tag);
+ }
+
void registerClass(String name, JClassEnv classEnv) {
_classMap[name] = classEnv;
}
@@ -96,16 +123,64 @@
}
class JLibraryData {
+ /// Tag used for identifying serialized [JLibraryData] objects in a
+ /// debugging data stream.
+ static const String tag = 'library-data';
+
final ir.Library library;
// TODO(johnniwinther): Avoid direct access to [imports]. It might be null if
// it hasn't been computed for the corresponding [KLibraryData].
final Map<ir.LibraryDependency, ImportEntity> imports;
JLibraryData(this.library, this.imports);
+
+ factory JLibraryData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Library library = source.readLibraryNode();
+ int importCount = source.readInt();
+ Map<ir.LibraryDependency, ImportEntity> imports;
+ if (importCount > 0) {
+ // TODO(johnniwinther): Deserialize imports.
+ }
+ source.end(tag);
+ return new JLibraryData(library, imports);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeLibraryNode(library);
+ if (imports == null) {
+ sink.writeInt(0);
+ } else {
+ sink.writeInt(imports.length);
+ // TODO(johnniwinther): Serialize imports.
+ }
+ sink.end(tag);
+ }
}
+/// Enum used for identifying [JClassEnv] subclasses in serialization.
+enum JClassEnvKind { node, closure, record }
+
/// Member data for a class.
abstract class JClassEnv {
+ /// Deserializes a [JClassEnv] object from [source].
+ factory JClassEnv.readFromDataSource(DataSource source) {
+ JClassEnvKind kind = source.readEnum(JClassEnvKind.values);
+ switch (kind) {
+ case JClassEnvKind.node:
+ return new JClassEnvImpl.readFromDataSource(source);
+ case JClassEnvKind.closure:
+ return new ClosureClassEnv.readFromDataSource(source);
+ case JClassEnvKind.record:
+ return new RecordEnv.readFromDataSource(source);
+ }
+ throw new UnsupportedError("Unsupported JClassEnvKind $kind");
+ }
+
+ /// Serializes this [JClassEnv] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// The [ir.Class] that defined the class, if any.
ir.Class get cls;
@@ -139,6 +214,10 @@
/// Environment for fast lookup of class members.
class JClassEnvImpl implements JClassEnv {
+ /// Tag used for identifying serialized [JClassEnv] objects in a
+ /// debugging data stream.
+ static const String tag = 'class-env';
+
final ir.Class cls;
final Map<String, ir.Member> _constructorMap;
final Map<String, ir.Member> _memberMap;
@@ -152,6 +231,35 @@
JClassEnvImpl(this.cls, this._constructorMap, this._memberMap,
this._setterMap, this._members, this.isSuperMixinApplication);
+ factory JClassEnvImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Class cls = source.readClassNode();
+ Map<String, ir.Member> constructorMap =
+ source.readStringMap(source.readMemberNode);
+ Map<String, ir.Member> memberMap =
+ source.readStringMap(source.readMemberNode);
+ Map<String, ir.Member> setterMap =
+ source.readStringMap(source.readMemberNode);
+ List<ir.Member> members = source.readMemberNodes();
+ bool isSuperMixinApplication = source.readBool();
+ source.end(tag);
+ return new JClassEnvImpl(cls, constructorMap, memberMap, setterMap, members,
+ isSuperMixinApplication);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassEnvKind.node);
+ sink.begin(tag);
+ sink.writeClassNode(cls);
+ sink.writeStringMap(_constructorMap, sink.writeMemberNode);
+ sink.writeStringMap(_memberMap, sink.writeMemberNode);
+ sink.writeStringMap(_setterMap, sink.writeMemberNode);
+ sink.writeMemberNodes(_members);
+ sink.writeBool(isSuperMixinApplication);
+ sink.end(tag);
+ }
+
bool get isUnnamedMixinApplication => cls.isAnonymousMixin;
/// Return the [MemberEntity] for the member [name] in [cls]. If [setter] is
@@ -195,10 +303,31 @@
}
class RecordEnv implements JClassEnv {
+ /// Tag used for identifying serialized [RecordEnv] objects in a
+ /// debugging data stream.
+ static const String tag = 'record-env';
+
final Map<String, IndexedMember> _memberMap;
RecordEnv(this._memberMap);
+ factory RecordEnv.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Map<String, IndexedMember> _memberMap =
+ source.readStringMap(() => source.readMember());
+ source.end(tag);
+ return new RecordEnv(_memberMap);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassEnvKind.record);
+ sink.begin(tag);
+ sink.writeStringMap(
+ _memberMap, (IndexedMember member) => sink.writeMember(member));
+ sink.end(tag);
+ }
+
@override
void forEachConstructorBody(void f(ConstructorBodyEntity constructor)) {
// We do not create constructor bodies for containers.
@@ -238,8 +367,29 @@
}
class ClosureClassEnv extends RecordEnv {
+ /// Tag used for identifying serialized [ClosureClassEnv] objects in a
+ /// debugging data stream.
+ static const String tag = 'closure-class-env';
+
ClosureClassEnv(Map<String, MemberEntity> memberMap) : super(memberMap);
+ factory ClosureClassEnv.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Map<String, IndexedMember> _memberMap =
+ source.readStringMap(() => source.readMember());
+ source.end(tag);
+ return new ClosureClassEnv(_memberMap);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassEnvKind.closure);
+ sink.begin(tag);
+ sink.writeStringMap(
+ _memberMap, (IndexedMember member) => sink.writeMember(member));
+ sink.end(tag);
+ }
+
@override
MemberEntity lookupMember(IrToElementMap elementMap, String name,
{bool setter: false}) {
@@ -251,7 +401,27 @@
}
}
+/// Enum used for identifying [JClassData] subclasses in serialization.
+enum JClassDataKind { node, closure, record }
+
abstract class JClassData {
+ /// Deserializes a [JClassData] object from [source].
+ factory JClassData.readFromDataSource(DataSource source) {
+ JClassDataKind kind = source.readEnum(JClassDataKind.values);
+ switch (kind) {
+ case JClassDataKind.node:
+ return new JClassDataImpl.readFromDataSource(source);
+ case JClassDataKind.closure:
+ return new ClosureClassData.readFromDataSource(source);
+ case JClassDataKind.record:
+ return new RecordClassData.readFromDataSource(source);
+ }
+ throw new UnsupportedError("Unexpected JClassDataKind $kind");
+ }
+
+ /// Serializes this [JClassData] to [sink].
+ void writeToDataSink(DataSink sink);
+
ClassDefinition get definition;
InterfaceType get thisType;
@@ -267,6 +437,10 @@
}
class JClassDataImpl implements JClassData {
+ /// Tag used for identifying serialized [JClassDataImpl] objects in a
+ /// debugging data stream.
+ static const String tag = 'class-data';
+
final ir.Class cls;
final ClassDefinition definition;
bool isMixinApplication;
@@ -281,17 +455,75 @@
JClassDataImpl(this.cls, this.definition);
+ factory JClassDataImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Class cls = source.readClassNode();
+ ClassDefinition definition = new ClassDefinition.readFromDataSource(source);
+ source.end(tag);
+ return new JClassDataImpl(cls, definition);
+ }
+
+ @override
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JClassDataKind.node);
+ sink.begin(tag);
+ sink.writeClassNode(cls);
+ definition.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
bool get isEnumClass => cls != null && cls.isEnum;
DartType get callType => null;
}
+/// Enum used for identifying [JMemberData] subclasses in serialization.
+enum JMemberDataKind {
+ function,
+ field,
+ constructor,
+ constructorBody,
+ signature,
+ generatorBody,
+ closureFunction,
+ closureField,
+}
+
abstract class JMemberData {
MemberDefinition get definition;
InterfaceType getMemberThisType(JsToElementMap elementMap);
ClassTypeVariableAccess get classTypeVariableAccess;
+
+ JMemberData();
+
+ /// Deserializes a [JMemberData] object from [source].
+ factory JMemberData.readFromDataSource(DataSource source) {
+ JMemberDataKind kind = source.readEnum(JMemberDataKind.values);
+ switch (kind) {
+ case JMemberDataKind.function:
+ return new FunctionDataImpl.readFromDataSource(source);
+ case JMemberDataKind.field:
+ return new JFieldDataImpl.readFromDataSource(source);
+ case JMemberDataKind.constructor:
+ return new JConstructorDataImpl.readFromDataSource(source);
+ case JMemberDataKind.constructorBody:
+ return new ConstructorBodyDataImpl.readFromDataSource(source);
+ case JMemberDataKind.signature:
+ return new SignatureFunctionData.readFromDataSource(source);
+ case JMemberDataKind.generatorBody:
+ return new GeneratorBodyFunctionData.readFromDataSource(source);
+ case JMemberDataKind.closureFunction:
+ return new ClosureFunctionData.readFromDataSource(source);
+ case JMemberDataKind.closureField:
+ return new ClosureFieldData.readFromDataSource(source);
+ }
+ throw new UnsupportedError("Unexpected JMemberDataKind $kind");
+ }
+
+ /// Serializes this [JMemberData] to [sink].
+ void writeToDataSink(DataSink sink);
}
abstract class JMemberDataImpl implements JMemberData {
@@ -351,6 +583,10 @@
class FunctionDataImpl extends JMemberDataImpl
with FunctionDataMixin
implements FunctionData {
+ /// Tag used for identifying serialized [FunctionDataImpl] objects in a
+ /// debugging data stream.
+ static const String tag = 'function-data';
+
final ir.FunctionNode functionNode;
FunctionType _type;
@@ -358,6 +594,32 @@
ir.Member node, this.functionNode, MemberDefinition definition)
: super(node, definition);
+ factory FunctionDataImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Member node = source.readMemberNode();
+ ir.FunctionNode functionNode;
+ if (node is ir.Procedure) {
+ functionNode = node.function;
+ } else if (node is ir.Constructor) {
+ functionNode = node.function;
+ } else {
+ throw new UnsupportedError(
+ "Unexpected member node $node (${node.runtimeType}).");
+ }
+ MemberDefinition definition =
+ new MemberDefinition.readFromDataSource(source);
+ source.end(tag);
+ return new FunctionDataImpl(node, functionNode, definition);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberDataKind.function);
+ sink.begin(tag);
+ sink.writeMemberNode(node);
+ definition.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
FunctionType getFunctionType(covariant JsToElementMapBase elementMap) {
return _type ??= elementMap.getFunctionType(functionNode);
}
@@ -395,6 +657,10 @@
}
class SignatureFunctionData implements FunctionData {
+ /// Tag used for identifying serialized [SignatureFunctionData] objects in a
+ /// debugging data stream.
+ static const String tag = 'signature-function-data';
+
final MemberDefinition definition;
final InterfaceType memberThisType;
final ClassTypeVariableAccess classTypeVariableAccess;
@@ -403,6 +669,29 @@
SignatureFunctionData(this.definition, this.memberThisType,
this.typeParameters, this.classTypeVariableAccess);
+ factory SignatureFunctionData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ MemberDefinition definition =
+ new MemberDefinition.readFromDataSource(source);
+ InterfaceType memberThisType = source.readDartType(allowNull: true);
+ List<ir.TypeParameter> typeParameters = source.readTypeParameterNodes();
+ ClassTypeVariableAccess classTypeVariableAccess =
+ source.readEnum(ClassTypeVariableAccess.values);
+ source.end(tag);
+ return new SignatureFunctionData(
+ definition, memberThisType, typeParameters, classTypeVariableAccess);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberDataKind.signature);
+ sink.begin(tag);
+ definition.writeToDataSink(sink);
+ sink.writeDartType(memberThisType, allowNull: true);
+ sink.writeTypeParameterNodes(typeParameters);
+ sink.writeEnum(classTypeVariableAccess);
+ sink.end(tag);
+ }
+
FunctionType getFunctionType(covariant JsToElementMapBase elementMap) {
throw new UnsupportedError("SignatureFunctionData.getFunctionType");
}
@@ -451,9 +740,32 @@
}
class GeneratorBodyFunctionData extends DelegatedFunctionData {
+ /// Tag used for identifying serialized [GeneratorBodyFunctionData] objects in
+ /// a debugging data stream.
+ static const String tag = 'generator-body-data';
+
final MemberDefinition definition;
+
GeneratorBodyFunctionData(FunctionData baseData, this.definition)
: super(baseData);
+
+ factory GeneratorBodyFunctionData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ // TODO(johnniwinther): Share the original base data on deserialization.
+ FunctionData baseData = new JMemberData.readFromDataSource(source);
+ MemberDefinition definition =
+ new MemberDefinition.readFromDataSource(source);
+ source.end(tag);
+ return new GeneratorBodyFunctionData(baseData, definition);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberDataKind.generatorBody);
+ sink.begin(tag);
+ baseData.writeToDataSink(sink);
+ definition.writeToDataSink(sink);
+ sink.end(tag);
+ }
}
abstract class JConstructorData extends FunctionData {
@@ -463,6 +775,10 @@
class JConstructorDataImpl extends FunctionDataImpl
implements JConstructorData {
+ /// Tag used for identifying serialized [JConstructorDataImpl] objects in a
+ /// debugging data stream.
+ static const String tag = 'constructor-data';
+
ConstantConstructor _constantConstructor;
JConstructorBody constructorBody;
@@ -470,6 +786,33 @@
ir.Member node, ir.FunctionNode functionNode, MemberDefinition definition)
: super(node, functionNode, definition);
+ factory JConstructorDataImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Member node = source.readMemberNode();
+ ir.FunctionNode functionNode;
+ if (node is ir.Procedure) {
+ functionNode = node.function;
+ } else if (node is ir.Constructor) {
+ functionNode = node.function;
+ } else {
+ throw new UnsupportedError(
+ "Unexpected member node $node (${node.runtimeType}).");
+ }
+ MemberDefinition definition =
+ new MemberDefinition.readFromDataSource(source);
+ source.end(tag);
+ return new JConstructorDataImpl(node, functionNode, definition);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberDataKind.constructor);
+ sink.begin(tag);
+ sink.writeMemberNode(node);
+ definition.writeToDataSink(sink);
+ assert(constructorBody == null);
+ sink.end(tag);
+ }
+
ConstantConstructor getConstructorConstant(
JsToElementMapBase elementMap, ConstructorEntity constructor) {
if (_constantConstructor == null) {
@@ -492,10 +835,40 @@
}
class ConstructorBodyDataImpl extends FunctionDataImpl {
+ /// Tag used for identifying serialized [ConstructorBodyDataImpl] objects in
+ /// a debugging data stream.
+ static const String tag = 'constructor-body-data';
+
ConstructorBodyDataImpl(
ir.Member node, ir.FunctionNode functionNode, MemberDefinition definition)
: super(node, functionNode, definition);
+ factory ConstructorBodyDataImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Member node = source.readMemberNode();
+ ir.FunctionNode functionNode;
+ if (node is ir.Procedure) {
+ functionNode = node.function;
+ } else if (node is ir.Constructor) {
+ functionNode = node.function;
+ } else {
+ throw new UnsupportedError(
+ "Unexpected member node $node (${node.runtimeType}).");
+ }
+ MemberDefinition definition =
+ new MemberDefinition.readFromDataSource(source);
+ source.end(tag);
+ return new ConstructorBodyDataImpl(node, functionNode, definition);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberDataKind.constructorBody);
+ sink.begin(tag);
+ sink.writeMemberNode(node);
+ definition.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
// TODO(johnniwinther,sra): Constructor bodies should access type variables
// through `this`.
@override
@@ -518,6 +891,10 @@
}
class JFieldDataImpl extends JMemberDataImpl implements JFieldData {
+ /// Tag used for identifying serialized [JFieldDataImpl] objects in
+ /// a debugging data stream.
+ static const String tag = 'field-data';
+
DartType _type;
bool _isConstantComputed = false;
ConstantValue _constantValue;
@@ -526,6 +903,23 @@
JFieldDataImpl(ir.Field node, MemberDefinition definition)
: super(node, definition);
+ factory JFieldDataImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.Member node = source.readMemberNode();
+ MemberDefinition definition =
+ new MemberDefinition.readFromDataSource(source);
+ source.end(tag);
+ return new JFieldDataImpl(node, definition);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeEnum(JMemberDataKind.field);
+ sink.begin(tag);
+ sink.writeMemberNode(node);
+ definition.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
ir.Field get node => super.node;
DartType getFieldType(covariant JsToElementMapBase elementMap) {
@@ -582,18 +976,52 @@
}
class JTypedefData {
+ /// Tag used for identifying serialized [JTypedefData] objects in
+ /// a debugging data stream.
+ static const String tag = 'typedef-data';
+
final TypedefType rawType;
JTypedefData(this.rawType);
+
+ factory JTypedefData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ TypedefType rawType = source.readDartType();
+ source.end(tag);
+ return new JTypedefData(rawType);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeDartType(rawType);
+ sink.end(tag);
+ }
}
class JTypeVariableData {
+ /// Tag used for identifying serialized [JTypeVariableData] objects in
+ /// a debugging data stream.
+ static const String tag = 'type-variable-data';
+
final ir.TypeParameter node;
DartType _bound;
DartType _defaultType;
JTypeVariableData(this.node);
+ factory JTypeVariableData.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ ir.TypeParameter node = source.readTypeParameterNode();
+ source.end(tag);
+ return new JTypeVariableData(node);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeTypeParameterNode(node);
+ sink.end(tag);
+ }
+
DartType getBound(IrToElementMap elementMap) {
return _bound ??= elementMap.getDartType(node.bound);
}
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 7b9921c..3421f91 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -16,10 +16,12 @@
import '../constants/constant_system.dart';
import '../constants/values.dart';
import '../deferred_load.dart';
+import '../diagnostics/diagnostic_listener.dart';
import '../elements/entities.dart';
import '../elements/names.dart';
import '../elements/types.dart';
import '../elements/entity_utils.dart' as utils;
+import '../environment.dart';
import '../enqueue.dart';
import '../io/kernel_source_information.dart'
show KernelSourceInformationStrategy;
@@ -42,6 +44,7 @@
import '../native/behavior.dart';
import '../ordered_typeset.dart';
import '../options.dart';
+import '../serialization/serialization.dart';
import '../ssa/builder_kernel.dart';
import '../ssa/nodes.dart';
import '../ssa/ssa.dart';
@@ -64,7 +67,6 @@
class JsBackendStrategy implements BackendStrategy {
final Compiler _compiler;
JsKernelToElementMap _elementMap;
- Sorter _sorter;
JsBackendStrategy(this._compiler);
@@ -101,8 +103,8 @@
}
@override
- Sorter get sorter {
- return _sorter ??= new KernelSorter(elementMap);
+ void registerJClosedWorld(covariant JsClosedWorld closedWorld) {
+ _elementMap = closedWorld.elementMap;
}
@override
@@ -634,6 +636,8 @@
}
class JsClosedWorld extends ClosedWorldBase {
+ static const String tag = 'closed-world';
+
final JsKernelToElementMap elementMap;
final RuntimeTypesNeed rtiNeed;
AbstractValueDomain _abstractValueDomain;
@@ -642,6 +646,7 @@
final GlobalLocalsMap globalLocalsMap;
final ClosureData closureDataLookup;
final OutputUnitData outputUnitData;
+ Sorter _sorter;
JsClosedWorld(this.elementMap,
{ConstantSystem constantSystem,
@@ -656,8 +661,8 @@
Iterable<MemberEntity> liveInstanceMembers,
Iterable<MemberEntity> assignedInstanceMembers,
Iterable<MemberEntity> processedMembers,
- Map<ClassEntity, Iterable<ClassEntity>> mixinUses,
- Map<ClassEntity, Iterable<ClassEntity>> typesImplementedBySubclasses,
+ Map<ClassEntity, Set<ClassEntity>> mixinUses,
+ Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses,
ClassHierarchy classHierarchy,
AbstractValueStrategy abstractValueStrategy,
this.annotationsData,
@@ -684,6 +689,113 @@
_abstractValueDomain = abstractValueStrategy.createDomain(this);
}
+ /// Deserializes a [JsClosedWorld] object from [source].
+ factory JsClosedWorld.readFromDataSource(
+ CompilerOptions options,
+ DiagnosticReporter reporter,
+ Environment environment,
+ AbstractValueStrategy abstractValueStrategy,
+ ir.Component component,
+ DataSource source) {
+ source.begin(tag);
+
+ JsKernelToElementMap elementMap =
+ new JsKernelToElementMap.readFromDataSource(
+ options, reporter, environment, component, source);
+ GlobalLocalsMap globalLocalsMap =
+ new GlobalLocalsMap.readFromDataSource(source);
+ source.registerLocalLookup(new LocalLookupImpl(globalLocalsMap));
+ ClassHierarchy classHierarchy = new ClassHierarchy.readFromDataSource(
+ source, elementMap.commonElements);
+ NativeData nativeData = new NativeData.readFromDataSource(
+ source, elementMap.elementEnvironment);
+ elementMap.nativeBasicData = nativeData;
+ InterceptorData interceptorData = new InterceptorData.readFromDataSource(
+ source, nativeData, elementMap.commonElements);
+ BackendUsage backendUsage = new BackendUsage.readFromDataSource(source);
+ RuntimeTypesNeed rtiNeed = new RuntimeTypesNeed.readFromDataSource(
+ source, elementMap.elementEnvironment);
+ JAllocatorAnalysis allocatorAnalysis =
+ new JAllocatorAnalysis.readFromDataSource(source, options);
+ NoSuchMethodData noSuchMethodData =
+ new NoSuchMethodData.readFromDataSource(source);
+
+ Set<ClassEntity> implementedClasses = source.readClasses().toSet();
+ Iterable<ClassEntity> liveNativeClasses = source.readClasses();
+ Iterable<MemberEntity> liveInstanceMembers = source.readMembers();
+ Iterable<MemberEntity> assignedInstanceMembers = source.readMembers();
+ Iterable<MemberEntity> processedMembers = source.readMembers();
+ Map<ClassEntity, Set<ClassEntity>> mixinUses =
+ source.readClassMap(() => source.readClasses().toSet());
+ Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses =
+ source.readClassMap(() => source.readClasses().toSet());
+
+ AnnotationsData annotationsData =
+ new AnnotationsData.readFromDataSource(source);
+
+ ClosureData closureData =
+ new ClosureData.readFromDataSource(elementMap, source);
+
+ OutputUnitData outputUnitData =
+ new OutputUnitData.readFromDataSource(source);
+
+ source.end(tag);
+
+ return new JsClosedWorld(elementMap,
+ nativeData: nativeData,
+ interceptorData: interceptorData,
+ backendUsage: backendUsage,
+ rtiNeed: rtiNeed,
+ allocatorAnalysis: allocatorAnalysis,
+ noSuchMethodData: noSuchMethodData,
+ implementedClasses: implementedClasses,
+ liveNativeClasses: liveNativeClasses,
+ liveInstanceMembers: liveInstanceMembers,
+ assignedInstanceMembers: assignedInstanceMembers,
+ processedMembers: processedMembers,
+ mixinUses: mixinUses,
+ typesImplementedBySubclasses: typesImplementedBySubclasses,
+ classHierarchy: classHierarchy,
+ abstractValueStrategy: abstractValueStrategy,
+ annotationsData: annotationsData,
+ globalLocalsMap: globalLocalsMap,
+ closureDataLookup: closureData,
+ outputUnitData: outputUnitData);
+ }
+
+ /// Serializes this [JsClosedWorld] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ elementMap.writeToDataSink(sink);
+ globalLocalsMap.writeToDataSink(sink);
+
+ classHierarchy.writeToDataSink(sink);
+ nativeData.writeToDataSink(sink);
+ interceptorData.writeToDataSink(sink);
+ backendUsage.writeToDataSink(sink);
+ rtiNeed.writeToDataSink(sink);
+ allocatorAnalysis.writeToDataSink(sink);
+ noSuchMethodData.writeToDataSink(sink);
+ sink.writeClasses(implementedClasses);
+ sink.writeClasses(liveNativeClasses);
+ sink.writeMembers(liveInstanceMembers);
+ sink.writeMembers(assignedInstanceMembers);
+ sink.writeMembers(processedMembers);
+ sink.writeClassMap(
+ mixinUses, (Set<ClassEntity> set) => sink.writeClasses(set));
+ sink.writeClassMap(typesImplementedBySubclasses,
+ (Set<ClassEntity> set) => sink.writeClasses(set));
+ annotationsData.writeToDataSink(sink);
+ closureDataLookup.writeToDataSink(sink);
+ outputUnitData.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
+ @override
+ Sorter get sorter {
+ return _sorter ??= new KernelSorter(elementMap);
+ }
+
@override
AbstractValueDomain get abstractValueDomain {
return _abstractValueDomain;
@@ -1236,3 +1348,16 @@
a, definition1.location, b, definition2.location);
}
}
+
+/// [LocalLookup] implementation used to deserialize [JsClosedWorld].
+class LocalLookupImpl implements LocalLookup {
+ final GlobalLocalsMap _globalLocalsMap;
+
+ LocalLookupImpl(this._globalLocalsMap);
+
+ @override
+ Local getLocalByIndex(MemberEntity memberContext, int index) {
+ KernelToLocalsMapImpl map = _globalLocalsMap.getLocalsMap(memberContext);
+ return map.getLocalByIndex(index);
+ }
+}
diff --git a/pkg/compiler/lib/src/js_model/locals.dart b/pkg/compiler/lib/src/js_model/locals.dart
index 14a933d..6f66920 100644
--- a/pkg/compiler/lib/src/js_model/locals.dart
+++ b/pkg/compiler/lib/src/js_model/locals.dart
@@ -13,15 +13,60 @@
import '../elements/jumps.dart';
import '../elements/types.dart';
import '../ir/util.dart';
+import '../serialization/serialization.dart';
import 'element_map.dart';
import 'elements.dart' show JGeneratorBody;
class GlobalLocalsMap {
+ /// Tag used for identifying serialized [GlobalLocalsMap] objects in a
+ /// debugging data stream.
+ static const String tag = 'global-locals-map';
+
final Map<MemberEntity, KernelToLocalsMap> _localsMaps;
GlobalLocalsMap() : _localsMaps = {};
+ GlobalLocalsMap.internal(this._localsMaps);
+
+ /// Deserializes a [GlobalLocalsMap] object from [source].
+ factory GlobalLocalsMap.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ Map<MemberEntity, KernelToLocalsMap> _localsMaps = {};
+ int mapCount = source.readInt();
+ for (int i = 0; i < mapCount; i++) {
+ KernelToLocalsMap localsMap =
+ new KernelToLocalsMapImpl.readFromDataSource(source);
+ List<MemberEntity> members = source.readMembers();
+ for (MemberEntity member in members) {
+ _localsMaps[member] = localsMap;
+ }
+ }
+ source.end(tag);
+ return new GlobalLocalsMap.internal(_localsMaps);
+ }
+
+ /// Serializes this [GlobalLocalsMap] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ // [KernelToLocalsMap]s are shared between members and their nested
+ // closures, so we reverse [_localsMaps] to ensure that [KernelToLocalsMap]s
+ // are shared upon deserialization. The sharing is needed for correctness
+ // since captured variables will otherwise have distinct locals for their
+ // non-captured and captured uses.
+ Map<KernelToLocalsMap, List<MemberEntity>> reverseMap = {};
+ _localsMaps.forEach((MemberEntity member, KernelToLocalsMap localsMap) {
+ reverseMap.putIfAbsent(localsMap, () => []).add(member);
+ });
+ sink.writeInt(reverseMap.length);
+ reverseMap
+ .forEach((KernelToLocalsMap localsMap, List<MemberEntity> members) {
+ localsMap.writeToDataSink(sink);
+ sink.writeMembers(members);
+ });
+ sink.end(tag);
+ }
+
/// Returns the [KernelToLocalsMap] for [member].
KernelToLocalsMap getLocalsMap(MemberEntity member) {
// If element is a ConstructorBodyEntity, its localsMap is the same as for
@@ -48,6 +93,10 @@
}
class KernelToLocalsMapImpl implements KernelToLocalsMap {
+ /// Tag used for identifying serialized [KernelToLocalsMapImpl] objects in a
+ /// debugging data stream.
+ static const String tag = 'locals-map';
+
MemberEntity _currentMember;
final EntityDataMap<JLocal, LocalData> _locals =
new EntityDataMap<JLocal, LocalData>();
@@ -56,6 +105,73 @@
Map<ir.TreeNode, JJumpTarget> _jumpTargetMap;
Iterable<ir.BreakStatement> _breaksAsContinue;
+ KernelToLocalsMapImpl(this._currentMember);
+
+ /// Deserializes a [KernelToLocalsMapImpl] object from [source].
+ KernelToLocalsMapImpl.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ _currentMember = source.readMember();
+ int localsCount = source.readInt();
+ for (int i = 0; i < localsCount; i++) {
+ int index = source.readInt();
+ String name = source.readStringOrNull();
+ bool isRegularParameter = source.readBool();
+ ir.VariableDeclaration node = source.readTreeNode();
+ JLocal local = new JLocal(name, currentMember,
+ isRegularParameter: isRegularParameter);
+ LocalData data = new LocalData(node);
+ _locals.registerByIndex(index, local, data);
+ _variableMap[node] = local;
+ }
+ int jumpCount = source.readInt();
+ if (jumpCount > 0) {
+ _jumpTargetMap = {};
+ for (int i = 0; i < jumpCount; i++) {
+ JJumpTarget target = new JJumpTarget.readFromDataSource(source);
+ List<ir.TreeNode> nodes = source.readTreeNodes();
+ for (ir.TreeNode node in nodes) {
+ _jumpTargetMap[node] = target;
+ }
+ }
+ }
+ _breaksAsContinue = source.readTreeNodes();
+ source.end(tag);
+ }
+
+ /// Serializes this [KernelToLocalsMapImpl] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeMember(currentMember);
+ sink.writeInt(_locals.size);
+ _locals.forEach((JLocal local, LocalData data) {
+ assert(local.memberContext == currentMember);
+ sink.writeInt(local.localIndex);
+ sink.writeStringOrNull(local.name);
+ sink.writeBool(local.isRegularParameter);
+ sink.writeTreeNode(data.node);
+ });
+ if (_jumpTargetMap != null) {
+ // [JJumpTarget]s are shared between nodes, so we reverse
+ // [_jumpTargetMap] to ensure that [JJumpTarget]s are shared upon
+ // deserialization. This sharing is needed for correctness since for
+ // instance a label statement containing a for loop both constitutes the
+ // same jump target and the SSA graph builder dependents on this property.
+ Map<JJumpTarget, List<ir.TreeNode>> reversedMap = {};
+ _jumpTargetMap.forEach((ir.TreeNode node, JJumpTarget target) {
+ reversedMap.putIfAbsent(target, () => []).add(node);
+ });
+ sink.writeInt(reversedMap.length);
+ reversedMap.forEach((JJumpTarget target, List<ir.TreeNode> nodes) {
+ target.writeToDataSink(sink);
+ sink.writeTreeNodes(nodes);
+ });
+ } else {
+ sink.writeInt(0);
+ }
+ sink.writeTreeNodes(_breaksAsContinue, allowNull: true);
+ sink.end(tag);
+ }
+
// TODO(johnniwinther): Compute this eagerly from the root of the member.
void _ensureJumpMap(ir.TreeNode node) {
if (_jumpTargetMap == null) {
@@ -72,9 +188,12 @@
}
}
- KernelToLocalsMapImpl(this._currentMember);
-
MemberEntity get currentMember => _currentMember;
+
+ Local getLocalByIndex(int index) {
+ return _locals.getEntity(index);
+ }
+
@override
JumpTarget getJumpTargetForBreak(ir.BreakStatement node) {
_ensureJumpMap(node.target);
@@ -328,6 +447,10 @@
}
class JJumpTarget extends JumpTarget {
+ /// Tag used for identifying serialized [JJumpTarget] objects in a
+ /// debugging data stream.
+ static const String tag = 'jump-target';
+
final MemberEntity memberContext;
final int nestingLevel;
List<LabelDefinition> _labels;
@@ -337,6 +460,47 @@
JJumpTarget(this.memberContext, this.nestingLevel,
{this.isSwitch: false, this.isSwitchCase: false});
+ /// Deserializes a [JJumpTarget] object from [source].
+ factory JJumpTarget.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ MemberEntity memberContext = source.readMember();
+ int nestingLevel = source.readInt();
+ bool isSwitch = source.readBool();
+ bool isSwitchCase = source.readBool();
+ JJumpTarget target = new JJumpTarget(memberContext, nestingLevel,
+ isSwitch: isSwitch, isSwitchCase: isSwitchCase);
+ int labelCount = source.readInt();
+ for (int i = 0; i < labelCount; i++) {
+ String labelName = source.readString();
+ bool isBreakTarget = source.readBool();
+ bool isContinueTarget = source.readBool();
+ target.addLabel(labelName,
+ isBreakTarget: isBreakTarget, isContinueTarget: isContinueTarget);
+ }
+ source.end(tag);
+ return target;
+ }
+
+ /// Serializes this [JJumpTarget] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeMember(memberContext);
+ sink.writeInt(nestingLevel);
+ sink.writeBool(isSwitch);
+ sink.writeBool(isSwitchCase);
+ if (_labels != null) {
+ sink.writeInt(_labels.length);
+ for (LabelDefinition definition in _labels) {
+ sink.writeString(definition.name);
+ sink.writeBool(definition.isBreakTarget);
+ sink.writeBool(definition.isContinueTarget);
+ }
+ } else {
+ sink.writeInt(0);
+ }
+ sink.end(tag);
+ }
+
bool isBreakTarget = false;
bool isContinueTarget = false;
diff --git a/pkg/compiler/lib/src/kernel/env.dart b/pkg/compiler/lib/src/kernel/env.dart
index a343e9f..e82ef91 100644
--- a/pkg/compiler/lib/src/kernel/env.dart
+++ b/pkg/compiler/lib/src/kernel/env.dart
@@ -399,7 +399,7 @@
}
if (!includeStatic && member.isStatic) return;
if (member.isNoSuchMethodForwarder) {
- // TODO(sigmund): remove once #33665 is fixed.
+ // TODO(sigmund): remove once #33732 is fixed.
if (!includeNoSuchMethodForwarders ||
member.name.isPrivate &&
member.name.libraryName != member.enclosingLibrary.reference) {
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index 5de83bd..a437151 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -9,6 +9,7 @@
import '../elements/types.dart';
import '../js/js.dart' as js;
import '../js_backend/native_data.dart' show NativeBasicData;
+import '../serialization/serialization.dart';
import '../universe/side_effects.dart' show SideEffects;
import 'js.dart';
@@ -124,6 +125,10 @@
* `null` may be returned.
*/
class NativeBehavior {
+ /// Tag used for identifying serialized [NativeBehavior] objects in a
+ /// debugging data stream.
+ static const String tag = 'native-behavior';
+
/// [DartType]s or [SpecialType]s returned or yielded by the native
/// element.
final List typesReturned = [];
@@ -156,6 +161,88 @@
NativeBehavior.internal(this.sideEffects);
+ /// Deserializes a [NativeBehavior] object from [source].
+ factory NativeBehavior.readFromDataSource(DataSource source) {
+ source.begin(tag);
+
+ List readTypes() {
+ List types = [];
+ types.addAll(source.readDartTypes());
+ int specialCount = source.readInt();
+ for (int i = 0; i < specialCount; i++) {
+ String name = source.readString();
+ types.add(SpecialType.fromName(name));
+ }
+ return types;
+ }
+
+ List typesReturned = readTypes();
+ List typesInstantiated = readTypes();
+ String codeTemplateText = source.readStringOrNull();
+ SideEffects sideEffects = new SideEffects.readFromDataSource(source);
+ int throwBehavior = source.readInt();
+ bool isAllocation = source.readBool();
+ bool useGvn = source.readBool();
+ source.end(tag);
+
+ NativeBehavior behavior = new NativeBehavior.internal(sideEffects);
+ behavior.typesReturned.addAll(typesReturned);
+ behavior.typesInstantiated.addAll(typesInstantiated);
+ if (codeTemplateText != null) {
+ behavior.codeTemplateText = codeTemplateText;
+ behavior.codeTemplate = js.js.parseForeignJS(codeTemplateText);
+ }
+ switch (throwBehavior) {
+ case 0:
+ behavior.throwBehavior = NativeThrowBehavior.NEVER;
+ break;
+ case 1:
+ behavior.throwBehavior =
+ NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS;
+ break;
+ case 2:
+ behavior.throwBehavior = NativeThrowBehavior.MAY;
+ break;
+ case 3:
+ behavior.throwBehavior = NativeThrowBehavior.MUST;
+ break;
+ }
+ behavior.isAllocation = isAllocation;
+ behavior.useGvn = useGvn;
+ return behavior;
+ }
+
+ /// Serializes this [NativeBehavior] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+
+ void writeTypes(List types) {
+ List<DartType> dartTypes = [];
+ List<SpecialType> specialTypes = [];
+ for (var type in types) {
+ if (type is DartType) {
+ dartTypes.add(type);
+ } else {
+ specialTypes.add(type);
+ }
+ }
+ sink.writeDartTypes(dartTypes);
+ sink.writeInt(specialTypes.length);
+ for (SpecialType type in specialTypes) {
+ sink.writeString(type.name);
+ }
+ }
+
+ writeTypes(typesReturned);
+ writeTypes(typesInstantiated);
+ sink.writeStringOrNull(codeTemplateText);
+ sideEffects.writeToDataSink(sink);
+ sink.writeInt(throwBehavior._bits);
+ sink.writeBool(isAllocation);
+ sink.writeBool(useGvn);
+ sink.end(tag);
+ }
+
String toString() {
return 'NativeBehavior('
'returns: ${typesReturned}'
diff --git a/pkg/compiler/lib/src/ordered_typeset.dart b/pkg/compiler/lib/src/ordered_typeset.dart
index 4b587b6..57ed4cb 100644
--- a/pkg/compiler/lib/src/ordered_typeset.dart
+++ b/pkg/compiler/lib/src/ordered_typeset.dart
@@ -11,6 +11,7 @@
import 'diagnostics/diagnostic_listener.dart' show DiagnosticReporter;
import 'elements/entities.dart';
import 'elements/types.dart';
+import 'serialization/serialization.dart';
/**
* An ordered set of the supertypes of a class. The supertypes of a class are
@@ -30,12 +31,80 @@
* C: [C, B, A, Object]
*/
class OrderedTypeSet {
+ /// Tag used for identifying serialized [OrderedTypeSet] objects in a
+ /// debugging data stream.
+ static const String tag = 'ordered-type-set';
+
final List<Link<InterfaceType>> _levels;
final Link<InterfaceType> types;
final Link<InterfaceType> _supertypes;
OrderedTypeSet.internal(this._levels, this.types, this._supertypes);
+ /// Deserializes a [OrderedTypeSet] object from [source].
+ factory OrderedTypeSet.readFromDataSource(DataSource source) {
+ // TODO(johnniwinther): Make the deserialized type sets share their
+ // internal links like the original type sets do?
+ source.begin(tag);
+ int typesCount = source.readInt();
+ LinkBuilder<InterfaceType> typeLinkBuilder =
+ new LinkBuilder<InterfaceType>();
+ List<Link<InterfaceType>> links = [];
+ for (int i = 0; i < typesCount; i++) {
+ links.add(typeLinkBuilder.addLast(source.readDartType()));
+ }
+ Link<InterfaceType> types =
+ typeLinkBuilder.toLink(const Link<InterfaceType>());
+ links.add(const Link<InterfaceType>());
+
+ int supertypesCount = source.readInt();
+ LinkBuilder<InterfaceType> supertypeLinkBuilder =
+ new LinkBuilder<InterfaceType>();
+ for (int i = 0; i < supertypesCount; i++) {
+ supertypeLinkBuilder.addLast(source.readDartType());
+ }
+ Link<InterfaceType> supertypes =
+ supertypeLinkBuilder.toLink(const Link<InterfaceType>());
+
+ int levelCount = source.readInt();
+ List<Link<InterfaceType>> levels =
+ new List<Link<InterfaceType>>(levelCount);
+ for (int i = 0; i < levelCount; i++) {
+ levels[i] = links[source.readInt()];
+ }
+ source.end(tag);
+ return new OrderedTypeSet.internal(levels, types, supertypes);
+ }
+
+ /// Serializes this [OrderedTypeSet] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ List<InterfaceType> typeList = types.toList();
+ sink.writeInt(typeList.length);
+ for (InterfaceType type in typeList) {
+ sink.writeDartType(type);
+ }
+ List<InterfaceType> supertypeList = _supertypes.toList();
+ sink.writeInt(supertypeList.length);
+ for (InterfaceType supertype in supertypeList) {
+ sink.writeDartType(supertype);
+ }
+ List<int> levelList = [];
+ Link<InterfaceType> link = types;
+ while (link != null) {
+ int index = _levels.indexOf(link);
+ if (index != -1) {
+ levelList.add(index);
+ }
+ link = link.tail;
+ }
+ sink.writeInt(levelList.length);
+ for (int level in levelList) {
+ sink.writeInt(level);
+ }
+ sink.end(tag);
+ }
+
factory OrderedTypeSet.singleton(InterfaceType type) {
Link<InterfaceType> types =
new LinkEntry<InterfaceType>(type, const Link<InterfaceType>());
diff --git a/pkg/compiler/lib/src/serialization/abstract_sink.dart b/pkg/compiler/lib/src/serialization/abstract_sink.dart
new file mode 100644
index 0000000..b63b9a2
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/abstract_sink.dart
@@ -0,0 +1,332 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// Base implementation of [DataSink] using [DataSinkMixin] to implement
+/// convenience methods.
+abstract class AbstractDataSink extends DataSinkMixin implements DataSink {
+ /// If `true`, serialization of every data kind is preceded by a [DataKind]
+ /// value.
+ ///
+ /// This is used for debugging data inconsistencies between serialization
+ /// and deserialization.
+ final bool useDataKinds;
+
+ /// Visitor used for serializing [DartType]s.
+ DartTypeWriter _dartTypeWriter;
+
+ /// Stack of tags used when [useDataKinds] is `true` to help debugging section
+ /// inconsistencies between serialization and deserialization.
+ List<String> _tags;
+
+ /// Map of [_MemberData] object for serialized kernel member nodes.
+ Map<ir.Member, _MemberData> _memberData = {};
+
+ AbstractDataSink({this.useDataKinds: false}) {
+ _dartTypeWriter = new DartTypeWriter(this);
+ }
+
+ void begin(String tag) {
+ if (useDataKinds) {
+ _tags ??= <String>[];
+ _tags.add(tag);
+ _begin(tag);
+ }
+ }
+
+ void end(Object tag) {
+ if (useDataKinds) {
+ _end(tag);
+
+ String existingTag = _tags.removeLast();
+ assert(existingTag == tag,
+ "Unexpected tag end. Expected $existingTag, found $tag.");
+ }
+ }
+
+ @override
+ void writeSourceSpan(SourceSpan value) {
+ _writeDataKind(DataKind.sourceSpan);
+ _writeUri(value.uri);
+ _writeInt(value.begin);
+ _writeInt(value.end);
+ }
+
+ @override
+ void writeDartType(DartType value, {bool allowNull: false}) {
+ _writeDataKind(DataKind.dartType);
+ _writeDartType(value, [], allowNull: allowNull);
+ }
+
+ void _writeDartType(
+ DartType value, List<FunctionTypeVariable> functionTypeVariables,
+ {bool allowNull: false}) {
+ if (value == null) {
+ if (!allowNull) {
+ throw new UnsupportedError("Missing DartType is not allowed.");
+ }
+ writeEnum(DartTypeKind.none);
+ } else {
+ _dartTypeWriter.visit(value, functionTypeVariables);
+ }
+ }
+
+ @override
+ void writeMemberNode(ir.Member value) {
+ _writeDataKind(DataKind.memberNode);
+ _writeMemberNode(value);
+ }
+
+ void _writeMemberNode(ir.Member value) {
+ ir.Class cls = value.enclosingClass;
+ if (cls != null) {
+ _writeEnum(MemberContextKind.cls);
+ _writeClassNode(cls);
+ _writeString(_computeMemberName(value));
+ } else {
+ _writeEnum(MemberContextKind.library);
+ _writeLibraryNode(value.enclosingLibrary);
+ _writeString(_computeMemberName(value));
+ }
+ }
+
+ @override
+ void writeClassNode(ir.Class value) {
+ _writeDataKind(DataKind.classNode);
+ _writeClassNode(value);
+ }
+
+ void _writeClassNode(ir.Class value) {
+ _writeLibraryNode(value.enclosingLibrary);
+ _writeString(value.name);
+ }
+
+ @override
+ void writeLibraryNode(ir.Library value) {
+ _writeDataKind(DataKind.libraryNode);
+ _writeLibraryNode(value);
+ }
+
+ void _writeLibraryNode(ir.Library value) {
+ _writeUri(value.importUri);
+ }
+
+ @override
+ void writeEnum(dynamic value) {
+ _writeDataKind(DataKind.enumValue);
+ _writeEnum(value);
+ }
+
+ @override
+ void writeBool(bool value) {
+ assert(value != null);
+ _writeDataKind(DataKind.bool);
+ _writeInt(value ? 1 : 0);
+ }
+
+ @override
+ void writeUri(Uri value) {
+ assert(value != null);
+ _writeDataKind(DataKind.uri);
+ _writeUri(value);
+ }
+
+ @override
+ void writeString(String value) {
+ assert(value != null);
+ _writeDataKind(DataKind.string);
+ _writeString(value);
+ }
+
+ @override
+ void writeInt(int value) {
+ assert(value != null);
+ assert(value >= 0 && value >> 30 == 0);
+ _writeDataKind(DataKind.int);
+ _writeInt(value);
+ }
+
+ void writeTreeNode(ir.TreeNode value) {
+ _writeDataKind(DataKind.treeNode);
+ _writeTreeNode(value);
+ }
+
+ void _writeTreeNode(ir.TreeNode value) {
+ if (value is ir.Class) {
+ _writeEnum(_TreeNodeKind.cls);
+ _writeClassNode(value);
+ } else if (value is ir.Member) {
+ _writeEnum(_TreeNodeKind.member);
+ _writeMemberNode(value);
+ } else if (value is ir.VariableDeclaration &&
+ value.parent is ir.FunctionDeclaration) {
+ _writeEnum(_TreeNodeKind.functionDeclarationVariable);
+ _writeTreeNode(value.parent);
+ } else if (value is ir.FunctionNode) {
+ _writeEnum(_TreeNodeKind.functionNode);
+ _writeFunctionNode(value);
+ } else if (value is ir.TypeParameter) {
+ _writeEnum(_TreeNodeKind.typeParameter);
+ _writeTypeParameter(value);
+ } else {
+ _writeEnum(_TreeNodeKind.node);
+ ir.TreeNode member = value;
+ while (member is! ir.Member) {
+ if (member == null) {
+ throw new UnsupportedError("No enclosing member of TreeNode "
+ "$value (${value.runtimeType})");
+ }
+ member = member.parent;
+ }
+ _writeMemberNode(member);
+ _MemberData memberData = _memberData[member] ??= new _MemberData(member);
+ int index = memberData.getIndexByTreeNode(value);
+ assert(index != null, "No index found for ${value.runtimeType}.");
+ _writeInt(index);
+ }
+ }
+
+ void _writeFunctionNode(ir.FunctionNode value) {
+ ir.TreeNode parent = value.parent;
+ if (parent is ir.Procedure) {
+ _writeEnum(_FunctionNodeKind.procedure);
+ _writeMemberNode(parent);
+ } else if (parent is ir.Constructor) {
+ _writeEnum(_FunctionNodeKind.constructor);
+ _writeMemberNode(parent);
+ } else if (parent is ir.FunctionExpression) {
+ _writeEnum(_FunctionNodeKind.functionExpression);
+ _writeTreeNode(parent);
+ } else if (parent is ir.FunctionDeclaration) {
+ _writeEnum(_FunctionNodeKind.functionDeclaration);
+ _writeTreeNode(parent);
+ } else {
+ throw new UnsupportedError(
+ "Unsupported FunctionNode parent ${parent.runtimeType}");
+ }
+ }
+
+ @override
+ void writeTypeParameterNode(ir.TypeParameter value) {
+ _writeDataKind(DataKind.typeParameterNode);
+ _writeTypeParameter(value);
+ }
+
+ void _writeTypeParameter(ir.TypeParameter value) {
+ ir.TreeNode parent = value.parent;
+ if (parent is ir.Class) {
+ _writeEnum(_TypeParameterKind.cls);
+ _writeClassNode(parent);
+ _writeInt(parent.typeParameters.indexOf(value));
+ } else if (parent is ir.FunctionNode) {
+ _writeEnum(_TypeParameterKind.functionNode);
+ _writeFunctionNode(parent);
+ _writeInt(parent.typeParameters.indexOf(value));
+ } else {
+ throw new UnsupportedError(
+ "Unsupported TypeParameter parent ${parent.runtimeType}");
+ }
+ }
+
+ void _writeDataKind(DataKind kind) {
+ if (useDataKinds) _writeEnum(kind);
+ }
+
+ void writeLibrary(IndexedLibrary value) {
+ writeInt(value.libraryIndex);
+ }
+
+ void writeClass(IndexedClass value) {
+ writeInt(value.classIndex);
+ }
+
+ void writeTypedef(IndexedTypedef value) {
+ writeInt(value.typedefIndex);
+ }
+
+ void writeMember(IndexedMember value) {
+ writeInt(value.memberIndex);
+ }
+
+ void writeLocal(Local local) {
+ if (local is JLocal) {
+ writeEnum(LocalKind.jLocal);
+ writeMember(local.memberContext);
+ writeInt(local.localIndex);
+ } else if (local is ThisLocal) {
+ writeEnum(LocalKind.thisLocal);
+ writeClass(local.enclosingClass);
+ } else if (local is BoxLocal) {
+ writeEnum(LocalKind.boxLocal);
+ writeClass(local.container);
+ } else if (local is AnonymousClosureLocal) {
+ writeEnum(LocalKind.anonymousClosureLocal);
+ writeClass(local.closureClass);
+ } else if (local is TypeVariableLocal) {
+ writeEnum(LocalKind.typeVariableLocal);
+ writeDartType(local.typeVariable);
+ } else {
+ throw new UnsupportedError("Unsupported local ${local.runtimeType}");
+ }
+ }
+
+ @override
+ void writeConstant(ConstantValue value) {
+ _writeDataKind(DataKind.constant);
+ _writeConstant(value);
+ }
+
+ void _writeConstant(ConstantValue value) {
+ _writeEnum(value.kind);
+ switch (value.kind) {
+ case ConstantValueKind.BOOL:
+ BoolConstantValue constant = value;
+ writeBool(constant.boolValue);
+ break;
+ case ConstantValueKind.INT:
+ IntConstantValue constant = value;
+ writeString(constant.intValue.toString());
+ break;
+ case ConstantValueKind.DOUBLE:
+ DoubleConstantValue constant = value;
+ ByteData data = new ByteData(8);
+ data.setFloat64(0, constant.doubleValue);
+ writeInt(data.getUint16(0));
+ writeInt(data.getUint16(2));
+ writeInt(data.getUint16(4));
+ writeInt(data.getUint16(6));
+ break;
+ case ConstantValueKind.STRING:
+ StringConstantValue constant = value;
+ writeString(constant.stringValue);
+ break;
+ case ConstantValueKind.NULL:
+ break;
+ default:
+ // TODO(johnniwinther): Support remaining constant values.
+ throw new UnsupportedError(
+ "Unexpected constant value kind ${value.kind}.");
+ }
+ }
+
+ /// Actual serialization of a section begin tag, implemented by subclasses.
+ void _begin(String tag);
+
+ /// Actual serialization of a section end tag, implemented by subclasses.
+ void _end(String tag);
+
+ /// Actual serialization of a URI value, implemented by subclasses.
+ void _writeUri(Uri value);
+
+ /// Actual serialization of a String value, implemented by subclasses.
+ void _writeString(String value);
+
+ /// Actual serialization of a non-negative integer value, implemented by
+ /// subclasses.
+ void _writeInt(int value);
+
+ /// Actual serialization of an enum value, implemented by subclasses.
+ void _writeEnum(dynamic value);
+}
diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart
new file mode 100644
index 0000000..f258917
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/abstract_source.dart
@@ -0,0 +1,418 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// Base implementation of [DataSource] using [DataSourceMixin] to implement
+/// convenience methods.
+abstract class AbstractDataSource extends DataSourceMixin
+ implements DataSource {
+ final bool useDataKinds;
+ ComponentLookup _componentLookup;
+ EntityLookup _entityLookup;
+ LocalLookup _localLookup;
+
+ AbstractDataSource({this.useDataKinds: false});
+
+ void begin(String tag) {
+ if (useDataKinds) _begin(tag);
+ }
+
+ void end(String tag) {
+ if (useDataKinds) _end(tag);
+ }
+
+ void registerComponentLookup(ComponentLookup componentLookup) {
+ assert(_componentLookup == null);
+ _componentLookup = componentLookup;
+ }
+
+ ComponentLookup get componentLookup {
+ assert(_componentLookup != null);
+ return _componentLookup;
+ }
+
+ void registerEntityLookup(EntityLookup entityLookup) {
+ assert(_entityLookup == null);
+ _entityLookup = entityLookup;
+ }
+
+ EntityLookup get entityLookup {
+ assert(_entityLookup != null);
+ return _entityLookup;
+ }
+
+ void registerLocalLookup(LocalLookup localLookup) {
+ assert(_localLookup == null);
+ _localLookup = localLookup;
+ }
+
+ LocalLookup get localLookup {
+ assert(_localLookup != null);
+ return _localLookup;
+ }
+
+ IndexedLibrary readLibrary() {
+ return getIndexedLibrary(readInt());
+ }
+
+ IndexedClass readClass() {
+ return getIndexedClass(readInt());
+ }
+
+ IndexedTypedef readTypedef() {
+ return getIndexedTypedef(readInt());
+ }
+
+ IndexedMember readMember() {
+ return getIndexedMember(readInt());
+ }
+
+ IndexedLibrary getIndexedLibrary(int libraryIndex) =>
+ entityLookup.getLibraryByIndex(libraryIndex);
+
+ IndexedClass getIndexedClass(int classIndex) =>
+ entityLookup.getClassByIndex(classIndex);
+
+ IndexedTypedef getIndexedTypedef(int typedefIndex) =>
+ entityLookup.getTypedefByIndex(typedefIndex);
+
+ IndexedMember getIndexedMember(int memberIndex) =>
+ entityLookup.getMemberByIndex(memberIndex);
+
+ IndexedTypeVariable getIndexedTypeVariable(int typeVariableIndex) =>
+ entityLookup.getTypeVariableByIndex(typeVariableIndex);
+
+ List<DartType> _readDartTypes(
+ List<FunctionTypeVariable> functionTypeVariables) {
+ int count = readInt();
+ List<DartType> types = new List<DartType>(count);
+ for (int index = 0; index < count; index++) {
+ types[index] = _readDartType(functionTypeVariables);
+ }
+ return types;
+ }
+
+ @override
+ SourceSpan readSourceSpan() {
+ _checkDataKind(DataKind.sourceSpan);
+ Uri uri = _readUri();
+ int begin = _readInt();
+ int end = _readInt();
+ return new SourceSpan(uri, begin, end);
+ }
+
+ @override
+ DartType readDartType({bool allowNull: false}) {
+ _checkDataKind(DataKind.dartType);
+ DartType type = _readDartType([]);
+ assert(type != null || allowNull);
+ return type;
+ }
+
+ DartType _readDartType(List<FunctionTypeVariable> functionTypeVariables) {
+ DartTypeKind kind = readEnum(DartTypeKind.values);
+ switch (kind) {
+ case DartTypeKind.none:
+ return null;
+ case DartTypeKind.voidType:
+ return const VoidType();
+ case DartTypeKind.typeVariable:
+ return new TypeVariableType(getIndexedTypeVariable(readInt()));
+ case DartTypeKind.functionTypeVariable:
+ int index = readInt();
+ assert(0 <= index && index < functionTypeVariables.length);
+ return functionTypeVariables[index];
+ case DartTypeKind.functionType:
+ int typeVariableCount = readInt();
+ List<FunctionTypeVariable> typeVariables =
+ new List<FunctionTypeVariable>.generate(typeVariableCount,
+ (int index) => new FunctionTypeVariable(index));
+ functionTypeVariables =
+ new List<FunctionTypeVariable>.from(functionTypeVariables)
+ ..addAll(typeVariables);
+ for (int index = 0; index < typeVariableCount; index++) {
+ typeVariables[index].bound = _readDartType(functionTypeVariables);
+ }
+ DartType returnType = _readDartType(functionTypeVariables);
+ List<DartType> parameterTypes = _readDartTypes(functionTypeVariables);
+ List<DartType> optionalParameterTypes =
+ _readDartTypes(functionTypeVariables);
+ List<DartType> namedParameterTypes =
+ _readDartTypes(functionTypeVariables);
+ List<String> namedParameters =
+ new List<String>(namedParameterTypes.length);
+ for (int i = 0; i < namedParameters.length; i++) {
+ namedParameters[i] = readString();
+ }
+ return new FunctionType(
+ returnType,
+ parameterTypes,
+ optionalParameterTypes,
+ namedParameters,
+ namedParameterTypes,
+ typeVariables);
+
+ case DartTypeKind.interfaceType:
+ IndexedClass cls = getIndexedClass(readInt());
+ List<DartType> typeArguments = _readDartTypes(functionTypeVariables);
+ return new InterfaceType(cls, typeArguments);
+ case DartTypeKind.typedef:
+ IndexedTypedef typedef = getIndexedTypedef(readInt());
+ List<DartType> typeArguments = _readDartTypes(functionTypeVariables);
+ DartType unaliased = _readDartType(functionTypeVariables);
+ return new TypedefType(typedef, typeArguments, unaliased);
+ case DartTypeKind.dynamicType:
+ return const DynamicType();
+ case DartTypeKind.futureOr:
+ DartType typeArgument = _readDartType(functionTypeVariables);
+ return new FutureOrType(typeArgument);
+ }
+ throw new UnsupportedError("Unexpected DartTypeKind $kind");
+ }
+
+ _MemberData _readMemberData() {
+ MemberContextKind kind = _readEnum(MemberContextKind.values);
+ switch (kind) {
+ case MemberContextKind.cls:
+ _ClassData cls = _readClassData();
+ String name = _readString();
+ return cls.lookupMember(name);
+ case MemberContextKind.library:
+ _LibraryData library = _readLibraryData();
+ String name = _readString();
+ return library.lookupMember(name);
+ }
+ throw new UnsupportedError("Unsupported _MemberKind $kind");
+ }
+
+ @override
+ ir.Member readMemberNode() {
+ _checkDataKind(DataKind.memberNode);
+ return _readMemberData().node;
+ }
+
+ _ClassData _readClassData() {
+ _LibraryData library = _readLibraryData();
+ String name = _readString();
+ return library.lookupClass(name);
+ }
+
+ @override
+ ir.Class readClassNode() {
+ _checkDataKind(DataKind.classNode);
+ return _readClassData().node;
+ }
+
+ _LibraryData _readLibraryData() {
+ Uri canonicalUri = _readUri();
+ return componentLookup.getLibraryDataByUri(canonicalUri);
+ }
+
+ @override
+ ir.Library readLibraryNode() {
+ _checkDataKind(DataKind.libraryNode);
+ return _readLibraryData().node;
+ }
+
+ @override
+ E readEnum<E>(List<E> values) {
+ _checkDataKind(DataKind.enumValue);
+ return _readEnum(values);
+ }
+
+ @override
+ Uri readUri() {
+ _checkDataKind(DataKind.uri);
+ return _readUri();
+ }
+
+ @override
+ bool readBool() {
+ _checkDataKind(DataKind.bool);
+ int value = _readInt();
+ assert(value == 0 || value == 1);
+ return value == 1;
+ }
+
+ @override
+ String readString() {
+ _checkDataKind(DataKind.string);
+ return _readString();
+ }
+
+ @override
+ int readInt() {
+ _checkDataKind(DataKind.int);
+ return _readInt();
+ }
+
+ @override
+ ir.TreeNode readTreeNode() {
+ _checkDataKind(DataKind.treeNode);
+ return _readTreeNode();
+ }
+
+ @override
+ ConstantValue readConstant() {
+ _checkDataKind(DataKind.constant);
+ return _readConstant();
+ }
+
+ ConstantValue _readConstant() {
+ ConstantValueKind kind = _readEnum(ConstantValueKind.values);
+ ConstantValue constant;
+ switch (kind) {
+ case ConstantValueKind.BOOL:
+ bool value = readBool();
+ constant = new BoolConstantValue(value);
+ break;
+ case ConstantValueKind.INT:
+ BigInt value = BigInt.parse(readString());
+ constant = new IntConstantValue(value);
+ break;
+ case ConstantValueKind.DOUBLE:
+ ByteData data = new ByteData(8);
+ data.setUint16(0, readInt());
+ data.setUint16(2, readInt());
+ data.setUint16(4, readInt());
+ data.setUint16(6, readInt());
+ double value = data.getFloat64(0);
+ constant = new DoubleConstantValue(value);
+ break;
+ case ConstantValueKind.STRING:
+ String value = readString();
+ constant = new StringConstantValue(value);
+ break;
+ case ConstantValueKind.NULL:
+ constant = const NullConstantValue();
+ break;
+ default:
+ // TODO(johnniwinther): Support remaining constant values.
+ throw new UnsupportedError("Unexpected constant value kind ${kind}.");
+ }
+ return constant;
+ }
+
+ ir.TreeNode _readTreeNode() {
+ _TreeNodeKind kind = _readEnum(_TreeNodeKind.values);
+ switch (kind) {
+ case _TreeNodeKind.cls:
+ return _readClassData().node;
+ case _TreeNodeKind.member:
+ return _readMemberData().node;
+ case _TreeNodeKind.functionDeclarationVariable:
+ ir.FunctionDeclaration functionDeclaration = _readTreeNode();
+ return functionDeclaration.variable;
+ case _TreeNodeKind.functionNode:
+ return _readFunctionNode();
+ case _TreeNodeKind.typeParameter:
+ return _readTypeParameter();
+ case _TreeNodeKind.node:
+ _MemberData data = _readMemberData();
+ int index = _readInt();
+ ir.TreeNode treeNode = data.getTreeNodeByIndex(index);
+ assert(treeNode != null,
+ "No TreeNode found for index $index in ${data.node}.$_errorContext");
+ return treeNode;
+ }
+ throw new UnsupportedError("Unexpected _TreeNodeKind $kind");
+ }
+
+ ir.FunctionNode _readFunctionNode() {
+ _FunctionNodeKind kind = _readEnum(_FunctionNodeKind.values);
+ switch (kind) {
+ case _FunctionNodeKind.procedure:
+ ir.Procedure procedure = _readMemberData().node;
+ return procedure.function;
+ case _FunctionNodeKind.constructor:
+ ir.Constructor constructor = _readMemberData().node;
+ return constructor.function;
+ case _FunctionNodeKind.functionExpression:
+ ir.FunctionExpression functionExpression = _readTreeNode();
+ return functionExpression.function;
+ case _FunctionNodeKind.functionDeclaration:
+ ir.FunctionDeclaration functionDeclaration = _readTreeNode();
+ return functionDeclaration.function;
+ }
+ throw new UnsupportedError("Unexpected _FunctionNodeKind $kind");
+ }
+
+ @override
+ ir.TypeParameter readTypeParameterNode() {
+ _checkDataKind(DataKind.typeParameterNode);
+ return _readTypeParameter();
+ }
+
+ ir.TypeParameter _readTypeParameter() {
+ _TypeParameterKind kind = _readEnum(_TypeParameterKind.values);
+ switch (kind) {
+ case _TypeParameterKind.cls:
+ ir.Class cls = _readClassData().node;
+ return cls.typeParameters[_readInt()];
+ case _TypeParameterKind.functionNode:
+ ir.FunctionNode functionNode = _readFunctionNode();
+ return functionNode.typeParameters[_readInt()];
+ }
+ throw new UnsupportedError("Unexpected _TypeParameterKind kind $kind");
+ }
+
+ void _checkDataKind(DataKind expectedKind) {
+ if (!useDataKinds) return;
+ DataKind actualKind = _readEnum(DataKind.values);
+ assert(
+ actualKind == expectedKind,
+ "Invalid data kind. "
+ "Expected $expectedKind, found $actualKind.$_errorContext");
+ }
+
+ @override
+ Local readLocal() {
+ LocalKind kind = readEnum(LocalKind.values);
+ switch (kind) {
+ case LocalKind.jLocal:
+ MemberEntity memberContext = readMember();
+ int localIndex = readInt();
+ return localLookup.getLocalByIndex(memberContext, localIndex);
+ case LocalKind.thisLocal:
+ ClassEntity cls = readClass();
+ return new ThisLocal(cls);
+ case LocalKind.boxLocal:
+ ClassEntity cls = readClass();
+ return new BoxLocal(cls);
+ case LocalKind.anonymousClosureLocal:
+ ClassEntity cls = readClass();
+ return new AnonymousClosureLocal(cls);
+ case LocalKind.typeVariableLocal:
+ TypeVariableType typeVariable = readDartType();
+ return new TypeVariableLocal(typeVariable);
+ }
+ throw new UnsupportedError("Unexpected local kind $kind");
+ }
+
+ /// Actual deserialization of a section begin tag, implemented by subclasses.
+ void _begin(String tag);
+
+ /// Actual deserialization of a section end tag, implemented by subclasses.
+ void _end(String tag);
+
+ /// Actual deserialization of a string value, implemented by subclasses.
+ String _readString();
+
+ /// Actual deserialization of a non-negative integer value, implemented by
+ /// subclasses.
+ int _readInt();
+
+ /// Actual deserialization of a URI value, implemented by subclasses.
+ Uri _readUri();
+
+ /// Actual deserialization of an enum value in [values], implemented by
+ /// subclasses.
+ E _readEnum<E>(List<E> values);
+
+ /// Returns a string representation of the current state of the data source
+ /// useful for debugging in consistencies between serialization and
+ /// deserialization.
+ String get _errorContext;
+}
diff --git a/pkg/compiler/lib/src/serialization/binary_sink.dart b/pkg/compiler/lib/src/serialization/binary_sink.dart
new file mode 100644
index 0000000..e7c2114
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/binary_sink.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// [DataSink] that writes data as a sequence of bytes.
+///
+/// This data sink works together with [BinarySource].
+class BinarySink extends AbstractDataSink {
+ final Sink<List<int>> sink;
+ BufferedSink _bufferedSink;
+
+ BinarySink(this.sink, {bool useDataKinds: false})
+ : _bufferedSink = new BufferedSink(sink),
+ super(useDataKinds: useDataKinds);
+
+ void _begin(String tag) {
+ // TODO(johnniwinther): Support tags in binary serialization?
+ }
+ void _end(String tag) {
+ // TODO(johnniwinther): Support tags in binary serialization?
+ }
+
+ @override
+ void _writeUri(Uri value) {
+ _writeString(value.toString());
+ }
+
+ @override
+ void _writeString(String value) {
+ List<int> bytes = utf8.encode(value);
+ _writeInt(bytes.length);
+ _bufferedSink.addBytes(bytes);
+ }
+
+ @override
+ void _writeInt(int value) {
+ assert(value >= 0 && value >> 30 == 0);
+ if (value < 0x80) {
+ _bufferedSink.addByte(value);
+ } else if (value < 0x4000) {
+ _bufferedSink.addByte2((value >> 8) | 0x80, value & 0xFF);
+ } else {
+ _bufferedSink.addByte4((value >> 24) | 0xC0, (value >> 16) & 0xFF,
+ (value >> 8) & 0xFF, value & 0xFF);
+ }
+ }
+
+ @override
+ void _writeEnum(dynamic value) {
+ _writeInt(value.index);
+ }
+
+ void close() {
+ _bufferedSink.flushAndDestroy();
+ _bufferedSink = null;
+ sink.close();
+ }
+}
diff --git a/pkg/compiler/lib/src/serialization/binary_source.dart b/pkg/compiler/lib/src/serialization/binary_source.dart
new file mode 100644
index 0000000..0836209
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/binary_source.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// [DataSource] that reads data from a sequence of bytes.
+///
+/// This data source works together with [BinarySink].
+class BinarySourceImpl extends AbstractDataSource {
+ int _byteOffset = 0;
+ final List<int> _bytes;
+
+ BinarySourceImpl(this._bytes, {bool useDataKinds: false})
+ : super(useDataKinds: useDataKinds);
+
+ void _begin(String tag) {}
+ void _end(String tag) {}
+
+ int _readByte() => _bytes[_byteOffset++];
+
+ @override
+ String _readString() {
+ int length = _readInt();
+ List<int> bytes = new Uint8List(length);
+ bytes.setRange(0, bytes.length, _bytes, _byteOffset);
+ _byteOffset += bytes.length;
+ return utf8.decode(bytes);
+ }
+
+ @override
+ int _readInt() {
+ var byte = _readByte();
+ if (byte & 0x80 == 0) {
+ // 0xxxxxxx
+ return byte;
+ } else if (byte & 0x40 == 0) {
+ // 10xxxxxx
+ return ((byte & 0x3F) << 8) | _readByte();
+ } else {
+ // 11xxxxxx
+ return ((byte & 0x3F) << 24) |
+ (_readByte() << 16) |
+ (_readByte() << 8) |
+ _readByte();
+ }
+ }
+
+ @override
+ Uri _readUri() {
+ String text = _readString();
+ return Uri.parse(text);
+ }
+
+ @override
+ E _readEnum<E>(List<E> values) {
+ int index = _readInt();
+ assert(
+ 0 <= index && index < values.length,
+ "Invalid data kind index. "
+ "Expected one of $values, found index $index.");
+ return values[index];
+ }
+
+ @override
+ String get _errorContext => ' Offset $_byteOffset in ${_bytes.length}.';
+}
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
new file mode 100644
index 0000000..14446a1
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -0,0 +1,176 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// Enum values used for identifying different kinds of serialized data.
+///
+/// This is used to for debugging data inconsistencies between serialization
+/// and deserialization.
+enum DataKind {
+ bool,
+ int,
+ string,
+ enumValue,
+ uri,
+ libraryNode,
+ classNode,
+ memberNode,
+ treeNode,
+ typeParameterNode,
+ dartType,
+ sourceSpan,
+ constant,
+}
+
+/// Enum used for identifying the enclosing entity of a member in serialization.
+enum MemberContextKind { library, cls }
+
+/// Enum used for identifying [Local] subclasses in serialization.
+enum LocalKind {
+ jLocal,
+ thisLocal,
+ boxLocal,
+ anonymousClosureLocal,
+ typeVariableLocal,
+}
+
+/// Enum used for identifying [ir.TreeNode] subclasses in serialization.
+enum _TreeNodeKind {
+ cls,
+ member,
+ node,
+ functionNode,
+ typeParameter,
+ functionDeclarationVariable
+}
+
+/// Enum used for identifying [ir.FunctionNode] context in serialization.
+enum _FunctionNodeKind {
+ procedure,
+ constructor,
+ functionExpression,
+ functionDeclaration,
+}
+
+/// Enum used for identifying [ir.TypeParameter] context in serialization.
+enum _TypeParameterKind {
+ cls,
+ functionNode,
+}
+
+/// Class used for encoding tags in [ObjectSink] and [ObjectSource].
+class Tag {
+ final String value;
+
+ Tag(this.value);
+
+ int get hashCode => value.hashCode * 13;
+
+ bool operator ==(other) {
+ if (identical(this, other)) return true;
+ if (other is! Tag) return false;
+ return value == other.value;
+ }
+
+ String toString() => 'Tag($value)';
+}
+
+/// Enum used for identifying [DartType] subclasses in serialization.
+enum DartTypeKind {
+ none,
+ voidType,
+ typeVariable,
+ functionTypeVariable,
+ functionType,
+ interfaceType,
+ typedef,
+ dynamicType,
+ futureOr
+}
+
+/// Visitor that serializes [DartType] object together with [AbstractDataSink].
+class DartTypeWriter
+ implements DartTypeVisitor<void, List<FunctionTypeVariable>> {
+ final AbstractDataSink _sink;
+
+ DartTypeWriter(this._sink);
+
+ void visit(covariant DartType type,
+ List<FunctionTypeVariable> functionTypeVariables) =>
+ type.accept(this, functionTypeVariables);
+
+ void visitTypes(
+ List<DartType> types, List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeInt(types.length);
+ for (DartType type in types) {
+ _sink._writeDartType(type, functionTypeVariables);
+ }
+ }
+
+ void visitVoidType(covariant VoidType type,
+ List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeEnum(DartTypeKind.voidType);
+ }
+
+ void visitTypeVariableType(covariant TypeVariableType type,
+ List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeEnum(DartTypeKind.typeVariable);
+ IndexedTypeVariable typeVariable = type.element;
+ _sink.writeInt(typeVariable.typeVariableIndex);
+ }
+
+ void visitFunctionTypeVariable(covariant FunctionTypeVariable type,
+ List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeEnum(DartTypeKind.functionTypeVariable);
+ int index = functionTypeVariables.indexOf(type);
+ assert(index != -1);
+ _sink.writeInt(index);
+ }
+
+ void visitFunctionType(covariant FunctionType type,
+ List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeEnum(DartTypeKind.functionType);
+ functionTypeVariables =
+ new List<FunctionTypeVariable>.from(functionTypeVariables)
+ ..addAll(type.typeVariables);
+ _sink.writeInt(type.typeVariables.length);
+ for (FunctionTypeVariable variable in type.typeVariables) {
+ _sink._writeDartType(variable.bound, functionTypeVariables);
+ }
+ _sink._writeDartType(type.returnType, functionTypeVariables);
+ visitTypes(type.parameterTypes, functionTypeVariables);
+ visitTypes(type.optionalParameterTypes, functionTypeVariables);
+ visitTypes(type.namedParameterTypes, functionTypeVariables);
+ for (String namedParameter in type.namedParameters) {
+ _sink.writeString(namedParameter);
+ }
+ }
+
+ void visitInterfaceType(covariant InterfaceType type,
+ List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeEnum(DartTypeKind.interfaceType);
+ _sink.writeClass(type.element);
+ visitTypes(type.typeArguments, functionTypeVariables);
+ }
+
+ void visitTypedefType(covariant TypedefType type,
+ List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeEnum(DartTypeKind.typedef);
+ _sink.writeTypedef(type.element);
+ visitTypes(type.typeArguments, functionTypeVariables);
+ _sink._writeDartType(type.unaliased, functionTypeVariables);
+ }
+
+ void visitDynamicType(covariant DynamicType type,
+ List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeEnum(DartTypeKind.dynamicType);
+ }
+
+ void visitFutureOrType(covariant FutureOrType type,
+ List<FunctionTypeVariable> functionTypeVariables) {
+ _sink.writeEnum(DartTypeKind.futureOr);
+ _sink._writeDartType(type.typeArgument, functionTypeVariables);
+ }
+}
diff --git a/pkg/compiler/lib/src/serialization/member_data.dart b/pkg/compiler/lib/src/serialization/member_data.dart
new file mode 100644
index 0000000..08fa9a3
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/member_data.dart
@@ -0,0 +1,159 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// Helper for looking up object library data from an [ir.Component] node.
+class ComponentLookup {
+ final ir.Component _component;
+
+ /// Cache of [_LibraryData] for libraries in [_component].
+ Map<Uri, _LibraryData> _libraryMap;
+
+ ComponentLookup(this._component);
+
+ /// Returns the [_LibraryData] object for the library with the [canonicalUri].
+ _LibraryData getLibraryDataByUri(Uri canonicalUri) {
+ if (_libraryMap == null) {
+ _libraryMap = {};
+ for (ir.Library library in _component.libraries) {
+ _libraryMap[library.importUri] = new _LibraryData(library);
+ }
+ }
+ return _libraryMap[canonicalUri];
+ }
+}
+
+/// Returns a name uniquely identifying a member within its enclosing library
+/// or class.
+String _computeMemberName(ir.Member member) {
+ if (member.name.isPrivate &&
+ member.name.libraryName != member.enclosingLibrary.reference) {
+ // TODO(33732): Handle noSuchMethod forwarders for private members from
+ // other libraries.
+ return null;
+ }
+ String name = member.name.name;
+ if (member is ir.Procedure && member.kind == ir.ProcedureKind.Setter) {
+ name += "=";
+ }
+ return name;
+}
+
+/// Helper for looking up classes and members from an [ir.Library] node.
+class _LibraryData {
+ /// The [ir.Library] that defines the library.
+ final ir.Library node;
+
+ /// Cache of [_ClassData] for classes in this library.
+ Map<String, _ClassData> _classes;
+
+ /// Cache of [_MemberData] for members in this library.
+ Map<String, _MemberData> _members;
+
+ _LibraryData(this.node);
+
+ /// Returns the [_ClassData] for the class [name] in this library.
+ _ClassData lookupClass(String name) {
+ if (_classes == null) {
+ _classes = {};
+ for (ir.Class cls in node.classes) {
+ assert(!_classes.containsKey(cls.name),
+ "Duplicate class '${cls.name}' in $_classes trying to add $cls.");
+ _classes[cls.name] = new _ClassData(cls);
+ }
+ }
+ return _classes[name];
+ }
+
+ /// Returns the [_MemberData] for the member uniquely identified by [name] in
+ /// this library.
+ _MemberData lookupMember(String name) {
+ if (_members == null) {
+ _members = {};
+ for (ir.Member member in node.members) {
+ String name = _computeMemberName(member);
+ if (name == null) continue;
+ assert(!_members.containsKey(name),
+ "Duplicate member '$name' in $_members trying to add $member.");
+ _members[name] = new _MemberData(member);
+ }
+ }
+ return _members[name];
+ }
+
+ String toString() => '_LibraryData($node(${identityHashCode(node)}))';
+}
+
+/// Helper for looking up members from an [ir.Class] node.
+class _ClassData {
+ /// The [ir.Class] that defines the class.
+ final ir.Class node;
+
+ /// Cache of [_MemberData] for members in this class.
+ Map<String, _MemberData> _members;
+
+ _ClassData(this.node);
+
+ /// Returns the [_MemberData] for the member uniquely identified by [name] in
+ /// this class.
+ _MemberData lookupMember(String name) {
+ if (_members == null) {
+ _members = {};
+ for (ir.Member member in node.members) {
+ String name = _computeMemberName(member);
+ if (name == null) continue;
+ assert(!_members.containsKey(name),
+ "Duplicate member '$name' in $_members trying to add $member.");
+ _members[name] = new _MemberData(member);
+ }
+ }
+ return _members[name];
+ }
+
+ String toString() => '_ClassData($node(${identityHashCode(node)}))';
+}
+
+/// Helper for looking up child [ir.TreeNode]s of a [ir.Member] node.
+class _MemberData {
+ /// The [ir.Member] that defines the member.
+ final ir.Member node;
+
+ /// Cached index to [ir.TreeNode] map used for deserialization of
+ /// [ir.TreeNode]s.
+ Map<int, ir.TreeNode> _indexToNodeMap;
+
+ /// Cached [ir.TreeNode] to index map used for serialization of
+ /// [ir.TreeNode]s.
+ Map<ir.TreeNode, int> _nodeToIndexMap;
+
+ _MemberData(this.node);
+
+ void _ensureMaps() {
+ if (_indexToNodeMap == null) {
+ _indexToNodeMap = {};
+ _nodeToIndexMap = {};
+ node.accept(
+ new _TreeNodeIndexerVisitor(_indexToNodeMap, _nodeToIndexMap));
+ }
+ }
+
+ /// Returns the [ir.TreeNode] corresponding to [index] in this member.
+ ir.TreeNode getTreeNodeByIndex(int index) {
+ _ensureMaps();
+ ir.TreeNode treeNode = _indexToNodeMap[index];
+ assert(treeNode != null, "No TreeNode found for index $index in $node.");
+ return treeNode;
+ }
+
+ /// Returns the index corresponding to [ir.TreeNode] in this member.
+ int getIndexByTreeNode(ir.TreeNode node) {
+ _ensureMaps();
+ int index = _nodeToIndexMap[node];
+ assert(index != null, "No index found for ${node.runtimeType}.");
+ return index;
+ }
+
+ String toString() => '_MemberData($node(${identityHashCode(node)}))';
+}
diff --git a/pkg/compiler/lib/src/serialization/mixins.dart b/pkg/compiler/lib/src/serialization/mixins.dart
new file mode 100644
index 0000000..e5b009f
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/mixins.dart
@@ -0,0 +1,569 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// Mixin that implements all convenience methods of [DataSource].
+abstract class DataSourceMixin implements DataSource {
+ @override
+ E readValueOrNull<E>(E f()) {
+ bool hasValue = readBool();
+ if (hasValue) {
+ return f();
+ }
+ return null;
+ }
+
+ @override
+ List<E> readList<E>(E f(), {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<E> list = new List<E>(count);
+ for (int i = 0; i < count; i++) {
+ list[i] = f();
+ }
+ return list;
+ }
+
+ @override
+ int readIntOrNull() {
+ bool hasValue = readBool();
+ if (hasValue) {
+ return readInt();
+ }
+ return null;
+ }
+
+ @override
+ String readStringOrNull() {
+ bool hasValue = readBool();
+ if (hasValue) {
+ return readString();
+ }
+ return null;
+ }
+
+ @override
+ List<String> readStrings({bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<String> list = new List<String>(count);
+ for (int i = 0; i < count; i++) {
+ list[i] = readString();
+ }
+ return list;
+ }
+
+ @override
+ List<DartType> readDartTypes({bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<DartType> list = new List<DartType>(count);
+ for (int i = 0; i < count; i++) {
+ list[i] = readDartType();
+ }
+ return list;
+ }
+
+ @override
+ List<ir.TypeParameter> readTypeParameterNodes({bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<ir.TypeParameter> list = new List<ir.TypeParameter>(count);
+ for (int i = 0; i < count; i++) {
+ list[i] = readTypeParameterNode();
+ }
+ return list;
+ }
+
+ @override
+ List<E> readMembers<E extends MemberEntity>({bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<E> list = new List<E>(count);
+ for (int i = 0; i < count; i++) {
+ MemberEntity member = readMember();
+ list[i] = member;
+ }
+ return list;
+ }
+
+ @override
+ List<E> readMemberNodes<E extends ir.Member>({bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<E> list = new List<E>(count);
+ for (int i = 0; i < count; i++) {
+ ir.Member value = readMemberNode();
+ list[i] = value;
+ }
+ return list;
+ }
+
+ @override
+ List<E> readClasses<E extends ClassEntity>({bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<E> list = new List<E>(count);
+ for (int i = 0; i < count; i++) {
+ ClassEntity cls = readClass();
+ list[i] = cls;
+ }
+ return list;
+ }
+
+ @override
+ Map<K, V> readLibraryMap<K extends LibraryEntity, V>(V f(),
+ {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ Map<K, V> map = {};
+ for (int i = 0; i < count; i++) {
+ LibraryEntity library = readLibrary();
+ V value = f();
+ map[library] = value;
+ }
+ return map;
+ }
+
+ @override
+ Map<K, V> readClassMap<K extends ClassEntity, V>(V f(),
+ {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ Map<K, V> map = {};
+ for (int i = 0; i < count; i++) {
+ ClassEntity cls = readClass();
+ V value = f();
+ map[cls] = value;
+ }
+ return map;
+ }
+
+ @override
+ Map<K, V> readMemberMap<K extends MemberEntity, V>(V f(),
+ {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ Map<K, V> map = {};
+ for (int i = 0; i < count; i++) {
+ MemberEntity member = readMember();
+ V value = f();
+ map[member] = value;
+ }
+ return map;
+ }
+
+ @override
+ Map<K, V> readTreeNodeMap<K extends ir.TreeNode, V>(V f(),
+ {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ Map<K, V> map = {};
+ for (int i = 0; i < count; i++) {
+ ir.TreeNode node = readTreeNode();
+ V value = f();
+ map[node] = value;
+ }
+ return map;
+ }
+
+ @override
+ List<E> readLocals<E extends Local>({bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<E> list = new List<E>(count);
+ for (int i = 0; i < count; i++) {
+ Local local = readLocal();
+ list[i] = local;
+ }
+ return list;
+ }
+
+ @override
+ Map<K, V> readLocalMap<K extends Local, V>(V f(), {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ Map<K, V> map = {};
+ for (int i = 0; i < count; i++) {
+ Local local = readLocal();
+ V value = f();
+ map[local] = value;
+ }
+ return map;
+ }
+
+ @override
+ List<E> readTreeNodes<E extends ir.TreeNode>({bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ List<E> list = new List<E>(count);
+ for (int i = 0; i < count; i++) {
+ ir.TreeNode node = readTreeNode();
+ list[i] = node;
+ }
+ return list;
+ }
+
+ @override
+ Map<String, V> readStringMap<V>(V f(), {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ Map<String, V> map = {};
+ for (int i = 0; i < count; i++) {
+ String key = readString();
+ V value = f();
+ map[key] = value;
+ }
+ return map;
+ }
+
+ @override
+ IndexedClass readClassOrNull() {
+ bool hasClass = readBool();
+ if (hasClass) {
+ return readClass();
+ }
+ return null;
+ }
+
+ @override
+ ir.TreeNode readTreeNodeOrNull() {
+ bool hasValue = readBool();
+ if (hasValue) {
+ return readTreeNode();
+ }
+ return null;
+ }
+
+ @override
+ IndexedMember readMemberOrNull() {
+ bool hasValue = readBool();
+ if (hasValue) {
+ return readMember();
+ }
+ return null;
+ }
+
+ @override
+ Local readLocalOrNull() {
+ bool hasValue = readBool();
+ if (hasValue) {
+ return readLocal();
+ }
+ return null;
+ }
+
+ @override
+ Map<K, V> readConstantMap<K extends ConstantValue, V>(V f(),
+ {bool emptyAsNull: false}) {
+ int count = readInt();
+ if (count == 0 && emptyAsNull) return null;
+ Map<K, V> map = {};
+ for (int i = 0; i < count; i++) {
+ ConstantValue key = readConstant();
+ V value = f();
+ map[key] = value;
+ }
+ return map;
+ }
+
+ @override
+ IndexedLibrary readLibraryOrNull() {
+ bool hasValue = readBool();
+ if (hasValue) {
+ return readLibrary();
+ }
+ return null;
+ }
+}
+
+/// Mixin that implements all convenience methods of [DataSink].
+abstract class DataSinkMixin implements DataSink {
+ @override
+ void writeIntOrNull(int value) {
+ writeBool(value != null);
+ if (value != null) {
+ writeInt(value);
+ }
+ }
+
+ @override
+ void writeStringOrNull(String value) {
+ writeBool(value != null);
+ if (value != null) {
+ writeString(value);
+ }
+ }
+
+ @override
+ void writeClassOrNull(IndexedClass value) {
+ writeBool(value != null);
+ if (value != null) {
+ writeClass(value);
+ }
+ }
+
+ @override
+ void writeLocalOrNull(Local value) {
+ writeBool(value != null);
+ if (value != null) {
+ writeLocal(value);
+ }
+ }
+
+ @override
+ void writeClasses(Iterable<ClassEntity> values, {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ for (IndexedClass value in values) {
+ writeClass(value);
+ }
+ }
+ }
+
+ @override
+ void writeTreeNodes(Iterable<ir.TreeNode> values, {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ for (ir.TreeNode value in values) {
+ writeTreeNode(value);
+ }
+ }
+ }
+
+ @override
+ void writeStrings(Iterable<String> values, {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ for (String value in values) {
+ writeString(value);
+ }
+ }
+ }
+
+ @override
+ void writeMemberNodes(Iterable<ir.Member> values, {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ for (ir.Member value in values) {
+ writeMemberNode(value);
+ }
+ }
+ }
+
+ @override
+ void writeDartTypes(Iterable<DartType> values, {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ for (DartType value in values) {
+ writeDartType(value);
+ }
+ }
+ }
+
+ @override
+ void writeLibraryMap<V>(Map<LibraryEntity, V> map, void f(V value),
+ {bool allowNull: false}) {
+ if (map == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(map.length);
+ map.forEach((LibraryEntity library, V value) {
+ writeLibrary(library);
+ f(value);
+ });
+ }
+ }
+
+ @override
+ void writeClassMap<V>(Map<ClassEntity, V> map, void f(V value),
+ {bool allowNull: false}) {
+ if (map == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(map.length);
+ map.forEach((ClassEntity cls, V value) {
+ writeClass(cls);
+ f(value);
+ });
+ }
+ }
+
+ @override
+ void writeMemberMap<V>(Map<MemberEntity, V> map, void f(V value),
+ {bool allowNull: false}) {
+ if (map == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(map.length);
+ map.forEach((MemberEntity member, V value) {
+ writeMember(member);
+ f(value);
+ });
+ }
+ }
+
+ @override
+ void writeStringMap<V>(Map<String, V> map, void f(V value),
+ {bool allowNull: false}) {
+ if (map == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(map.length);
+ map.forEach((String key, V value) {
+ writeString(key);
+ f(value);
+ });
+ }
+ }
+
+ @override
+ void writeLocals(Iterable<Local> values, {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ for (Local value in values) {
+ writeLocal(value);
+ }
+ }
+ }
+
+ @override
+ void writeLocalMap<V>(Map<Local, V> map, void f(V value),
+ {bool allowNull: false}) {
+ if (map == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(map.length);
+ map.forEach((Local key, V value) {
+ writeLocal(key);
+ f(value);
+ });
+ }
+ }
+
+ @override
+ void writeTreeNodeMap<V>(Map<ir.TreeNode, V> map, void f(V value),
+ {bool allowNull: false}) {
+ if (map == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(map.length);
+ map.forEach((ir.TreeNode key, V value) {
+ writeTreeNode(key);
+ f(value);
+ });
+ }
+ }
+
+ @override
+ void writeList<E>(Iterable<E> values, void f(E value),
+ {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ values.forEach(f);
+ }
+ }
+
+ @override
+ void writeTreeNodeOrNull(ir.TreeNode value) {
+ writeBool(value != null);
+ if (value != null) {
+ writeTreeNode(value);
+ }
+ }
+
+ @override
+ void writeValueOrNull<E>(E value, void f(E value)) {
+ writeBool(value != null);
+ if (value != null) {
+ f(value);
+ }
+ }
+
+ @override
+ void writeMemberOrNull(IndexedMember value) {
+ writeBool(value != null);
+ if (value != null) {
+ writeMember(value);
+ }
+ }
+
+ @override
+ void writeMembers(Iterable<MemberEntity> values, {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ for (IndexedMember value in values) {
+ writeMember(value);
+ }
+ }
+ }
+
+ @override
+ void writeTypeParameterNodes(Iterable<ir.TypeParameter> values,
+ {bool allowNull: false}) {
+ if (values == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(values.length);
+ for (ir.TypeParameter value in values) {
+ writeTypeParameterNode(value);
+ }
+ }
+ }
+
+ @override
+ void writeConstantMap<V>(Map<ConstantValue, V> map, void f(V value),
+ {bool allowNull: false}) {
+ if (map == null) {
+ assert(allowNull);
+ writeInt(0);
+ } else {
+ writeInt(map.length);
+ map.forEach((ConstantValue key, V value) {
+ writeConstant(key);
+ f(value);
+ });
+ }
+ }
+
+ @override
+ void writeLibraryOrNull(IndexedLibrary value) {
+ writeBool(value != null);
+ if (value != null) {
+ writeLibrary(value);
+ }
+ }
+}
diff --git a/pkg/compiler/lib/src/serialization/node_indexer.dart b/pkg/compiler/lib/src/serialization/node_indexer.dart
new file mode 100644
index 0000000..c9370f1
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/node_indexer.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// Visitor that ascribes an index to all [ir.TreeNode]s that potentially
+/// needed for serialization and deserialization.
+class _TreeNodeIndexerVisitor extends ir.Visitor<void> {
+ int _currentIndex = 0;
+ final Map<int, ir.TreeNode> _indexToNodeMap;
+ final Map<ir.TreeNode, int> _nodeToIndexMap;
+
+ _TreeNodeIndexerVisitor(this._indexToNodeMap, this._nodeToIndexMap);
+
+ void registerNode(ir.TreeNode node) {
+ _indexToNodeMap[_currentIndex] = node;
+ _nodeToIndexMap[node] = _currentIndex;
+ _currentIndex++;
+ }
+
+ @override
+ void defaultTreeNode(ir.TreeNode node) {
+ node.visitChildren(this);
+ }
+
+ @override
+ void visitFunctionExpression(ir.FunctionExpression node) {
+ registerNode(node);
+ super.visitFunctionExpression(node);
+ }
+
+ @override
+ void visitFunctionDeclaration(ir.FunctionDeclaration node) {
+ registerNode(node);
+ super.visitFunctionDeclaration(node);
+ }
+
+ @override
+ void visitBlock(ir.Block node) {
+ registerNode(node);
+ super.visitBlock(node);
+ }
+
+ @override
+ void visitVariableDeclaration(ir.VariableDeclaration node) {
+ if (node.parent is! ir.FunctionDeclaration) {
+ registerNode(node);
+ }
+ super.visitVariableDeclaration(node);
+ }
+
+ @override
+ void visitSwitchStatement(ir.SwitchStatement node) {
+ registerNode(node);
+ super.visitSwitchStatement(node);
+ }
+
+ @override
+ void visitForStatement(ir.ForStatement node) {
+ registerNode(node);
+ super.visitForStatement(node);
+ }
+
+ @override
+ void visitForInStatement(ir.ForInStatement node) {
+ registerNode(node);
+ super.visitForInStatement(node);
+ }
+
+ @override
+ void visitWhileStatement(ir.WhileStatement node) {
+ registerNode(node);
+ super.visitWhileStatement(node);
+ }
+
+ @override
+ void visitDoStatement(ir.DoStatement node) {
+ registerNode(node);
+ super.visitDoStatement(node);
+ }
+
+ @override
+ void visitBreakStatement(ir.BreakStatement node) {
+ registerNode(node);
+ super.visitBreakStatement(node);
+ }
+
+ @override
+ void visitListLiteral(ir.ListLiteral node) {
+ registerNode(node);
+ super.visitListLiteral(node);
+ }
+
+ @override
+ void visitMapLiteral(ir.MapLiteral node) {
+ registerNode(node);
+ super.visitMapLiteral(node);
+ }
+
+ @override
+ void visitPropertyGet(ir.PropertyGet node) {
+ registerNode(node);
+ super.visitPropertyGet(node);
+ }
+
+ @override
+ void visitPropertySet(ir.PropertySet node) {
+ registerNode(node);
+ super.visitPropertySet(node);
+ }
+
+ @override
+ void visitMethodInvocation(ir.MethodInvocation node) {
+ registerNode(node);
+ super.visitMethodInvocation(node);
+ }
+
+ @override
+ void visitDirectPropertyGet(ir.DirectPropertyGet node) {
+ registerNode(node);
+ super.visitDirectPropertyGet(node);
+ }
+
+ @override
+ void visitDirectPropertySet(ir.DirectPropertySet node) {
+ registerNode(node);
+ super.visitDirectPropertySet(node);
+ }
+
+ @override
+ void visitDirectMethodInvocation(ir.DirectMethodInvocation node) {
+ registerNode(node);
+ super.visitDirectMethodInvocation(node);
+ }
+
+ @override
+ void visitStaticInvocation(ir.StaticInvocation node) {
+ registerNode(node);
+ super.visitStaticInvocation(node);
+ }
+}
diff --git a/pkg/compiler/lib/src/serialization/object_sink.dart b/pkg/compiler/lib/src/serialization/object_sink.dart
new file mode 100644
index 0000000..195db2a
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/object_sink.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// [DataSink] that writes to a list of objects, useful for debugging
+/// inconsistencies between serialization and deserialization.
+///
+/// This data sink works together with [ObjectSource].
+class ObjectSink extends AbstractDataSink {
+ List<dynamic> _data;
+
+ ObjectSink(this._data, {bool useDataKinds})
+ : super(useDataKinds: useDataKinds);
+
+ void _begin(String tag) {
+ _data.add(new Tag('begin:$tag'));
+ }
+
+ void _end(String tag) {
+ _data.add(new Tag('end:$tag'));
+ }
+
+ @override
+ void _writeEnum(dynamic value) {
+ assert(value != null);
+ _data.add(value);
+ }
+
+ @override
+ void _writeInt(int value) {
+ assert(value != null);
+ _data.add(value);
+ }
+
+ @override
+ void _writeString(String value) {
+ assert(value != null);
+ _data.add(value);
+ }
+
+ @override
+ void _writeUri(Uri value) {
+ assert(value != null);
+ _data.add(value);
+ }
+
+ @override
+ void close() {
+ _data = null;
+ }
+}
diff --git a/pkg/compiler/lib/src/serialization/object_source.dart b/pkg/compiler/lib/src/serialization/object_source.dart
new file mode 100644
index 0000000..cae965b
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/object_source.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+part of 'serialization.dart';
+
+/// [DataSource] that read from a list of objects, useful for debugging
+/// inconsistencies between serialization and deserialization.
+///
+/// This data source works together with [ObjectSink].
+class ObjectSource extends AbstractDataSource {
+ int _index = 0;
+ final List<dynamic> _data;
+
+ ObjectSource(this._data, {bool useDataKinds})
+ : super(useDataKinds: useDataKinds);
+
+ T _read<T>() {
+ dynamic value = _data[_index++];
+ assert(value is T, "Expected $T value, found $value.$_errorContext");
+ return value;
+ }
+
+ void _begin(String tag) {
+ Tag expectedTag = new Tag('begin:$tag');
+ Tag actualTag = _read();
+ assert(
+ expectedTag == actualTag,
+ "Unexpected begin tag. "
+ "Expected $expectedTag, found $actualTag.$_errorContext");
+ }
+
+ void _end(String tag) {
+ Tag expectedTag = new Tag('end:$tag');
+ Tag actualTag = _read();
+ assert(
+ expectedTag == actualTag,
+ "Unexpected end tag. "
+ "Expected $expectedTag, found $actualTag.$_errorContext");
+ }
+
+ @override
+ String _readString() => _read();
+
+ @override
+ E _readEnum<E>(List<E> values) => _read();
+
+ @override
+ Uri _readUri() => _read();
+
+ @override
+ int _readInt() => _read();
+
+ @override
+ String get _errorContext {
+ StringBuffer sb = new StringBuffer();
+ for (int i = _index - 50; i < _index + 10; i++) {
+ if (i >= 0 && i < _data.length) {
+ if (i == _index - 1) {
+ sb.write('\n> ');
+ } else {
+ sb.write('\n ');
+ }
+ sb.write(i);
+ sb.write(' ');
+ sb.write(_data[i]);
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
new file mode 100644
index 0000000..a5b738a
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -0,0 +1,560 @@
+// Copyright (c) 2018, the Dart 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 file.
+
+import 'dart:convert';
+import 'dart:typed_data';
+import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/binary/ast_to_binary.dart';
+import '../closure.dart';
+import '../constants/values.dart';
+import '../diagnostics/source_span.dart';
+import '../elements/entities.dart';
+import '../elements/indexed.dart';
+import '../elements/types.dart';
+import '../js_model/closure.dart';
+import '../js_model/locals.dart';
+
+part 'abstract_sink.dart';
+part 'abstract_source.dart';
+part 'binary_sink.dart';
+part 'binary_source.dart';
+part 'helpers.dart';
+part 'member_data.dart';
+part 'mixins.dart';
+part 'node_indexer.dart';
+part 'object_sink.dart';
+part 'object_source.dart';
+
+/// Interface for serialization.
+abstract class DataSink {
+ /// Flushes any pending data and closes this data sink.
+ ///
+ /// The data sink can no longer be written to after closing.
+ void close();
+
+ /// Registers that the section [tag] starts.
+ ///
+ /// This is used for debugging to verify that sections are correctly aligned
+ /// between serialization and deserialization.
+ void begin(String tag);
+
+ /// Registers that the section [tag] ends.
+ ///
+ /// This is used for debugging to verify that sections are correctly aligned
+ /// between serialization and deserialization.
+ void end(String tag);
+
+ /// Writes the potentially `null` [value] to this data sink. If [value] is
+ /// non-null [f] is called to write the non-null value to the data sink.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readValueOrNull].
+ void writeValueOrNull<E>(E value, void f(E value));
+
+ /// Writes the [values] to this data sink calling [f] to write each value to
+ /// the data sink. If [allowNull] is `true`, [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readList].
+ void writeList<E>(Iterable<E> values, void f(E value),
+ {bool allowNull: false});
+
+ /// Writes the boolean [value] to this data sink.
+ void writeBool(bool value);
+
+ /// Writes the non-negative integer [value] to this data sink.
+ void writeInt(int value);
+
+ /// Writes the potentially `null` non-negative [value] to this data sink.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readIntOrNull].
+ void writeIntOrNull(int value);
+
+ /// Writes the string [value] to this data sink.
+ void writeString(String value);
+
+ /// Writes the potentially `null` string [value] to this data sink.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readStringOrNull].
+ void writeStringOrNull(String value);
+
+ /// Writes the string [values] to this data sink. If [allowNull] is `true`,
+ /// [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readStrings].
+ void writeStrings(Iterable<String> values, {bool allowNull: false});
+
+ /// Writes the [map] from string to [V] values to this data sink, calling [f]
+ /// to write each value to the data sink. If [allowNull] is `true`, [map] is
+ /// allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readStringMap].
+ void writeStringMap<V>(Map<String, V> map, void f(V value),
+ {bool allowNull: false});
+
+ /// Writes the enum value [value] to this data sink.
+ // TODO(johnniwinther): Change the signature to
+ // `void writeEnum<E extends Enum<E>>(E value);` when an interface for enums
+ // is added to the language.
+ void writeEnum(dynamic value);
+
+ /// Writes the URI [value] to this data sink.
+ void writeUri(Uri value);
+
+ /// Writes a reference to the kernel library node [value] to this data sink.
+ void writeLibraryNode(ir.Library value);
+
+ /// Writes a reference to the kernel class node [value] to this data sink.
+ void writeClassNode(ir.Class value);
+
+ /// Writes a reference to the kernel member node [value] to this data sink.
+ void writeMemberNode(ir.Member value);
+
+ /// Writes references to the kernel member node [values] to this data sink.
+ /// If [allowNull] is `true`, [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readMemberNodes].
+ void writeMemberNodes(Iterable<ir.Member> values, {bool allowNull: false});
+
+ /// Writes a reference to the kernel tree node [value] to this data sink.
+ void writeTreeNode(ir.TreeNode value);
+
+ /// Writes a reference to the potentially `null` kernel tree node [value]
+ /// to this data sink.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readTreeNodeOrNull].
+ void writeTreeNodeOrNull(ir.TreeNode value);
+
+ /// Writes references to the kernel tree node [values] to this data sink.
+ /// If [allowNull] is `true`, [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readTreeNodes].
+ void writeTreeNodes(Iterable<ir.TreeNode> values, {bool allowNull: false});
+
+ /// Writes the [map] from references to kernel tree nodes to [V] values to
+ /// this data sink, calling [f] to write each value to the data sink. If
+ /// [allowNull] is `true`, [map] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readTreeNodeMap].
+ void writeTreeNodeMap<V>(Map<ir.TreeNode, V> map, void f(V value),
+ {bool allowNull: false});
+
+ /// Writes a reference to the kernel type parameter node [value] to this data
+ /// sink.
+ void writeTypeParameterNode(ir.TypeParameter value);
+
+ /// Writes references to the kernel type parameter node [values] to this data
+ /// sink.
+ /// If [allowNull] is `true`, [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readTypeParameterNodes].
+ void writeTypeParameterNodes(Iterable<ir.TypeParameter> values,
+ {bool allowNull: false});
+
+ /// Writes the type [value] to this data sink. If [allowNull] is `true`,
+ /// [value] is allowed to be `null`.
+ void writeDartType(DartType value, {bool allowNull: false});
+
+ /// Writes the type [values] to this data sink. If [allowNull] is `true`,
+ /// [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readDartTypes].
+ void writeDartTypes(Iterable<DartType> values, {bool allowNull: false});
+
+ /// Writes the source span [value] to this data sink.
+ void writeSourceSpan(SourceSpan value);
+
+ /// Writes a reference to the indexed library [value] to this data sink.
+ void writeLibrary(IndexedLibrary value);
+
+ /// Writes a reference to the potentially `null` indexed library [value]
+ /// to this data sink.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readLibraryOrNull].
+ void writeLibraryOrNull(IndexedLibrary value);
+
+ /// Writes the [map] from references to indexed libraries to [V] values to
+ /// this data sink, calling [f] to write each value to the data sink. If
+ /// [allowNull] is `true`, [map] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readLibraryMap].
+ void writeLibraryMap<V>(Map<LibraryEntity, V> map, void f(V value),
+ {bool allowNull: false});
+
+ /// Writes a reference to the indexed class [value] to this data sink.
+ void writeClass(IndexedClass value);
+
+ /// Writes a reference to the potentially `null` indexed class [value]
+ /// to this data sink.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readClassOrNull].
+ void writeClassOrNull(IndexedClass value);
+
+ /// Writes references to the indexed class [values] to this data sink. If
+ /// [allowNull] is `true`, [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readClasses].
+ void writeClasses(Iterable<ClassEntity> values, {bool allowNull: false});
+
+ /// Writes the [map] from references to indexed classes to [V] values to this
+ /// data sink, calling [f] to write each value to the data sink. If
+ /// [allowNull] is `true`, [map] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readClassMap].
+ void writeClassMap<V>(Map<ClassEntity, V> map, void f(V value),
+ {bool allowNull: false});
+
+ /// Writes a reference to the indexed typedef [value] to this data sink.
+ void writeTypedef(IndexedTypedef value);
+
+ /// Writes a reference to the indexed member [value] to this data sink.
+ void writeMember(IndexedMember value);
+
+ /// Writes a reference to the potentially `null` indexed member [value]
+ /// to this data sink.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readMemberOrNull].
+ void writeMemberOrNull(IndexedMember value);
+
+ /// Writes references to the indexed member [values] to this data sink. If
+ /// [allowNull] is `true`, [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readMembers].
+ void writeMembers(Iterable<MemberEntity> values, {bool allowNull: false});
+
+ /// Writes the [map] from references to indexed members to [V] values to this
+ /// data sink, calling [f] to write each value to the data sink. If
+ /// [allowNull] is `true`, [map] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readMemberMap].
+ void writeMemberMap<V>(Map<MemberEntity, V> map, void f(V value),
+ {bool allowNull: false});
+
+ /// Writes a reference to the local [value] to this data sink.
+ void writeLocal(Local local);
+
+ /// Writes a reference to the potentially `null` local [value]
+ /// to this data sink.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readLocalOrNull].
+ void writeLocalOrNull(Local local);
+
+ /// Writes references to the local [values] to this data sink. If [allowNull]
+ /// is `true`, [values] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readLocals].
+ void writeLocals(Iterable<Local> locals, {bool allowNull: false});
+
+ /// Writes the [map] from references to locals to [V] values to this data
+ /// sink, calling [f] to write each value to the data sink. If [allowNull] is
+ /// `true`, [map] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readLocalMap].
+ void writeLocalMap<V>(Map<Local, V> map, void f(V value),
+ {bool allowNull: false});
+
+ /// Writes the constant [value] to this data sink.
+ void writeConstant(ConstantValue value);
+
+ /// Writes the [map] from constant values to [V] values to this data sink,
+ /// calling [f] to write each value to the data sink. If [allowNull] is
+ /// `true`, [map] is allowed to be `null`.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSource.readConstantMap].
+ void writeConstantMap<V>(Map<ConstantValue, V> map, void f(V value),
+ {bool allowNull: false});
+}
+
+/// Interface for deserialization.
+abstract class DataSource {
+ /// Registers that the section [tag] starts.
+ ///
+ /// This is used for debugging to verify that sections are correctly aligned
+ /// between serialization and deserialization.
+ void begin(String tag);
+
+ /// Registers that the section [tag] ends.
+ ///
+ /// This is used for debugging to verify that sections are correctly aligned
+ /// between serialization and deserialization.
+ void end(String tag);
+
+ /// Registers a [ComponentLookup] object with this data source to support
+ /// deserialization of references to kernel nodes.
+ void registerComponentLookup(ComponentLookup componentLookup);
+
+ /// Registers an [EntityLookup] object with this data source to support
+ /// deserialization of references to indexed entities.
+ void registerEntityLookup(EntityLookup entityLookup);
+
+ /// Registers a [LocalLookup] object with this data source to support
+ /// deserialization of references to locals.
+ void registerLocalLookup(LocalLookup localLookup);
+
+ /// Reads a potentially `null` [E] value from this data source, calling [f] to
+ /// read the non-null value from the data source.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeValueOrNull].
+ E readValueOrNull<E>(E f());
+
+ /// Reads a list of [E] values from this data source. If [emptyAsNull] is
+ /// `true`, `null` is returned instead of an empty list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeList].
+ List<E> readList<E>(E f(), {bool emptyAsNull: false});
+
+ /// Reads a boolean value from this data source.
+ bool readBool();
+
+ /// Reads a non-negative integer value from this data source.
+ int readInt();
+
+ /// Reads a potentially `null` non-negative integer value from this data
+ /// source.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeIntOrNull].
+ int readIntOrNull();
+
+ /// Reads a string value from this data source.
+ String readString();
+
+ /// Reads a potentially `null` string value from this data source.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeStringOrNull].
+ String readStringOrNull();
+
+ /// Reads a list of string values from this data source. If [emptyAsNull] is
+ /// `true`, `null` is returned instead of an empty list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeStrings].
+ List<String> readStrings({bool emptyAsNull: false});
+
+ /// Reads a map from string values to [V] values from this data source,
+ /// calling [f] to read each value from the data source. If [emptyAsNull] is
+ /// `true`, `null` is returned instead of an empty map.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeStringMap].
+ Map<String, V> readStringMap<V>(V f(), {bool emptyAsNull: false});
+
+ /// Reads an enum value from the list of enum [values] from this data source.
+ ///
+ /// The [values] argument is intended to be the static `.values` field on
+ /// enum classes, for instance:
+ ///
+ /// enum Foo { bar, baz }
+ /// ...
+ /// Foo foo = source.readEnum(Foo.values);
+ ///
+ E readEnum<E>(List<E> values);
+
+ /// Reads a URI value from this data source.
+ Uri readUri();
+
+ /// Reads a reference to a kernel library node from this data source.
+ ir.Library readLibraryNode();
+
+ /// Reads a reference to a kernel class node from this data source.
+ ir.Class readClassNode();
+
+ /// Reads a reference to a kernel member node from this data source.
+ ir.Member readMemberNode();
+
+ /// Reads a list of references to kernel member nodes from this data source.
+ /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeMemberNodes].
+ List<ir.Member> readMemberNodes<E extends ir.Member>(
+ {bool emptyAsNull: false});
+
+ /// Reads a reference to a kernel tree node from this data source.
+ ir.TreeNode readTreeNode();
+
+ /// Reads a reference to a potentially `null` kernel tree node from this data
+ /// source.
+ ir.TreeNode readTreeNodeOrNull();
+
+ /// Reads a list of references to kernel tree nodes from this data source.
+ /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeTreeNodes].
+ List<E> readTreeNodes<E extends ir.TreeNode>({bool emptyAsNull: false});
+
+ /// Reads a map from kernel tree nodes to [V] values from this data source,
+ /// calling [f] to read each value from the data source. If [emptyAsNull] is
+ /// `true`, `null` is returned instead of an empty map.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeTreeNodeMap].
+ Map<K, V> readTreeNodeMap<K extends ir.TreeNode, V>(V f(),
+ {bool emptyAsNull: false});
+
+ /// Reads a reference to a kernel type parameter node from this data source.
+ ir.TypeParameter readTypeParameterNode();
+
+ /// Reads a list of references to kernel type parameter nodes from this data
+ /// source. If [emptyAsNull] is `true`, `null` is returned instead of an empty
+ /// list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeTypeParameterNodes].
+ List<ir.TypeParameter> readTypeParameterNodes({bool emptyAsNull: false});
+
+ /// Reads a type from this data source. If [allowNull], the returned type is
+ /// allowed to be `null`.
+ DartType readDartType({bool allowNull: false});
+
+ /// Reads a list of types from this data source. If [emptyAsNull] is `true`,
+ /// `null` is returned instead of an empty list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeDartTypes].
+ List<DartType> readDartTypes({bool emptyAsNull: false});
+
+ /// Reads a source span from this data source.
+ SourceSpan readSourceSpan();
+
+ /// Reads a reference to an indexed library from this data source.
+ IndexedLibrary readLibrary();
+
+ /// Reads a reference to a potentially `null` indexed library from this data
+ /// source.
+ IndexedLibrary readLibraryOrNull();
+ Map<K, V> readLibraryMap<K extends LibraryEntity, V>(V f(),
+ {bool emptyAsNull: false});
+
+ /// Reads a reference to an indexed class from this data source.
+ IndexedClass readClass();
+
+ /// Reads a reference to a potentially `null` indexed class from this data
+ /// source.
+ IndexedClass readClassOrNull();
+
+ /// Reads a list of references to indexed classes from this data source.
+ /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeClasses].
+ List<E> readClasses<E extends ClassEntity>({bool emptyAsNull: false});
+
+ /// Reads a map from indexed classes to [V] values from this data source,
+ /// calling [f] to read each value from the data source. If [emptyAsNull] is
+ /// `true`, `null` is returned instead of an empty map.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeClassMap].
+ Map<K, V> readClassMap<K extends ClassEntity, V>(V f(),
+ {bool emptyAsNull: false});
+
+ /// Reads a reference to an indexed typedef from this data source.
+ IndexedTypedef readTypedef();
+
+ /// Reads a reference to an indexed member from this data source.
+ IndexedMember readMember();
+
+ /// Reads a reference to a potentially `null` indexed member from this data
+ /// source.
+ IndexedMember readMemberOrNull();
+
+ /// Reads a list of references to indexed members from this data source.
+ /// If [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeMembers].
+ List<E> readMembers<E extends MemberEntity>({bool emptyAsNull: false});
+
+ /// Reads a map from indexed members to [V] values from this data source,
+ /// calling [f] to read each value from the data source. If [emptyAsNull] is
+ /// `true`, `null` is returned instead of an empty map.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeMemberMap].
+ Map<K, V> readMemberMap<K extends MemberEntity, V>(V f(),
+ {bool emptyAsNull: false});
+
+ /// Reads a reference to a local from this data source.
+ Local readLocal();
+
+ /// Reads a reference to a potentially `null` local from this data source.
+ Local readLocalOrNull();
+
+ /// Reads a list of references to locals from this data source. If
+ /// [emptyAsNull] is `true`, `null` is returned instead of an empty list.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeLocals].
+ List<E> readLocals<E extends Local>({bool emptyAsNull: false});
+
+ /// Reads a map from locals to [V] values from this data source, calling [f]
+ /// to read each value from the data source. If [emptyAsNull] is `true`,
+ /// `null` is returned instead of an empty map.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeLocalMap].
+ Map<K, V> readLocalMap<K extends Local, V>(V f(), {bool emptyAsNull: false});
+
+ /// Reads a constant value from this data source.
+ ConstantValue readConstant();
+
+ /// Reads a map from constant values to [V] values from this data source,
+ /// calling [f] to read each value from the data source. If [emptyAsNull] is
+ /// `true`, `null` is returned instead of an empty map.
+ ///
+ /// This is a convenience method to be used together with
+ /// [DataSink.writeConstantMap].
+ Map<K, V> readConstantMap<K extends ConstantValue, V>(V f(),
+ {bool emptyAsNull: false});
+}
+
+/// Interface used for looking up entities by index during deserialization.
+abstract class EntityLookup {
+ /// Returns the indexed library corresponding to [index].
+ IndexedLibrary getLibraryByIndex(int index);
+
+ /// Returns the indexed class corresponding to [index].
+ IndexedClass getClassByIndex(int index);
+
+ /// Returns the indexed typedef corresponding to [index].
+ IndexedTypedef getTypedefByIndex(int index);
+
+ /// Returns the indexed member corresponding to [index].
+ IndexedMember getMemberByIndex(int index);
+
+ /// Returns the indexed type variable corresponding to [index].
+ IndexedTypeVariable getTypeVariableByIndex(int index);
+}
+
+/// Interface used for looking up locals by index during deserialization.
+abstract class LocalLookup {
+ Local getLocalByIndex(MemberEntity memberContext, int index);
+}
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
index 37ff14d..d6cd5d0 100644
--- a/pkg/compiler/lib/src/types/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -6,6 +6,7 @@
import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
import '../elements/entities.dart';
+import '../serialization/serialization.dart';
import '../universe/selector.dart';
import '../universe/world_builder.dart';
import '../world.dart';
@@ -456,4 +457,10 @@
/// Returns compact a textual representation for [value] used for debugging.
String getCompactText(AbstractValue value);
+
+ /// Deserializes an [AbstractValue] for this domain from [source].
+ AbstractValue readAbstractValueFromDataSource(DataSource source);
+
+ /// Serializes this [value] for this domain to [sink].
+ void writeAbstractValueToDataSink(DataSink sink, AbstractValue value);
}
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index 77d194c..03ed29e5 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -12,9 +12,11 @@
import '../elements/entities.dart';
import '../js_backend/inferred_data.dart';
import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
+import '../serialization/serialization.dart';
import '../universe/selector.dart' show Selector;
import '../world.dart' show JClosedWorld;
import 'abstract_value_domain.dart';
+import '../inferrer/inferrer_engine.dart';
/// Results about a single element (e.g. a method, parameter, or field)
/// produced by the global type-inference algorithm.
@@ -27,6 +29,14 @@
/// guarantees) and the `subclass of Object or null` type mask for the type
/// based queries (the runtime value could be anything).
abstract class GlobalTypeInferenceMemberResult {
+ /// Deserializes a [GlobalTypeInferenceMemberResult] object from [source].
+ factory GlobalTypeInferenceMemberResult.readFromDataSource(
+ DataSource source, AbstractValueDomain abstractValueDomain) =
+ GlobalTypeInferenceMemberResultImpl.readFromDataSource;
+
+ /// Serializes this [GlobalTypeInferenceMemberResult] to [sink].
+ void writeToDataSink(DataSink sink, AbstractValueDomain abstractValueDomain);
+
/// The inferred type when this result belongs to a field, null otherwise.
AbstractValue get type;
@@ -67,6 +77,18 @@
/// Internal data used during type-inference to store intermediate results about
/// a single element.
abstract class GlobalTypeInferenceElementData {
+ /// Deserializes a [GlobalTypeInferenceElementData] object from [source].
+ factory GlobalTypeInferenceElementData.readFromDataSource(
+ DataSource source, AbstractValueDomain abstractValueDomain) =
+ KernelGlobalTypeInferenceElementData.readFromDataSource;
+
+ /// Serializes this [GlobalTypeInferenceElementData] to [sink].
+ void writeToDataSink(DataSink sink, AbstractValueDomain abstractValueDomain);
+
+ /// Compresses the inner representation by removing [AbstractValue] mappings
+ /// to `null`.
+ void compress();
+
// TODO(johnniwinther): Remove this. Maybe split by access/invoke.
AbstractValue typeOfSend(ir.TreeNode node);
AbstractValue typeOfGetter(ir.TreeNode node);
@@ -98,6 +120,20 @@
/// return was inferred to be a "guaranteed type", that means, it is a type that
/// we can prove to be correct for all executions of the program.
abstract class GlobalTypeInferenceResults {
+ /// Deserializes a [GlobalTypeInferenceResults] object from [source].
+ factory GlobalTypeInferenceResults.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld, InferredData inferredData) {
+ bool isTrivial = source.readBool();
+ if (isTrivial) {
+ return new TrivialGlobalTypeInferenceResults(closedWorld);
+ }
+ return new GlobalTypeInferenceResultsImpl.readFromDataSource(
+ source, closedWorld, inferredData);
+ }
+
+ /// Serializes this [GlobalTypeInferenceResults] to [sink].
+ void writeToDataSink(DataSink sink);
+
JClosedWorld get closedWorld;
InferredData get inferredData;
@@ -154,6 +190,10 @@
}
class GlobalTypeInferenceResultsImpl implements GlobalTypeInferenceResults {
+ /// Tag used for identifying serialized [GlobalTypeInferenceResults] objects
+ /// in a debugging data stream.
+ static const String tag = 'global-type-inference-results';
+
final JClosedWorld closedWorld;
final InferredData inferredData;
final GlobalTypeInferenceMemberResult _deadFieldResult;
@@ -162,7 +202,7 @@
final Map<MemberEntity, GlobalTypeInferenceMemberResult> memberResults;
final Map<Local, AbstractValue> parameterResults;
- final Set<ir.Node> checkedForGrowableLists;
+ final Set<ir.TreeNode> checkedForGrowableLists;
final Set<Selector> returnsListElementTypeSet;
GlobalTypeInferenceResultsImpl(
@@ -178,6 +218,46 @@
closedWorld.abstractValueDomain),
_trivialParameterResult = closedWorld.abstractValueDomain.dynamicType;
+ factory GlobalTypeInferenceResultsImpl.readFromDataSource(
+ DataSource source, JClosedWorld closedWorld, InferredData inferredData) {
+ source.begin(tag);
+ Map<MemberEntity, GlobalTypeInferenceMemberResult> memberResults =
+ source.readMemberMap(() =>
+ new GlobalTypeInferenceMemberResult.readFromDataSource(
+ source, closedWorld.abstractValueDomain));
+ Map<Local, AbstractValue> parameterResults = source.readLocalMap(() =>
+ closedWorld.abstractValueDomain
+ .readAbstractValueFromDataSource(source));
+ Set<ir.TreeNode> checkedForGrowableLists = source.readTreeNodes().toSet();
+ Set<Selector> returnsListElementTypeSet =
+ source.readList(() => new Selector.readFromDataSource(source)).toSet();
+ source.end(tag);
+ return new GlobalTypeInferenceResultsImpl(
+ closedWorld,
+ inferredData,
+ memberResults,
+ parameterResults,
+ checkedForGrowableLists,
+ returnsListElementTypeSet);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.writeBool(false); // Is _not_ trivial.
+ sink.begin(tag);
+ sink.writeMemberMap(
+ memberResults,
+ (GlobalTypeInferenceMemberResult result) =>
+ result.writeToDataSink(sink, closedWorld.abstractValueDomain));
+ sink.writeLocalMap(
+ parameterResults,
+ (AbstractValue value) => closedWorld.abstractValueDomain
+ .writeAbstractValueToDataSink(sink, value));
+ sink.writeTreeNodes(checkedForGrowableLists);
+ sink.writeList(returnsListElementTypeSet,
+ (Selector selector) => selector.writeToDataSink(sink));
+ sink.end(tag);
+ }
+
@override
GlobalTypeInferenceMemberResult resultOfMember(MemberEntity member) {
assert(
@@ -285,6 +365,10 @@
class GlobalTypeInferenceMemberResultImpl
implements GlobalTypeInferenceMemberResult {
+ /// Tag used for identifying serialized [GlobalTypeInferenceMemberResult]
+ /// objects in a debugging data stream.
+ static const String tag = 'global-type-inference-mebmer-result';
+
final GlobalTypeInferenceElementData _data;
final Map<ir.TreeNode, AbstractValue> _allocatedLists;
final AbstractValue returnType;
@@ -296,6 +380,43 @@
this._data, this._allocatedLists, this.returnType, this.type,
{this.throwsAlways, this.isCalledOnce});
+ factory GlobalTypeInferenceMemberResultImpl.readFromDataSource(
+ DataSource source, AbstractValueDomain abstractValueDomain) {
+ source.begin(tag);
+ GlobalTypeInferenceElementData data = source.readValueOrNull(() {
+ return new GlobalTypeInferenceElementData.readFromDataSource(
+ source, abstractValueDomain);
+ });
+ Map<ir.TreeNode, AbstractValue> allocatedLists = source.readTreeNodeMap(
+ () => abstractValueDomain.readAbstractValueFromDataSource(source));
+ AbstractValue returnType =
+ abstractValueDomain.readAbstractValueFromDataSource(source);
+ AbstractValue type =
+ abstractValueDomain.readAbstractValueFromDataSource(source);
+ bool throwsAlways = source.readBool();
+ bool isCalledOnce = source.readBool();
+ source.end(tag);
+ return new GlobalTypeInferenceMemberResultImpl(
+ data, allocatedLists, returnType, type,
+ throwsAlways: throwsAlways, isCalledOnce: isCalledOnce);
+ }
+
+ void writeToDataSink(DataSink sink, AbstractValueDomain abstractValueDomain) {
+ sink.begin(tag);
+ sink.writeValueOrNull(_data, (GlobalTypeInferenceElementData data) {
+ data.writeToDataSink(sink, abstractValueDomain);
+ });
+ sink.writeTreeNodeMap(
+ _allocatedLists,
+ (AbstractValue value) =>
+ abstractValueDomain.writeAbstractValueToDataSink(sink, value));
+ abstractValueDomain.writeAbstractValueToDataSink(sink, returnType);
+ abstractValueDomain.writeAbstractValueToDataSink(sink, type);
+ sink.writeBool(throwsAlways);
+ sink.writeBool(isCalledOnce);
+ sink.end(tag);
+ }
+
AbstractValue typeOfSend(ir.Node node) => _data?.typeOfSend(node);
AbstractValue typeOfGetter(ir.Node node) => _data?.typeOfGetter(node);
AbstractValue typeOfIterator(ir.Node node) => _data?.typeOfIterator(node);
@@ -320,6 +441,10 @@
closedWorld.abstractValueDomain.dynamicType),
_trivialParameterResult = closedWorld.abstractValueDomain.dynamicType;
+ void writeToDataSink(DataSink sink) {
+ sink.writeBool(true); // Is trivial.
+ }
+
@override
bool isFixedArrayCheckedForGrowable(ir.Node node) => false;
@@ -377,6 +502,11 @@
@override
bool get isCalledOnce => false;
+
+ void writeToDataSink(DataSink sink, AbstractValueDomain abstractValueDomain) {
+ throw new UnsupportedError(
+ "TrivialGlobalTypeInferenceMemberResult.writeToDataSink");
+ }
}
class DeadFieldGlobalTypeInferenceResult
@@ -420,6 +550,11 @@
@override
bool get isCalledOnce => false;
+
+ void writeToDataSink(DataSink sink, AbstractValueDomain abstractValueDomain) {
+ throw new UnsupportedError(
+ "DeadFieldGlobalTypeInferenceResult.writeToDataSink");
+ }
}
class DeadMethodGlobalTypeInferenceResult
@@ -463,4 +598,9 @@
@override
bool get isCalledOnce => false;
+
+ void writeToDataSink(DataSink sink, AbstractValueDomain abstractValueDomain) {
+ throw new UnsupportedError(
+ "DeadFieldGlobalTypeInferenceResult.writeToDataSink");
+ }
}
diff --git a/pkg/compiler/lib/src/universe/call_structure.dart b/pkg/compiler/lib/src/universe/call_structure.dart
index 0ca8c4d..c574ac8 100644
--- a/pkg/compiler/lib/src/universe/call_structure.dart
+++ b/pkg/compiler/lib/src/universe/call_structure.dart
@@ -6,6 +6,7 @@
import '../common/names.dart' show Names;
import '../elements/entities.dart' show ParameterStructure;
+import '../serialization/serialization.dart';
import '../util/util.dart';
import 'selector.dart' show Selector;
@@ -14,6 +15,10 @@
// TODO(johnniwinther): Should isGetter/isSetter be part of the call structure
// instead of the selector?
class CallStructure {
+ /// Tag used for identifying serialized [CallStructure] objects in a debugging
+ /// data stream.
+ static const String tag = 'call-structure';
+
static const CallStructure NO_ARGS = const CallStructure.unnamed(0);
static const CallStructure ONE_ARG = const CallStructure.unnamed(1);
static const CallStructure TWO_ARGS = const CallStructure.unnamed(2);
@@ -43,6 +48,25 @@
argumentCount, namedArguments, typeArgumentCount);
}
+ /// Deserializes a [CallStructure] object from [source].
+ factory CallStructure.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ int argumentCount = source.readInt();
+ List<String> namedArguments = source.readStrings();
+ int typeArgumentCount = source.readInt();
+ source.end(tag);
+ return new CallStructure(argumentCount, namedArguments, typeArgumentCount);
+ }
+
+ /// Serializes this [CallStructure] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeInt(argumentCount);
+ sink.writeStrings(namedArguments);
+ sink.writeInt(typeArgumentCount);
+ sink.end(tag);
+ }
+
CallStructure withTypeArgumentCount(int typeArgumentCount) =>
new CallStructure(argumentCount, namedArguments, typeArgumentCount);
diff --git a/pkg/compiler/lib/src/universe/class_hierarchy.dart b/pkg/compiler/lib/src/universe/class_hierarchy.dart
index c351f1e..7032550 100644
--- a/pkg/compiler/lib/src/universe/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/universe/class_hierarchy.dart
@@ -6,11 +6,20 @@
import '../common_elements.dart';
import '../elements/entities.dart';
import '../elements/types.dart' show InterfaceType;
+import '../serialization/serialization.dart';
import 'class_set.dart';
// TODO(johnniwinther): Move more methods from `JClosedWorld` to
// `ClassHierarchy`.
abstract class ClassHierarchy {
+ /// Deserializes a [ClassHierarchy] object from [source].
+ factory ClassHierarchy.readFromDataSource(
+ DataSource source, CommonElements commonElements) =
+ ClassHierarchyImpl.readFromDataSource;
+
+ /// Serializes this [ClassHierarchy] to [sink].
+ void writeToDataSink(DataSink sink);
+
/// Returns `true` if [cls] is either directly or indirectly instantiated.
bool isInstantiated(ClassEntity cls);
@@ -141,6 +150,10 @@
}
class ClassHierarchyImpl implements ClassHierarchy {
+ /// Tag used for identifying serialized [ClassHierarchy] objects in a debugging
+ /// data stream.
+ static const String tag = 'class-hierarchy';
+
final CommonElements _commonElements;
final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes;
final Map<ClassEntity, ClassSet> _classSets;
@@ -148,6 +161,44 @@
ClassHierarchyImpl(
this._commonElements, this._classHierarchyNodes, this._classSets);
+ factory ClassHierarchyImpl.readFromDataSource(
+ DataSource source, CommonElements commonElements) {
+ source.begin(tag);
+ Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes =
+ new ClassHierarchyNodesMap();
+ int classCount = source.readInt();
+ for (int i = 0; i < classCount; i++) {
+ ClassHierarchyNode node = new ClassHierarchyNode.readFromDataSource(
+ source, classHierarchyNodes);
+ classHierarchyNodes[node.cls] = node;
+ }
+ Map<ClassEntity, ClassSet> classSets = {};
+ for (int i = 0; i < classCount; i++) {
+ ClassSet classSet =
+ new ClassSet.readFromDataSource(source, classHierarchyNodes);
+ classSets[classSet.cls] = classSet;
+ }
+
+ source.end(tag);
+ return new ClassHierarchyImpl(
+ commonElements, classHierarchyNodes, classSets);
+ }
+
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeInt(_classSets.length);
+ ClassHierarchyNode node =
+ getClassHierarchyNode(_commonElements.objectClass);
+ node.forEachSubclass((ClassEntity cls) {
+ getClassHierarchyNode(cls).writeToDataSink(sink);
+ }, ClassHierarchyNode.ALL);
+ ClassSet set = getClassSet(_commonElements.objectClass);
+ set.forEachSubclass((ClassEntity cls) {
+ getClassSet(cls).writeToDataSink(sink);
+ }, ClassHierarchyNode.ALL);
+ sink.end(tag);
+ }
+
@override
bool isInstantiated(ClassEntity cls) {
ClassHierarchyNode node = _classHierarchyNodes[cls];
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index 04a9733..6431ab6 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -10,6 +10,7 @@
import '../elements/entities.dart' show ClassEntity;
import '../elements/indexed.dart' show IndexedClass;
+import '../serialization/serialization.dart';
import '../util/enumset.dart' show EnumSet;
/// Enum for the different kinds of instantiation of a class.
@@ -46,6 +47,10 @@
/// E
///
class ClassHierarchyNode {
+ /// Tag used for identifying serialized [ClassHierarchyNode] objects in a
+ /// debugging data stream.
+ static const String tag = 'class-hierarchy-node';
+
/// Enum set for selecting instantiated classes in
/// [ClassHierarchyNode.subclassesByMask],
/// [ClassHierarchyNode.subclassesByMask] and [ClassSet.subtypesByMask].
@@ -209,6 +214,38 @@
}
}
+ /// Deserializes a [ClassHierarchyNode] object from [source].
+ factory ClassHierarchyNode.readFromDataSource(
+ DataSource source, Map<ClassEntity, ClassHierarchyNode> nodeMap) {
+ source.begin(tag);
+ IndexedClass cls = source.readClass();
+ ClassHierarchyNode parentNode;
+ IndexedClass superclass = source.readClassOrNull();
+ if (superclass != null) {
+ parentNode = nodeMap[superclass];
+ assert(parentNode != null,
+ "No ClassHierarchyNode for superclass $superclass.");
+ }
+ int maskValue = source.readInt();
+ int hierarchyDepth = source.readInt();
+ int instantiatedSubclassCount = source.readInt();
+ source.end(tag);
+ return new ClassHierarchyNode(parentNode, cls, hierarchyDepth)
+ .._instantiatedSubclassCount = instantiatedSubclassCount
+ .._mask.value = maskValue;
+ }
+
+ /// Serializes this [ClassHierarchyNode] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeClass(cls);
+ sink.writeClassOrNull(parentNode?.cls);
+ sink.writeInt(_mask.value);
+ sink.writeInt(hierarchyDepth);
+ sink.writeInt(_instantiatedSubclassCount);
+ sink.end(tag);
+ }
+
/// Adds [subclass] as a direct subclass of [cls].
void addDirectSubclass(ClassHierarchyNode subclass) {
assert(!_directSubclasses.contains(subclass));
@@ -463,6 +500,10 @@
/// B E
///
class ClassSet {
+ /// Tag used for identifying serialized [ClassSet] objects in a debugging
+ /// data stream.
+ static const String tag = 'class-set';
+
final ClassHierarchyNode node;
ClassEntity _leastUpperInstantiatedSubtype;
@@ -502,6 +543,36 @@
ClassSet(this.node);
+ /// Deserializes a [ClassSet] object from [source].
+ factory ClassSet.readFromDataSource(
+ DataSource source, Map<ClassEntity, ClassHierarchyNode> nodeMap) {
+ source.begin(tag);
+ ClassHierarchyNode node = nodeMap[source.readClass()];
+ List<ClassHierarchyNode> subtypes = source.readList(() {
+ return nodeMap[source.readClass()];
+ }, emptyAsNull: true);
+ List<ClassHierarchyNode> mixinApplications = source.readList(() {
+ return nodeMap[source.readClass()];
+ }, emptyAsNull: true);
+ source.end(tag);
+ return new ClassSet(node)
+ .._subtypes = subtypes
+ .._mixinApplications = mixinApplications;
+ }
+
+ /// Serializes this [ClassSet] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeClass(node.cls);
+ sink.writeList(_subtypes, (ClassHierarchyNode node) {
+ sink.writeClass(node.cls);
+ }, allowNull: true);
+ sink.writeList(_mixinApplications, (ClassHierarchyNode node) {
+ sink.writeClass(node.cls);
+ }, allowNull: true);
+ sink.end(tag);
+ }
+
ClassEntity get cls => node.cls;
/// Returns `true` if `other.cls` is a subclass of [cls].
diff --git a/pkg/compiler/lib/src/universe/selector.dart b/pkg/compiler/lib/src/universe/selector.dart
index 34aaf06..acc7100 100644
--- a/pkg/compiler/lib/src/universe/selector.dart
+++ b/pkg/compiler/lib/src/universe/selector.dart
@@ -10,6 +10,7 @@
import '../elements/entity_utils.dart' as utils;
import '../elements/names.dart';
import '../elements/operators.dart';
+import '../serialization/serialization.dart';
import '../util/util.dart' show Hashing;
import 'call_structure.dart' show CallStructure;
@@ -40,6 +41,10 @@
}
class Selector {
+ /// Tag used for identifying serialized [Selector] objects in a debugging
+ /// data stream.
+ static const String tag = 'selector';
+
final SelectorKind kind;
final Name memberName;
final CallStructure callStructure;
@@ -192,6 +197,30 @@
Names.genericInstantiation,
new CallStructure(0, null, typeArguments));
+ /// Deserializes a [Selector] object from [source].
+ factory Selector.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ SelectorKind kind = source.readEnum(SelectorKind.values);
+ bool isSetter = source.readBool();
+ LibraryEntity library = source.readLibraryOrNull();
+ String text = source.readString();
+ CallStructure callStructure = new CallStructure.readFromDataSource(source);
+ source.end(tag);
+ return new Selector(
+ kind, new Name(text, library, isSetter: isSetter), callStructure);
+ }
+
+ /// Serializes this [Selector] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeEnum(kind);
+ sink.writeBool(memberName.isSetter);
+ sink.writeLibraryOrNull(memberName.library);
+ sink.writeString(memberName.text);
+ callStructure.writeToDataSink(sink);
+ sink.end(tag);
+ }
+
bool get isGetter => kind == SelectorKind.GETTER;
bool get isSetter => kind == SelectorKind.SETTER;
bool get isCall => kind == SelectorKind.CALL;
diff --git a/pkg/compiler/lib/src/universe/side_effects.dart b/pkg/compiler/lib/src/universe/side_effects.dart
index 81d513f..aac589a 100644
--- a/pkg/compiler/lib/src/universe/side_effects.dart
+++ b/pkg/compiler/lib/src/universe/side_effects.dart
@@ -5,8 +5,13 @@
library universe.side_effects;
import '../elements/entities.dart';
+import '../serialization/serialization.dart';
class SideEffects {
+ /// Tag used for identifying serialized [SideEffects] objects in a debugging
+ /// data stream.
+ static const String tag = 'side-effects';
+
// Changes flags.
static const int FLAG_CHANGES_INDEX = 0;
static const int FLAG_CHANGES_INSTANCE_PROPERTY = FLAG_CHANGES_INDEX + 1;
@@ -37,6 +42,21 @@
SideEffects.fromFlags(this._flags);
+ /// Deserializes a [SideEffects] object from [source].
+ factory SideEffects.readFromDataSource(DataSource source) {
+ source.begin(tag);
+ int flags = source.readInt();
+ source.end(tag);
+ return new SideEffects.fromFlags(flags);
+ }
+
+ /// Serializes this [SideEffects] to [sink].
+ void writeToDataSink(DataSink sink) {
+ sink.begin(tag);
+ sink.writeInt(_flags);
+ sink.end(tag);
+ }
+
bool operator ==(other) => _flags == other._flags;
int get hashCode => throw new UnsupportedError('SideEffects.hashCode');
diff --git a/pkg/compiler/lib/src/util/enumset.dart b/pkg/compiler/lib/src/util/enumset.dart
index 31fef3c..97df1a4 100644
--- a/pkg/compiler/lib/src/util/enumset.dart
+++ b/pkg/compiler/lib/src/util/enumset.dart
@@ -32,6 +32,10 @@
/// The bit mask of the shifted indices for the enum values in this set.
int get value;
+ /// Sets the enum values in this set through a bit mask of the shifted enum
+ /// value indices.
+ void set value(int mask);
+
/// Adds [enumValue] to this set.
void add(E enumValue);
@@ -128,6 +132,11 @@
int get value => _value;
@override
+ void set value(int mask) {
+ _value = mask;
+ }
+
+ @override
void add(E enumValue) {
_value |= 1 << (enumValue as dynamic).index;
}
@@ -173,6 +182,10 @@
return new _ConstEnumSet(value);
}
+ void set value(int mask) {
+ throw new UnsupportedError('EnumSet.value=');
+ }
+
@override
void add(E enumValue) {
throw new UnsupportedError('EnumSet.add');
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index e174ebc..cb83743 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -32,6 +32,7 @@
import 'js_model/locals.dart';
import 'ordered_typeset.dart';
import 'options.dart';
+import 'js_emitter/sorter.dart';
import 'types/abstract_value_domain.dart';
import 'universe/class_hierarchy.dart';
import 'universe/class_set.dart';
@@ -88,6 +89,9 @@
OutputUnitData get outputUnitData;
+ /// The [Sorter] used for sorting elements in the generated code.
+ Sorter get sorter;
+
/// Returns `true` if [cls] is implemented by an instantiated class.
bool isImplemented(ClassEntity cls);
@@ -258,7 +262,7 @@
final JCommonElements commonElements;
// TODO(johnniwinther): Can this be derived from [ClassSet]s?
- final Set<ClassEntity> _implementedClasses;
+ final Set<ClassEntity> implementedClasses;
final Iterable<MemberEntity> liveInstanceMembers;
@@ -280,15 +284,14 @@
this.interceptorData,
this.backendUsage,
this.noSuchMethodData,
- Set<ClassEntity> implementedClasses,
+ this.implementedClasses,
this.liveNativeClasses,
this.liveInstanceMembers,
this.assignedInstanceMembers,
this.processedMembers,
this.mixinUses,
this.typesImplementedBySubclasses,
- this.classHierarchy)
- : this._implementedClasses = implementedClasses;
+ this.classHierarchy);
OrderedTypeSet getOrderedTypeSet(covariant ClassEntity cls);
@@ -304,7 +307,7 @@
/// Returns `true` if [cls] is implemented by an instantiated class.
bool isImplemented(ClassEntity cls) {
- return _implementedClasses.contains(cls);
+ return implementedClasses.contains(cls);
}
@override
diff --git a/tests/compiler/dart2js/analyses/dart2js_allowed.json b/tests/compiler/dart2js/analyses/dart2js_allowed.json
index 1277128..c8f89bc6 100644
--- a/tests/compiler/dart2js/analyses/dart2js_allowed.json
+++ b/tests/compiler/dart2js/analyses/dart2js_allowed.json
@@ -217,6 +217,12 @@
"Dynamic access of 'isString'.": 1,
"Dynamic access of 'stringValue'.": 1
},
+ "pkg/compiler/lib/src/serialization/binary_sink.dart": {
+ "Dynamic access of 'index'.": 1
+ },
+ "pkg/compiler/lib/src/serialization/helpers.dart": {
+ "Dynamic access of 'value'.": 1
+ },
"pkg/compiler/lib/src/universe/use.dart": {
"Dynamic access of 'selector'.": 1,
"Dynamic access of 'receiverConstraint'.": 1,
@@ -298,6 +304,12 @@
"Dynamic access of 'usedBy'.": 2,
"Dynamic access of 'inputs'.": 1
},
+ "pkg/compiler/lib/src/inferrer/inferrer_engine.dart": {
+ "Dynamic access of 'isVoid'.": 1,
+ "Dynamic access of 'isDynamic'.": 1,
+ "Dynamic access of 'isInterfaceType'.": 1,
+ "Dynamic access of 'element'.": 1
+ },
"pkg/compiler/lib/src/universe/function_set.dart": {
"Dynamic access of 'selector'.": 1,
"Dynamic access of 'receiver'.": 1
@@ -365,12 +377,6 @@
"Dynamic invocation of '[]'.": 9,
"Dynamic invocation of 'toStatement'.": 3
},
- "pkg/compiler/lib/src/inferrer/inferrer_engine.dart": {
- "Dynamic access of 'isVoid'.": 1,
- "Dynamic access of 'isDynamic'.": 1,
- "Dynamic access of 'isInterfaceType'.": 1,
- "Dynamic access of 'element'.": 1
- },
"pkg/compiler/lib/src/inferrer/type_graph_nodes.dart": {
"Dynamic invocation of 'add'.": 1,
"Dynamic invocation of 'remove'.": 1,
@@ -383,6 +389,16 @@
"Dynamic access of 'startPosition'.": 1,
"Dynamic access of 'innerPosition'.": 1
},
+ "pkg/compiler/lib/src/inferrer/locals_handler.dart": {
+ "Dynamic access of 'isEmpty'.": 1,
+ "Dynamic access of 'positional'.": 2,
+ "Dynamic access of 'length'.": 2,
+ "Dynamic access of 'named'.": 2,
+ "Dynamic invocation of '[]'.": 2
+ },
+ "pkg/compiler/lib/src/inferrer/type_graph_dump.dart": {
+ "Dynamic invocation of 'contains'.": 2
+ },
"pkg/compiler/lib/src/ssa/variable_allocator.dart": {
"Dynamic access of 'checkedInput'.": 1,
"Dynamic access of 'usedBy'.": 1,
@@ -412,16 +428,6 @@
"pkg/compiler/lib/src/ssa/value_set.dart": {
"Dynamic invocation of 'add'.": 2
},
- "pkg/compiler/lib/src/inferrer/locals_handler.dart": {
- "Dynamic access of 'isEmpty'.": 1,
- "Dynamic access of 'positional'.": 2,
- "Dynamic access of 'length'.": 2,
- "Dynamic access of 'named'.": 2,
- "Dynamic invocation of '[]'.": 2
- },
- "pkg/compiler/lib/src/inferrer/type_graph_dump.dart": {
- "Dynamic invocation of 'contains'.": 2
- },
"pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart": {
"Dynamic access of 'scheme'.": 1,
"Dynamic invocation of 'finalizeTokens'.": 1
diff --git a/tests/compiler/dart2js/model/in_memory_split_test.dart b/tests/compiler/dart2js/model/in_memory_split_test.dart
index 8c1a080..ab13b90 100644
--- a/tests/compiler/dart2js/model/in_memory_split_test.dart
+++ b/tests/compiler/dart2js/model/in_memory_split_test.dart
@@ -2,41 +2,95 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import 'package:args/args.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/filenames.dart';
import 'package:compiler/src/js_backend/inferred_data.dart';
+import 'package:compiler/src/js_model/js_strategy.dart';
+import 'package:compiler/src/serialization/serialization.dart';
import 'package:compiler/src/types/types.dart';
-import 'package:compiler/src/world.dart';
import 'package:expect/expect.dart';
+import 'package:front_end/src/fasta/kernel/utils.dart' as ir
+ show serializeComponent;
+import 'package:front_end/src/fasta/kernel/utils.dart';
+import 'package:kernel/ast.dart' as ir;
+import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
import '../helpers/memory_compiler.dart';
-String code = '''
-main() {}
-''';
-main() {
+main(List<String> args) {
+ ArgParser argParser = new ArgParser(allowTrailingOptions: true);
+ argParser.addFlag('debug', abbr: 'd', defaultsTo: false);
+ argParser.addFlag('object', abbr: 'o', defaultsTo: false);
+ argParser.addFlag('kinds', abbr: 'k', defaultsTo: false);
+ ArgResults argResults = argParser.parse(args);
+
+ bool useObjectSink = argResults['object'] || argResults['debug'];
+ bool useDataKinds = argResults['kinds'] || argResults['debug'];
+
asyncTest(() async {
+ Uri entryPoint;
+ if (argResults.rest.isEmpty) {
+ entryPoint = Uri.base.resolve('samples-dev/swarm/swarm.dart');
+ } else {
+ entryPoint = Uri.base.resolve(nativeToUriPath(argResults.rest.last));
+ }
+
CompilationResult result = await runCompiler(
- memorySourceFiles: {'main.dart': code},
+ entryPoint: entryPoint,
beforeRun: (Compiler compiler) {
compiler.stopAfterTypeInference = true;
});
Expect.isTrue(result.isSuccess);
Compiler compiler = result.compiler;
- GlobalTypeInferenceResults globalInferenceResults =
- cloneInferenceResults(compiler.globalInference.resultsForTesting);
+ GlobalTypeInferenceResults globalInferenceResults = cloneInferenceResults(
+ compiler, compiler.globalInference.resultsForTesting,
+ useObjectSink: useObjectSink, useDataKinds: useDataKinds);
compiler.generateJavaScriptCode(globalInferenceResults);
});
}
GlobalTypeInferenceResults cloneInferenceResults(
- GlobalTypeInferenceResultsImpl result) {
- JClosedWorld closedWorld = result.closedWorld;
- InferredData inferredData = result.inferredData;
- return new GlobalTypeInferenceResultsImpl(
- closedWorld,
- inferredData,
- result.memberResults,
- result.parameterResults,
- result.checkedForGrowableLists,
- result.returnsListElementTypeSet);
+ Compiler compiler, GlobalTypeInferenceResults results,
+ {bool useObjectSink: false, bool useDataKinds}) {
+ JsClosedWorld closedWorld = results.closedWorld;
+ InferredData inferredData = results.inferredData;
+ ir.Component component = closedWorld.elementMap.programEnv.mainComponent;
+ List<int> irData = ir.serializeComponent(component);
+
+ Function() getData;
+
+ DataSink sink;
+ if (useObjectSink) {
+ List data = [];
+ sink = new ObjectSink(data, useDataKinds: useDataKinds);
+ getData = () => data;
+ } else {
+ ByteSink byteSink = new ByteSink();
+ sink = new BinarySink(byteSink, useDataKinds: useDataKinds);
+ getData = () => byteSink.builder.takeBytes();
+ }
+ closedWorld.writeToDataSink(sink);
+ inferredData.writeToDataSink(sink);
+ results.writeToDataSink(sink);
+ sink.close();
+ var worldData = getData();
+ print('data size: ${worldData.length}');
+
+ ir.Component newComponent = new ir.Component();
+ new BinaryBuilder(irData).readComponent(newComponent);
+ DataSource source = useObjectSink
+ ? new ObjectSource(worldData, useDataKinds: useDataKinds)
+ : new BinarySourceImpl(worldData, useDataKinds: useDataKinds);
+ closedWorld = new JsClosedWorld.readFromDataSource(
+ compiler.options,
+ compiler.reporter,
+ compiler.environment,
+ compiler.abstractValueStrategy,
+ newComponent,
+ source);
+ inferredData = new InferredData.readFromDataSource(source, closedWorld);
+ results = new GlobalTypeInferenceResults.readFromDataSource(
+ source, closedWorld, inferredData);
+ return results;
}