mozJSModuleLoader.h (8503B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozJSModuleLoader_h 8 #define mozJSModuleLoader_h 9 10 #include "SyncModuleLoader.h" 11 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS 12 #include "mozilla/dom/ScriptSettings.h" 13 #include "mozilla/FileLocation.h" 14 #include "mozilla/Maybe.h" // mozilla::Maybe 15 #include "mozilla/RefPtr.h" // RefPtr, mozilla::StaticRefPtr 16 #include "mozilla/StaticPtr.h" 17 #include "mozilla/ThreadLocal.h" // MOZ_THREAD_LOCAL 18 #include "nsIURI.h" 19 #include "nsClassHashtable.h" 20 #include "jsapi.h" 21 #include "js/CompileOptions.h" 22 #include "js/experimental/JSStencil.h" 23 24 #include "xpcpublic.h" 25 26 class nsIFile; 27 class ModuleLoaderInfo; 28 29 namespace mozilla { 30 class ScriptPreloader; 31 } // namespace mozilla 32 33 namespace JS::loader { 34 class ModuleLoadRequest; 35 } // namespace JS::loader 36 37 #if defined(NIGHTLY_BUILD) || defined(MOZ_DEV_EDITION) || defined(DEBUG) 38 # define STARTUP_RECORDER_ENABLED 39 #endif 40 41 namespace mozilla::loader { 42 43 class NonSharedGlobalSyncModuleLoaderScope; 44 45 } // namespace mozilla::loader 46 47 class mozJSModuleLoader final { 48 public: 49 NS_INLINE_DECL_REFCOUNTING(mozJSModuleLoader); 50 51 // Returns the list of all ESMs. 52 nsresult GetLoadedESModules(nsTArray<nsCString>& aLoadedModules); 53 54 nsresult GetModuleImportStack(const nsACString& aLocation, 55 nsACString& aRetval); 56 57 void FindTargetObject(JSContext* aCx, JS::MutableHandleObject aTargetObject); 58 59 static void InitStatics(); 60 static void UnloadLoaders(); 61 static void ShutdownLoaders(); 62 63 static mozJSModuleLoader* Get() { 64 MOZ_ASSERT(sSelf, "Should have already created the module loader"); 65 return sSelf; 66 } 67 68 JSObject* GetSharedGlobal() { 69 MOZ_ASSERT(mLoaderGlobal); 70 return mLoaderGlobal; 71 } 72 73 private: 74 void InitSharedGlobal(JSContext* aCx); 75 76 void InitSyncModuleLoaderForGlobal(nsIGlobalObject* aGlobal); 77 void DisconnectSyncModuleLoaderFromGlobal(); 78 79 friend class mozilla::loader::NonSharedGlobalSyncModuleLoaderScope; 80 81 public: 82 static mozJSModuleLoader* GetDevToolsLoader() { return sDevToolsLoader; } 83 static mozJSModuleLoader* GetOrCreateDevToolsLoader(JSContext* aCx); 84 85 // Synchronously load an ES6 module and all its dependencies. 86 nsresult ImportESModule(JSContext* aCx, const nsACString& aResourceURI, 87 JS::MutableHandleObject aModuleNamespace); 88 89 #ifdef STARTUP_RECORDER_ENABLED 90 void RecordImportStack(JSContext* aCx, 91 JS::loader::ModuleLoadRequest* aRequest); 92 #endif 93 94 nsresult IsESModuleLoaded(const nsACString& aResourceURI, bool* aRetval); 95 bool IsLoaderGlobal(JSObject* aObj) { return mLoaderGlobal == aObj; } 96 bool IsDevToolsLoader() const { return this == sDevToolsLoader; } 97 98 static bool IsSharedSystemGlobal(nsIGlobalObject* aGlobal); 99 static bool IsDevToolsLoaderGlobal(nsIGlobalObject* aGlobal); 100 101 // Public methods for use from SyncModuleLoader. 102 static nsresult LoadSingleModuleScript( 103 mozilla::loader::SyncModuleLoader* aModuleLoader, JSContext* aCx, 104 JS::loader::ModuleLoadRequest* aRequest, 105 JS::MutableHandleScript aScriptOut); 106 107 private: 108 static nsresult ReadScriptOnMainThread(JSContext* aCx, 109 const nsCString& aLocation, 110 nsCString& aData); 111 static nsresult LoadSingleModuleScriptOnWorker( 112 mozilla::loader::SyncModuleLoader* aModuleLoader, JSContext* aCx, 113 JS::loader::ModuleLoadRequest* aRequest, 114 JS::MutableHandleScript aScriptOut); 115 116 public: 117 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf); 118 119 bool DefineJSServices(JSContext* aCx, JS::Handle<JSObject*> aGlobal); 120 121 protected: 122 mozJSModuleLoader(); 123 ~mozJSModuleLoader(); 124 125 friend class XPCJSRuntime; 126 127 private: 128 static mozilla::StaticRefPtr<mozJSModuleLoader> sSelf; 129 static mozilla::StaticRefPtr<mozJSModuleLoader> sDevToolsLoader; 130 131 void Unload(); 132 void UnloadModules(); 133 134 void CreateLoaderGlobal(JSContext* aCx, const nsACString& aLocation, 135 JS::MutableHandleObject aGlobal); 136 void CreateDevToolsLoaderGlobal(JSContext* aCx, const nsACString& aLocation, 137 JS::MutableHandleObject aGlobal); 138 139 bool CreateJSServices(JSContext* aCx); 140 141 static nsresult GetSourceFile(nsIURI* aResolvedURI, nsIFile** aSourceFileOut); 142 143 static bool LocationIsRealFile(nsIURI* aURI); 144 145 static void SetModuleOptions(JS::CompileOptions& aOptions); 146 147 // Get the script for a given location, either from a cached stencil or by 148 // compiling it from source. 149 static nsresult GetScriptForLocation(JSContext* aCx, ModuleLoaderInfo& aInfo, 150 nsIFile* aModuleFile, bool aUseMemMap, 151 JS::MutableHandleScript aScriptOut, 152 char** aLocationOut = nullptr); 153 154 static JSScript* InstantiateStencil(JSContext* aCx, JS::Stencil* aStencil); 155 156 class ModuleEntry { 157 public: 158 explicit ModuleEntry(JS::RootingContext* aRootingCx) 159 : obj(aRootingCx), exports(aRootingCx), thisObjectKey(aRootingCx) { 160 location = nullptr; 161 } 162 163 ~ModuleEntry() { Clear(); } 164 165 void Clear() { 166 if (obj) { 167 if (JS_HasExtensibleLexicalEnvironment(obj)) { 168 JS::RootedObject lexicalEnv(mozilla::dom::RootingCx(), 169 JS_ExtensibleLexicalEnvironment(obj)); 170 JS_SetAllNonReservedSlotsToUndefined(lexicalEnv); 171 } 172 JS_SetAllNonReservedSlotsToUndefined(obj); 173 obj = nullptr; 174 thisObjectKey = nullptr; 175 } 176 177 if (location) { 178 free(location); 179 } 180 181 obj = nullptr; 182 thisObjectKey = nullptr; 183 location = nullptr; 184 } 185 186 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; 187 188 JS::PersistentRootedObject obj; 189 JS::PersistentRootedObject exports; 190 JS::PersistentRootedScript thisObjectKey; 191 char* location; 192 nsCString resolvedURL; 193 }; 194 195 #ifdef STARTUP_RECORDER_ENABLED 196 nsTHashMap<nsCStringHashKey, nsCString> mImportStacks; 197 #endif 198 199 bool mInitialized; 200 bool mIsUnloaded = false; 201 #ifdef DEBUG 202 bool mIsInitializingLoaderGlobal = false; 203 #endif 204 JS::PersistentRooted<JSObject*> mLoaderGlobal; 205 JS::PersistentRooted<JSObject*> mServicesObj; 206 207 RefPtr<mozilla::loader::SyncModuleLoader> mModuleLoader; 208 }; 209 210 namespace mozilla::loader { 211 212 // Automatically allocate and initialize a sync module loader for given 213 // non-shared global, and override the module loader for the global with sync 214 // module loader. 215 // 216 // This is not re-entrant, and the consumer must check IsActive method before 217 // allocating this on the stack. 218 // 219 // The consumer should ensure the target global's module loader has no 220 // ongoing fetching modules (ModuleLoaderBase::HasFetchingModules). 221 // If there's any fetching modules, the consumer should wait for them before 222 // allocating this class on the stack. 223 // 224 // The consumer should also verify that the target global has module loader, 225 // as a part of the above step. 226 // 227 // The loader returned by ActiveLoader can be reused only when 228 // ActiveLoader's global matches the global the consumer wants to use. 229 class MOZ_STACK_CLASS NonSharedGlobalSyncModuleLoaderScope { 230 public: 231 NonSharedGlobalSyncModuleLoaderScope(JSContext* aCx, 232 nsIGlobalObject* aGlobal); 233 ~NonSharedGlobalSyncModuleLoaderScope(); 234 235 // After successfully importing a module graph, move all imported modules to 236 // the target global's module loader. 237 void Finish(); 238 239 // Returns true if another instance of NonSharedGlobalSyncModuleLoaderScope 240 // is on stack. 241 static bool IsActive(); 242 243 static mozJSModuleLoader* ActiveLoader(); 244 245 static void InitStatics(); 246 247 private: 248 RefPtr<mozJSModuleLoader> mLoader; 249 250 // Reference to thread-local module loader on the stack. 251 // This is used by another sync module load during a sync module load is 252 // ongoing. 253 static MOZ_THREAD_LOCAL(mozJSModuleLoader*) sTlsActiveLoader; 254 255 // The module loader of the target global. 256 RefPtr<JS::loader::ModuleLoaderBase> mAsyncModuleLoader; 257 258 mozilla::Maybe<JS::loader::AutoOverrideModuleLoader> mMaybeOverride; 259 }; 260 261 } // namespace mozilla::loader 262 263 #endif // mozJSModuleLoader_h