tor-browser

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

AssemblerBuffer-x86-shared.h (8060B)


      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 *
      4 * ***** BEGIN LICENSE BLOCK *****
      5 * Copyright (C) 2008 Apple Inc. All rights reserved.
      6 *
      7 * Redistribution and use in source and binary forms, with or without
      8 * modification, are permitted provided that the following conditions
      9 * are met:
     10 * 1. Redistributions of source code must retain the above copyright
     11 *    notice, this list of conditions and the following disclaimer.
     12 * 2. Redistributions in binary form must reproduce the above copyright
     13 *    notice, this list of conditions and the following disclaimer in the
     14 *    documentation and/or other materials provided with the distribution.
     15 *
     16 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 *
     28 * ***** END LICENSE BLOCK ***** */
     29 
     30 #ifndef jit_x86_shared_AssemblerBuffer_x86_shared_h
     31 #define jit_x86_shared_AssemblerBuffer_x86_shared_h
     32 
     33 #include "mozilla/Assertions.h"
     34 #include "mozilla/Attributes.h"
     35 #include "mozilla/Likely.h"
     36 #include "mozilla/Vector.h"
     37 
     38 #include <stdarg.h>
     39 #include <stddef.h>
     40 #include <stdint.h>
     41 
     42 #include "jit/JitContext.h"
     43 #include "jit/JitSpewer.h"
     44 #include "jit/ProcessExecutableMemory.h"
     45 #include "js/AllocPolicy.h"
     46 #include "js/Vector.h"
     47 
     48 // Spew formatting helpers.
     49 #define PRETTYHEX(x)      \
     50  (((x) < 0) ? "-" : ""), \
     51      ((unsigned)((x) ^ ((x) >> 31)) + ((unsigned)(x) >> 31))
     52 
     53 #define MEM_o "%s0x%x"
     54 #define MEM_os MEM_o "(,%s,%d)"
     55 #define MEM_ob MEM_o "(%s)"
     56 #define MEM_obs MEM_o "(%s,%s,%d)"
     57 
     58 #define MEM_o32 "%s0x%04x"
     59 #define MEM_o32s MEM_o32 "(,%s,%d)"
     60 #define MEM_o32b MEM_o32 "(%s)"
     61 #define MEM_o32bs MEM_o32 "(%s,%s,%d)"
     62 #define MEM_o32r ".Lfrom%d(%%rip)"
     63 
     64 #define ADDR_o(offset) PRETTYHEX(offset)
     65 #define ADDR_os(offset, index, scale) \
     66  ADDR_o(offset), GPRegName((index)), (1 << (scale))
     67 #define ADDR_ob(offset, base) ADDR_o(offset), GPRegName((base))
     68 #define ADDR_obs(offset, base, index, scale) \
     69  ADDR_ob(offset, base), GPRegName((index)), (1 << (scale))
     70 
     71 #define ADDR_o32(offset) ADDR_o(offset)
     72 #define ADDR_o32s(offset, index, scale) ADDR_os(offset, index, scale)
     73 #define ADDR_o32b(offset, base) ADDR_ob(offset, base)
     74 #define ADDR_o32bs(offset, base, index, scale) \
     75  ADDR_obs(offset, base, index, scale)
     76 #define ADDR_o32r(offset) (offset)
     77 
     78 namespace js {
     79 
     80 class JS_PUBLIC_API Sprinter;
     81 
     82 namespace jit {
     83 
     84 namespace x86_shared {
     85 
     86 // AllocPolicy for AssemblerBuffer. OOMs when trying to allocate more than
     87 // MaxCodeBytesPerProcess bytes. Use private inheritance to make sure we
     88 // explicitly have to expose SystemAllocPolicy methods.
     89 class AssemblerBufferAllocPolicy : private SystemAllocPolicy {
     90 public:
     91  using SystemAllocPolicy::checkSimulatedOOM;
     92  using SystemAllocPolicy::free_;
     93  using SystemAllocPolicy::reportAllocOverflow;
     94 
     95  template <typename T>
     96  T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
     97    static_assert(
     98        sizeof(T) == 1,
     99        "AssemblerBufferAllocPolicy should only be used with byte vectors");
    100    MOZ_ASSERT(oldSize <= MaxCodeBytesPerProcess);
    101    if (MOZ_UNLIKELY(newSize > MaxCodeBytesPerProcess)) {
    102      return nullptr;
    103    }
    104    return SystemAllocPolicy::pod_realloc<T>(p, oldSize, newSize);
    105  }
    106  template <typename T>
    107  T* pod_malloc(size_t numElems) {
    108    static_assert(
    109        sizeof(T) == 1,
    110        "AssemblerBufferAllocPolicy should only be used with byte vectors");
    111    if (MOZ_UNLIKELY(numElems > MaxCodeBytesPerProcess)) {
    112      return nullptr;
    113    }
    114    return SystemAllocPolicy::pod_malloc<T>(numElems);
    115  }
    116 };
    117 
    118 class AssemblerBuffer {
    119  template <size_t size, typename T>
    120  MOZ_ALWAYS_INLINE void sizedAppendUnchecked(T value) {
    121    m_buffer.infallibleAppend(reinterpret_cast<unsigned char*>(&value), size);
    122  }
    123 
    124  template <size_t size, typename T>
    125  MOZ_ALWAYS_INLINE void sizedAppend(T value) {
    126    if (MOZ_UNLIKELY(
    127            !m_buffer.append(reinterpret_cast<unsigned char*>(&value), size))) {
    128      oomDetected();
    129    }
    130  }
    131 
    132 public:
    133  AssemblerBuffer() : m_oom(false) {}
    134 
    135  void ensureSpace(size_t space) {
    136    // This should only be called with small |space| values to ensure
    137    // we don't overflow below.
    138    MOZ_ASSERT(space <= 16);
    139    if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space))) {
    140      oomDetected();
    141    }
    142  }
    143 
    144  bool isAligned(size_t alignment) const {
    145    return !(m_buffer.length() & (alignment - 1));
    146  }
    147 
    148  MOZ_ALWAYS_INLINE void putByteUnchecked(int value) {
    149    sizedAppendUnchecked<1>(value);
    150  }
    151  MOZ_ALWAYS_INLINE void putShortUnchecked(int value) {
    152    sizedAppendUnchecked<2>(value);
    153  }
    154  MOZ_ALWAYS_INLINE void putIntUnchecked(int value) {
    155    sizedAppendUnchecked<4>(value);
    156  }
    157  MOZ_ALWAYS_INLINE void putInt64Unchecked(int64_t value) {
    158    sizedAppendUnchecked<8>(value);
    159  }
    160 
    161  MOZ_ALWAYS_INLINE void putByte(int value) { sizedAppend<1>(value); }
    162  MOZ_ALWAYS_INLINE void putShort(int value) { sizedAppend<2>(value); }
    163  MOZ_ALWAYS_INLINE void putInt(int value) { sizedAppend<4>(value); }
    164  MOZ_ALWAYS_INLINE void putInt64(int64_t value) { sizedAppend<8>(value); }
    165 
    166  [[nodiscard]] bool append(const unsigned char* values, size_t size) {
    167    if (MOZ_UNLIKELY(!m_buffer.append(values, size))) {
    168      oomDetected();
    169      return false;
    170    }
    171    return true;
    172  }
    173 
    174  size_t size() const { return m_buffer.length(); }
    175 
    176  bool oom() const { return m_oom; }
    177 
    178  bool reserve(size_t size) { return !m_oom && m_buffer.reserve(size); }
    179 
    180  bool swap(Vector<uint8_t, 0, SystemAllocPolicy>& bytes);
    181 
    182  const unsigned char* buffer() const {
    183    MOZ_RELEASE_ASSERT(!m_oom);
    184    return m_buffer.begin();
    185  }
    186 
    187  unsigned char* data() { return m_buffer.begin(); }
    188 
    189 protected:
    190  /*
    191   * OOM handling: This class can OOM in the ensureSpace() method trying
    192   * to allocate a new buffer. In response to an OOM, we need to avoid
    193   * crashing and report the error. We also want to make it so that
    194   * users of this class need to check for OOM only at certain points
    195   * and not after every operation.
    196   *
    197   * Our strategy for handling an OOM is to set m_oom, and then clear (but
    198   * not free) m_buffer, preserving the current buffer. This way, the user
    199   * can continue assembling into the buffer, deferring OOM checking
    200   * until the user wants to read code out of the buffer.
    201   *
    202   * See also the |buffer| method.
    203   */
    204  void oomDetected() {
    205    m_oom = true;
    206    m_buffer.clear();
    207 #ifdef DEBUG
    208    JitContext* context = MaybeGetJitContext();
    209    if (context) {
    210      context->setOOM();
    211    }
    212 #endif
    213  }
    214 
    215  mozilla::Vector<unsigned char, 256, AssemblerBufferAllocPolicy> m_buffer;
    216  bool m_oom;
    217 };
    218 
    219 }  // namespace x86_shared
    220 
    221 class GenericAssembler {
    222 #ifdef JS_JITSPEW
    223  Sprinter* printer;
    224 #endif
    225 public:
    226  GenericAssembler()
    227 #ifdef JS_JITSPEW
    228      : printer(nullptr)
    229 #endif
    230  {
    231  }
    232 
    233  void setPrinter(Sprinter* sp) {
    234 #ifdef JS_JITSPEW
    235    printer = sp;
    236 #endif
    237  }
    238 
    239 #ifdef JS_JITSPEW
    240  inline void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {
    241    if (MOZ_UNLIKELY(printer || JitSpewEnabled(JitSpew_Codegen))) {
    242      va_list va;
    243      va_start(va, fmt);
    244      spew(fmt, va);
    245      va_end(va);
    246    }
    247  }
    248 #else
    249  MOZ_ALWAYS_INLINE void spew(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3) {}
    250 #endif
    251 
    252 #ifdef JS_JITSPEW
    253  MOZ_COLD void spew(const char* fmt, va_list va) MOZ_FORMAT_PRINTF(2, 0);
    254 #endif
    255 };
    256 
    257 }  // namespace jit
    258 }  // namespace js
    259 
    260 #endif /* jit_x86_shared_AssemblerBuffer_x86_shared_h */