Files
sdk/runtime/vm/bitmap.cc
T
Tess Strickland 45a46ca2b8 [vm] Add (S)LEB128 encoding/decoding to BaseWriteStream.
Unlike cfc8e6de, this does _not_ replace the default variable length
encoding for {Read,Write}Streams, but insteads adds separate
{Read,Write}{S,}LEB128 methods to the appropriate classes. If we later
find the cause of the issues that led to the revert of cfc8e6de, it'll
be easy to switch over then.

Note that WriteLEB128 asserts that the value is non-negative if used
with a signed type (since negative values suggests that SLEB128 should
be used instead for minimal encoding).

Also removes the various other encoding and decoding methods for
(S)LEB128 across the codebase and changes those clients to use
{Read,Write}Streams instead.

Other cleanups:

* Various constant-related cleanups in datastream.h.

* Adds DART_FORCE_INLINE to ReadStream::ReadByte and uses it in the
  default variable length decoding methods for retrieving bytes
  from the stream instead of managing current_ by hand.

* Creates a canonical empty CompressedStackMaps instance and uses
  that instead of the null CompressedStackMaps instance in most cases.
  The only remaining (expected) use of the null CompressedStackMaps
  instance is for the global table in the object store when no global
  table exists (e.g., in JIT mode before any snapshotting).

* Moves CompressedStackMapsIterator from code_descriptors.h to an
  Iterator class within CompressedStackMaps in object.h (similar to
  PcDescriptors::Iterator), to limit friend declarations and because it
  conceptually makes more sense as part of CompressedStackMaps.

* Removed CompressedStackMaps::PayloadByte, since existing clients
  (CompressedStackMaps::Iterator, StackMapEntry in program_visitor.cc)
  are better served by just operating on the payload buffer directly
  (with appropriate NoSafepointScopes).

* WriteStreams no longer allocate their initial space on construction,
  but rather on the first write, so no allocation is performed by
  constructing a never-used WriteStream.

Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-mac-release-simarm64-try,vm-kernel-mac-debug-x64-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-ubsan-linux-release-x64-try,vm-kernel-tsan-linux-release-x64-try,vm-kernel-precomp-ubsan-linux-release-x64-try,vm-kernel-precomp-tsan-linux-release-x64-try,vm-kernel-precomp-msan-linux-release-x64-try,vm-kernel-precomp-asan-linux-release-x64-try,vm-kernel-msan-linux-release-x64-try,vm-kernel-asan-linux-release-x64-try
Change-Id: Ice63321abaa79157fbe9f230a864c8bba0e6dea9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166421
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
2020-10-09 10:08:16 +00:00

145 lines
4.6 KiB
C++

// Copyright (c) 2012, 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/bitmap.h"
#include "platform/assert.h"
#include "vm/object.h"
namespace dart {
void BitmapBuilder::SetLength(intptr_t new_length) {
// When this function is used to shorten the length, affected bits in the
// backing store need to be cleared because the implementation assumes it.
if (new_length < length_) {
// Byte offset containing the first bit to be cleared.
intptr_t byte_offset = new_length >> kBitsPerByteLog2;
if (byte_offset < data_size_in_bytes_) {
// First bit index (in the byte) to be cleared.
intptr_t bit_index = new_length & (kBitsPerByte - 1);
intptr_t mask = (1 << bit_index) - 1;
data_[byte_offset] &= mask;
// Clear the rest.
++byte_offset;
if (byte_offset < data_size_in_bytes_) {
memset(&data_[byte_offset], 0, data_size_in_bytes_ - byte_offset);
}
}
}
length_ = new_length;
}
bool BitmapBuilder::Get(intptr_t bit_offset) const {
if (!InRange(bit_offset)) {
return false;
}
intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
// Bits not covered by the backing store are implicitly false.
return (byte_offset < data_size_in_bytes_) && GetBit(bit_offset);
}
void BitmapBuilder::Set(intptr_t bit_offset, bool value) {
if (!InRange(bit_offset)) {
length_ = bit_offset + 1;
// Bits not covered by the backing store are implicitly false.
if (!value) return;
// Grow the backing store if necessary.
intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
if (byte_offset >= data_size_in_bytes_) {
uint8_t* old_data = data_;
intptr_t old_size = data_size_in_bytes_;
data_size_in_bytes_ =
Utils::RoundUp(byte_offset + 1, kIncrementSizeInBytes);
ASSERT(data_size_in_bytes_ > 0);
data_ = Thread::Current()->zone()->Alloc<uint8_t>(data_size_in_bytes_);
ASSERT(data_ != NULL);
memmove(data_, old_data, old_size);
memset(&data_[old_size], 0, (data_size_in_bytes_ - old_size));
}
}
SetBit(bit_offset, value);
}
void BitmapBuilder::SetRange(intptr_t min, intptr_t max, bool value) {
for (intptr_t i = min; i <= max; i++) {
Set(i, value);
}
}
void BitmapBuilder::Print() const {
for (intptr_t i = 0; i < Length(); i++) {
if (Get(i)) {
OS::PrintErr("1");
} else {
OS::PrintErr("0");
}
}
}
void BitmapBuilder::AppendAsBytesTo(BaseWriteStream* stream) const {
// Early return if there are no bits in the payload to copy.
if (Length() == 0) return;
const intptr_t total_size =
Utils::RoundUp(Length(), kBitsPerByte) / kBitsPerByte;
intptr_t payload_size;
intptr_t extra_size;
if (total_size > data_size_in_bytes_) {
// A [BitmapBuilder] does not allocate storage for the trailing 0 bits in
// the backing store, so we need to add additional empty bytes here.
payload_size = data_size_in_bytes_;
extra_size = total_size - data_size_in_bytes_;
} else {
payload_size = total_size;
extra_size = 0;
}
#if defined(DEBUG)
// Make sure any bits in the payload beyond the bit length if we're not
// appending trailing zeroes are cleared to ensure deterministic snapshots.
if (extra_size == 0 && Length() % kBitsPerByte != 0) {
const int8_t mask = (1 << (Length() % kBitsPerByte)) - 1;
ASSERT_EQUAL(data_[payload_size - 1], (data_[payload_size - 1] & mask));
}
#endif
for (intptr_t i = 0; i < payload_size; i++) {
stream->WriteByte(data_[i]);
}
for (intptr_t i = 0; i < extra_size; i++) {
stream->WriteByte(0U);
}
}
bool BitmapBuilder::GetBit(intptr_t bit_offset) const {
if (!InRange(bit_offset)) {
return false;
}
intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
ASSERT(byte_offset < data_size_in_bytes_);
intptr_t bit_remainder = bit_offset & (kBitsPerByte - 1);
uint8_t mask = 1U << bit_remainder;
ASSERT(data_ != NULL);
return ((data_[byte_offset] & mask) != 0);
}
void BitmapBuilder::SetBit(intptr_t bit_offset, bool value) {
if (!InRange(bit_offset)) {
FATAL1(
"Fatal error in BitmapBuilder::SetBit :"
" invalid bit_offset, %" Pd "\n",
bit_offset);
}
intptr_t byte_offset = bit_offset >> kBitsPerByteLog2;
ASSERT(byte_offset < data_size_in_bytes_);
intptr_t bit_remainder = bit_offset & (kBitsPerByte - 1);
uint8_t mask = 1U << bit_remainder;
ASSERT(data_ != NULL);
if (value) {
data_[byte_offset] |= mask;
} else {
data_[byte_offset] &= ~mask;
}
}
} // namespace dart