Serialize ResolutionImpact instead of WorldImpact.

R=sigmund@google.com

Review URL: https://codereview.chromium.org/1839243003 .
This commit is contained in:
Johnni Winther 2016-03-31 09:55:03 +02:00
parent c53ec0971b
commit 27b2c36ec1
6 changed files with 203 additions and 34 deletions

View file

@ -190,6 +190,9 @@ abstract class Resolution {
ResolutionWorkItem createWorkItem(
Element element, ItemCompilationContext compilationContext);
/// Returns the precomputed [ResolutionImpact] for [element].
ResolutionImpact getResolutionImpact(Element element);
/// Returns the precomputed [WorldImpact] for [element].
WorldImpact getWorldImpact(Element element);

View file

@ -1957,6 +1957,8 @@ class _CompilerDiagnosticReporter extends DiagnosticReporter {
// TODO(johnniwinther): Move [ResolverTask] here.
class _CompilerResolution implements Resolution {
final Compiler compiler;
final Map<Element, ResolutionImpact> _resolutionImpactCache =
<Element, ResolutionImpact>{};
final Map<Element, WorldImpact> _worldImpactCache = <Element, WorldImpact>{};
_CompilerResolution(this.compiler);
@ -2000,6 +2002,14 @@ class _CompilerResolution implements Resolution {
return compiler.resolver.resolveTypeAnnotation(element, node);
}
@override
ResolutionImpact getResolutionImpact(Element element) {
ResolutionImpact resolutionImpact = _resolutionImpactCache[element];
assert(invariant(element, resolutionImpact != null,
message: "ResolutionImpact not available for $element."));
return resolutionImpact;
}
@override
WorldImpact getWorldImpact(Element element) {
WorldImpact worldImpact = _worldImpactCache[element];
@ -2016,6 +2026,14 @@ class _CompilerResolution implements Resolution {
assert(invariant(element, !element.isSynthesized || tree == null));
ResolutionImpact resolutionImpact =
compiler.resolver.resolve(element);
if (compiler.serialization.supportSerialization) {
// [ResolutionImpact] is currently only used by serialization. The
// enqueuer uses the [WorldImpact] which is always cached.
// TODO(johnniwinther): Align these use cases better; maybe only
// cache [ResolutionImpact] and let the enqueuer transform it into
// a [WorldImpact].
_resolutionImpactCache[element] = resolutionImpact;
}
if (tree != null && !compiler.options.analyzeSignaturesOnly) {
// TODO(het): don't do this if suppressWarnings is on, currently we have
// to do it because the typechecker also sets types
@ -2035,6 +2053,7 @@ class _CompilerResolution implements Resolution {
assert(invariant(element, _worldImpactCache[element] != null,
message: "WorldImpact not computed for $element."));
_worldImpactCache[element] = const WorldImpact();
_resolutionImpactCache.remove(element);
}
@override
@ -2042,6 +2061,7 @@ class _CompilerResolution implements Resolution {
for (Element element in _worldImpactCache.keys) {
_worldImpactCache[element] = const WorldImpact();
}
_resolutionImpactCache.clear();
}
@override

View file

@ -5,26 +5,58 @@
library dart2js.serialization.impact;
import '../dart_types.dart';
import '../common/resolution.dart';
import '../constants/expressions.dart';
import '../elements/elements.dart';
import '../universe/call_structure.dart';
import '../universe/selector.dart';
import '../universe/world_impact.dart';
import '../universe/use.dart';
import '../util/enumset.dart';
import 'keys.dart';
import 'serialization.dart';
/// Visitor that serializes a [WorldImpact] object using an [ObjectEncoder].
/// Visitor that serializes a [ResolutionImpact] object using an
/// [ObjectEncoder].
class ImpactSerializer implements WorldImpactVisitor {
final ObjectEncoder objectEncoder;
final ListEncoder staticUses;
final ListEncoder dynamicUses;
final ListEncoder typeUses;
ImpactSerializer(ObjectEncoder objectEncoder)
: staticUses = objectEncoder.createList(Key.STATIC_USES),
: this.objectEncoder = objectEncoder,
staticUses = objectEncoder.createList(Key.STATIC_USES),
dynamicUses = objectEncoder.createList(Key.DYNAMIC_USES),
typeUses = objectEncoder.createList(Key.TYPE_USES);
void serialize(ResolutionImpact resolutionImpact) {
resolutionImpact.apply(this);
objectEncoder.setStrings(Key.SYMBOLS, resolutionImpact.constSymbolNames);
objectEncoder.setConstants(
Key.CONSTANTS, resolutionImpact.constantLiterals);
objectEncoder.setEnums(Key.FEATURES, resolutionImpact.features);
if (resolutionImpact.listLiterals.isNotEmpty) {
ListEncoder encoder = objectEncoder.createList(Key.LISTS);
for (ListLiteralUse use in resolutionImpact.listLiterals) {
ObjectEncoder useEncoder = encoder.createObject();
useEncoder.setType(Key.TYPE, use.type);
useEncoder.setBool(Key.IS_CONST, use.isConstant);
useEncoder.setBool(Key.IS_EMPTY, use.isEmpty);
}
}
if (resolutionImpact.mapLiterals.isNotEmpty) {
ListEncoder encoder = objectEncoder.createList(Key.MAPS);
for (MapLiteralUse use in resolutionImpact.mapLiterals) {
ObjectEncoder useEncoder = encoder.createObject();
useEncoder.setType(Key.TYPE, use.type);
useEncoder.setBool(Key.IS_CONST, use.isConstant);
useEncoder.setBool(Key.IS_EMPTY, use.isEmpty);
}
}
}
@override
void visitDynamicUse(DynamicUse dynamicUse) {
ObjectEncoder object = dynamicUses.createObject();
@ -66,22 +98,47 @@ class ImpactSerializer implements WorldImpactVisitor {
}
/// A deserialized [WorldImpact] object.
class DeserializedWorldImpact extends WorldImpact with WorldImpactBuilder {}
class DeserializedResolutionImpact extends WorldImpact
implements ResolutionImpact {
final Iterable<String> constSymbolNames;
final Iterable<ConstantExpression> constantLiterals;
final Iterable<DynamicUse> dynamicUses;
final EnumSet<Feature> _features;
final Iterable<ListLiteralUse> listLiterals;
final Iterable<MapLiteralUse> mapLiterals;
final Iterable<StaticUse> staticUses;
final Iterable<TypeUse> typeUses;
DeserializedResolutionImpact({
this.constSymbolNames,
this.constantLiterals,
this.dynamicUses,
EnumSet<Feature> features,
this.listLiterals,
this.mapLiterals,
this.staticUses,
this.typeUses})
: this._features = features;
Iterable<Feature> get features => _features.iterable(Feature.values);
}
class ImpactDeserializer {
/// Deserializes a [WorldImpact] from [objectDecoder].
static WorldImpact deserializeImpact(ObjectDecoder objectDecoder) {
DeserializedWorldImpact worldImpact = new DeserializedWorldImpact();
ListDecoder staticUses = objectDecoder.getList(Key.STATIC_USES);
for (int index = 0; index < staticUses.length; index++) {
ObjectDecoder object = staticUses.getObject(index);
static ResolutionImpact deserializeImpact(ObjectDecoder objectDecoder) {
ListDecoder staticUseDecoder = objectDecoder.getList(Key.STATIC_USES);
List<StaticUse> staticUses = <StaticUse>[];
for (int index = 0; index < staticUseDecoder.length; index++) {
ObjectDecoder object = staticUseDecoder.getObject(index);
StaticUseKind kind = object.getEnum(Key.KIND, StaticUseKind.values);
Element element = object.getElement(Key.ELEMENT);
worldImpact.registerStaticUse(new StaticUse.internal(element, kind));
staticUses.add(new StaticUse.internal(element, kind));
}
ListDecoder dynamicUses = objectDecoder.getList(Key.DYNAMIC_USES);
for (int index = 0; index < dynamicUses.length; index++) {
ObjectDecoder object = dynamicUses.getObject(index);
ListDecoder dynamicUseDecoder = objectDecoder.getList(Key.DYNAMIC_USES);
List<DynamicUse> dynamicUses = <DynamicUse>[];
for (int index = 0; index < dynamicUseDecoder.length; index++) {
ObjectDecoder object = dynamicUseDecoder.getObject(index);
SelectorKind kind = object.getEnum(Key.KIND, SelectorKind.values);
int argumentCount = object.getInt(Key.ARGUMENTS);
List<String> namedArguments =
@ -89,7 +146,7 @@ class ImpactDeserializer {
String name = object.getString(Key.NAME);
bool isSetter = object.getBool(Key.IS_SETTER);
LibraryElement library = object.getElement(Key.LIBRARY, isOptional: true);
worldImpact.registerDynamicUse(
dynamicUses.add(
new DynamicUse(
new Selector(
kind,
@ -97,13 +154,63 @@ class ImpactDeserializer {
new CallStructure(argumentCount, namedArguments)),
null));
}
ListDecoder typeUses = objectDecoder.getList(Key.TYPE_USES);
for (int index = 0; index < typeUses.length; index++) {
ObjectDecoder object = typeUses.getObject(index);
ListDecoder typeUseDecoder = objectDecoder.getList(Key.TYPE_USES);
List<TypeUse> typeUses = <TypeUse>[];
for (int index = 0; index < typeUseDecoder.length; index++) {
ObjectDecoder object = typeUseDecoder.getObject(index);
TypeUseKind kind = object.getEnum(Key.KIND, TypeUseKind.values);
DartType type = object.getType(Key.TYPE);
worldImpact.registerTypeUse(new TypeUse.internal(type, kind));
typeUses.add(new TypeUse.internal(type, kind));
}
return worldImpact;
List<String> constSymbolNames =
objectDecoder.getStrings(Key.SYMBOLS, isOptional: true);
List<ConstantExpression> constantLiterals =
objectDecoder.getConstants(Key.CONSTANTS, isOptional: true);
EnumSet<Feature> features =
objectDecoder.getEnums(Key.FEATURES, isOptional: true);
ListDecoder listLiteralDecoder =
objectDecoder.getList(Key.LISTS, isOptional: true);
List<ListLiteralUse> listLiterals = const <ListLiteralUse>[];
if (listLiteralDecoder != null) {
listLiterals = <ListLiteralUse>[];
for (int i = 0; i < listLiteralDecoder.length; i++) {
ObjectDecoder useDecoder = listLiteralDecoder.getObject(i);
DartType type = useDecoder.getType(Key.TYPE);
bool isConstant = useDecoder.getBool(Key.IS_CONST);
bool isEmpty = useDecoder.getBool(Key.IS_EMPTY);
listLiterals.add(new ListLiteralUse(
type, isConstant: isConstant, isEmpty: isEmpty));
}
}
ListDecoder mapLiteralDecoder =
objectDecoder.getList(Key.LISTS, isOptional: true);
List<MapLiteralUse> mapLiterals = const <MapLiteralUse>[];
if (listLiteralDecoder != null) {
mapLiterals = <MapLiteralUse>[];
for (int i = 0; i < mapLiteralDecoder.length; i++) {
ObjectDecoder useDecoder = mapLiteralDecoder.getObject(i);
DartType type = useDecoder.getType(Key.TYPE);
bool isConstant = useDecoder.getBool(Key.IS_CONST);
bool isEmpty = useDecoder.getBool(Key.IS_EMPTY);
mapLiterals.add(new MapLiteralUse(
type, isConstant: isConstant, isEmpty: isEmpty));
}
}
return new DeserializedResolutionImpact(
constSymbolNames: constSymbolNames,
constantLiterals: constantLiterals,
dynamicUses: dynamicUses,
features: features,
listLiterals: listLiterals,
mapLiterals: mapLiterals,
staticUses: staticUses,
typeUses: typeUses);
}
}

View file

@ -29,6 +29,7 @@ class Key {
static const Key EXPORT_SCOPE = const Key('export-scope');
static const Key EXPRESSION = const Key('expression');
static const Key FALSE = const Key('false');
static const Key FEATURES = const Key('features');
static const Key FIELD = const Key('field');
static const Key FIELDS = const Key('fields');
static const Key FUNCTION = const Key('function');
@ -42,6 +43,7 @@ class Key {
static const Key IS_ABSTRACT = const Key('isAbstract');
static const Key IS_CONST = const Key('isConst');
static const Key IS_DEFERRED = const Key('isDeferred');
static const Key IS_EMPTY = const Key('isEmpty');
static const Key IS_EXTERNAL = const Key('isExternal');
static const Key IS_FINAL = const Key('isFinal');
static const Key IS_NAMED = const Key('isNamed');
@ -58,6 +60,8 @@ class Key {
static const Key LIBRARY = const Key('library');
static const Key LIBRARY_DEPENDENCY = const Key('library-dependency');
static const Key LIBRARY_NAME = const Key('library-name');
static const Key LISTS = const Key('lists');
static const Key MAPS = const Key('maps');
static const Key MEMBERS = const Key('members');
static const Key MIXIN = const Key('mixin');
static const Key MIXINS = const Key('mixins');
@ -78,6 +82,7 @@ class Key {
static const Key STATIC_USES = const Key('static-uses');
static const Key SUPERTYPE = const Key('supertype');
static const Key SUPERTYPES = const Key('supertypes');
static const Key SYMBOLS = const Key('symbols');
static const Key TAGS = const Key('tags');
static const Key TRUE = const Key('true');
static const Key TYPE = const Key('type');

View file

@ -7,6 +7,7 @@ library dart2js.serialization;
import '../elements/elements.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../util/enumset.dart';
import 'constant_serialization.dart';
import 'element_serialization.dart';
@ -103,6 +104,17 @@ abstract class AbstractEncoder<K> {
_map[key] = new EnumValue(value);
}
/// Maps the [key] entry to the set of enum [values] in the encoded object.
void setEnums(K key, Iterable values) {
setEnumSet(key, new EnumSet.fromValues(values));
}
/// Maps the [key] entry to the enum [set] in the encoded object.
void setEnumSet(K key, EnumSet set) {
_checkKey(key);
_map[key] = new IntValue(set.value);
}
/// Maps the [key] entry to the [element] in the encoded object.
void setElement(K key, Element element) {
_checkKey(key);
@ -321,6 +333,22 @@ abstract class AbstractDecoder<K> {
return enumValues[value];
}
/// Returns the set of enum values associated with [key] in the decoded
/// object.
///
/// If no value is associated with [key], then if [isOptional] is `true`,
/// [defaultValue] is returned, otherwise an exception is thrown.
EnumSet getEnums(K key, {bool isOptional: false}) {
int value = _map[_getKeyValue(key)];
if (value == null) {
if (isOptional) {
return const EnumSet.fixed(0);
}
throw new StateError("enum values '$key' not found in $_map.");
}
return new EnumSet.fixed(value);
}
/// Returns the [Element] value associated with [key] in the decoded object.
///
/// If no value is associated with [key], then if [isOptional] is `true`,

View file

@ -8,6 +8,7 @@ import 'dart:async';
import 'package:async_helper/async_helper.dart';
import 'package:expect/expect.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/common/backend_api.dart';
import 'package:compiler/src/common/names.dart';
import 'package:compiler/src/common/resolution.dart';
import 'package:compiler/src/compiler.dart';
@ -247,7 +248,9 @@ Future analyze(String serializedData, Uri entryPoint, Test test) async {
const JsonSerializationDecoder());
deserializer.plugins.add(compiler.backend.serialization.deserializer);
compiler.serialization.deserializer =
new _DeserializerSystem(deserializer);
new _DeserializerSystem(
deserializer,
compiler.backend.impactTransformer);
});
if (test != null) {
Expect.equals(test.expectedErrorCount, diagnosticCollector.errors.length,
@ -274,7 +277,7 @@ Future<String> serializeDartCore() async {
String serialize(Compiler compiler) {
Serializer serializer = new Serializer();
serializer.plugins.add(compiler.backend.serialization.serializer);
serializer.plugins.add(new WorldImpactSerializer(compiler.resolution));
serializer.plugins.add(new ResolutionImpactSerializer(compiler.resolution));
for (LibraryElement library in compiler.libraryLoader.libraries) {
serializer.serialize(library);
@ -284,23 +287,23 @@ String serialize(Compiler compiler) {
const String WORLD_IMPACT_TAG = 'worldImpact';
class WorldImpactSerializer extends SerializerPlugin {
class ResolutionImpactSerializer extends SerializerPlugin {
final Resolution resolution;
WorldImpactSerializer(this.resolution);
ResolutionImpactSerializer(this.resolution);
@override
void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
if (resolution.hasBeenResolved(element)) {
WorldImpact impact = resolution.getWorldImpact(element);
ResolutionImpact impact = resolution.getResolutionImpact(element);
ObjectEncoder encoder = createEncoder(WORLD_IMPACT_TAG);
impact.apply(new ImpactSerializer(encoder));
new ImpactSerializer(encoder).serialize(impact);
}
}
}
class WorldImpactDeserializer extends DeserializerPlugin {
Map<Element, WorldImpact> impactMap = <Element, WorldImpact>{};
class ResolutionImpactDeserializer extends DeserializerPlugin {
Map<Element, ResolutionImpact> impactMap = <Element, ResolutionImpact>{};
@override
void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
@ -314,11 +317,12 @@ class WorldImpactDeserializer extends DeserializerPlugin {
class _DeserializerSystem extends DeserializerSystem {
final Deserializer _deserializer;
final List<LibraryElement> deserializedLibraries = <LibraryElement>[];
final WorldImpactDeserializer _worldImpactDeserializer =
new WorldImpactDeserializer();
final ResolutionImpactDeserializer _resolutionImpactDeserializer =
new ResolutionImpactDeserializer();
final ImpactTransformer _impactTransformer;
_DeserializerSystem(this._deserializer) {
_deserializer.plugins.add(_worldImpactDeserializer);
_DeserializerSystem(this._deserializer, this._impactTransformer) {
_deserializer.plugins.add(_resolutionImpactDeserializer);
}
LibraryElement readLibrary(Uri resolvedUri) {
@ -331,12 +335,14 @@ class _DeserializerSystem extends DeserializerSystem {
@override
WorldImpact computeWorldImpact(Element element) {
WorldImpact impact = _worldImpactDeserializer.impactMap[element];
if (impact == null) {
ResolutionImpact resolutionImpact =
_resolutionImpactDeserializer.impactMap[element];
if (resolutionImpact == null) {
print('No impact found for $element (${element.library})');
impact = const WorldImpact();
return const WorldImpact();
} else {
return _impactTransformer.transformResolutionImpact(resolutionImpact);
}
return impact;
}
@override