Modules.h (12746B)
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 /* JavaScript module (as in, the syntactic construct) operations. */ 8 9 #ifndef js_Modules_h 10 #define js_Modules_h 11 12 #include <stdint.h> // uint32_t 13 14 #include "jstypes.h" // JS_PUBLIC_API 15 16 #include "js/AllocPolicy.h" // js::SystemAllocPolicy 17 #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin 18 #include "js/CompileOptions.h" // JS::ReadOnlyCompileOptions 19 #include "js/RootingAPI.h" // JS::{Mutable,}Handle 20 #include "js/Value.h" // JS::Value 21 #include "js/Vector.h" // js::Vector 22 23 struct JS_PUBLIC_API JSContext; 24 class JS_PUBLIC_API JSObject; 25 struct JS_PUBLIC_API JSRuntime; 26 class JS_PUBLIC_API JSString; 27 28 namespace JS { 29 template <typename UnitT> 30 class SourceText; 31 } // namespace JS 32 33 namespace mozilla { 34 union Utf8Unit; 35 } 36 37 namespace JS { 38 39 // This enum is used to index into an array, and we assume that we have 40 // sequential numbers starting at zero for the unknown type. 41 enum class ModuleType : uint32_t { 42 Unknown = 0, 43 JavaScript, 44 JSON, 45 CSS, 46 Bytes, 47 48 // The specification has renamed the "javascript" module type to 49 // "javascript-or-wasm". For now, we'll add JavaScriptOrWasm as 50 // an alias of JavaScript. Code that's been updated to handle 51 // wasm modules will use JavaScriptOrWasm, other code will continue 52 // to use JavaScript. Once everything has been updated to use 53 // JavaScriptOrWasm, we'll can just rename JavaScript to JavaScriptOrWasm. 54 JavaScriptOrWasm = JavaScript, 55 56 Limit = Bytes, 57 }; 58 59 /** 60 * The HostLoadImportedModule hook. 61 * 62 * See: https://tc39.es/ecma262/#sec-HostLoadImportedModule 63 * 64 * This embedding-defined hook is used to implement module loading. It is called 65 * to get or create a module object corresponding to |moduleRequest| occurring 66 * in the context of the script or module |referrer| with private value 67 * |referencingPrivate|. 68 * 69 * The module specifier string for the request can be obtained by calling 70 * JS::GetModuleRequestSpecifier. 71 * 72 * The private value for a script or module is set with JS::SetScriptPrivate or 73 * JS::SetModulePrivate. It's assumed that the embedding can handle receiving 74 * either here. 75 * 76 * If this call succeeds then the embedding must call 77 * FinishLoadingImportedModule or one of the FinishLoadingImportedModuleFailed 78 * APIs at some point in the future. This is handled by the engine if the call 79 * returns false. 80 * 81 * This hook must obey the restrictions defined in the spec: 82 * - Each time the hook is called with the same (referrer, referencingPrivate) 83 * pair, then it must call FinishLoadingImportedModule with the same result 84 * each time. 85 * - The operation must treat the |payload| argument as an opaque 86 * value to be passed through to FinishLoadingImportedModule. 87 */ 88 using ModuleLoadHook = bool (*)(JSContext* cx, Handle<JSScript*> referrer, 89 Handle<JSObject*> moduleRequest, 90 Handle<Value> hostDefined, 91 Handle<Value> payload, uint32_t lineNumber, 92 JS::ColumnNumberOneOrigin columnNumber); 93 94 /** 95 * Get the HostLoadImportedModule hook for the runtime. 96 */ 97 extern JS_PUBLIC_API ModuleLoadHook GetModuleLoadHook(JSRuntime* rt); 98 99 /** 100 * Set the HostLoadImportedModule hook for the runtime to the given function. 101 */ 102 extern JS_PUBLIC_API void SetModuleLoadHook(JSRuntime* rt, ModuleLoadHook func); 103 104 using LoadModuleResolvedCallback = bool (*)(JSContext* cx, 105 JS::Handle<JS::Value>); 106 using LoadModuleRejectedCallback = bool (*)(JSContext* cx, 107 JS::Handle<JS::Value> hostDefined, 108 Handle<JS::Value> error); 109 110 /** 111 * https://tc39.es/ecma262/#sec-LoadRequestedModules 112 * 113 * Load the dependency module graph of the parameter 'module'. 114 * 115 * The spec defines using 'promise objects' to notify the result. 116 * To address the synchronous loading behavior from mozJSModuleLoader, an 117 * overloaded version that takes function callbacks to notify the result is also 118 * provided. 119 */ 120 extern JS_PUBLIC_API bool LoadRequestedModules( 121 JSContext* cx, Handle<JSObject*> module, Handle<Value> hostDefined, 122 LoadModuleResolvedCallback resolved, LoadModuleRejectedCallback rejected); 123 124 extern JS_PUBLIC_API bool LoadRequestedModules( 125 JSContext* cx, Handle<JSObject*> module, Handle<Value> hostDefined, 126 MutableHandle<JSObject*> promiseOut); 127 128 /** 129 * The module metadata hook. 130 * 131 * See: https://tc39.es/ecma262/#sec-hostgetimportmetaproperties 132 * 133 * Populate the |metaObject| object returned when import.meta is evaluated in 134 * the context of the script or module with private value |privateValue|. 135 * 136 * This is based on the spec's HostGetImportMetaProperties hook but defines 137 * properties on the meta object directly rather than returning a list. 138 */ 139 using ModuleMetadataHook = bool (*)(JSContext* cx, Handle<Value> privateValue, 140 Handle<JSObject*> metaObject); 141 142 /** 143 * Get the hook for populating the import.meta metadata object. 144 */ 145 extern JS_PUBLIC_API ModuleMetadataHook GetModuleMetadataHook(JSRuntime* rt); 146 147 /** 148 * Set the hook for populating the import.meta metadata object to the given 149 * function. 150 */ 151 extern JS_PUBLIC_API void SetModuleMetadataHook(JSRuntime* rt, 152 ModuleMetadataHook func); 153 154 /** 155 * A function callback called by the host layer to indicate the call of 156 * HostLoadImportedModule has finished. 157 * 158 * See https://tc39.es/ecma262/#sec-FinishLoadingImportedModule 159 */ 160 extern JS_PUBLIC_API bool FinishLoadingImportedModule( 161 JSContext* cx, Handle<JSScript*> referrer, Handle<JSObject*> moduleRequest, 162 Handle<Value> payload, Handle<JSObject*> result, bool usePromise); 163 164 /** 165 * Overloaded version of FinishLoadingImportedModule for error handling. 166 */ 167 extern JS_PUBLIC_API bool FinishLoadingImportedModuleFailed( 168 JSContext* cx, Handle<Value> payload, Handle<Value> error); 169 170 extern JS_PUBLIC_API bool FinishLoadingImportedModuleFailedWithPendingException( 171 JSContext* cx, Handle<Value> payload); 172 173 /** 174 * Parse the given source buffer as a module in the scope of the current global 175 * of cx and return a source text module record. 176 */ 177 extern JS_PUBLIC_API JSObject* CompileModule( 178 JSContext* cx, const ReadOnlyCompileOptions& options, 179 SourceText<char16_t>& srcBuf); 180 181 /** 182 * Parse the given source buffer as a module in the scope of the current global 183 * of cx and return a source text module record. An error is reported if a 184 * UTF-8 encoding error is encountered. 185 */ 186 extern JS_PUBLIC_API JSObject* CompileModule( 187 JSContext* cx, const ReadOnlyCompileOptions& options, 188 SourceText<mozilla::Utf8Unit>& srcBuf); 189 190 /** 191 * Parse the given source buffer as a JSON module in the scope of the current 192 * global of cx and return a synthetic module record. 193 */ 194 extern JS_PUBLIC_API JSObject* CompileJsonModule( 195 JSContext* cx, const ReadOnlyCompileOptions& options, 196 SourceText<char16_t>& srcBuf); 197 198 /** 199 * Parse the given source buffer as a JSON module in the scope of the current 200 * global of cx and return a synthetic module record. An error is reported if a 201 * UTF-8 encoding error is encountered. 202 */ 203 extern JS_PUBLIC_API JSObject* CompileJsonModule( 204 JSContext* cx, const ReadOnlyCompileOptions& options, 205 SourceText<mozilla::Utf8Unit>& srcBuf); 206 207 /** 208 * Create a synthetic module record that exports a single value as its default 209 * export. The caller is responsible for providing the already-constructed 210 * value to export. 211 * 212 * This matches the ECMAScript specification's definition: 213 * https://tc39.es/ecma262/#sec-create-default-export-synthetic-module 214 */ 215 extern JS_PUBLIC_API JSObject* CreateDefaultExportSyntheticModule( 216 JSContext* cx, const Value& defaultExport); 217 218 /** 219 * Parse the given source buffer as a module in the scope of the current global 220 * of cx and return a source text module record. 221 */ 222 extern JS_PUBLIC_API JSObject* CompileWasmModule( 223 JSContext* cx, const ReadOnlyCompileOptions& options, 224 SourceText<char16_t>& srcBuf); 225 226 /** 227 * Parse the given source buffer as a module in the scope of the current global 228 * of cx and return a source text module record. 229 */ 230 extern JS_PUBLIC_API JSObject* CompileWasmModule( 231 JSContext* cx, const ReadOnlyCompileOptions& options, 232 SourceText<mozilla::Utf8Unit>& srcBuf); 233 234 /** 235 * Set a private value associated with a source text module record. 236 */ 237 extern JS_PUBLIC_API void SetModulePrivate(JSObject* module, 238 const Value& value); 239 /** 240 * Clear the private value associated with a source text module record. 241 * 242 * This is used during unlinking and can be called on a gray module, skipping 243 * the usual checks. 244 */ 245 extern JS_PUBLIC_API void ClearModulePrivate(JSObject* module); 246 247 /** 248 * Get the private value associated with a source text module record. 249 */ 250 extern JS_PUBLIC_API Value GetModulePrivate(JSObject* module); 251 252 /** 253 * Checks if the given module is a cyclic module. 254 */ 255 extern JS_PUBLIC_API bool IsCyclicModule(JSObject* module); 256 257 /* 258 * Perform the ModuleLink operation on the given source text module record. 259 * 260 * This transitively resolves all module dependencies (calling the 261 * HostResolveImportedModule hook) and initializes the environment record for 262 * the module. 263 */ 264 extern JS_PUBLIC_API bool ModuleLink(JSContext* cx, 265 Handle<JSObject*> moduleRecord); 266 267 /* 268 * Perform the ModuleEvaluate operation on the given source text module record 269 * and returns a bool. A result value is returned in result and is either 270 * undefined (and ignored) or a promise (if Top Level Await is enabled). 271 * 272 * If this module has already been evaluated, it returns the evaluation 273 * promise. Otherwise, it transitively evaluates all dependences of this module 274 * and then evaluates this module. 275 * 276 * ModuleLink must have completed prior to calling this. 277 */ 278 extern JS_PUBLIC_API bool ModuleEvaluate(JSContext* cx, 279 Handle<JSObject*> moduleRecord, 280 MutableHandleValue rval); 281 282 enum ModuleErrorBehaviour { 283 // Report module evaluation errors asynchronously when the evaluation promise 284 // is rejected. This is used for web content. 285 ReportModuleErrorsAsync, 286 287 // Throw module evaluation errors synchronously by setting an exception on the 288 // context. Does not support modules that use top-level await. 289 ThrowModuleErrorsSync 290 }; 291 292 /* 293 * If a module evaluation fails, unwrap the resulting evaluation promise 294 * and rethrow. 295 * 296 * This does nothing if this module succeeds in evaluation. Otherwise, it 297 * takes the reason for the module throwing, unwraps it and throws it as a 298 * regular error rather than as an uncaught promise. 299 * 300 * ModuleEvaluate must have completed prior to calling this. 301 */ 302 extern JS_PUBLIC_API bool ThrowOnModuleEvaluationFailure( 303 JSContext* cx, Handle<JSObject*> evaluationPromise, 304 ModuleErrorBehaviour errorBehaviour = ReportModuleErrorsAsync); 305 306 /* 307 * Get the module type of a requested module. 308 */ 309 extern JS_PUBLIC_API ModuleType GetRequestedModuleType( 310 JSContext* cx, Handle<JSObject*> moduleRecord, uint32_t index); 311 312 /* 313 * Get the top-level script for a module which has not yet been executed. 314 */ 315 extern JS_PUBLIC_API JSScript* GetModuleScript(Handle<JSObject*> moduleRecord); 316 317 extern JS_PUBLIC_API JSString* GetModuleRequestSpecifier( 318 JSContext* cx, Handle<JSObject*> moduleRequestArg); 319 320 /* 321 * Get the module type of the specified module request. 322 */ 323 extern JS_PUBLIC_API ModuleType 324 GetModuleRequestType(JSContext* cx, Handle<JSObject*> moduleRequestArg); 325 326 /* 327 * Get the module record for a module script. 328 */ 329 extern JS_PUBLIC_API JSObject* GetModuleObject(Handle<JSScript*> moduleScript); 330 331 /* 332 * Get the namespace object for a module. 333 */ 334 extern JS_PUBLIC_API JSObject* GetModuleNamespace( 335 JSContext* cx, Handle<JSObject*> moduleRecord); 336 337 extern JS_PUBLIC_API JSObject* GetModuleForNamespace( 338 JSContext* cx, Handle<JSObject*> moduleNamespace); 339 340 extern JS_PUBLIC_API JSObject* GetModuleEnvironment( 341 JSContext* cx, Handle<JSObject*> moduleObj); 342 343 /* 344 * Clear all bindings in a module's environment. Used during shutdown. 345 */ 346 extern JS_PUBLIC_API void ClearModuleEnvironment(JSObject* moduleObj); 347 348 extern JS_PUBLIC_API bool ModuleIsLinked(JSObject* moduleObj); 349 350 } // namespace JS 351 352 #endif // js_Modules_h