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/LinkedList.h"
13 #include "mozilla/MemoryReporting.h"
14 #include "mozilla/PodOperations.h"
15 #include "mozilla/Scoped.h"
16 #include "mozilla/ThreadLocal.h"
17 #include "mozilla/UniquePtr.h"
18 #include "mozilla/Vector.h"
19
20 #include <setjmp.h>
21
22 #include "jsatom.h"
23 #include "jsclist.h"
24 #include "jsscript.h"
25
26 #ifdef XP_DARWIN
27 # include "asmjs/AsmJSSignalHandlers.h"
28 #endif
29 #include "builtin/AtomicsObject.h"
30 #include "ds/FixedSizeHash.h"
31 #include "frontend/ParseMaps.h"
32 #include "gc/GCRuntime.h"
33 #include "gc/Tracer.h"
34 #include "irregexp/RegExpStack.h"
35 #include "js/Debug.h"
36 #include "js/HashTable.h"
37 #ifdef DEBUG
38 # include "js/Proxy.h" // For AutoEnterPolicy
39 #endif
40 #include "js/TraceableVector.h"
41 #include "js/Vector.h"
42 #include "vm/CodeCoverage.h"
43 #include "vm/CommonPropertyNames.h"
44 #include "vm/DateTime.h"
45 #include "vm/MallocProvider.h"
46 #include "vm/SPSProfiler.h"
47 #include "vm/Stack.h"
48 #include "vm/Stopwatch.h"
49 #include "vm/Symbol.h"
50
51 #ifdef _MSC_VER
52 #pragma warning(push)
53 #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
54 #endif
55
56 namespace js {
57
58 class PerThreadData;
59 class ExclusiveContext;
60 class AutoKeepAtoms;
61 #ifdef JS_TRACE_LOGGING
62 class TraceLoggerThread;
63 #endif
64
65 /* Thread Local Storage slot for storing the runtime for a thread. */
66 extern mozilla::ThreadLocal<PerThreadData*> TlsPerThreadData;
67
68 } // namespace js
69
70 struct DtoaState;
71
72 #ifdef JS_SIMULATOR_ARM64
73 namespace vixl {
74 class Simulator;
75 }
76 #endif
77
78 namespace js {
79
80 extern MOZ_COLD void
81 ReportOutOfMemory(ExclusiveContext* cx);
82
83 extern MOZ_COLD void
84 ReportAllocationOverflow(ExclusiveContext* maybecx);
85
86 extern MOZ_COLD void
87 ReportOverRecursed(ExclusiveContext* cx);
88
89 class Activation;
90 class ActivationIterator;
91 class AsmJSActivation;
92 class AsmJSModule;
93 class MathCache;
94
95 namespace jit {
96 class JitRuntime;
97 class JitActivation;
98 struct PcScriptCache;
99 struct AutoFlushICache;
100 class CompileRuntime;
101
102 #ifdef JS_SIMULATOR_ARM64
103 typedef vixl::Simulator Simulator;
104 #elif defined(JS_SIMULATOR)
105 class Simulator;
106 #endif
107 } // namespace jit
108
109 /*
110 * GetSrcNote cache to avoid O(n^2) growth in finding a source note for a
111 * given pc in a script. We use the script->code pointer to tag the cache,
112 * instead of the script address itself, so that source notes are always found
113 * by offset from the bytecode with which they were generated.
114 */
115 struct GSNCache {
116 typedef HashMap<jsbytecode*,
117 jssrcnote*,
118 PointerHasher<jsbytecode*, 0>,
119 SystemAllocPolicy> Map;
120
121 jsbytecode* code;
122 Map map;
123
GSNCacheGSNCache124 GSNCache() : code(nullptr) { }
125
126 void purge();
127 };
128
129 /*
130 * ScopeCoordinateName cache to avoid O(n^2) growth in finding the name
131 * associated with a given aliasedvar operation.
132 */
133 struct ScopeCoordinateNameCache {
134 typedef HashMap<uint32_t,
135 jsid,
136 DefaultHasher<uint32_t>,
137 SystemAllocPolicy> Map;
138
139 Shape* shape;
140 Map map;
141
ScopeCoordinateNameCacheScopeCoordinateNameCache142 ScopeCoordinateNameCache() : shape(nullptr) {}
143 void purge();
144 };
145
146 using ScriptAndCountsVector = TraceableVector<ScriptAndCounts, 0, SystemAllocPolicy>;
147
148 struct EvalCacheEntry
149 {
150 JSLinearString* str;
151 JSScript* script;
152 JSScript* callerScript;
153 jsbytecode* pc;
154 };
155
156 struct EvalCacheLookup
157 {
EvalCacheLookupEvalCacheLookup158 explicit EvalCacheLookup(JSContext* cx) : str(cx), callerScript(cx) {}
159 RootedLinearString str;
160 RootedScript callerScript;
161 JSVersion version;
162 jsbytecode* pc;
163 };
164
165 struct EvalCacheHashPolicy
166 {
167 typedef EvalCacheLookup Lookup;
168
169 static HashNumber hash(const Lookup& l);
170 static bool match(const EvalCacheEntry& entry, const EvalCacheLookup& l);
171 };
172
173 typedef HashSet<EvalCacheEntry, EvalCacheHashPolicy, SystemAllocPolicy> EvalCache;
174
175 struct LazyScriptHashPolicy
176 {
177 struct Lookup {
178 JSContext* cx;
179 LazyScript* lazy;
180
LookupLazyScriptHashPolicy::Lookup181 Lookup(JSContext* cx, LazyScript* lazy)
182 : cx(cx), lazy(lazy)
183 {}
184 };
185
186 static const size_t NumHashes = 3;
187
188 static void hash(const Lookup& lookup, HashNumber hashes[NumHashes]);
189 static bool match(JSScript* script, const Lookup& lookup);
190
191 // Alternate methods for use when removing scripts from the hash without an
192 // explicit LazyScript lookup.
193 static void hash(JSScript* script, HashNumber hashes[NumHashes]);
matchLazyScriptHashPolicy194 static bool match(JSScript* script, JSScript* lookup) { return script == lookup; }
195
clearLazyScriptHashPolicy196 static void clear(JSScript** pscript) { *pscript = nullptr; }
isClearedLazyScriptHashPolicy197 static bool isCleared(JSScript* script) { return !script; }
198 };
199
200 typedef FixedSizeHashSet<JSScript*, LazyScriptHashPolicy, 769> LazyScriptCache;
201
202 class PropertyIteratorObject;
203
204 class NativeIterCache
205 {
206 static const size_t SIZE = size_t(1) << 8;
207
208 /* Cached native iterators. */
209 PropertyIteratorObject* data[SIZE];
210
getIndex(uint32_t key)211 static size_t getIndex(uint32_t key) {
212 return size_t(key) % SIZE;
213 }
214
215 public:
216 /* Native iterator most recently started. */
217 PropertyIteratorObject* last;
218
NativeIterCache()219 NativeIterCache()
220 : last(nullptr)
221 {
222 mozilla::PodArrayZero(data);
223 }
224
purge()225 void purge() {
226 last = nullptr;
227 mozilla::PodArrayZero(data);
228 }
229
get(uint32_t key)230 PropertyIteratorObject* get(uint32_t key) const {
231 return data[getIndex(key)];
232 }
233
set(uint32_t key,PropertyIteratorObject * iterobj)234 void set(uint32_t key, PropertyIteratorObject* iterobj) {
235 data[getIndex(key)] = iterobj;
236 }
237 };
238
239 /*
240 * Cache for speeding up repetitive creation of objects in the VM.
241 * When an object is created which matches the criteria in the 'key' section
242 * below, an entry is filled with the resulting object.
243 */
244 class NewObjectCache
245 {
246 /* Statically asserted to be equal to sizeof(JSObject_Slots16) */
247 static const unsigned MAX_OBJ_SIZE = 4 * sizeof(void*) + 16 * sizeof(Value);
248
staticAsserts()249 static void staticAsserts() {
250 JS_STATIC_ASSERT(NewObjectCache::MAX_OBJ_SIZE == sizeof(JSObject_Slots16));
251 JS_STATIC_ASSERT(gc::AllocKind::OBJECT_LAST == gc::AllocKind::OBJECT16_BACKGROUND);
252 }
253
254 struct Entry
255 {
256 /* Class of the constructed object. */
257 const Class* clasp;
258
259 /*
260 * Key with one of three possible values:
261 *
262 * - Global for the object. The object must have a standard class for
263 * which the global's prototype can be determined, and the object's
264 * parent will be the global.
265 *
266 * - Prototype for the object (cannot be global). The object's parent
267 * will be the prototype's parent.
268 *
269 * - Type for the object. The object's parent will be the type's
270 * prototype's parent.
271 */
272 gc::Cell* key;
273
274 /* Allocation kind for the constructed object. */
275 gc::AllocKind kind;
276
277 /* Number of bytes to copy from the template object. */
278 uint32_t nbytes;
279
280 /*
281 * Template object to copy from, with the initial values of fields,
282 * fixed slots (undefined) and private data (nullptr).
283 */
284 char templateObject[MAX_OBJ_SIZE];
285 };
286
287 Entry entries[41]; // TODO: reconsider size
288
289 public:
290
291 typedef int EntryIndex;
292
NewObjectCache()293 NewObjectCache() { mozilla::PodZero(this); }
purge()294 void purge() { mozilla::PodZero(this); }
295
296 /* Remove any cached items keyed on moved objects. */
297 void clearNurseryObjects(JSRuntime* rt);
298
299 /*
300 * Get the entry index for the given lookup, return whether there was a hit
301 * on an existing entry.
302 */
303 inline bool lookupProto(const Class* clasp, JSObject* proto, gc::AllocKind kind, EntryIndex* pentry);
304 inline bool lookupGlobal(const Class* clasp, js::GlobalObject* global, gc::AllocKind kind,
305 EntryIndex* pentry);
306
lookupGroup(js::ObjectGroup * group,gc::AllocKind kind,EntryIndex * pentry)307 bool lookupGroup(js::ObjectGroup* group, gc::AllocKind kind, EntryIndex* pentry) {
308 return lookup(group->clasp(), group, kind, pentry);
309 }
310
311 /*
312 * Return a new object from a cache hit produced by a lookup method, or
313 * nullptr if returning the object could possibly trigger GC (does not
314 * indicate failure).
315 */
316 inline NativeObject* newObjectFromHit(JSContext* cx, EntryIndex entry, js::gc::InitialHeap heap);
317
318 /* Fill an entry after a cache miss. */
319 void fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto proto,
320 gc::AllocKind kind, NativeObject* obj);
321
322 inline void fillGlobal(EntryIndex entry, const Class* clasp, js::GlobalObject* global,
323 gc::AllocKind kind, NativeObject* obj);
324
fillGroup(EntryIndex entry,js::ObjectGroup * group,gc::AllocKind kind,NativeObject * obj)325 void fillGroup(EntryIndex entry, js::ObjectGroup* group, gc::AllocKind kind,
326 NativeObject* obj)
327 {
328 MOZ_ASSERT(obj->group() == group);
329 return fill(entry, group->clasp(), group, kind, obj);
330 }
331
332 /* Invalidate any entries which might produce an object with shape/proto. */
333 void invalidateEntriesForShape(JSContext* cx, HandleShape shape, HandleObject proto);
334
335 private:
makeIndex(const Class * clasp,gc::Cell * key,gc::AllocKind kind)336 EntryIndex makeIndex(const Class* clasp, gc::Cell* key, gc::AllocKind kind) {
337 uintptr_t hash = (uintptr_t(clasp) ^ uintptr_t(key)) + size_t(kind);
338 return hash % mozilla::ArrayLength(entries);
339 }
340
lookup(const Class * clasp,gc::Cell * key,gc::AllocKind kind,EntryIndex * pentry)341 bool lookup(const Class* clasp, gc::Cell* key, gc::AllocKind kind, EntryIndex* pentry) {
342 *pentry = makeIndex(clasp, key, kind);
343 Entry* entry = &entries[*pentry];
344
345 /* N.B. Lookups with the same clasp/key but different kinds map to different entries. */
346 return entry->clasp == clasp && entry->key == key;
347 }
348
fill(EntryIndex entry_,const Class * clasp,gc::Cell * key,gc::AllocKind kind,NativeObject * obj)349 void fill(EntryIndex entry_, const Class* clasp, gc::Cell* key, gc::AllocKind kind,
350 NativeObject* obj) {
351 MOZ_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
352 MOZ_ASSERT(entry_ == makeIndex(clasp, key, kind));
353 Entry* entry = &entries[entry_];
354
355 entry->clasp = clasp;
356 entry->key = key;
357 entry->kind = kind;
358
359 entry->nbytes = gc::Arena::thingSize(kind);
360 js_memcpy(&entry->templateObject, obj, entry->nbytes);
361 }
362
copyCachedToObject(NativeObject * dst,NativeObject * src,gc::AllocKind kind)363 static void copyCachedToObject(NativeObject* dst, NativeObject* src, gc::AllocKind kind) {
364 js_memcpy(dst, src, gc::Arena::thingSize(kind));
365 Shape::writeBarrierPost(&dst->shape_, nullptr, dst->shape_);
366 ObjectGroup::writeBarrierPost(&dst->group_, nullptr, dst->group_);
367 }
368 };
369
370 /*
371 * A FreeOp can do one thing: free memory. For convenience, it has delete_
372 * convenience methods that also call destructors.
373 *
374 * FreeOp is passed to finalizers and other sweep-phase hooks so that we do not
375 * need to pass a JSContext to those hooks.
376 */
377 class FreeOp : public JSFreeOp
378 {
379 Vector<void*, 0, SystemAllocPolicy> freeLaterList;
380 ThreadType threadType;
381
382 public:
get(JSFreeOp * fop)383 static FreeOp* get(JSFreeOp* fop) {
384 return static_cast<FreeOp*>(fop);
385 }
386
387 explicit FreeOp(JSRuntime* rt, ThreadType thread = MainThread)
JSFreeOp(rt)388 : JSFreeOp(rt), threadType(thread)
389 {}
390
~FreeOp()391 ~FreeOp() {
392 for (size_t i = 0; i < freeLaterList.length(); i++)
393 free_(freeLaterList[i]);
394 }
395
onBackgroundThread()396 bool onBackgroundThread() {
397 return threadType == BackgroundThread;
398 }
399
400 inline void free_(void* p);
401 inline void freeLater(void* p);
402
403 template <class T>
delete_(T * p)404 inline void delete_(T* p) {
405 if (p) {
406 p->~T();
407 free_(p);
408 }
409 }
410 };
411
412 } /* namespace js */
413
414 namespace JS {
415 struct RuntimeSizes;
416 } // namespace JS
417
418 /* Various built-in or commonly-used names pinned on first context. */
419 struct JSAtomState
420 {
421 #define PROPERTYNAME_FIELD(idpart, id, text) js::ImmutablePropertyNamePtr id;
422 FOR_EACH_COMMON_PROPERTYNAME(PROPERTYNAME_FIELD)
423 #undef PROPERTYNAME_FIELD
424 #define PROPERTYNAME_FIELD(name, code, init, clasp) js::ImmutablePropertyNamePtr name;
JS_FOR_EACH_PROTOTYPEJSAtomState425 JS_FOR_EACH_PROTOTYPE(PROPERTYNAME_FIELD)
426 #undef PROPERTYNAME_FIELD
427
428 js::ImmutablePropertyNamePtr* wellKnownSymbolDescriptions() {
429 return &Symbol_iterator;
430 }
431 };
432
433 namespace js {
434
435 /*
436 * Storage for well-known symbols. It's a separate struct from the Runtime so
437 * that it can be shared across multiple runtimes. As in JSAtomState, each
438 * field is a smart pointer that's immutable once initialized.
439 * `rt->wellKnownSymbols->iterator` is convertible to Handle<Symbol*>.
440 *
441 * Well-known symbols are never GC'd. The description() of each well-known
442 * symbol is a permanent atom.
443 */
444 struct WellKnownSymbols
445 {
446 js::ImmutableSymbolPtr iterator;
447 js::ImmutableSymbolPtr match;
448 js::ImmutableSymbolPtr species;
449 js::ImmutableSymbolPtr toPrimitive;
450
getWellKnownSymbols451 const ImmutableSymbolPtr& get(size_t u) const {
452 MOZ_ASSERT(u < JS::WellKnownSymbolLimit);
453 const ImmutableSymbolPtr* symbols = reinterpret_cast<const ImmutableSymbolPtr*>(this);
454 return symbols[u];
455 }
456
getWellKnownSymbols457 const ImmutableSymbolPtr& get(JS::SymbolCode code) const {
458 return get(size_t(code));
459 }
460 };
461
462 #define NAME_OFFSET(name) offsetof(JSAtomState, name)
463
464 inline HandlePropertyName
AtomStateOffsetToName(const JSAtomState & atomState,size_t offset)465 AtomStateOffsetToName(const JSAtomState& atomState, size_t offset)
466 {
467 return *reinterpret_cast<js::ImmutablePropertyNamePtr*>((char*)&atomState + offset);
468 }
469
470 // There are several coarse locks in the enum below. These may be either
471 // per-runtime or per-process. When acquiring more than one of these locks,
472 // the acquisition must be done in the order below to avoid deadlocks.
473 enum RuntimeLock {
474 ExclusiveAccessLock,
475 HelperThreadStateLock,
476 GCLock
477 };
478
479 #ifdef DEBUG
480 void AssertCurrentThreadCanLock(RuntimeLock which);
481 #else
AssertCurrentThreadCanLock(RuntimeLock which)482 inline void AssertCurrentThreadCanLock(RuntimeLock which) {}
483 #endif
484
485 inline bool
CanUseExtraThreads()486 CanUseExtraThreads()
487 {
488 extern bool gCanUseExtraThreads;
489 return gCanUseExtraThreads;
490 }
491
492 void DisableExtraThreads();
493
494 /*
495 * Encapsulates portions of the runtime/context that are tied to a
496 * single active thread. Instances of this structure can occur for
497 * the main thread as |JSRuntime::mainThread|, for select operations
498 * performed off thread, such as parsing.
499 */
500 class PerThreadData : public PerThreadDataFriendFields
501 {
502 #ifdef DEBUG
503 // Grant access to runtime_.
504 friend void js::AssertCurrentThreadCanLock(RuntimeLock which);
505 #endif
506
507 /*
508 * Backpointer to the full shared JSRuntime* with which this
509 * thread is associated. This is private because accessing the
510 * fields of this runtime can provoke race conditions, so the
511 * intention is that access will be mediated through safe
512 * functions like |runtimeFromMainThread| and |associatedWith()| below.
513 */
514 JSRuntime* runtime_;
515
516 public:
517 #ifdef JS_TRACE_LOGGING
518 TraceLoggerThread* traceLogger;
519 #endif
520
521 /* Pointer to the current AutoFlushICache. */
522 js::jit::AutoFlushICache* autoFlushICache_;
523
524 public:
525 /* State used by jsdtoa.cpp. */
526 DtoaState* dtoaState;
527
528 /*
529 * When this flag is non-zero, any attempt to GC will be skipped. It is used
530 * to suppress GC when reporting an OOM (see ReportOutOfMemory) and in
531 * debugging facilities that cannot tolerate a GC and would rather OOM
532 * immediately, such as utilities exposed to GDB. Setting this flag is
533 * extremely dangerous and should only be used when in an OOM situation or
534 * in non-exposed debugging facilities.
535 */
536 int32_t suppressGC;
537
538 #ifdef DEBUG
539 // Whether this thread is actively Ion compiling.
540 bool ionCompiling;
541
542 // Whether this thread is actively Ion compiling in a context where a minor
543 // GC could happen simultaneously. If this is true, this thread cannot use
544 // any pointers into the nursery.
545 bool ionCompilingSafeForMinorGC;
546
547 // Whether this thread is currently sweeping GC things.
548 bool gcSweeping;
549 #endif
550
551 // Number of active bytecode compilation on this thread.
552 unsigned activeCompilations;
553
554 explicit PerThreadData(JSRuntime* runtime);
555 ~PerThreadData();
556
557 bool init();
558
associatedWith(const JSRuntime * rt)559 bool associatedWith(const JSRuntime* rt) { return runtime_ == rt; }
560 inline JSRuntime* runtimeFromMainThread();
561 inline JSRuntime* runtimeIfOnOwnerThread();
562
563 inline bool exclusiveThreadsPresent();
564 inline void addActiveCompilation();
565 inline void removeActiveCompilation();
566
567 // For threads which may be associated with different runtimes, depending
568 // on the work they are doing.
569 class MOZ_STACK_CLASS AutoEnterRuntime
570 {
571 PerThreadData* pt;
572
573 public:
AutoEnterRuntime(PerThreadData * pt,JSRuntime * rt)574 AutoEnterRuntime(PerThreadData* pt, JSRuntime* rt)
575 : pt(pt)
576 {
577 MOZ_ASSERT(!pt->runtime_);
578 pt->runtime_ = rt;
579 }
580
~AutoEnterRuntime()581 ~AutoEnterRuntime() {
582 pt->runtime_ = nullptr;
583 }
584 };
585
586 js::jit::AutoFlushICache* autoFlushICache() const;
587 void setAutoFlushICache(js::jit::AutoFlushICache* afc);
588
589 #ifdef JS_SIMULATOR
590 js::jit::Simulator* simulator() const;
591 #endif
592 };
593
594 class AutoLockForExclusiveAccess;
595 } // namespace js
596
597 struct JSRuntime : public JS::shadow::Runtime,
598 public js::MallocProvider<JSRuntime>
599 {
600 /*
601 * Per-thread data for the main thread that is associated with
602 * this JSRuntime, as opposed to any worker threads used in
603 * parallel sections. See definition of |PerThreadData| struct
604 * above for more details.
605 *
606 * NB: This field is statically asserted to be at offset
607 * sizeof(js::shadow::Runtime). See
608 * PerThreadDataFriendFields::getMainThread.
609 */
610 js::PerThreadData mainThread;
611
612 /*
613 * If Baseline or Ion code is on the stack, and has called into C++, this
614 * will be aligned to an exit frame.
615 */
616 uint8_t* jitTop;
617
618 /*
619 * The current JSContext when entering JIT code. This field may only be used
620 * from JIT code and C++ directly called by JIT code (otherwise it may refer
621 * to the wrong JSContext).
622 */
623 JSContext* jitJSContext;
624
625 /*
626 * Points to the most recent JitActivation pushed on the thread.
627 * See JitActivation constructor in vm/Stack.cpp
628 */
629 js::jit::JitActivation* jitActivation;
630
631 /* See comment for JSRuntime::interrupt_. */
632 private:
633 mozilla::Atomic<uintptr_t, mozilla::Relaxed> jitStackLimit_;
634 void resetJitStackLimit();
635
636 // Like jitStackLimit_, but not reset to trigger interrupts.
637 uintptr_t jitStackLimitNoInterrupt_;
638
639 public:
640 void initJitStackLimit();
641
jitStackLimitJSRuntime642 uintptr_t jitStackLimit() const { return jitStackLimit_; }
643
644 // For read-only JIT use:
addressOfJitStackLimitJSRuntime645 void* addressOfJitStackLimit() { return &jitStackLimit_; }
offsetOfJitStackLimitJSRuntime646 static size_t offsetOfJitStackLimit() { return offsetof(JSRuntime, jitStackLimit_); }
647
addressOfJitStackLimitNoInterruptJSRuntime648 void* addressOfJitStackLimitNoInterrupt() { return &jitStackLimitNoInterrupt_; }
649
650 // Information about the heap allocated backtrack stack used by RegExp JIT code.
651 js::irregexp::RegExpStack regexpStack;
652
653 private:
654 friend class js::Activation;
655 friend class js::ActivationIterator;
656 friend class js::jit::JitActivation;
657 friend class js::AsmJSActivation;
658 friend class js::jit::CompileRuntime;
659 #ifdef DEBUG
660 friend void js::AssertCurrentThreadCanLock(js::RuntimeLock which);
661 #endif
662
663 /*
664 * Points to the most recent activation running on the thread.
665 * See Activation comment in vm/Stack.h.
666 */
667 js::Activation* activation_;
668
669 /*
670 * Points to the most recent profiling activation running on the
671 * thread.
672 */
673 js::Activation * volatile profilingActivation_;
674
675 /*
676 * The profiler sampler generation after the latest sample.
677 *
678 * The lapCount indicates the number of largest number of 'laps'
679 * (wrapping from high to low) that occurred when writing entries
680 * into the sample buffer. All JitcodeGlobalMap entries referenced
681 * from a given sample are assigned the generation of the sample buffer
682 * at the START of the run. If multiple laps occur, then some entries
683 * (towards the end) will be written out with the "wrong" generation.
684 * The lapCount indicates the required fudge factor to use to compare
685 * entry generations with the sample buffer generation.
686 */
687 mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> profilerSampleBufferGen_;
688 mozilla::Atomic<uint32_t, mozilla::ReleaseAcquire> profilerSampleBufferLapCount_;
689
690 /* See AsmJSActivation comment. */
691 js::AsmJSActivation * volatile asmJSActivationStack_;
692
693 public:
694 /*
695 * Youngest frame of a saved stack that will be picked up as an async stack
696 * by any new Activation, and is nullptr when no async stack should be used.
697 *
698 * The JS::AutoSetAsyncStackForNewCalls class can be used to set this.
699 *
700 * New activations will reset this to nullptr on construction after getting
701 * the current value, and will restore the previous value on destruction.
702 */
703 JS::PersistentRooted<js::SavedFrame*> asyncStackForNewActivations;
704
705 /*
706 * Value of asyncCause to be attached to asyncStackForNewActivations.
707 */
708 JS::PersistentRooted<JSString*> asyncCauseForNewActivations;
709
710 /*
711 * True if the async call was explicitly requested, e.g. via
712 * callFunctionWithAsyncStack.
713 */
714 bool asyncCallIsExplicit;
715
716 /* If non-null, report JavaScript entry points to this monitor. */
717 JS::dbg::AutoEntryMonitor* entryMonitor;
718
addressOfActivationJSRuntime719 js::Activation* const* addressOfActivation() const {
720 return &activation_;
721 }
offsetOfActivationJSRuntime722 static unsigned offsetOfActivation() {
723 return offsetof(JSRuntime, activation_);
724 }
725
profilingActivationJSRuntime726 js::Activation* profilingActivation() const {
727 return profilingActivation_;
728 }
addressOfProfilingActivationJSRuntime729 void* addressOfProfilingActivation() {
730 return (void*) &profilingActivation_;
731 }
offsetOfProfilingActivationJSRuntime732 static unsigned offsetOfProfilingActivation() {
733 return offsetof(JSRuntime, profilingActivation_);
734 }
735
profilerSampleBufferGenJSRuntime736 uint32_t profilerSampleBufferGen() {
737 return profilerSampleBufferGen_;
738 }
resetProfilerSampleBufferGenJSRuntime739 void resetProfilerSampleBufferGen() {
740 profilerSampleBufferGen_ = 0;
741 }
setProfilerSampleBufferGenJSRuntime742 void setProfilerSampleBufferGen(uint32_t gen) {
743 // May be called from sampler thread or signal handler; use
744 // compareExchange to make sure we have monotonic increase.
745 for (;;) {
746 uint32_t curGen = profilerSampleBufferGen_;
747 if (curGen >= gen)
748 break;
749
750 if (profilerSampleBufferGen_.compareExchange(curGen, gen))
751 break;
752 }
753 }
754
profilerSampleBufferLapCountJSRuntime755 uint32_t profilerSampleBufferLapCount() {
756 MOZ_ASSERT(profilerSampleBufferLapCount_ > 0);
757 return profilerSampleBufferLapCount_;
758 }
resetProfilerSampleBufferLapCountJSRuntime759 void resetProfilerSampleBufferLapCount() {
760 profilerSampleBufferLapCount_ = 1;
761 }
updateProfilerSampleBufferLapCountJSRuntime762 void updateProfilerSampleBufferLapCount(uint32_t lapCount) {
763 MOZ_ASSERT(profilerSampleBufferLapCount_ > 0);
764
765 // May be called from sampler thread or signal handler; use
766 // compareExchange to make sure we have monotonic increase.
767 for (;;) {
768 uint32_t curLapCount = profilerSampleBufferLapCount_;
769 if (curLapCount >= lapCount)
770 break;
771
772 if (profilerSampleBufferLapCount_.compareExchange(curLapCount, lapCount))
773 break;
774 }
775 }
776
asmJSActivationStackJSRuntime777 js::AsmJSActivation* asmJSActivationStack() const {
778 return asmJSActivationStack_;
779 }
innermostAsmJSActivationJSRuntime780 static js::AsmJSActivation* innermostAsmJSActivation() {
781 js::PerThreadData* ptd = js::TlsPerThreadData.get();
782 return ptd ? ptd->runtimeFromMainThread()->asmJSActivationStack_ : nullptr;
783 }
784
activationJSRuntime785 js::Activation* activation() const {
786 return activation_;
787 }
788
789 /*
790 * If non-null, another runtime guaranteed to outlive this one and whose
791 * permanent data may be used by this one where possible.
792 */
793 JSRuntime* parentRuntime;
794
795 private:
796 mozilla::Atomic<uint32_t, mozilla::Relaxed> interrupt_;
797
798 /* Call this to accumulate telemetry data. */
799 JSAccumulateTelemetryDataCallback telemetryCallback;
800 public:
801 // Accumulates data for Firefox telemetry. |id| is the ID of a JS_TELEMETRY_*
802 // histogram. |key| provides an additional key to identify the histogram.
803 // |sample| is the data to add to the histogram.
804 void addTelemetry(int id, uint32_t sample, const char* key = nullptr);
805
806 void setTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback);
807
808 enum InterruptMode {
809 RequestInterruptUrgent,
810 RequestInterruptCanWait
811 };
812
813 // Any thread can call requestInterrupt() to request that the main JS thread
814 // stop running and call the interrupt callback (allowing the interrupt
815 // callback to halt execution). To stop the main JS thread, requestInterrupt
816 // sets two fields: interrupt_ (set to true) and jitStackLimit_ (set to
817 // UINTPTR_MAX). The JS engine must continually poll one of these fields
818 // and call handleInterrupt if either field has the interrupt value. (The
819 // point of setting jitStackLimit_ to UINTPTR_MAX is that JIT code already
820 // needs to guard on jitStackLimit_ in every function prologue to avoid
821 // stack overflow, so we avoid a second branch on interrupt_ by setting
822 // jitStackLimit_ to a value that is guaranteed to fail the guard.)
823 //
824 // Note that the writes to interrupt_ and jitStackLimit_ use a Relaxed
825 // Atomic so, while the writes are guaranteed to eventually be visible to
826 // the main thread, it can happen in any order. handleInterrupt calls the
827 // interrupt callback if either is set, so it really doesn't matter as long
828 // as the JS engine is continually polling at least one field. In corner
829 // cases, this relaxed ordering could lead to an interrupt handler being
830 // called twice in succession after a single requestInterrupt call, but
831 // that's fine.
832 void requestInterrupt(InterruptMode mode);
833 bool handleInterrupt(JSContext* cx);
834
hasPendingInterruptJSRuntime835 MOZ_ALWAYS_INLINE bool hasPendingInterrupt() const {
836 return interrupt_;
837 }
838
839 // For read-only JIT use:
addressOfInterruptUint32JSRuntime840 void* addressOfInterruptUint32() {
841 static_assert(sizeof(interrupt_) == sizeof(uint32_t), "Assumed by JIT callers");
842 return &interrupt_;
843 }
844
845 /* Set when handling a signal for a thread associated with this runtime. */
846 bool handlingSignal;
847
848 JSInterruptCallback interruptCallback;
849
850 #ifdef DEBUG
851 void assertCanLock(js::RuntimeLock which);
852 #else
assertCanLockJSRuntime853 void assertCanLock(js::RuntimeLock which) {}
854 #endif
855
856 private:
857 /*
858 * Lock taken when using per-runtime or per-zone data that could otherwise
859 * be accessed simultaneously by both the main thread and another thread
860 * with an ExclusiveContext.
861 *
862 * Locking this only occurs if there is actually a thread other than the
863 * main thread with an ExclusiveContext which could access such data.
864 */
865 PRLock* exclusiveAccessLock;
866 mozilla::DebugOnly<PRThread*> exclusiveAccessOwner;
867 mozilla::DebugOnly<bool> mainThreadHasExclusiveAccess;
868
869 /* Number of non-main threads with an ExclusiveContext. */
870 size_t numExclusiveThreads;
871
872 friend class js::AutoLockForExclusiveAccess;
873
874 public:
875 void setUsedByExclusiveThread(JS::Zone* zone);
876 void clearUsedByExclusiveThread(JS::Zone* zone);
877
878 #ifdef DEBUG
currentThreadHasExclusiveAccessJSRuntime879 bool currentThreadHasExclusiveAccess() {
880 return (!numExclusiveThreads && mainThreadHasExclusiveAccess) ||
881 exclusiveAccessOwner == PR_GetCurrentThread();
882 }
883 #endif // DEBUG
884
exclusiveThreadsPresentJSRuntime885 bool exclusiveThreadsPresent() const {
886 return numExclusiveThreads > 0;
887 }
888
889 // How many compartments there are across all zones. This number includes
890 // ExclusiveContext compartments, so it isn't necessarily equal to the
891 // number of compartments visited by CompartmentsIter.
892 size_t numCompartments;
893
894 /* Locale-specific callbacks for string conversion. */
895 const JSLocaleCallbacks* localeCallbacks;
896
897 /* Default locale for Internationalization API */
898 char* defaultLocale;
899
900 /* Default JSVersion. */
901 JSVersion defaultVersion_;
902
903 /* Futex state, used by futexWait and futexWake on the Atomics object */
904 js::FutexRuntime fx;
905
906 private:
907 /* See comment for JS_AbortIfWrongThread in jsapi.h. */
908 void* ownerThread_;
909 size_t ownerThreadNative_;
910 friend bool js::CurrentThreadCanAccessRuntime(JSRuntime* rt);
911 public:
912
ownerThreadNativeJSRuntime913 size_t ownerThreadNative() const {
914 return ownerThreadNative_;
915 }
916
917 /* Temporary arena pool used while compiling and decompiling. */
918 static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 4 * 1024;
919 js::LifoAlloc tempLifoAlloc;
920
921 private:
922 js::jit::JitRuntime* jitRuntime_;
923
924 /*
925 * Self-hosting state cloned on demand into other compartments. Shared with the parent
926 * runtime if there is one.
927 */
928 js::NativeObject* selfHostingGlobal_;
929
930 static js::GlobalObject*
931 createSelfHostingGlobal(JSContext* cx);
932
933 /* Space for interpreter frames. */
934 js::InterpreterStack interpreterStack_;
935
936 js::jit::JitRuntime* createJitRuntime(JSContext* cx);
937
938 public:
getJitRuntimeJSRuntime939 js::jit::JitRuntime* getJitRuntime(JSContext* cx) {
940 return jitRuntime_ ? jitRuntime_ : createJitRuntime(cx);
941 }
jitRuntimeJSRuntime942 js::jit::JitRuntime* jitRuntime() const {
943 return jitRuntime_;
944 }
hasJitRuntimeJSRuntime945 bool hasJitRuntime() const {
946 return !!jitRuntime_;
947 }
interpreterStackJSRuntime948 js::InterpreterStack& interpreterStack() {
949 return interpreterStack_;
950 }
951
952 private:
953 // Used to generate random keys for hash tables.
954 mozilla::Maybe<mozilla::non_crypto::XorShift128PlusRNG> randomKeyGenerator_;
955 mozilla::non_crypto::XorShift128PlusRNG& randomKeyGenerator();
956
957 public:
958 mozilla::HashCodeScrambler randomHashCodeScrambler();
959 mozilla::non_crypto::XorShift128PlusRNG forkRandomKeyGenerator();
960
961 //-------------------------------------------------------------------------
962 // Self-hosting support
963 //-------------------------------------------------------------------------
964
965 bool initSelfHosting(JSContext* cx);
966 void finishSelfHosting();
967 void markSelfHostingGlobal(JSTracer* trc);
isSelfHostingGlobalJSRuntime968 bool isSelfHostingGlobal(JSObject* global) {
969 return global == selfHostingGlobal_;
970 }
971 bool isSelfHostingCompartment(JSCompartment* comp) const;
972 bool isSelfHostingZone(const JS::Zone* zone) const;
973 bool cloneSelfHostedFunctionScript(JSContext* cx, js::Handle<js::PropertyName*> name,
974 js::Handle<JSFunction*> targetFun);
975 bool cloneSelfHostedValue(JSContext* cx, js::Handle<js::PropertyName*> name,
976 js::MutableHandleValue vp);
977
978 //-------------------------------------------------------------------------
979 // Locale information
980 //-------------------------------------------------------------------------
981
982 /*
983 * Set the default locale for the ECMAScript Internationalization API
984 * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
985 * Note that the Internationalization API encourages clients to
986 * specify their own locales.
987 * The locale string remains owned by the caller.
988 */
989 bool setDefaultLocale(const char* locale);
990
991 /* Reset the default locale to OS defaults. */
992 void resetDefaultLocale();
993
994 /* Gets current default locale. String remains owned by context. */
995 const char* getDefaultLocale();
996
defaultVersionJSRuntime997 JSVersion defaultVersion() { return defaultVersion_; }
setDefaultVersionJSRuntime998 void setDefaultVersion(JSVersion v) { defaultVersion_ = v; }
999
1000 /* Base address of the native stack for the current thread. */
1001 const uintptr_t nativeStackBase;
1002
1003 /* The native stack size limit that runtime should not exceed. */
1004 size_t nativeStackQuota[js::StackKindCount];
1005
1006 /* Context create/destroy callback. */
1007 JSContextCallback cxCallback;
1008 void* cxCallbackData;
1009
1010 /* Compartment destroy callback. */
1011 JSDestroyCompartmentCallback destroyCompartmentCallback;
1012
1013 /* Zone destroy callback. */
1014 JSZoneCallback destroyZoneCallback;
1015
1016 /* Zone sweep callback. */
1017 JSZoneCallback sweepZoneCallback;
1018
1019 /* Call this to get the name of a compartment. */
1020 JSCompartmentNameCallback compartmentNameCallback;
1021
1022 js::ActivityCallback activityCallback;
1023 void* activityCallbackArg;
1024 void triggerActivityCallback(bool active);
1025
1026 /* The request depth for this thread. */
1027 unsigned requestDepth;
1028
1029 #ifdef DEBUG
1030 unsigned checkRequestDepth;
1031
1032 /*
1033 * To help embedders enforce their invariants, we allow them to specify in
1034 * advance which JSContext should be passed to JSAPI calls. If this is set
1035 * to a non-null value, the assertSameCompartment machinery does double-
1036 * duty (in debug builds) to verify that it matches the cx being used.
1037 */
1038 JSContext* activeContext;
1039 #endif
1040
1041 /* Garbage collector state, used by jsgc.c. */
1042 js::gc::GCRuntime gc;
1043
1044 /* Garbage collector state has been successfully initialized. */
1045 bool gcInitialized;
1046
gcZealJSRuntime1047 int gcZeal() { return gc.zeal(); }
1048
lockGCJSRuntime1049 void lockGC() {
1050 assertCanLock(js::GCLock);
1051 gc.lockGC();
1052 }
1053
unlockGCJSRuntime1054 void unlockGC() {
1055 gc.unlockGC();
1056 }
1057
1058 #ifdef JS_SIMULATOR
1059 js::jit::Simulator* simulator_;
1060 #endif
1061
1062 public:
1063 #ifdef JS_SIMULATOR
1064 js::jit::Simulator* simulator() const;
1065 uintptr_t* addressOfSimulatorStackLimit();
1066 #endif
1067
1068 /* Strong references on scripts held for PCCount profiling API. */
1069 JS::PersistentRooted<js::ScriptAndCountsVector>* scriptAndCountsVector;
1070
1071 /* Code coverage output. */
1072 js::coverage::LCovRuntime lcovOutput;
1073
1074 /* Well-known numbers held for use by this runtime's contexts. */
1075 const js::Value NaNValue;
1076 const js::Value negativeInfinityValue;
1077 const js::Value positiveInfinityValue;
1078
1079 js::PropertyName* emptyString;
1080
1081 /* List of active contexts sharing this runtime. */
1082 mozilla::LinkedList<JSContext> contextList;
1083
hasContextsJSRuntime1084 bool hasContexts() const {
1085 return !contextList.isEmpty();
1086 }
1087
1088 mozilla::UniquePtr<js::SourceHook> sourceHook;
1089
1090 /* SPS profiling metadata */
1091 js::SPSProfiler spsProfiler;
1092
1093 /* If true, new scripts must be created with PC counter information. */
1094 bool profilingScripts;
1095
1096 /* Whether sampling should be enabled or not. */
1097 private:
1098 mozilla::Atomic<bool, mozilla::SequentiallyConsistent> suppressProfilerSampling;
1099
1100 public:
isProfilerSamplingEnabledJSRuntime1101 bool isProfilerSamplingEnabled() const {
1102 return !suppressProfilerSampling;
1103 }
disableProfilerSamplingJSRuntime1104 void disableProfilerSampling() {
1105 suppressProfilerSampling = true;
1106 }
enableProfilerSamplingJSRuntime1107 void enableProfilerSampling() {
1108 suppressProfilerSampling = false;
1109 }
1110
1111 /* Had an out-of-memory error which did not populate an exception. */
1112 bool hadOutOfMemory;
1113
1114 /* A context has been created on this runtime. */
1115 bool haveCreatedContext;
1116
1117 /*
1118 * Allow relazifying functions in compartments that are active. This is
1119 * only used by the relazifyFunctions() testing function.
1120 */
1121 bool allowRelazificationForTesting;
1122
1123 /* Linked list of all Debugger objects in the runtime. */
1124 mozilla::LinkedList<js::Debugger> debuggerList;
1125
1126 /*
1127 * Head of circular list of all enabled Debuggers that have
1128 * onNewGlobalObject handler methods established.
1129 */
1130 JSCList onNewGlobalObjectWatchers;
1131
1132 /* Client opaque pointers */
1133 void* data;
1134
1135 #if defined(XP_DARWIN) && defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
1136 js::AsmJSMachExceptionHandler asmJSMachExceptionHandler;
1137 #endif
1138
1139 private:
1140 // Whether EnsureSignalHandlersInstalled succeeded in installing all the
1141 // relevant handlers for this platform.
1142 bool signalHandlersInstalled_;
1143
1144 // Whether we should use them or they have been disabled for making
1145 // debugging easier. If signal handlers aren't installed, it is set to false.
1146 bool canUseSignalHandlers_;
1147
1148 public:
canUseSignalHandlersJSRuntime1149 bool canUseSignalHandlers() const {
1150 return canUseSignalHandlers_;
1151 }
setCanUseSignalHandlersJSRuntime1152 void setCanUseSignalHandlers(bool enable) {
1153 canUseSignalHandlers_ = signalHandlersInstalled_ && enable;
1154 }
1155
1156 private:
1157 js::FreeOp defaultFreeOp_;
1158
1159 public:
defaultFreeOpJSRuntime1160 js::FreeOp* defaultFreeOp() {
1161 return &defaultFreeOp_;
1162 }
1163
1164 uint32_t debuggerMutations;
1165
1166 const JSSecurityCallbacks* securityCallbacks;
1167 const js::DOMCallbacks* DOMcallbacks;
1168 JSDestroyPrincipalsOp destroyPrincipals;
1169 JSReadPrincipalsOp readPrincipals;
1170
1171 /* Optional error reporter. */
1172 JSErrorReporter errorReporter;
1173
1174 /* AsmJSCache callbacks are runtime-wide. */
1175 JS::AsmJSCacheOps asmJSCacheOps;
1176
1177 /* Head of the linked list of linked asm.js modules. */
1178 js::AsmJSModule* linkedAsmJSModules;
1179
1180 /*
1181 * The propertyRemovals counter is incremented for every JSObject::clear,
1182 * and for each JSObject::remove method call that frees a slot in the given
1183 * object. See js_NativeGet and js_NativeSet in jsobj.cpp.
1184 */
1185 uint32_t propertyRemovals;
1186
1187 #if !EXPOSE_INTL_API
1188 /* Number localization, used by jsnum.cpp. */
1189 const char* thousandsSeparator;
1190 const char* decimalSeparator;
1191 const char* numGrouping;
1192 #endif
1193
1194 private:
1195 js::MathCache* mathCache_;
1196 js::MathCache* createMathCache(JSContext* cx);
1197 public:
getMathCacheJSRuntime1198 js::MathCache* getMathCache(JSContext* cx) {
1199 return mathCache_ ? mathCache_ : createMathCache(cx);
1200 }
maybeGetMathCacheJSRuntime1201 js::MathCache* maybeGetMathCache() {
1202 return mathCache_;
1203 }
1204
1205 js::GSNCache gsnCache;
1206 js::ScopeCoordinateNameCache scopeCoordinateNameCache;
1207 js::NewObjectCache newObjectCache;
1208 js::NativeIterCache nativeIterCache;
1209 js::UncompressedSourceCache uncompressedSourceCache;
1210 js::EvalCache evalCache;
1211 js::LazyScriptCache lazyScriptCache;
1212
1213 js::CompressedSourceSet compressedSourceSet;
1214
1215 // Pool of maps used during parse/emit. This may be modified by threads
1216 // with an ExclusiveContext and requires a lock. Active compilations
1217 // prevent the pool from being purged during GCs.
1218 private:
1219 js::frontend::ParseMapPool parseMapPool_;
1220 unsigned activeCompilations_;
1221 public:
parseMapPoolJSRuntime1222 js::frontend::ParseMapPool& parseMapPool() {
1223 MOZ_ASSERT(currentThreadHasExclusiveAccess());
1224 return parseMapPool_;
1225 }
hasActiveCompilationsJSRuntime1226 bool hasActiveCompilations() {
1227 return activeCompilations_ != 0;
1228 }
addActiveCompilationJSRuntime1229 void addActiveCompilation() {
1230 MOZ_ASSERT(currentThreadHasExclusiveAccess());
1231 activeCompilations_++;
1232 }
removeActiveCompilationJSRuntime1233 void removeActiveCompilation() {
1234 MOZ_ASSERT(currentThreadHasExclusiveAccess());
1235 activeCompilations_--;
1236 }
1237
1238 // Count of AutoKeepAtoms instances on the main thread's stack. When any
1239 // instances exist, atoms in the runtime will not be collected. Threads
1240 // with an ExclusiveContext do not increment this value, but the presence
1241 // of any such threads also inhibits collection of atoms. We don't scan the
1242 // stacks of exclusive threads, so we need to avoid collecting their
1243 // objects in another way. The only GC thing pointers they have are to
1244 // their exclusive compartment (which is not collected) or to the atoms
1245 // compartment. Therefore, we avoid collecting the atoms compartment when
1246 // exclusive threads are running.
1247 private:
1248 unsigned keepAtoms_;
1249 friend class js::AutoKeepAtoms;
1250 public:
keepAtomsJSRuntime1251 bool keepAtoms() {
1252 MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
1253 return keepAtoms_ != 0 || exclusiveThreadsPresent();
1254 }
1255
1256 private:
1257 const JSPrincipals* trustedPrincipals_;
1258 public:
setTrustedPrincipalsJSRuntime1259 void setTrustedPrincipals(const JSPrincipals* p) { trustedPrincipals_ = p; }
trustedPrincipalsJSRuntime1260 const JSPrincipals* trustedPrincipals() const { return trustedPrincipals_; }
1261
1262 private:
1263 bool beingDestroyed_;
1264 public:
isBeingDestroyedJSRuntime1265 bool isBeingDestroyed() const {
1266 return beingDestroyed_;
1267 }
1268
1269 private:
1270 // Set of all atoms other than those in permanentAtoms and staticStrings.
1271 // Reading or writing this set requires the calling thread to have an
1272 // ExclusiveContext and hold a lock. Use AutoLockForExclusiveAccess.
1273 js::AtomSet* atoms_;
1274
1275 // Compartment and associated zone containing all atoms in the runtime, as
1276 // well as runtime wide IonCode stubs. Modifying the contents of this
1277 // compartment requires the calling thread to have an ExclusiveContext and
1278 // hold a lock. Use AutoLockForExclusiveAccess.
1279 JSCompartment* atomsCompartment_;
1280
1281 // Set of all live symbols produced by Symbol.for(). All such symbols are
1282 // allocated in the atomsCompartment. Reading or writing the symbol
1283 // registry requires the calling thread to have an ExclusiveContext and
1284 // hold a lock. Use AutoLockForExclusiveAccess.
1285 js::SymbolRegistry symbolRegistry_;
1286
1287 public:
1288 bool initializeAtoms(JSContext* cx);
1289 void finishAtoms();
1290
1291 void sweepAtoms();
1292
atomsJSRuntime1293 js::AtomSet& atoms() {
1294 MOZ_ASSERT(currentThreadHasExclusiveAccess());
1295 return *atoms_;
1296 }
atomsCompartmentJSRuntime1297 JSCompartment* atomsCompartment() {
1298 MOZ_ASSERT(currentThreadHasExclusiveAccess());
1299 return atomsCompartment_;
1300 }
1301
isAtomsCompartmentJSRuntime1302 bool isAtomsCompartment(JSCompartment* comp) {
1303 return comp == atomsCompartment_;
1304 }
1305
1306 // The atoms compartment is the only one in its zone.
1307 inline bool isAtomsZone(const JS::Zone* zone) const;
1308
1309 bool activeGCInAtomsZone();
1310
symbolRegistryJSRuntime1311 js::SymbolRegistry& symbolRegistry() {
1312 MOZ_ASSERT(currentThreadHasExclusiveAccess());
1313 return symbolRegistry_;
1314 }
1315
1316 // Permanent atoms are fixed during initialization of the runtime and are
1317 // not modified or collected until the runtime is destroyed. These may be
1318 // shared with another, longer living runtime through |parentRuntime| and
1319 // can be freely accessed with no locking necessary.
1320
1321 // Permanent atoms pre-allocated for general use.
1322 js::StaticStrings* staticStrings;
1323
1324 // Cached pointers to various permanent property names.
1325 JSAtomState* commonNames;
1326
1327 // All permanent atoms in the runtime, other than those in staticStrings.
1328 // Unlike |atoms_|, access to this does not require
1329 // AutoLockForExclusiveAccess because it is frozen and thus read-only.
1330 js::FrozenAtomSet* permanentAtoms;
1331
1332 bool transformToPermanentAtoms(JSContext* cx);
1333
1334 // Cached well-known symbols (ES6 rev 24 6.1.5.1). Like permanent atoms,
1335 // these are shared with the parentRuntime, if any.
1336 js::WellKnownSymbols* wellKnownSymbols;
1337
1338 const JSWrapObjectCallbacks* wrapObjectCallbacks;
1339 js::PreserveWrapperCallback preserveWrapperCallback;
1340
1341 // Table of bytecode and other data that may be shared across scripts
1342 // within the runtime. This may be modified by threads with an
1343 // ExclusiveContext and requires a lock.
1344 private:
1345 js::ScriptDataTable scriptDataTable_;
1346 public:
scriptDataTableJSRuntime1347 js::ScriptDataTable& scriptDataTable() {
1348 MOZ_ASSERT(currentThreadHasExclusiveAccess());
1349 return scriptDataTable_;
1350 }
1351
1352 bool jitSupportsFloatingPoint;
1353 bool jitSupportsSimd;
1354
1355 // Cache for jit::GetPcScript().
1356 js::jit::PcScriptCache* ionPcScriptCache;
1357
1358 js::ScriptEnvironmentPreparer* scriptEnvironmentPreparer;
1359
1360 js::CTypesActivityCallback ctypesActivityCallback;
1361
1362 private:
1363 static mozilla::Atomic<size_t> liveRuntimesCount;
1364
1365 public:
hasLiveRuntimesJSRuntime1366 static bool hasLiveRuntimes() {
1367 return liveRuntimesCount > 0;
1368 }
1369
1370 explicit JSRuntime(JSRuntime* parentRuntime);
1371 ~JSRuntime();
1372
1373 bool init(uint32_t maxbytes, uint32_t maxNurseryBytes);
1374
thisFromCtorJSRuntime1375 JSRuntime* thisFromCtor() { return this; }
1376
1377 /*
1378 * Call this after allocating memory held by GC things, to update memory
1379 * pressure counters or report the OOM error if necessary. If oomError and
1380 * cx is not null the function also reports OOM error.
1381 *
1382 * The function must be called outside the GC lock and in case of OOM error
1383 * the caller must ensure that no deadlock possible during OOM reporting.
1384 */
1385 void updateMallocCounter(size_t nbytes);
1386 void updateMallocCounter(JS::Zone* zone, size_t nbytes);
1387
reportAllocationOverflowJSRuntime1388 void reportAllocationOverflow() { js::ReportAllocationOverflow(nullptr); }
1389
1390 /*
1391 * This should be called after system malloc/calloc/realloc returns nullptr
1392 * to try to recove some memory or to report an error. For realloc, the
1393 * original pointer must be passed as reallocPtr.
1394 *
1395 * The function must be called outside the GC lock.
1396 */
1397 JS_FRIEND_API(void*) onOutOfMemory(js::AllocFunction allocator, size_t nbytes,
1398 void* reallocPtr = nullptr, JSContext* maybecx = nullptr);
1399
1400 /* onOutOfMemory but can call the largeAllocationFailureCallback. */
1401 JS_FRIEND_API(void*) onOutOfMemoryCanGC(js::AllocFunction allocator, size_t nbytes,
1402 void* reallocPtr = nullptr);
1403
1404 void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* runtime);
1405
1406 private:
1407 JS::RuntimeOptions options_;
1408 const js::Class* windowProxyClass_;
1409
1410 // Settings for how helper threads can be used.
1411 bool offthreadIonCompilationEnabled_;
1412 bool parallelParsingEnabled_;
1413
1414 bool autoWritableJitCodeActive_;
1415
1416 public:
1417
1418 // Note: these values may be toggled dynamically (in response to about:config
1419 // prefs changing).
setOffthreadIonCompilationEnabledJSRuntime1420 void setOffthreadIonCompilationEnabled(bool value) {
1421 offthreadIonCompilationEnabled_ = value;
1422 }
canUseOffthreadIonCompilationJSRuntime1423 bool canUseOffthreadIonCompilation() const {
1424 return offthreadIonCompilationEnabled_;
1425 }
setParallelParsingEnabledJSRuntime1426 void setParallelParsingEnabled(bool value) {
1427 parallelParsingEnabled_ = value;
1428 }
canUseParallelParsingJSRuntime1429 bool canUseParallelParsing() const {
1430 return parallelParsingEnabled_;
1431 }
1432
toggleAutoWritableJitCodeActiveJSRuntime1433 void toggleAutoWritableJitCodeActive(bool b) {
1434 MOZ_ASSERT(autoWritableJitCodeActive_ != b, "AutoWritableJitCode should not be nested.");
1435 MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
1436 autoWritableJitCodeActive_ = b;
1437 }
1438
optionsJSRuntime1439 const JS::RuntimeOptions& options() const {
1440 return options_;
1441 }
optionsJSRuntime1442 JS::RuntimeOptions& options() {
1443 return options_;
1444 }
1445
maybeWindowProxyClassJSRuntime1446 const js::Class* maybeWindowProxyClass() const {
1447 return windowProxyClass_;
1448 }
setWindowProxyClassJSRuntime1449 void setWindowProxyClass(const js::Class* clasp) {
1450 windowProxyClass_ = clasp;
1451 }
1452
1453 #ifdef DEBUG
1454 public:
1455 js::AutoEnterPolicy* enteredPolicy;
1456 #endif
1457
1458 /* See comment for JS::SetLargeAllocationFailureCallback in jsapi.h. */
1459 JS::LargeAllocationFailureCallback largeAllocationFailureCallback;
1460 void* largeAllocationFailureCallbackData;
1461
1462 /* See comment for JS::SetOutOfMemoryCallback in jsapi.h. */
1463 JS::OutOfMemoryCallback oomCallback;
1464 void* oomCallbackData;
1465
1466 /*
1467 * These variations of malloc/calloc/realloc will call the
1468 * large-allocation-failure callback on OOM and retry the allocation.
1469 */
1470
1471 static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
1472
1473 template <typename T>
pod_callocCanGCJSRuntime1474 T* pod_callocCanGC(size_t numElems) {
1475 T* p = pod_calloc<T>(numElems);
1476 if (MOZ_LIKELY(!!p))
1477 return p;
1478 size_t bytes;
1479 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
1480 reportAllocationOverflow();
1481 return nullptr;
1482 }
1483 return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Calloc, bytes));
1484 }
1485
1486 template <typename T>
pod_reallocCanGCJSRuntime1487 T* pod_reallocCanGC(T* p, size_t oldSize, size_t newSize) {
1488 T* p2 = pod_realloc<T>(p, oldSize, newSize);
1489 if (MOZ_LIKELY(!!p2))
1490 return p2;
1491 size_t bytes;
1492 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) {
1493 reportAllocationOverflow();
1494 return nullptr;
1495 }
1496 return static_cast<T*>(onOutOfMemoryCanGC(js::AllocFunction::Realloc, bytes, p));
1497 }
1498
1499 /*
1500 * Debugger.Memory functions like takeCensus use this embedding-provided
1501 * function to assess the size of malloc'd blocks of memory.
1502 */
1503 mozilla::MallocSizeOf debuggerMallocSizeOf;
1504
1505 /* Last time at which an animation was played for this runtime. */
1506 int64_t lastAnimationTime;
1507
1508 public:
1509 js::PerformanceMonitoring performanceMonitoring;
1510 };
1511
1512 namespace js {
1513
1514 // When entering JIT code, the calling JSContext* is stored into the thread's
1515 // PerThreadData. This function retrieves the JSContext with the pre-condition
1516 // that the caller is JIT code or C++ called directly from JIT code. This
1517 // function should not be called from arbitrary locations since the JSContext
1518 // may be the wrong one.
1519 static inline JSContext*
GetJSContextFromJitCode()1520 GetJSContextFromJitCode()
1521 {
1522 JSContext* cx = js::TlsPerThreadData.get()->runtimeFromMainThread()->jitJSContext;
1523 MOZ_ASSERT(cx);
1524 return cx;
1525 }
1526
1527 /*
1528 * Flags accompany script version data so that a) dynamically created scripts
1529 * can inherit their caller's compile-time properties and b) scripts can be
1530 * appropriately compared in the eval cache across global option changes. An
1531 * example of the latter is enabling the top-level-anonymous-function-is-error
1532 * option: subsequent evals of the same, previously-valid script text may have
1533 * become invalid.
1534 */
1535 namespace VersionFlags {
1536 static const unsigned MASK = 0x0FFF; /* see JSVersion in jspubtd.h */
1537 } /* namespace VersionFlags */
1538
1539 static inline JSVersion
VersionNumber(JSVersion version)1540 VersionNumber(JSVersion version)
1541 {
1542 return JSVersion(uint32_t(version) & VersionFlags::MASK);
1543 }
1544
1545 static inline JSVersion
VersionExtractFlags(JSVersion version)1546 VersionExtractFlags(JSVersion version)
1547 {
1548 return JSVersion(uint32_t(version) & ~VersionFlags::MASK);
1549 }
1550
1551 static inline void
VersionCopyFlags(JSVersion * version,JSVersion from)1552 VersionCopyFlags(JSVersion* version, JSVersion from)
1553 {
1554 *version = JSVersion(VersionNumber(*version) | VersionExtractFlags(from));
1555 }
1556
1557 static inline bool
VersionHasFlags(JSVersion version)1558 VersionHasFlags(JSVersion version)
1559 {
1560 return !!VersionExtractFlags(version);
1561 }
1562
1563 static inline bool
VersionIsKnown(JSVersion version)1564 VersionIsKnown(JSVersion version)
1565 {
1566 return VersionNumber(version) != JSVERSION_UNKNOWN;
1567 }
1568
1569 inline void
free_(void * p)1570 FreeOp::free_(void* p)
1571 {
1572 js_free(p);
1573 }
1574
1575 inline void
freeLater(void * p)1576 FreeOp::freeLater(void* p)
1577 {
1578 // FreeOps other than the defaultFreeOp() are constructed on the stack,
1579 // and won't hold onto the pointers to free indefinitely.
1580 MOZ_ASSERT(this != runtime()->defaultFreeOp());
1581
1582 AutoEnterOOMUnsafeRegion oomUnsafe;
1583 if (!freeLaterList.append(p))
1584 oomUnsafe.crash("FreeOp::freeLater");
1585 }
1586
1587 /*
1588 * RAII class that takes the GC lock while it is live.
1589 *
1590 * Note that the lock may be temporarily released by use of AutoUnlockGC when
1591 * passed a non-const reference to this class.
1592 */
1593 class MOZ_RAII AutoLockGC
1594 {
1595 public:
AutoLockGC(JSRuntime * rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1596 explicit AutoLockGC(JSRuntime* rt
1597 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1598 : runtime_(rt), wasUnlocked_(false)
1599 {
1600 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1601 lock();
1602 }
1603
~AutoLockGC()1604 ~AutoLockGC() {
1605 unlock();
1606 }
1607
lock()1608 void lock() {
1609 runtime_->lockGC();
1610 }
1611
unlock()1612 void unlock() {
1613 runtime_->unlockGC();
1614 wasUnlocked_ = true;
1615 }
1616
1617 #ifdef DEBUG
wasUnlocked()1618 bool wasUnlocked() {
1619 return wasUnlocked_;
1620 }
1621 #endif
1622
1623 private:
1624 JSRuntime* runtime_;
1625 mozilla::DebugOnly<bool> wasUnlocked_;
1626 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1627
1628 AutoLockGC(const AutoLockGC&) = delete;
1629 AutoLockGC& operator=(const AutoLockGC&) = delete;
1630 };
1631
1632 class MOZ_RAII AutoUnlockGC
1633 {
1634 public:
AutoUnlockGC(AutoLockGC & lock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1635 explicit AutoUnlockGC(AutoLockGC& lock
1636 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1637 : lock(lock)
1638 {
1639 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1640 lock.unlock();
1641 }
1642
~AutoUnlockGC()1643 ~AutoUnlockGC() {
1644 lock.lock();
1645 }
1646
1647 private:
1648 AutoLockGC& lock;
1649 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1650
1651 AutoUnlockGC(const AutoUnlockGC&) = delete;
1652 AutoUnlockGC& operator=(const AutoUnlockGC&) = delete;
1653 };
1654
1655 class MOZ_RAII AutoKeepAtoms
1656 {
1657 PerThreadData* pt;
1658 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1659
1660 public:
AutoKeepAtoms(PerThreadData * pt MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1661 explicit AutoKeepAtoms(PerThreadData* pt
1662 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
1663 : pt(pt)
1664 {
1665 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1666 if (JSRuntime* rt = pt->runtimeIfOnOwnerThread()) {
1667 rt->keepAtoms_++;
1668 } else {
1669 // This should be a thread with an exclusive context, which will
1670 // always inhibit collection of atoms.
1671 MOZ_ASSERT(pt->exclusiveThreadsPresent());
1672 }
1673 }
~AutoKeepAtoms()1674 ~AutoKeepAtoms() {
1675 if (JSRuntime* rt = pt->runtimeIfOnOwnerThread()) {
1676 MOZ_ASSERT(rt->keepAtoms_);
1677 rt->keepAtoms_--;
1678 if (rt->gc.fullGCForAtomsRequested() && !rt->keepAtoms())
1679 rt->gc.triggerFullGCForAtoms();
1680 }
1681 }
1682 };
1683
1684 inline JSRuntime*
runtimeFromMainThread()1685 PerThreadData::runtimeFromMainThread()
1686 {
1687 MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_));
1688 return runtime_;
1689 }
1690
1691 inline JSRuntime*
runtimeIfOnOwnerThread()1692 PerThreadData::runtimeIfOnOwnerThread()
1693 {
1694 return (runtime_ && CurrentThreadCanAccessRuntime(runtime_)) ? runtime_ : nullptr;
1695 }
1696
1697 inline bool
exclusiveThreadsPresent()1698 PerThreadData::exclusiveThreadsPresent()
1699 {
1700 return runtime_->exclusiveThreadsPresent();
1701 }
1702
1703 inline void
addActiveCompilation()1704 PerThreadData::addActiveCompilation()
1705 {
1706 activeCompilations++;
1707 runtime_->addActiveCompilation();
1708 }
1709
1710 inline void
removeActiveCompilation()1711 PerThreadData::removeActiveCompilation()
1712 {
1713 MOZ_ASSERT(activeCompilations);
1714 activeCompilations--;
1715 runtime_->removeActiveCompilation();
1716 }
1717
1718 /************************************************************************/
1719
1720 static MOZ_ALWAYS_INLINE void
MakeRangeGCSafe(Value * vec,size_t len)1721 MakeRangeGCSafe(Value* vec, size_t len)
1722 {
1723 mozilla::PodZero(vec, len);
1724 }
1725
1726 static MOZ_ALWAYS_INLINE void
MakeRangeGCSafe(Value * beg,Value * end)1727 MakeRangeGCSafe(Value* beg, Value* end)
1728 {
1729 mozilla::PodZero(beg, end - beg);
1730 }
1731
1732 static MOZ_ALWAYS_INLINE void
MakeRangeGCSafe(jsid * beg,jsid * end)1733 MakeRangeGCSafe(jsid* beg, jsid* end)
1734 {
1735 for (jsid* id = beg; id != end; ++id)
1736 *id = INT_TO_JSID(0);
1737 }
1738
1739 static MOZ_ALWAYS_INLINE void
MakeRangeGCSafe(jsid * vec,size_t len)1740 MakeRangeGCSafe(jsid* vec, size_t len)
1741 {
1742 MakeRangeGCSafe(vec, vec + len);
1743 }
1744
1745 static MOZ_ALWAYS_INLINE void
MakeRangeGCSafe(Shape ** beg,Shape ** end)1746 MakeRangeGCSafe(Shape** beg, Shape** end)
1747 {
1748 mozilla::PodZero(beg, end - beg);
1749 }
1750
1751 static MOZ_ALWAYS_INLINE void
MakeRangeGCSafe(Shape ** vec,size_t len)1752 MakeRangeGCSafe(Shape** vec, size_t len)
1753 {
1754 mozilla::PodZero(vec, len);
1755 }
1756
1757 static MOZ_ALWAYS_INLINE void
SetValueRangeToUndefined(Value * beg,Value * end)1758 SetValueRangeToUndefined(Value* beg, Value* end)
1759 {
1760 for (Value* v = beg; v != end; ++v)
1761 v->setUndefined();
1762 }
1763
1764 static MOZ_ALWAYS_INLINE void
SetValueRangeToUndefined(Value * vec,size_t len)1765 SetValueRangeToUndefined(Value* vec, size_t len)
1766 {
1767 SetValueRangeToUndefined(vec, vec + len);
1768 }
1769
1770 static MOZ_ALWAYS_INLINE void
SetValueRangeToNull(Value * beg,Value * end)1771 SetValueRangeToNull(Value* beg, Value* end)
1772 {
1773 for (Value* v = beg; v != end; ++v)
1774 v->setNull();
1775 }
1776
1777 static MOZ_ALWAYS_INLINE void
SetValueRangeToNull(Value * vec,size_t len)1778 SetValueRangeToNull(Value* vec, size_t len)
1779 {
1780 SetValueRangeToNull(vec, vec + len);
1781 }
1782
1783 /*
1784 * Allocation policy that uses JSRuntime::pod_malloc and friends, so that
1785 * memory pressure is properly accounted for. This is suitable for
1786 * long-lived objects owned by the JSRuntime.
1787 *
1788 * Since it doesn't hold a JSContext (those may not live long enough), it
1789 * can't report out-of-memory conditions itself; the caller must check for
1790 * OOM and take the appropriate action.
1791 *
1792 * FIXME bug 647103 - replace these *AllocPolicy names.
1793 */
1794 class RuntimeAllocPolicy
1795 {
1796 JSRuntime* const runtime;
1797
1798 public:
RuntimeAllocPolicy(JSRuntime * rt)1799 MOZ_IMPLICIT RuntimeAllocPolicy(JSRuntime* rt) : runtime(rt) {}
1800
1801 template <typename T>
maybe_pod_malloc(size_t numElems)1802 T* maybe_pod_malloc(size_t numElems) {
1803 return runtime->maybe_pod_malloc<T>(numElems);
1804 }
1805
1806 template <typename T>
maybe_pod_calloc(size_t numElems)1807 T* maybe_pod_calloc(size_t numElems) {
1808 return runtime->maybe_pod_calloc<T>(numElems);
1809 }
1810
1811 template <typename T>
maybe_pod_realloc(T * p,size_t oldSize,size_t newSize)1812 T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
1813 return runtime->maybe_pod_realloc<T>(p, oldSize, newSize);
1814 }
1815
1816 template <typename T>
pod_malloc(size_t numElems)1817 T* pod_malloc(size_t numElems) {
1818 return runtime->pod_malloc<T>(numElems);
1819 }
1820
1821 template <typename T>
pod_calloc(size_t numElems)1822 T* pod_calloc(size_t numElems) {
1823 return runtime->pod_calloc<T>(numElems);
1824 }
1825
1826 template <typename T>
pod_realloc(T * p,size_t oldSize,size_t newSize)1827 T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
1828 return runtime->pod_realloc<T>(p, oldSize, newSize);
1829 }
1830
free_(void * p)1831 void free_(void* p) { js_free(p); }
reportAllocOverflow()1832 void reportAllocOverflow() const {}
1833
checkSimulatedOOM()1834 bool checkSimulatedOOM() const {
1835 return !js::oom::ShouldFailWithOOM();
1836 }
1837 };
1838
1839 extern const JSSecurityCallbacks NullSecurityCallbacks;
1840
1841 // Debugging RAII class which marks the current thread as performing an Ion
1842 // compilation, for use by CurrentThreadCan{Read,Write}CompilationData
1843 class MOZ_RAII AutoEnterIonCompilation
1844 {
1845 public:
AutoEnterIonCompilation(bool safeForMinorGC MOZ_GUARD_OBJECT_NOTIFIER_PARAM)1846 explicit AutoEnterIonCompilation(bool safeForMinorGC
1847 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
1848 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
1849
1850 #ifdef DEBUG
1851 PerThreadData* pt = js::TlsPerThreadData.get();
1852 MOZ_ASSERT(!pt->ionCompiling);
1853 MOZ_ASSERT(!pt->ionCompilingSafeForMinorGC);
1854 pt->ionCompiling = true;
1855 pt->ionCompilingSafeForMinorGC = safeForMinorGC;
1856 #endif
1857 }
1858
~AutoEnterIonCompilation()1859 ~AutoEnterIonCompilation() {
1860 #ifdef DEBUG
1861 PerThreadData* pt = js::TlsPerThreadData.get();
1862 MOZ_ASSERT(pt->ionCompiling);
1863 pt->ionCompiling = false;
1864 pt->ionCompilingSafeForMinorGC = false;
1865 #endif
1866 }
1867
1868 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
1869 };
1870
1871 /*
1872 * Provides a delete policy that can be used for objects which have their
1873 * lifetime managed by the GC and can only safely be destroyed while the nursery
1874 * is empty.
1875 *
1876 * This is necessary when initializing such an object may fail after the initial
1877 * allocation. The partially-initialized object must be destroyed, but it may
1878 * not be safe to do so at the current time. This policy puts the object on a
1879 * queue to be destroyed at a safe time.
1880 */
1881 template <typename T>
1882 struct GCManagedDeletePolicy
1883 {
operatorGCManagedDeletePolicy1884 void operator()(const T* ptr) {
1885 if (ptr) {
1886 JSRuntime* rt = TlsPerThreadData.get()->runtimeIfOnOwnerThread();
1887 if (rt)
1888 rt->gc.callAfterMinorGC(deletePtr, const_cast<T*>(ptr));
1889 else
1890 js_delete(const_cast<T*>(ptr));
1891 }
1892 }
1893
1894 private:
deletePtrGCManagedDeletePolicy1895 static void deletePtr(void* data) {
1896 js_delete(reinterpret_cast<T*>(data));
1897 }
1898 };
1899
1900 } /* namespace js */
1901
1902 namespace JS {
1903
1904 template <typename T>
1905 struct DeletePolicy<js::HeapPtr<T>> : public js::GCManagedDeletePolicy<js::HeapPtr<T>>
1906 {};
1907
1908 } /* namespace JS */
1909
1910 #ifdef _MSC_VER
1911 #pragma warning(pop)
1912 #endif
1913
1914 #endif /* vm_Runtime_h */
1915