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

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: 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
14 Parser;
15 import '../parser/listener.dart' show
16 ParserError;
17 import '../parser/node_listener.dart' show
18 NodeListener;
19 import '../resolution/enum_creator.dart';
20 import '../resolution/send_structure.dart';
21 import '../resolution/tree_elements.dart';
22 import '../tree/tree.dart';
23 import '../tokens/token.dart';
24 import '../universe/selector.dart';
25 import 'keys.dart';
26 import 'serialization.dart';
27 import 'serialization_util.dart';
28
29 /// Visitor that computes a node-index mapping.
30 class AstIndexComputer extends Visitor {
31 final Map<Node, int> nodeIndices = <Node, int>{};
32 final List<Node> nodeList = <Node>[];
33
34 @override
35 visitNode(Node node) {
36 nodeIndices.putIfAbsent(node, () {
37 // Some nodes (like Modifier and empty NodeList) can be reused.
38 nodeList.add(node);
39 return nodeIndices.length;
40 });
41 node.visitChildren(this);
42 }
43 }
44
45 /// The kind of AST node. Used for determining how to deserialize
46 /// [ResolvedAst]s.
47 enum AstKind {
48 ENUM_CONSTRUCTOR,
49 ENUM_CONSTANT,
50 ENUM_INDEX_FIELD,
51 ENUM_VALUES_FIELD,
52 ENUM_TO_STRING,
53 FACTORY,
54 FIELD,
55 FUNCTION,
56 }
57
58 /// Serializer for [ResolvedAst]s.
59 class ResolvedAstSerializer extends Visitor {
60 final ObjectEncoder objectEncoder;
61 final ResolvedAst resolvedAst;
62 final AstIndexComputer indexComputer = new AstIndexComputer();
63 final Map<int, ObjectEncoder> nodeData = <int, ObjectEncoder>{};
64 ListEncoder _nodeDataEncoder;
65
66 ResolvedAstSerializer(this.objectEncoder, this.resolvedAst);
67
68 AstElement get element => resolvedAst.element;
69
70 TreeElements get elements => resolvedAst.elements;
71
72 Node get root => resolvedAst.node;
73
74 Map<Node, int> get nodeIndices => indexComputer.nodeIndices;
75 List<Node> get nodeList => indexComputer.nodeList;
76
77 /// Serializes [resolvedAst] into [objectEncoder].
78 void serialize() {
79 objectEncoder.setUri(Key.URI,
80 elements.analyzedElement.compilationUnit.script.resourceUri,
Siggi Cherem (dart-lang) 2016/04/08 16:55:33 eventually we should look into what URI to use - r
Johnni Winther 2016/04/11 08:54:04 This is a known issue for the serialization itself
Siggi Cherem (dart-lang) 2016/04/11 17:48:07 could we file a bug/add a todo to track this issue
Johnni Winther 2016/04/12 08:05:47 Done: #26244
81 elements.analyzedElement.compilationUnit.script.resourceUri);
82 AstKind kind;
83 if (element.enclosingClass is EnumClassElement) {
84 if (element.name == 'index') {
85 kind = AstKind.ENUM_INDEX_FIELD;
86 } else if (element.name == 'values') {
87 kind = AstKind.ENUM_VALUES_FIELD;
88 } else if (element.name == 'toString') {
89 kind = AstKind.ENUM_TO_STRING;
90 } else if (element.isConstructor) {
91 kind = AstKind.ENUM_CONSTRUCTOR;
92 } else {
93 assert(invariant(element, element.isConst,
94 message: "Unexpected enum member: $element"));
95 kind = AstKind.ENUM_CONSTANT;
96 }
97 } else if (element.isFactoryConstructor) {
Siggi Cherem (dart-lang) 2016/04/08 16:55:33 nit: small refactor just to make it more self expl
Johnni Winther 2016/04/11 08:54:04 Done.
98 objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset);
99 kind = AstKind.FACTORY;
100 } else if (element.isField) {
101 objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset);
Siggi Cherem (dart-lang) 2016/04/08 16:55:33 question: as we make progress we'll drop the token
Johnni Winther 2016/04/11 08:54:04 Yes. Source information such replace tokens/nodes
102 kind = AstKind.FIELD;
103 } else {
104 objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset);
105 kind = AstKind.FUNCTION;
106 FunctionExpression functionExpression = root.asFunctionExpression();
107 if (functionExpression.getOrSet != null) {
108 objectEncoder.setInt(
109 Key.GET_OR_SET, functionExpression.getOrSet.charOffset);
Siggi Cherem (dart-lang) 2016/04/08 16:55:33 follow up question: this seems trickier to do with
Johnni Winther 2016/04/11 08:54:04 This is only for reparsing. When we have a complet
110 }
111 }
112 objectEncoder.setEnum(Key.KIND, kind);
113 root.accept(indexComputer);
114 root.accept(this);
115 }
116
117 /// Computes the [ListEncoder] for serializing data for nodes.
118 ListEncoder get nodeDataEncoder {
119 if (_nodeDataEncoder == null) {
120 _nodeDataEncoder = objectEncoder.createList(Key.DATA);
121 }
122 return _nodeDataEncoder;
123 }
124
125 /// Computes the [ObjectEncoder] for serializing data for [node].
126 ObjectEncoder getNodeDataEncoder(Node node) {
127 int id = nodeIndices[node];
128 return nodeData.putIfAbsent(id, () {
129 ObjectEncoder objectEncoder = nodeDataEncoder.createObject();
130 objectEncoder.setInt(Key.ID, id);
131 return objectEncoder;
132 });
133 }
134
135 @override
136 visitNode(Node node) {
137 Element nodeElement = elements[node];
138 if (nodeElement != null) {
139 if (nodeElement.enclosingClass != null &&
140 nodeElement.enclosingClass.isUnnamedMixinApplication) {
141 // TODO(johnniwinther): Handle references to members of unnamed mixin
142 // applications.
143 } else {
144 getNodeDataEncoder(node).setElement(Key.ELEMENT, nodeElement);
145 }
146 }
147 DartType type = elements.getType(node);
148 if (type != null) {
149 getNodeDataEncoder(node).setType(Key.TYPE, type);
150 }
151 Selector selector = elements.getSelector(node);
152 if (selector != null) {
153 serializeSelector(
154 selector,
155 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(structure,
175 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(structure,
185 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(
218 Element element,
219 ObjectDecoder objectDecoder,
220 Parsing parsing,
221 Token getBeginToken(Uri uri, int charOffset)) {
222 CompilationUnitElement compilationUnit = element.compilationUnit;
223 DiagnosticReporter reporter = parsing.reporter;
224
225 /// Returns the first [Token] for parsing the [Node] for [element].
226 Token readBeginToken() {
227 Uri uri = objectDecoder.getUri(Key.URI);
228 int charOffset = objectDecoder.getInt(Key.OFFSET);
229 Token beginToken = getBeginToken(uri, charOffset);
230 if (beginToken == null) {
231 reporter.internalError(
232 element, "No token found for $element in $uri @ $charOffset");
233 }
234 return beginToken;
235 }
236
237 /// Create the [Node] for the element by parsing the source code.
238 Node doParse(parse(Parser parser)) {
239 return parsing.measure(() {
240 return reporter.withCurrentElement(element, () {
241 CompilationUnitElement unit = element.compilationUnit;
242 NodeListener listener = new NodeListener(
243 parsing.getScannerOptionsFor(element), reporter, null);
244 listener.memberErrors = listener.memberErrors.prepend(false);
245 try {
246 Parser parser = new Parser(listener, parsing.parserOptions);
247 parse(parser);
248 } on ParserError catch (e) {
249 reporter.internalError(element, '$e');
250 }
251 return listener.popNode();
252 });
253 });
254 }
255
256 /// Computes the [Node] for the element based on the [AstKind].
257 Node computeNode(AstKind kind) {
258 switch (kind) {
259 case AstKind.ENUM_INDEX_FIELD:
260 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
261 Identifier identifier = builder.identifier('index');
262 VariableDefinitions node = new VariableDefinitions(
263 null,
264 builder.modifiers(isFinal: true),
265 new NodeList.singleton(identifier));
266 return node;
267 case AstKind.ENUM_VALUES_FIELD:
268 EnumClassElement enumClass = element.enclosingClass;
269 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
270 List<FieldElement> enumValues = <FieldElement>[];
271 List<Node> valueReferences = <Node>[];
272 for (EnumConstantElement enumConstant in enumClass.enumValues) {
273 AstBuilder valueBuilder =
274 new AstBuilder(enumConstant.sourcePosition.begin);
275 Identifier name = valueBuilder.identifier(enumConstant.name);
276
277 // Add reference for the `values` field.
278 valueReferences.add(valueBuilder.reference(name));
279 }
280
281 Identifier valuesIdentifier = builder.identifier('values');
282 // TODO(johnniwinther): Add type argument.
283 Expression initializer = builder.listLiteral(
284 valueReferences, isConst: true);
285
286 Node definition =
287 builder.createDefinition(valuesIdentifier, initializer);
288 VariableDefinitions node = new VariableDefinitions(
289 null,
290 builder.modifiers(isStatic: true, isConst: true),
291 new NodeList.singleton(definition));
292 return node;
293 case AstKind.ENUM_TO_STRING:
294 EnumClassElement enumClass = element.enclosingClass;
295 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
296 List<LiteralMapEntry> mapEntries = <LiteralMapEntry>[];
297 for (EnumConstantElement enumConstant in enumClass.enumValues) {
298 AstBuilder valueBuilder =
299 new AstBuilder(enumConstant.sourcePosition.begin);
300 Identifier name = valueBuilder.identifier(enumConstant.name);
301
302 // Add map entry for `toString` implementation.
303 mapEntries.add(valueBuilder.mapLiteralEntry(
304 valueBuilder.literalInt(enumConstant.index),
305 valueBuilder.literalString(
306 '${enumClass.name}.${name.source}')));
307 }
308
309 // TODO(johnniwinther): Support return type. Note `String` might be
310 // prefixed or not imported within the current library.
311 FunctionExpression toStringNode = builder.functionExpression(
312 Modifiers.EMPTY,
313 'toString',
314 builder.argumentList([]),
315 builder.returnStatement(
316 builder.indexGet(
317 builder.mapLiteral(mapEntries, isConst: true),
318 builder.reference(builder.identifier('index')))
319 )
320 );
321 return toStringNode;
322 case AstKind.ENUM_CONSTRUCTOR:
323 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
324 VariableDefinitions indexDefinition =
325 builder.initializingFormal('index');
326 FunctionExpression constructorNode = builder.functionExpression(
327 builder.modifiers(isConst: true),
328 element.enclosingClass.name,
329 builder.argumentList([indexDefinition]),
330 builder.emptyStatement());
331 return constructorNode;
332 case AstKind.ENUM_CONSTANT:
333 EnumConstantElement enumConstant = element;
334 EnumClassElement enumClass = element.enclosingClass;
335 int index = enumConstant.index;
336 AstBuilder builder = new AstBuilder(element.sourcePosition.begin);
337 Identifier name = builder.identifier(element.name);
338
339 Expression initializer = builder.newExpression(
340 enumClass.name,
341 builder.argumentList([builder.literalInt(index)]),
342 isConst: true);
343 SendSet definition = builder.createDefinition(name, initializer);
344
345 VariableDefinitions node = new VariableDefinitions(
346 null,
347 builder.modifiers(isStatic: true, isConst: true),
348 new NodeList.singleton(definition));
349 return node;
350 case AstKind.FACTORY:
351 Token beginToken = readBeginToken();
352 return doParse((parser) => parser.parseFactoryMethod(beginToken));
353 case AstKind.FIELD:
354 Token beginToken = readBeginToken();
355 return doParse((parser) => parser.parseMember(beginToken));
356 case AstKind.FUNCTION:
357 Token beginToken = readBeginToken();
358 int getOrSetOffset =
359 objectDecoder.getInt(Key.GET_OR_SET, isOptional: true);
360 Token getOrSet;
361 if (getOrSetOffset != null) {
362 getOrSet = findTokenInStream(beginToken, getOrSetOffset);
363 if (getOrSet == null) {
364 reporter.internalError(
365 element,
366 "No token found for $element in "
367 "${objectDecoder.getUri(Key.URI)} @ $getOrSetOffset");
368 }
369 }
370 return doParse((parser) {
371 parser.parseFunction(beginToken, getOrSet);
372 });
373 }
374 }
375
376 AstKind kind = objectDecoder.getEnum(Key.KIND, AstKind.values);
377 Node root = computeNode(kind);
378 TreeElementMapping elements = new TreeElementMapping(element);
379 AstIndexComputer indexComputer = new AstIndexComputer();
380 Map<Node, int> nodeIndices = indexComputer.nodeIndices;
381 List<Node> nodeList = indexComputer.nodeList;
382 root.accept(indexComputer);
383 ListDecoder dataDecoder = objectDecoder.getList(Key.DATA);
384 if (dataDecoder != null) {
385 for (int i = 0; i < dataDecoder.length; i++) {
386 ObjectDecoder objectDecoder = dataDecoder.getObject(i);
387 int id = objectDecoder.getInt(Key.ID);
388 Node node = nodeList[id];
389 Element nodeElement =
390 objectDecoder.getElement(Key.ELEMENT, isOptional: true);
391 if (nodeElement != null) {
392 elements[node] = nodeElement;
393 }
394 DartType type = objectDecoder.getType(Key.TYPE, isOptional: true);
395 if (type != null) {
396 elements.setType(node, type);
397 }
398 ObjectDecoder selectorDecoder =
399 objectDecoder.getObject(Key.SELECTOR, isOptional: true);
400 if (selectorDecoder != null) {
401 elements.setSelector(node, deserializeSelector(selectorDecoder));
402 }
403 ConstantExpression constant =
404 objectDecoder.getConstant(Key.CONSTANT, isOptional: true);
405 if (constant != null) {
406 elements.setConstant(node, constant);
407 }
408 DartType cachedType =
409 objectDecoder.getType(Key.CACHED_TYPE, isOptional: true);
410 if (cachedType != null) {
411 elements.typesCache[node] = cachedType;
412 }
413 ObjectDecoder sendStructureDecoder =
414 objectDecoder.getObject(Key.SEND_STRUCTURE, isOptional: true);
415 if (sendStructureDecoder != null) {
416 elements.setSendStructure(node,
417 deserializeSendStructure(sendStructureDecoder));
418 }
419 ObjectDecoder newStructureDecoder =
420 objectDecoder.getObject(Key.NEW_STRUCTURE, isOptional: true);
421 if (newStructureDecoder != null) {
422 elements.setNewStructure(node,
423 deserializeNewStructure(newStructureDecoder));
424 }
425 }
426 }
427 return new ResolvedAst(element, root, elements);
428 }
429 }
430
431
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698