tor-browser

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

CompactBuffer.h (6615B)


      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 #ifndef jit_Compactbuffer_h
      8 #define jit_Compactbuffer_h
      9 
     10 #include "mozilla/Assertions.h"
     11 
     12 #include <stddef.h>
     13 #include <stdint.h>
     14 
     15 #include "js/AllocPolicy.h"
     16 #include "js/Vector.h"
     17 
     18 namespace js {
     19 namespace jit {
     20 
     21 class CompactBufferWriter;
     22 
     23 // CompactBuffers are byte streams designed for compressable integers. It has
     24 // helper functions for writing bytes, fixed-size integers, and variable-sized
     25 // integers. Variable sized integers are encoded in 1-5 bytes, each byte
     26 // containing 7 bits of the integer and a bit which specifies whether the next
     27 // byte is also part of the integer.
     28 //
     29 // Fixed-width integers are also available, in case the actual value will not
     30 // be known until later.
     31 
     32 class CompactBufferReader {
     33  const uint8_t* buffer_;
     34  const uint8_t* end_;
     35 
     36  uint32_t readVariableLength() {
     37    uint32_t val = 0;
     38    uint32_t shift = 0;
     39    uint8_t byte;
     40    while (true) {
     41      MOZ_ASSERT(shift < 32);
     42      byte = readByte();
     43      val |= (uint32_t(byte) >> 1) << shift;
     44      shift += 7;
     45      if (!(byte & 1)) {
     46        return val;
     47      }
     48    }
     49  }
     50 
     51  uint64_t readVariableLength64() {
     52    uint64_t val = 0;
     53    uint32_t shift = 0;
     54    uint8_t byte;
     55    while (true) {
     56      MOZ_ASSERT(shift < 64);
     57      byte = readByte();
     58      val |= (uint64_t(byte) >> 1) << shift;
     59      shift += 7;
     60      if (!(byte & 1)) {
     61        return val;
     62      }
     63    }
     64  }
     65 
     66 public:
     67  CompactBufferReader(const uint8_t* start, const uint8_t* end)
     68      : buffer_(start), end_(end) {}
     69  inline explicit CompactBufferReader(const CompactBufferWriter& writer);
     70  uint8_t readByte() {
     71    MOZ_ASSERT(buffer_ < end_);
     72    return *buffer_++;
     73  }
     74  uint32_t readFixedUint32_t() {
     75    uint32_t b0 = readByte();
     76    uint32_t b1 = readByte();
     77    uint32_t b2 = readByte();
     78    uint32_t b3 = readByte();
     79    return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
     80  }
     81  uint16_t readFixedUint16_t() {
     82    uint32_t b0 = readByte();
     83    uint32_t b1 = readByte();
     84    return b0 | (b1 << 8);
     85  }
     86  uint16_t peekFixedUint16_t() {
     87    uint32_t b0 = buffer_[0];
     88    uint32_t b1 = buffer_[1];
     89    return b0 | (b1 << 8);
     90  }
     91  uint32_t readNativeEndianUint32_t() {
     92    // Must be at 4-byte boundary
     93    MOZ_ASSERT(uintptr_t(buffer_) % sizeof(uint32_t) == 0);
     94    return *reinterpret_cast<const uint32_t*>(buffer_);
     95  }
     96  uint32_t readUnsigned() { return readVariableLength(); }
     97  uint64_t readUnsigned64() { return readVariableLength64(); }
     98  int32_t readSigned() {
     99    uint8_t b = readByte();
    100    bool isNegative = !!(b & (1 << 0));
    101    bool more = !!(b & (1 << 1));
    102    int32_t result = b >> 2;
    103    if (more) {
    104      result |= readUnsigned() << 6;
    105    }
    106    if (isNegative) {
    107      return -result;
    108    }
    109    return result;
    110  }
    111  void* readRawPointer() {
    112    uintptr_t ptrWord = 0;
    113    for (unsigned i = 0; i < sizeof(uintptr_t); i++) {
    114      ptrWord |= static_cast<uintptr_t>(readByte()) << (i * 8);
    115    }
    116    return reinterpret_cast<void*>(ptrWord);
    117  }
    118 
    119  bool more() const {
    120    MOZ_ASSERT(buffer_ <= end_);
    121    return buffer_ < end_;
    122  }
    123 
    124  void seek(const uint8_t* start, uint32_t offset) {
    125    buffer_ = start + offset;
    126    MOZ_ASSERT(start < end_);
    127    MOZ_ASSERT(buffer_ <= end_);
    128  }
    129 
    130  const uint8_t* currentPosition() const { return buffer_; }
    131 };
    132 
    133 class CompactBufferWriter {
    134  js::Vector<uint8_t, 32, SystemAllocPolicy> buffer_;
    135  bool enoughMemory_;
    136 
    137 public:
    138  CompactBufferWriter() : enoughMemory_(true) {}
    139 
    140  void setOOM() { enoughMemory_ = false; }
    141 
    142  // Note: writeByte() takes uint32 to catch implicit casts with a runtime
    143  // assert.
    144  void writeByte(uint32_t byte) {
    145    MOZ_ASSERT(byte <= 0xFF);
    146    if (!buffer_.append(byte)) {
    147      enoughMemory_ = false;
    148    }
    149  }
    150  void writeByteAt(uint32_t pos, uint32_t byte) {
    151    MOZ_ASSERT(byte <= 0xFF);
    152    if (!oom()) {
    153      buffer_[pos] = byte;
    154    }
    155  }
    156  void writeUnsigned(uint32_t value) {
    157    do {
    158      uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F);
    159      writeByte(byte);
    160      value >>= 7;
    161    } while (value);
    162  }
    163  void writeUnsignedAt(uint32_t pos, uint32_t value, uint32_t original) {
    164    MOZ_ASSERT(value <= original);
    165    do {
    166      uint8_t byte = ((value & 0x7F) << 1) | (original > 0x7F);
    167      writeByteAt(pos++, byte);
    168      value >>= 7;
    169      original >>= 7;
    170    } while (original);
    171  }
    172  void writeUnsigned64(uint64_t value) {
    173    do {
    174      uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F);
    175      writeByte(byte);
    176      value >>= 7;
    177    } while (value);
    178  }
    179  void writeSigned(int32_t v) {
    180    bool isNegative = v < 0;
    181    uint32_t value = isNegative ? -v : v;
    182    uint8_t byte =
    183        ((value & 0x3F) << 2) | ((value > 0x3F) << 1) | uint32_t(isNegative);
    184    writeByte(byte);
    185 
    186    // Write out the rest of the bytes, if needed.
    187    value >>= 6;
    188    if (value == 0) {
    189      return;
    190    }
    191    writeUnsigned(value);
    192  }
    193  void writeFixedUint32_t(uint32_t value) {
    194    writeByte(value & 0xFF);
    195    writeByte((value >> 8) & 0xFF);
    196    writeByte((value >> 16) & 0xFF);
    197    writeByte((value >> 24) & 0xFF);
    198  }
    199  void writeFixedUint16_t(uint16_t value) {
    200    writeByte(value & 0xFF);
    201    writeByte(value >> 8);
    202  }
    203  void writeNativeEndianUint32_t(uint32_t value) {
    204    // Must be at 4-byte boundary
    205    MOZ_ASSERT_IF(!oom(), length() % sizeof(uint32_t) == 0);
    206    writeFixedUint32_t(0);
    207    if (oom()) {
    208      return;
    209    }
    210    uint8_t* endPtr = buffer() + length();
    211    reinterpret_cast<uint32_t*>(endPtr)[-1] = value;
    212  }
    213  void writeRawPointer(const void* ptr) {
    214    uintptr_t ptrWord = reinterpret_cast<uintptr_t>(ptr);
    215    for (unsigned i = 0; i < sizeof(uintptr_t); i++) {
    216      writeByte((ptrWord >> (i * 8)) & 0xFF);
    217    }
    218  }
    219  void writeBytes(const uint8_t* data, size_t len) {
    220    if (!buffer_.append(data, len)) {
    221      enoughMemory_ = false;
    222    }
    223  }
    224  size_t length() const { return buffer_.length(); }
    225  uint8_t* buffer() {
    226    MOZ_ASSERT(!oom());
    227    return &buffer_[0];
    228  }
    229  const uint8_t* buffer() const {
    230    MOZ_ASSERT(!oom());
    231    return &buffer_[0];
    232  }
    233  bool oom() const { return !enoughMemory_; }
    234  void propagateOOM(bool success) { enoughMemory_ &= success; }
    235 };
    236 
    237 CompactBufferReader::CompactBufferReader(const CompactBufferWriter& writer)
    238    : buffer_(writer.buffer()), end_(writer.buffer() + writer.length()) {}
    239 
    240 }  // namespace jit
    241 }  // namespace js
    242 
    243 #endif /* jit_Compactbuffer_h */