OLD | NEW |
| (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_helper; | |
6 | |
7 import 'dart:async'; | |
8 import 'dart:io'; | |
9 | |
10 import 'package:compiler/src/commandline_options.dart'; | |
11 import 'package:compiler/src/common.dart'; | |
12 import 'package:compiler/src/common/backend_api.dart'; | |
13 import 'package:compiler/src/common/names.dart'; | |
14 import 'package:compiler/src/common/resolution.dart'; | |
15 import 'package:compiler/src/compiler.dart'; | |
16 import 'package:compiler/src/elements/elements.dart'; | |
17 import 'package:compiler/src/io/source_file.dart'; | |
18 import 'package:compiler/src/scanner/scanner.dart'; | |
19 import 'package:compiler/src/script.dart'; | |
20 import 'package:compiler/src/serialization/impact_serialization.dart'; | |
21 import 'package:compiler/src/serialization/json_serializer.dart'; | |
22 import 'package:compiler/src/serialization/modelz.dart'; | |
23 import 'package:compiler/src/serialization/resolved_ast_serialization.dart'; | |
24 import 'package:compiler/src/serialization/serialization.dart'; | |
25 import 'package:compiler/src/serialization/task.dart'; | |
26 import 'package:compiler/src/tokens/token.dart'; | |
27 import 'package:compiler/src/universe/call_structure.dart'; | |
28 import 'package:compiler/src/universe/world_impact.dart'; | |
29 import 'package:compiler/src/universe/use.dart'; | |
30 | |
31 import 'memory_compiler.dart'; | |
32 | |
33 class Arguments { | |
34 final String filename; | |
35 final bool loadSerializedData; | |
36 final bool saveSerializedData; | |
37 final String serializedDataFileName; | |
38 final bool verbose; | |
39 | |
40 const Arguments({ | |
41 this.filename, | |
42 this.loadSerializedData: false, | |
43 this.saveSerializedData: false, | |
44 this.serializedDataFileName: 'out.data', | |
45 this.verbose: false}); | |
46 | |
47 factory Arguments.from(List<String> arguments) { | |
48 String filename; | |
49 for (String arg in arguments) { | |
50 if (!arg.startsWith('-')) { | |
51 filename = arg; | |
52 } | |
53 } | |
54 bool verbose = arguments.contains('-v'); | |
55 bool loadSerializedData = arguments.contains('-l'); | |
56 bool saveSerializedData = arguments.contains('-s'); | |
57 return new Arguments( | |
58 filename: filename, | |
59 verbose: verbose, | |
60 loadSerializedData: loadSerializedData, | |
61 saveSerializedData: saveSerializedData); | |
62 } | |
63 } | |
64 | |
65 | |
66 Future<String> serializeDartCore( | |
67 {Arguments arguments: const Arguments(), | |
68 bool serializeResolvedAst: false}) async { | |
69 print('------------------------------------------------------------------'); | |
70 print('serialize dart:core'); | |
71 print('------------------------------------------------------------------'); | |
72 String serializedData; | |
73 if (arguments.loadSerializedData) { | |
74 File file = new File(arguments.serializedDataFileName); | |
75 if (file.existsSync()) { | |
76 print('Loading data from $file'); | |
77 serializedData = file.readAsStringSync(); | |
78 } | |
79 } | |
80 if (serializedData == null) { | |
81 Compiler compiler = compilerFor( | |
82 options: [Flags.analyzeAll]); | |
83 compiler.serialization.supportSerialization = true; | |
84 await compiler.run(Uris.dart_core); | |
85 serializedData = serialize( | |
86 compiler, | |
87 compiler.libraryLoader.libraries, | |
88 serializeResolvedAst: serializeResolvedAst) | |
89 .toText(const JsonSerializationEncoder()); | |
90 if (arguments.saveSerializedData) { | |
91 File file = new File(arguments.serializedDataFileName); | |
92 print('Saving data to $file'); | |
93 file.writeAsStringSync(serializedData); | |
94 } | |
95 } | |
96 return serializedData; | |
97 } | |
98 | |
99 Serializer serialize( | |
100 Compiler compiler, | |
101 Iterable<LibraryElement> libraries, | |
102 {bool serializeResolvedAst: false}) { | |
103 assert(compiler.serialization.supportSerialization); | |
104 | |
105 Serializer serializer = new Serializer(); | |
106 serializer.plugins.add(compiler.backend.serialization.serializer); | |
107 serializer.plugins.add(new ResolutionImpactSerializer(compiler.resolution)); | |
108 if (serializeResolvedAst) { | |
109 serializer.plugins.add( | |
110 new ResolvedAstSerializerPlugin(compiler.resolution, compiler.backend)); | |
111 } | |
112 | |
113 for (LibraryElement library in libraries) { | |
114 serializer.serialize(library); | |
115 } | |
116 return serializer; | |
117 } | |
118 | |
119 void deserialize(Compiler compiler, | |
120 String serializedData, | |
121 {bool deserializeResolvedAst: false}) { | |
122 Deserializer deserializer = new Deserializer.fromText( | |
123 new DeserializationContext(), | |
124 serializedData, | |
125 const JsonSerializationDecoder()); | |
126 deserializer.plugins.add(compiler.backend.serialization.deserializer); | |
127 compiler.serialization.deserializer = | |
128 new _DeserializerSystem( | |
129 compiler, | |
130 deserializer, | |
131 compiler.backend.impactTransformer, | |
132 deserializeResolvedAst: deserializeResolvedAst); | |
133 } | |
134 | |
135 | |
136 const String WORLD_IMPACT_TAG = 'worldImpact'; | |
137 | |
138 class ResolutionImpactSerializer extends SerializerPlugin { | |
139 final Resolution resolution; | |
140 | |
141 ResolutionImpactSerializer(this.resolution); | |
142 | |
143 @override | |
144 void onElement(Element element, ObjectEncoder createEncoder(String tag)) { | |
145 if (resolution.hasBeenResolved(element)) { | |
146 ResolutionImpact impact = resolution.getResolutionImpact(element); | |
147 ObjectEncoder encoder = createEncoder(WORLD_IMPACT_TAG); | |
148 new ImpactSerializer(element, encoder).serialize(impact); | |
149 } | |
150 } | |
151 } | |
152 | |
153 class ResolutionImpactDeserializer extends DeserializerPlugin { | |
154 Map<Element, ResolutionImpact> impactMap = <Element, ResolutionImpact>{}; | |
155 | |
156 @override | |
157 void onElement(Element element, ObjectDecoder getDecoder(String tag)) { | |
158 ObjectDecoder decoder = getDecoder(WORLD_IMPACT_TAG); | |
159 if (decoder != null) { | |
160 impactMap[element] = | |
161 ImpactDeserializer.deserializeImpact(element, decoder); | |
162 } | |
163 } | |
164 } | |
165 | |
166 class _DeserializerSystem extends DeserializerSystem { | |
167 final Compiler _compiler; | |
168 final Deserializer _deserializer; | |
169 final List<LibraryElement> deserializedLibraries = <LibraryElement>[]; | |
170 final ResolutionImpactDeserializer _resolutionImpactDeserializer = | |
171 new ResolutionImpactDeserializer(); | |
172 final ResolvedAstDeserializerPlugin _resolvedAstDeserializer; | |
173 final ImpactTransformer _impactTransformer; | |
174 final bool _deserializeResolvedAst; | |
175 | |
176 _DeserializerSystem( | |
177 Compiler compiler, | |
178 this._deserializer, | |
179 this._impactTransformer, | |
180 {bool deserializeResolvedAst: false}) | |
181 : this._compiler = compiler, | |
182 this._deserializeResolvedAst = deserializeResolvedAst, | |
183 this._resolvedAstDeserializer = deserializeResolvedAst | |
184 ? new ResolvedAstDeserializerPlugin( | |
185 compiler.parsingContext, compiler.backend) : null { | |
186 _deserializer.plugins.add(_resolutionImpactDeserializer); | |
187 if (_deserializeResolvedAst) { | |
188 _deserializer.plugins.add(_resolvedAstDeserializer); | |
189 } | |
190 } | |
191 | |
192 @override | |
193 Future<LibraryElement> readLibrary(Uri resolvedUri) { | |
194 LibraryElement library = _deserializer.lookupLibrary(resolvedUri); | |
195 if (library != null) { | |
196 deserializedLibraries.add(library); | |
197 if (_deserializeResolvedAst) { | |
198 return Future.forEach(library.compilationUnits, | |
199 (CompilationUnitElement compilationUnit) { | |
200 ScriptZ script = compilationUnit.script; | |
201 return _compiler.readScript(script.readableUri) | |
202 .then((Script newScript) { | |
203 script.file = newScript.file; | |
204 _resolvedAstDeserializer.sourceFiles[script.resourceUri] = | |
205 newScript.file; | |
206 }); | |
207 }).then((_) => library); | |
208 } | |
209 } | |
210 return new Future<LibraryElement>.value(library); | |
211 } | |
212 | |
213 @override | |
214 bool hasResolvedAst(Element element) { | |
215 if (_resolvedAstDeserializer != null) { | |
216 return _resolvedAstDeserializer.hasResolvedAst(element); | |
217 } | |
218 return false; | |
219 } | |
220 | |
221 @override | |
222 ResolvedAst getResolvedAst(Element element) { | |
223 if (_resolvedAstDeserializer != null) { | |
224 return _resolvedAstDeserializer.getResolvedAst(element); | |
225 } | |
226 return null; | |
227 } | |
228 | |
229 @override | |
230 bool hasResolutionImpact(Element element) { | |
231 if (element.isConstructor && | |
232 element.enclosingClass.isUnnamedMixinApplication) { | |
233 return true; | |
234 } | |
235 return _resolutionImpactDeserializer.impactMap.containsKey(element); | |
236 } | |
237 | |
238 @override | |
239 ResolutionImpact getResolutionImpact(Element element) { | |
240 if (element.isConstructor && | |
241 element.enclosingClass.isUnnamedMixinApplication) { | |
242 ClassElement superclass = element.enclosingClass.superclass; | |
243 ConstructorElement superclassConstructor = | |
244 superclass.lookupConstructor(element.name); | |
245 assert(invariant(element, superclassConstructor != null, | |
246 message: "Superclass constructor '${element.name}' called from " | |
247 "${element} not found in ${superclass}.")); | |
248 // TODO(johnniwinther): Compute callStructure. Currently not used. | |
249 CallStructure callStructure; | |
250 return _resolutionImpactDeserializer.impactMap.putIfAbsent(element, () { | |
251 return new DeserializedResolutionImpact( | |
252 staticUses: <StaticUse>[new StaticUse.superConstructorInvoke( | |
253 superclassConstructor, callStructure)]); | |
254 }); | |
255 } | |
256 return _resolutionImpactDeserializer.impactMap[element]; | |
257 } | |
258 | |
259 @override | |
260 WorldImpact computeWorldImpact(Element element) { | |
261 ResolutionImpact resolutionImpact = getResolutionImpact(element); | |
262 assert(invariant(element, resolutionImpact != null, | |
263 message: 'No impact found for $element (${element.library})')); | |
264 return _impactTransformer.transformResolutionImpact(resolutionImpact); | |
265 } | |
266 | |
267 @override | |
268 bool isDeserialized(Element element) { | |
269 return deserializedLibraries.contains(element.library); | |
270 } | |
271 } | |
272 | |
273 const String RESOLVED_AST_TAG = 'resolvedAst'; | |
274 | |
275 class ResolvedAstSerializerPlugin extends SerializerPlugin { | |
276 final Resolution resolution; | |
277 final Backend backend; | |
278 | |
279 ResolvedAstSerializerPlugin(this.resolution, this.backend); | |
280 | |
281 @override | |
282 void onElement(Element element, ObjectEncoder createEncoder(String tag)) { | |
283 assert(invariant(element, element.isDeclaration, | |
284 message: "Element $element must be the declaration")); | |
285 if (element is MemberElement) { | |
286 assert(invariant(element, resolution.hasResolvedAst(element), | |
287 message: "Element $element must have a resolved ast")); | |
288 ResolvedAst resolvedAst = resolution.getResolvedAst(element); | |
289 ObjectEncoder objectEncoder = createEncoder(RESOLVED_AST_TAG); | |
290 new ResolvedAstSerializer( | |
291 objectEncoder, | |
292 resolvedAst, | |
293 backend.serialization.serializer).serialize(); | |
294 } | |
295 } | |
296 } | |
297 | |
298 class ResolvedAstDeserializerPlugin extends DeserializerPlugin { | |
299 final ParsingContext parsingContext; | |
300 final Backend backend; | |
301 final Map<Uri, SourceFile> sourceFiles = <Uri, SourceFile>{}; | |
302 | |
303 Map<Element, ResolvedAst> _resolvedAstMap = <Element, ResolvedAst>{}; | |
304 Map<Element, ObjectDecoder> _decoderMap = <Element, ObjectDecoder>{}; | |
305 Map<Uri, Token> beginTokenMap = <Uri, Token>{}; | |
306 | |
307 ResolvedAstDeserializerPlugin(this.parsingContext, this.backend); | |
308 | |
309 bool hasResolvedAst(Element element) { | |
310 return _resolvedAstMap.containsKey(element) || | |
311 _decoderMap.containsKey(element); | |
312 } | |
313 | |
314 ResolvedAst getResolvedAst(Element element) { | |
315 ResolvedAst resolvedAst = _resolvedAstMap[element]; | |
316 if (resolvedAst == null) { | |
317 ObjectDecoder decoder = _decoderMap[element]; | |
318 if (decoder != null) { | |
319 resolvedAst = _resolvedAstMap[element] = | |
320 ResolvedAstDeserializer.deserialize( | |
321 element, decoder, parsingContext, findToken, | |
322 backend.serialization.deserializer); | |
323 _decoderMap.remove(element); | |
324 } | |
325 } | |
326 return resolvedAst; | |
327 } | |
328 | |
329 Token findToken(Uri uri, int offset) { | |
330 Token beginToken = beginTokenMap.putIfAbsent(uri, () { | |
331 SourceFile sourceFile = sourceFiles[uri]; | |
332 if (sourceFile == null) { | |
333 throw 'No source file found for $uri in:\n ' | |
334 '${sourceFiles.keys.join('\n ')}'; | |
335 } | |
336 return new Scanner(sourceFile).tokenize(); | |
337 }); | |
338 return ResolvedAstDeserializer.findTokenInStream(beginToken, offset); | |
339 } | |
340 | |
341 @override | |
342 void onElement(Element element, ObjectDecoder getDecoder(String tag)) { | |
343 ObjectDecoder decoder = getDecoder(RESOLVED_AST_TAG); | |
344 if (decoder != null) { | |
345 _decoderMap[element] = decoder; | |
346 } | |
347 } | |
348 } | |
349 | |
OLD | NEW |