michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jit_Compactbuffer_h michael@0: #define jit_Compactbuffer_h michael@0: michael@0: #include "jsalloc.h" michael@0: michael@0: #include "jit/IonTypes.h" michael@0: #include "js/Vector.h" michael@0: michael@0: namespace js { michael@0: namespace jit { michael@0: michael@0: class CompactBufferWriter; michael@0: michael@0: // CompactBuffers are byte streams designed for compressable integers. It has michael@0: // helper functions for writing bytes, fixed-size integers, and variable-sized michael@0: // integers. Variable sized integers are encoded in 1-5 bytes, each byte michael@0: // containing 7 bits of the integer and a bit which specifies whether the next michael@0: // byte is also part of the integer. michael@0: // michael@0: // Fixed-width integers are also available, in case the actual value will not michael@0: // be known until later. michael@0: michael@0: class CompactBufferReader michael@0: { michael@0: const uint8_t *buffer_; michael@0: const uint8_t *end_; michael@0: michael@0: uint32_t readVariableLength() { michael@0: uint32_t val = 0; michael@0: uint32_t shift = 0; michael@0: uint8_t byte; michael@0: while (true) { michael@0: JS_ASSERT(shift < 32); michael@0: byte = readByte(); michael@0: val |= (uint32_t(byte) >> 1) << shift; michael@0: shift += 7; michael@0: if (!(byte & 1)) michael@0: return val; michael@0: } michael@0: MOZ_ASSUME_UNREACHABLE("unreachable"); michael@0: } michael@0: michael@0: public: michael@0: CompactBufferReader(const uint8_t *start, const uint8_t *end) michael@0: : buffer_(start), michael@0: end_(end) michael@0: { } michael@0: inline CompactBufferReader(const CompactBufferWriter &writer); michael@0: uint8_t readByte() { michael@0: JS_ASSERT(buffer_ < end_); michael@0: return *buffer_++; michael@0: } michael@0: uint32_t readFixedUint32_t() { michael@0: uint32_t b0 = readByte(); michael@0: uint32_t b1 = readByte(); michael@0: uint32_t b2 = readByte(); michael@0: uint32_t b3 = readByte(); michael@0: return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); michael@0: } michael@0: uint16_t readFixedUint16_t() { michael@0: uint32_t b0 = readByte(); michael@0: uint32_t b1 = readByte(); michael@0: return b0 | (b1 << 8); michael@0: } michael@0: uint32_t readUnsigned() { michael@0: return readVariableLength(); michael@0: } michael@0: int32_t readSigned() { michael@0: uint8_t b = readByte(); michael@0: bool isNegative = !!(b & (1 << 0)); michael@0: bool more = !!(b & (1 << 1)); michael@0: int32_t result = b >> 2; michael@0: if (more) michael@0: result |= readUnsigned() << 6; michael@0: if (isNegative) michael@0: return -result; michael@0: return result; michael@0: } michael@0: michael@0: bool more() const { michael@0: JS_ASSERT(buffer_ <= end_); michael@0: return buffer_ < end_; michael@0: } michael@0: michael@0: void seek(const uint8_t *start, uint32_t offset) { michael@0: buffer_ = start + offset; michael@0: MOZ_ASSERT(start < end_); michael@0: MOZ_ASSERT(buffer_ < end_); michael@0: } michael@0: }; michael@0: michael@0: class CompactBufferWriter michael@0: { michael@0: js::Vector buffer_; michael@0: bool enoughMemory_; michael@0: michael@0: public: michael@0: CompactBufferWriter() michael@0: : enoughMemory_(true) michael@0: { } michael@0: michael@0: // Note: writeByte() takes uint32 to catch implicit casts with a runtime michael@0: // assert. michael@0: void writeByte(uint32_t byte) { michael@0: JS_ASSERT(byte <= 0xFF); michael@0: enoughMemory_ &= buffer_.append(byte); michael@0: } michael@0: void writeUnsigned(uint32_t value) { michael@0: do { michael@0: uint8_t byte = ((value & 0x7F) << 1) | (value > 0x7F); michael@0: writeByte(byte); michael@0: value >>= 7; michael@0: } while (value); michael@0: } michael@0: void writeSigned(int32_t v) { michael@0: bool isNegative = v < 0; michael@0: uint32_t value = isNegative ? -v : v; michael@0: uint8_t byte = ((value & 0x3F) << 2) | ((value > 0x3F) << 1) | uint32_t(isNegative); michael@0: writeByte(byte); michael@0: michael@0: // Write out the rest of the bytes, if needed. michael@0: value >>= 6; michael@0: if (value == 0) michael@0: return; michael@0: writeUnsigned(value); michael@0: } michael@0: void writeFixedUint32_t(uint32_t value) { michael@0: writeByte(value & 0xFF); michael@0: writeByte((value >> 8) & 0xFF); michael@0: writeByte((value >> 16) & 0xFF); michael@0: writeByte((value >> 24) & 0xFF); michael@0: } michael@0: void writeFixedUint16_t(uint16_t value) { michael@0: writeByte(value & 0xFF); michael@0: writeByte(value >> 8); michael@0: } michael@0: size_t length() const { michael@0: return buffer_.length(); michael@0: } michael@0: uint8_t *buffer() { michael@0: return &buffer_[0]; michael@0: } michael@0: const uint8_t *buffer() const { michael@0: return &buffer_[0]; michael@0: } michael@0: bool oom() const { michael@0: return !enoughMemory_; michael@0: } michael@0: }; michael@0: michael@0: CompactBufferReader::CompactBufferReader(const CompactBufferWriter &writer) michael@0: : buffer_(writer.buffer()), michael@0: end_(writer.buffer() + writer.length()) michael@0: { michael@0: } michael@0: michael@0: } // namespace jit michael@0: } // namespace js michael@0: michael@0: #endif /* jit_Compactbuffer_h */