Files
palemoon27/js/src/vm/Runtime.cpp
T
roytam1 a51002fbca import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1202386: Add logging macros for HAL IPC, r=shuang (246eb96f38)
- Bug 1202386: Output clear HAL IPC errors, r=shuang (eaba0dc9a8)
- Bug 1202704: Move Bluetooth IPC pack functions to generic HAL IPC, r=shuang (4c745de79c)
- Bug 1202704: Move Bluetooth IPC unpack functions to generic HAL IPC, r=shuang (4f8600030b)
- Bug 1202704: Move Bluetooth's |UnpackPDUInitOp| to generic HAL IPC code, r=shuang (345f21c637)
- Bug 1209085: Add 6-argument operator () to |UnpackPDUInitOp|, r=joliu (f5f8cf2dd9)
- Bug 1123760 - make autocomplete dropmarker in the urlbar actually work when activated through a11y APIs, r=surkov (eee42195f4)
- Bug 1123760 - bustage follow-up: remove unused variable, rs=bustage on a CLOSED TREE (6de8519b23)
- Bug 1152836 - QR Decoder: Let everywhere, style nits: 580ms -> 400ms r=past (92a7fd6a15)
- Bug 1212430 - Remove CrashAtUnhandlableOOM() and replace with AutoEnterOOMUnsafeRegion r=jandem (f595b87951)
- Bug 1175755 - Only clear GC statistics aborted flag at the end of the outermost nested GC r=bbouvier (ca73f34c69)
- reapply  Bug 1221385 - Handle OOM during JitRuntime (e7def65b78)
- No bug: Clarify documentation for js::NewObjectMetadataState. DONTBUILD r=fitzgen (41022b4137)
- Bug 1211164 - Collect JS deprecated language extension telemetry for Add-ons. r=till,bsmedberg (eacd40ad66)
- Bug 1212296 - undo a state change on OOM. r=till (6e272353d0)
- Bug 1214006 - Take account of the fact that JSScript::atoms may be null while tracing r=terrence (19f61d7494)
- missing bits of Bug 1208665 (c31173b0d4)
- Bug 1221891 - "Fix a typo in TraceLoggingGraph.h". r=hv1989 (e1fc11f8df)
- Bug 1221460 - "TraceLogger: Enable several new optimizations in 'TLLOG=IonCompiler'". r=hv1989 (ab3398646e)
- Bug 1204365 - Repair external view source file name and extension. r=mconley (f033e55a0e)
- Bug 1163693 - Fix View Source external editor fallback. r=jryans. (9c8becc93b)
- Bug 1207629 - Don't assume that viewSourceUtils.js has Services in scope. r=jryans (07977953c0)
- add back some telemetry (1e3b5bde5b)
- Bug 1186785 - Replace nsBaseHashtable::EnumerateRead() calls in toolkit/ with iterators. r=froydnj. (e93e098dd8)
- add back some crashreporter (80e325b3be)
- Bug 1220035 - Fix -Wimplicit-fallthrough warnings in xpcom. r=mccr8 (2ef9ecad5f)
- Bug 1215629 - Remove nsDebug logger. r=froydnj (46784f05fd)
- Bug 1137963 - Use a spin lock for TraceRefCnt. r=waldo, r=froydnj (b2420c97c0)
- Bug 1196430 - part 1 - rename serialNumberRecord to SerialNumberRecord; r=mccr8 (933670070d)
- Bug 1196430 - part 2 - give SerialNumberRecord a proper constructor; r=mccr8 (3ddf3d5e69)
- Bug 1196430 - part 3 - remove unnecessary nsString.h include from nsTraceRefcnt.cpp; r=mccr8 (034954e692)
- Bug 1196430 - part 4 - record allocation stacks for classes in XPCOM_MEM_LOG_CLASSES; r=mccr8 (366b612807)
- Bug 1196430 - part 5 - dump allocation stacks for leaked objects in XPCOM_MEM_LOG_CLASSES; r=mccr8 (dce7b9cca2)
- Bug 1180745 - Fix logging test screenshotting errors. r=jgriffin (a589f0d322)
- Bug 1091285 - move dumpScreen in a new mozscreenshot package. r=jgriffin This also completely remove build/automationutils.py. (6e633359ef)
- some crashreporter stuff (2d0bc9c95d)
- Bug 1196430 - part 6 - move cut-and-paste stack fixer code into mozrunner; r=wlach (ffc7ccd521)
- Bug 1196430 - part 7 - teach process_leak_log how to symbolicate leaked object stacks; r=mccr8 (0b5a4ace7c)
- Bug 1196430 - part 8 - use less reinterpret_cast in nsTraceRefcnt.cpp; r=mccr8 (758cfca0aa)
- Bug 1196430 follow-up: Hide the usage of gCodeAddressService behind #ifdef MOZ_STACKWALKING (e8d62dd73e)
- Bug 487494 - Add an xpcshell selftest for readable stacks from assertions.;r=ted (ea15cf3cbb)
- Bug 1156977 - Assert when aClassName is empty in BloatEntry. r=froydnj Bug 1116550 - Part 1: Turn HaveLeaks and Clear into methods. r=froydnj (8d7f88f498)
- Bug 1116550 - Part 2: Print out negative values for leaks when there are more dtors than ctors. r=froydnj (7c9e3e7848)
- Bug 1190483 - Add a way to record a DMD log late in shutdown. r=erahm (df7c22e64d)
- Bug 1174344 - make error message for mismatched leak log entries more helpful; r=mccr8 (7f969e72c0)
- Bug 1190483 - Followup to address review comment. (d3873f76fd)
- Bug 1186025. Optimize the usage of regions. r=mstange (263080a66e)
- Bug 1211841 - Style off the main thread markers differently, r=jsantell (1a183c5d3e)
- Bug 1211839 - Don't allow off the main thread markers to nest under main thread markers, r=smaug, jsantell (f4d4b7ccf1)
- Bug 1207161 - fix run-by-dir leak in test_bug846906.xul; r=mccr8 (5511752103)
- Bug 1205348 - Always do shutdown CCs when NS_FREE_PERMANENT_DATA is defined. r=smaug (7fd7a7455c)
- Bug 1208157, part 1 - Add and use nsCycleCollector::IsIdle() predicate. r=smaug (a06c2bd1db)
- Bug 1208157, part 2 - Make the fields of nsCycleCollector private. r=smaug (494637fbef)
- Bug 1207368 - Use swap() instead of forget() to remove MessageElement::mMessage. r=froydnj (8c58d38a55)
- Bug 1181520 - Remove support for passing in reftest arguments via the command line, r=jmaher (75e9440e40)
- Bug 1196814 - Fail Android mochitest, robocop, reftests when Fennec is not installed; r=jmaher (6ec15636eb)
- Bug 1183717 - Increase default timeout for Android Debug reftests; r=jmaher (1b07fc1c9b)
- Bug 1181516 - Allow reftests to take paths to multiple directories containing tests on the command line, r=jmaher (1e27ef0d69)
- Bug 1198944 - remove vmware recording support from mochitest; r=khuey (06e79556fb)
- Bug 1162003 - Enable run-by-dir mode on Fx desktop opt builds. r=jmaher (0ef288a33c)
- Bug 1087629 - Add two new test cases for ICE connection states. r=ekr (374112f2d0)
- Bug 1186551 - [mozlog] add structured action process_start/process_exit. r=jgraham (13ce88dbf7)
- Bug 1154111 - Colorize SKIP in test logs. r=jgraham (85910e0f8b)
- Bug 1191267 - Fix mozlog log buffering command line option, r=chmanchester (2bd6592f9b)
- Bug 1185244 - Improve mach support for running mochitests on Valgrind. r=jgraham, njn. (7f5a830fa0)
- Bug 1219870 - [mozlog] ensure correct suite state when logging suite_start/suite_end via StructuredLogger.log_raw, r=chmanchester (21710387a4)
- Bug 1198257 - Better support for providing a directory name and discovering reftests under that directory, r=jmaher (f6255fc44c)
- Bug 1208220 - Remove test of manifest filename that breaks my workflow. r=jgraham (ae4e45946d)
- Bug 1186888 - [mozlog] Ability to use a pre-existing logger with commandline.setup_logging(), r=jgraham (80dfa2a8a8)
- Bug 1042998 - Use StructuredLog.jsm for mochitest logging, r=chmanchester (8851b1b6f9)
- Bug 1218010 - Shorten the polling interval when waiting for httpd.js startup in mochitest. r=ahal (a1f2c81a8e)
- Bug 1224305 - Add an option to the mochitest harness to provide a copy of the extra chrome manifest it writes. r=ahal (e617971f41)
- Bug 1170342 - Don't disable XInput2 for mochitests on GTK3, off by default now. r=karlt (05d53439da)
- Bug 1145375 - Don't kill the debugger if the user Ctrl-C's as running a mochitest; r=ted (6c310500b8)
- Bug 1199241 - Average runtime data across platforms instead of keeping it distinct, r=jgriffin (cd497f509c)
- Bug 1157852 - Mochitest DevTools test directories run multiple times. r=ahal (415ab41a3a)
- Bug 1186791 (part 1) - Replace nsBaseHashtable::EnumerateRead() calls in storage/ with iterators. r=mak. (84f6f1f566)
- Bug 1186791 (part 2) - Replace nsBaseHashtable::EnumerateRead() calls in storage/ with iterators. r=mak. (9c67504d0c)
- Bug 1186791 (part 3) - Replace nsBaseHashtable::EnumerateRead() calls in storage/ with iterators. r=mak. (02f472c197)
- Bug 1219238 - remove AutoArray from mozStorageSQLFunctions.cpp; r=mak (45e751d2b7)
- Bug 1166931 - JS Warning in MobileIdentityManager.jsm r=ferjm (2022d4cccd)
- var-const (b7800ec532)
- Trivial, no bug: add missing semicolon to nsBlocklistService.js to avoid a strict warning. (ee6b8a7593)
- Bug 1208242 - Part 1: hook up the blocklist service to b2g web extensions r=mossop,ferjm (d0ad653af4)
- Bug 1208242 - Part 3: don't ship things that should not ship r=me (cd75e88080)
- Bug 1009795 - Use toLocalString to format download size instead of the decimalSymbol hook; r=mak (a4b4442d2c)
- Bug 1009795 - Part 2: Revert to the old gDecimalSymbol hack if the Internationalization API is not available; r=mak (465e23f2c3)
- Bug 1116385. r=Mossop (f0a7b7d450)
- let-var (cb5d9d1d07)
- Bug 1210459: Add originAttributes for tests that implement nsILoadContext. r=bholley (ea6be1490a)
- var-let (d7d4533b53)
- Bug 1034724 - Fixed Unicode values of prefs in about:support. r=adw (1c8253ac5b)
- Bug 1153381. Add a D3D11 ANGLE blacklist. r=mstange (9008483ca5)
- add back some WIn XP and 2k3 stuff (896a4a7e9b)
- Bug 1141783 - Correct user message for mismatched drivers. Don't mismatch if the DLLs are missing. r=jrmuizelaar (872d0c3aff)
- missing members version (4771ff5f24)
- bug 1170987 - Fix gfx/2d to build on iOS. r=jrmuizel (1e555cb6b3)
- Bug 1201937 - push transform onto cairo context when evaluating path bounds. r=eihrul (6a4d8d98ec)
- Bug 1165900 - Make MaybeSnapToDevicePixels return a boolean to indicate whether snapping occurred. r=Bas (8f33f6cf7d)
- Bug 1190705 - Add crashtest for canvas 2d. r=Bas (bf3afb2acc)
- Bug 1161277 - verify SkPath is finite before doing ContainsPoint queries. r=jmuizelaar (c56f9ef322)
- Bug 1218900 - Make shell function startTimingMutator() fail with an error rather than asserting when called at the wrong time r=sfink (856e8678ce)
- small type fix (b36cfdf416)
- Bug 1214846 - Make SPSProfiler::enter() report OOM to the context r=terrence (6086f60d17)
- Bug 1218637 - IonMonkey: MIPS64: Add support into vm. r=arai (ae22538418)
- gfx: add back `AddCrashReportAnnotations()` prototype (c13f61cd8a)
2022-12-29 09:22:12 +08:00

882 lines
24 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "vm/Runtime-inl.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Atomics.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/ThreadLocal.h"
#if defined(XP_DARWIN)
#include <mach/mach.h>
#elif defined(XP_UNIX)
#include <sys/resource.h>
#elif defined(XP_WIN)
#include <processthreadsapi.h>
#include <windows.h>
#endif // defined(XP_DARWIN) || defined(XP_UNIX) || defined(XP_WIN)
#include <locale.h>
#include <string.h>
#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES
# include <sys/mman.h>
#endif
#include "jsatom.h"
#include "jsdtoa.h"
#include "jsgc.h"
#include "jsmath.h"
#include "jsnativestack.h"
#include "jsobj.h"
#include "jsscript.h"
#include "jswatchpoint.h"
#include "jswin.h"
#include "jswrapper.h"
#include "asmjs/AsmJSSignalHandlers.h"
#include "jit/arm/Simulator-arm.h"
#include "jit/arm64/vixl/Simulator-vixl.h"
#include "jit/JitCompartment.h"
#include "jit/mips32/Simulator-mips32.h"
#include "jit/mips64/Simulator-mips64.h"
#include "jit/PcScriptCache.h"
#include "js/Date.h"
#include "js/MemoryMetrics.h"
#include "js/SliceBudget.h"
#include "vm/Debugger.h"
#include "jscntxtinlines.h"
#include "jsgcinlines.h"
using namespace js;
using namespace js::gc;
using mozilla::Atomic;
using mozilla::DebugOnly;
using mozilla::NegativeInfinity;
using mozilla::PodZero;
using mozilla::PodArrayZero;
using mozilla::PositiveInfinity;
using mozilla::ThreadLocal;
using JS::GenericNaN;
using JS::DoubleNaNValue;
/* static */ ThreadLocal<PerThreadData*> js::TlsPerThreadData;
/* static */ Atomic<size_t> JSRuntime::liveRuntimesCount;
namespace js {
bool gCanUseExtraThreads = true;
} // namespace js
void
js::DisableExtraThreads()
{
gCanUseExtraThreads = false;
}
const JSSecurityCallbacks js::NullSecurityCallbacks = { };
PerThreadData::PerThreadData(JSRuntime* runtime)
: PerThreadDataFriendFields(),
runtime_(runtime),
#ifdef JS_TRACE_LOGGING
traceLogger(nullptr),
#endif
autoFlushICache_(nullptr),
dtoaState(nullptr),
suppressGC(0),
#ifdef DEBUG
ionCompiling(false),
ionCompilingSafeForMinorGC(false),
gcSweeping(false),
#endif
activeCompilations(0)
{}
PerThreadData::~PerThreadData()
{
if (dtoaState)
DestroyDtoaState(dtoaState);
}
bool
PerThreadData::init()
{
dtoaState = NewDtoaState();
if (!dtoaState)
return false;
return true;
}
static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = {
TransparentObjectWrapper,
nullptr
};
static size_t
ReturnZeroSize(const void* p)
{
return 0;
}
JSRuntime::JSRuntime(JSRuntime* parentRuntime)
: mainThread(this),
jitTop(nullptr),
jitJSContext(nullptr),
jitActivation(nullptr),
jitStackLimit_(0xbad),
jitStackLimitNoInterrupt_(0xbad),
activation_(nullptr),
profilingActivation_(nullptr),
profilerSampleBufferGen_(0),
profilerSampleBufferLapCount_(1),
asmJSActivationStack_(nullptr),
asyncStackForNewActivations(this),
asyncCauseForNewActivations(this),
asyncCallIsExplicit(false),
entryMonitor(nullptr),
parentRuntime(parentRuntime),
interrupt_(false),
handlingSignal(false),
interruptCallback(nullptr),
exclusiveAccessLock(nullptr),
exclusiveAccessOwner(nullptr),
mainThreadHasExclusiveAccess(false),
numExclusiveThreads(0),
numCompartments(0),
localeCallbacks(nullptr),
defaultLocale(nullptr),
defaultVersion_(JSVERSION_DEFAULT),
ownerThread_(nullptr),
ownerThreadNative_(0),
tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
jitRuntime_(nullptr),
selfHostingGlobal_(nullptr),
nativeStackBase(GetNativeStackBase()),
cxCallback(nullptr),
destroyCompartmentCallback(nullptr),
destroyZoneCallback(nullptr),
sweepZoneCallback(nullptr),
compartmentNameCallback(nullptr),
activityCallback(nullptr),
activityCallbackArg(nullptr),
requestDepth(0),
#ifdef DEBUG
checkRequestDepth(0),
activeContext(nullptr),
#endif
gc(thisFromCtor()),
gcInitialized(false),
#ifdef JS_SIMULATOR
simulator_(nullptr),
#endif
scriptAndCountsVector(nullptr),
lcovOutput(),
NaNValue(DoubleNaNValue()),
negativeInfinityValue(DoubleValue(NegativeInfinity<double>())),
positiveInfinityValue(DoubleValue(PositiveInfinity<double>())),
emptyString(nullptr),
spsProfiler(thisFromCtor()),
profilingScripts(false),
suppressProfilerSampling(false),
hadOutOfMemory(false),
handlingInitFailure(false),
haveCreatedContext(false),
allowRelazificationForTesting(false),
data(nullptr),
signalHandlersInstalled_(false),
canUseSignalHandlers_(false),
defaultFreeOp_(thisFromCtor()),
debuggerMutations(0),
securityCallbacks(const_cast<JSSecurityCallbacks*>(&NullSecurityCallbacks)),
DOMcallbacks(nullptr),
destroyPrincipals(nullptr),
readPrincipals(nullptr),
errorReporter(nullptr),
linkedAsmJSModules(nullptr),
propertyRemovals(0),
#if !EXPOSE_INTL_API
thousandsSeparator(0),
decimalSeparator(0),
numGrouping(0),
#endif
mathCache_(nullptr),
activeCompilations_(0),
keepAtoms_(0),
trustedPrincipals_(nullptr),
beingDestroyed_(false),
atoms_(nullptr),
atomsCompartment_(nullptr),
staticStrings(nullptr),
commonNames(nullptr),
permanentAtoms(nullptr),
wellKnownSymbols(nullptr),
wrapObjectCallbacks(&DefaultWrapObjectCallbacks),
preserveWrapperCallback(nullptr),
jitSupportsFloatingPoint(false),
jitSupportsSimd(false),
ionPcScriptCache(nullptr),
scriptEnvironmentPreparer(nullptr),
ctypesActivityCallback(nullptr),
windowProxyClass_(nullptr),
offthreadIonCompilationEnabled_(true),
parallelParsingEnabled_(true),
autoWritableJitCodeActive_(false),
#ifdef DEBUG
enteredPolicy(nullptr),
#endif
largeAllocationFailureCallback(nullptr),
oomCallback(nullptr),
debuggerMallocSizeOf(ReturnZeroSize),
lastAnimationTime(0),
performanceMonitoring(thisFromCtor())
{
setGCStoreBufferPtr(&gc.storeBuffer);
liveRuntimesCount++;
/* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */
JS_INIT_CLIST(&onNewGlobalObjectWatchers);
PodArrayZero(nativeStackQuota);
PodZero(&asmJSCacheOps);
lcovOutput.init();
}
static bool
SignalBasedTriggersDisabled()
{
// Don't bother trying to cache the getenv lookup; this should be called
// infrequently.
return !!getenv("JS_DISABLE_SLOW_SCRIPT_SIGNALS") || !!getenv("JS_NO_SIGNALS");
}
bool
JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
{
ownerThread_ = PR_GetCurrentThread();
// Get a platform-native handle for the owner thread, used by
// js::InterruptRunningJitCode to halt the runtime's main thread.
#ifdef XP_WIN
size_t openFlags = THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME |
THREAD_QUERY_INFORMATION;
HANDLE self = OpenThread(openFlags, false, GetCurrentThreadId());
if (!self)
return false;
static_assert(sizeof(HANDLE) <= sizeof(ownerThreadNative_), "need bigger field");
ownerThreadNative_ = (size_t)self;
#else
static_assert(sizeof(pthread_t) <= sizeof(ownerThreadNative_), "need bigger field");
ownerThreadNative_ = (size_t)pthread_self();
#endif
exclusiveAccessLock = PR_NewLock();
if (!exclusiveAccessLock)
return false;
if (!mainThread.init())
return false;
if (!regexpStack.init())
return false;
if (CanUseExtraThreads() && !EnsureHelperThreadsInitialized())
return false;
js::TlsPerThreadData.set(&mainThread);
if (!gc.init(maxbytes, maxNurseryBytes))
return false;
ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this));
if (!atomsZone || !atomsZone->init(true))
return false;
JS::CompartmentOptions options;
ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options));
if (!atomsCompartment || !atomsCompartment->init(nullptr))
return false;
if (!gc.zones.append(atomsZone.get()))
return false;
if (!atomsZone->compartments.append(atomsCompartment.get()))
return false;
atomsCompartment->setIsSystem(true);
atomsZone.forget();
this->atomsCompartment_ = atomsCompartment.forget();
if (!symbolRegistry_.init())
return false;
if (!scriptDataTable_.init())
return false;
if (!evalCache.init())
return false;
if (!compressedSourceSet.init())
return false;
/* The garbage collector depends on everything before this point being initialized. */
gcInitialized = true;
if (!InitRuntimeNumberState(this))
return false;
JS::ResetTimeZone();
#ifdef JS_SIMULATOR
simulator_ = js::jit::Simulator::Create();
if (!simulator_)
return false;
#endif
jitSupportsFloatingPoint = js::jit::JitSupportsFloatingPoint();
jitSupportsSimd = js::jit::JitSupportsSimd();
signalHandlersInstalled_ = EnsureSignalHandlersInstalled(this);
canUseSignalHandlers_ = signalHandlersInstalled_ && !SignalBasedTriggersDisabled();
if (!spsProfiler.init())
return false;
if (!fx.initInstance())
return false;
return true;
}
JSRuntime::~JSRuntime()
{
MOZ_ASSERT(!isHeapBusy());
fx.destroyInstance();
if (gcInitialized) {
/* Free source hook early, as its destructor may want to delete roots. */
sourceHook = nullptr;
/*
* Cancel any pending, in progress or completed Ion compilations and
* parse tasks. Waiting for AsmJS and compression tasks is done
* synchronously (on the main thread or during parse tasks), so no
* explicit canceling is needed for these.
*/
for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next())
CancelOffThreadIonCompile(comp, nullptr);
CancelOffThreadParses(this);
/* Clear debugging state to remove GC roots. */
for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next()) {
if (WatchpointMap* wpmap = comp->watchpointMap)
wpmap->clear();
}
/*
* Clear script counts map, to remove the strong reference on the
* JSScript key.
*/
for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next())
comp->clearScriptCounts();
/* Clear atoms to remove GC roots and heap allocations. */
finishAtoms();
/* Remove persistent GC roots. */
gc.finishRoots();
/*
* Flag us as being destroyed. This allows the GC to free things like
* interned atoms and Ion trampolines.
*/
beingDestroyed_ = true;
/* Allow the GC to release scripts that were being profiled. */
profilingScripts = false;
/* Set the profiler sampler buffer generation to invalid. */
profilerSampleBufferGen_ = UINT32_MAX;
JS::PrepareForFullGC(this);
gc.gc(GC_NORMAL, JS::gcreason::DESTROY_RUNTIME);
}
/*
* Clear the self-hosted global and delete self-hosted classes *after*
* GC, as finalizers for objects check for clasp->finalize during GC.
*/
finishSelfHosting();
MOZ_ASSERT(!exclusiveAccessOwner);
if (exclusiveAccessLock)
PR_DestroyLock(exclusiveAccessLock);
// Avoid bogus asserts during teardown.
MOZ_ASSERT(!numExclusiveThreads);
mainThreadHasExclusiveAccess = true;
/*
* Even though all objects in the compartment are dead, we may have keep
* some filenames around because of gcKeepAtoms.
*/
FreeScriptData(this);
#ifdef DEBUG
/* Don't hurt everyone in leaky ol' Mozilla with a fatal MOZ_ASSERT! */
if (hasContexts()) {
unsigned cxcount = 0;
for (ContextIter acx(this); !acx.done(); acx.next()) {
fprintf(stderr,
"JS API usage error: found live context at %p\n",
(void*) acx.get());
cxcount++;
}
fprintf(stderr,
"JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n",
cxcount, (cxcount == 1) ? "" : "s");
}
#endif
#if !EXPOSE_INTL_API
FinishRuntimeNumberState(this);
#endif
gc.finish();
atomsCompartment_ = nullptr;
js_free(defaultLocale);
js_delete(mathCache_);
js_delete(jitRuntime_);
js_delete(ionPcScriptCache);
gc.storeBuffer.disable();
gc.nursery.disable();
#ifdef JS_SIMULATOR
js::jit::Simulator::Destroy(simulator_);
#endif
DebugOnly<size_t> oldCount = liveRuntimesCount--;
MOZ_ASSERT(oldCount > 0);
js::TlsPerThreadData.set(nullptr);
#ifdef XP_WIN
if (ownerThreadNative_)
CloseHandle((HANDLE)ownerThreadNative_);
#endif
}
void
NewObjectCache::clearNurseryObjects(JSRuntime* rt)
{
for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) {
Entry& e = entries[i];
NativeObject* obj = reinterpret_cast<NativeObject*>(&e.templateObject);
if (IsInsideNursery(e.key) ||
rt->gc.nursery.isInside(obj->slots_) ||
rt->gc.nursery.isInside(obj->elements_))
{
PodZero(&e);
}
}
}
void
JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes* rtSizes)
{
// Several tables in the runtime enumerated below can be used off thread.
AutoLockForExclusiveAccess lock(this);
rtSizes->object += mallocSizeOf(this);
rtSizes->atomsTable += atoms().sizeOfIncludingThis(mallocSizeOf);
if (!parentRuntime) {
rtSizes->atomsTable += mallocSizeOf(staticStrings);
rtSizes->atomsTable += mallocSizeOf(commonNames);
rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf);
}
for (ContextIter acx(this); !acx.done(); acx.next())
rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf);
rtSizes->dtoa += mallocSizeOf(mainThread.dtoaState);
rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf);
rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0;
rtSizes->uncompressedSourceCache += uncompressedSourceCache.sizeOfExcludingThis(mallocSizeOf);
rtSizes->compressedSourceSet += compressedSourceSet.sizeOfExcludingThis(mallocSizeOf);
rtSizes->scriptData += scriptDataTable().sizeOfExcludingThis(mallocSizeOf);
for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront())
rtSizes->scriptData += mallocSizeOf(r.front());
if (jitRuntime_)
jitRuntime_->execAlloc().addSizeOfCode(&rtSizes->code);
rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf);
rtSizes->gc.nurseryCommitted += gc.nursery.sizeOfHeapCommitted();
rtSizes->gc.nurseryDecommitted += gc.nursery.sizeOfHeapDecommitted();
rtSizes->gc.nurseryMallocedBuffers += gc.nursery.sizeOfMallocedBuffers(mallocSizeOf);
gc.storeBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc);
}
static bool
InvokeInterruptCallback(JSContext* cx)
{
MOZ_ASSERT(cx->runtime()->requestDepth >= 1);
cx->runtime()->gc.gcIfRequested();
// A worker thread may have requested an interrupt after finishing an Ion
// compilation.
jit::AttachFinishedCompilations(cx);
// Important: Additional callbacks can occur inside the callback handler
// if it re-enters the JS engine. The embedding must ensure that the
// callback is disconnected before attempting such re-entry.
JSInterruptCallback cb = cx->runtime()->interruptCallback;
if (!cb)
return true;
if (cb(cx)) {
// Debugger treats invoking the interrupt callback as a "step", so
// invoke the onStep handler.
if (cx->compartment()->isDebuggee()) {
ScriptFrameIter iter(cx);
if (iter.script()->stepModeEnabled()) {
RootedValue rval(cx);
switch (Debugger::onSingleStep(cx, &rval)) {
case JSTRAP_ERROR:
return false;
case JSTRAP_CONTINUE:
return true;
case JSTRAP_RETURN:
// See note in Debugger::propagateForcedReturn.
Debugger::propagateForcedReturn(cx, iter.abstractFramePtr(), rval);
return false;
case JSTRAP_THROW:
cx->setPendingException(rval);
return false;
default:;
}
}
}
return true;
}
// No need to set aside any pending exception here: ComputeStackString
// already does that.
JSString* stack = ComputeStackString(cx);
JSFlatString* flat = stack ? stack->ensureFlat(cx) : nullptr;
const char16_t* chars;
AutoStableStringChars stableChars(cx);
if (flat && stableChars.initTwoByte(cx, flat))
chars = stableChars.twoByteRange().start().get();
else
chars = MOZ_UTF16("(stack not available)");
JS_ReportErrorFlagsAndNumberUC(cx, JSREPORT_WARNING, GetErrorMessage, nullptr,
JSMSG_TERMINATED, chars);
return false;
}
void
JSRuntime::resetJitStackLimit()
{
// Note that, for now, we use the untrusted limit for ion. This is fine,
// because it's the most conservative limit, and if we hit it, we'll bail
// out of ion into the interpreter, which will do a proper recursion check.
#ifdef JS_SIMULATOR
jitStackLimit_ = jit::Simulator::StackLimit();
#else
jitStackLimit_ = mainThread.nativeStackLimit[StackForUntrustedScript];
#endif
jitStackLimitNoInterrupt_ = jitStackLimit_;
}
void
JSRuntime::initJitStackLimit()
{
resetJitStackLimit();
}
void
JSRuntime::requestInterrupt(InterruptMode mode)
{
interrupt_ = true;
jitStackLimit_ = UINTPTR_MAX;
if (mode == JSRuntime::RequestInterruptUrgent) {
// If this interrupt is urgent (slow script dialog and garbage
// collection among others), take additional steps to
// interrupt corner cases where the above fields are not
// regularly polled. Wake both ilooping JIT code and
// futexWait.
fx.lock();
if (fx.isWaiting())
fx.wake(FutexRuntime::WakeForJSInterrupt);
fx.unlock();
InterruptRunningJitCode(this);
}
}
bool
JSRuntime::handleInterrupt(JSContext* cx)
{
MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
if (interrupt_ || jitStackLimit_ == UINTPTR_MAX) {
interrupt_ = false;
resetJitStackLimit();
return InvokeInterruptCallback(cx);
}
return true;
}
MathCache*
JSRuntime::createMathCache(JSContext* cx)
{
MOZ_ASSERT(!mathCache_);
MOZ_ASSERT(cx->runtime() == this);
MathCache* newMathCache = js_new<MathCache>();
if (!newMathCache) {
ReportOutOfMemory(cx);
return nullptr;
}
mathCache_ = newMathCache;
return mathCache_;
}
bool
JSRuntime::setDefaultLocale(const char* locale)
{
if (!locale)
return false;
resetDefaultLocale();
defaultLocale = JS_strdup(this, locale);
return defaultLocale != nullptr;
}
void
JSRuntime::resetDefaultLocale()
{
js_free(defaultLocale);
defaultLocale = nullptr;
}
const char*
JSRuntime::getDefaultLocale()
{
if (defaultLocale)
return defaultLocale;
char* locale;
char* lang;
char* p;
#ifdef HAVE_SETLOCALE
locale = setlocale(LC_ALL, nullptr);
#else
locale = getenv("LANG");
#endif
// convert to a well-formed BCP 47 language tag
if (!locale || !strcmp(locale, "C"))
locale = const_cast<char*>("und");
lang = JS_strdup(this, locale);
if (!lang)
return nullptr;
if ((p = strchr(lang, '.')))
*p = '\0';
while ((p = strchr(lang, '_')))
*p = '-';
defaultLocale = lang;
return defaultLocale;
}
void
JSRuntime::triggerActivityCallback(bool active)
{
if (!activityCallback)
return;
/*
* The activity callback must not trigger a GC: it would create a cirular
* dependency between entering a request and Rooted's requirement of being
* in a request. In practice this callback already cannot trigger GC. The
* suppression serves to inform the exact rooting hazard analysis of this
* property and ensures that it remains true in the future.
*/
AutoSuppressGC suppress(this);
activityCallback(activityCallbackArg, active);
}
void
JSRuntime::updateMallocCounter(size_t nbytes)
{
updateMallocCounter(nullptr, nbytes);
}
void
JSRuntime::updateMallocCounter(JS::Zone* zone, size_t nbytes)
{
gc.updateMallocCounter(zone, nbytes);
}
JS_FRIEND_API(void*)
JSRuntime::onOutOfMemory(AllocFunction allocFunc, size_t nbytes, void* reallocPtr,
JSContext* maybecx)
{
MOZ_ASSERT_IF(allocFunc != AllocFunction::Realloc, !reallocPtr);
MOZ_ASSERT(CurrentThreadCanAccessRuntime(this));
if (isHeapBusy())
return nullptr;
if (!oom::IsSimulatedOOMAllocation()) {
/*
* Retry when we are done with the background sweeping and have stopped
* all the allocations and released the empty GC chunks.
*/
gc.onOutOfMallocMemory();
void* p;
switch (allocFunc) {
case AllocFunction::Malloc:
p = js_malloc(nbytes);
break;
case AllocFunction::Calloc:
p = js_calloc(nbytes);
break;
case AllocFunction::Realloc:
p = js_realloc(reallocPtr, nbytes);
break;
default:
MOZ_CRASH();
}
if (p)
return p;
}
if (maybecx)
ReportOutOfMemory(maybecx);
return nullptr;
}
void*
JSRuntime::onOutOfMemoryCanGC(AllocFunction allocFunc, size_t bytes, void* reallocPtr)
{
if (largeAllocationFailureCallback && bytes >= LARGE_ALLOCATION)
largeAllocationFailureCallback(largeAllocationFailureCallbackData);
return onOutOfMemory(allocFunc, bytes, reallocPtr);
}
bool
JSRuntime::activeGCInAtomsZone()
{
Zone* zone = atomsCompartment_->zone();
return zone->needsIncrementalBarrier() || zone->isGCScheduled() || zone->wasGCStarted();
}
void
JSRuntime::setUsedByExclusiveThread(Zone* zone)
{
MOZ_ASSERT(!zone->usedByExclusiveThread);
zone->usedByExclusiveThread = true;
numExclusiveThreads++;
}
void
JSRuntime::clearUsedByExclusiveThread(Zone* zone)
{
MOZ_ASSERT(zone->usedByExclusiveThread);
zone->usedByExclusiveThread = false;
numExclusiveThreads--;
if (gc.fullGCForAtomsRequested() && !keepAtoms())
gc.triggerFullGCForAtoms();
}
bool
js::CurrentThreadCanAccessRuntime(JSRuntime* rt)
{
return rt->ownerThread_ == PR_GetCurrentThread();
}
bool
js::CurrentThreadCanAccessZone(Zone* zone)
{
if (CurrentThreadCanAccessRuntime(zone->runtime_))
return true;
// Only zones in use by an exclusive thread can be used off the main thread.
// We don't keep track of which thread owns such zones though, so this check
// is imperfect.
return zone->usedByExclusiveThread;
}
#ifdef DEBUG
void
JSRuntime::assertCanLock(RuntimeLock which)
{
// In the switch below, each case falls through to the one below it. None
// of the runtime locks are reentrant, and when multiple locks are acquired
// it must be done in the order below.
switch (which) {
case ExclusiveAccessLock:
MOZ_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread());
case HelperThreadStateLock:
MOZ_ASSERT(!HelperThreadState().isLocked());
case GCLock:
gc.assertCanLock();
break;
default:
MOZ_CRASH();
}
}
void
js::AssertCurrentThreadCanLock(RuntimeLock which)
{
PerThreadData* pt = TlsPerThreadData.get();
if (pt && pt->runtime_)
pt->runtime_->assertCanLock(which);
}
#endif // DEBUG
JS_FRIEND_API(void)
JS::UpdateJSRuntimeProfilerSampleBufferGen(JSRuntime* runtime, uint32_t generation,
uint32_t lapCount)
{
runtime->setProfilerSampleBufferGen(generation);
runtime->updateProfilerSampleBufferLapCount(lapCount);
}
JS_FRIEND_API(bool)
JS::IsProfilingEnabledForRuntime(JSRuntime* runtime)
{
MOZ_ASSERT(runtime);
return runtime->spsProfiler.enabled();
}