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

Side by Side 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library dart2js.serialization.resolved_ast;
6
7 import '../common.dart';
8 import '../common/resolution.dart';
9 import '../constants/expressions.dart';
10 import '../dart_types.dart';
11 import '../diagnostics/diagnostic_listener.dart';
12 import '../elements/elements.dart';
13 import '../parser/parser.dart' show Parser;
14 import '../parser/listener.dart' show ParserError;
15 import '../parser/node_listener.dart' show NodeListener;
16 import '../resolution/enum_creator.dart';
17 import '../resolution/send_structure.dart';
18 import '../resolution/tree_elements.dart';
19 import '../tree/tree.dart';
20 import '../tokens/token.dart';
21 import '../universe/selector.dart';
22 import 'keys.dart';
23 import 'serialization.dart';
24 import 'serialization_util.dart';
25
26 /// Visitor that computes a node-index mapping.
27 class AstIndexComputer extends Visitor {
28 final Map<Node, int> nodeIndices = <Node, int>{};
29 final List<Node> nodeList = <Node>[];
30
31 @override
32 visitNode(Node node) {
33 nodeIndices.putIfAbsent(node, () {
34 // Some nodes (like Modifier and empty NodeList) can be reused.
35 nodeList.add(node);
36 return nodeIndices.length;
37 });
38 node.visitChildren(this);
39 }
40 }
41
42 /// The kind of AST node. Used for determining how to deserialize
43 /// [ResolvedAst]s.
44 enum AstKind {
45 ENUM_CONSTRUCTOR,
46 ENUM_CONSTANT,
47 ENUM_INDEX_FIELD,
48 ENUM_VALUES_FIELD,
49 ENUM_TO_STRING,
50 FACTORY,
51 FIELD,
52 FUNCTION,
53 }
54
55 /// Serializer for [ResolvedAst]s.
56 class ResolvedAstSerializer extends Visitor {
57 final ObjectEncoder objectEncoder;
58 final ResolvedAst resolvedAst;
59 final AstIndexComputer indexComputer = new AstIndexComputer();
60 final Map<int, ObjectEncoder> nodeData = <int, ObjectEncoder>{};
61 ListEncoder _nodeDataEncoder;
62
63 ResolvedAstSerializer(this.objectEncoder, this.resolvedAst);
64
65 AstElement get element => resolvedAst.element;
66
67 TreeElements get elements => resolvedAst.elements;
68
69 Node get root => resolvedAst.node;
70
71 Map<Node, int> get nodeIndices => indexComputer.nodeIndices;
72 List<Node> get nodeList => indexComputer.nodeList;
73
74 /// Serializes [resolvedAst] into [objectEncoder].
75 void serialize() {
76 objectEncoder.setUri(
77 Key.URI,
78 elements.analyzedElement.compilationUnit.script.resourceUri,
79 elements.analyzedElement.compilationUnit.script.resourceUri);
80 AstKind kind;
81 if (element.enclosingClass is EnumClassElement) {
82 if (element.name == 'index') {
83 kind = AstKind.ENUM_INDEX_FIELD;
84 } else if (element.name == 'values') {
85 kind = AstKind.ENUM_VALUES_FIELD;
86 } else if (element.name == 'toString') {
87 kind = AstKind.ENUM_TO_STRING;
88 } else if (element.isConstructor) {
89 kind = AstKind.ENUM_CONSTRUCTOR;
90 } else {
91 assert(invariant(element, element.isConst,
92 message: "Unexpected enum member: $element"));
93 kind = AstKind.ENUM_CONSTANT;
94 }
95 } else {
96 // [element] has a body that we'll need to re-parse. We store where to
97 // start parsing from.
98 objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset);
99 if (element.isFactoryConstructor) {
100 kind = AstKind.FACTORY;
101 } else if (element.isField) {
102 kind = AstKind.FIELD;
103 } else {
104 kind = AstKind.FUNCTION;
105 FunctionExpression functionExpression = root.asFunctionExpression();
106 if (functionExpression.getOrSet != null) {
107 // Getters/setters need the get/set token to be parsed.
108 objectEncoder.setInt(
109 Key.GET_OR_SET, functionExpression.getOrSet.charOffset);
110 }
111 }
112 }
113 objectEncoder.setEnum(Key.KIND, kind);
114 root.accept(indexComputer);
115 root.accept(this);
116 }
117
118 /// Computes the [ListEncoder] for serializing data for nodes.
119 ListEncoder get nodeDataEncoder {
120 if (_nodeDataEncoder == null) {
121 _nodeDataEncoder = objectEncoder.createList(Key.DATA);
122 }
123 return _nodeDataEncoder;
124 }
125
126 /// Computes the [ObjectEncoder] for serializing data for [node].
127 ObjectEncoder getNodeDataEncoder(Node node) {
128 int id = nodeIndices[node];
129 return nodeData.putIfAbsent(id, () {
130 ObjectEncoder objectEncoder = nodeDataEncoder.createObject();
131 objectEncoder.setInt(Key.ID, id);
132 return objectEncoder;
133 });
134 }
135
136 @override
137 visitNode(Node node) {
138 Element nodeElement = elements[node];
139 if (nodeElement != null) {
140 if (nodeElement.enclosingClass != null &&
141 nodeElement.enclosingClass.isUnnamedMixinApplication) {
142 // TODO(johnniwinther): Handle references to members of unnamed mixin
143 // applications.
144 } else {
145 getNodeDataEncoder(node).setElement(Key.ELEMENT, nodeElement);
146 }
147 }
148 DartType type = elements.getType(node);
149 if (type != null) {
150 getNodeDataEncoder(node).setType(Key.TYPE, type);
151 }
152 Selector selector = elements.getSelector(node);
153 if (selector != null) {
154 serializeSelector(
155 selector, getNodeDataEncoder(node).createObject(Key.SELECTOR));
156 }
157 ConstantExpression constant = elements.getConstant(node);
158 if (constant != null) {
159 getNodeDataEncoder(node).setConstant(Key.CONSTANT, constant);
160 }
161 DartType cachedType = elements.typesCache[node];
162 if (cachedType != null) {
163 getNodeDataEncoder(node).setType(Key.CACHED_TYPE, cachedType);
164 }
165 // TODO(johnniwinther): Serialize [JumpTarget]s.
166 node.visitChildren(this);
167 }
168
169 @override
170 visitSend(Send node) {
171 visitExpression(node);
172 SendStructure structure = elements.getSendStructure(node);
173 if (structure != null) {
174 serializeSendStructure(
175 structure, getNodeDataEncoder(node).createObject(Key.SEND_STRUCTURE));
176 }
177 }
178
179 @override
180 visitNewExpression(NewExpression node) {
181 visitExpression(node);
182 NewStructure structure = elements.getNewStructure(node);
183 if (structure != null) {
184 serializeNewStructure(
185 structure, getNodeDataEncoder(node).createObject(Key.NEW_STRUCTURE));
186 }
187 }
188
189 @override
190 visitGotoStatement(GotoStatement node) {
191 visitStatement(node);
192 // TODO(johnniwinther): Serialize [JumpTarget]s and [LabelDefinition]s.
193 }
194
195 @override
196 visitLabel(Label node) {
197 visitNode(node);
198 // TODO(johnniwinther): Serialize[LabelDefinition]s.
199 }
200 }
201
202 class ResolvedAstDeserializer {
203 /// Find the [Token] at [offset] searching through successors of [token].
204 static Token findTokenInStream(Token token, int offset) {
205 while (token.charOffset <= offset && token.next != token) {
206 if (token.charOffset == offset) {
207 return token;
208 }
209 token = token.next;
210 }
211 return null;
212 }
213
214 /// Deserializes the [ResolvedAst] for [element] from [objectDecoder].
215 /// [parsing] and [getBeginToken] are used for parsing the [Node] for
216 /// [element] from its source code.
217 static ResolvedAst deserialize(Element element, ObjectDecoder objectDecoder,
218 Parsing parsing, Token getBeginToken(Uri uri, int charOffset)) {
219 CompilationUnitElement compilationUnit = element.compilationUnit;
220 DiagnosticReporter reporter = parsing.reporter;
221
222 /// Returns the first [Token] for parsing the [Node] for [element].
223 Token readBeginToken() {
224 Uri uri = objectDecoder.getUri(Key.URI);
225 int charOffset = objectDecoder.getInt(Key.OFFSET);
226 Token beginToken = getBeginToken(uri, charOffset);
227 if (beginToken == null) {
228 reporter.internalError(
229 element, "No token found for $element in $uri @ $charOffset");
230 }
231 return beginToken;
232 }
233
234 /// Create the [Node] for the element by parsing the source code.
235 Node doParse(parse(Parser parser)) {
236 return parsing.measure(() {
237 return reporter.withCurrentElement(element, () {
238 CompilationUnitElement unit = element.compilationUnit;
239 NodeListener listener = new NodeListener(
240 parsing.getScannerOptionsFor(element), reporter, null);
241 listener.memberErrors = listener.memberErrors.prepend(false);
242 try {
243 Parser parser = new Parser(listener, parsing.parserOptions);
244 parse(parser);
245 } on ParserError catch (e) {
246 reporter.internalError(element, '$e');
247 }
248 return listener.popNode();
249 });
250 });
251 }
252
253 /// Computes the [Node] for the element based on the [AstKind].
254 Node computeNode(AstKind kind) {
255 switch (kind) {
256 case AstKind.ENUM_INDEX_FIELD:
257 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
258 Identifier identifier = builder.identifier('index');
259 VariableDefinitions node = new VariableDefinitions(
260 null,
261 builder.modifiers(isFinal: true),
262 new NodeList.singleton(identifier));
263 return node;
264 case AstKind.ENUM_VALUES_FIELD:
265 EnumClassElement enumClass = element.enclosingClass;
266 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
267 List<FieldElement> enumValues = <FieldElement>[];
268 List<Node> valueReferences = <Node>[];
269 for (EnumConstantElement enumConstant in enumClass.enumValues) {
270 AstBuilder valueBuilder =
271 new AstBuilder(enumConstant.sourcePosition.begin);
272 Identifier name = valueBuilder.identifier(enumConstant.name);
273
274 // Add reference for the `values` field.
275 valueReferences.add(valueBuilder.reference(name));
276 }
277
278 Identifier valuesIdentifier = builder.identifier('values');
279 // TODO(johnniwinther): Add type argument.
280 Expression initializer =
281 builder.listLiteral(valueReferences, isConst: true);
282
283 Node definition =
284 builder.createDefinition(valuesIdentifier, initializer);
285 VariableDefinitions node = new VariableDefinitions(
286 null,
287 builder.modifiers(isStatic: true, isConst: true),
288 new NodeList.singleton(definition));
289 return node;
290 case AstKind.ENUM_TO_STRING:
291 EnumClassElement enumClass = element.enclosingClass;
292 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
293 List<LiteralMapEntry> mapEntries = <LiteralMapEntry>[];
294 for (EnumConstantElement enumConstant in enumClass.enumValues) {
295 AstBuilder valueBuilder =
296 new AstBuilder(enumConstant.sourcePosition.begin);
297 Identifier name = valueBuilder.identifier(enumConstant.name);
298
299 // Add map entry for `toString` implementation.
300 mapEntries.add(valueBuilder.mapLiteralEntry(
301 valueBuilder.literalInt(enumConstant.index),
302 valueBuilder
303 .literalString('${enumClass.name}.${name.source}')));
304 }
305
306 // TODO(johnniwinther): Support return type. Note `String` might be
307 // prefixed or not imported within the current library.
308 FunctionExpression toStringNode = builder.functionExpression(
309 Modifiers.EMPTY,
310 'toString',
311 builder.argumentList([]),
312 builder.returnStatement(builder.indexGet(
313 builder.mapLiteral(mapEntries, isConst: true),
314 builder.reference(builder.identifier('index')))));
315 return toStringNode;
316 case AstKind.ENUM_CONSTRUCTOR:
317 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
318 VariableDefinitions indexDefinition =
319 builder.initializingFormal('index');
320 FunctionExpression constructorNode = builder.functionExpression(
321 builder.modifiers(isConst: true),
322 element.enclosingClass.name,
323 builder.argumentList([indexDefinition]),
324 builder.emptyStatement());
325 return constructorNode;
326 case AstKind.ENUM_CONSTANT:
327 EnumConstantElement enumConstant = element;
328 EnumClassElement enumClass = element.enclosingClass;
329 int index = enumConstant.index;
330 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
331 Identifier name = builder.identifier(element.name);
332
333 Expression initializer = builder.newExpression(
334 enumClass.name, builder.argumentList([builder.literalInt(index)]),
335 isConst: true);
336 SendSet definition = builder.createDefinition(name, initializer);
337
338 VariableDefinitions node = new VariableDefinitions(
339 null,
340 builder.modifiers(isStatic: true, isConst: true),
341 new NodeList.singleton(definition));
342 return node;
343 case AstKind.FACTORY:
344 Token beginToken = readBeginToken();
345 return doParse((parser) => parser.parseFactoryMethod(beginToken));
346 case AstKind.FIELD:
347 Token beginToken = readBeginToken();
348 return doParse((parser) => parser.parseMember(beginToken));
349 case AstKind.FUNCTION:
350 Token beginToken = readBeginToken();
351 int getOrSetOffset =
352 objectDecoder.getInt(Key.GET_OR_SET, isOptional: true);
353 Token getOrSet;
354 if (getOrSetOffset != null) {
355 getOrSet = findTokenInStream(beginToken, getOrSetOffset);
356 if (getOrSet == null) {
357 reporter.internalError(
358 element,
359 "No token found for $element in "
360 "${objectDecoder.getUri(Key.URI)} @ $getOrSetOffset");
361 }
362 }
363 return doParse((parser) {
364 parser.parseFunction(beginToken, getOrSet);
365 });
366 }
367 }
368
369 AstKind kind = objectDecoder.getEnum(Key.KIND, AstKind.values);
370 Node root = computeNode(kind);
371 TreeElementMapping elements = new TreeElementMapping(element);
372 AstIndexComputer indexComputer = new AstIndexComputer();
373 Map<Node, int> nodeIndices = indexComputer.nodeIndices;
374 List<Node> nodeList = indexComputer.nodeList;
375 root.accept(indexComputer);
376 ListDecoder dataDecoder = objectDecoder.getList(Key.DATA);
377 if (dataDecoder != null) {
378 for (int i = 0; i < dataDecoder.length; i++) {
379 ObjectDecoder objectDecoder = dataDecoder.getObject(i);
380 int id = objectDecoder.getInt(Key.ID);
381 Node node = nodeList[id];
382 Element nodeElement =
383 objectDecoder.getElement(Key.ELEMENT, isOptional: true);
384 if (nodeElement != null) {
385 elements[node] = nodeElement;
386 }
387 DartType type = objectDecoder.getType(Key.TYPE, isOptional: true);
388 if (type != null) {
389 elements.setType(node, type);
390 }
391 ObjectDecoder selectorDecoder =
392 objectDecoder.getObject(Key.SELECTOR, isOptional: true);
393 if (selectorDecoder != null) {
394 elements.setSelector(node, deserializeSelector(selectorDecoder));
395 }
396 ConstantExpression constant =
397 objectDecoder.getConstant(Key.CONSTANT, isOptional: true);
398 if (constant != null) {
399 elements.setConstant(node, constant);
400 }
401 DartType cachedType =
402 objectDecoder.getType(Key.CACHED_TYPE, isOptional: true);
403 if (cachedType != null) {
404 elements.typesCache[node] = cachedType;
405 }
406 ObjectDecoder sendStructureDecoder =
407 objectDecoder.getObject(Key.SEND_STRUCTURE, isOptional: true);
408 if (sendStructureDecoder != null) {
409 elements.setSendStructure(
410 node, deserializeSendStructure(sendStructureDecoder));
411 }
412 ObjectDecoder newStructureDecoder =
413 objectDecoder.getObject(Key.NEW_STRUCTURE, isOptional: true);
414 if (newStructureDecoder != null) {
415 elements.setNewStructure(
416 node, deserializeNewStructure(newStructureDecoder));
417 }
418 }
419 }
420 return new ResolvedAst(element, root, elements);
421 }
422 }
OLDNEW
« 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