Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sts=4 et sw=4 tw=99:
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_Runtime_h
8 : #define vm_Runtime_h
9 :
10 : #include "mozilla/Atomics.h"
11 : #include "mozilla/Attributes.h"
12 : #include "mozilla/DoublyLinkedList.h"
13 : #include "mozilla/LinkedList.h"
14 : #include "mozilla/Maybe.h"
15 : #include "mozilla/MaybeOneOf.h"
16 : #include "mozilla/MemoryReporting.h"
17 : #include "mozilla/Scoped.h"
18 : #include "mozilla/ThreadLocal.h"
19 : #include "mozilla/Vector.h"
20 :
21 : #include <algorithm>
22 : #include <setjmp.h>
23 :
24 : #include "builtin/AtomicsObject.h"
25 : #include "builtin/intl/SharedIntlData.h"
26 : #include "builtin/Promise.h"
27 : #include "frontend/BinSourceRuntimeSupport.h"
28 : #include "frontend/NameCollections.h"
29 : #include "gc/GCRuntime.h"
30 : #include "gc/Tracer.h"
31 : #include "irregexp/RegExpStack.h"
32 : #include "js/Debug.h"
33 : #include "js/GCVector.h"
34 : #include "js/HashTable.h"
35 : #ifdef DEBUG
36 : # include "js/Proxy.h" // For AutoEnterPolicy
37 : #endif
38 : #include "js/UniquePtr.h"
39 : #include "js/Vector.h"
40 : #include "threading/Thread.h"
41 : #include "vm/Caches.h"
42 : #include "vm/CodeCoverage.h"
43 : #include "vm/CommonPropertyNames.h"
44 : #include "vm/DateTime.h"
45 : #include "vm/GeckoProfiler.h"
46 : #include "vm/JSAtom.h"
47 : #include "vm/JSScript.h"
48 : #include "vm/Scope.h"
49 : #include "vm/SharedImmutableStringsCache.h"
50 : #include "vm/Stack.h"
51 : #include "vm/Stopwatch.h"
52 : #include "vm/SymbolType.h"
53 : #include "wasm/WasmTypes.h"
54 :
55 : namespace js {
56 :
57 : class AutoAssertNoContentJS;
58 : class AutoKeepAtoms;
59 : class EnterDebuggeeNoExecute;
60 : #ifdef JS_TRACE_LOGGING
61 : class TraceLoggerThread;
62 : #endif
63 :
64 : } // namespace js
65 :
66 : struct DtoaState;
67 :
68 : #ifdef JS_SIMULATOR_ARM64
69 : namespace vixl {
70 : class Simulator;
71 : }
72 : #endif
73 :
74 : namespace js {
75 :
76 : extern MOZ_COLD void
77 : ReportOutOfMemory(JSContext* cx);
78 :
79 : /* Different signature because the return type has MOZ_MUST_USE_TYPE. */
80 : extern MOZ_COLD mozilla::GenericErrorResult<OOM&>
81 : ReportOutOfMemoryResult(JSContext* cx);
82 :
83 : extern MOZ_COLD void
84 : ReportAllocationOverflow(JSContext* maybecx);
85 :
86 : extern MOZ_COLD void
87 : ReportOverRecursed(JSContext* cx);
88 :
89 : class Activation;
90 : class ActivationIterator;
91 :
92 : namespace jit {
93 : class JitRuntime;
94 : class JitActivation;
95 : struct PcScriptCache;
96 : struct AutoFlushICache;
97 : class CompileRuntime;
98 :
99 : #ifdef JS_SIMULATOR_ARM64
100 : typedef vixl::Simulator Simulator;
101 : #elif defined(JS_SIMULATOR)
102 : class Simulator;
103 : #endif
104 : } // namespace jit
105 :
106 : // JS Engine Threading
107 : //
108 : // Threads interacting with a runtime are divided into two categories:
109 : //
110 : // - The main thread is capable of running JS. There's at most one main thread
111 : // per runtime.
112 : //
113 : // - Helper threads do not run JS, and are controlled or triggered by activity
114 : // on the main thread (or main threads, since all runtimes in a process share
115 : // helper threads). Helper threads may have exclusive access to zones created
116 : // for them, for parsing and similar tasks, but their activities do not cause
117 : // observable changes in script behaviors. Activity on helper threads may be
118 : // referred to as happening 'off thread' or on a background thread in some
119 : // parts of the VM.
120 :
121 : } /* namespace js */
122 :
123 : namespace JS {
124 : struct RuntimeSizes;
125 : } // namespace JS
126 :
127 : /* Various built-in or commonly-used names pinned on first context. */
128 : struct JSAtomState
129 : {
130 : #define PROPERTYNAME_FIELD(idpart, id, text) js::ImmutablePropertyNamePtr id;
131 : FOR_EACH_COMMON_PROPERTYNAME(PROPERTYNAME_FIELD)
132 : #undef PROPERTYNAME_FIELD
133 : #define PROPERTYNAME_FIELD(name, init, clasp) js::ImmutablePropertyNamePtr name;
134 : JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD)
135 : #undef PROPERTYNAME_FIELD
136 : #define PROPERTYNAME_FIELD(name) js::ImmutablePropertyNamePtr name;
137 : JS_FOR_EACH_WELL_KNOWN_SYMBOL(PROPERTYNAME_FIELD)
138 : #undef PROPERTYNAME_FIELD
139 : #define PROPERTYNAME_FIELD(name) js::ImmutablePropertyNamePtr Symbol_##name;
140 : JS_FOR_EACH_WELL_KNOWN_SYMBOL(PROPERTYNAME_FIELD)
141 : #undef PROPERTYNAME_FIELD
142 :
143 : js::ImmutablePropertyNamePtr* wellKnownSymbolNames() {
144 : #define FIRST_PROPERTYNAME_FIELD(name) return &name;
145 0 : JS_FOR_EACH_WELL_KNOWN_SYMBOL(FIRST_PROPERTYNAME_FIELD)
146 : #undef FIRST_PROPERTYNAME_FIELD
147 : }
148 :
149 : js::ImmutablePropertyNamePtr* wellKnownSymbolDescriptions() {
150 : #define FIRST_PROPERTYNAME_FIELD(name) return &Symbol_ ##name;
151 0 : JS_FOR_EACH_WELL_KNOWN_SYMBOL(FIRST_PROPERTYNAME_FIELD)
152 : #undef FIRST_PROPERTYNAME_FIELD
153 : }
154 : };
155 :
156 : namespace js {
157 :
158 : /*
159 : * Storage for well-known symbols. It's a separate struct from the Runtime so
160 : * that it can be shared across multiple runtimes. As in JSAtomState, each
161 : * field is a smart pointer that's immutable once initialized.
162 : * `rt->wellKnownSymbols->iterator` is convertible to Handle<Symbol*>.
163 : *
164 : * Well-known symbols are never GC'd. The description() of each well-known
165 : * symbol is a permanent atom.
166 : */
167 : struct WellKnownSymbols
168 : {
169 : #define DECLARE_SYMBOL(name) js::ImmutableSymbolPtr name;
170 : JS_FOR_EACH_WELL_KNOWN_SYMBOL(DECLARE_SYMBOL)
171 : #undef DECLARE_SYMBOL
172 :
173 0 : const ImmutableSymbolPtr& get(size_t u) const {
174 0 : MOZ_ASSERT(u < JS::WellKnownSymbolLimit);
175 0 : const ImmutableSymbolPtr* symbols = reinterpret_cast<const ImmutableSymbolPtr*>(this);
176 0 : return symbols[u];
177 : }
178 :
179 : const ImmutableSymbolPtr& get(JS::SymbolCode code) const {
180 0 : return get(size_t(code));
181 : }
182 :
183 0 : WellKnownSymbols() {}
184 : WellKnownSymbols(const WellKnownSymbols&) = delete;
185 : WellKnownSymbols& operator=(const WellKnownSymbols&) = delete;
186 : };
187 :
188 : #define NAME_OFFSET(name) offsetof(JSAtomState, name)
189 :
190 : inline HandlePropertyName
191 : AtomStateOffsetToName(const JSAtomState& atomState, size_t offset)
192 : {
193 0 : return *reinterpret_cast<js::ImmutablePropertyNamePtr*>((char*)&atomState + offset);
194 : }
195 :
196 : // There are several coarse locks in the enum below. These may be either
197 : // per-runtime or per-process. When acquiring more than one of these locks,
198 : // the acquisition must be done in the order below to avoid deadlocks.
199 : enum RuntimeLock {
200 : ExclusiveAccessLock,
201 : HelperThreadStateLock,
202 : GCLock
203 : };
204 :
205 : inline bool
206 : CanUseExtraThreads()
207 : {
208 : extern bool gCanUseExtraThreads;
209 0 : return gCanUseExtraThreads;
210 : }
211 :
212 : void DisableExtraThreads();
213 :
214 : using ScriptAndCountsVector = GCVector<ScriptAndCounts, 0, SystemAllocPolicy>;
215 :
216 : class AutoLockForExclusiveAccess;
217 : class AutoLockScriptData;
218 :
219 : } // namespace js
220 :
221 : struct JSRuntime : public js::MallocProvider<JSRuntime>
222 : {
223 : private:
224 : friend class js::Activation;
225 : friend class js::ActivationIterator;
226 : friend class js::jit::JitActivation;
227 : friend class js::jit::CompileRuntime;
228 :
229 : public:
230 : /*
231 : * If non-null, another runtime guaranteed to outlive this one and whose
232 : * permanent data may be used by this one where possible.
233 : */
234 : JSRuntime* const parentRuntime;
235 :
236 : #ifdef DEBUG
237 : /* The number of child runtimes that have this runtime as their parent. */
238 : mozilla::Atomic<size_t> childRuntimeCount;
239 :
240 : class AutoUpdateChildRuntimeCount
241 : {
242 : JSRuntime* parent_;
243 :
244 : public:
245 : explicit AutoUpdateChildRuntimeCount(JSRuntime* parent)
246 0 : : parent_(parent)
247 : {
248 0 : if (parent_)
249 0 : parent_->childRuntimeCount++;
250 : }
251 :
252 : ~AutoUpdateChildRuntimeCount() {
253 0 : if (parent_)
254 0 : parent_->childRuntimeCount--;
255 : }
256 : };
257 :
258 : AutoUpdateChildRuntimeCount updateChildRuntimeCount;
259 : #endif
260 :
261 : private:
262 : #ifdef DEBUG
263 : js::WriteOnceData<bool> initialized_;
264 : #endif
265 :
266 : // The JSContext* for the runtime's main thread. Immutable after this is set
267 : // in JSRuntime::init.
268 : JSContext* mainContext_;
269 :
270 : public:
271 : JSContext* mainContextFromAnyThread() const { return mainContext_; }
272 : const void* addressOfMainContext() { return &mainContext_; }
273 :
274 : inline JSContext* mainContextFromOwnThread();
275 :
276 : /*
277 : * The start of the range stored in the profiler sample buffer, as measured
278 : * after the most recent sample.
279 : * All JitcodeGlobalTable entries referenced from a given sample are
280 : * assigned the buffer position of the START of the sample. The buffer
281 : * entries that reference the JitcodeGlobalTable entries will only ever be
282 : * read from the buffer while the entire sample is still inside the buffer;
283 : * if some buffer entries at the start of the sample have left the buffer,
284 : * the entire sample will be considered inaccessible.
285 : * This means that, once profilerSampleBufferRangeStart_ advances beyond
286 : * the sample position that's stored on a JitcodeGlobalTable entry, the
287 : * buffer entries that reference this JitcodeGlobalTable entry will be
288 : * considered inaccessible, and those JitcodeGlobalTable entry can be
289 : * disposed of.
290 : */
291 : mozilla::Atomic<uint64_t, mozilla::ReleaseAcquire> profilerSampleBufferRangeStart_;
292 :
293 0 : mozilla::Maybe<uint64_t> profilerSampleBufferRangeStart() {
294 0 : if (beingDestroyed_ || !geckoProfiler().enabled()) {
295 : return mozilla::Nothing();
296 : }
297 0 : uint64_t rangeStart = profilerSampleBufferRangeStart_;
298 : return mozilla::Some(rangeStart);
299 : }
300 : void setProfilerSampleBufferRangeStart(uint64_t rangeStart) {
301 0 : profilerSampleBufferRangeStart_ = rangeStart;
302 : }
303 :
304 : /* Call this to accumulate telemetry data. */
305 : js::MainThreadData<JSAccumulateTelemetryDataCallback> telemetryCallback;
306 :
307 : /* Call this to accumulate use counter data. */
308 : js::MainThreadData<JSSetUseCounterCallback> useCounterCallback;
309 :
310 : public:
311 : // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
312 : // histogram. |key| provides an additional key to identify the histogram.
313 : // |sample| is the data to add to the histogram.
314 : void addTelemetry(int id, uint32_t sample, const char* key = nullptr);
315 :
316 : void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback);
317 :
318 : // Sets the use counter for a specific feature, measuring the presence or
319 : // absence of usage of a feature on a specific web page and document which
320 : // the passed JSObject belongs to.
321 : void setUseCounter(JSObject* obj, JSUseCounter counter);
322 :
323 : void setUseCounterCallback(JSRuntime* rt, JSSetUseCounterCallback callback);
324 :
325 : public:
326 : js::UnprotectedData<js::OffThreadPromiseRuntimeState> offThreadPromiseState;
327 : js::UnprotectedData<JS::ConsumeStreamCallback> consumeStreamCallback;
328 :
329 : JSObject* getIncumbentGlobal(JSContext* cx);
330 : bool enqueuePromiseJob(JSContext* cx, js::HandleFunction job, js::HandleObject promise,
331 : js::HandleObject incumbentGlobal);
332 : void addUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
333 : void removeUnhandledRejectedPromise(JSContext* cx, js::HandleObject promise);
334 :
335 : js::UnprotectedData<JS::RequestReadableStreamDataCallback> readableStreamDataRequestCallback;
336 : js::UnprotectedData<JS::WriteIntoReadRequestBufferCallback> readableStreamWriteIntoReadRequestCallback;
337 : js::UnprotectedData<JS::CancelReadableStreamCallback> readableStreamCancelCallback;
338 : js::UnprotectedData<JS::ReadableStreamClosedCallback> readableStreamClosedCallback;
339 : js::UnprotectedData<JS::ReadableStreamErroredCallback> readableStreamErroredCallback;
340 : js::UnprotectedData<JS::ReadableStreamFinalizeCallback> readableStreamFinalizeCallback;
341 :
342 : /* Had an out-of-memory error which did not populate an exception. */
343 : mozilla::Atomic<bool> hadOutOfMemory;
344 :
345 : /*
346 : * Allow relazifying functions in compartments that are active. This is
347 : * only used by the relazifyFunctions() testing function.
348 : */
349 : js::MainThreadData<bool> allowRelazificationForTesting;
350 :
351 : /* Compartment destroy callback. */
352 : js::MainThreadData<JSDestroyCompartmentCallback> destroyCompartmentCallback;
353 :
354 : /* Compartment memory reporting callback. */
355 : js::MainThreadData<JSSizeOfIncludingThisCompartmentCallback> sizeOfIncludingThisCompartmentCallback;
356 :
357 : /* Realm destroy callback. */
358 : js::MainThreadData<JS::DestroyRealmCallback> destroyRealmCallback;
359 :
360 : /* Call this to get the name of a realm. */
361 : js::MainThreadData<JS::RealmNameCallback> realmNameCallback;
362 :
363 : /* Callback for doing memory reporting on external strings. */
364 : js::MainThreadData<JSExternalStringSizeofCallback> externalStringSizeofCallback;
365 :
366 : js::MainThreadData<mozilla::UniquePtr<js::SourceHook>> sourceHook;
367 :
368 : js::MainThreadData<const JSSecurityCallbacks*> securityCallbacks;
369 : js::MainThreadData<const js::DOMCallbacks*> DOMcallbacks;
370 : js::MainThreadData<JSDestroyPrincipalsOp> destroyPrincipals;
371 : js::MainThreadData<JSReadPrincipalsOp> readPrincipals;
372 :
373 : /* Optional warning reporter. */
374 : js::MainThreadData<JS::WarningReporter> warningReporter;
375 :
376 : private:
377 : /* Gecko profiling metadata */
378 : js::UnprotectedData<js::GeckoProfilerRuntime> geckoProfiler_;
379 : public:
380 32660 : js::GeckoProfilerRuntime& geckoProfiler() { return geckoProfiler_.ref(); }
381 :
382 : // Heap GC roots for PersistentRooted pointers.
383 : js::MainThreadData<mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit,
384 : mozilla::LinkedList<JS::PersistentRooted<void*>>>> heapRoots;
385 :
386 : void tracePersistentRoots(JSTracer* trc);
387 : void finishPersistentRoots();
388 :
389 : void finishRoots();
390 :
391 : public:
392 : js::UnprotectedData<JS::BuildIdOp> buildIdOp;
393 :
394 : /* AsmJSCache callbacks are runtime-wide. */
395 : js::UnprotectedData<JS::AsmJSCacheOps> asmJSCacheOps;
396 :
397 : private:
398 : js::UnprotectedData<const JSPrincipals*> trustedPrincipals_;
399 : public:
400 2 : void setTrustedPrincipals(const JSPrincipals* p) { trustedPrincipals_ = p; }
401 34464 : const JSPrincipals* trustedPrincipals() const { return trustedPrincipals_; }
402 :
403 : js::MainThreadData<const JSWrapObjectCallbacks*> wrapObjectCallbacks;
404 : js::MainThreadData<js::PreserveWrapperCallback> preserveWrapperCallback;
405 :
406 : js::MainThreadData<js::ScriptEnvironmentPreparer*> scriptEnvironmentPreparer;
407 :
408 : js::MainThreadData<js::CTypesActivityCallback> ctypesActivityCallback;
409 :
410 : private:
411 : js::WriteOnceData<const js::Class*> windowProxyClass_;
412 :
413 : public:
414 : const js::Class* maybeWindowProxyClass() const {
415 124608 : return windowProxyClass_;
416 : }
417 : void setWindowProxyClass(const js::Class* clasp) {
418 0 : windowProxyClass_ = clasp;
419 : }
420 :
421 : private:
422 : // List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup.
423 : js::MainThreadData<mozilla::LinkedList<JS::detail::WeakCacheBase>> weakCaches_;
424 : public:
425 0 : mozilla::LinkedList<JS::detail::WeakCacheBase>& weakCaches() { return weakCaches_.ref(); }
426 : void registerWeakCache(JS::detail::WeakCacheBase* cachep) {
427 0 : weakCaches().insertBack(cachep);
428 : }
429 :
430 : template <typename T>
431 : struct GlobalObjectWatchersLinkAccess {
432 : static mozilla::DoublyLinkedListElement<T>& Get(T* aThis) {
433 : return aThis->onNewGlobalObjectWatchersLink;
434 : }
435 : };
436 :
437 : using WatchersList =
438 : mozilla::DoublyLinkedList<js::Debugger,
439 : GlobalObjectWatchersLinkAccess<js::Debugger>>;
440 : private:
441 : /*
442 : * List of all enabled Debuggers that have onNewGlobalObject handler
443 : * methods established.
444 : */
445 : js::MainThreadData<WatchersList> onNewGlobalObjectWatchers_;
446 :
447 : public:
448 42 : WatchersList& onNewGlobalObjectWatchers() { return onNewGlobalObjectWatchers_.ref(); }
449 :
450 : private:
451 : /* Linked list of all Debugger objects in the runtime. */
452 : js::MainThreadData<mozilla::LinkedList<js::Debugger>> debuggerList_;
453 : public:
454 4 : mozilla::LinkedList<js::Debugger>& debuggerList() { return debuggerList_.ref(); }
455 :
456 : private:
457 : /*
458 : * Lock taken when using per-runtime or per-zone data that could otherwise
459 : * be accessed simultaneously by multiple threads.
460 : *
461 : * Locking this only occurs if there is actually a thread other than the
462 : * main thread which could access such data.
463 : */
464 : js::Mutex exclusiveAccessLock;
465 : #ifdef DEBUG
466 : bool activeThreadHasExclusiveAccess;
467 : #endif
468 :
469 : /*
470 : * Lock used to protect the script data table, which can be used by
471 : * off-thread parsing.
472 : *
473 : * Locking this only occurs if there is actually a thread other than the
474 : * main thread which could access this.
475 : */
476 : js::Mutex scriptDataLock;
477 : #ifdef DEBUG
478 : bool activeThreadHasScriptDataAccess;
479 : #endif
480 :
481 : // Number of zones which may be operated on by helper threads.
482 : mozilla::Atomic<size_t> numActiveHelperThreadZones;
483 :
484 : // Any GC activity affecting the heap.
485 : mozilla::Atomic<JS::HeapState> heapState_;
486 :
487 : friend class js::AutoLockForExclusiveAccess;
488 : friend class js::AutoLockScriptData;
489 :
490 : public:
491 : void setUsedByHelperThread(JS::Zone* zone);
492 943788 : void clearUsedByHelperThread(JS::Zone* zone);
493 :
494 : bool hasHelperThreadZones() const {
495 : return numActiveHelperThreadZones > 0;
496 286157 : }
497 286157 :
498 258881 : #ifdef DEBUG
499 : bool currentThreadHasExclusiveAccess() const {
500 0 : if (!hasHelperThreadZones())
501 : return CurrentThreadCanAccessRuntime(this) && activeThreadHasExclusiveAccess;
502 :
503 0 : return exclusiveAccessLock.ownedByCurrentThread();
504 25417 : }
505 21614 :
506 : bool currentThreadHasScriptDataAccess() const {
507 0 : if (!hasHelperThreadZones())
508 : return CurrentThreadCanAccessRuntime(this) && activeThreadHasScriptDataAccess;
509 :
510 : return scriptDataLock.ownedByCurrentThread();
511 : }
512 : #endif
513 :
514 : JS::HeapState heapState() const {
515 : return heapState_;
516 : }
517 :
518 : // How many realms there are across all zones. This number includes
519 : // off-thread context realms, so it isn't necessarily equal to the
520 : // number of realms visited by RealmsIter.
521 : js::MainThreadData<size_t> numRealms;
522 :
523 : /* Locale-specific callbacks for string conversion. */
524 : js::MainThreadData<const JSLocaleCallbacks*> localeCallbacks;
525 :
526 : /* Default locale for Internationalization API */
527 : js::MainThreadData<char*> defaultLocale;
528 :
529 : /* If true, new scripts must be created with PC counter information. */
530 : js::MainThreadOrIonCompileData<bool> profilingScripts;
531 :
532 40468 : /* Strong references on scripts held for PCCount profiling API. */
533 : js::MainThreadData<JS::PersistentRooted<js::ScriptAndCountsVector>*> scriptAndCountsVector;
534 :
535 : private:
536 : /* Code coverage output. */
537 : js::UnprotectedData<js::coverage::LCovRuntime> lcovOutput_;
538 : public:
539 : js::coverage::LCovRuntime& lcovOutput() { return lcovOutput_.ref(); }
540 :
541 : private:
542 : js::UnprotectedData<js::jit::JitRuntime*> jitRuntime_;
543 :
544 : /*
545 : * Self-hosting state cloned on demand into other compartments. Shared with the parent
546 : * runtime if there is one.
547 : */
548 : js::WriteOnceData<js::NativeObject*> selfHostingGlobal_;
549 :
550 : static js::GlobalObject*
551 : createSelfHostingGlobal(JSContext* cx);
552 :
553 14 : bool getUnclonedSelfHostedValue(JSContext* cx, js::HandlePropertyName name,
554 38 : js::MutableHandleValue vp);
555 : JSFunction* getUnclonedSelfHostedFunction(JSContext* cx, js::HandlePropertyName name);
556 :
557 0 : js::jit::JitRuntime* createJitRuntime(JSContext* cx);
558 :
559 : public:
560 0 : js::jit::JitRuntime* getJitRuntime(JSContext* cx) {
561 : return jitRuntime_ ? jitRuntime_.ref() : createJitRuntime(cx);
562 : }
563 : js::jit::JitRuntime* jitRuntime() const {
564 : return jitRuntime_.ref();
565 : }
566 : bool hasJitRuntime() const {
567 : return !!jitRuntime_;
568 : }
569 :
570 : private:
571 : // Used to generate random keys for hash tables.
572 : mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomKeyGenerator_;
573 : mozilla::non_crypto::XorShift128PlusRNG& randomKeyGenerator();
574 :
575 : // Used to generate random hash codes for symbols.
576 : mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomHashCodeGenerator_;
577 :
578 : public:
579 : mozilla::HashCodeScrambler randomHashCodeScrambler();
580 : mozilla::non_crypto::XorShift128PlusRNG forkRandomKeyGenerator();
581 :
582 96 : js::HashNumber randomHashCode();
583 :
584 : //-------------------------------------------------------------------------
585 : // Self-hosting support
586 : //-------------------------------------------------------------------------
587 :
588 : bool hasInitializedSelfHosting() const {
589 231720 : return selfHostingGlobal_;
590 : }
591 :
592 : bool initSelfHosting(JSContext* cx);
593 : void finishSelfHosting();
594 : void traceSelfHostingGlobal(JSTracer* trc);
595 : bool isSelfHostingGlobal(JSObject* global) {
596 : return global == selfHostingGlobal_;
597 : }
598 : bool isSelfHostingZone(const JS::Zone* zone) const;
599 : bool createLazySelfHostedFunctionClone(JSContext* cx, js::HandlePropertyName selfHostedName,
600 : js::HandleAtom name, unsigned nargs,
601 : js::HandleObject proto,
602 : js::NewObjectKind newKind,
603 : js::MutableHandleFunction fun);
604 : bool cloneSelfHostedFunctionScript(JSContext* cx, js::Handle<js::PropertyName*> name,
605 : js::Handle<JSFunction*> targetFun);
606 : bool cloneSelfHostedValue(JSContext* cx, js::Handle<js::PropertyName*> name,
607 : js::MutableHandleValue vp);
608 : void assertSelfHostedFunctionHasCanonicalName(JSContext* cx, js::HandlePropertyName name);
609 :
610 : //-------------------------------------------------------------------------
611 : // Locale information
612 : //-------------------------------------------------------------------------
613 :
614 : /*
615 : * Set the default locale for the ECMAScript Internationalization API
616 : * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
617 : * Note that the Internationalization API encourages clients to
618 : * specify their own locales.
619 : * The locale string remains owned by the caller.
620 : */
621 : bool setDefaultLocale(const char* locale);
622 :
623 : /* Reset the default locale to OS defaults. */
624 : void resetDefaultLocale();
625 :
626 : /* Gets current default locale. String remains owned by context. */
627 : const char* getDefaultLocale();
628 84 :
629 : /* Garbage collector state. */
630 : js::gc::GCRuntime gc;
631 :
632 : /* Garbage collector state has been successfully initialized. */
633 : js::WriteOnceData<bool> gcInitialized;
634 :
635 : bool hasZealMode(js::gc::ZealMode mode) { return gc.hasZealMode(mode); }
636 :
637 : void lockGC() {
638 : gc.lockGC();
639 : }
640 :
641 : void unlockGC() {
642 : gc.unlockGC();
643 : }
644 :
645 : /* Well-known numbers. */
646 : const js::Value NaNValue;
647 : const js::Value negativeInfinityValue;
648 : const js::Value positiveInfinityValue;
649 130110 :
650 260220 : js::WriteOnceData<js::PropertyName*> emptyString;
651 260220 :
652 : private:
653 : js::WriteOnceData<js::FreeOp*> defaultFreeOp_;
654 :
655 : public:
656 : js::FreeOp* defaultFreeOp() {
657 : MOZ_ASSERT(defaultFreeOp_);
658 : return defaultFreeOp_;
659 : }
660 :
661 : #if !EXPOSE_INTL_API
662 : /* Number localization, used by jsnum.cpp. */
663 : js::WriteOnceData<const char*> thousandsSeparator;
664 : js::WriteOnceData<const char*> decimalSeparator;
665 : js::WriteOnceData<const char*> numGrouping;
666 : #endif
667 :
668 0 : private:
669 : mozilla::Maybe<js::SharedImmutableStringsCache> sharedImmutableStrings_;
670 :
671 : public:
672 : // If this particular JSRuntime has a SharedImmutableStringsCache, return a
673 1007 : // pointer to it, otherwise return nullptr.
674 1131 : js::SharedImmutableStringsCache* maybeThisRuntimeSharedImmutableStrings() {
675 2076 : return sharedImmutableStrings_.isSome() ? &*sharedImmutableStrings_ : nullptr;
676 0 : }
677 :
678 : // Get a reference to this JSRuntime's or its parent's
679 : // SharedImmutableStringsCache.
680 : js::SharedImmutableStringsCache& sharedImmutableStrings() {
681 : MOZ_ASSERT_IF(parentRuntime, !sharedImmutableStrings_);
682 : MOZ_ASSERT_IF(!parentRuntime, sharedImmutableStrings_);
683 0 : return parentRuntime ? parentRuntime->sharedImmutableStrings() : *sharedImmutableStrings_;
684 : }
685 :
686 : private:
687 : js::WriteOnceData<bool> beingDestroyed_;
688 : public:
689 : bool isBeingDestroyed() const {
690 : return beingDestroyed_;
691 : }
692 :
693 : private:
694 : bool allowContentJS_;
695 : public:
696 : bool allowContentJS() const {
697 : return allowContentJS_;
698 : }
699 :
700 : friend class js::AutoAssertNoContentJS;
701 :
702 : private:
703 : // Set of all atoms other than those in permanentAtoms and staticStrings.
704 : // Reading or writing this set requires the calling thread to use
705 : // AutoLockForExclusiveAccess.
706 : js::ExclusiveAccessLockOrGCTaskData<js::AtomSet*> atoms_;
707 :
708 : // Set of all atoms added while the main atoms table is being swept.
709 : js::ExclusiveAccessLockData<js::AtomSet*> atomsAddedWhileSweeping_;
710 :
711 : // Set of all live symbols produced by Symbol.for(). All such symbols are
712 0 : // allocated in the atomsZone. Reading or writing the symbol registry
713 : // requires the calling thread to use AutoLockForExclusiveAccess.
714 0 : js::ExclusiveAccessLockOrGCTaskData<js::SymbolRegistry> symbolRegistry_;
715 0 :
716 0 : public:
717 : bool initializeAtoms(JSContext* cx);
718 : void finishAtoms();
719 0 : bool atomsAreFinished() const { return !atoms_; }
720 133262 :
721 133262 : js::AtomSet* atomsForSweeping() {
722 : MOZ_ASSERT(JS::RuntimeHeapIsCollecting());
723 0 : return atoms_;
724 0 : }
725 0 :
726 : js::AtomSet& atoms(js::AutoLockForExclusiveAccess& lock) {
727 : MOZ_ASSERT(atoms_);
728 : return *atoms_;
729 : }
730 : js::AtomSet& unsafeAtoms() {
731 133262 : MOZ_ASSERT(atoms_);
732 : return *atoms_;
733 : }
734 :
735 : bool createAtomsAddedWhileSweepingTable();
736 : void destroyAtomsAddedWhileSweepingTable();
737 : js::AtomSet* atomsAddedWhileSweeping() {
738 97100 : return atomsAddedWhileSweeping_;
739 : }
740 :
741 0 : const JS::Zone* atomsZone(const js::AutoLockForExclusiveAccess& lock) const {
742 : return gc.atomsZone;
743 : }
744 : JS::Zone* atomsZone(const js::AutoLockForExclusiveAccess& lock) {
745 40082838 : return gc.atomsZone;
746 : }
747 : JS::Zone* unsafeAtomsZone() {
748 : return gc.atomsZone;
749 : }
750 :
751 0 : bool isAtomsZone(const JS::Zone* zone) const {
752 : return zone == gc.atomsZone;
753 : }
754 0 :
755 : bool activeGCInAtomsZone();
756 :
757 : js::SymbolRegistry& symbolRegistry(js::AutoLockForExclusiveAccess& lock) {
758 : return symbolRegistry_.ref();
759 : }
760 : js::SymbolRegistry& unsafeSymbolRegistry() {
761 : return symbolRegistry_.ref();
762 : }
763 :
764 : // Permanent atoms are fixed during initialization of the runtime and are
765 : // not modified or collected until the runtime is destroyed. These may be
766 : // shared with another, longer living runtime through |parentRuntime| and
767 : // can be freely accessed with no locking necessary.
768 :
769 : // Permanent atoms pre-allocated for general use.
770 : js::WriteOnceData<js::StaticStrings*> staticStrings;
771 :
772 : // Cached pointers to various permanent property names.
773 : js::WriteOnceData<JSAtomState*> commonNames;
774 :
775 : // All permanent atoms in the runtime, other than those in staticStrings.
776 : // Unlike |atoms_|, access to this does not require
777 : // AutoLockForExclusiveAccess because it is frozen and thus read-only.
778 : js::WriteOnceData<js::FrozenAtomSet*> permanentAtoms;
779 :
780 : bool transformToPermanentAtoms(JSContext* cx);
781 :
782 : // Cached well-known symbols (ES6 rev 24 6.1.5.1). Like permanent atoms,
783 : // these are shared with the parentRuntime, if any.
784 : js::WriteOnceData<js::WellKnownSymbols*> wellKnownSymbols;
785 :
786 : /* Shared Intl data for this runtime. */
787 : js::MainThreadData<js::intl::SharedIntlData> sharedIntlData;
788 :
789 : void traceSharedIntlData(JSTracer* trc);
790 :
791 26366 : // Table of bytecode and other data that may be shared across scripts
792 : // within the runtime. This may be modified by threads using
793 : // AutoLockForExclusiveAccess.
794 : private:
795 : js::ScriptDataLockData<js::ScriptDataTable> scriptDataTable_;
796 : public:
797 : js::ScriptDataTable& scriptDataTable(const js::AutoLockScriptData& lock) {
798 : return scriptDataTable_.ref();
799 : }
800 :
801 : js::WriteOnceData<bool> jitSupportsFloatingPoint;
802 : js::WriteOnceData<bool> jitSupportsUnalignedAccesses;
803 1 : js::WriteOnceData<bool> jitSupportsSimd;
804 :
805 : private:
806 : static mozilla::Atomic<size_t> liveRuntimesCount;
807 :
808 : public:
809 : static bool hasLiveRuntimes() {
810 : return liveRuntimesCount > 0;
811 : }
812 :
813 : explicit JSRuntime(JSRuntime* parentRuntime);
814 : ~JSRuntime();
815 :
816 : // destroyRuntime is used instead of a destructor, to ensure the downcast
817 : // to JSContext remains valid. The final GC triggered here depends on this.
818 : void destroyRuntime();
819 :
820 : bool init(JSContext* cx, uint32_t maxbytes, uint32_t maxNurseryBytes);
821 :
822 : JSRuntime* thisFromCtor() { return this; }
823 :
824 : public:
825 : /*
826 : * Call this after allocating memory held by GC things, to update memory
827 : * pressure counters or report the OOM error if necessary. If oomError and
828 0 : * cx is not null the function also reports OOM error.
829 : *
830 : * The function must be called outside the GC lock and in case of OOM error
831 : * the caller must ensure that no deadlock possible during OOM reporting.
832 : */
833 : void updateMallocCounter(size_t nbytes);
834 :
835 : void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }
836 :
837 : /*
838 : * This should be called after system malloc/calloc/realloc returns nullptr
839 : * to try to recove some memory or to report an error. For realloc, the
840 : * original pointer must be passed as reallocPtr.
841 : *
842 : * The function must be called outside the GC lock.
843 : */
844 : JS_FRIEND_API(void*) onOutOfMemory(js::AllocFunction allocator, size_t nbytes,
845 : void* reallocPtr = nullptr, JSContext* maybecx = nullptr);
846 :
847 : /* onOutOfMemory but can call OnLargeAllocationFailure. */
848 : JS_FRIEND_API(void*) onOutOfMemoryCanGC(js::AllocFunction allocator, size_t nbytes,
849 : void* reallocPtr = nullptr);
850 :
851 : static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
852 :
853 : void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes);
854 :
855 : private:
856 : // Settings for how helper threads can be used.
857 : mozilla::Atomic<bool> offthreadIonCompilationEnabled_;
858 : mozilla::Atomic<bool> parallelParsingEnabled_;
859 :
860 4 : js::MainThreadData<bool> autoWritableJitCodeActive_;
861 :
862 : public:
863 0 :
864 : // Note: these values may be toggled dynamically (in response to about:config
865 : // prefs changing).
866 0 : void setOffthreadIonCompilationEnabled(bool value) {
867 : offthreadIonCompilationEnabled_ = value;
868 : }
869 0 : bool canUseOffthreadIonCompilation() const {
870 : return offthreadIonCompilationEnabled_;
871 : }
872 0 : void setParallelParsingEnabled(bool value) {
873 11268 : parallelParsingEnabled_ = value;
874 11268 : }
875 0 : bool canUseParallelParsing() const {
876 : return parallelParsingEnabled_;
877 : }
878 :
879 : void toggleAutoWritableJitCodeActive(bool b) {
880 : MOZ_ASSERT(autoWritableJitCodeActive_ != b, "AutoWritableJitCode should not be nested.");
881 : autoWritableJitCodeActive_ = b;
882 : }
883 :
884 : /* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
885 : js::MainThreadData<JS::OutOfMemoryCallback> oomCallback;
886 : js::MainThreadData<void*> oomCallbackData;
887 :
888 : /*
889 : * Debugger.Memory functions like takeCensus use this embedding-provided
890 : * function to assess the size of malloc'd blocks of memory.
891 : */
892 : js::MainThreadData<mozilla::MallocSizeOf> debuggerMallocSizeOf;
893 33079 :
894 : /* Last time at which an animation was played for this runtime. */
895 : mozilla::Atomic<int64_t> lastAnimationTime;
896 :
897 : private:
898 : js::MainThreadData<js::PerformanceMonitoring> performanceMonitoring_;
899 : public:
900 : js::PerformanceMonitoring& performanceMonitoring() { return performanceMonitoring_.ref(); }
901 12 :
902 12 : private:
903 12 : /* The stack format for the current runtime. Only valid on non-child
904 0 : * runtimes. */
905 0 : mozilla::Atomic<js::StackFormat, mozilla::ReleaseAcquire> stackFormat_;
906 :
907 0 : public:
908 0 : js::StackFormat stackFormat() const {
909 : const JSRuntime* rt = this;
910 0 : while (rt->parentRuntime) {
911 0 : MOZ_ASSERT(rt->stackFormat_ == js::StackFormat::Default);
912 0 : rt = rt->parentRuntime;
913 0 : }
914 0 : MOZ_ASSERT(rt->stackFormat_ != js::StackFormat::Default);
915 : return rt->stackFormat_;
916 : }
917 : void setStackFormat(js::StackFormat format) {
918 : MOZ_ASSERT(!parentRuntime);
919 : MOZ_ASSERT(format != js::StackFormat::Default);
920 : stackFormat_ = format;
921 : }
922 :
923 96917 : // For inherited heap state accessors.
924 : friend class js::gc::AutoTraceSession;
925 : friend class JS::AutoEnterCycleCollection;
926 :
927 : private:
928 : js::MainThreadData<js::RuntimeCaches> caches_;
929 : public:
930 : js::RuntimeCaches& caches() { return caches_.ref(); }
931 :
932 : // List of all the live wasm::Instances in the runtime. Equal to the union
933 : // of all instances registered in all JS::Realms. Accessed from watchdog
934 : // threads for purposes of wasm::InterruptRunningCode().
935 : js::ExclusiveData<js::wasm::InstanceVector> wasmInstances;
936 :
937 : // The implementation-defined abstract operation HostResolveImportedModule.
938 : js::MainThreadData<JS::ModuleResolveHook> moduleResolveHook;
939 :
940 0 : // A hook that implements the abstract operations
941 : // HostGetImportMetaProperties and HostFinalizeImportMeta.
942 : js::MainThreadData<JS::ModuleMetadataHook> moduleMetadataHook;
943 :
944 : public:
945 : #if defined(JS_BUILD_BINAST)
946 : js::BinaryASTSupport& binast() {
947 : return binast_;
948 : }
949 : private:
950 : js::BinaryASTSupport binast_;
951 : #endif // defined(JS_BUILD_BINAST)
952 :
953 : public:
954 : #if defined(NIGHTLY_BUILD)
955 4 : // Support for informing the embedding of any error thrown.
956 4 : // This mechanism is designed to let the embedding
957 : // log/report/fail in case certain errors are thrown
958 : // (e.g. SyntaxError, ReferenceError or TypeError
959 : // in critical code).
960 : struct ErrorInterceptionSupport {
961 : ErrorInterceptionSupport()
962 : : isExecuting(false)
963 : , interceptor(nullptr)
964 : { }
965 :
966 : // true if the error interceptor is currently executing,
967 : // false otherwise. Used to avoid infinite loops.
968 : bool isExecuting;
969 :
970 : // if non-null, any call to `setPendingException`
971 : // in this runtime will trigger the call to `interceptor`
972 : JSErrorInterceptor* interceptor;
973 : };
974 : ErrorInterceptionSupport errorInterception;
975 : #endif // defined(NIGHTLY_BUILD)
976 : };
977 :
978 : namespace js {
979 :
980 : /*
981 : * RAII class that takes the GC lock while it is live.
982 : *
983 : * Usually functions will pass const references of this class. However
984 : * non-const references can be used to either temporarily release the lock by
985 : * use of AutoUnlockGC or to start background allocation when the lock is
986 16629 : * released.
987 : */
988 11086 : class MOZ_RAII AutoLockGC
989 0 : {
990 : public:
991 : explicit AutoLockGC(JSRuntime* rt
992 0 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
993 5543 : : runtime_(rt)
994 5543 : {
995 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
996 0 : lock();
997 0 : }
998 5563 :
999 0 : ~AutoLockGC() {
1000 : lockGuard_.reset();
1001 0 : }
1002 0 :
1003 5347 : void lock() {
1004 0 : MOZ_ASSERT(lockGuard_.isNothing());
1005 : lockGuard_.emplace(runtime_->gc.lock);
1006 : }
1007 0 :
1008 : void unlock() {
1009 : MOZ_ASSERT(lockGuard_.isSome());
1010 : lockGuard_.reset();
1011 : }
1012 :
1013 : js::LockGuard<js::Mutex>& guard() {
1014 : return lockGuard_.ref();
1015 : }
1016 :
1017 : protected:
1018 : JSRuntime* runtime() const { return runtime_; }
1019 :
1020 : private:
1021 : JSRuntime* runtime_;
1022 : mozilla::Maybe<js::LockGuard<js::Mutex>> lockGuard_;
1023 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1024 :
1025 : AutoLockGC(const AutoLockGC&) = delete;
1026 : AutoLockGC& operator=(const AutoLockGC&) = delete;
1027 : };
1028 :
1029 : /*
1030 5327 : * Same as AutoLockGC except it can optionally start a background chunk
1031 10654 : * allocation task when the lock is released.
1032 : */
1033 : class MOZ_RAII AutoLockGCBgAlloc : public AutoLockGC
1034 0 : {
1035 5327 : public:
1036 : explicit AutoLockGCBgAlloc(JSRuntime* rt)
1037 : : AutoLockGC(rt)
1038 : , startBgAlloc(false)
1039 : {}
1040 :
1041 : ~AutoLockGCBgAlloc() {
1042 5327 : unlock();
1043 20 :
1044 5327 : /*
1045 : * We have to do this after releasing the lock because it may acquire
1046 : * the helper lock which could cause lock inversion if we still held
1047 : * the GC lock.
1048 : */
1049 : if (startBgAlloc)
1050 : runtime()->gc.startBackgroundAllocTaskIfIdle();
1051 : }
1052 :
1053 20 : /*
1054 : * This can be used to start a background allocation task (if one isn't
1055 : * already running) that allocates chunks and makes them available in the
1056 : * free chunks list. This happens after the lock is released in order to
1057 : * avoid lock inversion.
1058 : */
1059 : void tryToStartBackgroundAllocation() {
1060 : startBgAlloc = true;
1061 : }
1062 :
1063 : private:
1064 : // true if we should start a background chunk allocation task after the
1065 : // lock is released.
1066 : bool startBgAlloc;
1067 40 : };
1068 :
1069 40 : class MOZ_RAII AutoUnlockGC
1070 0 : {
1071 : public:
1072 : explicit AutoUnlockGC(AutoLockGC& lock
1073 0 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1074 20 : : lock(lock)
1075 : {
1076 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1077 : lock.unlock();
1078 : }
1079 :
1080 : ~AutoUnlockGC() {
1081 : lock.lock();
1082 : }
1083 :
1084 : private:
1085 : AutoLockGC& lock;
1086 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1087 :
1088 : AutoUnlockGC(const AutoUnlockGC&) = delete;
1089 : AutoUnlockGC& operator=(const AutoUnlockGC&) = delete;
1090 : };
1091 :
1092 : /************************************************************************/
1093 :
1094 : static MOZ_ALWAYS_INLINE void
1095 : MakeRangeGCSafe(Value* vec, size_t len)
1096 : {
1097 : // Don't PodZero here because JS::Value is non-trivial.
1098 : for (size_t i = 0; i < len; i++)
1099 : vec[i].setDouble(+0.0);
1100 : }
1101 :
1102 : static MOZ_ALWAYS_INLINE void
1103 : MakeRangeGCSafe(Value* beg, Value* end)
1104 : {
1105 : MakeRangeGCSafe(beg, end - beg);
1106 : }
1107 :
1108 : static MOZ_ALWAYS_INLINE void
1109 : MakeRangeGCSafe(jsid* beg, jsid* end)
1110 : {
1111 : std::fill(beg, end, INT_TO_JSID(0));
1112 : }
1113 :
1114 : static MOZ_ALWAYS_INLINE void
1115 : MakeRangeGCSafe(jsid* vec, size_t len)
1116 : {
1117 : MakeRangeGCSafe(vec, vec + len);
1118 : }
1119 :
1120 : static MOZ_ALWAYS_INLINE void
1121 : MakeRangeGCSafe(Shape** beg, Shape** end)
1122 : {
1123 : std::fill(beg, end, nullptr);
1124 : }
1125 :
1126 : static MOZ_ALWAYS_INLINE void
1127 : MakeRangeGCSafe(Shape** vec, size_t len)
1128 38016 : {
1129 21144 : MakeRangeGCSafe(vec, vec + len);
1130 : }
1131 :
1132 : static MOZ_ALWAYS_INLINE void
1133 : SetValueRangeToUndefined(Value* beg, Value* end)
1134 : {
1135 33321 : for (Value* v = beg; v != end; ++v)
1136 : v->setUndefined();
1137 : }
1138 :
1139 : static MOZ_ALWAYS_INLINE void
1140 : SetValueRangeToUndefined(Value* vec, size_t len)
1141 : {
1142 : SetValueRangeToUndefined(vec, vec + len);
1143 : }
1144 :
1145 : static MOZ_ALWAYS_INLINE void
1146 : SetValueRangeToNull(Value* beg, Value* end)
1147 : {
1148 : for (Value* v = beg; v != end; ++v)
1149 : v->setNull();
1150 : }
1151 :
1152 : static MOZ_ALWAYS_INLINE void
1153 : SetValueRangeToNull(Value* vec, size_t len)
1154 : {
1155 : SetValueRangeToNull(vec, vec + len);
1156 : }
1157 :
1158 : extern const JSSecurityCallbacks NullSecurityCallbacks;
1159 :
1160 : // This callback is set by JS::SetProcessLargeAllocationFailureCallback
1161 : // and may be null. See comment in jsapi.h.
1162 : extern mozilla::Atomic<JS::LargeAllocationFailureCallback> OnLargeAllocationFailure;
1163 :
1164 : } /* namespace js */
1165 :
1166 : #endif /* vm_Runtime_h */
|