Skip to content

Commit

Permalink
Avoid copying the contents of large platform message responses (flutt…
Browse files Browse the repository at this point in the history
…er#4947)

Assets are loaded via platform messages, and currently asset payloads are
being copied into Dart typed data buffers.  This change uses external
typed data objects that wrap the existing buffer if copying would be
expensive.

See flutter/flutter#16291
  • Loading branch information
jason-simmons authored Apr 10, 2018
1 parent 5ff5272 commit c8e4c69
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 30 deletions.
43 changes: 30 additions & 13 deletions lib/ui/window/platform_message_response_dart.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,41 @@
#include <utility>

#include "flutter/common/threads.h"
#include "flutter/lib/ui/window/window.h"
#include "lib/fxl/functional/make_copyable.h"
#include "lib/tonic/dart_state.h"
#include "lib/tonic/logging/dart_invoke.h"

namespace blink {

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));
Dart_Handle data_handle = Dart_NewExternalTypedData(
Dart_TypedData_kByteData, heap_data->data(), heap_data->size());
DART_CHECK_VALID(data_handle);
Dart_NewWeakPersistentHandle(data_handle, heap_data, heap_data->size(),
MessageDataFinalizer);
return data_handle;
}
}

} // anonymous namespace

PlatformMessageResponseDart::PlatformMessageResponseDart(
tonic::DartPersistentValue callback)
: callback_(std::move(callback)) {}
Expand All @@ -38,19 +67,7 @@ void PlatformMessageResponseDart::Complete(std::vector<uint8_t> data) {
return;
tonic::DartState::Scope scope(dart_state);

Dart_Handle byte_buffer =
Dart_NewTypedData(Dart_TypedData_kByteData, data.size());
DART_CHECK_VALID(byte_buffer);

void* buffer;
intptr_t length;
Dart_TypedData_Type type;
DART_CHECK_VALID(
Dart_TypedDataAcquireData(byte_buffer, &type, &buffer, &length));
FXL_CHECK(type == Dart_TypedData_kByteData);
FXL_CHECK(static_cast<size_t>(length) == data.size());
memcpy(buffer, data.data(), length);
Dart_TypedDataReleaseData(byte_buffer);
Dart_Handle byte_buffer = WrapByteData(std::move(data));
tonic::DartInvoke(callback.Release(), {byte_buffer});
}));
}
Expand Down
34 changes: 17 additions & 17 deletions lib/ui/window/window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,6 @@ using tonic::ToDart;
namespace blink {
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;
FXL_CHECK(!Dart_IsError(
Dart_TypedDataAcquireData(data_handle, &type, &data, &num_bytes)));

memcpy(data, buffer.data(), num_bytes);
Dart_TypedDataReleaseData(data_handle);
return data_handle;
}

void DefaultRouteName(Dart_NativeArguments args) {
std::string routeName =
UIDartState::Current()->window()->client()->DefaultRouteName();
Expand Down Expand Up @@ -119,6 +102,23 @@ void _RespondToPlatformMessage(Dart_NativeArguments args) {

} // 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;
FXL_CHECK(!Dart_IsError(
Dart_TypedDataAcquireData(data_handle, &type, &data, &num_bytes)));

memcpy(data, buffer.data(), num_bytes);
Dart_TypedDataReleaseData(data_handle);
return data_handle;
}

WindowClient::~WindowClient() {}

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

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

class WindowClient {
public:
virtual std::string DefaultRouteName() = 0;
Expand Down

0 comments on commit c8e4c69

Please sign in to comment.