Chromium Code Reviews| 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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 | 230 |
| 231 // Sets the prototypes of classes. | 231 // Sets the prototypes of classes. |
| 232 #prototypes; | 232 #prototypes; |
| 233 // Sets aliases of methods (on the prototypes of classes). | 233 // Sets aliases of methods (on the prototypes of classes). |
| 234 #aliases; | 234 #aliases; |
| 235 // Installs the tear-offs of functions. | 235 // Installs the tear-offs of functions. |
| 236 #tearOffs; | 236 #tearOffs; |
| 237 // Builds the inheritance structure. | 237 // Builds the inheritance structure. |
| 238 #inheritance; | 238 #inheritance; |
| 239 | 239 |
| 240 // Emits the embedded globals. | |
| 241 #embeddedGlobals; | |
| 242 | |
| 243 // Sets up the native support. | |
| 244 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | |
| 245 #nativeSupport; | |
| 246 | |
| 247 // Instantiates all constants. | 240 // Instantiates all constants. |
| 248 #constants; | 241 #constants; |
| 249 // Initializes the static non-final fields (with their constant values). | 242 // Initializes the static non-final fields (with their constant values). |
| 250 #staticNonFinalFields; | 243 #staticNonFinalFields; |
| 251 // Creates lazy getters for statics that must run initializers on first access. | 244 // Creates lazy getters for statics that must run initializers on first access. |
| 252 #lazyStatics; | 245 #lazyStatics; |
| 253 | 246 |
| 247 // Emits the embedded globals. | |
| 248 #embeddedGlobals; | |
| 249 | |
| 250 // Sets up the native support. | |
| 251 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | |
| 252 #nativeSupport; | |
| 253 | |
| 254 // Invokes main (making sure that it records the 'current-script' value). | 254 // Invokes main (making sure that it records the 'current-script' value). |
| 255 #invokeMain; | 255 #invokeMain; |
| 256 })(); | 256 })(); |
| 257 }'''; | 257 }'''; |
| 258 | 258 |
| 259 /// Deferred fragments (aka 'hunks') are built similarly to the main fragment. | 259 /// Deferred fragments (aka 'hunks') are built similarly to the main fragment. |
| 260 /// | 260 /// |
| 261 /// However, at specific moments they need to contribute their data. | 261 /// However, at specific moments they need to contribute their data. |
| 262 /// For example, once the holders have been created, they are included into | 262 /// For example, once the holders have been created, they are included into |
| 263 /// the main holders. | 263 /// the main holders. |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 278 #updateHolders; | 278 #updateHolders; |
| 279 // Sets the prototypes of the new classes. | 279 // Sets the prototypes of the new classes. |
| 280 #prototypes; | 280 #prototypes; |
| 281 // Sets aliases of methods (on the prototypes of classes). | 281 // Sets aliases of methods (on the prototypes of classes). |
| 282 #aliases; | 282 #aliases; |
| 283 // Installs the tear-offs of functions. | 283 // Installs the tear-offs of functions. |
| 284 #tearOffs; | 284 #tearOffs; |
| 285 // Builds the inheritance structure. | 285 // Builds the inheritance structure. |
| 286 #inheritance; | 286 #inheritance; |
| 287 | 287 |
| 288 updateTypes(#types); | |
| 289 | |
| 290 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | |
| 291 #nativeSupport; | |
| 292 | |
| 293 // Instantiates all constants of this deferred fragment. | 288 // Instantiates all constants of this deferred fragment. |
| 294 // Note that the constant-holder has been updated earlier and storing the | 289 // Note that the constant-holder has been updated earlier and storing the |
| 295 // constant values in the constant-holder makes them available globally. | 290 // constant values in the constant-holder makes them available globally. |
| 296 #constants; | 291 #constants; |
| 297 // Initializes the static non-final fields (with their constant values). | 292 // Initializes the static non-final fields (with their constant values). |
| 298 #staticNonFinalFields; | 293 #staticNonFinalFields; |
| 299 // Creates lazy getters for statics that must run initializers on first access. | 294 // Creates lazy getters for statics that must run initializers on first access. |
| 300 #lazyStatics; | 295 #lazyStatics; |
| 296 | |
| 297 updateTypes(#types); | |
| 298 | |
| 299 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | |
| 300 #nativeSupport; | |
| 301 }; | 301 }; |
| 302 // TODO(floitsch): this last line should be outside the AST, since it | 302 // TODO(floitsch): this last line should be outside the AST, since it |
| 303 // requires to know the hash of the part of the code above this comment. | 303 // requires to know the hash of the part of the code above this comment. |
| 304 #deferredInitializers[#hash] = #deferredInitializers.current; | 304 #deferredInitializers[#hash] = #deferredInitializers.current; |
| 305 }'''; | 305 }'''; |
| 306 | 306 |
| 307 /** | 307 /** |
| 308 * This class builds a JavaScript tree for a given fragment. | 308 * This class builds a JavaScript tree for a given fragment. |
| 309 * | 309 * |
| 310 * A fragment is generally written into a separate file so that it can be | 310 * A fragment is generally written into a separate file so that it can be |
| (...skipping 543 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 854 return js.js.statement("lazy(#, #, #, #);", | 854 return js.js.statement("lazy(#, #, #, #);", |
| 855 [field.holder.name, | 855 [field.holder.name, |
| 856 js.quoteName(field.name), | 856 js.quoteName(field.name), |
| 857 js.quoteName(namer.deriveLazyInitializerName(field.name)), | 857 js.quoteName(namer.deriveLazyInitializerName(field.name)), |
| 858 field.code]); | 858 field.code]); |
| 859 }); | 859 }); |
| 860 | 860 |
| 861 return new js.Block(statements.toList()); | 861 return new js.Block(statements.toList()); |
| 862 } | 862 } |
| 863 | 863 |
| 864 emitEmbeddedGlobals(program) { | 864 /// Emits the embedded globals that are needed for deferred loading. |
| 865 throw new UnimplementedError('emitEmbeddedGlobals'); | 865 /// |
| 866 /// This function is only invoked for the main fragment. | |
| 867 /// | |
| 868 /// The [loadMap] contains a map from load-ids (for each deferred library) | |
| 869 /// to the list of generated fragments that must be installed when the | |
| 870 /// deferred library is loaded. | |
| 871 Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading( | |
| 872 Map<String, List<Fragment>> loadMap) { | |
| 873 if (loadMap.isEmpty) return []; | |
| 874 | |
| 875 List<js.Property> globals = <js.Property>[]; | |
| 876 | |
| 877 js.ArrayInitializer fragmentUris(List<Fragment> fragments) { | |
| 878 return js.stringArray(fragments.map((DeferredFragment fragment) => | |
| 879 "${fragment.outputFileName}.${ModelEmitter.deferredExtension}")); | |
| 880 } | |
| 881 js.ArrayInitializer fragmentHashes(List<Fragment> fragments) { | |
| 882 // TODO(floitsch): the hash must depend on the generated code. | |
| 883 return js.numArray( | |
| 884 fragments.map((DeferredFragment fragment) => fragment.hashCode)); | |
| 885 } | |
| 886 | |
| 887 List<js.Property> uris = new List<js.Property>(loadMap.length); | |
| 888 List<js.Property> hashes = new List<js.Property>(loadMap.length); | |
| 889 int count = 0; | |
| 890 loadMap.forEach((String loadId, List<Fragment> fragmentList) { | |
| 891 uris[count] = | |
| 892 new js.Property(js.string(loadId), fragmentUris(fragmentList)); | |
| 893 hashes[count] = | |
| 894 new js.Property(js.string(loadId), fragmentHashes(fragmentList)); | |
| 895 count++; | |
| 896 }); | |
| 897 | |
| 898 globals.add(new js.Property(js.string(DEFERRED_LIBRARY_URIS), | |
| 899 new js.ObjectInitializer(uris))); | |
| 900 globals.add(new js.Property(js.string(DEFERRED_LIBRARY_HASHES), | |
| 901 new js.ObjectInitializer(hashes))); | |
| 902 globals.add(new js.Property(js.string(DEFERRED_INITIALIZED), | |
| 903 js.js("Object.create(null)"))); | |
| 904 | |
| 905 String deferredGlobal = ModelEmitter.deferredInitializersGlobal; | |
| 906 js.Expression isHunkLoadedFunction = | |
| 907 js.js("function(hash) { return !!$deferredGlobal[hash]; }"); | |
| 908 globals.add(new js.Property(js.string(IS_HUNK_LOADED), | |
| 909 isHunkLoadedFunction)); | |
| 910 | |
| 911 js.Expression isHunkInitializedFunction = | |
| 912 js.js("function(hash) { return !!#deferredInitialized[hash]; }", | |
| 913 {'deferredInitialized': | |
| 914 generateEmbeddedGlobalAccess(DEFERRED_INITIALIZED)}); | |
| 915 globals.add(new js.Property(js.string(IS_HUNK_INITIALIZED), | |
| 916 isHunkInitializedFunction)); | |
| 917 | |
| 918 /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the | |
| 919 /// deferred hunk. | |
| 920 js.Expression initializeLoadedHunkFunction = | |
| 921 js.js(""" | |
| 922 function(hash) { | |
| 923 initializeDeferredHunk($deferredGlobal[hash]); | |
| 924 #deferredInitialized[hash] = true; | |
| 925 }""", {'deferredInitialized': | |
| 926 generateEmbeddedGlobalAccess(DEFERRED_INITIALIZED)}); | |
| 927 | |
| 928 globals.add(new js.Property(js.string(INITIALIZE_LOADED_HUNK), | |
| 929 initializeLoadedHunkFunction)); | |
| 930 | |
| 931 return globals; | |
| 932 } | |
| 933 | |
| 934 /// Emits the [MANGLED_GLOBAL_NAMES] embedded global. | |
| 935 /// | |
| 936 /// This global maps minified names for selected classes (some important | |
| 937 /// core classes, and some native classes) to their unminified names. | |
| 938 js.Property emitMangledGlobalNames() { | |
| 939 List<js.Property> names = <js.Property>[]; | |
| 940 | |
| 941 // We want to keep the original names for the most common core classes when | |
| 942 // calling toString on them. | |
| 943 List<ClassElement> nativeClassesNeedingUnmangledName = | |
| 944 [compiler.intClass, compiler.doubleClass, compiler.numClass, | |
| 945 compiler.stringClass, compiler.boolClass, compiler.nullClass, | |
| 946 compiler.listClass]; | |
| 947 // TODO(floitsch): this should probably be on a per-fragment basis. | |
| 948 nativeClassesNeedingUnmangledName.forEach((element) { | |
| 949 names.add(new js.Property(js.quoteName(namer.className(element)), | |
| 950 js.string(element.name))); | |
| 951 }); | |
| 952 | |
| 953 return new js.Property(js.string(MANGLED_GLOBAL_NAMES), | |
| 954 new js.ObjectInitializer(names)); | |
| 955 } | |
| 956 | |
| 957 /// Emits the [GET_TYPE_FROM_NAME] embedded global. | |
| 958 /// | |
| 959 /// This embedded global provides a way to go from a class name (which is | |
| 960 /// also the constructor's name) to the constructor itself. | |
| 961 js.Property emitGetTypeFromName() { | |
| 962 // TODO(floitsch): Fix getTypeFromName. It's too inefficient. | |
| 963 // The current implementation relies on the fact that the names in holders | |
| 964 // are unique across all holders. | |
| 965 // TODO(floitsch): constants and other globals may share the same name. | |
| 966 // If a global happens to have the same (minified) name this code breaks. | |
| 967 // A follow-up CL has a fix for this. | |
| 968 js.Expression function = | |
| 969 js.js( """function(name) { | |
| 970 for (var i = 0; i < holders.length; i++) { | |
| 971 // Relies on the fact that all variables are unique. | |
| 972 if (holders[i][name]) return holders[i][name]; | |
| 973 } | |
| 974 }"""); | |
| 975 return new js.Property(js.string(GET_TYPE_FROM_NAME), function); | |
| 976 } | |
| 977 | |
| 978 /// Emits the [METADATA] embedded global. | |
| 979 /// | |
| 980 /// The metadata itself has already been computed earlier and is stored in | |
| 981 /// the [program]. | |
| 982 List<js.Property> emitMetadata(Program program) { | |
| 983 List<js.Property> metadataGlobals = <js.Property>[]; | |
| 984 | |
| 985 js.Property createGlobal(js.Expression metadata, String global) { | |
| 986 return new js.Property(js.string(global), metadata); | |
| 987 } | |
| 988 | |
| 989 metadataGlobals.add(createGlobal(program.metadata, METADATA)); | |
| 990 js.Expression types = | |
| 991 program.metadataTypesForOutputUnit(program.mainFragment.outputUnit); | |
| 992 metadataGlobals.add(createGlobal(types, TYPES)); | |
| 993 | |
| 994 return metadataGlobals; | |
| 995 } | |
| 996 | |
| 997 /// Emits all embedded globals. | |
| 998 js.Block emitEmbeddedGlobals(Program program) { | |
| 999 List<js.Property> globals = <js.Property>[]; | |
| 1000 | |
| 1001 if (program.loadMap.isNotEmpty) { | |
| 1002 globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap)); | |
| 1003 } | |
| 1004 | |
| 1005 if (program.typeToInterceptorMap != null) { | |
| 1006 globals.add(new js.Property(js.string(TYPE_TO_INTERCEPTOR_MAP), | |
| 1007 program.typeToInterceptorMap)); | |
| 1008 } | |
| 1009 | |
| 1010 if (program.hasIsolateSupport) { | |
| 1011 String staticStateName = namer.staticStateHolder; | |
| 1012 // TODO(floitsch): this doesn't create a new isolate, but just reuses | |
| 1013 // the current static state. Since we don't run multiple isolates in the | |
| 1014 // same JavaScript context (except for testing) this shouldn't have any | |
| 1015 // impact on real-world programs, though. | |
| 1016 globals.add( | |
| 1017 new js.Property(js.string(CREATE_NEW_ISOLATE), | |
| 1018 js.js('function () { return $staticStateName; }'))); | |
| 1019 // TODO(floitsch): add remaining isolate functions. | |
| 1020 } | |
| 1021 | |
| 1022 globals.add(emitMangledGlobalNames()); | |
| 1023 | |
| 1024 globals.add(emitGetTypeFromName()); | |
| 1025 | |
| 1026 globals.addAll(emitMetadata(program)); | |
| 1027 | |
| 1028 if (program.needsNativeSupport) { | |
| 1029 globals.add(new js.Property(js.string(INTERCEPTORS_BY_TAG), | |
| 1030 new js.LiteralNull())); | |
| 1031 globals.add(new js.Property(js.string(LEAF_TAGS), | |
| 1032 new js.LiteralNull())); | |
| 1033 } | |
| 1034 | |
| 1035 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals); | |
| 1036 | |
| 1037 List<js.Statement> statements = | |
| 1038 [new js.ExpressionStatement( | |
| 1039 new js.VariableDeclarationList( | |
| 1040 [new js.VariableInitialization( | |
| 1041 new js.VariableDeclaration("init", allowRename: false), | |
| 1042 globalsObject)]))]; | |
|
Siggi Cherem (dart-lang)
2015/07/22 23:16:29
this makes me wonder if there are more features we
floitsch
2015/07/29 17:47:59
I actually think that we should be able to rename
| |
| 1043 return new js.Block(statements); | |
| 866 } | 1044 } |
| 867 | 1045 |
| 868 emitNativeSupport(fragment) { | 1046 emitNativeSupport(fragment) { |
| 869 throw new UnimplementedError('emitNativeSupport'); | 1047 throw new UnimplementedError('emitNativeSupport'); |
| 870 } | 1048 } |
| 871 } | 1049 } |
| OLD | NEW |