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