mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-09-30 03:58:07 +00:00
204 lines
5.6 KiB
C++
204 lines
5.6 KiB
C++
/* -*- 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 */
|