js/src/vm/Runtime.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial