| 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 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 231 | 231 |
| 232 // Sets the prototypes of classes. | 232 // Sets the prototypes of classes. |
| 233 #prototypes; | 233 #prototypes; |
| 234 // Sets aliases of methods (on the prototypes of classes). | 234 // Sets aliases of methods (on the prototypes of classes). |
| 235 #aliases; | 235 #aliases; |
| 236 // Installs the tear-offs of functions. | 236 // Installs the tear-offs of functions. |
| 237 #tearOffs; | 237 #tearOffs; |
| 238 // Builds the inheritance structure. | 238 // Builds the inheritance structure. |
| 239 #inheritance; | 239 #inheritance; |
| 240 | 240 |
| 241 // Emits the embedded globals. | |
| 242 #embeddedGlobals; | |
| 243 | |
| 244 // Sets up the native support. | |
| 245 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | |
| 246 #nativeSupport; | |
| 247 | |
| 248 // Instantiates all constants. | 241 // Instantiates all constants. |
| 249 #constants; | 242 #constants; |
| 250 // Initializes the static non-final fields (with their constant values). | 243 // Initializes the static non-final fields (with their constant values). |
| 251 #staticNonFinalFields; | 244 #staticNonFinalFields; |
| 252 // Creates lazy getters for statics that must run initializers on first access. | 245 // Creates lazy getters for statics that must run initializers on first access. |
| 253 #lazyStatics; | 246 #lazyStatics; |
| 254 | 247 |
| 248 // Emits the embedded globals. |
| 249 #embeddedGlobals; |
| 250 |
| 251 // Sets up the native support. |
| 252 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. |
| 253 #nativeSupport; |
| 254 |
| 255 // Invokes main (making sure that it records the 'current-script' value). | 255 // Invokes main (making sure that it records the 'current-script' value). |
| 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. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 279 #updateHolders; | 279 #updateHolders; |
| 280 // Sets the prototypes of the new classes. | 280 // Sets the prototypes of the new classes. |
| 281 #prototypes; | 281 #prototypes; |
| 282 // Sets aliases of methods (on the prototypes of classes). | 282 // Sets aliases of methods (on the prototypes of classes). |
| 283 #aliases; | 283 #aliases; |
| 284 // Installs the tear-offs of functions. | 284 // Installs the tear-offs of functions. |
| 285 #tearOffs; | 285 #tearOffs; |
| 286 // Builds the inheritance structure. | 286 // Builds the inheritance structure. |
| 287 #inheritance; | 287 #inheritance; |
| 288 | 288 |
| 289 updateTypes(#types); | |
| 290 | |
| 291 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. | |
| 292 #nativeSupport; | |
| 293 | |
| 294 // Instantiates all constants of this deferred fragment. | 289 // Instantiates all constants of this deferred fragment. |
| 295 // Note that the constant-holder has been updated earlier and storing the | 290 // Note that the constant-holder has been updated earlier and storing the |
| 296 // constant values in the constant-holder makes them available globally. | 291 // constant values in the constant-holder makes them available globally. |
| 297 #constants; | 292 #constants; |
| 298 // Initializes the static non-final fields (with their constant values). | 293 // Initializes the static non-final fields (with their constant values). |
| 299 #staticNonFinalFields; | 294 #staticNonFinalFields; |
| 300 // Creates lazy getters for statics that must run initializers on first access. | 295 // Creates lazy getters for statics that must run initializers on first access. |
| 301 #lazyStatics; | 296 #lazyStatics; |
| 297 |
| 298 updateTypes(#types); |
| 299 |
| 300 // Native-support uses setOrUpdateInterceptorsByTag and setOrUpdateLeafTags. |
| 301 #nativeSupport; |
| 302 }; | 302 }; |
| 303 // TODO(floitsch): this last line should be outside the AST, since it | 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. | 304 // requires to know the hash of the part of the code above this comment. |
| 305 #deferredInitializers[#hash] = #deferredInitializers.current; | 305 #deferredInitializers[#hash] = #deferredInitializers.current; |
| 306 }'''; | 306 }'''; |
| 307 | 307 |
| 308 /** | 308 /** |
| 309 * This class builds a JavaScript tree for a given fragment. | 309 * This class builds a JavaScript tree for a given fragment. |
| 310 * | 310 * |
| 311 * A fragment is generally written into a separate file so that it can be | 311 * A fragment is generally written into a separate file so that it can be |
| (...skipping 542 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.Statement 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 return js.js.statement('var init = #;', globalsObject); |
| 866 } | 1038 } |
| 867 | 1039 |
| 868 emitNativeSupport(fragment) { | 1040 emitNativeSupport(fragment) { |
| 869 throw new UnimplementedError('emitNativeSupport'); | 1041 throw new UnimplementedError('emitNativeSupport'); |
| 870 } | 1042 } |
| 871 } | 1043 } |
| OLD | NEW |