JSContext.h (44848B)
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 /* JS execution context. */ 8 9 #ifndef vm_JSContext_h 10 #define vm_JSContext_h 11 12 #include "mozilla/Attributes.h" 13 #include "mozilla/BaseProfilerUtils.h" // BaseProfilerThreadId 14 #include "mozilla/Maybe.h" 15 #include "mozilla/MemoryReporting.h" 16 17 #include "jstypes.h" // JS_PUBLIC_API 18 19 #include "builtin/AtomicsObject.h" 20 #include "ds/TraceableFifo.h" 21 #include "frontend/NameCollections.h" 22 #include "gc/Allocator.h" 23 #include "gc/GCEnum.h" 24 #include "gc/Memory.h" 25 #include "irregexp/RegExpTypes.h" 26 #include "js/ContextOptions.h" // JS::ContextOptions 27 #include "js/Debug.h" // JS::CustomObjectSummaryCallback 28 #include "js/Exception.h" 29 #include "js/friend/MicroTask.h" 30 #include "js/GCVector.h" 31 #include "js/Interrupt.h" 32 #include "js/Promise.h" 33 #include "js/Result.h" 34 #include "js/RootingAPI.h" 35 #include "js/Stack.h" // JS::NativeStackBase, JS::NativeStackLimit 36 #include "js/Utility.h" 37 #include "js/Vector.h" 38 #include "threading/ProtectedData.h" 39 #include "util/StructuredSpewer.h" 40 #include "vm/Activation.h" // js::Activation 41 #include "vm/MallocProvider.h" 42 #include "vm/Runtime.h" 43 #include "wasm/WasmContext.h" 44 45 struct JS_PUBLIC_API JSContext; 46 47 struct DtoaState; 48 49 namespace js { 50 51 class AutoAllocInAtomsZone; 52 class AutoMaybeLeaveAtomsZone; 53 class AutoRealm; 54 struct PortableBaselineStack; 55 56 #ifdef MOZ_EXECUTION_TRACING 57 class ExecutionTracer; 58 #endif 59 60 namespace jit { 61 class JitActivation; 62 class JitContext; 63 class DebugModeOSRVolatileJitFrameIter; 64 } // namespace jit 65 66 /* Detects cycles when traversing an object graph. */ 67 class MOZ_RAII AutoCycleDetector { 68 public: 69 using Vector = GCVector<JSObject*, 8>; 70 71 AutoCycleDetector(JSContext* cx, HandleObject objArg) 72 : cx(cx), obj(cx, objArg), cyclic(true) {} 73 74 ~AutoCycleDetector(); 75 76 bool init(); 77 78 bool foundCycle() { return cyclic; } 79 80 private: 81 JSContext* cx; 82 RootedObject obj; 83 bool cyclic; 84 }; 85 86 struct AutoResolving; 87 88 class InternalJobQueue : public JS::JobQueue { 89 public: 90 explicit InternalJobQueue(JSContext* cx) 91 : queue(cx, SystemAllocPolicy()), draining_(false), interrupted_(false) {} 92 ~InternalJobQueue() = default; 93 94 // JS::JobQueue methods. 95 bool getHostDefinedData(JSContext* cx, 96 JS::MutableHandle<JSObject*> data) const override; 97 98 bool getHostDefinedGlobal(JSContext*, 99 JS::MutableHandle<JSObject*>) const override; 100 101 bool enqueuePromiseJob(JSContext* cx, JS::HandleObject promise, 102 JS::HandleObject job, JS::HandleObject allocationSite, 103 JS::HandleObject hostDefinedData) override; 104 void runJobs(JSContext* cx) override; 105 bool empty() const override; 106 bool isDrainingStopped() const override { return interrupted_; } 107 108 // If we are currently in a call to runJobs(), make that call stop processing 109 // jobs once the current one finishes, and return. If we are not currently in 110 // a call to runJobs, make all future calls return immediately. 111 void interrupt() { interrupted_ = true; } 112 113 void uninterrupt() { interrupted_ = false; } 114 115 // Return the front element of the queue, or nullptr if the queue is empty. 116 // This is only used by shell testing functions. 117 JSObject* maybeFront() const; 118 119 #ifdef DEBUG 120 JSObject* copyJobs(JSContext* cx); 121 #endif 122 123 private: 124 using Queue = js::TraceableFifo<JSObject*, 0, SystemAllocPolicy>; 125 126 JS::PersistentRooted<Queue> queue; 127 128 // True if we are in the midst of draining jobs from this queue. We use this 129 // to avoid re-entry (nested calls simply return immediately). 130 bool draining_; 131 132 // True if we've been asked to interrupt draining jobs. Set by interrupt(). 133 bool interrupted_; 134 135 class SavedQueue; 136 js::UniquePtr<JobQueue::SavedJobQueue> saveJobQueue(JSContext*) override; 137 }; 138 139 class AutoLockScriptData; 140 141 /* Thread Local Storage slot for storing the context for a thread. */ 142 extern MOZ_THREAD_LOCAL(JSContext*) TlsContext; 143 144 #ifdef DEBUG 145 JSContext* MaybeGetJSContext(); 146 #endif 147 148 enum class InterruptReason : uint32_t { 149 MinorGC = 1 << 0, 150 MajorGC = 1 << 1, 151 AttachOffThreadCompilations = 1 << 2, 152 CallbackUrgent = 1 << 3, 153 CallbackCanWait = 1 << 4, 154 OOMStackTrace = 1 << 5, 155 }; 156 157 enum class ShouldCaptureStack { Maybe, Always }; 158 159 // A wrapper type to allow customization of tracing of 160 // MicroTaskElements. 161 struct MicroTaskQueueElement { 162 MOZ_IMPLICIT 163 MicroTaskQueueElement(const JS::Value& val) : value(val) {} 164 165 operator JS::Value() const { return value; } 166 167 void trace(JSTracer* trc); 168 169 private: 170 JS::Value value; 171 }; 172 173 // Use TempAllocPolicy to report OOM 174 // MG:XXX: It would be nice to explore the typical depth of the queue 175 // to see if we can get it all inline in the common case. 176 // MG:XXX: This appears to be broken for non-zero values of inline! 177 using MicroTaskQueue = 178 js::TraceableFifo<MicroTaskQueueElement, 0, TempAllocPolicy>; 179 180 // A pair of microtask queues; one debug and one 'regular' (non-debug). 181 struct MicroTaskQueueSet { 182 explicit MicroTaskQueueSet(JSContext* cx) 183 : microTaskQueue(cx), debugMicroTaskQueue(cx) {} 184 185 // We want to swap so we need move constructors 186 MicroTaskQueueSet(MicroTaskQueueSet&&) = default; 187 MicroTaskQueueSet& operator=(MicroTaskQueueSet&&) = default; 188 189 // Don't copy. 190 MicroTaskQueueSet(const MicroTaskQueueSet&) = delete; 191 MicroTaskQueueSet& operator=(const MicroTaskQueueSet&) = delete; 192 193 bool enqueueRegularMicroTask(JSContext* cx, const JS::GenericMicroTask&); 194 bool enqueueDebugMicroTask(JSContext* cx, const JS::GenericMicroTask&); 195 bool prependRegularMicroTask(JSContext* cx, const JS::GenericMicroTask&); 196 197 JS::GenericMicroTask popFront(); 198 JS::GenericMicroTask popDebugFront(); 199 200 bool empty() { return microTaskQueue.empty() && debugMicroTaskQueue.empty(); } 201 202 void trace(JSTracer* trc) { 203 microTaskQueue.trace(trc); 204 debugMicroTaskQueue.trace(trc); 205 } 206 207 void clear() { 208 microTaskQueue.clear(); 209 debugMicroTaskQueue.clear(); 210 } 211 212 MicroTaskQueue microTaskQueue; 213 MicroTaskQueue debugMicroTaskQueue; 214 }; 215 216 } /* namespace js */ 217 218 /* 219 * A JSContext encapsulates the thread local state used when using the JS 220 * runtime. 221 */ 222 struct JS_PUBLIC_API JSContext : public JS::RootingContext, 223 public js::MallocProvider<JSContext> { 224 JSContext(JSRuntime* runtime, const JS::ContextOptions& options); 225 ~JSContext(); 226 227 bool init(); 228 229 static JSContext* from(JS::RootingContext* rcx) { 230 return static_cast<JSContext*>(rcx); 231 } 232 233 private: 234 js::UnprotectedData<JSRuntime*> runtime_; 235 #ifdef DEBUG 236 js::WriteOnceData<bool> initialized_; 237 #endif 238 239 js::ContextData<JS::ContextOptions> options_; 240 241 // Are we currently timing execution? This flag ensures that we do not 242 // double-count execution time in reentrant situations. 243 js::ContextData<bool> measuringExecutionTimeEnabled_; 244 245 // This variable is used by the HelperThread scheduling to update the priority 246 // of task based on whether JavaScript is being executed on the main thread. 247 mozilla::Atomic<bool, mozilla::ReleaseAcquire> isExecuting_; 248 249 public: 250 // This is used by helper threads to change the runtime their context is 251 // currently operating on. 252 void setRuntime(JSRuntime* rt); 253 254 bool measuringExecutionTimeEnabled() const { 255 return measuringExecutionTimeEnabled_; 256 } 257 void setMeasuringExecutionTimeEnabled(bool value) { 258 measuringExecutionTimeEnabled_ = value; 259 } 260 261 // While JSContexts are meant to be used on a single thread, this reference is 262 // meant to be shared to helper thread tasks. This is used by helper threads 263 // to change the priority of tasks based on whether JavaScript is executed on 264 // the main thread. 265 const mozilla::Atomic<bool, mozilla::ReleaseAcquire>& isExecutingRef() const { 266 return isExecuting_; 267 } 268 void setIsExecuting(bool value) { isExecuting_ = value; } 269 270 #ifdef DEBUG 271 bool isInitialized() const { return initialized_; } 272 #endif 273 274 template <typename T> 275 bool isInsideCurrentZone(T thing) const { 276 return thing->zoneFromAnyThread() == zone_; 277 } 278 279 template <typename T> 280 inline bool isInsideCurrentCompartment(T thing) const { 281 return thing->compartment() == compartment(); 282 } 283 284 void onOutOfMemory(); 285 void* onOutOfMemory(js::AllocFunction allocFunc, arena_id_t arena, 286 size_t nbytes, void* reallocPtr = nullptr) { 287 return runtime_->onOutOfMemory(allocFunc, arena, nbytes, reallocPtr, this); 288 } 289 290 void onOverRecursed(); 291 292 // Allocate a GC thing. 293 template <typename T, js::AllowGC allowGC = js::CanGC, typename... Args> 294 T* newCell(Args&&... args); 295 296 /* Clear the pending exception (if any) due to OOM. */ 297 void recoverFromOutOfMemory(); 298 299 void reportAllocationOverflow(); 300 301 // Accessors for immutable runtime data. 302 JSAtomState& names() { return *runtime_->commonNames; } 303 js::StaticStrings& staticStrings() { return *runtime_->staticStrings; } 304 bool permanentAtomsPopulated() { return runtime_->permanentAtomsPopulated(); } 305 const js::FrozenAtomSet& permanentAtoms() { 306 return *runtime_->permanentAtoms(); 307 } 308 js::WellKnownSymbols& wellKnownSymbols() { 309 return *runtime_->wellKnownSymbols; 310 } 311 js::PropertyName* emptyString() { return runtime_->emptyString; } 312 JS::GCContext* gcContext() { return runtime_->gcContext(); } 313 JS::StackKind stackKindForCurrentPrincipal(); 314 JS::NativeStackLimit stackLimitForCurrentPrincipal(); 315 JS::NativeStackLimit stackLimit(JS::StackKind kind) { 316 return nativeStackLimit[kind]; 317 } 318 JS::NativeStackLimit stackLimitForJitCode(JS::StackKind kind); 319 size_t gcSystemPageSize() { return js::gc::SystemPageSize(); } 320 321 /* 322 * "Entering" a realm changes cx->realm (which changes cx->global). Note 323 * that this does not push an Activation so it's possible for the caller's 324 * realm to be != cx->realm(). This is not a problem since, in general, most 325 * places in the VM cannot know that they were called from script (e.g., 326 * they may have been called through the JSAPI via JS_CallFunction) and thus 327 * cannot expect there is a scripted caller. 328 * 329 * Realms should be entered/left in a LIFO fasion. To enter a realm, code 330 * should prefer using AutoRealm over JS::EnterRealm/JS::LeaveRealm. 331 * 332 * Also note that the JIT can enter (same-compartment) realms without going 333 * through these methods - it will update cx->realm_ directly. 334 */ 335 private: 336 inline void setRealm(JS::Realm* realm); 337 inline void enterRealm(JS::Realm* realm); 338 339 inline void enterAtomsZone(); 340 inline void leaveAtomsZone(JS::Realm* oldRealm); 341 inline void setZone(js::Zone* zone); 342 343 friend class js::AutoAllocInAtomsZone; 344 friend class js::AutoMaybeLeaveAtomsZone; 345 friend class js::AutoRealm; 346 347 public: 348 inline void enterRealmOf(JSObject* target); 349 inline void enterRealmOf(JSScript* target); 350 inline void enterRealmOf(js::Shape* target); 351 inline void enterNullRealm(); 352 353 inline void setRealmForJitExceptionHandler(JS::Realm* realm); 354 355 inline void leaveRealm(JS::Realm* oldRealm); 356 357 // Threads may freely access any data in their realm, compartment and zone. 358 JS::Compartment* compartment() const { 359 return realm_ ? JS::GetCompartmentForRealm(realm_) : nullptr; 360 } 361 362 JS::Realm* realm() const { return realm_; } 363 364 #ifdef DEBUG 365 bool inAtomsZone() const; 366 #endif 367 368 JS::Zone* zone() const { 369 MOZ_ASSERT_IF(!realm() && zone_, inAtomsZone()); 370 MOZ_ASSERT_IF(realm(), js::GetRealmZone(realm()) == zone_); 371 return zone_; 372 } 373 374 // For JIT use. 375 static size_t offsetOfZone() { return offsetof(JSContext, zone_); } 376 377 // Current global. This is only safe to use within the scope of the 378 // AutoRealm from which it's called. 379 inline js::Handle<js::GlobalObject*> global() const; 380 381 js::AtomsTable& atoms() { return runtime_->atoms(); } 382 383 js::SymbolRegistry& symbolRegistry() { return runtime_->symbolRegistry(); } 384 385 // Methods to access other runtime data that checks locking internally. 386 js::gc::AtomMarkingRuntime& atomMarking() { return runtime_->gc.atomMarking; } 387 void markAtom(JSAtom* atom) { atomMarking().markAtom(this, atom); } 388 void markAtom(JS::Symbol* symbol) { atomMarking().markAtom(this, symbol); } 389 void markId(jsid id) { atomMarking().markId(this, id); } 390 void markAtomValue(const js::Value& value) { 391 atomMarking().markAtomValue(this, value); 392 } 393 394 // Interface for recording telemetry metrics. 395 js::Metrics metrics() { return js::Metrics(runtime_); } 396 397 JSRuntime* runtime() { return runtime_; } 398 const JSRuntime* runtime() const { return runtime_; } 399 400 static size_t offsetOfRuntime() { 401 return offsetof(JSContext, runtime_) + 402 js::UnprotectedData<JSRuntime*>::offsetOfValue(); 403 } 404 static size_t offsetOfRealm() { return offsetof(JSContext, realm_); } 405 406 friend class JS::AutoSaveExceptionState; 407 friend class js::jit::DebugModeOSRVolatileJitFrameIter; 408 friend void js::ReportOutOfMemory(JSContext*); 409 friend void js::ReportOverRecursed(JSContext*); 410 friend void js::ReportOversizedAllocation(JSContext*, const unsigned); 411 412 public: 413 /** 414 * Intentionally awkward signpost method that is stationed on the 415 * boundary between Result-using and non-Result-using code. 416 */ 417 template <typename V, typename E> 418 bool resultToBool(const JS::Result<V, E>& result) { 419 return result.isOk(); 420 } 421 422 template <typename V, typename E> 423 V* resultToPtr(JS::Result<V*, E>& result) { 424 return result.isOk() ? result.unwrap() : nullptr; 425 } 426 427 mozilla::GenericErrorResult<JS::OOM> alreadyReportedOOM(); 428 mozilla::GenericErrorResult<JS::Error> alreadyReportedError(); 429 430 /* 431 * Points to the most recent JitActivation pushed on the thread. 432 * See JitActivation constructor in vm/Stack.cpp 433 */ 434 js::ContextData<js::jit::JitActivation*> jitActivation; 435 436 // Shim for V8 interfaces used by irregexp code 437 js::ContextData<js::irregexp::Isolate*> isolate; 438 439 /* 440 * Points to the most recent activation running on the thread. 441 * See Activation comment in vm/Stack.h. 442 */ 443 js::ContextData<js::Activation*> activation_; 444 445 /* 446 * Points to the most recent profiling activation running on the 447 * thread. 448 */ 449 js::Activation* volatile profilingActivation_; 450 451 public: 452 js::Activation* activation() const { return activation_; } 453 static size_t offsetOfActivation() { 454 return offsetof(JSContext, activation_); 455 } 456 457 js::Activation* profilingActivation() const { return profilingActivation_; } 458 static size_t offsetOfProfilingActivation() { 459 return offsetof(JSContext, profilingActivation_); 460 } 461 462 static size_t offsetOfJitActivation() { 463 return offsetof(JSContext, jitActivation); 464 } 465 466 #ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI 467 static size_t offsetOfInUnsafeCallWithABI() { 468 return offsetof(JSContext, inUnsafeCallWithABI); 469 } 470 #endif 471 472 public: 473 js::InterpreterStack& interpreterStack() { 474 return runtime()->interpreterStack(); 475 } 476 #ifdef ENABLE_PORTABLE_BASELINE_INTERP 477 js::PortableBaselineStack& portableBaselineStack() { 478 return runtime()->portableBaselineStack(); 479 } 480 #endif 481 482 private: 483 // Base address of the native stack for the current thread. 484 mozilla::Maybe<JS::NativeStackBase> nativeStackBase_; 485 486 public: 487 JS::NativeStackBase nativeStackBase() const { return *nativeStackBase_; } 488 489 public: 490 // In brittle mode, any failure will produce a diagnostic assertion rather 491 // than propagating an error or throwing an exception. This is used for 492 // intermittent crash diagnostics: if an operation is failing for unknown 493 // reasons, turn on brittle mode and annotate the operations within 494 // SpiderMonkey that the failing operation uses with: 495 // 496 // MOZ_DIAGNOSTIC_ASSERT(!cx->brittleMode, "specific failure"); 497 // 498 bool brittleMode = false; 499 500 /* 501 * Stack of debuggers that currently disallow debuggee execution. 502 * 503 * When we check for NX we are inside the debuggee compartment, and thus a 504 * stack of Debuggers that have prevented execution need to be tracked to 505 * enter the correct Debugger compartment to report the error. 506 */ 507 js::ContextData<js::EnterDebuggeeNoExecute*> noExecuteDebuggerTop; 508 509 #ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI 510 js::ContextData<uint32_t> inUnsafeCallWithABI; 511 js::ContextData<bool> hasAutoUnsafeCallWithABI; 512 #endif 513 514 #ifdef DEBUG 515 js::ContextData<uint32_t> liveArraySortDataInstances; 516 #endif 517 518 #ifdef JS_SIMULATOR 519 private: 520 js::ContextData<js::jit::Simulator*> simulator_; 521 522 public: 523 js::jit::Simulator* simulator() const; 524 JS::NativeStackLimit* addressOfSimulatorStackLimit(); 525 #endif 526 527 public: 528 // State used by util/DoubleToString.cpp. 529 js::ContextData<DtoaState*> dtoaState; 530 531 /* 532 * When this flag is non-zero, any attempt to GC will be skipped. See the 533 * AutoSuppressGC class for for details. 534 */ 535 js::ContextData<int32_t> suppressGC; 536 537 #ifdef FUZZING_JS_FUZZILLI 538 uint32_t executionHash; 539 uint32_t executionHashInputs; 540 #endif 541 542 #ifdef DEBUG 543 js::ContextData<size_t> noNurseryAllocationCheck; 544 545 /* 546 * If this is 0, all cross-compartment proxies must be registered in the 547 * wrapper map. This checking must be disabled temporarily while creating 548 * new wrappers. When non-zero, this records the recursion depth of wrapper 549 * creation. 550 */ 551 js::ContextData<uintptr_t> disableStrictProxyCheckingCount; 552 553 bool isNurseryAllocAllowed() { return noNurseryAllocationCheck == 0; } 554 void disallowNurseryAlloc() { ++noNurseryAllocationCheck; } 555 void allowNurseryAlloc() { 556 MOZ_ASSERT(!isNurseryAllocAllowed()); 557 --noNurseryAllocationCheck; 558 } 559 560 bool isStrictProxyCheckingEnabled() { 561 return disableStrictProxyCheckingCount == 0; 562 } 563 void disableStrictProxyChecking() { ++disableStrictProxyCheckingCount; } 564 void enableStrictProxyChecking() { 565 MOZ_ASSERT(disableStrictProxyCheckingCount > 0); 566 --disableStrictProxyCheckingCount; 567 } 568 #endif 569 570 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) 571 // We are currently running a simulated OOM test. 572 js::ContextData<bool> runningOOMTest; 573 #endif 574 575 /* 576 * Some regions of code are hard for the static rooting hazard analysis to 577 * understand. In those cases, we trade the static analysis for a dynamic 578 * analysis. When this is non-zero, we should assert if we trigger, or 579 * might trigger, a GC. 580 */ 581 js::ContextData<int> inUnsafeRegion; 582 583 // Count of AutoDisableGenerationalGC instances on the thread's stack. 584 js::ContextData<unsigned> generationalDisabled; 585 586 // Some code cannot tolerate compacting GC so it can be disabled temporarily 587 // with AutoDisableCompactingGC which uses this counter. 588 js::ContextData<unsigned> compactingDisabledCount; 589 590 // Match limit result for the most recent call to RegExpSearcher. 591 js::ContextData<uint32_t> regExpSearcherLastLimit; 592 593 static constexpr size_t offsetOfRegExpSearcherLastLimit() { 594 return offsetof(JSContext, regExpSearcherLastLimit); 595 } 596 597 // Whether we are currently executing the top level of a module. 598 js::ContextData<uint32_t> isEvaluatingModule; 599 600 private: 601 // Pools used for recycling name maps and vectors when parsing and 602 // emitting bytecode. Purged on GC when there are no active script 603 // compilations. 604 js::ContextData<js::frontend::NameCollectionPool> frontendCollectionPool_; 605 606 public: 607 js::frontend::NameCollectionPool& frontendCollectionPool() { 608 return frontendCollectionPool_.ref(); 609 } 610 611 void verifyIsSafeToGC() { 612 MOZ_DIAGNOSTIC_ASSERT(!inUnsafeRegion, 613 "[AutoAssertNoGC] possible GC in GC-unsafe region"); 614 } 615 616 bool isInUnsafeRegion() const { return bool(inUnsafeRegion); } 617 618 // For JIT use. 619 MOZ_NEVER_INLINE void resetInUnsafeRegion() { 620 MOZ_ASSERT(inUnsafeRegion >= 0); 621 inUnsafeRegion = 0; 622 } 623 624 static constexpr size_t offsetOfInUnsafeRegion() { 625 return offsetof(JSContext, inUnsafeRegion); 626 } 627 628 /* Whether sampling should be enabled or not. */ 629 private: 630 mozilla::Atomic<bool, mozilla::SequentiallyConsistent> 631 suppressProfilerSampling; 632 633 public: 634 bool isProfilerSamplingEnabled() const { return !suppressProfilerSampling; } 635 void disableProfilerSampling() { suppressProfilerSampling = true; } 636 void enableProfilerSampling() { suppressProfilerSampling = false; } 637 638 private: 639 js::wasm::Context wasm_; 640 641 public: 642 js::wasm::Context& wasm() { return wasm_; } 643 static constexpr size_t offsetOfWasm() { return offsetof(JSContext, wasm_); } 644 645 /* Temporary arena pool used while compiling and decompiling. */ 646 static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024; 647 648 private: 649 js::ContextData<js::LifoAlloc> tempLifoAlloc_; 650 651 public: 652 js::LifoAlloc& tempLifoAlloc() { return tempLifoAlloc_.ref(); } 653 const js::LifoAlloc& tempLifoAlloc() const { return tempLifoAlloc_.ref(); } 654 655 js::ContextData<uint32_t> debuggerMutations; 656 657 private: 658 // Indicates if an exception is pending and the reason for it. 659 js::ContextData<JS::ExceptionStatus> status; 660 js::ContextData<JS::PersistentRooted<JS::Value>> 661 unwrappedException_; /* most-recently-thrown exception */ 662 js::ContextData<JS::PersistentRooted<js::SavedFrame*>> 663 unwrappedExceptionStack_; /* stack when the exception was thrown */ 664 665 JS::Value& unwrappedException() { 666 if (!unwrappedException_.ref().initialized()) { 667 unwrappedException_.ref().init(this); 668 } 669 return unwrappedException_.ref().get(); 670 } 671 672 js::SavedFrame*& unwrappedExceptionStack() { 673 if (!unwrappedExceptionStack_.ref().initialized()) { 674 unwrappedExceptionStack_.ref().init(this); 675 } 676 return unwrappedExceptionStack_.ref().get(); 677 } 678 679 #ifdef DEBUG 680 // True if this context has ever thrown an exception because of an exceeded 681 // limit: stack space (ReportOverRecursed), memory (ReportOutOfMemory), or 682 // some other self-imposed limit (eg ReportOversizedAllocation). Used when 683 // detecting bailout loops in WarpOracle: bailout loops involving resource 684 // exhaustion are generally not interesting. 685 js::ContextData<bool> hadResourceExhaustion_; 686 687 // True if this context has ever thrown an uncatchable exception to terminate 688 // execution from the interrupt callback. 689 js::ContextData<bool> hadUncatchableException_; 690 691 public: 692 bool hadResourceExhaustion() const { 693 return hadResourceExhaustion_ || js::oom::simulator.isThreadSimulatingAny(); 694 } 695 bool hadUncatchableException() const { return hadUncatchableException_; } 696 #endif 697 698 public: 699 void reportResourceExhaustion() { 700 #ifdef DEBUG 701 hadResourceExhaustion_ = true; 702 #endif 703 } 704 void reportUncatchableException() { 705 // Make sure the context has no pending exception. See also the comment for 706 // JS::ReportUncatchableException. 707 clearPendingException(); 708 #ifdef DEBUG 709 hadUncatchableException_ = true; 710 #endif 711 } 712 713 // OOM stack trace buffer management 714 void unsetOOMStackTrace(); 715 const char* getOOMStackTrace() const; 716 bool hasOOMStackTrace() const; 717 void captureOOMStackTrace(); 718 719 js::ContextData<int32_t> reportGranularity; /* see vm/Probes.h */ 720 721 js::ContextData<js::AutoResolving*> resolvingList; 722 723 #ifdef DEBUG 724 js::ContextData<js::AutoEnterPolicy*> enteredPolicy; 725 #endif 726 727 /* True if generating an error, to prevent runaway recursion. */ 728 js::ContextData<bool> generatingError; 729 730 private: 731 /* State for object and array toSource conversion. */ 732 js::ContextData<js::AutoCycleDetector::Vector> cycleDetectorVector_; 733 734 public: 735 js::AutoCycleDetector::Vector& cycleDetectorVector() { 736 return cycleDetectorVector_.ref(); 737 } 738 const js::AutoCycleDetector::Vector& cycleDetectorVector() const { 739 return cycleDetectorVector_.ref(); 740 } 741 742 /* Client opaque pointer. */ 743 js::UnprotectedData<void*> data; 744 745 void initJitStackLimit(); 746 void resetJitStackLimit(); 747 748 public: 749 JS::ContextOptions& options() { return options_.ref(); } 750 751 bool runtimeMatches(JSRuntime* rt) const { return runtime_ == rt; } 752 753 private: 754 /* 755 * Youngest frame of a saved stack that will be picked up as an async stack 756 * by any new Activation, and is nullptr when no async stack should be used. 757 * 758 * The JS::AutoSetAsyncStackForNewCalls class can be used to set this. 759 * 760 * New activations will reset this to nullptr on construction after getting 761 * the current value, and will restore the previous value on destruction. 762 */ 763 js::ContextData<JS::PersistentRooted<js::SavedFrame*>> 764 asyncStackForNewActivations_; 765 766 public: 767 js::SavedFrame*& asyncStackForNewActivations() { 768 if (!asyncStackForNewActivations_.ref().initialized()) { 769 asyncStackForNewActivations_.ref().init(this); 770 } 771 return asyncStackForNewActivations_.ref().get(); 772 } 773 774 /* 775 * Value of asyncCause to be attached to asyncStackForNewActivations. 776 */ 777 js::ContextData<const char*> asyncCauseForNewActivations; 778 779 /* 780 * True if the async call was explicitly requested, e.g. via 781 * callFunctionWithAsyncStack. 782 */ 783 js::ContextData<bool> asyncCallIsExplicit; 784 785 bool currentlyRunningInInterpreter() const { 786 return activation()->isInterpreter(); 787 } 788 bool currentlyRunningInJit() const { return activation()->isJit(); } 789 js::InterpreterFrame* interpreterFrame() const { 790 return activation()->asInterpreter()->current(); 791 } 792 js::InterpreterRegs& interpreterRegs() const { 793 return activation()->asInterpreter()->regs(); 794 } 795 796 /* 797 * Get the topmost script and optional pc on the stack. By default, this 798 * function only returns a JSScript in the current realm, returning nullptr 799 * if the current script is in a different realm. This behavior can be 800 * overridden by passing AllowCrossRealm::Allow. 801 */ 802 enum class AllowCrossRealm { DontAllow = false, Allow = true }; 803 JSScript* currentScript( 804 jsbytecode** ppc = nullptr, 805 AllowCrossRealm allowCrossRealm = AllowCrossRealm::DontAllow); 806 807 inline void minorGC(JS::GCReason reason); 808 809 public: 810 bool isExceptionPending() const { 811 return JS::IsCatchableExceptionStatus(status); 812 } 813 814 /** 815 * Return the pending exception and wrap it into the current compartment. 816 */ 817 [[nodiscard]] bool getPendingException(JS::MutableHandleValue rval); 818 819 /** 820 * Return the pending exception stack and wrap it into the current 821 * compartment. Return |JS::NullValue| when the pending exception has no stack 822 * attached. 823 */ 824 [[nodiscard]] bool getPendingExceptionStack(JS::MutableHandleValue rval); 825 826 /** 827 * Return the pending exception stack, but does not wrap it into the current 828 * compartment. Return |nullptr| when the pending exception has no stack 829 * attached. 830 */ 831 js::SavedFrame* getPendingExceptionStack(); 832 833 #ifdef DEBUG 834 /** 835 * Return the pending exception (without wrapping). 836 */ 837 const JS::Value& getPendingExceptionUnwrapped(); 838 #endif 839 840 bool isThrowingDebuggeeWouldRun(); 841 bool isClosingGenerator(); 842 843 void setPendingException(JS::HandleValue v, 844 JS::Handle<js::SavedFrame*> stack); 845 void setPendingException(JS::HandleValue v, 846 js::ShouldCaptureStack captureStack); 847 848 void clearPendingException() { 849 status = JS::ExceptionStatus::None; 850 unwrappedException().setUndefined(); 851 unwrappedExceptionStack() = nullptr; 852 } 853 854 bool isThrowingOutOfMemory() const { 855 return status == JS::ExceptionStatus::OutOfMemory; 856 } 857 bool isThrowingOverRecursed() const { 858 return status == JS::ExceptionStatus::OverRecursed; 859 } 860 bool isPropagatingForcedReturn() const { 861 return status == JS::ExceptionStatus::ForcedReturn; 862 } 863 void setPropagatingForcedReturn() { 864 MOZ_ASSERT(status == JS::ExceptionStatus::None); 865 status = JS::ExceptionStatus::ForcedReturn; 866 } 867 void clearPropagatingForcedReturn() { 868 MOZ_ASSERT(status == JS::ExceptionStatus::ForcedReturn); 869 status = JS::ExceptionStatus::None; 870 } 871 872 /* 873 * See JS_SetTrustedPrincipals in jsapi.h. 874 * Note: !cx->realm() is treated as trusted. 875 */ 876 inline bool runningWithTrustedPrincipals(); 877 878 // Checks if the page's Content-Security-Policy (CSP) allows 879 // runtime code generation "unsafe-eval", or "wasm-unsafe-eval" for Wasm. 880 bool isRuntimeCodeGenEnabled( 881 JS::RuntimeCode kind, JS::Handle<JSString*> codeString, 882 JS::CompilationType compilationType, 883 JS::Handle<JS::StackGCVector<JSString*>> parameterStrings, 884 JS::Handle<JSString*> bodyString, 885 JS::Handle<JS::StackGCVector<JS::Value>> parameterArgs, 886 JS::Handle<JS::Value> bodyArg, bool* outCanCompileStrings); 887 888 // Get code to be used by eval for Object argument. 889 bool getCodeForEval(JS::HandleObject code, 890 JS::MutableHandle<JSString*> outCode); 891 892 size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 893 size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const; 894 895 void trace(JSTracer* trc); 896 897 inline js::RuntimeCaches& caches(); 898 899 public: 900 using InterruptCallbackVector = 901 js::Vector<JSInterruptCallback, 2, js::SystemAllocPolicy>; 902 903 private: 904 js::ContextData<InterruptCallbackVector> interruptCallbacks_; 905 906 public: 907 InterruptCallbackVector& interruptCallbacks() { 908 return interruptCallbacks_.ref(); 909 } 910 911 js::ContextData<bool> interruptCallbackDisabled; 912 913 // Bitfield storing InterruptReason values. 914 mozilla::Atomic<uint32_t, mozilla::Relaxed> interruptBits_; 915 916 // Any thread can call requestInterrupt() to request that this thread 917 // stop running. To stop this thread, requestInterrupt sets two fields: 918 // interruptBits_ (a bitset of InterruptReasons) and jitStackLimit (set to 919 // JS::NativeStackLimitMin). The JS engine must continually poll one of these 920 // fields and call handleInterrupt if either field has the interrupt value. 921 // 922 // The point of setting jitStackLimit to JS::NativeStackLimitMin is that JIT 923 // code already needs to guard on jitStackLimit in every function prologue to 924 // avoid stack overflow, so we avoid a second branch on interruptBits_ by 925 // setting jitStackLimit to a value that is guaranteed to fail the guard.) 926 // 927 // Note that the writes to interruptBits_ and jitStackLimit use a Relaxed 928 // Atomic so, while the writes are guaranteed to eventually be visible to 929 // this thread, it can happen in any order. handleInterrupt calls the 930 // interrupt callback if either is set, so it really doesn't matter as long 931 // as the JS engine is continually polling at least one field. In corner 932 // cases, this relaxed ordering could lead to an interrupt handler being 933 // called twice in succession after a single requestInterrupt call, but 934 // that's fine. 935 void requestInterrupt(js::InterruptReason reason); 936 bool handleInterrupt(); 937 bool handleInterruptNoCallbacks(); 938 939 MOZ_ALWAYS_INLINE bool hasAnyPendingInterrupt() const { 940 static_assert(sizeof(interruptBits_) == sizeof(uint32_t), 941 "Assumed by JIT callers"); 942 return interruptBits_ != 0; 943 } 944 bool hasPendingInterrupt(js::InterruptReason reason) const { 945 return interruptBits_ & uint32_t(reason); 946 } 947 void clearPendingInterrupt(js::InterruptReason reason); 948 949 public: 950 void* addressOfInterruptBits() { return &interruptBits_; } 951 void* addressOfJitStackLimit() { return &jitStackLimit; } 952 void* addressOfJitStackLimitNoInterrupt() { 953 return &jitStackLimitNoInterrupt; 954 } 955 void* addressOfZone() { return &zone_; } 956 957 const void* addressOfRealm() const { return &realm_; } 958 959 const void* addressOfJitActivation() const { return &jitActivation; } 960 961 // Futex state, used by Atomics.wait() and Atomics.wake() on the Atomics 962 // object. 963 js::FutexThread fx; 964 965 mozilla::Atomic<JS::NativeStackLimit, mozilla::Relaxed> jitStackLimit; 966 967 // Like jitStackLimit, but not reset to trigger interrupts. 968 js::ContextData<JS::NativeStackLimit> jitStackLimitNoInterrupt; 969 970 // Queue of pending jobs as described in ES2016 section 8.4. 971 // 972 // This is a non-owning pointer to either: 973 // - a JobQueue implementation the embedding provided by calling 974 // JS::SetJobQueue, owned by the embedding, or 975 // - our internal JobQueue implementation, established by calling 976 // js::UseInternalJobQueues, owned by JSContext::internalJobQueue below. 977 js::ContextData<JS::JobQueue*> jobQueue; 978 979 // If the embedding has called js::UseInternalJobQueues, this is the owning 980 // pointer to our internal JobQueue implementation, which JSContext::jobQueue 981 // borrows. 982 js::ContextData<js::UniquePtr<js::InternalJobQueue>> internalJobQueue; 983 984 // True if jobQueue is empty, or we are running the last job in the queue. 985 // Such conditions permit optimizations around `await` expressions. 986 js::ContextData<bool> canSkipEnqueuingJobs; 987 988 js::ContextData<JS::PromiseRejectionTrackerCallback> 989 promiseRejectionTrackerCallback; 990 js::ContextData<void*> promiseRejectionTrackerCallbackData; 991 992 // Pre-allocated buffer for storing out-of-memory stack traces. 993 // This buffer is allocated during context initialization to avoid 994 // allocation during OOM conditions. The buffer stores a formatted 995 // stack trace string that can be retrieved by privileged JavaScript. 996 static constexpr size_t OOMStackTraceBufferSize = 4096; 997 js::ContextData<char*> oomStackTraceBuffer_; 998 js::ContextData<bool> oomStackTraceBufferValid_; 999 1000 JSObject* getIncumbentGlobal(JSContext* cx); 1001 bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, 1002 js::HandleObject promise, 1003 js::HandleObject incumbentGlobal); 1004 void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise); 1005 void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise); 1006 1007 private: 1008 template <class... Args> 1009 inline void checkImpl(const Args&... args); 1010 1011 bool contextChecksEnabled() const { 1012 // Don't perform these checks when called from a finalizer. The checking 1013 // depends on other objects not having been swept yet. 1014 return !RuntimeHeapIsCollecting(runtime()->heapState()); 1015 } 1016 1017 public: 1018 // Assert the arguments are in this context's realm (for scripts), 1019 // compartment (for objects) or zone (for strings, symbols). 1020 template <class... Args> 1021 inline void check(const Args&... args); 1022 template <class... Args> 1023 inline void releaseCheck(const Args&... args); 1024 template <class... Args> 1025 MOZ_ALWAYS_INLINE void debugOnlyCheck(const Args&... args); 1026 1027 #ifdef JS_STRUCTURED_SPEW 1028 private: 1029 // Spewer for this thread 1030 js::UnprotectedData<js::StructuredSpewer> structuredSpewer_; 1031 1032 public: 1033 js::StructuredSpewer& spewer() { return structuredSpewer_.ref(); } 1034 #endif 1035 1036 // This flag indicates whether we should bypass CSP restrictions for 1037 // eval() and Function() calls or not. This flag can be set when 1038 // evaluating the code for Debugger.Frame.prototype.eval. 1039 js::ContextData<bool> bypassCSPForDebugger; 1040 1041 // Debugger having set `exclusiveDebuggerOnEval` property to true 1042 // want their evaluations and calls to be ignore by all other Debuggers 1043 // except themself. This flag indicates whether we are in such debugger 1044 // evaluation, and which debugger initiated the evaluation. This debugger 1045 // has other references on the stack and does not need to be traced. 1046 js::ContextData<js::Debugger*> insideExclusiveDebuggerOnEval; 1047 1048 #ifdef MOZ_EXECUTION_TRACING 1049 private: 1050 CustomObjectSummaryCallback customObjectSummaryCallback_ = nullptr; 1051 1052 // This holds onto the JS execution tracer, a system which when turned on 1053 // records function calls and other information about the JS which has been 1054 // run under this context. 1055 js::UniquePtr<js::ExecutionTracer> executionTracer_; 1056 1057 // See suspendExecutionTracing 1058 bool executionTracerSuspended_ = false; 1059 1060 // Cleans up caches and realm flags associated with execution tracing, while 1061 // leaving the underlying tracing buffers intact to be read from later. 1062 void cleanUpExecutionTracingState(); 1063 1064 public: 1065 js::ExecutionTracer& getExecutionTracer() { 1066 MOZ_ASSERT(hasExecutionTracer()); 1067 return *executionTracer_; 1068 } 1069 1070 CustomObjectSummaryCallback getCustomObjectSummaryCallback() { 1071 MOZ_ASSERT(hasExecutionTracer()); 1072 return customObjectSummaryCallback_; 1073 } 1074 1075 void setCustomObjectSummaryCallback(CustomObjectSummaryCallback cb) { 1076 customObjectSummaryCallback_ = cb; 1077 } 1078 1079 // See the latter clause of the comment over executionTracer_ 1080 [[nodiscard]] bool enableExecutionTracing(); 1081 void disableExecutionTracing(); 1082 1083 // suspendExecutionTracing will turn off tracing, and clean up the relevant 1084 // flags on this context's realms, but still leave the trace around to be 1085 // collected. This currently is only called when an error occurs during 1086 // tracing. 1087 void suspendExecutionTracing(); 1088 1089 // Returns true if there is currently an ExecutionTracer tracing this 1090 // context's execution. 1091 bool hasExecutionTracer() { 1092 return !!executionTracer_ && !executionTracerSuspended_; 1093 } 1094 #else 1095 bool hasExecutionTracer() { return false; } 1096 #endif 1097 1098 JS::PersistentRooted<js::UniquePtr<js::MicroTaskQueueSet>> microTaskQueues; 1099 }; /* struct JSContext */ 1100 1101 inline JSContext* JSRuntime::mainContextFromOwnThread() { 1102 MOZ_ASSERT(mainContextFromAnyThread() == js::TlsContext.get()); 1103 return mainContextFromAnyThread(); 1104 } 1105 1106 namespace js { 1107 1108 struct MOZ_RAII AutoResolving { 1109 public: 1110 AutoResolving(JSContext* cx, HandleObject obj, HandleId id) 1111 : context(cx), object(obj), id(id), link(cx->resolvingList) { 1112 MOZ_ASSERT(obj); 1113 cx->resolvingList = this; 1114 } 1115 1116 ~AutoResolving() { 1117 MOZ_ASSERT(context->resolvingList == this); 1118 context->resolvingList = link; 1119 } 1120 1121 bool alreadyStarted() const { return link && alreadyStartedSlow(); } 1122 1123 private: 1124 bool alreadyStartedSlow() const; 1125 1126 JSContext* const context; 1127 HandleObject object; 1128 HandleId id; 1129 AutoResolving* const link; 1130 }; 1131 1132 /* 1133 * Create and destroy functions for JSContext, which is manually allocated 1134 * and exclusively owned. 1135 */ 1136 extern JSContext* NewContext(uint32_t maxBytes, JSRuntime* parentRuntime); 1137 1138 extern void DestroyContext(JSContext* cx); 1139 1140 /* |callee| requires a usage string provided by JS_DefineFunctionsWithHelp. */ 1141 extern void ReportUsageErrorASCII(JSContext* cx, HandleObject callee, 1142 const char* msg); 1143 1144 extern void ReportIsNotDefined(JSContext* cx, Handle<PropertyName*> name); 1145 1146 extern void ReportIsNotDefined(JSContext* cx, HandleId id); 1147 1148 /* 1149 * Report an attempt to access the property of a null or undefined value (v). 1150 */ 1151 extern void ReportIsNullOrUndefinedForPropertyAccess(JSContext* cx, 1152 HandleValue v, int vIndex); 1153 extern void ReportIsNullOrUndefinedForPropertyAccess(JSContext* cx, 1154 HandleValue v, int vIndex, 1155 HandleId key); 1156 1157 /* 1158 * Report error using js::DecompileValueGenerator(cx, spindex, v, fallback) as 1159 * the first argument for the error message. 1160 */ 1161 extern bool ReportValueError(JSContext* cx, const unsigned errorNumber, 1162 int spindex, HandleValue v, HandleString fallback, 1163 const char* arg1 = nullptr, 1164 const char* arg2 = nullptr); 1165 1166 JSObject* CreateErrorNotesArray(JSContext* cx, JSErrorReport* report); 1167 1168 /************************************************************************/ 1169 1170 /* 1171 * Encapsulates an external array of values and adds a trace method, for use in 1172 * Rooted. 1173 */ 1174 class MOZ_STACK_CLASS ExternalValueArray { 1175 public: 1176 ExternalValueArray(size_t len, Value* vec) : array_(vec), length_(len) {} 1177 1178 Value* begin() { return array_; } 1179 size_t length() { return length_; } 1180 1181 void trace(JSTracer* trc); 1182 1183 private: 1184 Value* array_; 1185 size_t length_; 1186 }; 1187 1188 /* RootedExternalValueArray roots an external array of Values. */ 1189 class MOZ_RAII RootedExternalValueArray 1190 : public JS::Rooted<ExternalValueArray> { 1191 public: 1192 RootedExternalValueArray(JSContext* cx, size_t len, Value* vec) 1193 : JS::Rooted<ExternalValueArray>(cx, ExternalValueArray(len, vec)) {} 1194 1195 private: 1196 }; 1197 1198 class AutoAssertNoPendingException { 1199 #ifdef DEBUG 1200 JSContext* cx_; 1201 1202 public: 1203 explicit AutoAssertNoPendingException(JSContext* cxArg) : cx_(cxArg) { 1204 MOZ_ASSERT(!JS_IsExceptionPending(cx_)); 1205 } 1206 1207 ~AutoAssertNoPendingException() { MOZ_ASSERT(!JS_IsExceptionPending(cx_)); } 1208 #else 1209 public: 1210 explicit AutoAssertNoPendingException(JSContext* cxArg) {} 1211 #endif 1212 }; 1213 1214 class MOZ_RAII AutoNoteExclusiveDebuggerOnEval { 1215 JSContext* cx; 1216 Debugger* oldValue; 1217 1218 public: 1219 AutoNoteExclusiveDebuggerOnEval(JSContext* cx, Debugger* dbg) 1220 : cx(cx), oldValue(cx->insideExclusiveDebuggerOnEval) { 1221 cx->insideExclusiveDebuggerOnEval = dbg; 1222 } 1223 1224 ~AutoNoteExclusiveDebuggerOnEval() { 1225 cx->insideExclusiveDebuggerOnEval = oldValue; 1226 } 1227 }; 1228 1229 class MOZ_RAII AutoSetBypassCSPForDebugger { 1230 JSContext* cx; 1231 bool oldValue; 1232 1233 public: 1234 AutoSetBypassCSPForDebugger(JSContext* cx, bool value) 1235 : cx(cx), oldValue(cx->bypassCSPForDebugger) { 1236 cx->bypassCSPForDebugger = value; 1237 } 1238 1239 ~AutoSetBypassCSPForDebugger() { cx->bypassCSPForDebugger = oldValue; } 1240 }; 1241 1242 enum UnsafeABIStrictness { NoExceptions, AllowPendingExceptions }; 1243 1244 // Should be used in functions called directly from JIT code (with 1245 // masm.callWithABI). This assert invariants in debug builds. Resets 1246 // JSContext::inUnsafeCallWithABI on destruction. 1247 // 1248 // In debug mode, masm.callWithABI inserts code to verify that the callee 1249 // function uses AutoUnsafeCallWithABI. 1250 // 1251 // While this object is live: 1252 // 1. cx->hasAutoUnsafeCallWithABI must be true. 1253 // 2. We can't GC. 1254 // 3. Exceptions should not be pending/thrown. 1255 // 1256 // Note that #3 is a precaution, not a requirement. By default, we assert that 1257 // the function is not called with a pending exception, and that it does not 1258 // throw an exception itself. 1259 class MOZ_RAII AutoUnsafeCallWithABI { 1260 #ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI 1261 JSContext* cx_; 1262 bool nested_; 1263 bool checkForPendingException_; 1264 #endif 1265 JS::AutoCheckCannotGC nogc; 1266 1267 public: 1268 #ifdef JS_CHECK_UNSAFE_CALL_WITH_ABI 1269 explicit AutoUnsafeCallWithABI( 1270 UnsafeABIStrictness strictness = UnsafeABIStrictness::NoExceptions); 1271 ~AutoUnsafeCallWithABI(); 1272 #else 1273 explicit AutoUnsafeCallWithABI( 1274 UnsafeABIStrictness unused_ = UnsafeABIStrictness::NoExceptions) {} 1275 #endif 1276 }; 1277 1278 template <typename T> 1279 inline BufferHolder<T>::BufferHolder(JSContext* cx, T* buffer) 1280 : BufferHolder(cx->zone(), buffer) {} 1281 1282 } /* namespace js */ 1283 1284 #define CHECK_THREAD(cx) \ 1285 MOZ_ASSERT_IF(cx, js::CurrentThreadCanAccessRuntime(cx->runtime())) 1286 1287 /** 1288 * [SMDOC] JS::Result transitional macros 1289 * 1290 * ## Checking Results when your return type is not Result 1291 * 1292 * This header defines alternatives to MOZ_TRY for when you 1293 * need to call a `Result` function from a function that uses false or nullptr 1294 * to indicate errors: 1295 * 1296 * JS_TRY_OR_RETURN_FALSE(cx, DefenestrateObject(cx, obj)); 1297 * JS_TRY_VAR_OR_RETURN_FALSE(cx, v, GetObjectThrug(cx, obj)); 1298 * 1299 * JS_TRY_VAR_OR_RETURN_NULL(cx, v, GetObjectThrug(cx, obj)); 1300 * 1301 * When TRY is not what you want, because you need to do some cleanup or 1302 * recovery on error, use this idiom: 1303 * 1304 * if (!cx->resultToBool(expr_that_is_a_Result)) { 1305 * ... your recovery code here ... 1306 * } 1307 * 1308 * In place of a tail call, you can use one of these methods: 1309 * 1310 * return cx->resultToBool(expr); // false on error 1311 * return cx->resultToPtr(expr); // null on error 1312 * 1313 * Once we are using `Result` everywhere, including in public APIs, all of 1314 * these will go away. 1315 */ 1316 1317 /** 1318 * JS_TRY_OR_RETURN_FALSE(cx, expr) runs expr to compute a Result value. 1319 * On success, nothing happens; on error, it returns false immediately. 1320 * 1321 * Implementation note: this involves cx because this may eventually 1322 * do the work of setting a pending exception or reporting OOM. 1323 */ 1324 #define JS_TRY_OR_RETURN_FALSE(cx, expr) \ 1325 do { \ 1326 auto tmpResult_ = (expr); \ 1327 if (tmpResult_.isErr()) return (cx)->resultToBool(tmpResult_); \ 1328 } while (0) 1329 1330 #define JS_TRY_VAR_OR_RETURN_FALSE(cx, target, expr) \ 1331 do { \ 1332 auto tmpResult_ = (expr); \ 1333 if (tmpResult_.isErr()) return (cx)->resultToBool(tmpResult_); \ 1334 (target) = tmpResult_.unwrap(); \ 1335 } while (0) 1336 1337 #define JS_TRY_VAR_OR_RETURN_NULL(cx, target, expr) \ 1338 do { \ 1339 auto tmpResult_ = (expr); \ 1340 if (tmpResult_.isErr()) { \ 1341 MOZ_ALWAYS_FALSE((cx)->resultToBool(tmpResult_)); \ 1342 return nullptr; \ 1343 } \ 1344 (target) = tmpResult_.unwrap(); \ 1345 } while (0) 1346 1347 #endif /* vm_JSContext_h */