| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 part of dart2js.js_emitter.startup_emitter.model_emitter; | 5 part of dart2js.js_emitter.startup_emitter.model_emitter; |
| 6 | 6 |
| 7 /// The fast startup emitter's goal is to minimize the amount of work that the | 7 /// The fast startup emitter's goal is to minimize the amount of work that the |
| 8 /// JavaScript engine has to do before it can start running user code. | 8 /// JavaScript engine has to do before it can start running user code. |
| 9 /// | 9 /// |
| 10 /// Whenever possible, the emitter uses object literals instead of updating | 10 /// Whenever possible, the emitter uses object literals instead of updating |
| (...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 256 #invokeMain; | 256 #invokeMain; |
| 257 })(); | 257 })(); |
| 258 }'''; | 258 }'''; |
| 259 | 259 |
| 260 /// Deferred fragments (aka 'hunks') are built similarly to the main fragment. | 260 /// Deferred fragments (aka 'hunks') are built similarly to the main fragment. |
| 261 /// | 261 /// |
| 262 /// However, at specific moments they need to contribute their data. | 262 /// However, at specific moments they need to contribute their data. |
| 263 /// For example, once the holders have been created, they are included into | 263 /// For example, once the holders have been created, they are included into |
| 264 /// the main holders. | 264 /// the main holders. |
| 265 const String deferredBoilerplate = ''' | 265 const String deferredBoilerplate = ''' |
| 266 { | |
| 267 #deferredInitializers.current = | |
| 268 function(inherit, mixin, lazy, makeConstList, installTearOff, | 266 function(inherit, mixin, lazy, makeConstList, installTearOff, |
| 269 updateHolder, updateTypes, | 267 updateHolder, updateTypes, |
| 270 setOrUpdateInterceptorsByTag, setOrUpdateLeafTags, | 268 setOrUpdateInterceptorsByTag, setOrUpdateLeafTags, |
| 271 #embeddedGlobalsObject, holdersList, #staticState) { | 269 #embeddedGlobalsObject, holdersList, #staticState) { |
| 272 | 270 |
| 273 // Builds the holders. They only contain the data for new holders. | 271 // Builds the holders. They only contain the data for new holders. |
| 274 #holders; | 272 #holders; |
| 275 // Updates the holders of the main-fragment. Uses the provided holdersList to | 273 // Updates the holders of the main-fragment. Uses the provided holdersList to |
| 276 // access the main holders. | 274 // access the main holders. |
| 277 // The local holders are replaced by the combined holders. This is necessary | 275 // The local holders are replaced by the combined holders. This is necessary |
| (...skipping 14 matching lines...) Expand all Loading... |
| 292 #constants; | 290 #constants; |
| 293 // Initializes the static non-final fields (with their constant values). | 291 // Initializes the static non-final fields (with their constant values). |
| 294 #staticNonFinalFields; | 292 #staticNonFinalFields; |
| 295 // Creates lazy getters for statics that must run initializers on first access. | 293 // Creates lazy getters for statics that must run initializers on first access. |
| 296 #lazyStatics; | 294 #lazyStatics; |
| 297 | 295 |
| 298 updateTypes(#types); | 296 updateTypes(#types); |
| 299 | 297 |
| 300 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | 298 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. |
| 301 #nativeSupport; | 299 #nativeSupport; |
| 302 }; | |
| 303 // TODO(floitsch): this last line should be outside the AST, since it | |
| 304 // requires to know the hash of the part of the code above this comment. | |
| 305 #deferredInitializers[#hash] = #deferredInitializers.current; | |
| 306 }'''; | 300 }'''; |
| 307 | 301 |
| 308 /** | 302 /** |
| 309 * This class builds a JavaScript tree for a given fragment. | 303 * This class builds a JavaScript tree for a given fragment. |
| 310 * | 304 * |
| 311 * A fragment is generally written into a separate file so that it can be | 305 * A fragment is generally written into a separate file so that it can be |
| 312 * loaded dynamically when a deferred library is loaded. | 306 * loaded dynamically when a deferred library is loaded. |
| 313 * | 307 * |
| 314 * This class is stateless and can be reused for different fragments. | 308 * This class is stateless and can be reused for different fragments. |
| 315 */ | 309 */ |
| (...skipping 10 matching lines...) Expand all Loading... |
| 326 js.Expression generateEmbeddedGlobalAccess(String global) => | 320 js.Expression generateEmbeddedGlobalAccess(String global) => |
| 327 modelEmitter.generateEmbeddedGlobalAccess(global); | 321 modelEmitter.generateEmbeddedGlobalAccess(global); |
| 328 | 322 |
| 329 js.Expression generateConstantReference(ConstantValue value) => | 323 js.Expression generateConstantReference(ConstantValue value) => |
| 330 modelEmitter.generateConstantReference(value); | 324 modelEmitter.generateConstantReference(value); |
| 331 | 325 |
| 332 js.Expression classReference(Class cls) { | 326 js.Expression classReference(Class cls) { |
| 333 return js.js('#.#', [cls.holder.name, cls.name]); | 327 return js.js('#.#', [cls.holder.name, cls.name]); |
| 334 } | 328 } |
| 335 | 329 |
| 336 js.Statement emitMainFragment(Program program) { | 330 js.Statement emitMainFragment( |
| 331 Program program, |
| 332 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { |
| 337 MainFragment fragment = program.fragments.first; | 333 MainFragment fragment = program.fragments.first; |
| 338 | 334 |
| 339 return js.js.statement(mainBoilerplate, | 335 return js.js.statement(mainBoilerplate, |
| 340 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), | 336 {'deferredInitializer': emitDeferredInitializerGlobal(program.loadMap), |
| 341 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), | 337 'typeNameProperty': js.string(ModelEmitter.typeNameProperty), |
| 342 'cyclicThrow': backend.emitter.staticFunctionAccess( | 338 'cyclicThrow': backend.emitter.staticFunctionAccess( |
| 343 backend.getCyclicThrowHelper()), | 339 backend.getCyclicThrowHelper()), |
| 344 'operatorIsPrefix': js.string(namer.operatorIsPrefix), | 340 'operatorIsPrefix': js.string(namer.operatorIsPrefix), |
| 345 'tearOffCode': new js.Block(buildTearOffCode(backend)), | 341 'tearOffCode': new js.Block(buildTearOffCode(backend)), |
| 346 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), | 342 'embeddedTypes': generateEmbeddedGlobalAccess(TYPES), |
| (...skipping 11 matching lines...) Expand all Loading... |
| 358 'callName': js.string(namer.callNameField), | 354 'callName': js.string(namer.callNameField), |
| 359 'argumentCount': js.string(namer.requiredParameterField), | 355 'argumentCount': js.string(namer.requiredParameterField), |
| 360 'defaultArgumentValues': js.string(namer.defaultValuesField), | 356 'defaultArgumentValues': js.string(namer.defaultValuesField), |
| 361 'prototypes': emitPrototypes(fragment), | 357 'prototypes': emitPrototypes(fragment), |
| 362 'inheritance': emitInheritance(fragment), | 358 'inheritance': emitInheritance(fragment), |
| 363 'aliases': emitInstanceMethodAliases(fragment), | 359 'aliases': emitInstanceMethodAliases(fragment), |
| 364 'tearOffs': emitInstallTearOffs(fragment), | 360 'tearOffs': emitInstallTearOffs(fragment), |
| 365 'constants': emitConstants(fragment), | 361 'constants': emitConstants(fragment), |
| 366 'staticNonFinalFields': emitStaticNonFinalFields(fragment), | 362 'staticNonFinalFields': emitStaticNonFinalFields(fragment), |
| 367 'lazyStatics': emitLazilyInitializedStatics(fragment), | 363 'lazyStatics': emitLazilyInitializedStatics(fragment), |
| 368 'embeddedGlobals': emitEmbeddedGlobals(program), | 364 'embeddedGlobals': emitEmbeddedGlobals(program, deferredLoadHashes), |
| 369 'nativeSupport': program.needsNativeSupport | 365 'nativeSupport': program.needsNativeSupport |
| 370 ? emitNativeSupport(fragment) | 366 ? emitNativeSupport(fragment) |
| 371 : new js.EmptyStatement(), | 367 : new js.EmptyStatement(), |
| 372 'invokeMain': fragment.invokeMain, | 368 'invokeMain': fragment.invokeMain, |
| 373 }); | 369 }); |
| 374 } | 370 } |
| 375 | 371 |
| 376 js.Statement emitDeferredFragment(DeferredFragment fragment, | 372 js.Expression emitDeferredFragment(DeferredFragment fragment, |
| 377 js.Expression deferredTypes, | 373 js.Expression deferredTypes, |
| 378 List<Holder> holders) { | 374 List<Holder> holders) { |
| 379 List<js.Statement> updateHolderAssignments = <js.Statement>[]; | 375 List<js.Statement> updateHolderAssignments = <js.Statement>[]; |
| 380 for (int i = 0; i < holders.length; i++) { | 376 for (int i = 0; i < holders.length; i++) { |
| 381 Holder holder = holders[i]; | 377 Holder holder = holders[i]; |
| 382 if (holder.isStaticStateHolder) continue; | 378 if (holder.isStaticStateHolder) continue; |
| 383 updateHolderAssignments.add(js.js.statement( | 379 updateHolderAssignments.add(js.js.statement( |
| 384 '#holder = updateHolder(holdersList[#index], #holder)', | 380 '#holder = updateHolder(holdersList[#index], #holder)', |
| 385 {'index': js.number(i), | 381 {'index': js.number(i), |
| 386 'holder': new js.VariableUse(holder.name)})); | 382 'holder': new js.VariableUse(holder.name)})); |
| 387 } | 383 } |
| 388 | 384 |
| 389 // TODO(floitsch): if name is not set, run through all functions and set the | 385 // TODO(floitsch): if name is not set, run through all functions and set the |
| 390 // name for IE. | 386 // name for IE. |
| 391 // TODO(floitsch): don't just reference 'init'. | 387 // TODO(floitsch): don't just reference 'init'. |
| 392 return js.js.statement(deferredBoilerplate, | 388 return js.js(deferredBoilerplate, |
| 393 {'deferredInitializers': | 389 {'embeddedGlobalsObject': new js.Parameter('init'), |
| 394 js.js('#', ModelEmitter.deferredInitializersGlobal), | 390 'staticState': new js.Parameter(namer.staticStateHolder), |
| 395 'embeddedGlobalsObject': new js.Parameter('init'), | 391 'holders': emitHolders(holders, fragment), |
| 396 'staticState': new js.Parameter(namer.staticStateHolder), | 392 'updateHolders': new js.Block(updateHolderAssignments), |
| 397 'holders': emitHolders(holders, fragment), | 393 'prototypes': emitPrototypes(fragment), |
| 398 'updateHolders': new js.Block(updateHolderAssignments), | 394 'inheritance': emitInheritance(fragment), |
| 399 'prototypes': emitPrototypes(fragment), | 395 'aliases': emitInstanceMethodAliases(fragment), |
| 400 'inheritance': emitInheritance(fragment), | 396 'tearOffs': emitInstallTearOffs(fragment), |
| 401 'aliases': emitInstanceMethodAliases(fragment), | 397 'constants': emitConstants(fragment), |
| 402 'tearOffs': emitInstallTearOffs(fragment), | 398 'staticNonFinalFields': emitStaticNonFinalFields(fragment), |
| 403 'constants': emitConstants(fragment), | 399 'lazyStatics': emitLazilyInitializedStatics(fragment), |
| 404 'staticNonFinalFields': emitStaticNonFinalFields(fragment), | 400 'types': deferredTypes, |
| 405 'lazyStatics': emitLazilyInitializedStatics(fragment), | 401 // TODO(floitsch): only call emitNativeSupport if we need native. |
| 406 'types': deferredTypes, | 402 'nativeSupport': emitNativeSupport(fragment), |
| 407 // TODO(floitsch): only call emitNativeSupport if we need native. | |
| 408 'nativeSupport': emitNativeSupport(fragment), | |
| 409 'hash': js.number(fragment.hashCode), | |
| 410 }); | 403 }); |
| 411 } | 404 } |
| 412 | 405 |
| 413 js.Statement emitDeferredInitializerGlobal(Map loadMap) { | 406 js.Statement emitDeferredInitializerGlobal(Map loadMap) { |
| 414 if (loadMap.isEmpty) return new js.Block.empty(); | 407 if (loadMap.isEmpty) return new js.Block.empty(); |
| 415 | 408 |
| 416 return js.js.statement(""" | 409 return js.js.statement(""" |
| 417 if (typeof(${ModelEmitter.deferredInitializersGlobal}) === 'undefined') | 410 if (typeof(${ModelEmitter.deferredInitializersGlobal}) === 'undefined') |
| 418 var ${ModelEmitter.deferredInitializersGlobal} = Object.create(null);"""); | 411 var ${ModelEmitter.deferredInitializersGlobal} = Object.create(null);"""); |
| 419 } | 412 } |
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 863 } | 856 } |
| 864 | 857 |
| 865 /// Emits the embedded globals that are needed for deferred loading. | 858 /// Emits the embedded globals that are needed for deferred loading. |
| 866 /// | 859 /// |
| 867 /// This function is only invoked for the main fragment. | 860 /// This function is only invoked for the main fragment. |
| 868 /// | 861 /// |
| 869 /// The [loadMap] contains a map from load-ids (for each deferred library) | 862 /// The [loadMap] contains a map from load-ids (for each deferred library) |
| 870 /// to the list of generated fragments that must be installed when the | 863 /// to the list of generated fragments that must be installed when the |
| 871 /// deferred library is loaded. | 864 /// deferred library is loaded. |
| 872 Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading( | 865 Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading( |
| 873 Map<String, List<Fragment>> loadMap) { | 866 Map<String, List<Fragment>> loadMap, |
| 867 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { |
| 874 if (loadMap.isEmpty) return []; | 868 if (loadMap.isEmpty) return []; |
| 875 | 869 |
| 876 List<js.Property> globals = <js.Property>[]; | 870 List<js.Property> globals = <js.Property>[]; |
| 877 | 871 |
| 878 js.ArrayInitializer fragmentUris(List<Fragment> fragments) { | 872 js.ArrayInitializer fragmentUris(List<Fragment> fragments) { |
| 879 return js.stringArray(fragments.map((DeferredFragment fragment) => | 873 return js.stringArray(fragments.map((DeferredFragment fragment) => |
| 880 "${fragment.outputFileName}.$deferredExtension")); | 874 "${fragment.outputFileName}.$deferredExtension")); |
| 881 } | 875 } |
| 882 js.ArrayInitializer fragmentHashes(List<Fragment> fragments) { | 876 js.ArrayInitializer fragmentHashes(List<Fragment> fragments) { |
| 883 // TODO(floitsch): the hash must depend on the generated code. | 877 return new js.ArrayInitializer( |
| 884 return js.numArray( | 878 fragments |
| 885 fragments.map((DeferredFragment fragment) => fragment.hashCode)); | 879 .map((fragment) => deferredLoadHashes[fragment]) |
| 880 .toList(growable: false)); |
| 886 } | 881 } |
| 887 | 882 |
| 888 List<js.Property> uris = new List<js.Property>(loadMap.length); | 883 List<js.Property> uris = new List<js.Property>(loadMap.length); |
| 889 List<js.Property> hashes = new List<js.Property>(loadMap.length); | 884 List<js.Property> hashes = new List<js.Property>(loadMap.length); |
| 890 int count = 0; | 885 int count = 0; |
| 891 loadMap.forEach((String loadId, List<Fragment> fragmentList) { | 886 loadMap.forEach((String loadId, List<Fragment> fragmentList) { |
| 892 uris[count] = | 887 uris[count] = |
| 893 new js.Property(js.string(loadId), fragmentUris(fragmentList)); | 888 new js.Property(js.string(loadId), fragmentUris(fragmentList)); |
| 894 hashes[count] = | 889 hashes[count] = |
| 895 new js.Property(js.string(loadId), fragmentHashes(fragmentList)); | 890 new js.Property(js.string(loadId), fragmentHashes(fragmentList)); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 989 | 984 |
| 990 metadataGlobals.add(createGlobal(program.metadata, METADATA)); | 985 metadataGlobals.add(createGlobal(program.metadata, METADATA)); |
| 991 js.Expression types = | 986 js.Expression types = |
| 992 program.metadataTypesForOutputUnit(program.mainFragment.outputUnit); | 987 program.metadataTypesForOutputUnit(program.mainFragment.outputUnit); |
| 993 metadataGlobals.add(createGlobal(types, TYPES)); | 988 metadataGlobals.add(createGlobal(types, TYPES)); |
| 994 | 989 |
| 995 return metadataGlobals; | 990 return metadataGlobals; |
| 996 } | 991 } |
| 997 | 992 |
| 998 /// Emits all embedded globals. | 993 /// Emits all embedded globals. |
| 999 js.Block emitEmbeddedGlobals(Program program) { | 994 js.Block emitEmbeddedGlobals( |
| 995 Program program, |
| 996 Map<DeferredFragment, _DeferredFragmentHash> deferredLoadHashes) { |
| 1000 List<js.Property> globals = <js.Property>[]; | 997 List<js.Property> globals = <js.Property>[]; |
| 1001 | 998 |
| 1002 if (program.loadMap.isNotEmpty) { | 999 if (program.loadMap.isNotEmpty) { |
| 1003 globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap)); | 1000 globals.addAll(emitEmbeddedGlobalsForDeferredLoading( |
| 1001 program.loadMap, deferredLoadHashes)); |
| 1004 } | 1002 } |
| 1005 | 1003 |
| 1006 if (program.typeToInterceptorMap != null) { | 1004 if (program.typeToInterceptorMap != null) { |
| 1007 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), | 1005 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), |
| 1008 program.typeToInterceptorMap)); | 1006 program.typeToInterceptorMap)); |
| 1009 } | 1007 } |
| 1010 | 1008 |
| 1011 if (program.hasIsolateSupport) { | 1009 if (program.hasIsolateSupport) { |
| 1012 String staticStateName = namer.staticStateHolder; | 1010 String staticStateName = namer.staticStateHolder; |
| 1013 // TODO(floitsch): this doesn't create a new isolate, but just reuses | 1011 // TODO(floitsch): this doesn't create a new isolate, but just reuses |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1097 } | 1095 } |
| 1098 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", | 1096 statements.add(js.js.statement("setOrUpdateInterceptorsByTag(#);", |
| 1099 js.objectLiteral(interceptorsByTag))); | 1097 js.objectLiteral(interceptorsByTag))); |
| 1100 statements.add(js.js.statement("setOrUpdateLeafTags(#);", | 1098 statements.add(js.js.statement("setOrUpdateLeafTags(#);", |
| 1101 js.objectLiteral(leafTags))); | 1099 js.objectLiteral(leafTags))); |
| 1102 statements.add(subclassAssignment); | 1100 statements.add(subclassAssignment); |
| 1103 | 1101 |
| 1104 return new js.Block(statements); | 1102 return new js.Block(statements); |
| 1105 } | 1103 } |
| 1106 } | 1104 } |
| OLD | NEW |