Serialize TreeElements
R=sigmund@google.com Review URL: https://codereview.chromium.org/1873573004 .
This commit is contained in:
@@ -20,6 +20,7 @@ import '../elements/elements.dart'
|
||||
LocalFunctionElement,
|
||||
MetadataAnnotation,
|
||||
MethodElement,
|
||||
ResolvedAst,
|
||||
TypedefElement,
|
||||
TypeVariableElement;
|
||||
import '../enqueue.dart' show ResolutionEnqueuer;
|
||||
@@ -207,6 +208,12 @@ abstract class Resolution {
|
||||
ResolutionWorkItem createWorkItem(
|
||||
Element element, ItemCompilationContext compilationContext);
|
||||
|
||||
/// Returns `true` if [element] as a fully computed [ResolvedAst].
|
||||
bool hasResolvedAst(Element element);
|
||||
|
||||
/// Returns the `ResolvedAst` for the [element].
|
||||
ResolvedAst getResolvedAst(Element element);
|
||||
|
||||
/// Returns `true` if the [ResolutionImpact] for [element] is cached.
|
||||
bool hasResolutionImpact(Element element);
|
||||
|
||||
|
||||
@@ -1893,6 +1893,25 @@ class _CompilerResolution implements Resolution {
|
||||
return compiler.resolver.resolveTypeAnnotation(element, node);
|
||||
}
|
||||
|
||||
@override
|
||||
bool hasResolvedAst(Element element) {
|
||||
return element is AstElement &&
|
||||
hasBeenResolved(element) &&
|
||||
element.hasResolvedAst;
|
||||
}
|
||||
|
||||
@override
|
||||
ResolvedAst getResolvedAst(Element element) {
|
||||
if (hasResolvedAst(element)) {
|
||||
AstElement astElement = element;
|
||||
return astElement.resolvedAst;
|
||||
}
|
||||
assert(invariant(element, hasResolvedAst(element),
|
||||
message: "ResolvedAst not available for $element."));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
bool hasResolutionImpact(Element element) {
|
||||
return _resolutionImpactCache.containsKey(element);
|
||||
|
||||
@@ -634,46 +634,49 @@ class _LibraryLoaderTask extends CompilerTask implements LibraryLoaderTask {
|
||||
if (library != null) {
|
||||
return new Future.value(library);
|
||||
}
|
||||
library = deserializer.readLibrary(resolvedUri);
|
||||
if (library != null) {
|
||||
return loadDeserializedLibrary(handler, library);
|
||||
}
|
||||
return reporter.withCurrentElement(importingLibrary, () {
|
||||
return _readScript(node, readableUri, resolvedUri).then((Script script) {
|
||||
if (script == null) return null;
|
||||
LibraryElement element =
|
||||
createLibrarySync(handler, script, resolvedUri);
|
||||
CompilationUnitElementX compilationUnit = element.entryCompilationUnit;
|
||||
if (compilationUnit.partTag != null) {
|
||||
if (skipFileWithPartOfTag) {
|
||||
// TODO(johnniwinther): Avoid calling [listener.onLibraryCreated]
|
||||
// for this library.
|
||||
libraryCanonicalUriMap.remove(resolvedUri);
|
||||
return null;
|
||||
return deserializer.readLibrary(resolvedUri).then((LibraryElement library) {
|
||||
if (library != null) {
|
||||
return loadDeserializedLibrary(handler, library);
|
||||
}
|
||||
return reporter.withCurrentElement(importingLibrary, () {
|
||||
return _readScript(node, readableUri, resolvedUri)
|
||||
.then((Script script) {
|
||||
if (script == null) return null;
|
||||
LibraryElement element =
|
||||
createLibrarySync(handler, script, resolvedUri);
|
||||
CompilationUnitElementX compilationUnit =
|
||||
element.entryCompilationUnit;
|
||||
if (compilationUnit.partTag != null) {
|
||||
if (skipFileWithPartOfTag) {
|
||||
// TODO(johnniwinther): Avoid calling [listener.onLibraryCreated]
|
||||
// for this library.
|
||||
libraryCanonicalUriMap.remove(resolvedUri);
|
||||
return null;
|
||||
}
|
||||
if (importingLibrary == null) {
|
||||
DiagnosticMessage error = reporter.withCurrentElement(
|
||||
compilationUnit,
|
||||
() => reporter.createMessage(
|
||||
compilationUnit.partTag, MessageKind.MAIN_HAS_PART_OF));
|
||||
reporter.reportError(error);
|
||||
} else {
|
||||
DiagnosticMessage error = reporter.withCurrentElement(
|
||||
compilationUnit,
|
||||
() => reporter.createMessage(
|
||||
compilationUnit.partTag, MessageKind.IMPORT_PART_OF));
|
||||
DiagnosticMessage info = reporter.withCurrentElement(
|
||||
importingLibrary,
|
||||
() => reporter.createMessage(
|
||||
node, MessageKind.IMPORT_PART_OF_HERE));
|
||||
reporter.reportError(error, [info]);
|
||||
}
|
||||
}
|
||||
if (importingLibrary == null) {
|
||||
DiagnosticMessage error = reporter.withCurrentElement(
|
||||
compilationUnit,
|
||||
() => reporter.createMessage(
|
||||
compilationUnit.partTag, MessageKind.MAIN_HAS_PART_OF));
|
||||
reporter.reportError(error);
|
||||
} else {
|
||||
DiagnosticMessage error = reporter.withCurrentElement(
|
||||
compilationUnit,
|
||||
() => reporter.createMessage(
|
||||
compilationUnit.partTag, MessageKind.IMPORT_PART_OF));
|
||||
DiagnosticMessage info = reporter.withCurrentElement(
|
||||
importingLibrary,
|
||||
() => reporter.createMessage(
|
||||
node, MessageKind.IMPORT_PART_OF_HERE));
|
||||
reporter.reportError(error, [info]);
|
||||
}
|
||||
}
|
||||
return processLibraryTags(handler, element).then((_) {
|
||||
reporter.withCurrentElement(element, () {
|
||||
handler.registerLibraryExports(element);
|
||||
return processLibraryTags(handler, element).then((_) {
|
||||
reporter.withCurrentElement(element, () {
|
||||
handler.registerLibraryExports(element);
|
||||
});
|
||||
return element;
|
||||
});
|
||||
return element;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -105,8 +105,7 @@ class ConstantSerializer
|
||||
|
||||
@override
|
||||
void visitSymbol(SymbolConstantExpression exp, ObjectEncoder encoder) {
|
||||
throw new UnsupportedError(
|
||||
"ConstantSerializer.visitSymbol: ${exp.getText()}");
|
||||
encoder.setString(Key.NAME, exp.name);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -11,8 +11,13 @@ import '../constants/expressions.dart';
|
||||
import '../dart_types.dart';
|
||||
import '../elements/elements.dart';
|
||||
import '../elements/visitor.dart';
|
||||
import '../resolution/send_structure.dart';
|
||||
import '../resolution/tree_elements.dart';
|
||||
import '../tokens/token.dart';
|
||||
import '../tree/nodes.dart';
|
||||
import '../universe/selector.dart';
|
||||
import '../universe/use.dart';
|
||||
import 'resolved_ast_serialization.dart';
|
||||
|
||||
/// Equality based equivalence function.
|
||||
bool equality(a, b) => a == b;
|
||||
@@ -90,6 +95,8 @@ bool areConstantListsEquivalent(
|
||||
|
||||
/// Returns `true` if the selectors [a] and [b] are equivalent.
|
||||
bool areSelectorsEquivalent(Selector a, Selector b) {
|
||||
if (identical(a, b)) return true;
|
||||
if (a == null || b == null) return false;
|
||||
return a.kind == b.kind &&
|
||||
a.callStructure == b.callStructure &&
|
||||
areNamesEquivalent(a.memberName, b.memberName);
|
||||
@@ -131,14 +138,33 @@ bool areMapLiteralUsesEquivalent(MapLiteralUse a, MapLiteralUse b) {
|
||||
a.isEmpty == b.isEmpty;
|
||||
}
|
||||
|
||||
/// Returns `true` if the send structures [a] and [b] are equivalent.
|
||||
bool areSendStructuresEquivalent(SendStructure a, SendStructure b) {
|
||||
if (identical(a, b)) return true;
|
||||
if (a == null || b == null) return false;
|
||||
if (a.kind != b.kind) return false;
|
||||
// TODO(johnniwinther): Compute a deep equivalence.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns `true` if the new structures [a] and [b] are equivalent.
|
||||
bool areNewStructuresEquivalent(NewStructure a, NewStructure b) {
|
||||
if (identical(a, b)) return true;
|
||||
if (a == null || b == null) return false;
|
||||
if (a.kind != b.kind) return false;
|
||||
// TODO(johnniwinther): Compute a deep equivalence.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Strategy for testing equivalence.
|
||||
///
|
||||
/// Use this strategy to determine equivalence without failing on inequivalence.
|
||||
class TestStrategy {
|
||||
const TestStrategy();
|
||||
|
||||
bool test(var object1, var object2, String property, var value1, var value2) {
|
||||
return value1 == value2;
|
||||
bool test(var object1, var object2, String property, var value1, var value2,
|
||||
[bool equivalence(a, b) = equality]) {
|
||||
return equivalence(value1, value2);
|
||||
}
|
||||
|
||||
bool testLists(
|
||||
@@ -483,8 +509,9 @@ class ConstantEquivalence
|
||||
@override
|
||||
bool visitSymbol(
|
||||
SymbolConstantExpression exp1, SymbolConstantExpression exp2) {
|
||||
// TODO: implement visitSymbol
|
||||
return true;
|
||||
// TODO(johnniwinther): Handle private names. Currently not even supported
|
||||
// in resolution.
|
||||
return strategy.test(exp1, exp2, 'name', exp1.name, exp2.name);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -572,7 +599,7 @@ class ConstantEquivalence
|
||||
@override
|
||||
bool visitDeferred(
|
||||
DeferredConstantExpression exp1, DeferredConstantExpression exp2) {
|
||||
// TODO: implement visitDeferred
|
||||
// TODO(johnniwinther): Implement this.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -603,3 +630,178 @@ bool testResolutionImpactEquivalence(
|
||||
strategy.testSets(impact1, impact2, 'typeUses', impact1.typeUses,
|
||||
impact2.typeUses, areTypeUsesEquivalent);
|
||||
}
|
||||
|
||||
/// Tests the equivalence of [resolvedAst1] and [resolvedAst2] using [strategy].
|
||||
bool testResolvedAstEquivalence(
|
||||
ResolvedAst resolvedAst1, ResolvedAst resolvedAst2,
|
||||
[TestStrategy strategy = const TestStrategy()]) {
|
||||
return strategy.testElements(resolvedAst1, resolvedAst2, 'element',
|
||||
resolvedAst1.element, resolvedAst2.element) &&
|
||||
// Compute AST equivalence by structural comparison.
|
||||
strategy.test(
|
||||
resolvedAst1,
|
||||
resolvedAst2,
|
||||
'node',
|
||||
resolvedAst1.node.toDebugString(),
|
||||
resolvedAst2.node.toDebugString()) &&
|
||||
testTreeElementsEquivalence(resolvedAst1, resolvedAst2, strategy);
|
||||
}
|
||||
|
||||
/// Tests the equivalence of the data stored in the [TreeElements] of
|
||||
/// [resolvedAst1] and [resolvedAst2] using [strategy].
|
||||
bool testTreeElementsEquivalence(
|
||||
ResolvedAst resolvedAst1, ResolvedAst resolvedAst2,
|
||||
[TestStrategy strategy = const TestStrategy()]) {
|
||||
AstIndexComputer indices1 = new AstIndexComputer();
|
||||
resolvedAst1.node.accept(indices1);
|
||||
AstIndexComputer indices2 = new AstIndexComputer();
|
||||
resolvedAst2.node.accept(indices2);
|
||||
|
||||
TreeElements elements1 = resolvedAst1.elements;
|
||||
TreeElements elements2 = resolvedAst2.elements;
|
||||
|
||||
TreeElementsEquivalenceVisitor visitor = new TreeElementsEquivalenceVisitor(
|
||||
indices1, indices2, elements1, elements2, strategy);
|
||||
resolvedAst1.node.accept(visitor);
|
||||
return visitor.success;
|
||||
}
|
||||
|
||||
/// Visitor that checks the equivalence of [TreeElements] data.
|
||||
class TreeElementsEquivalenceVisitor extends Visitor {
|
||||
final TestStrategy strategy;
|
||||
final AstIndexComputer indices1;
|
||||
final AstIndexComputer indices2;
|
||||
final TreeElements elements1;
|
||||
final TreeElements elements2;
|
||||
bool success = true;
|
||||
|
||||
TreeElementsEquivalenceVisitor(
|
||||
this.indices1, this.indices2, this.elements1, this.elements2,
|
||||
[this.strategy = const TestStrategy()]);
|
||||
|
||||
visitNode(Node node1) {
|
||||
if (!success) return;
|
||||
int index = indices1.nodeIndices[node1];
|
||||
Node node2 = indices2.nodeList[index];
|
||||
success = strategy.testElements(
|
||||
node1, node2, '[$index]', elements1[node1], elements2[node2]) &&
|
||||
strategy.testTypes(node1, node2, 'getType($index)',
|
||||
elements1.getType(node1), elements2.getType(node2)) &&
|
||||
strategy.test(
|
||||
node1,
|
||||
node2,
|
||||
'getSelector($index)',
|
||||
elements1.getSelector(node1),
|
||||
elements2.getSelector(node2),
|
||||
areSelectorsEquivalent) &&
|
||||
strategy.testConstants(node1, node2, 'getConstant($index)',
|
||||
elements1.getConstant(node1), elements2.getConstant(node2)) &&
|
||||
strategy.testTypes(node1, node2, 'typesCache[$index]',
|
||||
elements1.typesCache[node1], elements2.typesCache[node2]);
|
||||
|
||||
node1.visitChildren(this);
|
||||
}
|
||||
|
||||
@override
|
||||
visitSend(Send node1) {
|
||||
visitExpression(node1);
|
||||
if (!success) return;
|
||||
int index = indices1.nodeIndices[node1];
|
||||
Send node2 = indices2.nodeList[index];
|
||||
success = strategy.test(node1, node2, 'isTypeLiteral($index)',
|
||||
elements1.isTypeLiteral(node1), elements2.isTypeLiteral(node2)) &&
|
||||
strategy.testTypes(
|
||||
node1,
|
||||
node2,
|
||||
'getTypeLiteralType($index)',
|
||||
elements1.getTypeLiteralType(node1),
|
||||
elements2.getTypeLiteralType(node2)) &&
|
||||
strategy.test(
|
||||
node1,
|
||||
node2,
|
||||
'getSendStructure($index)',
|
||||
elements1.getSendStructure(node1),
|
||||
elements2.getSendStructure(node2),
|
||||
areSendStructuresEquivalent);
|
||||
}
|
||||
|
||||
@override
|
||||
visitNewExpression(NewExpression node1) {
|
||||
visitExpression(node1);
|
||||
if (!success) return;
|
||||
int index = indices1.nodeIndices[node1];
|
||||
NewExpression node2 = indices2.nodeList[index];
|
||||
success = strategy.test(
|
||||
node1,
|
||||
node2,
|
||||
'getNewStructure($index)',
|
||||
elements1.getNewStructure(node1),
|
||||
elements2.getNewStructure(node2),
|
||||
areNewStructuresEquivalent);
|
||||
}
|
||||
|
||||
@override
|
||||
visitSendSet(SendSet node1) {
|
||||
visitSend(node1);
|
||||
if (!success) return;
|
||||
int index = indices1.nodeIndices[node1];
|
||||
SendSet node2 = indices2.nodeList[index];
|
||||
success = strategy.test(
|
||||
node1,
|
||||
node2,
|
||||
'getGetterSelectorInComplexSendSet($index)',
|
||||
elements1.getGetterSelectorInComplexSendSet(node1),
|
||||
elements2.getGetterSelectorInComplexSendSet(node2),
|
||||
areSelectorsEquivalent) &&
|
||||
strategy.test(
|
||||
node1,
|
||||
node2,
|
||||
'getOperatorSelectorInComplexSendSet($index)',
|
||||
elements1.getOperatorSelectorInComplexSendSet(node1),
|
||||
elements2.getOperatorSelectorInComplexSendSet(node2),
|
||||
areSelectorsEquivalent);
|
||||
}
|
||||
|
||||
@override
|
||||
visitFunctionExpression(FunctionExpression node1) {
|
||||
visitNode(node1);
|
||||
if (!success) return;
|
||||
int index = indices1.nodeIndices[node1];
|
||||
FunctionExpression node2 = indices2.nodeList[index];
|
||||
if (elements1[node1] is! FunctionElement) {
|
||||
// [getFunctionDefinition] is currently stored in [] which doesn't always
|
||||
// contain a [FunctionElement].
|
||||
return;
|
||||
}
|
||||
success = strategy.testElements(
|
||||
node1,
|
||||
node2,
|
||||
'getFunctionDefinition($index)',
|
||||
elements1.getFunctionDefinition(node1),
|
||||
elements2.getFunctionDefinition(node2));
|
||||
}
|
||||
|
||||
@override
|
||||
visitForIn(ForIn node1) {
|
||||
visitLoop(node1);
|
||||
if (!success) return;
|
||||
int index = indices1.nodeIndices[node1];
|
||||
ForIn node2 = indices2.nodeList[index];
|
||||
success = strategy.testElements(node1, node2, 'getForInVariable($index)',
|
||||
elements1.getForInVariable(node1), elements2.getForInVariable(node2));
|
||||
}
|
||||
|
||||
@override
|
||||
visitRedirectingFactoryBody(RedirectingFactoryBody node1) {
|
||||
visitStatement(node1);
|
||||
if (!success) return;
|
||||
int index = indices1.nodeIndices[node1];
|
||||
RedirectingFactoryBody node2 = indices2.nodeList[index];
|
||||
success = strategy.testElements(
|
||||
node1,
|
||||
node2,
|
||||
'getRedirectingTargetConstructor($index)',
|
||||
elements1.getRedirectingTargetConstructor(node1),
|
||||
elements2.getRedirectingTargetConstructor(node2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
||||
// Copyright (c) 2016, 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.
|
||||
|
||||
@@ -16,6 +16,7 @@ import '../util/enumset.dart';
|
||||
|
||||
import 'keys.dart';
|
||||
import 'serialization.dart';
|
||||
import 'serialization_util.dart';
|
||||
|
||||
/// Visitor that serializes a [ResolutionImpact] object using an
|
||||
/// [ObjectEncoder].
|
||||
@@ -60,18 +61,7 @@ class ImpactSerializer implements WorldImpactVisitor {
|
||||
@override
|
||||
void visitDynamicUse(DynamicUse dynamicUse) {
|
||||
ObjectEncoder object = dynamicUses.createObject();
|
||||
object.setEnum(Key.KIND, dynamicUse.selector.kind);
|
||||
|
||||
object.setInt(
|
||||
Key.ARGUMENTS, dynamicUse.selector.callStructure.argumentCount);
|
||||
object.setStrings(
|
||||
Key.NAMED_ARGUMENTS, dynamicUse.selector.callStructure.namedArguments);
|
||||
|
||||
object.setString(Key.NAME, dynamicUse.selector.memberName.text);
|
||||
object.setBool(Key.IS_SETTER, dynamicUse.selector.memberName.isSetter);
|
||||
if (dynamicUse.selector.memberName.library != null) {
|
||||
object.setElement(Key.LIBRARY, dynamicUse.selector.memberName.library);
|
||||
}
|
||||
serializeSelector(dynamicUse.selector, object);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -136,17 +126,8 @@ class ImpactDeserializer {
|
||||
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 =
|
||||
object.getStrings(Key.NAMED_ARGUMENTS, isOptional: true);
|
||||
String name = object.getString(Key.NAME);
|
||||
bool isSetter = object.getBool(Key.IS_SETTER);
|
||||
LibraryElement library = object.getElement(Key.LIBRARY, isOptional: true);
|
||||
dynamicUses.add(new DynamicUse(
|
||||
new Selector(kind, new Name(name, library, isSetter: isSetter),
|
||||
new CallStructure(argumentCount, namedArguments)),
|
||||
null));
|
||||
Selector selector = deserializeSelector(object);
|
||||
dynamicUses.add(new DynamicUse(selector, null));
|
||||
}
|
||||
|
||||
ListDecoder typeUseDecoder = objectDecoder.getList(Key.TYPE_USES);
|
||||
|
||||
@@ -9,6 +9,7 @@ class Key {
|
||||
static const Key ALIAS = const Key('alias');
|
||||
static const Key ARGUMENTS = const Key('arguments');
|
||||
static const Key BOUND = const Key('bound');
|
||||
static const Key CACHED_TYPE = const Key('cachedType');
|
||||
static const Key CALL_STRUCTURE = const Key('callStructure');
|
||||
static const Key CALL_TYPE = const Key('callType');
|
||||
static const Key CANONICAL_URI = const Key('canonicalUri');
|
||||
@@ -34,6 +35,8 @@ class Key {
|
||||
static const Key FIELD = const Key('field');
|
||||
static const Key FIELDS = const Key('fields');
|
||||
static const Key FUNCTION = const Key('function');
|
||||
static const Key GET_OR_SET = const Key('getOrSet');
|
||||
static const Key GETTER = const Key('getter');
|
||||
static const Key ID = const Key('id');
|
||||
static const Key IMPACTS = const Key('impacts');
|
||||
static const Key IMPORT = const Key('import');
|
||||
@@ -71,6 +74,7 @@ class Key {
|
||||
static const Key NAMED_ARGUMENTS = const Key('named-arguments');
|
||||
static const Key NAMED_PARAMETERS = const Key('named-parameters');
|
||||
static const Key NAMED_PARAMETER_TYPES = const Key('named-parameter-types');
|
||||
static const Key NEW_STRUCTURE = const Key('newStructure');
|
||||
static const Key OFFSET = const Key('offset');
|
||||
static const Key OPERATOR = const Key('operator');
|
||||
static const Key OPTIONAL_PARAMETER_TYPES =
|
||||
@@ -80,7 +84,12 @@ class Key {
|
||||
static const Key PREFIX = const Key('prefix');
|
||||
static const Key RETURN_TYPE = const Key('return-type');
|
||||
static const Key RIGHT = const Key('right');
|
||||
static const Key SELECTOR = const Key('selector');
|
||||
static const Key SEMANTICS = const Key('semantics');
|
||||
static const Key SEND_STRUCTURE = const Key('sendStructure');
|
||||
static const Key SETTER = const Key('setter');
|
||||
static const Key STATIC_USES = const Key('static-uses');
|
||||
static const Key SUB_KIND = const Key('subKind');
|
||||
static const Key SUPERTYPE = const Key('supertype');
|
||||
static const Key SUPERTYPES = const Key('supertypes');
|
||||
static const Key SYMBOLS = const Key('symbols');
|
||||
|
||||
@@ -1306,8 +1306,7 @@ class StaticFieldElementZ extends FieldElementZ
|
||||
|
||||
class EnumConstantElementZ extends StaticFieldElementZ
|
||||
implements EnumConstantElement {
|
||||
EnumConstantElementZ(ObjectDecoder decoder)
|
||||
: super(decoder);
|
||||
EnumConstantElementZ(ObjectDecoder decoder) : super(decoder);
|
||||
|
||||
int get index => _decoder.getInt(Key.INDEX);
|
||||
}
|
||||
@@ -1788,7 +1787,6 @@ class InitializingFormalElementZ extends ParameterElementZ
|
||||
ElementKind get kind => ElementKind.INITIALIZING_FORMAL;
|
||||
}
|
||||
|
||||
|
||||
class LocalVariableElementZ extends DeserializedElementZ
|
||||
with
|
||||
AnalyzableElementMixin,
|
||||
|
||||
@@ -0,0 +1,422 @@
|
||||
// Copyright (c) 2016, 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.
|
||||
|
||||
library dart2js.serialization.resolved_ast;
|
||||
|
||||
import '../common.dart';
|
||||
import '../common/resolution.dart';
|
||||
import '../constants/expressions.dart';
|
||||
import '../dart_types.dart';
|
||||
import '../diagnostics/diagnostic_listener.dart';
|
||||
import '../elements/elements.dart';
|
||||
import '../parser/parser.dart' show Parser;
|
||||
import '../parser/listener.dart' show ParserError;
|
||||
import '../parser/node_listener.dart' show NodeListener;
|
||||
import '../resolution/enum_creator.dart';
|
||||
import '../resolution/send_structure.dart';
|
||||
import '../resolution/tree_elements.dart';
|
||||
import '../tree/tree.dart';
|
||||
import '../tokens/token.dart';
|
||||
import '../universe/selector.dart';
|
||||
import 'keys.dart';
|
||||
import 'serialization.dart';
|
||||
import 'serialization_util.dart';
|
||||
|
||||
/// Visitor that computes a node-index mapping.
|
||||
class AstIndexComputer extends Visitor {
|
||||
final Map<Node, int> nodeIndices = <Node, int>{};
|
||||
final List<Node> nodeList = <Node>[];
|
||||
|
||||
@override
|
||||
visitNode(Node node) {
|
||||
nodeIndices.putIfAbsent(node, () {
|
||||
// Some nodes (like Modifier and empty NodeList) can be reused.
|
||||
nodeList.add(node);
|
||||
return nodeIndices.length;
|
||||
});
|
||||
node.visitChildren(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// The kind of AST node. Used for determining how to deserialize
|
||||
/// [ResolvedAst]s.
|
||||
enum AstKind {
|
||||
ENUM_CONSTRUCTOR,
|
||||
ENUM_CONSTANT,
|
||||
ENUM_INDEX_FIELD,
|
||||
ENUM_VALUES_FIELD,
|
||||
ENUM_TO_STRING,
|
||||
FACTORY,
|
||||
FIELD,
|
||||
FUNCTION,
|
||||
}
|
||||
|
||||
/// Serializer for [ResolvedAst]s.
|
||||
class ResolvedAstSerializer extends Visitor {
|
||||
final ObjectEncoder objectEncoder;
|
||||
final ResolvedAst resolvedAst;
|
||||
final AstIndexComputer indexComputer = new AstIndexComputer();
|
||||
final Map<int, ObjectEncoder> nodeData = <int, ObjectEncoder>{};
|
||||
ListEncoder _nodeDataEncoder;
|
||||
|
||||
ResolvedAstSerializer(this.objectEncoder, this.resolvedAst);
|
||||
|
||||
AstElement get element => resolvedAst.element;
|
||||
|
||||
TreeElements get elements => resolvedAst.elements;
|
||||
|
||||
Node get root => resolvedAst.node;
|
||||
|
||||
Map<Node, int> get nodeIndices => indexComputer.nodeIndices;
|
||||
List<Node> get nodeList => indexComputer.nodeList;
|
||||
|
||||
/// Serializes [resolvedAst] into [objectEncoder].
|
||||
void serialize() {
|
||||
objectEncoder.setUri(
|
||||
Key.URI,
|
||||
elements.analyzedElement.compilationUnit.script.resourceUri,
|
||||
elements.analyzedElement.compilationUnit.script.resourceUri);
|
||||
AstKind kind;
|
||||
if (element.enclosingClass is EnumClassElement) {
|
||||
if (element.name == 'index') {
|
||||
kind = AstKind.ENUM_INDEX_FIELD;
|
||||
} else if (element.name == 'values') {
|
||||
kind = AstKind.ENUM_VALUES_FIELD;
|
||||
} else if (element.name == 'toString') {
|
||||
kind = AstKind.ENUM_TO_STRING;
|
||||
} else if (element.isConstructor) {
|
||||
kind = AstKind.ENUM_CONSTRUCTOR;
|
||||
} else {
|
||||
assert(invariant(element, element.isConst,
|
||||
message: "Unexpected enum member: $element"));
|
||||
kind = AstKind.ENUM_CONSTANT;
|
||||
}
|
||||
} else {
|
||||
// [element] has a body that we'll need to re-parse. We store where to
|
||||
// start parsing from.
|
||||
objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset);
|
||||
if (element.isFactoryConstructor) {
|
||||
kind = AstKind.FACTORY;
|
||||
} else if (element.isField) {
|
||||
kind = AstKind.FIELD;
|
||||
} else {
|
||||
kind = AstKind.FUNCTION;
|
||||
FunctionExpression functionExpression = root.asFunctionExpression();
|
||||
if (functionExpression.getOrSet != null) {
|
||||
// Getters/setters need the get/set token to be parsed.
|
||||
objectEncoder.setInt(
|
||||
Key.GET_OR_SET, functionExpression.getOrSet.charOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
objectEncoder.setEnum(Key.KIND, kind);
|
||||
root.accept(indexComputer);
|
||||
root.accept(this);
|
||||
}
|
||||
|
||||
/// Computes the [ListEncoder] for serializing data for nodes.
|
||||
ListEncoder get nodeDataEncoder {
|
||||
if (_nodeDataEncoder == null) {
|
||||
_nodeDataEncoder = objectEncoder.createList(Key.DATA);
|
||||
}
|
||||
return _nodeDataEncoder;
|
||||
}
|
||||
|
||||
/// Computes the [ObjectEncoder] for serializing data for [node].
|
||||
ObjectEncoder getNodeDataEncoder(Node node) {
|
||||
int id = nodeIndices[node];
|
||||
return nodeData.putIfAbsent(id, () {
|
||||
ObjectEncoder objectEncoder = nodeDataEncoder.createObject();
|
||||
objectEncoder.setInt(Key.ID, id);
|
||||
return objectEncoder;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
visitNode(Node node) {
|
||||
Element nodeElement = elements[node];
|
||||
if (nodeElement != null) {
|
||||
if (nodeElement.enclosingClass != null &&
|
||||
nodeElement.enclosingClass.isUnnamedMixinApplication) {
|
||||
// TODO(johnniwinther): Handle references to members of unnamed mixin
|
||||
// applications.
|
||||
} else {
|
||||
getNodeDataEncoder(node).setElement(Key.ELEMENT, nodeElement);
|
||||
}
|
||||
}
|
||||
DartType type = elements.getType(node);
|
||||
if (type != null) {
|
||||
getNodeDataEncoder(node).setType(Key.TYPE, type);
|
||||
}
|
||||
Selector selector = elements.getSelector(node);
|
||||
if (selector != null) {
|
||||
serializeSelector(
|
||||
selector, getNodeDataEncoder(node).createObject(Key.SELECTOR));
|
||||
}
|
||||
ConstantExpression constant = elements.getConstant(node);
|
||||
if (constant != null) {
|
||||
getNodeDataEncoder(node).setConstant(Key.CONSTANT, constant);
|
||||
}
|
||||
DartType cachedType = elements.typesCache[node];
|
||||
if (cachedType != null) {
|
||||
getNodeDataEncoder(node).setType(Key.CACHED_TYPE, cachedType);
|
||||
}
|
||||
// TODO(johnniwinther): Serialize [JumpTarget]s.
|
||||
node.visitChildren(this);
|
||||
}
|
||||
|
||||
@override
|
||||
visitSend(Send node) {
|
||||
visitExpression(node);
|
||||
SendStructure structure = elements.getSendStructure(node);
|
||||
if (structure != null) {
|
||||
serializeSendStructure(
|
||||
structure, getNodeDataEncoder(node).createObject(Key.SEND_STRUCTURE));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitNewExpression(NewExpression node) {
|
||||
visitExpression(node);
|
||||
NewStructure structure = elements.getNewStructure(node);
|
||||
if (structure != null) {
|
||||
serializeNewStructure(
|
||||
structure, getNodeDataEncoder(node).createObject(Key.NEW_STRUCTURE));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
visitGotoStatement(GotoStatement node) {
|
||||
visitStatement(node);
|
||||
// TODO(johnniwinther): Serialize [JumpTarget]s and [LabelDefinition]s.
|
||||
}
|
||||
|
||||
@override
|
||||
visitLabel(Label node) {
|
||||
visitNode(node);
|
||||
// TODO(johnniwinther): Serialize[LabelDefinition]s.
|
||||
}
|
||||
}
|
||||
|
||||
class ResolvedAstDeserializer {
|
||||
/// Find the [Token] at [offset] searching through successors of [token].
|
||||
static Token findTokenInStream(Token token, int offset) {
|
||||
while (token.charOffset <= offset && token.next != token) {
|
||||
if (token.charOffset == offset) {
|
||||
return token;
|
||||
}
|
||||
token = token.next;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Deserializes the [ResolvedAst] for [element] from [objectDecoder].
|
||||
/// [parsing] and [getBeginToken] are used for parsing the [Node] for
|
||||
/// [element] from its source code.
|
||||
static ResolvedAst deserialize(Element element, ObjectDecoder objectDecoder,
|
||||
Parsing parsing, Token getBeginToken(Uri uri, int charOffset)) {
|
||||
CompilationUnitElement compilationUnit = element.compilationUnit;
|
||||
DiagnosticReporter reporter = parsing.reporter;
|
||||
|
||||
/// Returns the first [Token] for parsing the [Node] for [element].
|
||||
Token readBeginToken() {
|
||||
Uri uri = objectDecoder.getUri(Key.URI);
|
||||
int charOffset = objectDecoder.getInt(Key.OFFSET);
|
||||
Token beginToken = getBeginToken(uri, charOffset);
|
||||
if (beginToken == null) {
|
||||
reporter.internalError(
|
||||
element, "No token found for $element in $uri @ $charOffset");
|
||||
}
|
||||
return beginToken;
|
||||
}
|
||||
|
||||
/// Create the [Node] for the element by parsing the source code.
|
||||
Node doParse(parse(Parser parser)) {
|
||||
return parsing.measure(() {
|
||||
return reporter.withCurrentElement(element, () {
|
||||
CompilationUnitElement unit = element.compilationUnit;
|
||||
NodeListener listener = new NodeListener(
|
||||
parsing.getScannerOptionsFor(element), reporter, null);
|
||||
listener.memberErrors = listener.memberErrors.prepend(false);
|
||||
try {
|
||||
Parser parser = new Parser(listener, parsing.parserOptions);
|
||||
parse(parser);
|
||||
} on ParserError catch (e) {
|
||||
reporter.internalError(element, '$e');
|
||||
}
|
||||
return listener.popNode();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/// Computes the [Node] for the element based on the [AstKind].
|
||||
Node computeNode(AstKind kind) {
|
||||
switch (kind) {
|
||||
case AstKind.ENUM_INDEX_FIELD:
|
||||
AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
|
||||
Identifier identifier = builder.identifier('index');
|
||||
VariableDefinitions node = new VariableDefinitions(
|
||||
null,
|
||||
builder.modifiers(isFinal: true),
|
||||
new NodeList.singleton(identifier));
|
||||
return node;
|
||||
case AstKind.ENUM_VALUES_FIELD:
|
||||
EnumClassElement enumClass = element.enclosingClass;
|
||||
AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
|
||||
List<FieldElement> enumValues = <FieldElement>[];
|
||||
List<Node> valueReferences = <Node>[];
|
||||
for (EnumConstantElement enumConstant in enumClass.enumValues) {
|
||||
AstBuilder valueBuilder =
|
||||
new AstBuilder(enumConstant.sourcePosition.begin);
|
||||
Identifier name = valueBuilder.identifier(enumConstant.name);
|
||||
|
||||
// Add reference for the `values` field.
|
||||
valueReferences.add(valueBuilder.reference(name));
|
||||
}
|
||||
|
||||
Identifier valuesIdentifier = builder.identifier('values');
|
||||
// TODO(johnniwinther): Add type argument.
|
||||
Expression initializer =
|
||||
builder.listLiteral(valueReferences, isConst: true);
|
||||
|
||||
Node definition =
|
||||
builder.createDefinition(valuesIdentifier, initializer);
|
||||
VariableDefinitions node = new VariableDefinitions(
|
||||
null,
|
||||
builder.modifiers(isStatic: true, isConst: true),
|
||||
new NodeList.singleton(definition));
|
||||
return node;
|
||||
case AstKind.ENUM_TO_STRING:
|
||||
EnumClassElement enumClass = element.enclosingClass;
|
||||
AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
|
||||
List<LiteralMapEntry> mapEntries = <LiteralMapEntry>[];
|
||||
for (EnumConstantElement enumConstant in enumClass.enumValues) {
|
||||
AstBuilder valueBuilder =
|
||||
new AstBuilder(enumConstant.sourcePosition.begin);
|
||||
Identifier name = valueBuilder.identifier(enumConstant.name);
|
||||
|
||||
// Add map entry for `toString` implementation.
|
||||
mapEntries.add(valueBuilder.mapLiteralEntry(
|
||||
valueBuilder.literalInt(enumConstant.index),
|
||||
valueBuilder
|
||||
.literalString('${enumClass.name}.${name.source}')));
|
||||
}
|
||||
|
||||
// TODO(johnniwinther): Support return type. Note `String` might be
|
||||
// prefixed or not imported within the current library.
|
||||
FunctionExpression toStringNode = builder.functionExpression(
|
||||
Modifiers.EMPTY,
|
||||
'toString',
|
||||
builder.argumentList([]),
|
||||
builder.returnStatement(builder.indexGet(
|
||||
builder.mapLiteral(mapEntries, isConst: true),
|
||||
builder.reference(builder.identifier('index')))));
|
||||
return toStringNode;
|
||||
case AstKind.ENUM_CONSTRUCTOR:
|
||||
AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
|
||||
VariableDefinitions indexDefinition =
|
||||
builder.initializingFormal('index');
|
||||
FunctionExpression constructorNode = builder.functionExpression(
|
||||
builder.modifiers(isConst: true),
|
||||
element.enclosingClass.name,
|
||||
builder.argumentList([indexDefinition]),
|
||||
builder.emptyStatement());
|
||||
return constructorNode;
|
||||
case AstKind.ENUM_CONSTANT:
|
||||
EnumConstantElement enumConstant = element;
|
||||
EnumClassElement enumClass = element.enclosingClass;
|
||||
int index = enumConstant.index;
|
||||
AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
|
||||
Identifier name = builder.identifier(element.name);
|
||||
|
||||
Expression initializer = builder.newExpression(
|
||||
enumClass.name, builder.argumentList([builder.literalInt(index)]),
|
||||
isConst: true);
|
||||
SendSet definition = builder.createDefinition(name, initializer);
|
||||
|
||||
VariableDefinitions node = new VariableDefinitions(
|
||||
null,
|
||||
builder.modifiers(isStatic: true, isConst: true),
|
||||
new NodeList.singleton(definition));
|
||||
return node;
|
||||
case AstKind.FACTORY:
|
||||
Token beginToken = readBeginToken();
|
||||
return doParse((parser) => parser.parseFactoryMethod(beginToken));
|
||||
case AstKind.FIELD:
|
||||
Token beginToken = readBeginToken();
|
||||
return doParse((parser) => parser.parseMember(beginToken));
|
||||
case AstKind.FUNCTION:
|
||||
Token beginToken = readBeginToken();
|
||||
int getOrSetOffset =
|
||||
objectDecoder.getInt(Key.GET_OR_SET, isOptional: true);
|
||||
Token getOrSet;
|
||||
if (getOrSetOffset != null) {
|
||||
getOrSet = findTokenInStream(beginToken, getOrSetOffset);
|
||||
if (getOrSet == null) {
|
||||
reporter.internalError(
|
||||
element,
|
||||
"No token found for $element in "
|
||||
"${objectDecoder.getUri(Key.URI)} @ $getOrSetOffset");
|
||||
}
|
||||
}
|
||||
return doParse((parser) {
|
||||
parser.parseFunction(beginToken, getOrSet);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
AstKind kind = objectDecoder.getEnum(Key.KIND, AstKind.values);
|
||||
Node root = computeNode(kind);
|
||||
TreeElementMapping elements = new TreeElementMapping(element);
|
||||
AstIndexComputer indexComputer = new AstIndexComputer();
|
||||
Map<Node, int> nodeIndices = indexComputer.nodeIndices;
|
||||
List<Node> nodeList = indexComputer.nodeList;
|
||||
root.accept(indexComputer);
|
||||
ListDecoder dataDecoder = objectDecoder.getList(Key.DATA);
|
||||
if (dataDecoder != null) {
|
||||
for (int i = 0; i < dataDecoder.length; i++) {
|
||||
ObjectDecoder objectDecoder = dataDecoder.getObject(i);
|
||||
int id = objectDecoder.getInt(Key.ID);
|
||||
Node node = nodeList[id];
|
||||
Element nodeElement =
|
||||
objectDecoder.getElement(Key.ELEMENT, isOptional: true);
|
||||
if (nodeElement != null) {
|
||||
elements[node] = nodeElement;
|
||||
}
|
||||
DartType type = objectDecoder.getType(Key.TYPE, isOptional: true);
|
||||
if (type != null) {
|
||||
elements.setType(node, type);
|
||||
}
|
||||
ObjectDecoder selectorDecoder =
|
||||
objectDecoder.getObject(Key.SELECTOR, isOptional: true);
|
||||
if (selectorDecoder != null) {
|
||||
elements.setSelector(node, deserializeSelector(selectorDecoder));
|
||||
}
|
||||
ConstantExpression constant =
|
||||
objectDecoder.getConstant(Key.CONSTANT, isOptional: true);
|
||||
if (constant != null) {
|
||||
elements.setConstant(node, constant);
|
||||
}
|
||||
DartType cachedType =
|
||||
objectDecoder.getType(Key.CACHED_TYPE, isOptional: true);
|
||||
if (cachedType != null) {
|
||||
elements.typesCache[node] = cachedType;
|
||||
}
|
||||
ObjectDecoder sendStructureDecoder =
|
||||
objectDecoder.getObject(Key.SEND_STRUCTURE, isOptional: true);
|
||||
if (sendStructureDecoder != null) {
|
||||
elements.setSendStructure(
|
||||
node, deserializeSendStructure(sendStructureDecoder));
|
||||
}
|
||||
ObjectDecoder newStructureDecoder =
|
||||
objectDecoder.getObject(Key.NEW_STRUCTURE, isOptional: true);
|
||||
if (newStructureDecoder != null) {
|
||||
elements.setNewStructure(
|
||||
node, deserializeNewStructure(newStructureDecoder));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ResolvedAst(element, root, elements);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,481 @@
|
||||
// Copyright (c) 2016, 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.
|
||||
|
||||
library dart2js.serialization.util;
|
||||
|
||||
import '../dart_types.dart';
|
||||
import '../common/resolution.dart';
|
||||
import '../constants/expressions.dart';
|
||||
import '../elements/elements.dart';
|
||||
import '../resolution/access_semantics.dart';
|
||||
import '../resolution/operators.dart';
|
||||
import '../resolution/send_structure.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';
|
||||
|
||||
/// Serialize [name] into [encoder].
|
||||
void serializeName(Name name, ObjectEncoder encoder) {
|
||||
encoder.setString(Key.NAME, name.text);
|
||||
encoder.setBool(Key.IS_SETTER, name.isSetter);
|
||||
if (name.library != null) {
|
||||
encoder.setElement(Key.LIBRARY, name.library);
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize a [Name] from [decoder].
|
||||
Name deserializeName(ObjectDecoder decoder) {
|
||||
String name = decoder.getString(Key.NAME);
|
||||
bool isSetter = decoder.getBool(Key.IS_SETTER);
|
||||
LibraryElement library = decoder.getElement(Key.LIBRARY, isOptional: true);
|
||||
return new Name(name, library, isSetter: isSetter);
|
||||
}
|
||||
|
||||
/// Serialize [selector] into [encoder].
|
||||
void serializeSelector(Selector selector, ObjectEncoder encoder) {
|
||||
encoder.setEnum(Key.KIND, selector.kind);
|
||||
|
||||
encoder.setInt(Key.ARGUMENTS, selector.callStructure.argumentCount);
|
||||
encoder.setStrings(
|
||||
Key.NAMED_ARGUMENTS, selector.callStructure.namedArguments);
|
||||
serializeName(selector.memberName, encoder);
|
||||
}
|
||||
|
||||
/// Deserialize a [Selector] from [decoder].
|
||||
Selector deserializeSelector(ObjectDecoder decoder) {
|
||||
SelectorKind kind = decoder.getEnum(Key.KIND, SelectorKind.values);
|
||||
int argumentCount = decoder.getInt(Key.ARGUMENTS);
|
||||
List<String> namedArguments =
|
||||
decoder.getStrings(Key.NAMED_ARGUMENTS, isOptional: true);
|
||||
String name = decoder.getString(Key.NAME);
|
||||
bool isSetter = decoder.getBool(Key.IS_SETTER);
|
||||
LibraryElement library = decoder.getElement(Key.LIBRARY, isOptional: true);
|
||||
return new Selector(kind, deserializeName(decoder),
|
||||
new CallStructure(argumentCount, namedArguments));
|
||||
}
|
||||
|
||||
/// Serialize [sendStructure] into [encoder].
|
||||
void serializeSendStructure(
|
||||
SendStructure sendStructure, ObjectEncoder encoder) {
|
||||
encoder.setEnum(Key.KIND, sendStructure.kind);
|
||||
switch (sendStructure.kind) {
|
||||
case SendStructureKind.IF_NULL:
|
||||
case SendStructureKind.LOGICAL_AND:
|
||||
case SendStructureKind.LOGICAL_OR:
|
||||
case SendStructureKind.NOT:
|
||||
case SendStructureKind.INVALID_UNARY:
|
||||
case SendStructureKind.INVALID_BINARY:
|
||||
// No additional properties.
|
||||
break;
|
||||
case SendStructureKind.IS:
|
||||
IsStructure structure = sendStructure;
|
||||
encoder.setType(Key.TYPE, structure.type);
|
||||
break;
|
||||
case SendStructureKind.IS_NOT:
|
||||
IsNotStructure structure = sendStructure;
|
||||
encoder.setType(Key.TYPE, structure.type);
|
||||
break;
|
||||
case SendStructureKind.AS:
|
||||
AsStructure structure = sendStructure;
|
||||
encoder.setType(Key.TYPE, structure.type);
|
||||
break;
|
||||
case SendStructureKind.INVOKE:
|
||||
InvokeStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
serializeSelector(structure.selector, encoder.createObject(Key.SELECTOR));
|
||||
break;
|
||||
case SendStructureKind.INCOMPATIBLE_INVOKE:
|
||||
IncompatibleInvokeStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
serializeSelector(structure.selector, encoder.createObject(Key.SELECTOR));
|
||||
break;
|
||||
case SendStructureKind.GET:
|
||||
GetStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
break;
|
||||
case SendStructureKind.SET:
|
||||
SetStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
break;
|
||||
case SendStructureKind.UNARY:
|
||||
UnaryStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
|
||||
break;
|
||||
case SendStructureKind.INDEX:
|
||||
IndexStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
break;
|
||||
case SendStructureKind.EQUALS:
|
||||
EqualsStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
break;
|
||||
case SendStructureKind.NOT_EQUALS:
|
||||
NotEqualsStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
break;
|
||||
case SendStructureKind.BINARY:
|
||||
BinaryStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
|
||||
break;
|
||||
case SendStructureKind.INDEX_SET:
|
||||
IndexSetStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
break;
|
||||
case SendStructureKind.INDEX_PREFIX:
|
||||
IndexPrefixStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
|
||||
break;
|
||||
case SendStructureKind.INDEX_POSTFIX:
|
||||
IndexPostfixStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
|
||||
break;
|
||||
case SendStructureKind.COMPOUND:
|
||||
CompoundStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
|
||||
break;
|
||||
case SendStructureKind.SET_IF_NULL:
|
||||
SetIfNullStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
break;
|
||||
case SendStructureKind.COMPOUND_INDEX_SET:
|
||||
CompoundIndexSetStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
|
||||
break;
|
||||
case SendStructureKind.INDEX_SET_IF_NULL:
|
||||
IndexSetIfNullStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
break;
|
||||
case SendStructureKind.PREFIX:
|
||||
PrefixStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
|
||||
break;
|
||||
case SendStructureKind.POSTFIX:
|
||||
PostfixStructure structure = sendStructure;
|
||||
serializeAccessSemantics(
|
||||
structure.semantics, encoder.createObject(Key.SEMANTICS));
|
||||
encoder.setEnum(Key.OPERATOR, structure.operator.kind);
|
||||
break;
|
||||
case SendStructureKind.DEFERRED_PREFIX:
|
||||
DeferredPrefixStructure structure = sendStructure;
|
||||
encoder.setElement(Key.PREFIX, structure.prefix);
|
||||
serializeSendStructure(
|
||||
structure.sendStructure, encoder.createObject(Key.SEND_STRUCTURE));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize a [SendStructure] from [decoder].
|
||||
SendStructure deserializeSendStructure(ObjectDecoder decoder) {
|
||||
SendStructureKind kind = decoder.getEnum(Key.KIND, SendStructureKind.values);
|
||||
switch (kind) {
|
||||
case SendStructureKind.IF_NULL:
|
||||
return const IfNullStructure();
|
||||
case SendStructureKind.LOGICAL_AND:
|
||||
return const LogicalAndStructure();
|
||||
case SendStructureKind.LOGICAL_OR:
|
||||
return const LogicalOrStructure();
|
||||
case SendStructureKind.IS:
|
||||
return new IsStructure(decoder.getType(Key.TYPE));
|
||||
case SendStructureKind.IS_NOT:
|
||||
return new IsNotStructure(decoder.getType(Key.TYPE));
|
||||
case SendStructureKind.AS:
|
||||
return new AsStructure(decoder.getType(Key.TYPE));
|
||||
case SendStructureKind.INVOKE:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
Selector selector = deserializeSelector(decoder.getObject(Key.SELECTOR));
|
||||
return new InvokeStructure(semantics, selector);
|
||||
case SendStructureKind.INCOMPATIBLE_INVOKE:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
Selector selector = deserializeSelector(decoder.getObject(Key.SELECTOR));
|
||||
return new IncompatibleInvokeStructure(semantics, selector);
|
||||
case SendStructureKind.GET:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new GetStructure(semantics);
|
||||
case SendStructureKind.SET:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new SetStructure(semantics);
|
||||
case SendStructureKind.NOT:
|
||||
return const NotStructure();
|
||||
case SendStructureKind.UNARY:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new UnaryStructure(
|
||||
semantics,
|
||||
UnaryOperator.fromKind(
|
||||
decoder.getEnum(Key.OPERATOR, UnaryOperatorKind.values)));
|
||||
case SendStructureKind.INVALID_UNARY:
|
||||
return new InvalidUnaryStructure();
|
||||
case SendStructureKind.INDEX:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new IndexStructure(semantics);
|
||||
case SendStructureKind.EQUALS:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new EqualsStructure(semantics);
|
||||
case SendStructureKind.NOT_EQUALS:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new NotEqualsStructure(semantics);
|
||||
case SendStructureKind.BINARY:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new BinaryStructure(
|
||||
semantics,
|
||||
BinaryOperator.fromKind(
|
||||
decoder.getEnum(Key.OPERATOR, BinaryOperatorKind.values)));
|
||||
case SendStructureKind.INVALID_BINARY:
|
||||
return const InvalidBinaryStructure();
|
||||
case SendStructureKind.INDEX_SET:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new IndexSetStructure(semantics);
|
||||
case SendStructureKind.INDEX_PREFIX:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new IndexPrefixStructure(
|
||||
semantics,
|
||||
IncDecOperator.fromKind(
|
||||
decoder.getEnum(Key.OPERATOR, IncDecOperatorKind.values)));
|
||||
case SendStructureKind.INDEX_POSTFIX:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new IndexPostfixStructure(
|
||||
semantics,
|
||||
IncDecOperator.fromKind(
|
||||
decoder.getEnum(Key.OPERATOR, IncDecOperatorKind.values)));
|
||||
case SendStructureKind.COMPOUND:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new CompoundStructure(
|
||||
semantics,
|
||||
AssignmentOperator.fromKind(
|
||||
decoder.getEnum(Key.OPERATOR, AssignmentOperatorKind.values)));
|
||||
case SendStructureKind.SET_IF_NULL:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new SetIfNullStructure(semantics);
|
||||
case SendStructureKind.COMPOUND_INDEX_SET:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new CompoundIndexSetStructure(
|
||||
semantics,
|
||||
AssignmentOperator.fromKind(
|
||||
decoder.getEnum(Key.OPERATOR, AssignmentOperatorKind.values)));
|
||||
case SendStructureKind.INDEX_SET_IF_NULL:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new IndexSetIfNullStructure(semantics);
|
||||
case SendStructureKind.PREFIX:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new PrefixStructure(
|
||||
semantics,
|
||||
IncDecOperator.fromKind(
|
||||
decoder.getEnum(Key.OPERATOR, IncDecOperatorKind.values)));
|
||||
case SendStructureKind.POSTFIX:
|
||||
AccessSemantics semantics =
|
||||
deserializeAccessSemantics(decoder.getObject(Key.SEMANTICS));
|
||||
return new PostfixStructure(
|
||||
semantics,
|
||||
IncDecOperator.fromKind(
|
||||
decoder.getEnum(Key.OPERATOR, IncDecOperatorKind.values)));
|
||||
case SendStructureKind.DEFERRED_PREFIX:
|
||||
PrefixElement prefix = decoder.getElement(Key.PREFIX);
|
||||
SendStructure sendStructure =
|
||||
deserializeSendStructure(decoder.getObject(Key.SEND_STRUCTURE));
|
||||
return new DeferredPrefixStructure(prefix, sendStructure);
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize [newStructure] into [encoder].
|
||||
void serializeNewStructure(NewStructure newStructure, ObjectEncoder encoder) {
|
||||
encoder.setEnum(Key.KIND, newStructure.kind);
|
||||
switch (newStructure.kind) {
|
||||
case NewStructureKind.NEW_INVOKE:
|
||||
NewInvokeStructure structure = newStructure;
|
||||
encoder.setEnum(Key.SUB_KIND, structure.semantics.kind);
|
||||
encoder.setElement(Key.ELEMENT, structure.semantics.element);
|
||||
encoder.setType(Key.TYPE, structure.semantics.type);
|
||||
serializeSelector(structure.selector, encoder.createObject(Key.SELECTOR));
|
||||
break;
|
||||
case NewStructureKind.CONST_INVOKE:
|
||||
ConstInvokeStructure structure = newStructure;
|
||||
encoder.setEnum(Key.SUB_KIND, structure.constantInvokeKind);
|
||||
encoder.setConstant(Key.CONSTANT, structure.constant);
|
||||
break;
|
||||
case NewStructureKind.LATE_CONST:
|
||||
throw new UnsupportedError(
|
||||
'Unsupported NewStructure kind ${newStructure.kind}.');
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize a [NewStructure] from [decoder].
|
||||
NewStructure deserializeNewStructure(ObjectDecoder decoder) {
|
||||
NewStructureKind kind = decoder.getEnum(Key.KIND, NewStructureKind.values);
|
||||
switch (kind) {
|
||||
case NewStructureKind.NEW_INVOKE:
|
||||
ConstructorAccessKind constructorAccessKind =
|
||||
decoder.getEnum(Key.SUB_KIND, ConstructorAccessKind.values);
|
||||
Element element = decoder.getElement(Key.ELEMENT);
|
||||
DartType type = decoder.getType(Key.TYPE);
|
||||
ConstructorAccessSemantics semantics =
|
||||
new ConstructorAccessSemantics(constructorAccessKind, element, type);
|
||||
Selector selector = deserializeSelector(decoder.getObject(Key.SELECTOR));
|
||||
return new NewInvokeStructure(semantics, selector);
|
||||
|
||||
case NewStructureKind.CONST_INVOKE:
|
||||
ConstantInvokeKind constantInvokeKind =
|
||||
decoder.getEnum(Key.SUB_KIND, ConstantInvokeKind.values);
|
||||
ConstantExpression constant = decoder.getConstant(Key.CONSTANT);
|
||||
return new ConstInvokeStructure(constantInvokeKind, constant);
|
||||
case NewStructureKind.LATE_CONST:
|
||||
throw new UnsupportedError('Unsupported NewStructure kind $kind.');
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize [semantics] into [encoder].
|
||||
void serializeAccessSemantics(
|
||||
AccessSemantics semantics, ObjectEncoder encoder) {
|
||||
encoder.setEnum(Key.KIND, semantics.kind);
|
||||
switch (semantics.kind) {
|
||||
case AccessKind.EXPRESSION:
|
||||
case AccessKind.THIS:
|
||||
// No additional properties.
|
||||
break;
|
||||
case AccessKind.THIS_PROPERTY:
|
||||
case AccessKind.DYNAMIC_PROPERTY:
|
||||
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
|
||||
serializeName(semantics.name, encoder);
|
||||
break;
|
||||
case AccessKind.CLASS_TYPE_LITERAL:
|
||||
case AccessKind.TYPEDEF_TYPE_LITERAL:
|
||||
case AccessKind.DYNAMIC_TYPE_LITERAL:
|
||||
encoder.setConstant(Key.CONSTANT, semantics.constant);
|
||||
break;
|
||||
case AccessKind.LOCAL_FUNCTION:
|
||||
case AccessKind.LOCAL_VARIABLE:
|
||||
case AccessKind.FINAL_LOCAL_VARIABLE:
|
||||
case AccessKind.PARAMETER:
|
||||
case AccessKind.FINAL_PARAMETER:
|
||||
case AccessKind.STATIC_FIELD:
|
||||
case AccessKind.FINAL_STATIC_FIELD:
|
||||
case AccessKind.STATIC_METHOD:
|
||||
case AccessKind.STATIC_GETTER:
|
||||
case AccessKind.STATIC_SETTER:
|
||||
case AccessKind.TOPLEVEL_FIELD:
|
||||
case AccessKind.FINAL_TOPLEVEL_FIELD:
|
||||
case AccessKind.TOPLEVEL_METHOD:
|
||||
case AccessKind.TOPLEVEL_GETTER:
|
||||
case AccessKind.TOPLEVEL_SETTER:
|
||||
case AccessKind.SUPER_FIELD:
|
||||
case AccessKind.SUPER_FINAL_FIELD:
|
||||
case AccessKind.SUPER_METHOD:
|
||||
case AccessKind.SUPER_GETTER:
|
||||
case AccessKind.SUPER_SETTER:
|
||||
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
|
||||
case AccessKind.UNRESOLVED:
|
||||
case AccessKind.UNRESOLVED_SUPER:
|
||||
case AccessKind.INVALID:
|
||||
encoder.setElement(Key.ELEMENT, semantics.element);
|
||||
break;
|
||||
case AccessKind.COMPOUND:
|
||||
CompoundAccessSemantics compoundAccess = semantics;
|
||||
encoder.setEnum(Key.SUB_KIND, compoundAccess.compoundAccessKind);
|
||||
encoder.setElement(Key.GETTER, semantics.getter);
|
||||
encoder.setElement(Key.SETTER, semantics.setter);
|
||||
break;
|
||||
case AccessKind.CONSTANT:
|
||||
throw new UnsupportedError('Unsupported access kind: ${semantics.kind}');
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize a [AccessSemantics] from [decoder].
|
||||
AccessSemantics deserializeAccessSemantics(ObjectDecoder decoder) {
|
||||
AccessKind kind = decoder.getEnum(Key.KIND, AccessKind.values);
|
||||
switch (kind) {
|
||||
case AccessKind.EXPRESSION:
|
||||
return const DynamicAccess.expression();
|
||||
case AccessKind.THIS:
|
||||
return const DynamicAccess.thisAccess();
|
||||
case AccessKind.THIS_PROPERTY:
|
||||
return new DynamicAccess.thisProperty(deserializeName(decoder));
|
||||
case AccessKind.DYNAMIC_PROPERTY:
|
||||
return new DynamicAccess.dynamicProperty(deserializeName(decoder));
|
||||
case AccessKind.CONDITIONAL_DYNAMIC_PROPERTY:
|
||||
return new DynamicAccess.ifNotNullProperty(deserializeName(decoder));
|
||||
case AccessKind.CLASS_TYPE_LITERAL:
|
||||
case AccessKind.TYPEDEF_TYPE_LITERAL:
|
||||
case AccessKind.DYNAMIC_TYPE_LITERAL:
|
||||
return new ConstantAccess(kind, decoder.getConstant(Key.CONSTANT));
|
||||
|
||||
case AccessKind.LOCAL_FUNCTION:
|
||||
case AccessKind.LOCAL_VARIABLE:
|
||||
case AccessKind.FINAL_LOCAL_VARIABLE:
|
||||
case AccessKind.PARAMETER:
|
||||
case AccessKind.FINAL_PARAMETER:
|
||||
case AccessKind.STATIC_FIELD:
|
||||
case AccessKind.FINAL_STATIC_FIELD:
|
||||
case AccessKind.STATIC_METHOD:
|
||||
case AccessKind.STATIC_GETTER:
|
||||
case AccessKind.STATIC_SETTER:
|
||||
case AccessKind.TOPLEVEL_FIELD:
|
||||
case AccessKind.FINAL_TOPLEVEL_FIELD:
|
||||
case AccessKind.TOPLEVEL_METHOD:
|
||||
case AccessKind.TOPLEVEL_GETTER:
|
||||
case AccessKind.TOPLEVEL_SETTER:
|
||||
case AccessKind.SUPER_FIELD:
|
||||
case AccessKind.SUPER_FINAL_FIELD:
|
||||
case AccessKind.SUPER_METHOD:
|
||||
case AccessKind.SUPER_GETTER:
|
||||
case AccessKind.SUPER_SETTER:
|
||||
case AccessKind.TYPE_PARAMETER_TYPE_LITERAL:
|
||||
case AccessKind.UNRESOLVED:
|
||||
case AccessKind.UNRESOLVED_SUPER:
|
||||
case AccessKind.INVALID:
|
||||
return new StaticAccess.internal(kind, decoder.getElement(Key.ELEMENT));
|
||||
|
||||
case AccessKind.COMPOUND:
|
||||
CompoundAccessKind compoundAccessKind =
|
||||
decoder.getEnum(Key.SUB_KIND, CompoundAccessKind.values);
|
||||
Element getter = decoder.getElement(Key.GETTER);
|
||||
Element setter = decoder.getElement(Key.SETTER);
|
||||
return new CompoundAccessSemantics(compoundAccessKind, getter, setter);
|
||||
case AccessKind.CONSTANT:
|
||||
throw new UnsupportedError('Unsupported access kind: $kind');
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
library dart2js.serialization.task;
|
||||
|
||||
import 'dart:async' show Future;
|
||||
import '../common/resolution.dart' show ResolutionImpact, ResolutionWorkItem;
|
||||
import '../common/tasks.dart' show CompilerTask;
|
||||
import '../common/work.dart' show ItemCompilationContext;
|
||||
@@ -17,7 +18,7 @@ import '../universe/world_impact.dart' show WorldImpact;
|
||||
abstract class LibraryDeserializer {
|
||||
/// Loads the [LibraryElement] associated with a library under [uri], or null
|
||||
/// if no serialized information is available for the given library.
|
||||
LibraryElement readLibrary(Uri uri);
|
||||
Future<LibraryElement> readLibrary(Uri uri);
|
||||
}
|
||||
|
||||
/// Task that supports deserialization of elements.
|
||||
@@ -35,8 +36,8 @@ class SerializationTask extends CompilerTask implements LibraryDeserializer {
|
||||
|
||||
/// Returns the [LibraryElement] for [resolvedUri] if available from
|
||||
/// serialization.
|
||||
LibraryElement readLibrary(Uri resolvedUri) {
|
||||
if (deserializer == null) return null;
|
||||
Future<LibraryElement> readLibrary(Uri resolvedUri) {
|
||||
if (deserializer == null) return new Future<LibraryElement>.value();
|
||||
return deserializer.readLibrary(resolvedUri);
|
||||
}
|
||||
|
||||
@@ -81,8 +82,9 @@ class DeserializedResolutionWorkItem implements ResolutionWorkItem {
|
||||
/// The interface for a system that supports deserialization of libraries and
|
||||
/// elements.
|
||||
abstract class DeserializerSystem {
|
||||
LibraryElement readLibrary(Uri resolvedUri);
|
||||
Future<LibraryElement> readLibrary(Uri resolvedUri);
|
||||
bool isDeserialized(Element element);
|
||||
ResolvedAst getResolvedAst(Element element);
|
||||
ResolutionImpact getResolutionImpact(Element element);
|
||||
WorldImpact computeWorldImpact(Element element);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ library dart2js.serialization_helper;
|
||||
import 'dart:async';
|
||||
import 'package:async_helper/async_helper.dart';
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:compiler/compiler_new.dart';
|
||||
import 'package:compiler/src/commandline_options.dart';
|
||||
import 'package:compiler/src/common/backend_api.dart';
|
||||
import 'package:compiler/src/common/names.dart';
|
||||
@@ -14,30 +15,46 @@ import 'package:compiler/src/common/resolution.dart';
|
||||
import 'package:compiler/src/compiler.dart';
|
||||
import 'package:compiler/src/elements/elements.dart';
|
||||
import 'package:compiler/src/filenames.dart';
|
||||
import 'package:compiler/src/io/source_file.dart';
|
||||
import 'package:compiler/src/scanner/scanner.dart';
|
||||
import 'package:compiler/src/serialization/element_serialization.dart';
|
||||
import 'package:compiler/src/serialization/impact_serialization.dart';
|
||||
import 'package:compiler/src/serialization/json_serializer.dart';
|
||||
import 'package:compiler/src/serialization/resolved_ast_serialization.dart';
|
||||
import 'package:compiler/src/serialization/serialization.dart';
|
||||
import 'package:compiler/src/serialization/modelz.dart';
|
||||
import 'package:compiler/src/serialization/task.dart';
|
||||
import 'package:compiler/src/tokens/token.dart';
|
||||
import 'package:compiler/src/script.dart';
|
||||
import 'package:compiler/src/universe/world_impact.dart';
|
||||
import 'memory_compiler.dart';
|
||||
|
||||
|
||||
Future<String> serializeDartCore() async {
|
||||
Future<String> serializeDartCore({bool serializeResolvedAst: false}) async {
|
||||
Compiler compiler = compilerFor(
|
||||
options: [Flags.analyzeAll]);
|
||||
compiler.serialization.supportSerialization = true;
|
||||
await compiler.run(Uris.dart_core);
|
||||
return serialize(compiler, compiler.libraryLoader.libraries)
|
||||
.toText(const JsonSerializationEncoder());
|
||||
return serialize(
|
||||
compiler,
|
||||
compiler.libraryLoader.libraries,
|
||||
serializeResolvedAst: serializeResolvedAst)
|
||||
.toText(const JsonSerializationEncoder());
|
||||
}
|
||||
|
||||
Serializer serialize(Compiler compiler, Iterable<LibraryElement> libraries) {
|
||||
Serializer serialize(
|
||||
Compiler compiler,
|
||||
Iterable<LibraryElement> libraries,
|
||||
{bool serializeResolvedAst: false}) {
|
||||
assert(compiler.serialization.supportSerialization);
|
||||
|
||||
Serializer serializer = new Serializer();
|
||||
serializer.plugins.add(compiler.backend.serialization.serializer);
|
||||
serializer.plugins.add(new ResolutionImpactSerializer(compiler.resolution));
|
||||
if (serializeResolvedAst) {
|
||||
serializer.plugins.add(
|
||||
new ResolvedAstSerializerPlugin(compiler.resolution));
|
||||
}
|
||||
|
||||
for (LibraryElement library in libraries) {
|
||||
serializer.serialize(library);
|
||||
@@ -45,7 +62,9 @@ Serializer serialize(Compiler compiler, Iterable<LibraryElement> libraries) {
|
||||
return serializer;
|
||||
}
|
||||
|
||||
void deserialize(Compiler compiler, String serializedData) {
|
||||
void deserialize(Compiler compiler,
|
||||
String serializedData,
|
||||
{bool deserializeResolvedAst: false}) {
|
||||
Deserializer deserializer = new Deserializer.fromText(
|
||||
new DeserializationContext(),
|
||||
serializedData,
|
||||
@@ -53,8 +72,10 @@ void deserialize(Compiler compiler, String serializedData) {
|
||||
deserializer.plugins.add(compiler.backend.serialization.deserializer);
|
||||
compiler.serialization.deserializer =
|
||||
new _DeserializerSystem(
|
||||
compiler,
|
||||
deserializer,
|
||||
compiler.backend.impactTransformer);
|
||||
compiler.backend.impactTransformer,
|
||||
deserializeResolvedAst: deserializeResolvedAst);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,24 +109,59 @@ class ResolutionImpactDeserializer extends DeserializerPlugin {
|
||||
}
|
||||
|
||||
class _DeserializerSystem extends DeserializerSystem {
|
||||
final Compiler _compiler;
|
||||
final Deserializer _deserializer;
|
||||
final List<LibraryElement> deserializedLibraries = <LibraryElement>[];
|
||||
final ResolutionImpactDeserializer _resolutionImpactDeserializer =
|
||||
new ResolutionImpactDeserializer();
|
||||
final ResolvedAstDeserializerPlugin _resolvedAstDeserializer;
|
||||
final ImpactTransformer _impactTransformer;
|
||||
final bool _deserializeResolvedAst;
|
||||
|
||||
_DeserializerSystem(this._deserializer, this._impactTransformer) {
|
||||
_DeserializerSystem(
|
||||
Compiler compiler,
|
||||
this._deserializer,
|
||||
this._impactTransformer,
|
||||
{bool deserializeResolvedAst: false})
|
||||
: this._compiler = compiler,
|
||||
this._deserializeResolvedAst = deserializeResolvedAst,
|
||||
this._resolvedAstDeserializer = deserializeResolvedAst
|
||||
? new ResolvedAstDeserializerPlugin(compiler.parsing) : null {
|
||||
_deserializer.plugins.add(_resolutionImpactDeserializer);
|
||||
if (_deserializeResolvedAst) {
|
||||
_deserializer.plugins.add(_resolvedAstDeserializer);
|
||||
}
|
||||
}
|
||||
|
||||
LibraryElement readLibrary(Uri resolvedUri) {
|
||||
@override
|
||||
Future<LibraryElement> readLibrary(Uri resolvedUri) {
|
||||
LibraryElement library = _deserializer.lookupLibrary(resolvedUri);
|
||||
if (library != null) {
|
||||
deserializedLibraries.add(library);
|
||||
if (_deserializeResolvedAst) {
|
||||
return Future.forEach(library.compilationUnits,
|
||||
(CompilationUnitElement compilationUnit) {
|
||||
Script script = compilationUnit.script;
|
||||
return _compiler.readScript(script.readableUri)
|
||||
.then((Script newScript) {
|
||||
_resolvedAstDeserializer.sourceFiles[script.resourceUri] =
|
||||
newScript.file;
|
||||
});
|
||||
}).then((_) => library);
|
||||
}
|
||||
}
|
||||
return library;
|
||||
return new Future<LibraryElement>.value(library);
|
||||
}
|
||||
|
||||
@override
|
||||
ResolvedAst getResolvedAst(Element element) {
|
||||
if (_resolvedAstDeserializer != null) {
|
||||
return _resolvedAstDeserializer.getResolvedAst(element);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
ResolutionImpact getResolutionImpact(Element element) {
|
||||
return _resolutionImpactDeserializer.impactMap[element];
|
||||
}
|
||||
@@ -126,3 +182,66 @@ class _DeserializerSystem extends DeserializerSystem {
|
||||
return deserializedLibraries.contains(element.library);
|
||||
}
|
||||
}
|
||||
|
||||
const String RESOLVED_AST_TAG = 'resolvedAst';
|
||||
|
||||
class ResolvedAstSerializerPlugin extends SerializerPlugin {
|
||||
final Resolution resolution;
|
||||
|
||||
ResolvedAstSerializerPlugin(this.resolution);
|
||||
|
||||
@override
|
||||
void onElement(Element element, ObjectEncoder createEncoder(String tag)) {
|
||||
if (element is MemberElement && resolution.hasResolvedAst(element)) {
|
||||
ResolvedAst resolvedAst = resolution.getResolvedAst(element);
|
||||
ObjectEncoder objectEncoder = createEncoder(RESOLVED_AST_TAG);
|
||||
new ResolvedAstSerializer(objectEncoder, resolvedAst).serialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResolvedAstDeserializerPlugin extends DeserializerPlugin {
|
||||
final Parsing parsing;
|
||||
final Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{};
|
||||
|
||||
Map<Element, ResolvedAst> _resolvedAstMap = <Element, ResolvedAst>{};
|
||||
Map<Element, ObjectDecoder> _decoderMap = <Element, ObjectDecoder>{};
|
||||
Map<Uri, Token> beginTokenMap = <Uri, Token>{};
|
||||
|
||||
ResolvedAstDeserializerPlugin(this.parsing);
|
||||
|
||||
ResolvedAst getResolvedAst(Element element) {
|
||||
ResolvedAst resolvedAst = _resolvedAstMap[element];
|
||||
if (resolvedAst == null) {
|
||||
ObjectDecoder decoder = _decoderMap[element];
|
||||
if (decoder != null) {
|
||||
resolvedAst = _resolvedAstMap[element] =
|
||||
ResolvedAstDeserializer.deserialize(
|
||||
element, decoder, parsing, findToken);
|
||||
_decoderMap.remove(element);
|
||||
}
|
||||
}
|
||||
return resolvedAst;
|
||||
}
|
||||
|
||||
Token findToken(Uri uri, int offset) {
|
||||
Token beginToken = beginTokenMap.putIfAbsent(uri, () {
|
||||
SourceFile sourceFile = sourceFiles[uri];
|
||||
if (sourceFile == null) {
|
||||
throw 'No source file found for $uri in:\n '
|
||||
'${sourceFiles.keys.join('\n ')}';
|
||||
}
|
||||
return new Scanner(sourceFile).tokenize();
|
||||
});
|
||||
return ResolvedAstDeserializer.findTokenInStream(beginToken, offset);
|
||||
}
|
||||
|
||||
@override
|
||||
void onElement(Element element, ObjectDecoder getDecoder(String tag)) {
|
||||
ObjectDecoder decoder = getDecoder(RESOLVED_AST_TAG);
|
||||
if (decoder != null) {
|
||||
_decoderMap[element] = decoder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2016, 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.
|
||||
|
||||
library dart2js.serialization_resolved_ast_test;
|
||||
|
||||
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/compiler.dart';
|
||||
import 'package:compiler/src/elements/elements.dart';
|
||||
import 'package:compiler/src/filenames.dart';
|
||||
import 'package:compiler/src/serialization/equivalence.dart';
|
||||
import 'memory_compiler.dart';
|
||||
import 'serialization_helper.dart';
|
||||
import 'serialization_test_data.dart';
|
||||
import 'serialization_test_helper.dart';
|
||||
|
||||
|
||||
main(List<String> arguments) {
|
||||
asyncTest(() async {
|
||||
String serializedData = await serializeDartCore(serializeResolvedAst: true);
|
||||
if (arguments.isNotEmpty) {
|
||||
Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.last));
|
||||
await check(serializedData, entryPoint);
|
||||
} else {
|
||||
Uri entryPoint = Uri.parse('memory:main.dart');
|
||||
// TODO(johnniwinther): Change to test all serialized resolved ast instead
|
||||
// only those used in the test.
|
||||
Test test = TESTS.last;
|
||||
await check(serializedData, entryPoint, test.sourceFiles);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future check(
|
||||
String serializedData,
|
||||
Uri entryPoint,
|
||||
[Map<String, String> sourceFiles = const <String, String>{}]) async {
|
||||
|
||||
Compiler compilerNormal = compilerFor(
|
||||
memorySourceFiles: sourceFiles,
|
||||
options: [Flags.analyzeOnly]);
|
||||
compilerNormal.resolution.retainCachesForTesting = true;
|
||||
await compilerNormal.run(entryPoint);
|
||||
|
||||
Compiler compilerDeserialized = compilerFor(
|
||||
memorySourceFiles: sourceFiles,
|
||||
options: [Flags.analyzeOnly]);
|
||||
compilerDeserialized.resolution.retainCachesForTesting = true;
|
||||
deserialize(
|
||||
compilerDeserialized, serializedData, deserializeResolvedAst: true);
|
||||
await compilerDeserialized.run(entryPoint);
|
||||
|
||||
checkAllResolvedAsts(compilerNormal, compilerDeserialized, verbose: true);
|
||||
}
|
||||
|
||||
void checkAllResolvedAsts(
|
||||
Compiler compiler1,
|
||||
Compiler compiler2,
|
||||
{bool verbose: false}) {
|
||||
checkLoadedLibraryMembers(
|
||||
compiler1,
|
||||
compiler2,
|
||||
(Element member1) {
|
||||
return compiler1.resolution.hasResolvedAst(member1);
|
||||
},
|
||||
checkResolvedAsts,
|
||||
verbose: true);
|
||||
}
|
||||
|
||||
|
||||
/// Check equivalence of [impact1] and [impact2].
|
||||
void checkResolvedAsts(Compiler compiler1, Element member1,
|
||||
Compiler compiler2, Element member2,
|
||||
{bool verbose: false}) {
|
||||
ResolvedAst resolvedAst1 = compiler1.resolution.getResolvedAst(member1);
|
||||
ResolvedAst resolvedAst2 =
|
||||
compiler2.serialization.deserializer.getResolvedAst(member2);
|
||||
|
||||
if (resolvedAst1 == null || resolvedAst2 == null) return;
|
||||
|
||||
if (verbose) {
|
||||
print('Checking resolved asts for $member1 vs $member2');
|
||||
}
|
||||
|
||||
testResolvedAstEquivalence(
|
||||
resolvedAst1, resolvedAst2, const CheckStrategy());
|
||||
}
|
||||
Reference in New Issue
Block a user