| 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 |