js/public/HeapAPI.h

changeset 0
6474c204b198
     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 */

mercurial