tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

MallocProvider.h (8098B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      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/. */
      6 
      7 /*
      8 * Hierarchy of SpiderMonkey system memory allocators:
      9 *
     10 *   - System {m,c,re}alloc/new/free: Overridden by jemalloc in most
     11 *     environments. Do not use these functions directly.
     12 *
     13 *   - js_{m,c,re}alloc/new/free: Wraps the system allocators and adds a
     14 *     failure injection framework for use by the fuzzers as well as templated,
     15 *     typesafe variants. See js/public/Utility.h.
     16 *
     17 *   - AllocPolicy: An interface for the js allocators, for use with templates.
     18 *     These allocators are for system memory whose lifetime is not associated
     19 *     with a GC thing. See js/public/AllocPolicy.h.
     20 *
     21 *       - SystemAllocPolicy: No extra functionality over bare allocators.
     22 *
     23 *       - TempAllocPolicy: Adds automatic error reporting to the provided
     24 *         JSContext when allocations fail.
     25 *
     26 *       - ZoneAllocPolicy: Forwards to the Zone MallocProvider.
     27 *
     28 *   - MallocProvider. A mixin base class that handles automatically updating
     29 *     the GC's state in response to allocations that are tied to a GC lifetime
     30 *     or are for a particular GC purpose. These allocators must only be used
     31 *     for memory that will be freed when a GC thing is swept.
     32 *
     33 *       - gc::Zone:  Automatically triggers zone GC.
     34 *       - JSRuntime: Automatically triggers full GC.
     35 *       - JSContext: Dispatches directly to the runtime.
     36 */
     37 
     38 #ifndef vm_MallocProvider_h
     39 #define vm_MallocProvider_h
     40 
     41 #include "mozilla/Attributes.h"  // MOZ_ALWAYS_INLINE
     42 #include "mozilla/Likely.h"      // MOZ_LIKELY, MOZ_UNLIKELY
     43 
     44 #include <stddef.h>  // size_t
     45 #include <stdint.h>  // uint8_t
     46 
     47 #include "js/AllocPolicy.h"  // AllocFunction
     48 #include "js/UniquePtr.h"    // UniquePtr
     49 #include "js/Utility.h"  // js_malloc, MallocArena, CalculateAllocSize, CalculateAllocSizeWithExtra, JS::FreePolicy
     50 
     51 namespace js {
     52 
     53 template <class Client>
     54 struct MallocProvider {
     55  template <class T>
     56  T* maybe_pod_arena_malloc(arena_id_t arena, size_t numElems) {
     57    T* p = js_pod_arena_malloc<T>(arena, numElems);
     58    if (MOZ_LIKELY(p)) {
     59      client()->updateMallocCounter(numElems * sizeof(T));
     60    }
     61    return p;
     62  }
     63 
     64  template <class T>
     65  T* maybe_pod_arena_calloc(arena_id_t arena, size_t numElems) {
     66    T* p = js_pod_arena_calloc<T>(arena, numElems);
     67    if (MOZ_LIKELY(p)) {
     68      client()->updateMallocCounter(numElems * sizeof(T));
     69    }
     70    return p;
     71  }
     72 
     73  template <class T>
     74  T* maybe_pod_arena_realloc(arena_id_t arena, T* prior, size_t oldSize,
     75                             size_t newSize) {
     76    T* p = js_pod_arena_realloc<T>(arena, prior, oldSize, newSize);
     77    if (MOZ_LIKELY(p)) {
     78      // For compatibility we do not account for realloc that decreases
     79      // previously allocated memory.
     80      if (newSize > oldSize) {
     81        client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
     82      }
     83    }
     84    return p;
     85  }
     86 
     87  template <class T>
     88  T* maybe_pod_malloc(size_t numElems) {
     89    return maybe_pod_arena_malloc<T>(js::MallocArena, numElems);
     90  }
     91 
     92  template <class T>
     93  T* maybe_pod_calloc(size_t numElems) {
     94    return maybe_pod_arena_calloc<T>(js::MallocArena, numElems);
     95  }
     96 
     97  template <class T>
     98  T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) {
     99    return maybe_pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize);
    100  }
    101 
    102  template <class T>
    103  T* pod_malloc() {
    104    return pod_malloc<T>(1);
    105  }
    106 
    107  template <class T>
    108  T* pod_arena_malloc(arena_id_t arena, size_t numElems) {
    109    T* p = maybe_pod_arena_malloc<T>(arena, numElems);
    110    if (MOZ_LIKELY(p)) {
    111      return p;
    112    }
    113    size_t bytes;
    114    if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
    115      client()->reportAllocationOverflow();
    116      return nullptr;
    117    }
    118    p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, arena, bytes);
    119    if (p) {
    120      client()->updateMallocCounter(bytes);
    121    }
    122    return p;
    123  }
    124 
    125  template <class T>
    126  T* pod_malloc(size_t numElems) {
    127    return pod_arena_malloc<T>(js::MallocArena, numElems);
    128  }
    129 
    130  template <class T, class U>
    131  T* pod_malloc_with_extra(size_t numExtra) {
    132    size_t bytes;
    133    if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
    134      client()->reportAllocationOverflow();
    135      return nullptr;
    136    }
    137    T* p = static_cast<T*>(js_malloc(bytes));
    138    if (MOZ_LIKELY(p)) {
    139      client()->updateMallocCounter(bytes);
    140      return p;
    141    }
    142    p = (T*)client()->onOutOfMemory(AllocFunction::Malloc, js::MallocArena,
    143                                    bytes);
    144    if (p) {
    145      client()->updateMallocCounter(bytes);
    146    }
    147    return p;
    148  }
    149 
    150  template <class T>
    151  UniquePtr<T[], JS::FreePolicy> make_pod_arena_array(arena_id_t arena,
    152                                                      size_t numElems) {
    153    return UniquePtr<T[], JS::FreePolicy>(pod_arena_malloc<T>(arena, numElems));
    154  }
    155 
    156  template <class T>
    157  UniquePtr<T[], JS::FreePolicy> make_pod_array(size_t numElems) {
    158    return make_pod_arena_array<T>(js::MallocArena, numElems);
    159  }
    160 
    161  template <class T>
    162  T* pod_arena_calloc(arena_id_t arena, size_t numElems = 1) {
    163    T* p = maybe_pod_arena_calloc<T>(arena, numElems);
    164    if (MOZ_LIKELY(p)) {
    165      return p;
    166    }
    167    size_t bytes;
    168    if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
    169      client()->reportAllocationOverflow();
    170      return nullptr;
    171    }
    172    p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, arena, bytes);
    173    if (p) {
    174      client()->updateMallocCounter(bytes);
    175    }
    176    return p;
    177  }
    178 
    179  template <class T>
    180  T* pod_calloc(size_t numElems = 1) {
    181    return pod_arena_calloc<T>(js::MallocArena, numElems);
    182  }
    183 
    184  template <class T, class U>
    185  T* pod_calloc_with_extra(size_t numExtra) {
    186    size_t bytes;
    187    if (MOZ_UNLIKELY((!CalculateAllocSizeWithExtra<T, U>(numExtra, &bytes)))) {
    188      client()->reportAllocationOverflow();
    189      return nullptr;
    190    }
    191    T* p = static_cast<T*>(js_calloc(bytes));
    192    if (p) {
    193      client()->updateMallocCounter(bytes);
    194      return p;
    195    }
    196    p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, js::MallocArena,
    197                                    bytes);
    198    if (p) {
    199      client()->updateMallocCounter(bytes);
    200    }
    201    return p;
    202  }
    203 
    204  template <class T>
    205  UniquePtr<T[], JS::FreePolicy> make_zeroed_pod_array(size_t numElems) {
    206    return UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems));
    207  }
    208 
    209  template <class T>
    210  T* pod_arena_realloc(arena_id_t arena, T* prior, size_t oldSize,
    211                       size_t newSize) {
    212    T* p = maybe_pod_arena_realloc(arena, prior, oldSize, newSize);
    213    if (MOZ_LIKELY(p)) {
    214      return p;
    215    }
    216    size_t bytes;
    217    if (MOZ_UNLIKELY(!CalculateAllocSize<T>(newSize, &bytes))) {
    218      client()->reportAllocationOverflow();
    219      return nullptr;
    220    }
    221    p = (T*)client()->onOutOfMemory(AllocFunction::Realloc, arena, bytes,
    222                                    prior);
    223    if (p && newSize > oldSize) {
    224      client()->updateMallocCounter((newSize - oldSize) * sizeof(T));
    225    }
    226    return p;
    227  }
    228 
    229  template <class T>
    230  T* pod_realloc(T* prior, size_t oldSize, size_t newSize) {
    231    return pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize);
    232  }
    233 
    234  JS_DECLARE_NEW_METHODS(new_, pod_malloc<uint8_t>, MOZ_ALWAYS_INLINE)
    235  JS_DECLARE_NEW_ARENA_METHODS(
    236      arena_new_,
    237      [this](arena_id_t arena, size_t size) {
    238        return pod_malloc<uint8_t>(size, arena);
    239      },
    240      MOZ_ALWAYS_INLINE)
    241 
    242  JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE)
    243  JS_DECLARE_MAKE_METHODS(arena_make_unique, arena_new_, MOZ_ALWAYS_INLINE)
    244 
    245 private:
    246  Client* client() { return static_cast<Client*>(this); }
    247 
    248  // The Default implementation is a no-op which can be overridden by the
    249  // client.
    250  void updateMallocCounter(size_t nbytes) {}
    251 };
    252 
    253 } /* namespace js */
    254 
    255 #endif /* vm_MallocProvider_h */