1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/public/HeapAPI.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,243 @@ 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 +#ifndef js_HeapAPI_h 1.11 +#define js_HeapAPI_h 1.12 + 1.13 +#include <limits.h> 1.14 + 1.15 +#include "jspubtd.h" 1.16 + 1.17 +#include "js/Utility.h" 1.18 + 1.19 +/* These values are private to the JS engine. */ 1.20 +namespace js { 1.21 + 1.22 +// Whether the current thread is permitted access to any part of the specified 1.23 +// runtime or zone. 1.24 +JS_FRIEND_API(bool) 1.25 +CurrentThreadCanAccessRuntime(JSRuntime *rt); 1.26 + 1.27 +JS_FRIEND_API(bool) 1.28 +CurrentThreadCanAccessZone(JS::Zone *zone); 1.29 + 1.30 +namespace gc { 1.31 + 1.32 +struct Cell; 1.33 + 1.34 +const size_t ArenaShift = 12; 1.35 +const size_t ArenaSize = size_t(1) << ArenaShift; 1.36 +const size_t ArenaMask = ArenaSize - 1; 1.37 + 1.38 +const size_t ChunkShift = 20; 1.39 +const size_t ChunkSize = size_t(1) << ChunkShift; 1.40 +const size_t ChunkMask = ChunkSize - 1; 1.41 + 1.42 +const size_t CellShift = 3; 1.43 +const size_t CellSize = size_t(1) << CellShift; 1.44 +const size_t CellMask = CellSize - 1; 1.45 + 1.46 +/* These are magic constants derived from actual offsets in gc/Heap.h. */ 1.47 +const size_t ChunkMarkBitmapOffset = 1032360; 1.48 +const size_t ChunkMarkBitmapBits = 129024; 1.49 +const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); 1.50 +const size_t ChunkLocationOffset = ChunkSize - sizeof(void*) - sizeof(uintptr_t); 1.51 + 1.52 +/* 1.53 + * Live objects are marked black. How many other additional colors are available 1.54 + * depends on the size of the GCThing. Objects marked gray are eligible for 1.55 + * cycle collection. 1.56 + */ 1.57 +static const uint32_t BLACK = 0; 1.58 +static const uint32_t GRAY = 1; 1.59 + 1.60 +/* 1.61 + * Constants used to indicate whether a chunk is part of the tenured heap or the 1.62 + * nusery. 1.63 + */ 1.64 +const uintptr_t ChunkLocationNursery = 0; 1.65 +const uintptr_t ChunkLocationTenuredHeap = 1; 1.66 + 1.67 +} /* namespace gc */ 1.68 +} /* namespace js */ 1.69 + 1.70 +namespace JS { 1.71 +struct Zone; 1.72 +} /* namespace JS */ 1.73 + 1.74 +namespace JS { 1.75 +namespace shadow { 1.76 + 1.77 +struct ArenaHeader 1.78 +{ 1.79 + JS::Zone *zone; 1.80 +}; 1.81 + 1.82 +struct Zone 1.83 +{ 1.84 + protected: 1.85 + JSRuntime *const runtime_; 1.86 + JSTracer *const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|. 1.87 + 1.88 + public: 1.89 + bool needsBarrier_; 1.90 + 1.91 + Zone(JSRuntime *runtime, JSTracer *barrierTracerArg) 1.92 + : runtime_(runtime), 1.93 + barrierTracer_(barrierTracerArg), 1.94 + needsBarrier_(false) 1.95 + {} 1.96 + 1.97 + bool needsBarrier() const { 1.98 + return needsBarrier_; 1.99 + } 1.100 + 1.101 + JSTracer *barrierTracer() { 1.102 + MOZ_ASSERT(needsBarrier_); 1.103 + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); 1.104 + return barrierTracer_; 1.105 + } 1.106 + 1.107 + JSRuntime *runtimeFromMainThread() const { 1.108 + MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_)); 1.109 + return runtime_; 1.110 + } 1.111 + 1.112 + // Note: Unrestricted access to the zone's runtime from an arbitrary 1.113 + // thread can easily lead to races. Use this method very carefully. 1.114 + JSRuntime *runtimeFromAnyThread() const { 1.115 + return runtime_; 1.116 + } 1.117 + 1.118 + static JS::shadow::Zone *asShadowZone(JS::Zone *zone) { 1.119 + return reinterpret_cast<JS::shadow::Zone*>(zone); 1.120 + } 1.121 +}; 1.122 + 1.123 +} /* namespace shadow */ 1.124 +} /* namespace JS */ 1.125 + 1.126 +namespace js { 1.127 +namespace gc { 1.128 + 1.129 +static MOZ_ALWAYS_INLINE uintptr_t * 1.130 +GetGCThingMarkBitmap(const void *thing) 1.131 +{ 1.132 + MOZ_ASSERT(thing); 1.133 + uintptr_t addr = uintptr_t(thing); 1.134 + addr &= ~js::gc::ChunkMask; 1.135 + addr |= js::gc::ChunkMarkBitmapOffset; 1.136 + return reinterpret_cast<uintptr_t *>(addr); 1.137 +} 1.138 + 1.139 +static MOZ_ALWAYS_INLINE JS::shadow::Runtime * 1.140 +GetGCThingRuntime(const void *thing) 1.141 +{ 1.142 + MOZ_ASSERT(thing); 1.143 + uintptr_t addr = uintptr_t(thing); 1.144 + addr &= ~js::gc::ChunkMask; 1.145 + addr |= js::gc::ChunkRuntimeOffset; 1.146 + return *reinterpret_cast<JS::shadow::Runtime **>(addr); 1.147 +} 1.148 + 1.149 +static MOZ_ALWAYS_INLINE void 1.150 +GetGCThingMarkWordAndMask(const void *thing, uint32_t color, 1.151 + uintptr_t **wordp, uintptr_t *maskp) 1.152 +{ 1.153 + uintptr_t addr = uintptr_t(thing); 1.154 + size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color; 1.155 + MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits); 1.156 + uintptr_t *bitmap = GetGCThingMarkBitmap(thing); 1.157 + const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT; 1.158 + *maskp = uintptr_t(1) << (bit % nbits); 1.159 + *wordp = &bitmap[bit / nbits]; 1.160 +} 1.161 + 1.162 +static MOZ_ALWAYS_INLINE JS::shadow::ArenaHeader * 1.163 +GetGCThingArena(void *thing) 1.164 +{ 1.165 + uintptr_t addr = uintptr_t(thing); 1.166 + addr &= ~js::gc::ArenaMask; 1.167 + return reinterpret_cast<JS::shadow::ArenaHeader *>(addr); 1.168 +} 1.169 + 1.170 +MOZ_ALWAYS_INLINE bool 1.171 +IsInsideNursery(const JS::shadow::Runtime *runtime, const void *p) 1.172 +{ 1.173 +#ifdef JSGC_GENERATIONAL 1.174 + return uintptr_t(p) >= runtime->gcNurseryStart_ && uintptr_t(p) < runtime->gcNurseryEnd_; 1.175 +#else 1.176 + return false; 1.177 +#endif 1.178 +} 1.179 + 1.180 +MOZ_ALWAYS_INLINE bool 1.181 +IsInsideNursery(const js::gc::Cell *cell) 1.182 +{ 1.183 +#ifdef JSGC_GENERATIONAL 1.184 + if (!cell) 1.185 + return false; 1.186 + uintptr_t addr = uintptr_t(cell); 1.187 + addr &= ~js::gc::ChunkMask; 1.188 + addr |= js::gc::ChunkLocationOffset; 1.189 + uint32_t location = *reinterpret_cast<uint32_t *>(addr); 1.190 + JS_ASSERT(location == gc::ChunkLocationNursery || 1.191 + location == gc::ChunkLocationTenuredHeap); 1.192 + return location == gc::ChunkLocationNursery; 1.193 +#else 1.194 + return false; 1.195 +#endif 1.196 +} 1.197 + 1.198 +} /* namespace gc */ 1.199 + 1.200 +} /* namespace js */ 1.201 + 1.202 +namespace JS { 1.203 + 1.204 +static MOZ_ALWAYS_INLINE Zone * 1.205 +GetGCThingZone(void *thing) 1.206 +{ 1.207 + MOZ_ASSERT(thing); 1.208 + return js::gc::GetGCThingArena(thing)->zone; 1.209 +} 1.210 + 1.211 +static MOZ_ALWAYS_INLINE Zone * 1.212 +GetObjectZone(JSObject *obj) 1.213 +{ 1.214 + return GetGCThingZone(obj); 1.215 +} 1.216 + 1.217 +static MOZ_ALWAYS_INLINE bool 1.218 +GCThingIsMarkedGray(void *thing) 1.219 +{ 1.220 +#ifdef JSGC_GENERATIONAL 1.221 + /* 1.222 + * GC things residing in the nursery cannot be gray: they have no mark bits. 1.223 + * All live objects in the nursery are moved to tenured at the beginning of 1.224 + * each GC slice, so the gray marker never sees nursery things. 1.225 + */ 1.226 + JS::shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing); 1.227 + if (js::gc::IsInsideNursery(rt, thing)) 1.228 + return false; 1.229 +#endif 1.230 + uintptr_t *word, mask; 1.231 + js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask); 1.232 + return *word & mask; 1.233 +} 1.234 + 1.235 +static MOZ_ALWAYS_INLINE bool 1.236 +IsIncrementalBarrierNeededOnGCThing(shadow::Runtime *rt, void *thing, JSGCTraceKind kind) 1.237 +{ 1.238 + if (!rt->needsBarrier_) 1.239 + return false; 1.240 + JS::Zone *zone = GetGCThingZone(thing); 1.241 + return reinterpret_cast<shadow::Zone *>(zone)->needsBarrier_; 1.242 +} 1.243 + 1.244 +} /* namespace JS */ 1.245 + 1.246 +#endif /* js_HeapAPI_h */