js/public/HeapAPI.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef js_HeapAPI_h
michael@0 8 #define js_HeapAPI_h
michael@0 9
michael@0 10 #include <limits.h>
michael@0 11
michael@0 12 #include "jspubtd.h"
michael@0 13
michael@0 14 #include "js/Utility.h"
michael@0 15
michael@0 16 /* These values are private to the JS engine. */
michael@0 17 namespace js {
michael@0 18
michael@0 19 // Whether the current thread is permitted access to any part of the specified
michael@0 20 // runtime or zone.
michael@0 21 JS_FRIEND_API(bool)
michael@0 22 CurrentThreadCanAccessRuntime(JSRuntime *rt);
michael@0 23
michael@0 24 JS_FRIEND_API(bool)
michael@0 25 CurrentThreadCanAccessZone(JS::Zone *zone);
michael@0 26
michael@0 27 namespace gc {
michael@0 28
michael@0 29 struct Cell;
michael@0 30
michael@0 31 const size_t ArenaShift = 12;
michael@0 32 const size_t ArenaSize = size_t(1) << ArenaShift;
michael@0 33 const size_t ArenaMask = ArenaSize - 1;
michael@0 34
michael@0 35 const size_t ChunkShift = 20;
michael@0 36 const size_t ChunkSize = size_t(1) << ChunkShift;
michael@0 37 const size_t ChunkMask = ChunkSize - 1;
michael@0 38
michael@0 39 const size_t CellShift = 3;
michael@0 40 const size_t CellSize = size_t(1) << CellShift;
michael@0 41 const size_t CellMask = CellSize - 1;
michael@0 42
michael@0 43 /* These are magic constants derived from actual offsets in gc/Heap.h. */
michael@0 44 const size_t ChunkMarkBitmapOffset = 1032360;
michael@0 45 const size_t ChunkMarkBitmapBits = 129024;
michael@0 46 const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*);
michael@0 47 const size_t ChunkLocationOffset = ChunkSize - sizeof(void*) - sizeof(uintptr_t);
michael@0 48
michael@0 49 /*
michael@0 50 * Live objects are marked black. How many other additional colors are available
michael@0 51 * depends on the size of the GCThing. Objects marked gray are eligible for
michael@0 52 * cycle collection.
michael@0 53 */
michael@0 54 static const uint32_t BLACK = 0;
michael@0 55 static const uint32_t GRAY = 1;
michael@0 56
michael@0 57 /*
michael@0 58 * Constants used to indicate whether a chunk is part of the tenured heap or the
michael@0 59 * nusery.
michael@0 60 */
michael@0 61 const uintptr_t ChunkLocationNursery = 0;
michael@0 62 const uintptr_t ChunkLocationTenuredHeap = 1;
michael@0 63
michael@0 64 } /* namespace gc */
michael@0 65 } /* namespace js */
michael@0 66
michael@0 67 namespace JS {
michael@0 68 struct Zone;
michael@0 69 } /* namespace JS */
michael@0 70
michael@0 71 namespace JS {
michael@0 72 namespace shadow {
michael@0 73
michael@0 74 struct ArenaHeader
michael@0 75 {
michael@0 76 JS::Zone *zone;
michael@0 77 };
michael@0 78
michael@0 79 struct Zone
michael@0 80 {
michael@0 81 protected:
michael@0 82 JSRuntime *const runtime_;
michael@0 83 JSTracer *const barrierTracer_; // A pointer to the JSRuntime's |gcMarker|.
michael@0 84
michael@0 85 public:
michael@0 86 bool needsBarrier_;
michael@0 87
michael@0 88 Zone(JSRuntime *runtime, JSTracer *barrierTracerArg)
michael@0 89 : runtime_(runtime),
michael@0 90 barrierTracer_(barrierTracerArg),
michael@0 91 needsBarrier_(false)
michael@0 92 {}
michael@0 93
michael@0 94 bool needsBarrier() const {
michael@0 95 return needsBarrier_;
michael@0 96 }
michael@0 97
michael@0 98 JSTracer *barrierTracer() {
michael@0 99 MOZ_ASSERT(needsBarrier_);
michael@0 100 MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
michael@0 101 return barrierTracer_;
michael@0 102 }
michael@0 103
michael@0 104 JSRuntime *runtimeFromMainThread() const {
michael@0 105 MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime_));
michael@0 106 return runtime_;
michael@0 107 }
michael@0 108
michael@0 109 // Note: Unrestricted access to the zone's runtime from an arbitrary
michael@0 110 // thread can easily lead to races. Use this method very carefully.
michael@0 111 JSRuntime *runtimeFromAnyThread() const {
michael@0 112 return runtime_;
michael@0 113 }
michael@0 114
michael@0 115 static JS::shadow::Zone *asShadowZone(JS::Zone *zone) {
michael@0 116 return reinterpret_cast<JS::shadow::Zone*>(zone);
michael@0 117 }
michael@0 118 };
michael@0 119
michael@0 120 } /* namespace shadow */
michael@0 121 } /* namespace JS */
michael@0 122
michael@0 123 namespace js {
michael@0 124 namespace gc {
michael@0 125
michael@0 126 static MOZ_ALWAYS_INLINE uintptr_t *
michael@0 127 GetGCThingMarkBitmap(const void *thing)
michael@0 128 {
michael@0 129 MOZ_ASSERT(thing);
michael@0 130 uintptr_t addr = uintptr_t(thing);
michael@0 131 addr &= ~js::gc::ChunkMask;
michael@0 132 addr |= js::gc::ChunkMarkBitmapOffset;
michael@0 133 return reinterpret_cast<uintptr_t *>(addr);
michael@0 134 }
michael@0 135
michael@0 136 static MOZ_ALWAYS_INLINE JS::shadow::Runtime *
michael@0 137 GetGCThingRuntime(const void *thing)
michael@0 138 {
michael@0 139 MOZ_ASSERT(thing);
michael@0 140 uintptr_t addr = uintptr_t(thing);
michael@0 141 addr &= ~js::gc::ChunkMask;
michael@0 142 addr |= js::gc::ChunkRuntimeOffset;
michael@0 143 return *reinterpret_cast<JS::shadow::Runtime **>(addr);
michael@0 144 }
michael@0 145
michael@0 146 static MOZ_ALWAYS_INLINE void
michael@0 147 GetGCThingMarkWordAndMask(const void *thing, uint32_t color,
michael@0 148 uintptr_t **wordp, uintptr_t *maskp)
michael@0 149 {
michael@0 150 uintptr_t addr = uintptr_t(thing);
michael@0 151 size_t bit = (addr & js::gc::ChunkMask) / js::gc::CellSize + color;
michael@0 152 MOZ_ASSERT(bit < js::gc::ChunkMarkBitmapBits);
michael@0 153 uintptr_t *bitmap = GetGCThingMarkBitmap(thing);
michael@0 154 const uintptr_t nbits = sizeof(*bitmap) * CHAR_BIT;
michael@0 155 *maskp = uintptr_t(1) << (bit % nbits);
michael@0 156 *wordp = &bitmap[bit / nbits];
michael@0 157 }
michael@0 158
michael@0 159 static MOZ_ALWAYS_INLINE JS::shadow::ArenaHeader *
michael@0 160 GetGCThingArena(void *thing)
michael@0 161 {
michael@0 162 uintptr_t addr = uintptr_t(thing);
michael@0 163 addr &= ~js::gc::ArenaMask;
michael@0 164 return reinterpret_cast<JS::shadow::ArenaHeader *>(addr);
michael@0 165 }
michael@0 166
michael@0 167 MOZ_ALWAYS_INLINE bool
michael@0 168 IsInsideNursery(const JS::shadow::Runtime *runtime, const void *p)
michael@0 169 {
michael@0 170 #ifdef JSGC_GENERATIONAL
michael@0 171 return uintptr_t(p) >= runtime->gcNurseryStart_ && uintptr_t(p) < runtime->gcNurseryEnd_;
michael@0 172 #else
michael@0 173 return false;
michael@0 174 #endif
michael@0 175 }
michael@0 176
michael@0 177 MOZ_ALWAYS_INLINE bool
michael@0 178 IsInsideNursery(const js::gc::Cell *cell)
michael@0 179 {
michael@0 180 #ifdef JSGC_GENERATIONAL
michael@0 181 if (!cell)
michael@0 182 return false;
michael@0 183 uintptr_t addr = uintptr_t(cell);
michael@0 184 addr &= ~js::gc::ChunkMask;
michael@0 185 addr |= js::gc::ChunkLocationOffset;
michael@0 186 uint32_t location = *reinterpret_cast<uint32_t *>(addr);
michael@0 187 JS_ASSERT(location == gc::ChunkLocationNursery ||
michael@0 188 location == gc::ChunkLocationTenuredHeap);
michael@0 189 return location == gc::ChunkLocationNursery;
michael@0 190 #else
michael@0 191 return false;
michael@0 192 #endif
michael@0 193 }
michael@0 194
michael@0 195 } /* namespace gc */
michael@0 196
michael@0 197 } /* namespace js */
michael@0 198
michael@0 199 namespace JS {
michael@0 200
michael@0 201 static MOZ_ALWAYS_INLINE Zone *
michael@0 202 GetGCThingZone(void *thing)
michael@0 203 {
michael@0 204 MOZ_ASSERT(thing);
michael@0 205 return js::gc::GetGCThingArena(thing)->zone;
michael@0 206 }
michael@0 207
michael@0 208 static MOZ_ALWAYS_INLINE Zone *
michael@0 209 GetObjectZone(JSObject *obj)
michael@0 210 {
michael@0 211 return GetGCThingZone(obj);
michael@0 212 }
michael@0 213
michael@0 214 static MOZ_ALWAYS_INLINE bool
michael@0 215 GCThingIsMarkedGray(void *thing)
michael@0 216 {
michael@0 217 #ifdef JSGC_GENERATIONAL
michael@0 218 /*
michael@0 219 * GC things residing in the nursery cannot be gray: they have no mark bits.
michael@0 220 * All live objects in the nursery are moved to tenured at the beginning of
michael@0 221 * each GC slice, so the gray marker never sees nursery things.
michael@0 222 */
michael@0 223 JS::shadow::Runtime *rt = js::gc::GetGCThingRuntime(thing);
michael@0 224 if (js::gc::IsInsideNursery(rt, thing))
michael@0 225 return false;
michael@0 226 #endif
michael@0 227 uintptr_t *word, mask;
michael@0 228 js::gc::GetGCThingMarkWordAndMask(thing, js::gc::GRAY, &word, &mask);
michael@0 229 return *word & mask;
michael@0 230 }
michael@0 231
michael@0 232 static MOZ_ALWAYS_INLINE bool
michael@0 233 IsIncrementalBarrierNeededOnGCThing(shadow::Runtime *rt, void *thing, JSGCTraceKind kind)
michael@0 234 {
michael@0 235 if (!rt->needsBarrier_)
michael@0 236 return false;
michael@0 237 JS::Zone *zone = GetGCThingZone(thing);
michael@0 238 return reinterpret_cast<shadow::Zone *>(zone)->needsBarrier_;
michael@0 239 }
michael@0 240
michael@0 241 } /* namespace JS */
michael@0 242
michael@0 243 #endif /* js_HeapAPI_h */

mercurial