blob: 87960bddbcee06a408fb7bfb8efcd64e39d4d52f [file] [log] [blame]
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 "jsalloc.h"
#include "jit/IonTypes.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;
}
}
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();
}
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;
}
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);
enoughMemory_ &= buffer_.append(byte);
}
void writeByteAt(uint32_t pos, uint32_t byte) {
MOZ_ASSERT(byte <= 0xFF);
if (!oom())
buffer_[pos] = byte;
}
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 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;
}
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_;
}
};
CompactBufferReader::CompactBufferReader(const CompactBufferWriter& writer)
: buffer_(writer.buffer()),
end_(writer.buffer() + writer.length())
{
}
} // namespace jit
} // namespace js
#endif /* jit_Compactbuffer_h */