RealmOptions.h (13999B)
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 /* 8 * Options specified when creating a realm to determine its behavior, immutable 9 * options determining the behavior of an existing realm, and mutable options on 10 * an existing realm that may be changed when desired. 11 */ 12 13 #ifndef js_RealmOptions_h 14 #define js_RealmOptions_h 15 16 #include "mozilla/Assertions.h" // MOZ_ASSERT 17 #include "mozilla/Maybe.h" 18 19 #include "jstypes.h" // JS_PUBLIC_API 20 21 #include "js/Class.h" // JSTraceOp 22 #include "js/RefCounted.h" 23 24 struct JS_PUBLIC_API JSContext; 25 class JS_PUBLIC_API JSObject; 26 27 namespace JS { 28 29 class JS_PUBLIC_API Compartment; 30 class JS_PUBLIC_API Realm; 31 class JS_PUBLIC_API Zone; 32 33 } // namespace JS 34 35 namespace JS { 36 37 /** 38 * Specification for which compartment/zone a newly created realm should use. 39 */ 40 enum class CompartmentSpecifier { 41 // Create a new realm and compartment in the single runtime wide system 42 // zone. The meaning of this zone is left to the embedder. 43 NewCompartmentInSystemZone, 44 45 // Create a new realm and compartment in a particular existing zone. 46 NewCompartmentInExistingZone, 47 48 // Create a new zone/compartment. 49 NewCompartmentAndZone, 50 51 // Create a new realm in an existing compartment. 52 ExistingCompartment, 53 }; 54 55 struct LocaleString : js::RefCounted<LocaleString> { 56 const char* chars_; 57 58 explicit LocaleString(const char* chars) : chars_(chars) {} 59 60 auto* chars() const { return chars_; } 61 }; 62 63 struct TimeZoneString : js::RefCounted<TimeZoneString> { 64 const char* chars_; 65 66 explicit TimeZoneString(const char* chars) : chars_(chars) {} 67 68 auto* chars() const { return chars_; } 69 }; 70 71 /** 72 * RealmCreationOptions specifies options relevant to creating a new realm, that 73 * are either immutable characteristics of that realm or that are discarded 74 * after the realm has been created. 75 * 76 * Access to these options on an existing realm is read-only: if you need 77 * particular selections, you must make them before you create the realm. 78 */ 79 class JS_PUBLIC_API RealmCreationOptions { 80 public: 81 RealmCreationOptions() : comp_(nullptr) {} 82 83 JSTraceOp getTrace() const { return traceGlobal_; } 84 RealmCreationOptions& setTrace(JSTraceOp op) { 85 traceGlobal_ = op; 86 return *this; 87 } 88 89 Zone* zone() const { 90 MOZ_ASSERT(compSpec_ == CompartmentSpecifier::NewCompartmentInExistingZone); 91 return zone_; 92 } 93 Compartment* compartment() const { 94 MOZ_ASSERT(compSpec_ == CompartmentSpecifier::ExistingCompartment); 95 return comp_; 96 } 97 CompartmentSpecifier compartmentSpecifier() const { return compSpec_; } 98 99 // Set the compartment/zone to use for the realm. See CompartmentSpecifier 100 // above. 101 RealmCreationOptions& setNewCompartmentInSystemZone(); 102 RealmCreationOptions& setNewCompartmentInExistingZone(JSObject* obj); 103 RealmCreationOptions& setNewCompartmentAndZone(); 104 RealmCreationOptions& setExistingCompartment(JSObject* obj); 105 RealmCreationOptions& setExistingCompartment(Compartment* compartment); 106 107 // Certain compartments are implementation details of the embedding, and 108 // references to them should never leak out to script. This flag causes this 109 // realm to skip firing onNewGlobalObject and makes addDebuggee a no-op for 110 // this global. 111 // 112 // Debugger visibility is per-compartment, not per-realm (it's only practical 113 // to enforce visibility on compartment boundaries), so if a realm is being 114 // created in an extant compartment, its requested visibility must match that 115 // of the compartment. 116 bool invisibleToDebugger() const { return invisibleToDebugger_; } 117 RealmCreationOptions& setInvisibleToDebugger(bool flag) { 118 invisibleToDebugger_ = flag; 119 return *this; 120 } 121 122 // Determines whether this realm should preserve JIT code on non-shrinking 123 // GCs. 124 // 125 // Useful for embedders who know their code is relatively stable. See 126 // Bug 1068697 for motivation. 127 // 128 // This is a hint not a guarantee and can be overriden by other heuristics in 129 // the engine. 130 bool preserveJitCode() const { return preserveJitCode_; } 131 RealmCreationOptions& setPreserveJitCode(bool flag) { 132 preserveJitCode_ = flag; 133 return *this; 134 } 135 136 // Determines whether 1) the global Atomic property is defined and atomic 137 // operations are supported, and 2) whether shared-memory operations are 138 // supported. 139 bool getSharedMemoryAndAtomicsEnabled() const; 140 RealmCreationOptions& setSharedMemoryAndAtomicsEnabled(bool flag); 141 142 // Determines (if getSharedMemoryAndAtomicsEnabled() is true) whether the 143 // global SharedArrayBuffer property is defined. If the property is not 144 // defined, shared array buffer functionality can only be invoked if the 145 // host/embedding specifically acts to expose it. 146 // 147 // This option defaults to true: embeddings unable to tolerate a global 148 // SharedAraryBuffer property must opt out of it. 149 bool defineSharedArrayBufferConstructor() const { 150 return defineSharedArrayBufferConstructor_; 151 } 152 RealmCreationOptions& setDefineSharedArrayBufferConstructor(bool flag) { 153 defineSharedArrayBufferConstructor_ = flag; 154 return *this; 155 } 156 157 // Structured clone operations support the cloning of shared memory objects 158 // (SharedArrayBuffer or or a shared WASM Memory object) *optionally* -- at 159 // the discretion of the embedder code that performs the cloning. When a 160 // structured clone operation encounters a shared memory object and cloning 161 // shared memory objects has not been enabled, the clone fails and an 162 // error is thrown. 163 // 164 // In the web embedding context, shared memory object cloning is disabled 165 // either because 166 // 167 // 1) *no* way of supporting it is available (because the 168 // Cross-Origin-Opener-Policy and Cross-Origin-Embedder-Policy HTTP 169 // headers are not respected to force the page into its own process), or 170 // 2) the aforementioned HTTP headers don't specify that the page should be 171 // opened in its own process. 172 // 173 // These two scenarios demand different error messages, and this option can be 174 // used to specify which scenario is in play. 175 // 176 // In the former case, if COOP/COEP support is not enabled, set this option to 177 // false. (This is the default.) 178 // 179 // In the latter case, if COOP/COEP weren't used to force this page into its 180 // own process, set this option to true. 181 // 182 // (Embeddings that are not the web and do not wish to support structured 183 // cloning of shared memory objects will get a "bad" web-centric error message 184 // no matter what. At present, SpiderMonkey does not offer a way for such 185 // embeddings to use an embedding-specific error message.) 186 bool getCoopAndCoepEnabled() const; 187 RealmCreationOptions& setCoopAndCoepEnabled(bool flag); 188 189 bool getToSourceEnabled() const { return toSource_; } 190 RealmCreationOptions& setToSourceEnabled(bool flag) { 191 toSource_ = flag; 192 return *this; 193 } 194 195 // This flag doesn't affect JS engine behavior. It is used by Gecko to 196 // mark whether content windows and workers are "Secure Context"s. See 197 // https://w3c.github.io/webappsec-secure-contexts/ 198 // https://bugzilla.mozilla.org/show_bug.cgi?id=1162772#c34 199 bool secureContext() const { return secureContext_; } 200 RealmCreationOptions& setSecureContext(bool flag) { 201 secureContext_ = flag; 202 return *this; 203 } 204 205 // Non-standard option to freeze certain builtin constructors and seal their 206 // prototypes. Also defines these constructors on the global as non-writable 207 // and non-configurable. 208 bool freezeBuiltins() const { return freezeBuiltins_; } 209 RealmCreationOptions& setFreezeBuiltins(bool flag) { 210 freezeBuiltins_ = flag; 211 return *this; 212 } 213 214 // Always use the fdlibm implementation of math functions instead of the 215 // platform native libc implementations. Useful for fingerprinting protection 216 // and cross-platform consistency. 217 bool alwaysUseFdlibm() const { return alwaysUseFdlibm_; } 218 RealmCreationOptions& setAlwaysUseFdlibm(bool flag) { 219 alwaysUseFdlibm_ = flag; 220 return *this; 221 } 222 223 uint64_t profilerRealmID() const { return profilerRealmID_; } 224 RealmCreationOptions& setProfilerRealmID(uint64_t id) { 225 profilerRealmID_ = id; 226 return *this; 227 } 228 229 private: 230 JSTraceOp traceGlobal_ = nullptr; 231 CompartmentSpecifier compSpec_ = CompartmentSpecifier::NewCompartmentAndZone; 232 union { 233 Compartment* comp_; 234 Zone* zone_; 235 }; 236 uint64_t profilerRealmID_ = 0; 237 bool invisibleToDebugger_ = false; 238 bool preserveJitCode_ = false; 239 bool sharedMemoryAndAtomics_ = false; 240 bool defineSharedArrayBufferConstructor_ = true; 241 bool coopAndCoep_ = false; 242 bool toSource_ = false; 243 244 bool secureContext_ = false; 245 bool freezeBuiltins_ = false; 246 bool alwaysUseFdlibm_ = false; 247 }; 248 249 // This is a wrapper for mozilla::RTPCallerType, that can't easily 250 // be exposed to the JS engine for layering reasons. 251 struct RTPCallerTypeToken { 252 uint8_t value; 253 }; 254 255 /** 256 * RealmBehaviors specifies behaviors of a realm that can be changed after the 257 * realm's been created. 258 */ 259 class JS_PUBLIC_API RealmBehaviors { 260 public: 261 RealmBehaviors() = default; 262 263 // When a JS::ReduceMicrosecondTimePrecisionCallback callback is defined via 264 // JS::SetReduceMicrosecondTimePrecisionCallback, a JS::RTPCallerTypeToken (a 265 // wrapper for mozilla::RTPCallerType) needs to be set for every Realm. 266 mozilla::Maybe<RTPCallerTypeToken> reduceTimerPrecisionCallerType() const { 267 return rtpCallerType; 268 } 269 RealmBehaviors& setReduceTimerPrecisionCallerType(RTPCallerTypeToken type) { 270 rtpCallerType = mozilla::Some(type); 271 return *this; 272 } 273 274 // For certain globals, we know enough about the code that will run in them 275 // that we can discard script source entirely. 276 bool discardSource() const { return discardSource_; } 277 RealmBehaviors& setDiscardSource(bool flag) { 278 discardSource_ = flag; 279 return *this; 280 } 281 282 bool clampAndJitterTime() const { return clampAndJitterTime_; } 283 RealmBehaviors& setClampAndJitterTime(bool flag) { 284 clampAndJitterTime_ = flag; 285 return *this; 286 } 287 288 // A Realm can stop being "live" in all the ways that matter before its global 289 // is actually GCed. Consumers that tear down parts of a Realm or its global 290 // before that point should set isNonLive accordingly. 291 bool isNonLive() const { return isNonLive_; } 292 RealmBehaviors& setNonLive() { 293 isNonLive_ = true; 294 return *this; 295 } 296 297 // Change the realm's current locale to a different value than the system 298 // default locale. The locale must be a valid BCP-47 locale identifier which 299 // is supported by ICU otherwise this option will be ignored and the 300 // last-ditch locale "en-GB" will be used! 301 // 302 // Any Unicode extension sequences are ignored. 303 // 304 // https://w3c.github.io/webdriver-bidi/#command-emulation-setLocaleOverride 305 RefPtr<LocaleString> localeOverride() const { return localeOverride_; } 306 RealmBehaviors& setLocaleOverride(const char* locale); 307 308 // Change the realm's current time zone to a different value than the system 309 // default time zone. The time zone must be a valid IANA time zone identifier, 310 // otherwise this option will be ignored and the system default time zone will 311 // be used! 312 // 313 // https://w3c.github.io/webdriver-bidi/#command-emulation-setTimezoneOverride 314 RefPtr<TimeZoneString> timeZoneOverride() const { return timeZoneOverride_; } 315 RealmBehaviors& setTimeZoneOverride(const char* timeZone); 316 317 private: 318 RefPtr<LocaleString> localeOverride_; 319 RefPtr<TimeZoneString> timeZoneOverride_; 320 mozilla::Maybe<RTPCallerTypeToken> rtpCallerType; 321 bool discardSource_ = false; 322 bool clampAndJitterTime_ = true; 323 bool isNonLive_ = false; 324 }; 325 326 /** 327 * RealmOptions specifies realm characteristics: both those that can't be 328 * changed on a realm once it's been created (RealmCreationOptions), and those 329 * that can be changed on an existing realm (RealmBehaviors). 330 */ 331 class JS_PUBLIC_API RealmOptions { 332 public: 333 explicit RealmOptions() : creationOptions_(), behaviors_() {} 334 335 RealmOptions(const RealmCreationOptions& realmCreation, 336 const RealmBehaviors& realmBehaviors) 337 : creationOptions_(realmCreation), behaviors_(realmBehaviors) {} 338 339 // RealmCreationOptions specify fundamental realm characteristics that must 340 // be specified when the realm is created, that can't be changed after the 341 // realm is created. 342 RealmCreationOptions& creationOptions() { return creationOptions_; } 343 const RealmCreationOptions& creationOptions() const { 344 return creationOptions_; 345 } 346 347 // RealmBehaviors specify realm characteristics that can be changed after 348 // the realm is created. 349 RealmBehaviors& behaviors() { return behaviors_; } 350 const RealmBehaviors& behaviors() const { return behaviors_; } 351 352 private: 353 RealmCreationOptions creationOptions_; 354 RealmBehaviors behaviors_; 355 }; 356 357 extern JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef( 358 Realm* realm); 359 360 extern JS_PUBLIC_API const RealmCreationOptions& RealmCreationOptionsRef( 361 JSContext* cx); 362 363 extern JS_PUBLIC_API const RealmBehaviors& RealmBehaviorsRef(Realm* realm); 364 365 extern JS_PUBLIC_API const RealmBehaviors& RealmBehaviorsRef(JSContext* cx); 366 367 extern JS_PUBLIC_API void SetRealmLocaleOverride(Realm* realm, 368 const char* locale); 369 370 extern JS_PUBLIC_API void SetRealmTimezoneOverride(Realm* realm, 371 const char* timezone); 372 373 extern JS_PUBLIC_API void SetRealmNonLive(Realm* realm); 374 375 // This behaves like RealmBehaviors::setReduceTimerPrecisionCallerType, but 376 // can be used even after the Realm has already been created. 377 extern JS_PUBLIC_API void SetRealmReduceTimerPrecisionCallerType( 378 Realm* realm, RTPCallerTypeToken type); 379 380 } // namespace JS 381 382 #endif // js_RealmOptions_h