Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
7 #include "vm/Runtime-inl.h"
9 #include "mozilla/ArrayUtils.h"
10 #include "mozilla/Atomics.h"
11 #include "mozilla/DebugOnly.h"
12 #include "mozilla/MemoryReporting.h"
13 #include "mozilla/ThreadLocal.h"
15 #include <locale.h>
16 #include <string.h>
18 #ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
19 # include <sys/mman.h>
20 #endif
22 #include "jsatom.h"
23 #include "jsdtoa.h"
24 #include "jsgc.h"
25 #include "jsmath.h"
26 #include "jsnativestack.h"
27 #include "jsobj.h"
28 #include "jsscript.h"
29 #include "jswatchpoint.h"
30 #include "jswrapper.h"
32 #if defined(JS_ION)
33 # include "assembler/assembler/MacroAssembler.h"
34 #endif
35 #include "jit/arm/Simulator-arm.h"
36 #include "jit/AsmJSSignalHandlers.h"
37 #include "jit/JitCompartment.h"
38 #include "jit/PcScriptCache.h"
39 #include "js/MemoryMetrics.h"
40 #include "js/SliceBudget.h"
41 #include "yarr/BumpPointerAllocator.h"
43 #include "jscntxtinlines.h"
44 #include "jsgcinlines.h"
46 using namespace js;
47 using namespace js::gc;
49 using mozilla::Atomic;
50 using mozilla::DebugOnly;
51 using mozilla::NegativeInfinity;
52 using mozilla::PodZero;
53 using mozilla::PodArrayZero;
54 using mozilla::PositiveInfinity;
55 using mozilla::ThreadLocal;
56 using JS::GenericNaN;
57 using JS::DoubleNaNValue;
59 /* static */ ThreadLocal<PerThreadData*> js::TlsPerThreadData;
61 #ifdef JS_THREADSAFE
62 /* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
63 #else
64 /* static */ size_t JSRuntime::liveRuntimesCount;
65 #endif
67 const JSSecurityCallbacks js::NullSecurityCallbacks = { };
69 PerThreadData::PerThreadData(JSRuntime *runtime)
70 : PerThreadDataFriendFields(),
71 runtime_(runtime),
72 ionTop(nullptr),
73 jitJSContext(nullptr),
74 jitStackLimit(0),
75 #ifdef JS_TRACE_LOGGING
76 traceLogger(nullptr),
77 #endif
78 activation_(nullptr),
79 asmJSActivationStack_(nullptr),
80 autoFlushICache_(nullptr),
81 #ifdef JS_ARM_SIMULATOR
82 simulator_(nullptr),
83 simulatorStackLimit_(0),
84 #endif
85 dtoaState(nullptr),
86 suppressGC(0),
87 activeCompilations(0)
88 {}
90 PerThreadData::~PerThreadData()
91 {
92 if (dtoaState)
93 js_DestroyDtoaState(dtoaState);
95 #ifdef JS_ARM_SIMULATOR
96 js_delete(simulator_);
97 #endif
98 }
100 bool
101 PerThreadData::init()
102 {
103 dtoaState = js_NewDtoaState();
104 if (!dtoaState)
105 return false;
107 return true;
108 }
110 static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
111 TransparentObjectWrapper,
112 nullptr
113 };
115 JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThreads)
116 : JS::shadow::Runtime(
117 #ifdef JSGC_GENERATIONAL
118 &gcStoreBuffer
119 #endif
120 ),
121 mainThread(this),
122 parentRuntime(parentRuntime),
123 interrupt(false),
124 #if defined(JS_THREADSAFE) && defined(JS_ION)
125 interruptPar(false),
126 #endif
127 handlingSignal(false),
128 interruptCallback(nullptr),
129 #ifdef JS_THREADSAFE
130 interruptLock(nullptr),
131 interruptLockOwner(nullptr),
132 exclusiveAccessLock(nullptr),
133 exclusiveAccessOwner(nullptr),
134 mainThreadHasExclusiveAccess(false),
135 numExclusiveThreads(0),
136 #else
137 interruptLockTaken(false),
138 #endif
139 systemZone(nullptr),
140 numCompartments(0),
141 localeCallbacks(nullptr),
142 defaultLocale(nullptr),
143 defaultVersion_(JSVERSION_DEFAULT),
144 #ifdef JS_THREADSAFE
145 ownerThread_(nullptr),
146 #endif
147 tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
148 freeLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
149 execAlloc_(nullptr),
150 bumpAlloc_(nullptr),
151 jitRuntime_(nullptr),
152 selfHostingGlobal_(nullptr),
153 nativeStackBase(0),
154 cxCallback(nullptr),
155 destroyCompartmentCallback(nullptr),
156 destroyZoneCallback(nullptr),
157 sweepZoneCallback(nullptr),
158 compartmentNameCallback(nullptr),
159 activityCallback(nullptr),
160 activityCallbackArg(nullptr),
161 #ifdef JS_THREADSAFE
162 requestDepth(0),
163 # ifdef DEBUG
164 checkRequestDepth(0),
165 # endif
166 #endif
167 #ifdef DEBUG
168 activeContext(nullptr),
169 #endif
170 gcInitialized(false),
171 gcSystemAvailableChunkListHead(nullptr),
172 gcUserAvailableChunkListHead(nullptr),
173 gcBytes(0),
174 gcMaxBytes(0),
175 gcMaxMallocBytes(0),
176 gcNumArenasFreeCommitted(0),
177 gcMarker(this),
178 gcVerifyPreData(nullptr),
179 gcVerifyPostData(nullptr),
180 gcChunkAllocationSinceLastGC(false),
181 gcNextFullGCTime(0),
182 gcLastGCTime(0),
183 gcJitReleaseTime(0),
184 gcAllocationThreshold(30 * 1024 * 1024),
185 gcHighFrequencyGC(false),
186 gcHighFrequencyTimeThreshold(1000),
187 gcHighFrequencyLowLimitBytes(100 * 1024 * 1024),
188 gcHighFrequencyHighLimitBytes(500 * 1024 * 1024),
189 gcHighFrequencyHeapGrowthMax(3.0),
190 gcHighFrequencyHeapGrowthMin(1.5),
191 gcLowFrequencyHeapGrowth(1.5),
192 gcDynamicHeapGrowth(false),
193 gcDynamicMarkSlice(false),
194 gcDecommitThreshold(32 * 1024 * 1024),
195 gcShouldCleanUpEverything(false),
196 gcGrayBitsValid(false),
197 gcIsNeeded(0),
198 gcStats(thisFromCtor()),
199 gcNumber(0),
200 gcStartNumber(0),
201 gcIsFull(false),
202 gcTriggerReason(JS::gcreason::NO_REASON),
203 gcStrictCompartmentChecking(false),
204 #ifdef DEBUG
205 gcDisableStrictProxyCheckingCount(0),
206 #endif
207 gcIncrementalState(gc::NO_INCREMENTAL),
208 gcLastMarkSlice(false),
209 gcSweepOnBackgroundThread(false),
210 gcFoundBlackGrayEdges(false),
211 gcSweepingZones(nullptr),
212 gcZoneGroupIndex(0),
213 gcZoneGroups(nullptr),
214 gcCurrentZoneGroup(nullptr),
215 gcSweepPhase(0),
216 gcSweepZone(nullptr),
217 gcSweepKindIndex(0),
218 gcAbortSweepAfterCurrentGroup(false),
219 gcArenasAllocatedDuringSweep(nullptr),
220 #ifdef DEBUG
221 gcMarkingValidator(nullptr),
222 #endif
223 gcInterFrameGC(0),
224 gcSliceBudget(SliceBudget::Unlimited),
225 gcIncrementalEnabled(true),
226 gcGenerationalDisabled(0),
227 gcManipulatingDeadZones(false),
228 gcObjectsMarkedInDeadZones(0),
229 gcPoke(false),
230 heapState(Idle),
231 #ifdef JSGC_GENERATIONAL
232 gcNursery(thisFromCtor()),
233 gcStoreBuffer(thisFromCtor(), gcNursery),
234 #endif
235 #ifdef JS_GC_ZEAL
236 gcZeal_(0),
237 gcZealFrequency(0),
238 gcNextScheduled(0),
239 gcDeterministicOnly(false),
240 gcIncrementalLimit(0),
241 #endif
242 gcValidate(true),
243 gcFullCompartmentChecks(false),
244 gcCallback(nullptr),
245 gcSliceCallback(nullptr),
246 gcFinalizeCallback(nullptr),
247 gcMallocBytes(0),
248 gcMallocGCTriggered(false),
249 #ifdef JS_ARM_SIMULATOR
250 simulatorRuntime_(nullptr),
251 #endif
252 scriptAndCountsVector(nullptr),
253 NaNValue(DoubleNaNValue()),
254 negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
255 positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
256 emptyString(nullptr),
257 debugMode(false),
258 spsProfiler(thisFromCtor()),
259 profilingScripts(false),
260 alwaysPreserveCode(false),
261 hadOutOfMemory(false),
262 haveCreatedContext(false),
263 data(nullptr),
264 gcLock(nullptr),
265 gcLockOwner(nullptr),
266 gcHelperThread(thisFromCtor()),
267 signalHandlersInstalled_(false),
268 defaultFreeOp_(thisFromCtor(), false),
269 debuggerMutations(0),
270 securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)),
271 DOMcallbacks(nullptr),
272 destroyPrincipals(nullptr),
273 structuredCloneCallbacks(nullptr),
274 telemetryCallback(nullptr),
275 propertyRemovals(0),
276 #if !EXPOSE_INTL_API
277 thousandsSeparator(0),
278 decimalSeparator(0),
279 numGrouping(0),
280 #endif
281 mathCache_(nullptr),
282 activeCompilations_(0),
283 keepAtoms_(0),
284 trustedPrincipals_(nullptr),
285 beingDestroyed_(false),
286 atoms_(nullptr),
287 atomsCompartment_(nullptr),
288 staticStrings(nullptr),
289 commonNames(nullptr),
290 permanentAtoms(nullptr),
291 wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
292 preserveWrapperCallback(nullptr),
293 #ifdef DEBUG
294 noGCOrAllocationCheck(0),
295 #endif
296 jitSupportsFloatingPoint(false),
297 ionPcScriptCache(nullptr),
298 threadPool(this),
299 defaultJSContextCallback(nullptr),
300 ctypesActivityCallback(nullptr),
301 forkJoinWarmup(0),
302 ionReturnOverride_(MagicValue(JS_ARG_POISON)),
303 useHelperThreads_(useHelperThreads),
304 parallelIonCompilationEnabled_(true),
305 parallelParsingEnabled_(true),
306 isWorkerRuntime_(false),
307 #ifdef DEBUG
308 enteredPolicy(nullptr),
309 #endif
310 largeAllocationFailureCallback(nullptr),
311 oomCallback(nullptr)
312 {
313 liveRuntimesCount++;
315 setGCMode(JSGC_MODE_GLOBAL);
317 /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
318 JS_INIT_CLIST(&onNewGlobalObjectWatchers);
320 PodZero(&debugHooks);
321 PodArrayZero(nativeStackQuota);
322 PodZero(&asmJSCacheOps);
323 }
325 static bool
326 JitSupportsFloatingPoint()
327 {
328 #if defined(JS_ION)
329 if (!JSC::MacroAssembler::supportsFloatingPoint())
330 return false;
332 #if defined(JS_ION) && WTF_ARM_ARCH_VERSION == 6
333 if (!js::jit::hasVFP())
334 return false;
335 #endif
337 return true;
338 #else
339 return false;
340 #endif
341 }
343 bool
344 JSRuntime::init(uint32_t maxbytes)
345 {
346 #ifdef JS_THREADSAFE
347 ownerThread_ = PR_GetCurrentThread();
349 interruptLock = PR_NewLock();
350 if (!interruptLock)
351 return false;
353 gcLock = PR_NewLock();
354 if (!gcLock)
355 return false;
357 exclusiveAccessLock = PR_NewLock();
358 if (!exclusiveAccessLock)
359 return false;
360 #endif
362 if (!mainThread.init())
363 return false;
365 js::TlsPerThreadData.set(&mainThread);
367 if (!threadPool.init())
368 return false;
370 if (!js_InitGC(this, maxbytes))
371 return false;
373 if (!gcMarker.init(gcMode()))
374 return false;
376 const char *size = getenv("JSGC_MARK_STACK_LIMIT");
377 if (size)
378 SetMarkStackLimit(this, atoi(size));
380 ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this));
381 if (!atomsZone)
382 return false;
384 JS::CompartmentOptions options;
385 ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
386 if (!atomsCompartment || !atomsCompartment->init(nullptr))
387 return false;
389 zones.append(atomsZone.get());
390 atomsZone->compartments.append(atomsCompartment.get());
392 atomsCompartment->isSystem = true;
393 atomsZone->isSystem = true;
394 atomsZone->setGCLastBytes(8192, GC_NORMAL);
396 atomsZone.forget();
397 this->atomsCompartment_ = atomsCompartment.forget();
399 if (!scriptDataTable_.init())
400 return false;
402 if (!evalCache.init())
403 return false;
405 /* The garbage collector depends on everything before this point being initialized. */
406 gcInitialized = true;
408 if (!InitRuntimeNumberState(this))
409 return false;
411 dateTimeInfo.updateTimeZoneAdjustment();
413 #ifdef JS_ARM_SIMULATOR
414 simulatorRuntime_ = js::jit::CreateSimulatorRuntime();
415 if (!simulatorRuntime_)
416 return false;
417 #endif
419 nativeStackBase = GetNativeStackBase();
421 jitSupportsFloatingPoint = JitSupportsFloatingPoint();
423 #ifdef JS_ION
424 signalHandlersInstalled_ = EnsureAsmJSSignalHandlersInstalled(this);
425 #endif
427 if (!spsProfiler.init())
428 return false;
430 return true;
431 }
433 JSRuntime::~JSRuntime()
434 {
435 JS_ASSERT(!isHeapBusy());
437 if (gcInitialized) {
438 /* Free source hook early, as its destructor may want to delete roots. */
439 sourceHook = nullptr;
441 /*
442 * Cancel any pending, in progress or completed Ion compilations and
443 * parse tasks. Waiting for AsmJS and compression tasks is done
444 * synchronously (on the main thread or during parse tasks), so no
445 * explicit canceling is needed for these.
446 */
447 for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next())
448 CancelOffThreadIonCompile(comp, nullptr);
449 CancelOffThreadParses(this);
451 /* Clear debugging state to remove GC roots. */
452 for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next()) {
453 comp->clearTraps(defaultFreeOp());
454 if (WatchpointMap *wpmap = comp->watchpointMap)
455 wpmap->clear();
456 }
458 /* Clear atoms to remove GC roots and heap allocations. */
459 finishAtoms();
461 /*
462 * Flag us as being destroyed. This allows the GC to free things like
463 * interned atoms and Ion trampolines.
464 */
465 beingDestroyed_ = true;
467 /* Allow the GC to release scripts that were being profiled. */
468 profilingScripts = false;
470 JS::PrepareForFullGC(this);
471 GC(this, GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
472 }
474 /*
475 * Clear the self-hosted global and delete self-hosted classes *after*
476 * GC, as finalizers for objects check for clasp->finalize during GC.
477 */
478 finishSelfHosting();
480 #ifdef JS_THREADSAFE
481 JS_ASSERT(!exclusiveAccessOwner);
482 if (exclusiveAccessLock)
483 PR_DestroyLock(exclusiveAccessLock);
485 // Avoid bogus asserts during teardown.
486 JS_ASSERT(!numExclusiveThreads);
487 mainThreadHasExclusiveAccess = true;
489 JS_ASSERT(!interruptLockOwner);
490 if (interruptLock)
491 PR_DestroyLock(interruptLock);
492 #endif
494 /*
495 * Even though all objects in the compartment are dead, we may have keep
496 * some filenames around because of gcKeepAtoms.
497 */
498 FreeScriptData(this);
500 #ifdef DEBUG
501 /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */
502 if (hasContexts()) {
503 unsigned cxcount = 0;
504 for (ContextIter acx(this); !acx.done(); acx.next()) {
505 fprintf(stderr,
506 "JS API usage error: found live context at %p\n",
507 (void *) acx.get());
508 cxcount++;
509 }
510 fprintf(stderr,
511 "JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
512 cxcount, (cxcount == 1) ? "" : "s");
513 }
514 #endif
516 #if !EXPOSE_INTL_API
517 FinishRuntimeNumberState(this);
518 #endif
520 js_FinishGC(this);
521 atomsCompartment_ = nullptr;
523 #ifdef JS_THREADSAFE
524 if (gcLock)
525 PR_DestroyLock(gcLock);
526 #endif
528 js_free(defaultLocale);
529 js_delete(bumpAlloc_);
530 js_delete(mathCache_);
531 #ifdef JS_ION
532 js_delete(jitRuntime_);
533 #endif
534 js_delete(execAlloc_); /* Delete after jitRuntime_. */
536 js_delete(ionPcScriptCache);
538 #ifdef JSGC_GENERATIONAL
539 gcStoreBuffer.disable();
540 gcNursery.disable();
541 #endif
543 #ifdef JS_ARM_SIMULATOR
544 js::jit::DestroySimulatorRuntime(simulatorRuntime_);
545 #endif
547 DebugOnly<size_t> oldCount = liveRuntimesCount--;
548 JS_ASSERT(oldCount > 0);
550 #ifdef JS_THREADSAFE
551 js::TlsPerThreadData.set(nullptr);
552 #endif
553 }
555 void
556 NewObjectCache::clearNurseryObjects(JSRuntime *rt)
557 {
558 for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) {
559 Entry &e = entries[i];
560 JSObject *obj = reinterpret_cast<JSObject *>(&e.templateObject);
561 if (IsInsideNursery(rt, e.key) ||
562 IsInsideNursery(rt, obj->slots) ||
563 IsInsideNursery(rt, obj->elements))
564 {
565 PodZero(&e);
566 }
567 }
568 }
570 void
571 JSRuntime::resetJitStackLimit()
572 {
573 AutoLockForInterrupt lock(this);
574 mainThread.setJitStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]);
576 #ifdef JS_ARM_SIMULATOR
577 mainThread.setJitStackLimit(js::jit::Simulator::StackLimit());
578 #endif
579 }
581 void
582 JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes)
583 {
584 // Several tables in the runtime enumerated below can be used off thread.
585 AutoLockForExclusiveAccess lock(this);
587 rtSizes->object += mallocSizeOf(this);
589 rtSizes->atomsTable += atoms().sizeOfIncludingThis(mallocSizeOf);
591 if (!parentRuntime) {
592 rtSizes->atomsTable += mallocSizeOf(staticStrings);
593 rtSizes->atomsTable += mallocSizeOf(commonNames);
594 rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
595 }
597 for (ContextIter acx(this); !acx.done(); acx.next())
598 rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
600 rtSizes->dtoa += mallocSizeOf(mainThread.dtoaState);
602 rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
604 rtSizes->regexpData += bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0;
606 rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
608 rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
610 rtSizes->sourceDataCache += sourceDataCache.sizeOfExcludingThis(mallocSizeOf);
612 rtSizes->scriptData += scriptDataTable().sizeOfExcludingThis(mallocSizeOf);
613 for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront())
614 rtSizes->scriptData += mallocSizeOf(r.front());
616 if (execAlloc_)
617 execAlloc_->addSizeOfCode(&rtSizes->code);
618 #ifdef JS_ION
619 {
620 AutoLockForInterrupt lock(this);
621 if (jitRuntime()) {
622 if (JSC::ExecutableAllocator *ionAlloc = jitRuntime()->ionAlloc(this))
623 ionAlloc->addSizeOfCode(&rtSizes->code);
624 }
625 }
626 #endif
628 rtSizes->gc.marker += gcMarker.sizeOfExcludingThis(mallocSizeOf);
629 #ifdef JSGC_GENERATIONAL
630 rtSizes->gc.nurseryCommitted += gcNursery.sizeOfHeapCommitted();
631 rtSizes->gc.nurseryDecommitted += gcNursery.sizeOfHeapDecommitted();
632 rtSizes->gc.nurseryHugeSlots += gcNursery.sizeOfHugeSlots(mallocSizeOf);
633 gcStoreBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
634 #endif
635 }
637 static bool
638 SignalBasedTriggersDisabled()
639 {
640 // Don't bother trying to cache the getenv lookup; this should be called
641 // infrequently.
642 return !!getenv("JS_DISABLE_SLOW_SCRIPT_SIGNALS");
643 }
645 void
646 JSRuntime::requestInterrupt(InterruptMode mode)
647 {
648 AutoLockForInterrupt lock(this);
650 /*
651 * Invalidate ionTop to trigger its over-recursion check. Note this must be
652 * set before interrupt, to avoid racing with js::InvokeInterruptCallback,
653 * into a weird state where interrupt is stuck at 0 but jitStackLimit is
654 * MAXADDR.
655 */
656 mainThread.setJitStackLimit(-1);
658 interrupt = true;
660 #ifdef JS_ION
661 #ifdef JS_THREADSAFE
662 RequestInterruptForForkJoin(this, mode);
663 #endif
665 /*
666 * asm.js and, optionally, normal Ion code use memory protection and signal
667 * handlers to halt running code.
668 */
669 if (!SignalBasedTriggersDisabled()) {
670 RequestInterruptForAsmJSCode(this);
671 jit::RequestInterruptForIonCode(this, mode);
672 }
673 #endif
674 }
676 JSC::ExecutableAllocator *
677 JSRuntime::createExecutableAllocator(JSContext *cx)
678 {
679 JS_ASSERT(!execAlloc_);
680 JS_ASSERT(cx->runtime() == this);
682 execAlloc_ = js_new<JSC::ExecutableAllocator>();
683 if (!execAlloc_)
684 js_ReportOutOfMemory(cx);
685 return execAlloc_;
686 }
688 WTF::BumpPointerAllocator *
689 JSRuntime::createBumpPointerAllocator(JSContext *cx)
690 {
691 JS_ASSERT(!bumpAlloc_);
692 JS_ASSERT(cx->runtime() == this);
694 bumpAlloc_ = js_new<WTF::BumpPointerAllocator>();
695 if (!bumpAlloc_)
696 js_ReportOutOfMemory(cx);
697 return bumpAlloc_;
698 }
700 MathCache *
701 JSRuntime::createMathCache(JSContext *cx)
702 {
703 JS_ASSERT(!mathCache_);
704 JS_ASSERT(cx->runtime() == this);
706 MathCache *newMathCache = js_new<MathCache>();
707 if (!newMathCache) {
708 js_ReportOutOfMemory(cx);
709 return nullptr;
710 }
712 mathCache_ = newMathCache;
713 return mathCache_;
714 }
716 bool
717 JSRuntime::setDefaultLocale(const char *locale)
718 {
719 if (!locale)
720 return false;
721 resetDefaultLocale();
722 defaultLocale = JS_strdup(this, locale);
723 return defaultLocale != nullptr;
724 }
726 void
727 JSRuntime::resetDefaultLocale()
728 {
729 js_free(defaultLocale);
730 defaultLocale = nullptr;
731 }
733 const char *
734 JSRuntime::getDefaultLocale()
735 {
736 if (defaultLocale)
737 return defaultLocale;
739 char *locale, *lang, *p;
740 #ifdef HAVE_SETLOCALE
741 locale = setlocale(LC_ALL, nullptr);
742 #else
743 locale = getenv("LANG");
744 #endif
745 // convert to a well-formed BCP 47 language tag
746 if (!locale || !strcmp(locale, "C"))
747 locale = const_cast<char*>("und");
748 lang = JS_strdup(this, locale);
749 if (!lang)
750 return nullptr;
751 if ((p = strchr(lang, '.')))
752 *p = '\0';
753 while ((p = strchr(lang, '_')))
754 *p = '-';
756 defaultLocale = lang;
757 return defaultLocale;
758 }
760 void
761 JSRuntime::triggerActivityCallback(bool active)
762 {
763 if (!activityCallback)
764 return;
766 /*
767 * The activity callback must not trigger a GC: it would create a cirular
768 * dependency between entering a request and Rooted's requirement of being
769 * in a request. In practice this callback already cannot trigger GC. The
770 * suppression serves to inform the exact rooting hazard analysis of this
771 * property and ensures that it remains true in the future.
772 */
773 AutoSuppressGC suppress(this);
775 activityCallback(activityCallbackArg, active);
776 }
778 void
779 JSRuntime::setGCMaxMallocBytes(size_t value)
780 {
781 /*
782 * For compatibility treat any value that exceeds PTRDIFF_T_MAX to
783 * mean that value.
784 */
785 gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
786 resetGCMallocBytes();
787 for (ZonesIter zone(this, WithAtoms); !zone.done(); zone.next())
788 zone->setGCMaxMallocBytes(value);
789 }
791 void
792 JSRuntime::updateMallocCounter(size_t nbytes)
793 {
794 updateMallocCounter(nullptr, nbytes);
795 }
797 void
798 JSRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes)
799 {
800 /* We tolerate any thread races when updating gcMallocBytes. */
801 gcMallocBytes -= ptrdiff_t(nbytes);
802 if (MOZ_UNLIKELY(gcMallocBytes <= 0))
803 onTooMuchMalloc();
804 else if (zone)
805 zone->updateMallocCounter(nbytes);
806 }
808 JS_FRIEND_API(void)
809 JSRuntime::onTooMuchMalloc()
810 {
811 if (!CurrentThreadCanAccessRuntime(this))
812 return;
814 if (!gcMallocGCTriggered)
815 gcMallocGCTriggered = TriggerGC(this, JS::gcreason::TOO_MUCH_MALLOC);
816 }
818 JS_FRIEND_API(void *)
819 JSRuntime::onOutOfMemory(void *p, size_t nbytes)
820 {
821 return onOutOfMemory(p, nbytes, nullptr);
822 }
824 JS_FRIEND_API(void *)
825 JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
826 {
827 if (isHeapBusy())
828 return nullptr;
830 /*
831 * Retry when we are done with the background sweeping and have stopped
832 * all the allocations and released the empty GC chunks.
833 */
834 JS::ShrinkGCBuffers(this);
835 gcHelperThread.waitBackgroundSweepOrAllocEnd();
836 if (!p)
837 p = js_malloc(nbytes);
838 else if (p == reinterpret_cast<void *>(1))
839 p = js_calloc(nbytes);
840 else
841 p = js_realloc(p, nbytes);
842 if (p)
843 return p;
844 if (cx)
845 js_ReportOutOfMemory(cx);
846 return nullptr;
847 }
849 bool
850 JSRuntime::activeGCInAtomsZone()
851 {
852 Zone *zone = atomsCompartment_->zone();
853 return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted();
854 }
856 #ifdef JS_THREADSAFE
858 void
859 JSRuntime::setUsedByExclusiveThread(Zone *zone)
860 {
861 JS_ASSERT(!zone->usedByExclusiveThread);
862 zone->usedByExclusiveThread = true;
863 numExclusiveThreads++;
864 }
866 void
867 JSRuntime::clearUsedByExclusiveThread(Zone *zone)
868 {
869 JS_ASSERT(zone->usedByExclusiveThread);
870 zone->usedByExclusiveThread = false;
871 numExclusiveThreads--;
872 }
874 bool
875 js::CurrentThreadCanAccessRuntime(JSRuntime *rt)
876 {
877 return rt->ownerThread_ == PR_GetCurrentThread() && !InParallelSection();
878 }
880 bool
881 js::CurrentThreadCanAccessZone(Zone *zone)
882 {
883 if (CurrentThreadCanAccessRuntime(zone->runtime_))
884 return true;
885 if (InParallelSection()) {
886 DebugOnly<PerThreadData *> pt = js::TlsPerThreadData.get();
887 JS_ASSERT(pt && pt->associatedWith(zone->runtime_));
888 return true;
889 }
891 // Only zones in use by an exclusive thread can be used off the main thread
892 // or outside of PJS. We don't keep track of which thread owns such zones
893 // though, so this check is imperfect.
894 return zone->usedByExclusiveThread;
895 }
897 #else // JS_THREADSAFE
899 bool
900 js::CurrentThreadCanAccessRuntime(JSRuntime *rt)
901 {
902 return true;
903 }
905 bool
906 js::CurrentThreadCanAccessZone(Zone *zone)
907 {
908 return true;
909 }
911 #endif // JS_THREADSAFE
913 #ifdef DEBUG
915 void
916 JSRuntime::assertCanLock(RuntimeLock which)
917 {
918 #ifdef JS_THREADSAFE
919 // In the switch below, each case falls through to the one below it. None
920 // of the runtime locks are reentrant, and when multiple locks are acquired
921 // it must be done in the order below.
922 switch (which) {
923 case ExclusiveAccessLock:
924 JS_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread());
925 case WorkerThreadStateLock:
926 JS_ASSERT(!WorkerThreadState().isLocked());
927 case InterruptLock:
928 JS_ASSERT(!currentThreadOwnsInterruptLock());
929 case GCLock:
930 JS_ASSERT(gcLockOwner != PR_GetCurrentThread());
931 break;
932 default:
933 MOZ_CRASH();
934 }
935 #endif // JS_THREADSAFE
936 }
938 void
939 js::AssertCurrentThreadCanLock(RuntimeLock which)
940 {
941 #ifdef JS_THREADSAFE
942 PerThreadData *pt = TlsPerThreadData.get();
943 if (pt && pt->runtime_)
944 pt->runtime_->assertCanLock(which);
945 #endif
946 }
948 #endif // DEBUG