[vm] Don't copy when reading typed data in messages sent to native ports.

Bug: https://github.com/dart-lang/sdk/issues/37833
Change-Id: Iac906e58320e003365c4c0624b4587579f352db1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/114970
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak 2019-08-30 17:49:28 +00:00 committed by commit-bot@chromium.org
parent bfec168c1e
commit 36985859e4
6 changed files with 62 additions and 29 deletions

View file

@ -2,6 +2,8 @@
// 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 <memory>
#include "vm/dart_api_message.h"
#include "platform/unicode.h"
#include "vm/object.h"
@ -557,29 +559,43 @@ Dart_CObject* ApiMessageReader::ReadInternalVMObject(intptr_t class_id,
return object;
}
#define READ_TYPED_DATA_HEADER(type) \
intptr_t len = ReadSmiValue(); \
Dart_CObject* object = \
AllocateDartCObjectTypedData(Dart_TypedData_k##type, len); \
AddBackRef(object_id, object, kIsDeserialized);
#define READ_TYPED_DATA(type, ctype) \
#define READ_TYPED_DATA(tname, ctype) \
{ \
READ_TYPED_DATA_HEADER(type); \
uint8_t* p = \
reinterpret_cast<uint8_t*>(object->value.as_typed_data.values); \
ReadBytes(p, len * sizeof(ctype)); \
intptr_t len = ReadSmiValue(); \
auto type = Dart_TypedData_k##tname; \
intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * len; \
Dart_CObject* object = \
reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject))); \
ASSERT(object != NULL); \
object->type = Dart_CObject_kTypedData; \
object->value.as_typed_data.type = type; \
object->value.as_typed_data.length = length_in_bytes; \
if (len > 0) { \
Align(Zone::kAlignment); \
object->value.as_typed_data.values = \
const_cast<uint8_t*>(CurrentBufferAddress()); \
Advance(length_in_bytes); \
} else { \
object->value.as_typed_data.values = NULL; \
} \
AddBackRef(object_id, object, kIsDeserialized); \
return object; \
}
#define READ_EXTERNAL_TYPED_DATA(type, ctype) \
#define READ_EXTERNAL_TYPED_DATA(tname, ctype) \
{ \
READ_TYPED_DATA_HEADER(type); \
uint8_t* p = \
reinterpret_cast<uint8_t*>(object->value.as_typed_data.values); \
FinalizableData finalizable_data = finalizable_data_->Take(); \
memmove(p, finalizable_data.data, len * sizeof(ctype)); \
finalizable_data.callback(NULL, NULL, finalizable_data.peer); \
intptr_t len = ReadSmiValue(); \
auto type = Dart_TypedData_k##tname; \
intptr_t length_in_bytes = GetTypedDataSizeInBytes(type) * len; \
Dart_CObject* object = \
reinterpret_cast<Dart_CObject*>(allocator(sizeof(Dart_CObject))); \
ASSERT(object != NULL); \
object->type = Dart_CObject_kTypedData; \
object->value.as_typed_data.type = type; \
object->value.as_typed_data.length = length_in_bytes; \
object->value.as_typed_data.values = \
reinterpret_cast<uint8_t*>(finalizable_data_->Get().data); \
AddBackRef(object_id, object, kIsDeserialized); \
return object; \
}
@ -635,7 +651,6 @@ Dart_CObject* ApiMessageReader::ReadInternalVMObject(intptr_t class_id,
#undef READ_TYPED_DATA
#undef READ_EXTERNAL_TYPED_DATA
#undef READ_TYPED_DATA_VIEW
#undef READ_TYPED_DATA_HEADER
case kGrowableObjectArrayCid: {
// A GrowableObjectArray is serialized as its type arguments and
@ -1069,11 +1084,13 @@ bool ApiMessageWriter::WriteCObjectInlined(Dart_CObject* object,
case kTypedDataInt8ArrayCid:
case kTypedDataUint8ArrayCid: {
uint8_t* bytes = object->value.as_typed_data.values;
Align(Zone::kAlignment);
WriteBytes(bytes, len);
break;
}
case kTypedDataUint32ArrayCid: {
uint8_t* bytes = object->value.as_typed_data.values;
Align(Zone::kAlignment);
WriteBytes(bytes, len * sizeof(uint32_t));
break;
}

View file

@ -89,7 +89,7 @@ class ReadStream : public ValueObject {
const uint8_t* AddressOfCurrentPosition() const { return current_; }
void Advance(intptr_t value) {
ASSERT((end_ - current_) > value);
ASSERT((end_ - current_) >= value);
current_ = current_ + value;
}

View file

@ -20,10 +20,11 @@ struct FinalizableData {
class MessageFinalizableData {
public:
MessageFinalizableData() : records_(0), position_(0), external_size_(0) {}
MessageFinalizableData()
: records_(0), get_position_(0), take_position_(0), external_size_(0) {}
~MessageFinalizableData() {
for (intptr_t i = position_; i < records_.length(); i++) {
for (intptr_t i = take_position_; i < records_.length(); i++) {
records_[i].callback(nullptr, nullptr, records_[i].peer);
}
}
@ -46,13 +47,22 @@ class MessageFinalizableData {
external_size_ += external_size;
}
// Retrieve the next FinalizableData, but still run its finalizer when |this|
// is destroyed.
FinalizableData Get() {
ASSERT(get_position_ < records_.length());
return records_[get_position_++];
}
// Retrieve the next FinalizableData, and skip its finalizer when |this| is
// destroyed.
FinalizableData Take() {
ASSERT(position_ < records_.length());
return records_[position_++];
ASSERT(take_position_ < records_.length());
return records_[take_position_++];
}
void SerializationSucceeded() {
for (intptr_t i = position_; i < records_.length(); i++) {
for (intptr_t i = 0; i < records_.length(); i++) {
if (records_[i].successful_write_callback != nullptr) {
records_[i].successful_write_callback(nullptr, nullptr,
records_[i].peer);
@ -64,7 +74,8 @@ class MessageFinalizableData {
private:
MallocGrowableArray<FinalizableData> records_;
intptr_t position_;
intptr_t get_position_;
intptr_t take_position_;
intptr_t external_size_;
DISALLOW_COPY_AND_ASSIGN(MessageFinalizableData);

View file

@ -1311,6 +1311,7 @@ RawTypedData* TypedData::ReadFrom(SnapshotReader* reader,
intptr_t length_in_bytes = len * element_size;
NoSafepointScope no_safepoint;
uint8_t* data = reinterpret_cast<uint8_t*>(result.DataAddr(0));
reader->Align(Zone::kAlignment);
reader->ReadBytes(data, length_in_bytes);
// If it is a canonical constant make it one.
@ -1456,6 +1457,7 @@ void RawTypedData::WriteTo(SnapshotWriter* writer,
writer->WriteTags(writer->GetObjectTags(this));
writer->Write<RawObject*>(ptr()->length_);
uint8_t* data = reinterpret_cast<uint8_t*>(ptr()->data());
writer->Align(Zone::kAlignment);
writer->WriteBytes(data, bytes);
}
}

View file

@ -255,6 +255,7 @@ class BaseReader {
return stream_.AddressOfCurrentPosition();
}
void Align(intptr_t value) { stream_.Align(value); }
void Advance(intptr_t value) { stream_.Advance(value); }
intptr_t PendingBytes() const { return stream_.PendingBytes(); }
@ -517,6 +518,8 @@ class BaseWriter : public StackResource {
Write<int8_t>(static_cast<int8_t>(flags));
}
void Align(intptr_t value) { stream_.Align(value); }
// Write out a buffer of bytes.
void WriteBytes(const uint8_t* addr, intptr_t len) {
stream_.WriteBytes(addr, len);

View file

@ -82,13 +82,13 @@ class Zone {
return false;
}
// All pointers returned from AllocateUnsafe() and New() have this alignment.
static const intptr_t kAlignment = kDoubleSize;
private:
Zone();
~Zone(); // Delete all memory associated with the zone.
// All pointers returned from AllocateUnsafe() and New() have this alignment.
static const intptr_t kAlignment = kDoubleSize;
// Default initial chunk size.
static const intptr_t kInitialChunkSize = 1 * KB;