Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(241)

Unified Diff: pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart

Issue 1873573004: Serialize TreeElements (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Check only the last test to avoid timeout. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
diff --git a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d25426ec8756b5e7093ada4bdc9d26106697ad47
--- /dev/null
+++ b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
@@ -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);
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/serialization/modelz.dart ('k') | pkg/compiler/lib/src/serialization/serialization_util.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698