Realm.h (34751B)
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 vm_Realm_h 8 #define vm_Realm_h 9 10 #include "mozilla/Array.h" 11 #include "mozilla/Maybe.h" 12 #include "mozilla/MemoryReporting.h" 13 #include "mozilla/TimeStamp.h" 14 #include "mozilla/XorShift128PlusRNG.h" 15 16 #include <stddef.h> 17 18 #include "builtin/Array.h" 19 #include "ds/IdValuePair.h" 20 #include "gc/Barrier.h" 21 #include "gc/WeakMap.h" 22 #include "jit/BaselineCompileQueue.h" 23 #include "js/GCVariant.h" 24 #include "js/RealmOptions.h" 25 #include "js/TelemetryTimers.h" 26 #include "js/UniquePtr.h" 27 #include "vm/ArrayBufferObject.h" 28 #include "vm/GuardFuse.h" 29 #include "vm/InvalidatingFuse.h" 30 #include "vm/JSContext.h" 31 #include "vm/RealmFuses.h" 32 #include "vm/SavedStacks.h" 33 #include "wasm/WasmRealm.h" 34 35 namespace js { 36 37 namespace coverage { 38 class LCovRealm; 39 } // namespace coverage 40 41 namespace jit { 42 class BaselineCompileQueue; 43 } // namespace jit 44 45 class AutoRestoreRealmDebugMode; 46 class DateTimeInfo; 47 class Debugger; 48 class GlobalObject; 49 class GlobalObjectData; 50 class GlobalLexicalEnvironmentObject; 51 class NonSyntacticLexicalEnvironmentObject; 52 struct IdValuePair; 53 struct NativeIterator; 54 55 /* 56 * A single-entry cache for some base-10 double-to-string conversions. This 57 * helps date-format-xparb.js. It also avoids skewing the results for 58 * v8-splay.js when measured by the SunSpider harness, where the splay tree 59 * initialization (which includes many repeated double-to-string conversions) 60 * is erroneously included in the measurement; see bug 562553. 61 */ 62 class DtoaCache { 63 double dbl; 64 int base; 65 JSLinearString* str; // if str==nullptr, dbl and base are not valid 66 67 public: 68 DtoaCache() : str(nullptr) {} 69 void purge() { str = nullptr; } 70 71 JSLinearString* lookup(int b, double d) { 72 return str && b == base && d == dbl ? str : nullptr; 73 } 74 75 void cache(int b, double d, JSLinearString* s) { 76 base = b; 77 dbl = d; 78 str = s; 79 } 80 81 #ifdef JSGC_HASH_TABLE_CHECKS 82 void checkCacheAfterMovingGC(); 83 #endif 84 }; 85 86 // Cache to speed up the group/shape lookup in ProxyObject::create. A proxy's 87 // shape is only determined by the Class + proto, so a small cache for this is 88 // very effective in practice. 89 class NewProxyCache { 90 struct Entry { 91 Shape* shape; 92 }; 93 static const size_t NumEntries = 4; 94 mozilla::UniquePtr<Entry[], JS::FreePolicy> entries_; 95 96 public: 97 MOZ_ALWAYS_INLINE bool lookup(const JSClass* clasp, TaggedProto proto, 98 Shape** shape) const { 99 if (!entries_) { 100 return false; 101 } 102 for (size_t i = 0; i < NumEntries; i++) { 103 const Entry& entry = entries_[i]; 104 if (entry.shape && entry.shape->getObjectClass() == clasp && 105 entry.shape->proto() == proto) { 106 *shape = entry.shape; 107 return true; 108 } 109 } 110 return false; 111 } 112 void add(Shape* shape) { 113 MOZ_ASSERT(shape); 114 if (!entries_) { 115 entries_.reset(js_pod_calloc<Entry>(NumEntries)); 116 if (!entries_) { 117 return; 118 } 119 } else { 120 for (size_t i = NumEntries - 1; i > 0; i--) { 121 entries_[i] = entries_[i - 1]; 122 } 123 } 124 entries_[0].shape = shape; 125 } 126 void purge() { entries_.reset(); } 127 }; 128 129 // Cache for NewPlainObjectWithProperties. When the list of properties matches 130 // a recently created object's shape, we can use this shape directly. 131 class NewPlainObjectWithPropsCache { 132 static const size_t NumEntries = 4; 133 mozilla::Array<SharedShape*, NumEntries> entries_; 134 135 public: 136 NewPlainObjectWithPropsCache() { purge(); } 137 138 SharedShape* lookup(Handle<IdValueVector> properties) const; 139 void add(SharedShape* shape); 140 141 void purge() { 142 for (size_t i = 0; i < NumEntries; i++) { 143 entries_[i] = nullptr; 144 } 145 } 146 }; 147 148 // Cache for Object.assign's fast path for two plain objects. It's used to 149 // optimize: 150 // 151 // Object.assign(to, from) 152 // 153 // If the |to| object has shape |emptyToShape_| (shape with no properties) and 154 // the |from| object has shape |fromShape_|, we can use |newToShape_| for |to| 155 // and copy all (data)) properties from the |from| object. 156 // 157 // This is a one-entry cache for now. It has a hit rate of > 90% on both 158 // Speedometer 2 and Speedometer 3. 159 class MOZ_NON_TEMPORARY_CLASS PlainObjectAssignCache { 160 SharedShape* emptyToShape_ = nullptr; 161 SharedShape* fromShape_ = nullptr; 162 SharedShape* newToShape_ = nullptr; 163 164 #ifdef DEBUG 165 void assertValid() const; 166 #else 167 void assertValid() const {} 168 #endif 169 170 public: 171 PlainObjectAssignCache() = default; 172 PlainObjectAssignCache(const PlainObjectAssignCache&) = delete; 173 void operator=(const PlainObjectAssignCache&) = delete; 174 175 SharedShape* lookup(Shape* emptyToShape, Shape* fromShape) const { 176 if (emptyToShape_ == emptyToShape && fromShape_ == fromShape) { 177 assertValid(); 178 return newToShape_; 179 } 180 return nullptr; 181 } 182 void fill(SharedShape* emptyToShape, SharedShape* fromShape, 183 SharedShape* newToShape) { 184 emptyToShape_ = emptyToShape; 185 fromShape_ = fromShape; 186 newToShape_ = newToShape; 187 assertValid(); 188 } 189 void purge() { 190 emptyToShape_ = nullptr; 191 fromShape_ = nullptr; 192 newToShape_ = nullptr; 193 } 194 }; 195 196 // [SMDOC] Object MetadataBuilder API 197 // 198 // We must ensure that all newly allocated JSObjects get their metadata 199 // set. However, metadata builders may require the new object be in a sane 200 // state (eg, have its reserved slots initialized so they can get the 201 // sizeOfExcludingThis of the object). Therefore, for objects of certain 202 // JSClasses (those marked with JSCLASS_DELAY_METADATA_BUILDER), it is not safe 203 // for the allocation paths to call the object metadata builder 204 // immediately. Instead, the JSClass-specific "constructor" C++ function up the 205 // stack makes a promise that it will ensure that the new object has its 206 // metadata set after the object is initialized. 207 // 208 // The js::AutoSetNewObjectMetadata RAII class provides an ergonomic way for 209 // constructor functions to do this. 210 // 211 // In the presence of internal errors, we do not set the new object's metadata 212 // (if it was even allocated). 213 214 class PropertyIteratorObject; 215 216 struct IteratorHashPolicy { 217 struct Lookup { 218 Shape* objShape; 219 Shape** protoShapes; 220 size_t numProtoShapes; 221 HashNumber shapesHash; 222 223 Lookup(Shape* objShape, Shape** protoShapes, size_t numProtoShapes, 224 HashNumber shapesHash) 225 : objShape(objShape), 226 protoShapes(protoShapes), 227 numProtoShapes(numProtoShapes), 228 shapesHash(shapesHash) { 229 MOZ_ASSERT(objShape); 230 } 231 }; 232 static HashNumber hash(const Lookup& lookup) { return lookup.shapesHash; } 233 static bool match(PropertyIteratorObject* obj, const Lookup& lookup); 234 }; 235 236 class DebugEnvironments; 237 class NonSyntacticVariablesObject; 238 class WithEnvironmentObject; 239 240 // ObjectRealm stores various tables and other state associated with particular 241 // objects in a realm. To make sure the correct ObjectRealm is used for an 242 // object, use of the ObjectRealm::get(obj) static method is required. 243 class ObjectRealm { 244 // All non-syntactic lexical environments in the realm. These are kept in a 245 // map because when loading scripts into a non-syntactic environment, we 246 // need to use the same lexical environment to persist lexical bindings. 247 using NonSyntacticLexialEnvironmentsMap = 248 WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>; 249 js::UniquePtr<NonSyntacticLexialEnvironmentsMap> 250 nonSyntacticLexicalEnvironments_; 251 252 ObjectRealm(const ObjectRealm&) = delete; 253 void operator=(const ObjectRealm&) = delete; 254 255 public: 256 // Map from array buffers to views sharing that storage. 257 JS::WeakCache<js::InnerViewTable> innerViews; 258 259 // Keep track of the metadata objects which can be associated with each JS 260 // object. Both keys and values are in this realm. 261 using ObjectMetadataTable = WeakMap<JSObject*, JSObject*, ZoneAllocPolicy>; 262 js::UniquePtr<ObjectMetadataTable> objectMetadataTable; 263 264 using IteratorCache = 265 js::HashSet<js::PropertyIteratorObject*, js::IteratorHashPolicy, 266 js::ZoneAllocPolicy>; 267 IteratorCache iteratorCache; 268 269 static inline ObjectRealm& get(const JSObject* obj); 270 271 explicit ObjectRealm(JS::Zone* zone); 272 273 void finishRoots(); 274 void trace(JSTracer* trc); 275 void sweepAfterMinorGC(JSTracer* trc); 276 277 void addSizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf, 278 size_t* innerViewsArg, 279 size_t* objectMetadataTablesArg, 280 size_t* nonSyntacticLexicalEnvironmentsArg); 281 282 NonSyntacticLexicalEnvironmentObject* 283 getOrCreateNonSyntacticLexicalEnvironment( 284 JSContext* cx, Handle<NonSyntacticVariablesObject*> enclosing); 285 286 NonSyntacticLexicalEnvironmentObject* 287 getOrCreateNonSyntacticLexicalEnvironment( 288 JSContext* cx, Handle<WithEnvironmentObject*> enclosing); 289 290 NonSyntacticLexicalEnvironmentObject* 291 getOrCreateNonSyntacticLexicalEnvironment( 292 JSContext* cx, Handle<WithEnvironmentObject*> enclosing, 293 Handle<NonSyntacticVariablesObject*> key); 294 295 private: 296 NonSyntacticLexicalEnvironmentObject* 297 getOrCreateNonSyntacticLexicalEnvironment(JSContext* cx, 298 HandleObject enclosing, 299 HandleObject key, 300 HandleObject thisv); 301 302 public: 303 NonSyntacticLexicalEnvironmentObject* getNonSyntacticLexicalEnvironment( 304 JSObject* key) const; 305 }; 306 307 } // namespace js 308 309 class JS::Realm : public JS::shadow::Realm { 310 JS::Zone* zone_; 311 JSRuntime* runtime_; 312 313 const JS::RealmCreationOptions creationOptions_; 314 JS::RealmBehaviors behaviors_; 315 316 friend struct ::JSContext; 317 js::WeakHeapPtr<js::GlobalObject*> global_; 318 319 // Note: this is private to enforce use of ObjectRealm::get(obj). 320 js::ObjectRealm objects_; 321 friend js::ObjectRealm& js::ObjectRealm::get(const JSObject*); 322 323 // See the "Object MetadataBuilder API" comment. 324 JSObject* objectPendingMetadata_ = nullptr; 325 #ifdef DEBUG 326 uint32_t numActiveAutoSetNewObjectMetadata_ = 0; 327 #endif 328 329 // Random number generator for Math.random(). 330 mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> 331 randomNumberGenerator_; 332 333 // Random number generator for randomHashCodeScrambler(). 334 mozilla::non_crypto::XorShift128PlusRNG randomKeyGenerator_; 335 336 JSPrincipals* principals_ = nullptr; 337 338 js::jit::BaselineCompileQueue baselineCompileQueue_; 339 340 // Bookkeeping information for debug scope objects. 341 js::UniquePtr<js::DebugEnvironments> debugEnvs_; 342 343 js::SavedStacks savedStacks_; 344 345 // Used by memory reporters and invalid otherwise. 346 JS::RealmStats* realmStats_ = nullptr; 347 348 const js::AllocationMetadataBuilder* allocationMetadataBuilder_ = nullptr; 349 void* realmPrivate_ = nullptr; 350 351 #if JS_HAS_INTL_API 352 // Date-time info for realms with non-default time zones. 353 js::UniquePtr<js::DateTimeInfo> dateTimeInfo_; 354 #endif 355 356 // There are two ways to enter a realm: 357 // 358 // (1) AutoRealm (and JSAutoRealm, JS::EnterRealm) 359 // (2) When calling a cross-realm (but same-compartment) function in JIT 360 // code. 361 // 362 // This field only accounts for (1), to keep the JIT code as simple as 363 // possible. 364 // 365 // An important invariant is that the JIT can only switch to a different 366 // realm within the same compartment, so whenever that happens there must 367 // always be a same-compartment realm with enterRealmDepthIgnoringJit_ > 0. 368 // This lets us set Compartment::hasEnteredRealm without walking the 369 // stack. 370 unsigned enterRealmDepthIgnoringJit_ = 0; 371 372 public: 373 // Various timers for collecting time spent delazifying, jit compiling, 374 // executing, etc 375 JS::JSTimers timers; 376 377 struct DebuggerVectorEntry { 378 // The debugger relies on iterating through the DebuggerVector to know what 379 // debuggers to notify about certain actions, which it does using this 380 // pointer. We need an explicit Debugger* because the JSObject* from 381 // the DebuggerDebuggeeLink to the Debugger is only set some of the time. 382 // This `Debugger*` pointer itself could also live on the 383 // DebuggerDebuggeeLink itself, but that would then require all of the 384 // places that iterate over the realm's DebuggerVector to also traverse 385 // the CCW which seems like it would be needlessly complicated. 386 js::WeakHeapPtr<js::Debugger*> dbg; 387 388 // This links to the debugger's DebuggerDebuggeeLink object, via a CCW. 389 // Tracing this link from the realm allows the debugger to define 390 // whether pieces of the debugger should be held live by a given realm. 391 js::HeapPtr<JSObject*> debuggerLink; 392 393 DebuggerVectorEntry(js::Debugger* dbg_, JSObject* link); 394 }; 395 using DebuggerVector = 396 js::Vector<DebuggerVectorEntry, 0, js::ZoneAllocPolicy>; 397 398 private: 399 DebuggerVector debuggers_; 400 401 enum { 402 IsDebuggee = 1 << 0, 403 DebuggerObservesAllExecution = 1 << 1, 404 DebuggerObservesAsmJS = 1 << 2, 405 DebuggerObservesCoverage = 1 << 3, 406 DebuggerObservesWasm = 1 << 4, 407 DebuggerObservesNativeCall = 1 << 5, 408 }; 409 uint32_t debugModeBits_ = 0; 410 friend class js::AutoRestoreRealmDebugMode; 411 412 bool isSystem_ = false; 413 bool allocatedDuringIncrementalGC_; 414 bool initializingGlobal_ = true; 415 416 // Indicates that we are tracing all execution within this realm, i.e., 417 // recording every entrance into exit from each function, among other 418 // things. See ExecutionTracer.h for where the bulk of this work 419 // happens. 420 bool isTracingExecution_ = false; 421 422 js::UniquePtr<js::coverage::LCovRealm> lcovRealm_ = nullptr; 423 424 public: 425 // WebAssembly state for the realm. 426 js::wasm::Realm wasm; 427 428 js::DtoaCache dtoaCache; 429 js::NewProxyCache newProxyCache; 430 js::NewPlainObjectWithPropsCache newPlainObjectWithPropsCache; 431 js::PlainObjectAssignCache plainObjectAssignCache; 432 433 // Last time at which an animation was played for this realm. 434 js::MainThreadData<mozilla::TimeStamp> lastAnimationTime; 435 436 /* 437 * For generational GC, record whether a write barrier has added this 438 * realm's global to the store buffer since the last minor GC. 439 * 440 * This is used to avoid calling into the VM every time a nursery object is 441 * written to a property of the global. 442 */ 443 uint32_t globalWriteBarriered = 0; 444 445 // Counter for shouldCaptureStackForThrow. 446 uint16_t numStacksCapturedForThrow_ = 0; 447 448 // Count the number of allocation sites pretenured, for testing purposes. 449 uint16_t numAllocSitesPretenured = 0; 450 451 #ifdef DEBUG 452 bool firedOnNewGlobalObject = false; 453 #endif 454 455 // True if all incoming wrappers have been nuked. This happens when 456 // NukeCrossCompartmentWrappers is called with the NukeAllReferences option. 457 // This prevents us from creating new wrappers for the compartment. 458 bool nukedIncomingWrappers = false; 459 460 // Enable async stack capturing for this realm even if 461 // JS::ContextOptions::asyncStackCaptureDebuggeeOnly_ is true. 462 // 463 // No-op when JS::ContextOptions::asyncStack_ is false, or 464 // JS::ContextOptions::asyncStackCaptureDebuggeeOnly_ is false. 465 // 466 // This can be used as a lightweight alternative for making the global 467 // debuggee, if the async stack capturing is necessary but no other debugging 468 // features are used. 469 bool isAsyncStackCapturingEnabled = false; 470 471 // Allow to collect more than 50 stack traces for throw even if the global is 472 // not a debuggee. 473 // 474 // Similarly to isAsyncStackCapturingEnabled, this is a lightweight 475 // alternative for making the global a debuggee, when no actual debugging 476 // features are required. 477 bool isUnlimitedStacksCapturingEnabled = false; 478 479 private: 480 void updateDebuggerObservesFlag(unsigned flag); 481 void restoreDebugModeBitsOnOOM(uint32_t bits); 482 483 Realm(const Realm&) = delete; 484 void operator=(const Realm&) = delete; 485 486 public: 487 Realm(JS::Compartment* comp, const JS::RealmOptions& options); 488 ~Realm(); 489 490 void init(JSContext* cx, JSPrincipals* principals); 491 void destroy(JS::GCContext* gcx); 492 493 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, 494 size_t* realmObject, size_t* realmTables, 495 size_t* innerViewsArg, 496 size_t* objectMetadataTablesArg, 497 size_t* savedStacksSet, 498 size_t* nonSyntacticLexicalEnvironmentsArg); 499 500 JS::Zone* zone() { return zone_; } 501 const JS::Zone* zone() const { return zone_; } 502 503 JSRuntime* runtimeFromMainThread() const { 504 MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); 505 return runtime_; 506 } 507 508 // Note: Unrestricted access to the runtime from an arbitrary thread 509 // can easily lead to races. Use this method very carefully. 510 JSRuntime* runtimeFromAnyThread() const { return runtime_; } 511 512 const JS::RealmCreationOptions& creationOptions() const { 513 return creationOptions_; 514 } 515 516 // NOTE: Do not provide accessor for mutable reference. 517 // Modifying RealmBehaviors after creating a realm can result in 518 // inconsistency. 519 const JS::RealmBehaviors& behaviors() const { return behaviors_; } 520 521 void setNonLive() { behaviors_.setNonLive(); } 522 void setReduceTimerPrecisionCallerType(JS::RTPCallerTypeToken type) { 523 behaviors_.setReduceTimerPrecisionCallerType(type); 524 } 525 526 /* Whether to preserve JIT code on non-shrinking GCs. */ 527 bool preserveJitCode() { return creationOptions_.preserveJitCode(); } 528 529 /* The global object for this realm. 530 * 531 * Note: the global_ field is null briefly during GC, after the global 532 * object is collected; but when that happens the Realm is destroyed during 533 * the same GC.) 534 * 535 * In contrast, JSObject::global() is infallible because marking a JSObject 536 * always marks its global as well. 537 */ 538 inline js::GlobalObject* maybeGlobal() const; 539 540 /* An unbarriered getter for use while tracing. */ 541 js::GlobalObject* unsafeUnbarrieredMaybeGlobal() const { 542 return global_.unbarrieredGet(); 543 } 544 545 /* True if a global exists and it's not being collected. */ 546 inline bool hasLiveGlobal() const; 547 548 /* True if a global exists and has been successfully initialized. */ 549 inline bool hasInitializedGlobal() const; 550 551 inline void initGlobal(js::GlobalObject& global); 552 void clearInitializingGlobal() { initializingGlobal_ = false; } 553 554 /* 555 * This method traces data that is live iff we know that this realm's 556 * global is still live. 557 */ 558 void traceGlobalData(JSTracer* trc); 559 560 void traceWeakGlobalEdge(JSTracer* trc); 561 562 /* 563 * This method traces Realm-owned GC roots that are considered live 564 * regardless of whether the realm's global is still live. 565 */ 566 void traceRoots(JSTracer* trc, 567 js::gc::GCRuntime::TraceOrMarkRuntime traceOrMark); 568 /* 569 * This method clears out tables of roots in preparation for the final GC. 570 */ 571 void finishRoots(); 572 573 void sweepAfterMinorGC(JSTracer* trc); 574 void traceWeakDebugEnvironmentEdges(JSTracer* trc); 575 576 void clearScriptCounts(); 577 void clearScriptLCov(); 578 579 void purge(); 580 581 void fixupAfterMovingGC(JSTracer* trc); 582 583 void enter() { enterRealmDepthIgnoringJit_++; } 584 void leave() { 585 MOZ_ASSERT(enterRealmDepthIgnoringJit_ > 0); 586 enterRealmDepthIgnoringJit_--; 587 } 588 bool hasBeenEnteredIgnoringJit() const { 589 return enterRealmDepthIgnoringJit_ > 0; 590 } 591 bool shouldTraceGlobal() const { 592 // If we entered this realm in JIT code, there must be a script and 593 // function on the stack for this realm, so the global will definitely 594 // be traced and it's safe to return false here. 595 return hasBeenEnteredIgnoringJit(); 596 } 597 598 bool hasAllocationMetadataBuilder() const { 599 return allocationMetadataBuilder_; 600 } 601 const js::AllocationMetadataBuilder* getAllocationMetadataBuilder() const { 602 return allocationMetadataBuilder_; 603 } 604 const void* addressOfMetadataBuilder() const { 605 return &allocationMetadataBuilder_; 606 } 607 bool isRecordingAllocations(); 608 void setAllocationMetadataBuilder( 609 const js::AllocationMetadataBuilder* builder); 610 void forgetAllocationMetadataBuilder(); 611 void setNewObjectMetadata(JSContext* cx, JS::HandleObject obj); 612 613 bool hasObjectPendingMetadata() const { 614 MOZ_ASSERT_IF(objectPendingMetadata_, hasAllocationMetadataBuilder()); 615 return objectPendingMetadata_ != nullptr; 616 } 617 void setObjectPendingMetadata(JSObject* obj) { 618 MOZ_ASSERT(numActiveAutoSetNewObjectMetadata_ > 0, 619 "Must not use JSCLASS_DELAY_METADATA_BUILDER without " 620 "AutoSetNewObjectMetadata"); 621 MOZ_ASSERT(!objectPendingMetadata_); 622 MOZ_ASSERT(obj); 623 if (MOZ_UNLIKELY(hasAllocationMetadataBuilder())) { 624 objectPendingMetadata_ = obj; 625 } 626 } 627 JSObject* getAndClearObjectPendingMetadata() { 628 MOZ_ASSERT(hasAllocationMetadataBuilder()); 629 JSObject* obj = objectPendingMetadata_; 630 objectPendingMetadata_ = nullptr; 631 return obj; 632 } 633 634 #ifdef DEBUG 635 bool hasActiveAutoSetNewObjectMetadata() const { 636 return numActiveAutoSetNewObjectMetadata_ > 0; 637 } 638 void incNumActiveAutoSetNewObjectMetadata() { 639 numActiveAutoSetNewObjectMetadata_++; 640 } 641 void decNumActiveAutoSetNewObjectMetadata() { 642 MOZ_ASSERT(numActiveAutoSetNewObjectMetadata_ > 0); 643 numActiveAutoSetNewObjectMetadata_--; 644 } 645 #endif 646 647 void* realmPrivate() const { return realmPrivate_; } 648 void setRealmPrivate(void* p) { realmPrivate_ = p; } 649 650 // This should only be called when it is non-null, i.e. during memory 651 // reporting. 652 JS::RealmStats& realmStats() { 653 // We use MOZ_RELEASE_ASSERT here because in bug 1132502 there was some 654 // (inconclusive) evidence that realmStats_ can be nullptr unexpectedly. 655 MOZ_RELEASE_ASSERT(realmStats_); 656 return *realmStats_; 657 } 658 void nullRealmStats() { 659 MOZ_ASSERT(realmStats_); 660 realmStats_ = nullptr; 661 } 662 void setRealmStats(JS::RealmStats* newStats) { 663 MOZ_ASSERT(!realmStats_ && newStats); 664 realmStats_ = newStats; 665 } 666 667 inline bool marked() const; 668 void clearAllocatedDuringGC() { allocatedDuringIncrementalGC_ = false; } 669 670 /* 671 * The principals associated with this realm. Note that the same several 672 * realms may share the same principals and that a realm may change 673 * principals during its lifetime (e.g. in case of lazy parsing). 674 */ 675 JSPrincipals* principals() { return principals_; } 676 void setPrincipals(JSPrincipals* principals) { principals_ = principals; } 677 678 bool isSystem() const { return isSystem_; } 679 // 680 // The Debugger observes execution on a frame-by-frame basis. The 681 // invariants of Realm's debug mode bits, JSScript::isDebuggee, 682 // InterpreterFrame::isDebuggee, and BaselineFrame::isDebuggee are 683 // enumerated below. 684 // 685 // 1. When a realm's isDebuggee() == true, relazification and lazy 686 // parsing are disabled. 687 // 688 // Whether AOT wasm is disabled is togglable by the Debugger API. By 689 // default it is disabled. See debuggerObservesAsmJS below. 690 // 691 // 2. When a realm's debuggerObservesAllExecution() == true, all of 692 // the realm's scripts are considered debuggee scripts. 693 // 694 // 3. A script is considered a debuggee script either when, per above, its 695 // realm is observing all execution, or if it has breakpoints set. 696 // 697 // 4. A debuggee script always pushes a debuggee frame. 698 // 699 // 5. A debuggee frame calls all slow path Debugger hooks in the 700 // Interpreter and Baseline. A debuggee frame implies that its script's 701 // BaselineScript, if extant, has been compiled with debug hook calls. 702 // 703 // 6. A debuggee script or a debuggee frame (i.e., during OSR) ensures 704 // that the compiled BaselineScript is compiled with debug hook calls 705 // when attempting to enter Baseline. 706 // 707 // 7. A debuggee script or a debuggee frame (i.e., during OSR) does not 708 // attempt to enter Ion. 709 // 710 // Note that a debuggee frame may exist without its script being a 711 // debuggee script. e.g., Debugger.Frame.prototype.eval only marks the 712 // frame in which it is evaluating as a debuggee frame. 713 // 714 715 // True if this realm's global is a debuggee of some Debugger 716 // object. 717 bool isDebuggee() const { return !!(debugModeBits_ & IsDebuggee); } 718 719 void setIsDebuggee(); 720 void unsetIsDebuggee(); 721 722 bool isTracingExecution() { return isTracingExecution_; } 723 724 void enableExecutionTracing() { 725 MOZ_ASSERT(!debuggerObservesCoverage()); 726 727 isTracingExecution_ = true; 728 setIsDebuggee(); 729 updateDebuggerObservesAllExecution(); 730 } 731 732 void disableExecutionTracing() { 733 if (!isTracingExecution_) { 734 return; 735 } 736 737 isTracingExecution_ = false; 738 // updateDebuggerObservesAllExecution always wants isDebuggee to be true, 739 // so we just have weird ordering here to play nicely with it 740 updateDebuggerObservesAllExecution(); 741 if (!hasDebuggers()) { 742 unsetIsDebuggee(); 743 } 744 } 745 746 DebuggerVector& getDebuggers(const JS::AutoRequireNoGC& nogc) { 747 return debuggers_; 748 }; 749 bool hasDebuggers() const { return !debuggers_.empty(); } 750 751 // True if this compartment's global is a debuggee of some Debugger 752 // object with a live hook that observes all execution; e.g., 753 // onEnterFrame. 754 bool debuggerObservesAllExecution() const { 755 static const unsigned Mask = IsDebuggee | DebuggerObservesAllExecution; 756 return (debugModeBits_ & Mask) == Mask; 757 } 758 void updateDebuggerObservesAllExecution() { 759 updateDebuggerObservesFlag(DebuggerObservesAllExecution); 760 } 761 762 // True if this realm's global is a debuggee of some Debugger object 763 // whose allowUnobservedAsmJS flag is false. 764 bool debuggerObservesAsmJS() const { 765 static const unsigned Mask = IsDebuggee | DebuggerObservesAsmJS; 766 return (debugModeBits_ & Mask) == Mask; 767 } 768 void updateDebuggerObservesAsmJS() { 769 updateDebuggerObservesFlag(DebuggerObservesAsmJS); 770 } 771 772 // True if this realm's global is a debuggee of some Debugger object 773 // whose allowUnobservedWasm flag is false. 774 // 775 // Note that since AOT wasm functions cannot bail out, this flag really 776 // means "observe wasm from this point forward". We cannot make 777 // already-compiled wasm code observable to Debugger. 778 bool debuggerObservesWasm() const { 779 static const unsigned Mask = IsDebuggee | DebuggerObservesWasm; 780 return (debugModeBits_ & Mask) == Mask; 781 } 782 void updateDebuggerObservesWasm() { 783 updateDebuggerObservesFlag(DebuggerObservesWasm); 784 } 785 786 // True if this compartment's global is a debuggee of some Debugger 787 // object with a live hook that observes native calls. 788 // (has a onNativeCall function registered) 789 bool debuggerObservesNativeCall() const { 790 static const unsigned Mask = IsDebuggee | DebuggerObservesNativeCall; 791 return (debugModeBits_ & Mask) == Mask; 792 } 793 void updateDebuggerObservesNativeCall() { 794 updateDebuggerObservesFlag(DebuggerObservesNativeCall); 795 } 796 797 // True if this realm's global is a debuggee of some Debugger object 798 // whose collectCoverageInfo flag is true. 799 bool debuggerObservesCoverage() const { 800 static const unsigned Mask = DebuggerObservesCoverage; 801 return (debugModeBits_ & Mask) == Mask; 802 } 803 void updateDebuggerObservesCoverage(); 804 805 // Returns true if the Debugger API is collecting code coverage data for this 806 // realm or if the process-wide LCov option is enabled. 807 bool collectCoverageForDebug() const; 808 809 // Get or allocate the associated LCovRealm. 810 js::coverage::LCovRealm* lcovRealm(); 811 812 bool shouldCaptureStackForThrow(); 813 814 // Returns the locale for this realm. (Pointer must NOT be freed!) 815 const char* getLocale() const; 816 817 // Set the locale for this realm. Reset to the system default locale when the 818 // input is |nullptr|. 819 void setLocaleOverride(const char* locale); 820 821 // Returns the date-time info for this realm. Returns nullptr unless a time 822 // zone override was specified in the realm creation options. 823 js::DateTimeInfo* getDateTimeInfo(); 824 825 // Set the time zone for this realm. Reset to the system default time zone 826 // when the input is |nullptr|. 827 void setTimeZoneOverride(const char* timeZone); 828 829 // Initializes randomNumberGenerator if needed. 830 mozilla::non_crypto::XorShift128PlusRNG& getOrCreateRandomNumberGenerator(); 831 832 const mozilla::non_crypto::XorShift128PlusRNG* 833 addressOfRandomNumberGenerator() const { 834 return randomNumberGenerator_.ptr(); 835 } 836 837 mozilla::HashCodeScrambler randomHashCodeScrambler(); 838 839 js::jit::BaselineCompileQueue& baselineCompileQueue() { 840 return baselineCompileQueue_; 841 } 842 static constexpr size_t offsetOfBaselineCompileQueue() { 843 return offsetof(Realm, baselineCompileQueue_); 844 } 845 void removeFromCompileQueue(JSScript* script); 846 847 js::DebugEnvironments* debugEnvs() { return debugEnvs_.get(); } 848 js::UniquePtr<js::DebugEnvironments>& debugEnvsRef() { return debugEnvs_; } 849 850 js::SavedStacks& savedStacks() { return savedStacks_; } 851 852 // Recompute the probability with which this realm should record 853 // profiling data (stack traces, allocations log, etc.) about each 854 // allocation. We first consult the JS runtime to see if it is recording 855 // allocations, and if not then check the probabilities requested by the 856 // Debugger instances observing us, if any. 857 void chooseAllocationSamplingProbability() { 858 savedStacks_.chooseSamplingProbability(this); 859 } 860 861 void traceWeakSavedStacks(JSTracer* trc); 862 863 static constexpr size_t offsetOfCompartment() { 864 return offsetof(JS::Realm, compartment_); 865 } 866 static constexpr size_t offsetOfAllocationMetadataBuilder() { 867 return offsetof(JS::Realm, allocationMetadataBuilder_); 868 } 869 static constexpr size_t offsetOfDebugModeBits() { 870 return offsetof(JS::Realm, debugModeBits_); 871 } 872 static constexpr uint32_t debugModeIsDebuggeeBit() { return IsDebuggee; } 873 874 // Note: similar to cx->global(), JIT code can omit the read barrier for the 875 // context's active global. 876 static constexpr size_t offsetOfActiveGlobal() { 877 static_assert(sizeof(global_) == sizeof(uintptr_t), 878 "JIT code assumes field is pointer-sized"); 879 return offsetof(JS::Realm, global_); 880 } 881 882 js::RealmFuses realmFuses; 883 884 // Allocation site used by binding code to provide feedback 885 // on allocation heap for DOM allocation functions. 886 // 887 // See CallIRGenerator::tryAttachCallNative 888 js::gc::AllocSite* localAllocSite = nullptr; 889 890 static size_t offsetOfLocalAllocSite() { 891 return offsetof(JS::Realm, localAllocSite); 892 } 893 }; 894 895 inline js::Handle<js::GlobalObject*> JSContext::global() const { 896 /* 897 * It's safe to use |unbarrieredGet()| here because any realm that is on-stack 898 * will be marked automatically, so there's no need for a read barrier on 899 * it. Once the realm is popped, the handle is no longer safe to use. 900 */ 901 MOZ_ASSERT(realm_, "Caller needs to enter a realm first"); 902 return js::Handle<js::GlobalObject*>::fromMarkedLocation( 903 realm_->global_.unbarrieredAddress()); 904 } 905 906 namespace js { 907 908 class MOZ_RAII AssertRealmUnchanged { 909 public: 910 explicit AssertRealmUnchanged(JSContext* cx) 911 : cx(cx), oldRealm(cx->realm()) {} 912 913 ~AssertRealmUnchanged() { MOZ_ASSERT(cx->realm() == oldRealm); } 914 915 protected: 916 JSContext* const cx; 917 JS::Realm* const oldRealm; 918 }; 919 920 // AutoRealm can be used to enter the realm of a JSObject or JSScript. It must 921 // not be used with cross-compartment wrappers, because CCWs are not associated 922 // with a single realm. 923 class AutoRealm { 924 JSContext* const cx_; 925 JS::Realm* const origin_; 926 927 public: 928 template <typename T> 929 inline AutoRealm(JSContext* cx, const T& target); 930 inline ~AutoRealm(); 931 932 JSContext* context() const { return cx_; } 933 JS::Realm* origin() const { return origin_; } 934 935 protected: 936 inline AutoRealm(JSContext* cx, JS::Realm* target); 937 938 private: 939 AutoRealm(const AutoRealm&) = delete; 940 AutoRealm& operator=(const AutoRealm&) = delete; 941 }; 942 943 class MOZ_RAII AutoAllocInAtomsZone { 944 JSContext* const cx_; 945 JS::Realm* const origin_; 946 AutoAllocInAtomsZone(const AutoAllocInAtomsZone&) = delete; 947 AutoAllocInAtomsZone& operator=(const AutoAllocInAtomsZone&) = delete; 948 949 public: 950 inline explicit AutoAllocInAtomsZone(JSContext* cx); 951 inline ~AutoAllocInAtomsZone(); 952 }; 953 954 // During GC we sometimes need to enter a realm when we may have been allocating 955 // in the the atoms zone. This leaves the atoms zone temporarily. 956 class MOZ_RAII AutoMaybeLeaveAtomsZone { 957 JSContext* const cx_; 958 bool wasInAtomsZone_; 959 AutoMaybeLeaveAtomsZone(const AutoMaybeLeaveAtomsZone&) = delete; 960 AutoMaybeLeaveAtomsZone& operator=(const AutoMaybeLeaveAtomsZone&) = delete; 961 962 public: 963 inline explicit AutoMaybeLeaveAtomsZone(JSContext* cx); 964 inline ~AutoMaybeLeaveAtomsZone(); 965 }; 966 967 // Enter a realm directly. Only use this where there's no target GC thing 968 // to pass to AutoRealm or where you need to avoid the assertions in 969 // JS::Compartment::enterCompartmentOf(). 970 class AutoRealmUnchecked : protected AutoRealm { 971 public: 972 inline AutoRealmUnchecked(JSContext* cx, JS::Realm* target); 973 }; 974 975 // Similar to AutoRealm, but this uses GetFunctionRealm in the spec, and 976 // handles both bound functions and proxies. 977 // 978 // If GetFunctionRealm fails for the following reasons, this does nothing: 979 // * `fun` is revoked proxy 980 // * unwrapping failed because of a security wrapper 981 class AutoFunctionOrCurrentRealm { 982 mozilla::Maybe<AutoRealmUnchecked> ar_; 983 984 public: 985 inline AutoFunctionOrCurrentRealm(JSContext* cx, js::HandleObject fun); 986 ~AutoFunctionOrCurrentRealm() = default; 987 988 private: 989 AutoFunctionOrCurrentRealm(const AutoFunctionOrCurrentRealm&) = delete; 990 AutoFunctionOrCurrentRealm& operator=(const AutoFunctionOrCurrentRealm&) = 991 delete; 992 }; 993 994 /* 995 * Use this to change the behavior of an AutoRealm slightly on error. If 996 * the exception happens to be an Error object, copy it to the origin 997 * compartment instead of wrapping it. 998 */ 999 class ErrorCopier { 1000 mozilla::Maybe<AutoRealm>& ar; 1001 1002 public: 1003 explicit ErrorCopier(mozilla::Maybe<AutoRealm>& ar) : ar(ar) {} 1004 ~ErrorCopier(); 1005 }; 1006 1007 // See the "Object MetadataBuilder API" comment. 1008 class MOZ_RAII AutoSetNewObjectMetadata { 1009 JSContext* cx_; 1010 1011 AutoSetNewObjectMetadata(const AutoSetNewObjectMetadata& aOther) = delete; 1012 void operator=(const AutoSetNewObjectMetadata& aOther) = delete; 1013 1014 void setPendingMetadata(); 1015 1016 public: 1017 explicit inline AutoSetNewObjectMetadata(JSContext* cx) : cx_(cx) { 1018 #ifdef DEBUG 1019 MOZ_ASSERT(!cx->realm()->hasObjectPendingMetadata()); 1020 cx_->realm()->incNumActiveAutoSetNewObjectMetadata(); 1021 #endif 1022 } 1023 inline ~AutoSetNewObjectMetadata() { 1024 #ifdef DEBUG 1025 cx_->realm()->decNumActiveAutoSetNewObjectMetadata(); 1026 #endif 1027 if (MOZ_UNLIKELY(cx_->realm()->hasAllocationMetadataBuilder())) { 1028 setPendingMetadata(); 1029 } 1030 } 1031 }; 1032 1033 } /* namespace js */ 1034 1035 #endif /* vm_Realm_h */