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.

     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 */

mercurial