зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1134425 - Part 1: move the allocator interface code out of line; r=jonco
--HG-- extra : rebase_source : cbeb8097a3c55397cc0c0f476deb0011ad496f62
This commit is contained in:
Родитель
a26a5496a6
Коммит
bb7d88df07
|
@ -19,6 +19,7 @@
|
|||
#include "jspubtd.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/TracingAPI.h"
|
||||
#include "js/Utility.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "frontend/Parser.h"
|
||||
#include "jit/IonCode.h"
|
||||
#include "js/Class.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "js/MemoryMetrics.h"
|
||||
|
||||
|
@ -50,9 +51,10 @@ using namespace js;
|
|||
using namespace jit;
|
||||
using namespace frontend;
|
||||
using mozilla::BinarySearch;
|
||||
using mozilla::Compression::LZ4;
|
||||
using mozilla::PodCopy;
|
||||
using mozilla::PodEqual;
|
||||
using mozilla::Compression::LZ4;
|
||||
using mozilla::PodZero;
|
||||
using mozilla::Swap;
|
||||
|
||||
static uint8_t *
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "js/Class.h"
|
||||
#include "vm/GlobalObject.h"
|
||||
#include "vm/SharedTypedArrayObject.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
/* -*- 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 "gc/Allocator.h"
|
||||
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "gc/GCTrace.h"
|
||||
#include "gc/Nursery.h"
|
||||
#include "jit/JitCompartment.h"
|
||||
#include "vm/Runtime.h"
|
||||
#include "vm/String.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace gc;
|
||||
|
||||
static inline bool
|
||||
ShouldNurseryAllocateObject(const Nursery &nursery, InitialHeap heap)
|
||||
{
|
||||
return nursery.isEnabled() && heap != TenuredHeap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to allocate a new GC thing out of the nursery. If there is not enough
|
||||
* room in the nursery or there is an OOM, this method will return nullptr.
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
inline JSObject *
|
||||
TryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const Class *clasp)
|
||||
{
|
||||
MOZ_ASSERT(!IsAtomsCompartment(cx->compartment()));
|
||||
JSRuntime *rt = cx->runtime();
|
||||
Nursery &nursery = rt->gc.nursery;
|
||||
JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp);
|
||||
if (obj)
|
||||
return obj;
|
||||
if (allowGC && !rt->mainThread.suppressGC) {
|
||||
cx->minorGC(JS::gcreason::OUT_OF_NURSERY);
|
||||
|
||||
/* Exceeding gcMaxBytes while tenuring can disable the Nursery. */
|
||||
if (nursery.isEnabled()) {
|
||||
JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp);
|
||||
MOZ_ASSERT(obj);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
PossiblyFail()
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL_BOOL();
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
GCIfNeeded(ExclusiveContext *cx)
|
||||
{
|
||||
if (cx->isJSContext()) {
|
||||
JSContext *ncx = cx->asJSContext();
|
||||
JSRuntime *rt = ncx->runtime();
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (rt->gc.needZealousGC())
|
||||
rt->gc.runDebugGC();
|
||||
#endif
|
||||
|
||||
// Invoking the interrupt callback can fail and we can't usefully
|
||||
// handle that here. Just check in case we need to collect instead.
|
||||
if (rt->hasPendingInterrupt())
|
||||
rt->gc.gcIfRequested(ncx);
|
||||
|
||||
// If we have grown past our GC heap threshold while in the middle of
|
||||
// an incremental GC, we're growing faster than we're GCing, so stop
|
||||
// the world and do a full, non-incremental GC right now, if possible.
|
||||
if (rt->gc.isIncrementalGCInProgress() &&
|
||||
cx->zone()->usage.gcBytes() > cx->zone()->threshold.gcTriggerBytes())
|
||||
{
|
||||
PrepareZoneForGC(cx->zone());
|
||||
AutoKeepAtoms keepAtoms(cx->perThreadData);
|
||||
rt->gc.gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static inline bool
|
||||
CheckAllocatorState(ExclusiveContext *cx, AllocKind kind)
|
||||
{
|
||||
if (allowGC) {
|
||||
if (!GCIfNeeded(cx))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cx->isJSContext())
|
||||
return true;
|
||||
|
||||
JSContext *ncx = cx->asJSContext();
|
||||
JSRuntime *rt = ncx->runtime();
|
||||
#if defined(JS_GC_ZEAL) || defined(DEBUG)
|
||||
MOZ_ASSERT_IF(rt->isAtomsCompartment(ncx->compartment()),
|
||||
kind == FINALIZE_STRING ||
|
||||
kind == FINALIZE_FAT_INLINE_STRING ||
|
||||
kind == FINALIZE_SYMBOL ||
|
||||
kind == FINALIZE_JITCODE);
|
||||
MOZ_ASSERT(!rt->isHeapBusy());
|
||||
MOZ_ASSERT(rt->gc.isAllocAllowed());
|
||||
#endif
|
||||
|
||||
// Crash if we perform a GC action when it is not safe.
|
||||
if (allowGC && !rt->mainThread.suppressGC)
|
||||
JS::AutoAssertOnGC::VerifyIsSafeToGC(rt);
|
||||
|
||||
// For testing out of memory conditions
|
||||
if (!PossiblyFail()) {
|
||||
ReportOutOfMemory(ncx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void
|
||||
CheckIncrementalZoneState(ExclusiveContext *cx, T *t)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!cx->isJSContext())
|
||||
return;
|
||||
|
||||
Zone *zone = cx->asJSContext()->zone();
|
||||
MOZ_ASSERT_IF(t && zone->wasGCStarted() && (zone->isGCMarking() || zone->isGCSweeping()),
|
||||
t->asTenured().arenaHeader()->allocatedDuringIncremental);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new GC thing. After a successful allocation the caller must
|
||||
* fully initialize the thing before calling any function that can potentially
|
||||
* trigger GC. This will ensure that GC tracing never sees junk values stored
|
||||
* in the partially initialized thing.
|
||||
*/
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline JSObject *
|
||||
AllocateObject(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, InitialHeap heap,
|
||||
const Class *clasp)
|
||||
{
|
||||
size_t thingSize = Arena::thingSize(kind);
|
||||
|
||||
MOZ_ASSERT(thingSize == Arena::thingSize(kind));
|
||||
MOZ_ASSERT(thingSize >= sizeof(JSObject_Slots0));
|
||||
static_assert(sizeof(JSObject_Slots0) >= CellSize,
|
||||
"All allocations must be at least the allocator-imposed minimum size.");
|
||||
|
||||
if (!CheckAllocatorState<allowGC>(cx, kind))
|
||||
return nullptr;
|
||||
|
||||
if (cx->isJSContext() &&
|
||||
ShouldNurseryAllocateObject(cx->asJSContext()->nursery(), heap))
|
||||
{
|
||||
JSObject *obj = TryNewNurseryObject<allowGC>(cx->asJSContext(), thingSize, nDynamicSlots,
|
||||
clasp);
|
||||
if (obj)
|
||||
return obj;
|
||||
}
|
||||
|
||||
HeapSlot *slots = nullptr;
|
||||
if (nDynamicSlots) {
|
||||
slots = cx->zone()->pod_malloc<HeapSlot>(nDynamicSlots);
|
||||
if (MOZ_UNLIKELY(!slots))
|
||||
return nullptr;
|
||||
Debug_SetSlotRangeToCrashOnTouch(slots, nDynamicSlots);
|
||||
}
|
||||
|
||||
JSObject *obj = reinterpret_cast<JSObject *>(cx->arenas()->allocateFromFreeList(kind, thingSize));
|
||||
if (!obj)
|
||||
obj = reinterpret_cast<JSObject *>(GCRuntime::refillFreeListFromAnyThread<allowGC>(cx, kind));
|
||||
|
||||
if (obj)
|
||||
obj->setInitialSlotsMaybeNonNative(slots);
|
||||
else
|
||||
js_free(slots);
|
||||
|
||||
CheckIncrementalZoneState(cx, obj);
|
||||
TraceTenuredAlloc(obj, kind);
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <typename T, AllowGC allowGC>
|
||||
inline T *
|
||||
AllocateNonObject(ExclusiveContext *cx)
|
||||
{
|
||||
static_assert(sizeof(T) >= CellSize,
|
||||
"All allocations must be at least the allocator-imposed minimum size.");
|
||||
|
||||
AllocKind kind = MapTypeToFinalizeKind<T>::kind;
|
||||
size_t thingSize = sizeof(T);
|
||||
|
||||
MOZ_ASSERT(thingSize == Arena::thingSize(kind));
|
||||
if (!CheckAllocatorState<allowGC>(cx, kind))
|
||||
return nullptr;
|
||||
|
||||
T *t = static_cast<T *>(cx->arenas()->allocateFromFreeList(kind, thingSize));
|
||||
if (!t)
|
||||
t = static_cast<T *>(GCRuntime::refillFreeListFromAnyThread<allowGC>(cx, kind));
|
||||
|
||||
CheckIncrementalZoneState(cx, t);
|
||||
TraceTenuredAlloc(t, kind);
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* When allocating for initialization from a cached object copy, we will
|
||||
* potentially destroy the cache entry we want to copy if we allow GC. On the
|
||||
* other hand, since these allocations are extremely common, we don't want to
|
||||
* delay GC from these allocation sites. Instead we allow the GC, but still
|
||||
* fail the allocation, forcing the non-cached path.
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
NativeObject *
|
||||
js::gc::AllocateObjectForCacheHit(JSContext *cx, AllocKind kind, InitialHeap heap,
|
||||
const js::Class *clasp)
|
||||
{
|
||||
MOZ_ASSERT(clasp->isNative());
|
||||
|
||||
if (ShouldNurseryAllocateObject(cx->nursery(), heap)) {
|
||||
size_t thingSize = Arena::thingSize(kind);
|
||||
|
||||
MOZ_ASSERT(thingSize == Arena::thingSize(kind));
|
||||
if (!CheckAllocatorState<NoGC>(cx, kind))
|
||||
return nullptr;
|
||||
|
||||
JSObject *obj = TryNewNurseryObject<NoGC>(cx, thingSize, 0, clasp);
|
||||
if (!obj && allowGC) {
|
||||
cx->minorGC(JS::gcreason::OUT_OF_NURSERY);
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<NativeObject *>(obj);
|
||||
}
|
||||
|
||||
JSObject *obj = AllocateObject<NoGC>(cx, kind, 0, heap, clasp);
|
||||
if (!obj && allowGC) {
|
||||
cx->runtime()->gc.maybeGC(cx->zone());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<NativeObject *>(obj);
|
||||
}
|
||||
template NativeObject *js::gc::AllocateObjectForCacheHit<CanGC>(JSContext *, AllocKind, InitialHeap,
|
||||
const Class *);
|
||||
template NativeObject *js::gc::AllocateObjectForCacheHit<NoGC>(JSContext *, AllocKind, InitialHeap,
|
||||
const Class *);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JSObject *
|
||||
js::NewGCObject(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots,
|
||||
InitialHeap heap, const Class *clasp)
|
||||
{
|
||||
MOZ_ASSERT(kind >= FINALIZE_OBJECT0 && kind <= FINALIZE_OBJECT_LAST);
|
||||
return AllocateObject<allowGC>(cx, kind, nDynamicSlots, heap, clasp);
|
||||
}
|
||||
template JSObject *js::NewGCObject<CanGC>(ExclusiveContext *, AllocKind, size_t, InitialHeap,
|
||||
const Class *);
|
||||
template JSObject *js::NewGCObject<NoGC>(ExclusiveContext *, AllocKind, size_t, InitialHeap,
|
||||
const Class *);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
jit::JitCode *
|
||||
js::NewJitCode(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<jit::JitCode, allowGC>(cx);
|
||||
}
|
||||
template jit::JitCode *js::NewJitCode<CanGC>(ExclusiveContext *cx);
|
||||
template jit::JitCode *js::NewJitCode<NoGC>(ExclusiveContext *cx);
|
||||
|
||||
ObjectGroup *
|
||||
js::NewObjectGroup(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<ObjectGroup, CanGC>(cx);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JSString *
|
||||
js::NewGCString(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<JSString, allowGC>(cx);
|
||||
}
|
||||
template JSString *js::NewGCString<CanGC>(ExclusiveContext *cx);
|
||||
template JSString *js::NewGCString<NoGC>(ExclusiveContext *cx);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JSFatInlineString *
|
||||
js::NewGCFatInlineString(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<JSFatInlineString, allowGC>(cx);
|
||||
}
|
||||
template JSFatInlineString *js::NewGCFatInlineString<CanGC>(ExclusiveContext *cx);
|
||||
template JSFatInlineString *js::NewGCFatInlineString<NoGC>(ExclusiveContext *cx);
|
||||
|
||||
JSExternalString *
|
||||
js::NewGCExternalString(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<JSExternalString, CanGC>(cx);
|
||||
}
|
||||
|
||||
Shape *
|
||||
js::NewGCShape(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<Shape, CanGC>(cx);
|
||||
}
|
||||
|
||||
Shape *
|
||||
js::NewGCAccessorShape(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<AccessorShape, CanGC>(cx);
|
||||
}
|
||||
|
||||
JSScript *
|
||||
js::NewGCScript(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<JSScript, CanGC>(cx);
|
||||
}
|
||||
|
||||
LazyScript *
|
||||
js::NewGCLazyScript(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<LazyScript, CanGC>(cx);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
BaseShape *
|
||||
js::NewGCBaseShape(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<BaseShape, allowGC>(cx);
|
||||
}
|
||||
template BaseShape *js::NewGCBaseShape<CanGC>(ExclusiveContext *cx);
|
||||
template BaseShape *js::NewGCBaseShape<NoGC>(ExclusiveContext *cx);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JS::Symbol *
|
||||
js::NewGCSymbol(ExclusiveContext *cx)
|
||||
{
|
||||
return AllocateNonObject<JS::Symbol, allowGC>(cx);
|
||||
}
|
||||
template JS::Symbol *js::NewGCSymbol<CanGC>(ExclusiveContext *cx);
|
||||
template JS::Symbol *js::NewGCSymbol<NoGC>(ExclusiveContext *cx);
|
|
@ -0,0 +1,84 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef gc_Allocator_h
|
||||
#define gc_Allocator_h
|
||||
|
||||
#include "gc/Heap.h"
|
||||
#include "js/RootingAPI.h"
|
||||
|
||||
namespace JS {
|
||||
class Symbol;
|
||||
} // namespace JS
|
||||
class JSExternalString;
|
||||
class JSFatInlineString;
|
||||
class JSObject;
|
||||
class JSScript;
|
||||
class JSString;
|
||||
|
||||
namespace js {
|
||||
struct Class;
|
||||
class BaseShape;
|
||||
class LazyScript;
|
||||
class ObjectGroup;
|
||||
class Shape;
|
||||
namespace jit {
|
||||
class JitCode;
|
||||
} // namespace jit
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JSObject *
|
||||
NewGCObject(ExclusiveContext *cx, gc::AllocKind kind, size_t nDynamicSlots,
|
||||
gc::InitialHeap heap, const Class *clasp);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
jit::JitCode *
|
||||
NewJitCode(ExclusiveContext *cx);
|
||||
|
||||
ObjectGroup *
|
||||
NewObjectGroup(ExclusiveContext *cx);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JSString *
|
||||
NewGCString(ExclusiveContext *cx);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JSFatInlineString *
|
||||
NewGCFatInlineString(ExclusiveContext *cx);
|
||||
|
||||
JSExternalString *
|
||||
NewGCExternalString(ExclusiveContext *cx);
|
||||
|
||||
Shape *
|
||||
NewGCShape(ExclusiveContext *cx);
|
||||
|
||||
Shape *
|
||||
NewGCAccessorShape(ExclusiveContext *cx);
|
||||
|
||||
JSScript *
|
||||
NewGCScript(ExclusiveContext *cx);
|
||||
|
||||
LazyScript *
|
||||
NewGCLazyScript(ExclusiveContext *cx);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
BaseShape *
|
||||
NewGCBaseShape(ExclusiveContext *cx);
|
||||
|
||||
template <AllowGC allowGC>
|
||||
JS::Symbol *
|
||||
NewGCSymbol(ExclusiveContext *cx);
|
||||
|
||||
namespace gc {
|
||||
|
||||
template <AllowGC allowGC>
|
||||
NativeObject *
|
||||
AllocateObjectForCacheHit(JSContext *cx, AllocKind kind, InitialHeap heap, const Class *clasp);
|
||||
|
||||
} // namespace gc
|
||||
} // namespace js
|
||||
|
||||
#endif // gc_Allocator_h
|
|
@ -26,7 +26,7 @@
|
|||
#include "vm/TypedArrayObject.h"
|
||||
#include "vm/TypeInference.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "gc/Statistics.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Runtime.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
#include "jit/CompileInfo.h"
|
||||
#include "jit/JitCommon.h"
|
||||
#include "jit/JitSpewer.h"
|
||||
#include "vm/Debugger.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsopcodeinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jscompartmentinlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "jit/CompileInfo.h"
|
||||
#include "jit/JitAllocPolicy.h"
|
||||
#include "jit/JitCompartment.h"
|
||||
#include "jit/MIR.h"
|
||||
#ifdef JS_ION_PERF
|
||||
# include "jit/PerfSpewer.h"
|
||||
#endif
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "js/Conversions.h"
|
||||
#include "vm/TraceLogging.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "mozilla/SizePrintfMacros.h"
|
||||
|
||||
#include "jsprf.h"
|
||||
|
||||
#include "ds/Sort.h"
|
||||
#include "jit/IonBuilder.h"
|
||||
#include "jit/JitcodeMap.h"
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "ds/Sort.h"
|
||||
#include "gc/Heap.h"
|
||||
#include "js/Class.h"
|
||||
#include "js/Conversions.h"
|
||||
#include "vm/ArgumentsObject.h"
|
||||
#include "vm/Interpreter.h"
|
||||
|
|
|
@ -35,6 +35,7 @@ using namespace js::gc;
|
|||
using namespace js::jit;
|
||||
|
||||
using mozilla::DebugOnly;
|
||||
using mozilla::PodArrayZero;
|
||||
|
||||
JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options = JS::CompartmentOptions())
|
||||
: options_(options),
|
||||
|
|
|
@ -29,12 +29,6 @@ GetGCObjectKind(const Class *clasp)
|
|||
return GetGCObjectKind(nslots);
|
||||
}
|
||||
|
||||
inline bool
|
||||
ShouldNurseryAllocateObject(const Nursery &nursery, InitialHeap heap)
|
||||
{
|
||||
return nursery.isEnabled() && heap != TenuredHeap;
|
||||
}
|
||||
|
||||
inline JSGCTraceKind
|
||||
GetGCThingTraceKind(const void *thing)
|
||||
{
|
||||
|
@ -378,325 +372,7 @@ class GCZoneGroupIter {
|
|||
|
||||
typedef CompartmentsIterT<GCZoneGroupIter> GCCompartmentGroupIter;
|
||||
|
||||
/*
|
||||
* Attempt to allocate a new GC thing out of the nursery. If there is not enough
|
||||
* room in the nursery or there is an OOM, this method will return nullptr.
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
inline JSObject *
|
||||
TryNewNurseryObject(JSContext *cx, size_t thingSize, size_t nDynamicSlots, const js::Class *clasp)
|
||||
{
|
||||
MOZ_ASSERT(!IsAtomsCompartment(cx->compartment()));
|
||||
JSRuntime *rt = cx->runtime();
|
||||
Nursery &nursery = rt->gc.nursery;
|
||||
JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp);
|
||||
if (obj)
|
||||
return obj;
|
||||
if (allowGC && !rt->mainThread.suppressGC) {
|
||||
cx->minorGC(JS::gcreason::OUT_OF_NURSERY);
|
||||
|
||||
/* Exceeding gcMaxBytes while tenuring can disable the Nursery. */
|
||||
if (nursery.isEnabled()) {
|
||||
JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots, clasp);
|
||||
MOZ_ASSERT(obj);
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
PossiblyFail()
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL_BOOL();
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
GCIfNeeded(ExclusiveContext *cx)
|
||||
{
|
||||
if (cx->isJSContext()) {
|
||||
JSContext *ncx = cx->asJSContext();
|
||||
JSRuntime *rt = ncx->runtime();
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (rt->gc.needZealousGC())
|
||||
rt->gc.runDebugGC();
|
||||
#endif
|
||||
|
||||
// Invoking the interrupt callback can fail and we can't usefully
|
||||
// handle that here. Just check in case we need to collect instead.
|
||||
if (rt->hasPendingInterrupt())
|
||||
rt->gc.gcIfRequested(ncx);
|
||||
|
||||
// If we have grown past our GC heap threshold while in the middle of
|
||||
// an incremental GC, we're growing faster than we're GCing, so stop
|
||||
// the world and do a full, non-incremental GC right now, if possible.
|
||||
if (rt->gc.isIncrementalGCInProgress() &&
|
||||
cx->zone()->usage.gcBytes() > cx->zone()->threshold.gcTriggerBytes())
|
||||
{
|
||||
PrepareZoneForGC(cx->zone());
|
||||
AutoKeepAtoms keepAtoms(cx->perThreadData);
|
||||
rt->gc.gc(GC_NORMAL, JS::gcreason::INCREMENTAL_TOO_SLOW);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
static inline bool
|
||||
CheckAllocatorState(ExclusiveContext *cx, AllocKind kind)
|
||||
{
|
||||
if (allowGC) {
|
||||
if (!GCIfNeeded(cx))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!cx->isJSContext())
|
||||
return true;
|
||||
|
||||
JSContext *ncx = cx->asJSContext();
|
||||
JSRuntime *rt = ncx->runtime();
|
||||
#if defined(JS_GC_ZEAL) || defined(DEBUG)
|
||||
MOZ_ASSERT_IF(rt->isAtomsCompartment(ncx->compartment()),
|
||||
kind == FINALIZE_STRING ||
|
||||
kind == FINALIZE_FAT_INLINE_STRING ||
|
||||
kind == FINALIZE_SYMBOL ||
|
||||
kind == FINALIZE_JITCODE);
|
||||
MOZ_ASSERT(!rt->isHeapBusy());
|
||||
MOZ_ASSERT(rt->gc.isAllocAllowed());
|
||||
#endif
|
||||
|
||||
// Crash if we perform a GC action when it is not safe.
|
||||
if (allowGC && !rt->mainThread.suppressGC)
|
||||
JS::AutoAssertOnGC::VerifyIsSafeToGC(rt);
|
||||
|
||||
// For testing out of memory conditions
|
||||
if (!PossiblyFail()) {
|
||||
ReportOutOfMemory(ncx);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void
|
||||
CheckIncrementalZoneState(ExclusiveContext *cx, T *t)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!cx->isJSContext())
|
||||
return;
|
||||
|
||||
Zone *zone = cx->asJSContext()->zone();
|
||||
MOZ_ASSERT_IF(t && zone->wasGCStarted() && (zone->isGCMarking() || zone->isGCSweeping()),
|
||||
t->asTenured().arenaHeader()->allocatedDuringIncremental);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new GC thing. After a successful allocation the caller must
|
||||
* fully initialize the thing before calling any function that can potentially
|
||||
* trigger GC. This will ensure that GC tracing never sees junk values stored
|
||||
* in the partially initialized thing.
|
||||
*/
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline JSObject *
|
||||
AllocateObject(ExclusiveContext *cx, AllocKind kind, size_t nDynamicSlots, InitialHeap heap,
|
||||
const js::Class *clasp)
|
||||
{
|
||||
size_t thingSize = Arena::thingSize(kind);
|
||||
|
||||
MOZ_ASSERT(thingSize == Arena::thingSize(kind));
|
||||
MOZ_ASSERT(thingSize >= sizeof(JSObject_Slots0));
|
||||
static_assert(sizeof(JSObject_Slots0) >= CellSize,
|
||||
"All allocations must be at least the allocator-imposed minimum size.");
|
||||
|
||||
if (!CheckAllocatorState<allowGC>(cx, kind))
|
||||
return nullptr;
|
||||
|
||||
if (cx->isJSContext() &&
|
||||
ShouldNurseryAllocateObject(cx->asJSContext()->nursery(), heap))
|
||||
{
|
||||
JSObject *obj = TryNewNurseryObject<allowGC>(cx->asJSContext(), thingSize, nDynamicSlots,
|
||||
clasp);
|
||||
if (obj)
|
||||
return obj;
|
||||
}
|
||||
|
||||
HeapSlot *slots = nullptr;
|
||||
if (nDynamicSlots) {
|
||||
slots = cx->zone()->pod_malloc<HeapSlot>(nDynamicSlots);
|
||||
if (MOZ_UNLIKELY(!slots))
|
||||
return nullptr;
|
||||
js::Debug_SetSlotRangeToCrashOnTouch(slots, nDynamicSlots);
|
||||
}
|
||||
|
||||
JSObject *obj = reinterpret_cast<JSObject *>(cx->arenas()->allocateFromFreeList(kind, thingSize));
|
||||
if (!obj)
|
||||
obj = reinterpret_cast<JSObject *>(GCRuntime::refillFreeListFromAnyThread<allowGC>(cx, kind));
|
||||
|
||||
if (obj)
|
||||
obj->setInitialSlotsMaybeNonNative(slots);
|
||||
else
|
||||
js_free(slots);
|
||||
|
||||
CheckIncrementalZoneState(cx, obj);
|
||||
js::gc::TraceTenuredAlloc(obj, kind);
|
||||
return obj;
|
||||
}
|
||||
|
||||
template <typename T, AllowGC allowGC>
|
||||
inline T *
|
||||
AllocateNonObject(ExclusiveContext *cx)
|
||||
{
|
||||
static_assert(sizeof(T) >= CellSize,
|
||||
"All allocations must be at least the allocator-imposed minimum size.");
|
||||
|
||||
AllocKind kind = MapTypeToFinalizeKind<T>::kind;
|
||||
size_t thingSize = sizeof(T);
|
||||
|
||||
MOZ_ASSERT(thingSize == Arena::thingSize(kind));
|
||||
if (!CheckAllocatorState<allowGC>(cx, kind))
|
||||
return nullptr;
|
||||
|
||||
T *t = static_cast<T *>(cx->arenas()->allocateFromFreeList(kind, thingSize));
|
||||
if (!t)
|
||||
t = static_cast<T *>(GCRuntime::refillFreeListFromAnyThread<allowGC>(cx, kind));
|
||||
|
||||
CheckIncrementalZoneState(cx, t);
|
||||
js::gc::TraceTenuredAlloc(t, kind);
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* When allocating for initialization from a cached object copy, we will
|
||||
* potentially destroy the cache entry we want to copy if we allow GC. On the
|
||||
* other hand, since these allocations are extremely common, we don't want to
|
||||
* delay GC from these allocation sites. Instead we allow the GC, but still
|
||||
* fail the allocation, forcing the non-cached path.
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
inline NativeObject *
|
||||
AllocateObjectForCacheHit(JSContext *cx, AllocKind kind, InitialHeap heap, const js::Class *clasp)
|
||||
{
|
||||
MOZ_ASSERT(clasp->isNative());
|
||||
|
||||
if (ShouldNurseryAllocateObject(cx->nursery(), heap)) {
|
||||
size_t thingSize = Arena::thingSize(kind);
|
||||
|
||||
MOZ_ASSERT(thingSize == Arena::thingSize(kind));
|
||||
if (!CheckAllocatorState<NoGC>(cx, kind))
|
||||
return nullptr;
|
||||
|
||||
JSObject *obj = TryNewNurseryObject<NoGC>(cx, thingSize, 0, clasp);
|
||||
if (!obj && allowGC) {
|
||||
cx->minorGC(JS::gcreason::OUT_OF_NURSERY);
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<NativeObject *>(obj);
|
||||
}
|
||||
|
||||
JSObject *obj = AllocateObject<NoGC>(cx, kind, 0, heap, clasp);
|
||||
if (!obj && allowGC) {
|
||||
cx->runtime()->gc.maybeGC(cx->zone());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return reinterpret_cast<NativeObject *>(obj);
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsInsideGGCNursery(const js::gc::Cell *cell)
|
||||
{
|
||||
if (!cell)
|
||||
return false;
|
||||
uintptr_t addr = uintptr_t(cell);
|
||||
addr &= ~js::gc::ChunkMask;
|
||||
addr |= js::gc::ChunkLocationOffset;
|
||||
uint32_t location = *reinterpret_cast<uint32_t *>(addr);
|
||||
MOZ_ASSERT(location != 0);
|
||||
return location & js::gc::ChunkLocationBitNursery;
|
||||
}
|
||||
|
||||
} /* namespace gc */
|
||||
|
||||
template <js::AllowGC allowGC>
|
||||
inline JSObject *
|
||||
NewGCObject(js::ExclusiveContext *cx, js::gc::AllocKind kind, size_t nDynamicSlots,
|
||||
js::gc::InitialHeap heap, const js::Class *clasp)
|
||||
{
|
||||
MOZ_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
|
||||
return js::gc::AllocateObject<allowGC>(cx, kind, nDynamicSlots, heap, clasp);
|
||||
}
|
||||
|
||||
template <js::AllowGC allowGC>
|
||||
inline jit::JitCode *
|
||||
NewJitCode(js::ExclusiveContext *cx)
|
||||
{
|
||||
return gc::AllocateNonObject<jit::JitCode, allowGC>(cx);
|
||||
}
|
||||
|
||||
inline
|
||||
ObjectGroup *
|
||||
NewObjectGroup(js::ExclusiveContext *cx)
|
||||
{
|
||||
return gc::AllocateNonObject<ObjectGroup, js::CanGC>(cx);
|
||||
}
|
||||
|
||||
template <js::AllowGC allowGC>
|
||||
inline JSString *
|
||||
NewGCString(js::ExclusiveContext *cx)
|
||||
{
|
||||
return js::gc::AllocateNonObject<JSString, allowGC>(cx);
|
||||
}
|
||||
|
||||
template <js::AllowGC allowGC>
|
||||
inline JSFatInlineString *
|
||||
NewGCFatInlineString(js::ExclusiveContext *cx)
|
||||
{
|
||||
return js::gc::AllocateNonObject<JSFatInlineString, allowGC>(cx);
|
||||
}
|
||||
|
||||
inline JSExternalString *
|
||||
NewGCExternalString(js::ExclusiveContext *cx)
|
||||
{
|
||||
return js::gc::AllocateNonObject<JSExternalString, js::CanGC>(cx);
|
||||
}
|
||||
|
||||
inline Shape *
|
||||
NewGCShape(ExclusiveContext *cx)
|
||||
{
|
||||
return gc::AllocateNonObject<Shape, CanGC>(cx);
|
||||
}
|
||||
|
||||
inline Shape *
|
||||
NewGCAccessorShape(ExclusiveContext *cx)
|
||||
{
|
||||
return gc::AllocateNonObject<AccessorShape, CanGC>(cx);
|
||||
}
|
||||
|
||||
inline JSScript *
|
||||
NewGCScript(ExclusiveContext *cx)
|
||||
{
|
||||
return gc::AllocateNonObject<JSScript, CanGC>(cx);
|
||||
}
|
||||
|
||||
inline LazyScript *
|
||||
NewGCLazyScript(ExclusiveContext *cx)
|
||||
{
|
||||
return gc::AllocateNonObject<LazyScript, CanGC>(cx);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline BaseShape *
|
||||
NewGCBaseShape(ExclusiveContext *cx)
|
||||
{
|
||||
return gc::AllocateNonObject<BaseShape, allowGC>(cx);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgcinlines_h */
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "jstypes.h"
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "js/Class.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "builtin/MapObject.h"
|
||||
#include "builtin/TypedObject.h"
|
||||
#include "gc/Allocator.h"
|
||||
#include "vm/ArrayObject.h"
|
||||
#include "vm/DateObject.h"
|
||||
#include "vm/NumberObject.h"
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
|
||||
#include "vm/Shape.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
#include "vm/Shape-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
|
@ -120,6 +120,7 @@ UNIFIED_SOURCES += [
|
|||
'frontend/ParseMaps.cpp',
|
||||
'frontend/ParseNode.cpp',
|
||||
'frontend/TokenStream.cpp',
|
||||
'gc/Allocator.cpp',
|
||||
'gc/Barrier.cpp',
|
||||
'gc/GCTrace.cpp',
|
||||
'gc/Iteration.cpp',
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "vm/ArrayObject.h"
|
||||
|
||||
#include "gc/GCTrace.h"
|
||||
#include "vm/String.h"
|
||||
|
||||
#include "vm/TypeInference-inl.h"
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "vm/ArrayObject.h"
|
||||
#include "vm/UnboxedObject.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "vm/ProxyObject.h"
|
||||
|
||||
#include "jscompartment.h"
|
||||
#include "jsgcinlines.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
using namespace js;
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
|
||||
#include "jscompartment.h"
|
||||
|
||||
#include "gc/Allocator.h"
|
||||
#include "gc/GCTrace.h"
|
||||
#include "vm/Probes.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
inline bool
|
||||
|
@ -25,13 +25,13 @@ NewObjectCache::lookupProto(const Class *clasp, JSObject *proto, gc::AllocKind k
|
|||
}
|
||||
|
||||
inline bool
|
||||
NewObjectCache::lookupGlobal(const Class *clasp, js::GlobalObject *global, gc::AllocKind kind, EntryIndex *pentry)
|
||||
NewObjectCache::lookupGlobal(const Class *clasp, GlobalObject *global, gc::AllocKind kind, EntryIndex *pentry)
|
||||
{
|
||||
return lookup(clasp, global, kind, pentry);
|
||||
}
|
||||
|
||||
inline void
|
||||
NewObjectCache::fillGlobal(EntryIndex entry, const Class *clasp, js::GlobalObject *global,
|
||||
NewObjectCache::fillGlobal(EntryIndex entry, const Class *clasp, GlobalObject *global,
|
||||
gc::AllocKind kind, NativeObject *obj)
|
||||
{
|
||||
//MOZ_ASSERT(global == obj->getGlobal());
|
||||
|
@ -39,7 +39,7 @@ NewObjectCache::fillGlobal(EntryIndex entry, const Class *clasp, js::GlobalObjec
|
|||
}
|
||||
|
||||
inline NativeObject *
|
||||
NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, js::gc::InitialHeap heap)
|
||||
NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, gc::InitialHeap heap)
|
||||
{
|
||||
// The new object cache does not account for metadata attached via callbacks.
|
||||
MOZ_ASSERT(!cx->compartment()->hasObjectMetadataCallback());
|
||||
|
@ -59,11 +59,11 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, js::gc::I
|
|||
if (cx->runtime()->gc.upcomingZealousGC())
|
||||
return nullptr;
|
||||
|
||||
NativeObject *obj = js::gc::AllocateObjectForCacheHit<NoGC>(cx, entry->kind, heap, group->clasp());
|
||||
NativeObject *obj = gc::AllocateObjectForCacheHit<NoGC>(cx, entry->kind, heap, group->clasp());
|
||||
if (obj) {
|
||||
copyCachedToObject(obj, templateObj, entry->kind);
|
||||
probes::CreateObject(cx, obj);
|
||||
js::gc::TraceCreateObject(obj);
|
||||
gc::TraceCreateObject(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, js::gc::I
|
|||
// take the slow allocation path. The callee is responsible for ensuring
|
||||
// that the index it uses to fill the cache is still correct after this GC.
|
||||
mozilla::DebugOnly<JSObject *> obj2 =
|
||||
js::gc::AllocateObjectForCacheHit<CanGC>(cx, entry->kind, heap, group->clasp());
|
||||
gc::AllocateObjectForCacheHit<CanGC>(cx, entry->kind, heap, group->clasp());
|
||||
MOZ_ASSERT(!obj2);
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
|
||||
#include "jsobj.h"
|
||||
|
||||
#include "gc/Allocator.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/ScopeObject.h"
|
||||
#include "vm/TypedArrayCommon.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -14,10 +14,9 @@
|
|||
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "gc/Allocator.h"
|
||||
#include "gc/Marking.h"
|
||||
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
// Allocate a thin inline string if possible, and a fat inline string if not.
|
||||
|
|
|
@ -10,11 +10,11 @@
|
|||
#include "jscompartment.h"
|
||||
|
||||
#include "builtin/SymbolObject.h"
|
||||
#include "gc/Allocator.h"
|
||||
#include "gc/Rooting.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
|
||||
#include "jscompartmentinlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
|
||||
using JS::Symbol;
|
||||
using namespace js;
|
||||
|
@ -26,7 +26,7 @@ Symbol::newInternal(ExclusiveContext *cx, JS::SymbolCode code, JSAtom *descripti
|
|||
MOZ_ASSERT(cx->atomsCompartment()->runtimeFromAnyThread()->currentThreadHasExclusiveAccess());
|
||||
|
||||
// Following js::AtomizeString, we grudgingly forgo last-ditch GC here.
|
||||
Symbol *p = gc::AllocateNonObject<Symbol, NoGC>(cx);
|
||||
Symbol *p = NewGCSymbol<NoGC>(cx);
|
||||
if (!p) {
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#include "vm/UnboxedObject.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jsgcinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
|
Загрузка…
Ссылка в новой задаче