diff -r 000000000000 -r 6474c204b198 js/public/HeapAPI.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/public/HeapAPI.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,243 @@ +/* -*- 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 js_HeapAPI_h +#define js_HeapAPI_h + +#include + +#include "jspubtd.h" + +#include "js/Utility.h" + +/* These values are private to the JS engine. */ +namespace js { + +// Whether the current thread is permitted access to any part of the specified +// runtime or zone. +JS_FRIEND_API(bool) +CurrentThreadCanAccessRuntime(JSRuntime *rt); + +JS_FRIEND_API(bool) +CurrentThreadCanAccessZone(JS::Zone *zone); + +namespace gc { + +struct Cell; + +const size_t ArenaShift = 12; +const size_t ArenaSize = size_t(1) << ArenaShift; +const size_t ArenaMask = ArenaSize - 1; + +const size_t ChunkShift = 20; +const size_t ChunkSize = size_t(1) << ChunkShift; +const size_t ChunkMask = ChunkSize - 1; + +const size_t CellShift = 3; +const size_t CellSize = size_t(1) << CellShift; +const size_t CellMask = CellSize - 1; + +/* These are magic constants derived from actual offsets in gc/Heap.h. */ +const size_t ChunkMarkBitmapOffset = 1032360; +const size_t ChunkMarkBitmapBits = 129024; +const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); +const size_t ChunkLocationOffset = ChunkSize - sizeof(void*) - sizeof(uintptr_t); + +/* + * Live objects are marked black. How many other additional colors are available + * depends on the size of the GCThing. Objects marked gray are eligible for + * cycle collection. + */ +static const uint32_t BLACK = 0; +static const uint32_t GRAY = 1; + +/* + * Constants used to indicate whether a chunk is part of the tenured heap or the + * nusery. + */ +const uintptr_t ChunkLocationNursery = 0; +const uintptr_t ChunkLocationTenuredHeap = 1; + +} /* namespace gc */ +} /* namespace js */ + +namespace JS { +struct Zone; +} /* namespace JS */ + +namespace JS { +namespace shadow { + +struct ArenaHeader +{ + JS::Zone *zone; +}; + +struct Zone +{ + protected: + JSRuntime *const runtime_; + JSTracer *const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|. + + public: + bool needsBarrier_; + + Zone(JSRuntime *runtime, JSTracer *barrierTracerArg) + : runtime_(runtime), + barrierTracer_(barrierTracerArg), + needsBarrier_(false) + {} + + bool needsBarrier() const { + return needsBarrier_; + } + + JSTracer *barrierTracer() { + MOZ_ASSERT(needsBarrier_); + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); + return barrierTracer_; + } + + JSRuntime *runtimeFromMainThread() const { + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); + return runtime_; + } + + // Note: Unrestricted access to the zone's runtime from an arbitrary + // thread can easily lead to races. Use this method very carefully. + JSRuntime *runtimeFromAnyThread() const { + return runtime_; + } + + static JS::shadow::Zone *asShadowZone(JS::Zone *zone) { + return reinterpret_cast(zone); + } +}; + +} /* namespace shadow */ +} /* namespace JS */ + +namespace js { +namespace gc { + +static MOZ_ALWAYS_INLINE uintptr_t * +GetGCThingMarkBitmap(const void *thing) +{ + MOZ_ASSERT(thing); + uintptr_t addr = uintptr_t(thing); + addr &= ~js::gc::ChunkMask; + addr |= js::gc::ChunkMarkBitmapOffset; + return reinterpret_cast(addr); +} + +static MOZ_ALWAYS_INLINE JS::shadow::Runtime * +GetGCThingRuntime(const void *thing) +{ + MOZ_ASSERT(thing); + uintptr_t addr = uintptr_t(thing); + addr &= ~js::gc::ChunkMask; + addr |= js::gc::ChunkRuntimeOffset; + return *reinterpret_cast(addr); +} + +static MOZ_ALWAYS_INLINE void +GetGCThingMarkWordAndMask(const void *thing, uint32_t color, + uintptr_t **wordp, uintptr_t *maskp) +{ + uintptr_t addr = uintptr_t(thing); + size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color; + MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits); + uintptr_t *bitmap = GetGCThingMarkBitmap(thing); + const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT; + *maskp = uintptr_t(1) << (bit % nbits); + *wordp = &bitmap[bit / nbits]; +} + +static MOZ_ALWAYS_INLINE JS::shadow::ArenaHeader * +GetGCThingArena(void *thing) +{ + uintptr_t addr = uintptr_t(thing); + addr &= ~js::gc::ArenaMask; + return reinterpret_cast(addr); +} + +MOZ_ALWAYS_INLINE bool +IsInsideNursery(const JS::shadow::Runtime *runtime, const void *p) +{ +#ifdef JSGC_GENERATIONAL + return uintptr_t(p) >= runtime->gcNurseryStart_ && uintptr_t(p) < runtime->gcNurseryEnd_; +#else + return false; +#endif +} + +MOZ_ALWAYS_INLINE bool +IsInsideNursery(const js::gc::Cell *cell) +{ +#ifdef JSGC_GENERATIONAL + if (!cell) + return false; + uintptr_t addr = uintptr_t(cell); + addr &= ~js::gc::ChunkMask; + addr |= js::gc::ChunkLocationOffset; + uint32_t location = *reinterpret_cast(addr); + JS_ASSERT(location == gc::ChunkLocationNursery || + location == gc::ChunkLocationTenuredHeap); + return location == gc::ChunkLocationNursery; +#else + return false; +#endif +} + +} /* namespace gc */ + +} /* namespace js */ + +namespace JS { + +static MOZ_ALWAYS_INLINE Zone * +GetGCThingZone(void *thing) +{ + MOZ_ASSERT(thing); + return js::gc::GetGCThingArena(thing)->zone; +} + +static MOZ_ALWAYS_INLINE Zone * +GetObjectZone(JSObject *obj) +{ + return GetGCThingZone(obj); +} + +static MOZ_ALWAYS_INLINE bool +GCThingIsMarkedGray(void *thing) +{ +#ifdef JSGC_GENERATIONAL + /* + * GC things residing in the nursery cannot be gray: they have no mark bits. + * All live objects in the nursery are moved to tenured at the beginning of + * each GC slice, so the gray marker never sees nursery things. + */ + JS::shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing); + if (js::gc::IsInsideNursery(rt, thing)) + return false; +#endif + uintptr_t *word, mask; + js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask); + return *word & mask; +} + +static MOZ_ALWAYS_INLINE bool +IsIncrementalBarrierNeededOnGCThing(shadow::Runtime *rt, void *thing, JSGCTraceKind kind) +{ + if (!rt->needsBarrier_) + return false; + JS::Zone *zone = GetGCThingZone(thing); + return reinterpret_cast(zone)->needsBarrier_; +} + +} /* namespace JS */ + +#endif /* js_HeapAPI_h */