summaryrefslogtreecommitdiffstats
path: root/js/src/jit/CompactBuffer.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/CompactBuffer.h')
-rw-r--r--js/src/jit/CompactBuffer.h254
1 files changed, 254 insertions, 0 deletions
diff --git a/js/src/jit/CompactBuffer.h b/js/src/jit/CompactBuffer.h
new file mode 100644
index 0000000000..2c7fefcb9a
--- /dev/null
+++ b/js/src/jit/CompactBuffer.h
@@ -0,0 +1,254 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_Compactbuffer_h
+#define jit_Compactbuffer_h
+
+#include "mozilla/Assertions.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "js/AllocPolicy.h"
+#include "js/Vector.h"
+
+namespace js {
+namespace jit {
+
+class CompactBufferWriter;
+
+// CompactBuffers are byte streams designed for compressable integers. It has
+// helper functions for writing bytes, fixed-size integers, and variable-sized
+// integers. Variable sized integers are encoded in 1-5 bytes, each byte
+// containing 7 bits of the integer and a bit which specifies whether the next
+// byte is also part of the integer.
+//
+// Fixed-width integers are also available, in case the actual value will not
+// be known until later.
+
+class CompactBufferReader {
+ const uint8_t* buffer_;
+ const uint8_t* end_;
+
+ uint32_t readVariableLength() {
+ uint32_t val = 0;
+ uint32_t shift = 0;
+ uint8_t byte;
+ while (true) {
+ MOZ_ASSERT(shift < 32);
+ byte = readByte();
+ val |= (uint32_t(byte) >> 1) << shift;
+ shift += 7;
+ if (!(byte & 1)) {
+ return val;
+ }
+ }
+ }
+
+ uint64_t readVariableLength64() {
+ uint64_t val = 0;
+ uint32_t shift = 0;
+ uint8_t byte;
+ while (true) {
+ MOZ_ASSERT(shift < 64);
+ byte = readByte();
+ val |= (uint64_t(byte) >> 1) << shift;
+ shift += 7;
+ if (!(byte & 1)) {
+ return val;
+ }
+ }
+ }
+
+ public:
+ CompactBufferReader(const uint8_t* start, const uint8_t* end)
+ : buffer_(start), end_(end) {}
+ inline explicit CompactBufferReader(const CompactBufferWriter& writer);
+ uint8_t readByte() {
+ MOZ_ASSERT(buffer_ < end_);
+ return *buffer_++;
+ }
+ uint32_t readFixedUint32_t() {
+ uint32_t b0 = readByte();
+ uint32_t b1 = readByte();
+ uint32_t b2 = readByte();
+ uint32_t b3 = readByte();
+ return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
+ }
+ uint16_t readFixedUint16_t() {
+ uint32_t b0 = readByte();
+ uint32_t b1 = readByte();
+ return b0 | (b1 << 8);
+ }
+ uint32_t readNativeEndianUint32_t() {
+ // Must be at 4-byte boundary
+ MOZ_ASSERT(uintptr_t(buffer_) % sizeof(uint32_t) == 0);
+ return *reinterpret_cast<const uint32_t*>(buffer_);
+ }
+ uint32_t readUnsigned() { return readVariableLength(); }
+ uint64_t readUnsigned64() { return readVariableLength64(); }
+ int32_t readSigned() {
+ uint8_t b = readByte();
+ bool isNegative = !!(b & (1 << 0));
+ bool more = !!(b & (1 << 1));
+ int32_t result = b >> 2;
+ if (more) {
+ result |= readUnsigned() << 6;
+ }
+ if (isNegative) {
+ return -result;
+ }
+ return result;
+ }
+ // Reads a value written by writeUnsigned15Bit.
+ uint32_t readUnsigned15Bit() {
+ uint8_t byte = readByte();
+ uint32_t val = byte >> 1;
+ if (byte & 1) {
+ val |= uint32_t(readByte()) << 7;
+ }
+ return val;
+ }
+ void* readRawPointer() {
+ uintptr_t ptrWord = 0;
+ for (unsigned i = 0; i < sizeof(uintptr_t); i++) {
+ ptrWord |= static_cast<uintptr_t>(readByte()) << (i * 8);
+ }
+ return reinterpret_cast<void*>(ptrWord);
+ }
+
+ bool more() const {
+ MOZ_ASSERT(buffer_ <= end_);
+ return buffer_ < end_;
+ }
+
+ void seek(const uint8_t* start, uint32_t offset) {
+ buffer_ = start + offset;
+ MOZ_ASSERT(start < end_);
+ MOZ_ASSERT(buffer_ <= end_);
+ }
+
+ const uint8_t* currentPosition() const { return buffer_; }
+};
+
+class CompactBufferWriter {
+ js::Vector<uint8_t, 32, SystemAllocPolicy> buffer_;
+ bool enoughMemory_;
+
+ public:
+ CompactBufferWriter() : enoughMemory_(true) {}
+
+ void setOOM() { enoughMemory_ = false; }
+
+ // Note: writeByte() takes uint32 to catch implicit casts with a runtime
+ // assert.
+ void writeByte(uint32_t byte) {
+ MOZ_ASSERT(byte <= 0xFF);
+ if (!buffer_.append(byte)) {
+ enoughMemory_ = false;
+ }
+ }
+ void writeByteAt(uint32_t pos, uint32_t byte) {
+ MOZ_ASSERT(byte <= 0xFF);
+ if (!oom()) {
+ buffer_[pos] = byte;
+ }
+ }
+ // Writes a variable-length value similar to writeUnsigned, but optimized for
+ // small 15-bit values that fit in one or two variable-length-encoded bytes.
+ // Must be read using readUnsigned15Bit.
+ void writeUnsigned15Bit(uint32_t value) {
+ uint8_t byte1 = ((value & 0x7F) << 1) | (value > 0x7F);
+ writeByte(byte1);
+ value >>= 7;
+ if (value) {
+ MOZ_ASSERT(value <= 0xFF);
+ writeByte(value);
+ }
+ }
+ void writeUnsigned(uint32_t value) {
+ do {
+ uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F);
+ writeByte(byte);
+ value >>= 7;
+ } while (value);
+ }
+ void writeUnsignedAt(uint32_t pos, uint32_t value, uint32_t original) {
+ MOZ_ASSERT(value <= original);
+ do {
+ uint8_t byte = ((value & 0x7F) << 1) | (original > 0x7F);
+ writeByteAt(pos++, byte);
+ value >>= 7;
+ original >>= 7;
+ } while (original);
+ }
+ void writeUnsigned64(uint64_t value) {
+ do {
+ uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F);
+ writeByte(byte);
+ value >>= 7;
+ } while (value);
+ }
+ void writeSigned(int32_t v) {
+ bool isNegative = v < 0;
+ uint32_t value = isNegative ? -v : v;
+ uint8_t byte =
+ ((value & 0x3F) << 2) | ((value > 0x3F) << 1) | uint32_t(isNegative);
+ writeByte(byte);
+
+ // Write out the rest of the bytes, if needed.
+ value >>= 6;
+ if (value == 0) {
+ return;
+ }
+ writeUnsigned(value);
+ }
+ void writeFixedUint32_t(uint32_t value) {
+ writeByte(value & 0xFF);
+ writeByte((value >> 8) & 0xFF);
+ writeByte((value >> 16) & 0xFF);
+ writeByte((value >> 24) & 0xFF);
+ }
+ void writeFixedUint16_t(uint16_t value) {
+ writeByte(value & 0xFF);
+ writeByte(value >> 8);
+ }
+ void writeNativeEndianUint32_t(uint32_t value) {
+ // Must be at 4-byte boundary
+ MOZ_ASSERT_IF(!oom(), length() % sizeof(uint32_t) == 0);
+ writeFixedUint32_t(0);
+ if (oom()) {
+ return;
+ }
+ uint8_t* endPtr = buffer() + length();
+ reinterpret_cast<uint32_t*>(endPtr)[-1] = value;
+ }
+ void writeRawPointer(const void* ptr) {
+ uintptr_t ptrWord = reinterpret_cast<uintptr_t>(ptr);
+ for (unsigned i = 0; i < sizeof(uintptr_t); i++) {
+ writeByte((ptrWord >> (i * 8)) & 0xFF);
+ }
+ }
+ size_t length() const { return buffer_.length(); }
+ uint8_t* buffer() {
+ MOZ_ASSERT(!oom());
+ return &buffer_[0];
+ }
+ const uint8_t* buffer() const {
+ MOZ_ASSERT(!oom());
+ return &buffer_[0];
+ }
+ bool oom() const { return !enoughMemory_; }
+ void propagateOOM(bool success) { enoughMemory_ &= success; }
+};
+
+CompactBufferReader::CompactBufferReader(const CompactBufferWriter& writer)
+ : buffer_(writer.buffer()), end_(writer.buffer() + writer.length()) {}
+
+} // namespace jit
+} // namespace js
+
+#endif /* jit_Compactbuffer_h */