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