1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/Runtime.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,948 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "vm/Runtime-inl.h" 1.11 + 1.12 +#include "mozilla/ArrayUtils.h" 1.13 +#include "mozilla/Atomics.h" 1.14 +#include "mozilla/DebugOnly.h" 1.15 +#include "mozilla/MemoryReporting.h" 1.16 +#include "mozilla/ThreadLocal.h" 1.17 + 1.18 +#include <locale.h> 1.19 +#include <string.h> 1.20 + 1.21 +#ifdef JS_CAN_CHECK_THREADSAFE_ACCESSES 1.22 +# include <sys/mman.h> 1.23 +#endif 1.24 + 1.25 +#include "jsatom.h" 1.26 +#include "jsdtoa.h" 1.27 +#include "jsgc.h" 1.28 +#include "jsmath.h" 1.29 +#include "jsnativestack.h" 1.30 +#include "jsobj.h" 1.31 +#include "jsscript.h" 1.32 +#include "jswatchpoint.h" 1.33 +#include "jswrapper.h" 1.34 + 1.35 +#if defined(JS_ION) 1.36 +# include "assembler/assembler/MacroAssembler.h" 1.37 +#endif 1.38 +#include "jit/arm/Simulator-arm.h" 1.39 +#include "jit/AsmJSSignalHandlers.h" 1.40 +#include "jit/JitCompartment.h" 1.41 +#include "jit/PcScriptCache.h" 1.42 +#include "js/MemoryMetrics.h" 1.43 +#include "js/SliceBudget.h" 1.44 +#include "yarr/BumpPointerAllocator.h" 1.45 + 1.46 +#include "jscntxtinlines.h" 1.47 +#include "jsgcinlines.h" 1.48 + 1.49 +using namespace js; 1.50 +using namespace js::gc; 1.51 + 1.52 +using mozilla::Atomic; 1.53 +using mozilla::DebugOnly; 1.54 +using mozilla::NegativeInfinity; 1.55 +using mozilla::PodZero; 1.56 +using mozilla::PodArrayZero; 1.57 +using mozilla::PositiveInfinity; 1.58 +using mozilla::ThreadLocal; 1.59 +using JS::GenericNaN; 1.60 +using JS::DoubleNaNValue; 1.61 + 1.62 +/* static */ ThreadLocal<PerThreadData*> js::TlsPerThreadData; 1.63 + 1.64 +#ifdef JS_THREADSAFE 1.65 +/* static */ Atomic<size_t> JSRuntime::liveRuntimesCount; 1.66 +#else 1.67 +/* static */ size_t JSRuntime::liveRuntimesCount; 1.68 +#endif 1.69 + 1.70 +const JSSecurityCallbacks js::NullSecurityCallbacks = { }; 1.71 + 1.72 +PerThreadData::PerThreadData(JSRuntime *runtime) 1.73 + : PerThreadDataFriendFields(), 1.74 + runtime_(runtime), 1.75 + ionTop(nullptr), 1.76 + jitJSContext(nullptr), 1.77 + jitStackLimit(0), 1.78 +#ifdef JS_TRACE_LOGGING 1.79 + traceLogger(nullptr), 1.80 +#endif 1.81 + activation_(nullptr), 1.82 + asmJSActivationStack_(nullptr), 1.83 + autoFlushICache_(nullptr), 1.84 +#ifdef JS_ARM_SIMULATOR 1.85 + simulator_(nullptr), 1.86 + simulatorStackLimit_(0), 1.87 +#endif 1.88 + dtoaState(nullptr), 1.89 + suppressGC(0), 1.90 + activeCompilations(0) 1.91 +{} 1.92 + 1.93 +PerThreadData::~PerThreadData() 1.94 +{ 1.95 + if (dtoaState) 1.96 + js_DestroyDtoaState(dtoaState); 1.97 + 1.98 +#ifdef JS_ARM_SIMULATOR 1.99 + js_delete(simulator_); 1.100 +#endif 1.101 +} 1.102 + 1.103 +bool 1.104 +PerThreadData::init() 1.105 +{ 1.106 + dtoaState = js_NewDtoaState(); 1.107 + if (!dtoaState) 1.108 + return false; 1.109 + 1.110 + return true; 1.111 +} 1.112 + 1.113 +static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = { 1.114 + TransparentObjectWrapper, 1.115 + nullptr 1.116 +}; 1.117 + 1.118 +JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThreads) 1.119 + : JS::shadow::Runtime( 1.120 +#ifdef JSGC_GENERATIONAL 1.121 + &gcStoreBuffer 1.122 +#endif 1.123 + ), 1.124 + mainThread(this), 1.125 + parentRuntime(parentRuntime), 1.126 + interrupt(false), 1.127 +#if defined(JS_THREADSAFE) && defined(JS_ION) 1.128 + interruptPar(false), 1.129 +#endif 1.130 + handlingSignal(false), 1.131 + interruptCallback(nullptr), 1.132 +#ifdef JS_THREADSAFE 1.133 + interruptLock(nullptr), 1.134 + interruptLockOwner(nullptr), 1.135 + exclusiveAccessLock(nullptr), 1.136 + exclusiveAccessOwner(nullptr), 1.137 + mainThreadHasExclusiveAccess(false), 1.138 + numExclusiveThreads(0), 1.139 +#else 1.140 + interruptLockTaken(false), 1.141 +#endif 1.142 + systemZone(nullptr), 1.143 + numCompartments(0), 1.144 + localeCallbacks(nullptr), 1.145 + defaultLocale(nullptr), 1.146 + defaultVersion_(JSVERSION_DEFAULT), 1.147 +#ifdef JS_THREADSAFE 1.148 + ownerThread_(nullptr), 1.149 +#endif 1.150 + tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), 1.151 + freeLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), 1.152 + execAlloc_(nullptr), 1.153 + bumpAlloc_(nullptr), 1.154 + jitRuntime_(nullptr), 1.155 + selfHostingGlobal_(nullptr), 1.156 + nativeStackBase(0), 1.157 + cxCallback(nullptr), 1.158 + destroyCompartmentCallback(nullptr), 1.159 + destroyZoneCallback(nullptr), 1.160 + sweepZoneCallback(nullptr), 1.161 + compartmentNameCallback(nullptr), 1.162 + activityCallback(nullptr), 1.163 + activityCallbackArg(nullptr), 1.164 +#ifdef JS_THREADSAFE 1.165 + requestDepth(0), 1.166 +# ifdef DEBUG 1.167 + checkRequestDepth(0), 1.168 +# endif 1.169 +#endif 1.170 +#ifdef DEBUG 1.171 + activeContext(nullptr), 1.172 +#endif 1.173 + gcInitialized(false), 1.174 + gcSystemAvailableChunkListHead(nullptr), 1.175 + gcUserAvailableChunkListHead(nullptr), 1.176 + gcBytes(0), 1.177 + gcMaxBytes(0), 1.178 + gcMaxMallocBytes(0), 1.179 + gcNumArenasFreeCommitted(0), 1.180 + gcMarker(this), 1.181 + gcVerifyPreData(nullptr), 1.182 + gcVerifyPostData(nullptr), 1.183 + gcChunkAllocationSinceLastGC(false), 1.184 + gcNextFullGCTime(0), 1.185 + gcLastGCTime(0), 1.186 + gcJitReleaseTime(0), 1.187 + gcAllocationThreshold(30 * 1024 * 1024), 1.188 + gcHighFrequencyGC(false), 1.189 + gcHighFrequencyTimeThreshold(1000), 1.190 + gcHighFrequencyLowLimitBytes(100 * 1024 * 1024), 1.191 + gcHighFrequencyHighLimitBytes(500 * 1024 * 1024), 1.192 + gcHighFrequencyHeapGrowthMax(3.0), 1.193 + gcHighFrequencyHeapGrowthMin(1.5), 1.194 + gcLowFrequencyHeapGrowth(1.5), 1.195 + gcDynamicHeapGrowth(false), 1.196 + gcDynamicMarkSlice(false), 1.197 + gcDecommitThreshold(32 * 1024 * 1024), 1.198 + gcShouldCleanUpEverything(false), 1.199 + gcGrayBitsValid(false), 1.200 + gcIsNeeded(0), 1.201 + gcStats(thisFromCtor()), 1.202 + gcNumber(0), 1.203 + gcStartNumber(0), 1.204 + gcIsFull(false), 1.205 + gcTriggerReason(JS::gcreason::NO_REASON), 1.206 + gcStrictCompartmentChecking(false), 1.207 +#ifdef DEBUG 1.208 + gcDisableStrictProxyCheckingCount(0), 1.209 +#endif 1.210 + gcIncrementalState(gc::NO_INCREMENTAL), 1.211 + gcLastMarkSlice(false), 1.212 + gcSweepOnBackgroundThread(false), 1.213 + gcFoundBlackGrayEdges(false), 1.214 + gcSweepingZones(nullptr), 1.215 + gcZoneGroupIndex(0), 1.216 + gcZoneGroups(nullptr), 1.217 + gcCurrentZoneGroup(nullptr), 1.218 + gcSweepPhase(0), 1.219 + gcSweepZone(nullptr), 1.220 + gcSweepKindIndex(0), 1.221 + gcAbortSweepAfterCurrentGroup(false), 1.222 + gcArenasAllocatedDuringSweep(nullptr), 1.223 +#ifdef DEBUG 1.224 + gcMarkingValidator(nullptr), 1.225 +#endif 1.226 + gcInterFrameGC(0), 1.227 + gcSliceBudget(SliceBudget::Unlimited), 1.228 + gcIncrementalEnabled(true), 1.229 + gcGenerationalDisabled(0), 1.230 + gcManipulatingDeadZones(false), 1.231 + gcObjectsMarkedInDeadZones(0), 1.232 + gcPoke(false), 1.233 + heapState(Idle), 1.234 +#ifdef JSGC_GENERATIONAL 1.235 + gcNursery(thisFromCtor()), 1.236 + gcStoreBuffer(thisFromCtor(), gcNursery), 1.237 +#endif 1.238 +#ifdef JS_GC_ZEAL 1.239 + gcZeal_(0), 1.240 + gcZealFrequency(0), 1.241 + gcNextScheduled(0), 1.242 + gcDeterministicOnly(false), 1.243 + gcIncrementalLimit(0), 1.244 +#endif 1.245 + gcValidate(true), 1.246 + gcFullCompartmentChecks(false), 1.247 + gcCallback(nullptr), 1.248 + gcSliceCallback(nullptr), 1.249 + gcFinalizeCallback(nullptr), 1.250 + gcMallocBytes(0), 1.251 + gcMallocGCTriggered(false), 1.252 +#ifdef JS_ARM_SIMULATOR 1.253 + simulatorRuntime_(nullptr), 1.254 +#endif 1.255 + scriptAndCountsVector(nullptr), 1.256 + NaNValue(DoubleNaNValue()), 1.257 + negativeInfinityValue(DoubleValue(NegativeInfinity<double>())), 1.258 + positiveInfinityValue(DoubleValue(PositiveInfinity<double>())), 1.259 + emptyString(nullptr), 1.260 + debugMode(false), 1.261 + spsProfiler(thisFromCtor()), 1.262 + profilingScripts(false), 1.263 + alwaysPreserveCode(false), 1.264 + hadOutOfMemory(false), 1.265 + haveCreatedContext(false), 1.266 + data(nullptr), 1.267 + gcLock(nullptr), 1.268 + gcLockOwner(nullptr), 1.269 + gcHelperThread(thisFromCtor()), 1.270 + signalHandlersInstalled_(false), 1.271 + defaultFreeOp_(thisFromCtor(), false), 1.272 + debuggerMutations(0), 1.273 + securityCallbacks(const_cast<JSSecurityCallbacks *>(&NullSecurityCallbacks)), 1.274 + DOMcallbacks(nullptr), 1.275 + destroyPrincipals(nullptr), 1.276 + structuredCloneCallbacks(nullptr), 1.277 + telemetryCallback(nullptr), 1.278 + propertyRemovals(0), 1.279 +#if !EXPOSE_INTL_API 1.280 + thousandsSeparator(0), 1.281 + decimalSeparator(0), 1.282 + numGrouping(0), 1.283 +#endif 1.284 + mathCache_(nullptr), 1.285 + activeCompilations_(0), 1.286 + keepAtoms_(0), 1.287 + trustedPrincipals_(nullptr), 1.288 + beingDestroyed_(false), 1.289 + atoms_(nullptr), 1.290 + atomsCompartment_(nullptr), 1.291 + staticStrings(nullptr), 1.292 + commonNames(nullptr), 1.293 + permanentAtoms(nullptr), 1.294 + wrapObjectCallbacks(&DefaultWrapObjectCallbacks), 1.295 + preserveWrapperCallback(nullptr), 1.296 +#ifdef DEBUG 1.297 + noGCOrAllocationCheck(0), 1.298 +#endif 1.299 + jitSupportsFloatingPoint(false), 1.300 + ionPcScriptCache(nullptr), 1.301 + threadPool(this), 1.302 + defaultJSContextCallback(nullptr), 1.303 + ctypesActivityCallback(nullptr), 1.304 + forkJoinWarmup(0), 1.305 + ionReturnOverride_(MagicValue(JS_ARG_POISON)), 1.306 + useHelperThreads_(useHelperThreads), 1.307 + parallelIonCompilationEnabled_(true), 1.308 + parallelParsingEnabled_(true), 1.309 + isWorkerRuntime_(false), 1.310 +#ifdef DEBUG 1.311 + enteredPolicy(nullptr), 1.312 +#endif 1.313 + largeAllocationFailureCallback(nullptr), 1.314 + oomCallback(nullptr) 1.315 +{ 1.316 + liveRuntimesCount++; 1.317 + 1.318 + setGCMode(JSGC_MODE_GLOBAL); 1.319 + 1.320 + /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ 1.321 + JS_INIT_CLIST(&onNewGlobalObjectWatchers); 1.322 + 1.323 + PodZero(&debugHooks); 1.324 + PodArrayZero(nativeStackQuota); 1.325 + PodZero(&asmJSCacheOps); 1.326 +} 1.327 + 1.328 +static bool 1.329 +JitSupportsFloatingPoint() 1.330 +{ 1.331 +#if defined(JS_ION) 1.332 + if (!JSC::MacroAssembler::supportsFloatingPoint()) 1.333 + return false; 1.334 + 1.335 +#if defined(JS_ION) && WTF_ARM_ARCH_VERSION == 6 1.336 + if (!js::jit::hasVFP()) 1.337 + return false; 1.338 +#endif 1.339 + 1.340 + return true; 1.341 +#else 1.342 + return false; 1.343 +#endif 1.344 +} 1.345 + 1.346 +bool 1.347 +JSRuntime::init(uint32_t maxbytes) 1.348 +{ 1.349 +#ifdef JS_THREADSAFE 1.350 + ownerThread_ = PR_GetCurrentThread(); 1.351 + 1.352 + interruptLock = PR_NewLock(); 1.353 + if (!interruptLock) 1.354 + return false; 1.355 + 1.356 + gcLock = PR_NewLock(); 1.357 + if (!gcLock) 1.358 + return false; 1.359 + 1.360 + exclusiveAccessLock = PR_NewLock(); 1.361 + if (!exclusiveAccessLock) 1.362 + return false; 1.363 +#endif 1.364 + 1.365 + if (!mainThread.init()) 1.366 + return false; 1.367 + 1.368 + js::TlsPerThreadData.set(&mainThread); 1.369 + 1.370 + if (!threadPool.init()) 1.371 + return false; 1.372 + 1.373 + if (!js_InitGC(this, maxbytes)) 1.374 + return false; 1.375 + 1.376 + if (!gcMarker.init(gcMode())) 1.377 + return false; 1.378 + 1.379 + const char *size = getenv("JSGC_MARK_STACK_LIMIT"); 1.380 + if (size) 1.381 + SetMarkStackLimit(this, atoi(size)); 1.382 + 1.383 + ScopedJSDeletePtr<Zone> atomsZone(new_<Zone>(this)); 1.384 + if (!atomsZone) 1.385 + return false; 1.386 + 1.387 + JS::CompartmentOptions options; 1.388 + ScopedJSDeletePtr<JSCompartment> atomsCompartment(new_<JSCompartment>(atomsZone.get(), options)); 1.389 + if (!atomsCompartment || !atomsCompartment->init(nullptr)) 1.390 + return false; 1.391 + 1.392 + zones.append(atomsZone.get()); 1.393 + atomsZone->compartments.append(atomsCompartment.get()); 1.394 + 1.395 + atomsCompartment->isSystem = true; 1.396 + atomsZone->isSystem = true; 1.397 + atomsZone->setGCLastBytes(8192, GC_NORMAL); 1.398 + 1.399 + atomsZone.forget(); 1.400 + this->atomsCompartment_ = atomsCompartment.forget(); 1.401 + 1.402 + if (!scriptDataTable_.init()) 1.403 + return false; 1.404 + 1.405 + if (!evalCache.init()) 1.406 + return false; 1.407 + 1.408 + /* The garbage collector depends on everything before this point being initialized. */ 1.409 + gcInitialized = true; 1.410 + 1.411 + if (!InitRuntimeNumberState(this)) 1.412 + return false; 1.413 + 1.414 + dateTimeInfo.updateTimeZoneAdjustment(); 1.415 + 1.416 +#ifdef JS_ARM_SIMULATOR 1.417 + simulatorRuntime_ = js::jit::CreateSimulatorRuntime(); 1.418 + if (!simulatorRuntime_) 1.419 + return false; 1.420 +#endif 1.421 + 1.422 + nativeStackBase = GetNativeStackBase(); 1.423 + 1.424 + jitSupportsFloatingPoint = JitSupportsFloatingPoint(); 1.425 + 1.426 +#ifdef JS_ION 1.427 + signalHandlersInstalled_ = EnsureAsmJSSignalHandlersInstalled(this); 1.428 +#endif 1.429 + 1.430 + if (!spsProfiler.init()) 1.431 + return false; 1.432 + 1.433 + return true; 1.434 +} 1.435 + 1.436 +JSRuntime::~JSRuntime() 1.437 +{ 1.438 + JS_ASSERT(!isHeapBusy()); 1.439 + 1.440 + if (gcInitialized) { 1.441 + /* Free source hook early, as its destructor may want to delete roots. */ 1.442 + sourceHook = nullptr; 1.443 + 1.444 + /* 1.445 + * Cancel any pending, in progress or completed Ion compilations and 1.446 + * parse tasks. Waiting for AsmJS and compression tasks is done 1.447 + * synchronously (on the main thread or during parse tasks), so no 1.448 + * explicit canceling is needed for these. 1.449 + */ 1.450 + for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next()) 1.451 + CancelOffThreadIonCompile(comp, nullptr); 1.452 + CancelOffThreadParses(this); 1.453 + 1.454 + /* Clear debugging state to remove GC roots. */ 1.455 + for (CompartmentsIter comp(this, SkipAtoms); !comp.done(); comp.next()) { 1.456 + comp->clearTraps(defaultFreeOp()); 1.457 + if (WatchpointMap *wpmap = comp->watchpointMap) 1.458 + wpmap->clear(); 1.459 + } 1.460 + 1.461 + /* Clear atoms to remove GC roots and heap allocations. */ 1.462 + finishAtoms(); 1.463 + 1.464 + /* 1.465 + * Flag us as being destroyed. This allows the GC to free things like 1.466 + * interned atoms and Ion trampolines. 1.467 + */ 1.468 + beingDestroyed_ = true; 1.469 + 1.470 + /* Allow the GC to release scripts that were being profiled. */ 1.471 + profilingScripts = false; 1.472 + 1.473 + JS::PrepareForFullGC(this); 1.474 + GC(this, GC_NORMAL, JS::gcreason::DESTROY_RUNTIME); 1.475 + } 1.476 + 1.477 + /* 1.478 + * Clear the self-hosted global and delete self-hosted classes *after* 1.479 + * GC, as finalizers for objects check for clasp->finalize during GC. 1.480 + */ 1.481 + finishSelfHosting(); 1.482 + 1.483 +#ifdef JS_THREADSAFE 1.484 + JS_ASSERT(!exclusiveAccessOwner); 1.485 + if (exclusiveAccessLock) 1.486 + PR_DestroyLock(exclusiveAccessLock); 1.487 + 1.488 + // Avoid bogus asserts during teardown. 1.489 + JS_ASSERT(!numExclusiveThreads); 1.490 + mainThreadHasExclusiveAccess = true; 1.491 + 1.492 + JS_ASSERT(!interruptLockOwner); 1.493 + if (interruptLock) 1.494 + PR_DestroyLock(interruptLock); 1.495 +#endif 1.496 + 1.497 + /* 1.498 + * Even though all objects in the compartment are dead, we may have keep 1.499 + * some filenames around because of gcKeepAtoms. 1.500 + */ 1.501 + FreeScriptData(this); 1.502 + 1.503 +#ifdef DEBUG 1.504 + /* Don't hurt everyone in leaky ol' Mozilla with a fatal JS_ASSERT! */ 1.505 + if (hasContexts()) { 1.506 + unsigned cxcount = 0; 1.507 + for (ContextIter acx(this); !acx.done(); acx.next()) { 1.508 + fprintf(stderr, 1.509 +"JS API usage error: found live context at %p\n", 1.510 + (void *) acx.get()); 1.511 + cxcount++; 1.512 + } 1.513 + fprintf(stderr, 1.514 +"JS API usage error: %u context%s left in runtime upon JS_DestroyRuntime.\n", 1.515 + cxcount, (cxcount == 1) ? "" : "s"); 1.516 + } 1.517 +#endif 1.518 + 1.519 +#if !EXPOSE_INTL_API 1.520 + FinishRuntimeNumberState(this); 1.521 +#endif 1.522 + 1.523 + js_FinishGC(this); 1.524 + atomsCompartment_ = nullptr; 1.525 + 1.526 +#ifdef JS_THREADSAFE 1.527 + if (gcLock) 1.528 + PR_DestroyLock(gcLock); 1.529 +#endif 1.530 + 1.531 + js_free(defaultLocale); 1.532 + js_delete(bumpAlloc_); 1.533 + js_delete(mathCache_); 1.534 +#ifdef JS_ION 1.535 + js_delete(jitRuntime_); 1.536 +#endif 1.537 + js_delete(execAlloc_); /* Delete after jitRuntime_. */ 1.538 + 1.539 + js_delete(ionPcScriptCache); 1.540 + 1.541 +#ifdef JSGC_GENERATIONAL 1.542 + gcStoreBuffer.disable(); 1.543 + gcNursery.disable(); 1.544 +#endif 1.545 + 1.546 +#ifdef JS_ARM_SIMULATOR 1.547 + js::jit::DestroySimulatorRuntime(simulatorRuntime_); 1.548 +#endif 1.549 + 1.550 + DebugOnly<size_t> oldCount = liveRuntimesCount--; 1.551 + JS_ASSERT(oldCount > 0); 1.552 + 1.553 +#ifdef JS_THREADSAFE 1.554 + js::TlsPerThreadData.set(nullptr); 1.555 +#endif 1.556 +} 1.557 + 1.558 +void 1.559 +NewObjectCache::clearNurseryObjects(JSRuntime *rt) 1.560 +{ 1.561 + for (unsigned i = 0; i < mozilla::ArrayLength(entries); ++i) { 1.562 + Entry &e = entries[i]; 1.563 + JSObject *obj = reinterpret_cast<JSObject *>(&e.templateObject); 1.564 + if (IsInsideNursery(rt, e.key) || 1.565 + IsInsideNursery(rt, obj->slots) || 1.566 + IsInsideNursery(rt, obj->elements)) 1.567 + { 1.568 + PodZero(&e); 1.569 + } 1.570 + } 1.571 +} 1.572 + 1.573 +void 1.574 +JSRuntime::resetJitStackLimit() 1.575 +{ 1.576 + AutoLockForInterrupt lock(this); 1.577 + mainThread.setJitStackLimit(mainThread.nativeStackLimit[js::StackForUntrustedScript]); 1.578 + 1.579 +#ifdef JS_ARM_SIMULATOR 1.580 + mainThread.setJitStackLimit(js::jit::Simulator::StackLimit()); 1.581 +#endif 1.582 + } 1.583 + 1.584 +void 1.585 +JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::RuntimeSizes *rtSizes) 1.586 +{ 1.587 + // Several tables in the runtime enumerated below can be used off thread. 1.588 + AutoLockForExclusiveAccess lock(this); 1.589 + 1.590 + rtSizes->object += mallocSizeOf(this); 1.591 + 1.592 + rtSizes->atomsTable += atoms().sizeOfIncludingThis(mallocSizeOf); 1.593 + 1.594 + if (!parentRuntime) { 1.595 + rtSizes->atomsTable += mallocSizeOf(staticStrings); 1.596 + rtSizes->atomsTable += mallocSizeOf(commonNames); 1.597 + rtSizes->atomsTable += permanentAtoms->sizeOfIncludingThis(mallocSizeOf); 1.598 + } 1.599 + 1.600 + for (ContextIter acx(this); !acx.done(); acx.next()) 1.601 + rtSizes->contexts += acx->sizeOfIncludingThis(mallocSizeOf); 1.602 + 1.603 + rtSizes->dtoa += mallocSizeOf(mainThread.dtoaState); 1.604 + 1.605 + rtSizes->temporary += tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf); 1.606 + 1.607 + rtSizes->regexpData += bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0; 1.608 + 1.609 + rtSizes->interpreterStack += interpreterStack_.sizeOfExcludingThis(mallocSizeOf); 1.610 + 1.611 + rtSizes->mathCache += mathCache_ ? mathCache_->sizeOfIncludingThis(mallocSizeOf) : 0; 1.612 + 1.613 + rtSizes->sourceDataCache += sourceDataCache.sizeOfExcludingThis(mallocSizeOf); 1.614 + 1.615 + rtSizes->scriptData += scriptDataTable().sizeOfExcludingThis(mallocSizeOf); 1.616 + for (ScriptDataTable::Range r = scriptDataTable().all(); !r.empty(); r.popFront()) 1.617 + rtSizes->scriptData += mallocSizeOf(r.front()); 1.618 + 1.619 + if (execAlloc_) 1.620 + execAlloc_->addSizeOfCode(&rtSizes->code); 1.621 +#ifdef JS_ION 1.622 + { 1.623 + AutoLockForInterrupt lock(this); 1.624 + if (jitRuntime()) { 1.625 + if (JSC::ExecutableAllocator *ionAlloc = jitRuntime()->ionAlloc(this)) 1.626 + ionAlloc->addSizeOfCode(&rtSizes->code); 1.627 + } 1.628 + } 1.629 +#endif 1.630 + 1.631 + rtSizes->gc.marker += gcMarker.sizeOfExcludingThis(mallocSizeOf); 1.632 +#ifdef JSGC_GENERATIONAL 1.633 + rtSizes->gc.nurseryCommitted += gcNursery.sizeOfHeapCommitted(); 1.634 + rtSizes->gc.nurseryDecommitted += gcNursery.sizeOfHeapDecommitted(); 1.635 + rtSizes->gc.nurseryHugeSlots += gcNursery.sizeOfHugeSlots(mallocSizeOf); 1.636 + gcStoreBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc); 1.637 +#endif 1.638 +} 1.639 + 1.640 +static bool 1.641 +SignalBasedTriggersDisabled() 1.642 +{ 1.643 + // Don't bother trying to cache the getenv lookup; this should be called 1.644 + // infrequently. 1.645 + return !!getenv("JS_DISABLE_SLOW_SCRIPT_SIGNALS"); 1.646 +} 1.647 + 1.648 +void 1.649 +JSRuntime::requestInterrupt(InterruptMode mode) 1.650 +{ 1.651 + AutoLockForInterrupt lock(this); 1.652 + 1.653 + /* 1.654 + * Invalidate ionTop to trigger its over-recursion check. Note this must be 1.655 + * set before interrupt, to avoid racing with js::InvokeInterruptCallback, 1.656 + * into a weird state where interrupt is stuck at 0 but jitStackLimit is 1.657 + * MAXADDR. 1.658 + */ 1.659 + mainThread.setJitStackLimit(-1); 1.660 + 1.661 + interrupt = true; 1.662 + 1.663 +#ifdef JS_ION 1.664 +#ifdef JS_THREADSAFE 1.665 + RequestInterruptForForkJoin(this, mode); 1.666 +#endif 1.667 + 1.668 + /* 1.669 + * asm.js and, optionally, normal Ion code use memory protection and signal 1.670 + * handlers to halt running code. 1.671 + */ 1.672 + if (!SignalBasedTriggersDisabled()) { 1.673 + RequestInterruptForAsmJSCode(this); 1.674 + jit::RequestInterruptForIonCode(this, mode); 1.675 + } 1.676 +#endif 1.677 +} 1.678 + 1.679 +JSC::ExecutableAllocator * 1.680 +JSRuntime::createExecutableAllocator(JSContext *cx) 1.681 +{ 1.682 + JS_ASSERT(!execAlloc_); 1.683 + JS_ASSERT(cx->runtime() == this); 1.684 + 1.685 + execAlloc_ = js_new<JSC::ExecutableAllocator>(); 1.686 + if (!execAlloc_) 1.687 + js_ReportOutOfMemory(cx); 1.688 + return execAlloc_; 1.689 +} 1.690 + 1.691 +WTF::BumpPointerAllocator * 1.692 +JSRuntime::createBumpPointerAllocator(JSContext *cx) 1.693 +{ 1.694 + JS_ASSERT(!bumpAlloc_); 1.695 + JS_ASSERT(cx->runtime() == this); 1.696 + 1.697 + bumpAlloc_ = js_new<WTF::BumpPointerAllocator>(); 1.698 + if (!bumpAlloc_) 1.699 + js_ReportOutOfMemory(cx); 1.700 + return bumpAlloc_; 1.701 +} 1.702 + 1.703 +MathCache * 1.704 +JSRuntime::createMathCache(JSContext *cx) 1.705 +{ 1.706 + JS_ASSERT(!mathCache_); 1.707 + JS_ASSERT(cx->runtime() == this); 1.708 + 1.709 + MathCache *newMathCache = js_new<MathCache>(); 1.710 + if (!newMathCache) { 1.711 + js_ReportOutOfMemory(cx); 1.712 + return nullptr; 1.713 + } 1.714 + 1.715 + mathCache_ = newMathCache; 1.716 + return mathCache_; 1.717 +} 1.718 + 1.719 +bool 1.720 +JSRuntime::setDefaultLocale(const char *locale) 1.721 +{ 1.722 + if (!locale) 1.723 + return false; 1.724 + resetDefaultLocale(); 1.725 + defaultLocale = JS_strdup(this, locale); 1.726 + return defaultLocale != nullptr; 1.727 +} 1.728 + 1.729 +void 1.730 +JSRuntime::resetDefaultLocale() 1.731 +{ 1.732 + js_free(defaultLocale); 1.733 + defaultLocale = nullptr; 1.734 +} 1.735 + 1.736 +const char * 1.737 +JSRuntime::getDefaultLocale() 1.738 +{ 1.739 + if (defaultLocale) 1.740 + return defaultLocale; 1.741 + 1.742 + char *locale, *lang, *p; 1.743 +#ifdef HAVE_SETLOCALE 1.744 + locale = setlocale(LC_ALL, nullptr); 1.745 +#else 1.746 + locale = getenv("LANG"); 1.747 +#endif 1.748 + // convert to a well-formed BCP 47 language tag 1.749 + if (!locale || !strcmp(locale, "C")) 1.750 + locale = const_cast<char*>("und"); 1.751 + lang = JS_strdup(this, locale); 1.752 + if (!lang) 1.753 + return nullptr; 1.754 + if ((p = strchr(lang, '.'))) 1.755 + *p = '\0'; 1.756 + while ((p = strchr(lang, '_'))) 1.757 + *p = '-'; 1.758 + 1.759 + defaultLocale = lang; 1.760 + return defaultLocale; 1.761 +} 1.762 + 1.763 +void 1.764 +JSRuntime::triggerActivityCallback(bool active) 1.765 +{ 1.766 + if (!activityCallback) 1.767 + return; 1.768 + 1.769 + /* 1.770 + * The activity callback must not trigger a GC: it would create a cirular 1.771 + * dependency between entering a request and Rooted's requirement of being 1.772 + * in a request. In practice this callback already cannot trigger GC. The 1.773 + * suppression serves to inform the exact rooting hazard analysis of this 1.774 + * property and ensures that it remains true in the future. 1.775 + */ 1.776 + AutoSuppressGC suppress(this); 1.777 + 1.778 + activityCallback(activityCallbackArg, active); 1.779 +} 1.780 + 1.781 +void 1.782 +JSRuntime::setGCMaxMallocBytes(size_t value) 1.783 +{ 1.784 + /* 1.785 + * For compatibility treat any value that exceeds PTRDIFF_T_MAX to 1.786 + * mean that value. 1.787 + */ 1.788 + gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1; 1.789 + resetGCMallocBytes(); 1.790 + for (ZonesIter zone(this, WithAtoms); !zone.done(); zone.next()) 1.791 + zone->setGCMaxMallocBytes(value); 1.792 +} 1.793 + 1.794 +void 1.795 +JSRuntime::updateMallocCounter(size_t nbytes) 1.796 +{ 1.797 + updateMallocCounter(nullptr, nbytes); 1.798 +} 1.799 + 1.800 +void 1.801 +JSRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes) 1.802 +{ 1.803 + /* We tolerate any thread races when updating gcMallocBytes. */ 1.804 + gcMallocBytes -= ptrdiff_t(nbytes); 1.805 + if (MOZ_UNLIKELY(gcMallocBytes <= 0)) 1.806 + onTooMuchMalloc(); 1.807 + else if (zone) 1.808 + zone->updateMallocCounter(nbytes); 1.809 +} 1.810 + 1.811 +JS_FRIEND_API(void) 1.812 +JSRuntime::onTooMuchMalloc() 1.813 +{ 1.814 + if (!CurrentThreadCanAccessRuntime(this)) 1.815 + return; 1.816 + 1.817 + if (!gcMallocGCTriggered) 1.818 + gcMallocGCTriggered = TriggerGC(this, JS::gcreason::TOO_MUCH_MALLOC); 1.819 +} 1.820 + 1.821 +JS_FRIEND_API(void *) 1.822 +JSRuntime::onOutOfMemory(void *p, size_t nbytes) 1.823 +{ 1.824 + return onOutOfMemory(p, nbytes, nullptr); 1.825 +} 1.826 + 1.827 +JS_FRIEND_API(void *) 1.828 +JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx) 1.829 +{ 1.830 + if (isHeapBusy()) 1.831 + return nullptr; 1.832 + 1.833 + /* 1.834 + * Retry when we are done with the background sweeping and have stopped 1.835 + * all the allocations and released the empty GC chunks. 1.836 + */ 1.837 + JS::ShrinkGCBuffers(this); 1.838 + gcHelperThread.waitBackgroundSweepOrAllocEnd(); 1.839 + if (!p) 1.840 + p = js_malloc(nbytes); 1.841 + else if (p == reinterpret_cast<void *>(1)) 1.842 + p = js_calloc(nbytes); 1.843 + else 1.844 + p = js_realloc(p, nbytes); 1.845 + if (p) 1.846 + return p; 1.847 + if (cx) 1.848 + js_ReportOutOfMemory(cx); 1.849 + return nullptr; 1.850 +} 1.851 + 1.852 +bool 1.853 +JSRuntime::activeGCInAtomsZone() 1.854 +{ 1.855 + Zone *zone = atomsCompartment_->zone(); 1.856 + return zone->needsBarrier() || zone->isGCScheduled() || zone->wasGCStarted(); 1.857 +} 1.858 + 1.859 +#ifdef JS_THREADSAFE 1.860 + 1.861 +void 1.862 +JSRuntime::setUsedByExclusiveThread(Zone *zone) 1.863 +{ 1.864 + JS_ASSERT(!zone->usedByExclusiveThread); 1.865 + zone->usedByExclusiveThread = true; 1.866 + numExclusiveThreads++; 1.867 +} 1.868 + 1.869 +void 1.870 +JSRuntime::clearUsedByExclusiveThread(Zone *zone) 1.871 +{ 1.872 + JS_ASSERT(zone->usedByExclusiveThread); 1.873 + zone->usedByExclusiveThread = false; 1.874 + numExclusiveThreads--; 1.875 +} 1.876 + 1.877 +bool 1.878 +js::CurrentThreadCanAccessRuntime(JSRuntime *rt) 1.879 +{ 1.880 + return rt->ownerThread_ == PR_GetCurrentThread() && !InParallelSection(); 1.881 +} 1.882 + 1.883 +bool 1.884 +js::CurrentThreadCanAccessZone(Zone *zone) 1.885 +{ 1.886 + if (CurrentThreadCanAccessRuntime(zone->runtime_)) 1.887 + return true; 1.888 + if (InParallelSection()) { 1.889 + DebugOnly<PerThreadData *> pt = js::TlsPerThreadData.get(); 1.890 + JS_ASSERT(pt && pt->associatedWith(zone->runtime_)); 1.891 + return true; 1.892 + } 1.893 + 1.894 + // Only zones in use by an exclusive thread can be used off the main thread 1.895 + // or outside of PJS. We don't keep track of which thread owns such zones 1.896 + // though, so this check is imperfect. 1.897 + return zone->usedByExclusiveThread; 1.898 +} 1.899 + 1.900 +#else // JS_THREADSAFE 1.901 + 1.902 +bool 1.903 +js::CurrentThreadCanAccessRuntime(JSRuntime *rt) 1.904 +{ 1.905 + return true; 1.906 +} 1.907 + 1.908 +bool 1.909 +js::CurrentThreadCanAccessZone(Zone *zone) 1.910 +{ 1.911 + return true; 1.912 +} 1.913 + 1.914 +#endif // JS_THREADSAFE 1.915 + 1.916 +#ifdef DEBUG 1.917 + 1.918 +void 1.919 +JSRuntime::assertCanLock(RuntimeLock which) 1.920 +{ 1.921 +#ifdef JS_THREADSAFE 1.922 + // In the switch below, each case falls through to the one below it. None 1.923 + // of the runtime locks are reentrant, and when multiple locks are acquired 1.924 + // it must be done in the order below. 1.925 + switch (which) { 1.926 + case ExclusiveAccessLock: 1.927 + JS_ASSERT(exclusiveAccessOwner != PR_GetCurrentThread()); 1.928 + case WorkerThreadStateLock: 1.929 + JS_ASSERT(!WorkerThreadState().isLocked()); 1.930 + case InterruptLock: 1.931 + JS_ASSERT(!currentThreadOwnsInterruptLock()); 1.932 + case GCLock: 1.933 + JS_ASSERT(gcLockOwner != PR_GetCurrentThread()); 1.934 + break; 1.935 + default: 1.936 + MOZ_CRASH(); 1.937 + } 1.938 +#endif // JS_THREADSAFE 1.939 +} 1.940 + 1.941 +void 1.942 +js::AssertCurrentThreadCanLock(RuntimeLock which) 1.943 +{ 1.944 +#ifdef JS_THREADSAFE 1.945 + PerThreadData *pt = TlsPerThreadData.get(); 1.946 + if (pt && pt->runtime_) 1.947 + pt->runtime_->assertCanLock(which); 1.948 +#endif 1.949 +} 1.950 + 1.951 +#endif // DEBUG