michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef js_HeapAPI_h michael@0: #define js_HeapAPI_h michael@0: michael@0: #include michael@0: michael@0: #include "jspubtd.h" michael@0: michael@0: #include "js/Utility.h" michael@0: michael@0: /* These values are private to the JS engine. */ michael@0: namespace js { michael@0: michael@0: // Whether the current thread is permitted access to any part of the specified michael@0: // runtime or zone. michael@0: JS_FRIEND_API(bool) michael@0: CurrentThreadCanAccessRuntime(JSRuntime *rt); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: CurrentThreadCanAccessZone(JS::Zone *zone); michael@0: michael@0: namespace gc { michael@0: michael@0: struct Cell; michael@0: michael@0: const size_t ArenaShift = 12; michael@0: const size_t ArenaSize = size_t(1) << ArenaShift; michael@0: const size_t ArenaMask = ArenaSize - 1; michael@0: michael@0: const size_t ChunkShift = 20; michael@0: const size_t ChunkSize = size_t(1) << ChunkShift; michael@0: const size_t ChunkMask = ChunkSize - 1; michael@0: michael@0: const size_t CellShift = 3; michael@0: const size_t CellSize = size_t(1) << CellShift; michael@0: const size_t CellMask = CellSize - 1; michael@0: michael@0: /* These are magic constants derived from actual offsets in gc/Heap.h. */ michael@0: const size_t ChunkMarkBitmapOffset = 1032360; michael@0: const size_t ChunkMarkBitmapBits = 129024; michael@0: const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); michael@0: const size_t ChunkLocationOffset = ChunkSize - sizeof(void*) - sizeof(uintptr_t); michael@0: michael@0: /* michael@0: * Live objects are marked black. How many other additional colors are available michael@0: * depends on the size of the GCThing. Objects marked gray are eligible for michael@0: * cycle collection. michael@0: */ michael@0: static const uint32_t BLACK = 0; michael@0: static const uint32_t GRAY = 1; michael@0: michael@0: /* michael@0: * Constants used to indicate whether a chunk is part of the tenured heap or the michael@0: * nusery. michael@0: */ michael@0: const uintptr_t ChunkLocationNursery = 0; michael@0: const uintptr_t ChunkLocationTenuredHeap = 1; michael@0: michael@0: } /* namespace gc */ michael@0: } /* namespace js */ michael@0: michael@0: namespace JS { michael@0: struct Zone; michael@0: } /* namespace JS */ michael@0: michael@0: namespace JS { michael@0: namespace shadow { michael@0: michael@0: struct ArenaHeader michael@0: { michael@0: JS::Zone *zone; michael@0: }; michael@0: michael@0: struct Zone michael@0: { michael@0: protected: michael@0: JSRuntime *const runtime_; michael@0: JSTracer *const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|. michael@0: michael@0: public: michael@0: bool needsBarrier_; michael@0: michael@0: Zone(JSRuntime *runtime, JSTracer *barrierTracerArg) michael@0: : runtime_(runtime), michael@0: barrierTracer_(barrierTracerArg), michael@0: needsBarrier_(false) michael@0: {} michael@0: michael@0: bool needsBarrier() const { michael@0: return needsBarrier_; michael@0: } michael@0: michael@0: JSTracer *barrierTracer() { michael@0: MOZ_ASSERT(needsBarrier_); michael@0: MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); michael@0: return barrierTracer_; michael@0: } michael@0: michael@0: JSRuntime *runtimeFromMainThread() const { michael@0: MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); michael@0: return runtime_; michael@0: } michael@0: michael@0: // Note: Unrestricted access to the zone's runtime from an arbitrary michael@0: // thread can easily lead to races. Use this method very carefully. michael@0: JSRuntime *runtimeFromAnyThread() const { michael@0: return runtime_; michael@0: } michael@0: michael@0: static JS::shadow::Zone *asShadowZone(JS::Zone *zone) { michael@0: return reinterpret_cast(zone); michael@0: } michael@0: }; michael@0: michael@0: } /* namespace shadow */ michael@0: } /* namespace JS */ michael@0: michael@0: namespace js { michael@0: namespace gc { michael@0: michael@0: static MOZ_ALWAYS_INLINE uintptr_t * michael@0: GetGCThingMarkBitmap(const void *thing) michael@0: { michael@0: MOZ_ASSERT(thing); michael@0: uintptr_t addr = uintptr_t(thing); michael@0: addr &= ~js::gc::ChunkMask; michael@0: addr |= js::gc::ChunkMarkBitmapOffset; michael@0: return reinterpret_cast(addr); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE JS::shadow::Runtime * michael@0: GetGCThingRuntime(const void *thing) michael@0: { michael@0: MOZ_ASSERT(thing); michael@0: uintptr_t addr = uintptr_t(thing); michael@0: addr &= ~js::gc::ChunkMask; michael@0: addr |= js::gc::ChunkRuntimeOffset; michael@0: return *reinterpret_cast(addr); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE void michael@0: GetGCThingMarkWordAndMask(const void *thing, uint32_t color, michael@0: uintptr_t **wordp, uintptr_t *maskp) michael@0: { michael@0: uintptr_t addr = uintptr_t(thing); michael@0: size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color; michael@0: MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits); michael@0: uintptr_t *bitmap = GetGCThingMarkBitmap(thing); michael@0: const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT; michael@0: *maskp = uintptr_t(1) << (bit % nbits); michael@0: *wordp = &bitmap[bit / nbits]; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE JS::shadow::ArenaHeader * michael@0: GetGCThingArena(void *thing) michael@0: { michael@0: uintptr_t addr = uintptr_t(thing); michael@0: addr &= ~js::gc::ArenaMask; michael@0: return reinterpret_cast(addr); michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: IsInsideNursery(const JS::shadow::Runtime *runtime, const void *p) michael@0: { michael@0: #ifdef JSGC_GENERATIONAL michael@0: return uintptr_t(p) >= runtime->gcNurseryStart_ && uintptr_t(p) < runtime->gcNurseryEnd_; michael@0: #else michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: MOZ_ALWAYS_INLINE bool michael@0: IsInsideNursery(const js::gc::Cell *cell) michael@0: { michael@0: #ifdef JSGC_GENERATIONAL michael@0: if (!cell) michael@0: return false; michael@0: uintptr_t addr = uintptr_t(cell); michael@0: addr &= ~js::gc::ChunkMask; michael@0: addr |= js::gc::ChunkLocationOffset; michael@0: uint32_t location = *reinterpret_cast(addr); michael@0: JS_ASSERT(location == gc::ChunkLocationNursery || michael@0: location == gc::ChunkLocationTenuredHeap); michael@0: return location == gc::ChunkLocationNursery; michael@0: #else michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: } /* namespace gc */ michael@0: michael@0: } /* namespace js */ michael@0: michael@0: namespace JS { michael@0: michael@0: static MOZ_ALWAYS_INLINE Zone * michael@0: GetGCThingZone(void *thing) michael@0: { michael@0: MOZ_ASSERT(thing); michael@0: return js::gc::GetGCThingArena(thing)->zone; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE Zone * michael@0: GetObjectZone(JSObject *obj) michael@0: { michael@0: return GetGCThingZone(obj); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: GCThingIsMarkedGray(void *thing) michael@0: { michael@0: #ifdef JSGC_GENERATIONAL michael@0: /* michael@0: * GC things residing in the nursery cannot be gray: they have no mark bits. michael@0: * All live objects in the nursery are moved to tenured at the beginning of michael@0: * each GC slice, so the gray marker never sees nursery things. michael@0: */ michael@0: JS::shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing); michael@0: if (js::gc::IsInsideNursery(rt, thing)) michael@0: return false; michael@0: #endif michael@0: uintptr_t *word, mask; michael@0: js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask); michael@0: return *word & mask; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: IsIncrementalBarrierNeededOnGCThing(shadow::Runtime *rt, void *thing, JSGCTraceKind kind) michael@0: { michael@0: if (!rt->needsBarrier_) michael@0: return false; michael@0: JS::Zone *zone = GetGCThingZone(thing); michael@0: return reinterpret_cast(zone)->needsBarrier_; michael@0: } michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: #endif /* js_HeapAPI_h */