Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Avoid creating a vector when constructing Dart typed data objects for platform messages #18838

Merged
merged 1 commit into from
Jun 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 3 additions & 33 deletions lib/ui/window/platform_message_response_dart.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,12 @@

#include "flutter/common/task_runners.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/lib/ui/window/window.h"
#include "third_party/tonic/dart_state.h"
#include "third_party/tonic/logging/dart_invoke.h"
#include "third_party/tonic/typed_data/dart_byte_data.h"

namespace flutter {

namespace {

// Avoid copying the contents of messages beyond a certain size.
const int kMessageCopyThreshold = 1000;

void MessageDataFinalizer(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
void* peer) {
std::vector<uint8_t>* data = reinterpret_cast<std::vector<uint8_t>*>(peer);
delete data;
}

Dart_Handle WrapByteData(std::vector<uint8_t> data) {
if (data.size() < kMessageCopyThreshold) {
return ToByteData(data);
} else {
std::vector<uint8_t>* heap_data = new std::vector<uint8_t>(std::move(data));
return Dart_NewExternalTypedDataWithFinalizer(
Dart_TypedData_kByteData, heap_data->data(), heap_data->size(),
heap_data, heap_data->size(), MessageDataFinalizer);
}
}

Dart_Handle WrapByteData(std::unique_ptr<fml::Mapping> mapping) {
std::vector<uint8_t> data(mapping->GetSize());
memcpy(data.data(), mapping->GetMapping(), mapping->GetSize());
return WrapByteData(std::move(data));
}

} // anonymous namespace

PlatformMessageResponseDart::PlatformMessageResponseDart(
tonic::DartPersistentValue callback,
fml::RefPtr<fml::TaskRunner> ui_task_runner)
Expand All @@ -71,7 +40,8 @@ void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) {
return;
tonic::DartState::Scope scope(dart_state);

Dart_Handle byte_buffer = WrapByteData(std::move(data));
Dart_Handle byte_buffer =
tonic::DartByteData::Create(data->GetMapping(), data->GetSize());
tonic::DartInvoke(callback.Release(), {byte_buffer});
}));
}
Expand Down
19 changes: 3 additions & 16 deletions lib/ui/window/window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -166,25 +166,12 @@ void GetPersistentIsolateData(Dart_NativeArguments args) {
persistent_isolate_data->GetSize()));
}

} // namespace

Dart_Handle ToByteData(const std::vector<uint8_t>& buffer) {
Dart_Handle data_handle =
Dart_NewTypedData(Dart_TypedData_kByteData, buffer.size());
if (Dart_IsError(data_handle))
return data_handle;

Dart_TypedData_Type type;
void* data = nullptr;
intptr_t num_bytes = 0;
FML_CHECK(!Dart_IsError(
Dart_TypedDataAcquireData(data_handle, &type, &data, &num_bytes)));

memcpy(data, buffer.data(), num_bytes);
Dart_TypedDataReleaseData(data_handle);
return data_handle;
return tonic::DartByteData::Create(buffer.data(), buffer.size());
}

} // namespace

WindowClient::~WindowClient() {}

Window::Window(WindowClient* client) : client_(client) {}
Expand Down
2 changes: 0 additions & 2 deletions lib/ui/window/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ namespace flutter {
class FontCollection;
class Scene;

Dart_Handle ToByteData(const std::vector<uint8_t>& buffer);

// Must match the AccessibilityFeatureFlag enum in window.dart.
enum class AccessibilityFeatureFlag : int32_t {
kAccessibleNavigation = 1 << 0,
Expand Down
28 changes: 25 additions & 3 deletions third_party/tonic/typed_data/dart_byte_data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,32 @@

namespace tonic {

namespace {

// For large objects it is more efficient to use an external typed data object
// with a buffer allocated outside the Dart heap.
const int kExternalSizeThreshold = 1000;

void FreeFinalizer(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
void* peer) {
free(peer);
}

} // anonymous namespace

Dart_Handle DartByteData::Create(const void* data, size_t length) {
auto handle = DartByteData{data, length}.dart_handle();
// The destructor should release the typed data.
return handle;
if (length < kExternalSizeThreshold) {
auto handle = DartByteData{data, length}.dart_handle();
// The destructor should release the typed data.
return handle;
} else {
void* buf = ::malloc(length);
TONIC_DCHECK(buf);
::memcpy(buf, data, length);
return Dart_NewExternalTypedDataWithFinalizer(
Dart_TypedData_kByteData, buf, length, buf, length, FreeFinalizer);
}
}

DartByteData::DartByteData()
Expand Down