blob: 397f9c73481779ad9410e23f7a1e95e40f384a33 [file] [log] [blame]
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/datastream.h"
#include "platform/text_buffer.h"
#include "vm/compiler/runtime_api.h"
#include "vm/os.h"
#include "vm/zone.h"
namespace dart {
// Setting up needed variables for the unrolled loop sections below.
#define UNROLLED_INIT() \
using Unsigned = typename std::make_unsigned<T>::type; \
Unsigned b = ReadByte(); \
if ((b & C::kMoreDataMask) == 0) { \
if ((b & C::kSignMask) != 0) { \
b |= ~Utils::NBitMask<Unsigned>(C::kDataBitsPerByte); \
} \
return static_cast<T>(b); \
} \
T r = static_cast<T>(b & C::kDataByteMask);
// Part of the unrolled loop where the loop may stop, having read the last part,
// or continue reading.
#define UNROLLED_BODY(bit_start) \
static_assert(bit_start % C::kDataBitsPerByte == 0, \
"Bit start must be a multiple of the data bits per byte"); \
static_assert(bit_start >= 0 && bit_start < kBitsPerByte * sizeof(T), \
"Starting unrolled body at invalid bit position"); \
static_assert(bit_start + C::kDataBitsPerByte < kBitsPerByte * sizeof(T), \
"Unrolled body should not contain final bits in value"); \
b = ReadByte(); \
r |= static_cast<Unsigned>(b & C::kDataByteMask) << bit_start; \
if ((b & C::kMoreDataMask) == 0) { \
if ((b & C::kSignMask) != 0) { \
r |= ~Utils::NBitMask<T>(bit_start + C::kDataBitsPerByte); \
} \
return r; \
}
// The end of the unrolled loop. Does not need to handle sign extension, as the
// last bits fill the rest of the bitspace.
#define UNROLLED_END(bit_start) \
static_assert(bit_start % C::kDataBitsPerByte == 0, \
"Bit start must be a multiple of the data bits per byte"); \
static_assert(bit_start >= 0 && bit_start < kBitsPerByte * sizeof(T), \
"Starting unrolled end at invalid bit position"); \
static_assert(bit_start + C::kDataBitsPerByte >= kBitsPerByte * sizeof(T), \
"Unrolled end does not contain final bits in value"); \
b = ReadByte(); \
ASSERT_EQUAL((b & C::kMoreDataMask), 0); \
r |= static_cast<Unsigned>(b & C::kDataByteMask) << bit_start; \
return r;
uint16_t ReadStream::Read16() {
using T = uint16_t;
UNROLLED_INIT();
UNROLLED_BODY(7);
UNROLLED_END(14);
}
uint32_t ReadStream::Read32() {
using T = uint32_t;
UNROLLED_INIT();
UNROLLED_BODY(7);
UNROLLED_BODY(14);
UNROLLED_BODY(21);
UNROLLED_END(28);
}
uint64_t ReadStream::Read64() {
using T = uint64_t;
UNROLLED_INIT();
UNROLLED_BODY(7);
UNROLLED_BODY(14);
UNROLLED_BODY(21);
UNROLLED_BODY(28);
UNROLLED_BODY(35);
UNROLLED_BODY(42);
UNROLLED_BODY(49);
UNROLLED_BODY(56);
UNROLLED_END(63);
}
#undef UNROLLED_INIT
#undef UNROLLED_BODY
#undef UNROLLED_END
static constexpr intptr_t kRowSize = 16;
void ReadStream::WriteWindow(BaseTextBuffer* buffer,
intptr_t start,
intptr_t window_size) {
const intptr_t buffer_size = end_ - buffer_;
ASSERT(0 <= start && start <= buffer_size);
intptr_t window_start = start - (window_size / 2);
intptr_t window_end = start + (window_size / 2);
if (window_start < 0) window_start = 0;
if (buffer_size < window_start + window_end) window_end = buffer_size;
for (intptr_t i = window_start - (window_start % kRowSize); i < window_end;
i += kRowSize) {
buffer->Printf("%016" Px " ", i);
intptr_t j = i;
if (j < window_start) {
while (j < window_start) {
buffer->AddString(" ");
++j;
}
}
for (; j < Utils::Minimum(window_end, i + kRowSize); j++) {
buffer->AddChar(j == start ? '|' : ' ');
buffer->Printf("%02x", static_cast<uint8_t>(buffer_[j] % kMaxUint8));
buffer->AddChar(j == start ? '|' : ' ');
}
buffer->AddChar('\n');
}
}
void ReadStream::PrintWindow(intptr_t start, intptr_t window_size) {
TextBuffer buffer(1024);
WriteWindow(&buffer, start, window_size);
OS::Print("%s", buffer.buffer());
}
void BaseWriteStream::WriteTargetWord(word value) {
ASSERT(compiler::target::kBitsPerWord == kBitsPerWord ||
Utils::IsAbsoluteUint(compiler::target::kBitsPerWord, value));
WriteFixed(static_cast<compiler::target::word>(value));
}
MallocWriteStream::~MallocWriteStream() {
free(buffer_);
}
void MallocWriteStream::Realloc(intptr_t new_size) {
const intptr_t old_offset = current_ - buffer_;
buffer_ = reinterpret_cast<uint8_t*>(realloc(buffer_, new_size));
capacity_ = buffer_ != nullptr ? new_size : 0;
current_ = buffer_ != nullptr ? buffer_ + old_offset : nullptr;
}
void ZoneWriteStream::Realloc(intptr_t new_size) {
const intptr_t old_offset = current_ - buffer_;
buffer_ = zone_->Realloc(buffer_, capacity_, new_size);
capacity_ = buffer_ != nullptr ? new_size : 0;
current_ = buffer_ != nullptr ? buffer_ + old_offset : nullptr;
}
StreamingWriteStream::~StreamingWriteStream() {
Flush();
free(buffer_);
}
void StreamingWriteStream::Realloc(intptr_t new_size) {
Flush();
// Check whether resetting the internal buffer by flushing gave enough space.
if (new_size <= capacity_) {
return;
}
const intptr_t new_capacity = Utils::RoundUp(new_size, 64 * KB);
buffer_ = reinterpret_cast<uint8_t*>(realloc(buffer_, new_capacity));
capacity_ = buffer_ != nullptr ? new_capacity : 0;
current_ = buffer_; // Flushing reset the internal buffer offset to 0.
}
void StreamingWriteStream::Flush() {
intptr_t size = current_ - buffer_;
callback_(callback_data_, buffer_, size);
flushed_size_ += size;
current_ = buffer_;
}
} // namespace dart