[VM] Optimize performance of dart_boostrap in debug-kernel-strong mode.

Since the kernel reading helpers have been extended to not only work
with a kernel blob in C heap, but also work based on a [TypedData]
buffer in the VM heap, access to the [TypedData] buffer is on the hot
path now.

This hot path is slowing things down considerably, in particular due
to NoSafepoingScope's.

This CL removes a critical NoSafepoingScope when accessing the
[TypedData] in read-only mode.  It also allows passing in the [Thread]
directly, to avoid TLS lookups.

Issue https://github.com/dart-lang/sdk/issues/32603

Change-Id: I91955bea5cd4eddbbd21c5d3bc6813504c2cece9
Reviewed-on: https://dart-review.googlesource.com/47222
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
Martin Kustermann 2018-03-21 10:24:29 +00:00 committed by commit-bot@chromium.org
parent 38dc57504b
commit 31dd6683f8
5 changed files with 45 additions and 15 deletions

View file

@ -286,6 +286,12 @@ class Utils {
static uint32_t HostToLittleEndian32(uint32_t host_value);
static uint64_t HostToLittleEndian64(uint64_t host_value);
static uint32_t BigEndianToHost32(uint32_t be_value) {
// Going between Host <-> BE is the same operation for all practical
// purposes.
return HostToBigEndian32(be_value);
}
static bool DoublesBitEqual(const double a, const double b) {
return bit_cast<int64_t, double>(a) == bit_cast<int64_t, double>(b);
}

View file

@ -69,7 +69,9 @@ void StackResource::UnwindAbove(Thread* thread, StackResource* new_top) {
}
#if defined(DEBUG)
NoSafepointScope::NoSafepointScope() : StackResource(Thread::Current()) {
NoSafepointScope::NoSafepointScope(Thread* current_thread)
: StackResource(current_thread != nullptr ? current_thread
: Thread::Current()) {
thread()->IncrementNoSafepointScopeDepth();
}

View file

@ -82,7 +82,7 @@ class ZoneAllocated {
#if defined(DEBUG)
class NoSafepointScope : public StackResource {
public:
NoSafepointScope();
explicit NoSafepointScope(Thread* thread = nullptr);
~NoSafepointScope();
private:
@ -91,7 +91,7 @@ class NoSafepointScope : public StackResource {
#else // defined(DEBUG)
class NoSafepointScope : public ValueObject {
public:
NoSafepointScope() {}
explicit NoSafepointScope(Thread* thread = nullptr) {}
private:
DISALLOW_COPY_AND_ASSIGN(NoSafepointScope);

View file

@ -163,10 +163,15 @@ static const int MetadataPayloadOffset = HeaderSize; // Right after header.
class Reader {
public:
Reader(const uint8_t* buffer, intptr_t size)
: raw_buffer_(buffer), typed_data_(NULL), size_(size), offset_(0) {}
: thread_(NULL),
raw_buffer_(buffer),
typed_data_(NULL),
size_(size),
offset_(0) {}
explicit Reader(const TypedData& typed_data)
: raw_buffer_(NULL),
: thread_(Thread::Current()),
raw_buffer_(NULL),
typed_data_(&typed_data),
size_(typed_data.IsNull() ? 0 : typed_data.Length()),
offset_(0) {}
@ -184,11 +189,13 @@ class Reader {
uint32_t ReadUInt32At(intptr_t offset) const {
ASSERT((size_ >= 4) && (offset >= 0) && (offset <= size_ - 4));
const uint8_t* buffer = this->buffer();
uint32_t value = (buffer[offset + 0] << 24) | (buffer[offset + 1] << 16) |
(buffer[offset + 2] << 8) | (buffer[offset + 3] << 0);
return value;
uint32_t value;
if (raw_buffer_ != NULL) {
value = *reinterpret_cast<const uint32_t*>(raw_buffer_ + offset);
} else {
value = typed_data_->GetUint32(offset);
}
return Utils::BigEndianToHost32(value);
}
uint32_t ReadFromIndexNoReset(intptr_t end_offset,
@ -323,14 +330,14 @@ class Reader {
void CopyDataToVMHeap(const TypedData& typed_data,
intptr_t offset,
intptr_t size) {
NoSafepointScope no_safepoint;
NoSafepointScope no_safepoint(thread_);
memmove(typed_data.DataAddr(0), buffer() + offset, size);
}
uint8_t* CopyDataIntoZone(Zone* zone, intptr_t offset, intptr_t length) {
uint8_t* buffer_ = zone->Alloc<uint8_t>(length);
{
NoSafepointScope no_safepoint;
NoSafepointScope no_safepoint(thread_);
memmove(buffer_, buffer() + offset, length);
}
return buffer_;
@ -341,10 +348,11 @@ class Reader {
if (raw_buffer_ != NULL) {
return raw_buffer_;
}
NoSafepointScope no_safepoint;
NoSafepointScope no_safepoint(thread_);
return reinterpret_cast<uint8_t*>(typed_data_->DataAddr(0));
}
Thread* thread_;
const uint8_t* raw_buffer_;
const TypedData* typed_data_;
intptr_t size_;

View file

@ -8168,8 +8168,10 @@ class TypedData : public Instance {
#define TYPED_GETTER_SETTER(name, type) \
type Get##name(intptr_t byte_offset) const { \
NoSafepointScope no_safepoint; \
return ReadUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset))); \
ASSERT((byte_offset >= 0) && \
(byte_offset + static_cast<intptr_t>(sizeof(type)) - 1) < \
LengthInBytes()); \
return ReadUnaligned(ReadOnlyDataAddr<type>(byte_offset)); \
} \
void Set##name(intptr_t byte_offset, type value) const { \
NoSafepointScope no_safepoint; \
@ -8295,6 +8297,18 @@ class TypedData : public Instance {
}
private:
// Provides const access to non-pointer, non-aligned data within the object.
// Such access does not need a write barrier, but it is *not* GC-safe, since
// the object might move.
//
// Therefore this method is private and the call-sites in this class need to
// ensure the returned pointer does not escape.
template <typename FieldType>
const FieldType* ReadOnlyDataAddr(intptr_t byte_offset) const {
return reinterpret_cast<const FieldType*>((raw_ptr()->data()) +
byte_offset);
}
static intptr_t element_size(intptr_t index) {
ASSERT(0 <= index && index < kNumElementSizes);
intptr_t size = element_size_table[index];