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

Commit a379730

Browse files
committed
Eliminates an extra copy when returning messages from the host platform to dart.
1 parent 10ff302 commit a379730

File tree

13 files changed

+152
-15
lines changed

13 files changed

+152
-15
lines changed

assets/BUILD.gn

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,15 @@ source_set("assets") {
1818

1919
public_configs = [ "//flutter:config" ]
2020
}
21+
22+
source_set("assets_unittests") {
23+
sources = [ "directory_asset_bundle_unittests.cc" ]
24+
25+
deps = [
26+
":assets",
27+
"//flutter/testing",
28+
]
29+
30+
public_configs = [ "//flutter:config" ]
31+
testonly = true
32+
}

assets/directory_asset_bundle.cc

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,14 @@ std::unique_ptr<fml::Mapping> DirectoryAssetBundle::GetAsMapping(
5050
return nullptr;
5151
}
5252

53-
auto mapping = std::make_unique<fml::FileMapping>(fml::OpenFile(
54-
descriptor_, asset_name.c_str(), false, fml::FilePermission::kRead));
53+
auto mapping = std::make_unique<fml::FileMapping>(
54+
fml::OpenFile(descriptor_, asset_name.c_str(), false,
55+
fml::FilePermission::kRead),
56+
std::initializer_list<fml::FileMapping::Protection>(
57+
{fml::FileMapping::Protection::kRead,
58+
fml::FileMapping::Protection::kWrite}),
59+
std::initializer_list<fml::FileMapping::Flags>(
60+
{fml::FileMapping::Flags::kCopyOnWrite}));
5561

5662
if (!mapping->IsValid()) {
5763
return nullptr;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/assets/directory_asset_bundle.h"
6+
#include "gtest/gtest.h"
7+
8+
namespace flutter {
9+
namespace testing {
10+
11+
TEST(DirectoryAssetBundle, MappingIsReadWrite) {
12+
fml::ScopedTemporaryDirectory temp_dir;
13+
const char* filename = "foo.txt";
14+
fml::MallocMapping write_mapping(static_cast<uint8_t*>(calloc(1, 4)), 4);
15+
fml::WriteAtomically(temp_dir.fd(), filename, write_mapping);
16+
fml::UniqueFD descriptor =
17+
fml::OpenDirectory(temp_dir.path().c_str(), /*create_if_necessary=*/false,
18+
fml::FilePermission::kRead);
19+
std::unique_ptr<AssetResolver> bundle =
20+
std::make_unique<DirectoryAssetBundle>(
21+
std::move(descriptor), /*is_valid_after_asset_manager_change=*/true);
22+
EXPECT_TRUE(bundle->IsValid());
23+
std::unique_ptr<fml::Mapping> read_mapping = bundle->GetAsMapping(filename);
24+
ASSERT_TRUE(read_mapping);
25+
ASSERT_TRUE(read_mapping->GetMutableMapping());
26+
EXPECT_EQ(read_mapping->GetSize(), 4u);
27+
read_mapping->GetMutableMapping()[0] = 'A';
28+
EXPECT_EQ(read_mapping->GetMapping()[0], 'A');
29+
std::unique_ptr<fml::Mapping> read_after_write_mapping =
30+
bundle->GetAsMapping(filename);
31+
EXPECT_EQ(read_after_write_mapping->GetMapping()[0], '\0');
32+
}
33+
34+
} // namespace testing
35+
} // namespace flutter

ci/licenses_golden/licenses_flutter

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ FILE: ../../../flutter/assets/asset_manager.h
2020
FILE: ../../../flutter/assets/asset_resolver.h
2121
FILE: ../../../flutter/assets/directory_asset_bundle.cc
2222
FILE: ../../../flutter/assets/directory_asset_bundle.h
23+
FILE: ../../../flutter/assets/directory_asset_bundle_unittests.cc
2324
FILE: ../../../flutter/benchmarking/benchmarking.cc
2425
FILE: ../../../flutter/benchmarking/benchmarking.h
2526
FILE: ../../../flutter/benchmarking/library.cc

fml/mapping.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace fml {
1111

1212
// FileMapping
1313

14-
uint8_t* FileMapping::GetMutableMapping() {
14+
uint8_t* FileMapping::GetMutableMapping() const {
1515
return mutable_mapping_;
1616
}
1717

@@ -146,6 +146,10 @@ const uint8_t* MallocMapping::GetMapping() const {
146146
return data_;
147147
}
148148

149+
uint8_t* MallocMapping::GetMutableMapping() const {
150+
return data_;
151+
}
152+
149153
bool MallocMapping::IsDontNeedSafe() const {
150154
return false;
151155
}

fml/mapping.h

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class Mapping {
2828

2929
virtual const uint8_t* GetMapping() const = 0;
3030

31+
virtual uint8_t* GetMutableMapping() const = 0;
32+
3133
// Whether calling madvise(DONTNEED) on the mapping is non-destructive.
3234
// Generally true for file-mapped memory and false for anonymous memory.
3335
virtual bool IsDontNeedSafe() const = 0;
@@ -44,9 +46,15 @@ class FileMapping final : public Mapping {
4446
kExecute,
4547
};
4648

47-
explicit FileMapping(const fml::UniqueFD& fd,
48-
std::initializer_list<Protection> protection = {
49-
Protection::kRead});
49+
enum class Flags {
50+
kNone,
51+
kCopyOnWrite,
52+
};
53+
54+
explicit FileMapping(
55+
const fml::UniqueFD& fd,
56+
std::initializer_list<Protection> protection = {Protection::kRead},
57+
std::initializer_list<Flags> flags = {Flags::kNone});
5058

5159
~FileMapping() override;
5260

@@ -72,7 +80,8 @@ class FileMapping final : public Mapping {
7280
// |Mapping|
7381
bool IsDontNeedSafe() const override;
7482

75-
uint8_t* GetMutableMapping();
83+
// |Mapping|
84+
uint8_t* GetMutableMapping() const override;
7685

7786
bool IsValid() const;
7887

@@ -103,6 +112,9 @@ class DataMapping final : public Mapping {
103112
// |Mapping|
104113
const uint8_t* GetMapping() const override;
105114

115+
// |Mapping|
116+
uint8_t* GetMutableMapping() const override { return nullptr; }
117+
106118
// |Mapping|
107119
bool IsDontNeedSafe() const override;
108120

@@ -128,6 +140,9 @@ class NonOwnedMapping final : public Mapping {
128140
// |Mapping|
129141
const uint8_t* GetMapping() const override;
130142

143+
// |Mapping|
144+
uint8_t* GetMutableMapping() const override { return nullptr; }
145+
131146
// |Mapping|
132147
bool IsDontNeedSafe() const override;
133148

@@ -177,6 +192,9 @@ class MallocMapping final : public Mapping {
177192
// |Mapping|
178193
const uint8_t* GetMapping() const override;
179194

195+
// |Mapping|
196+
uint8_t* GetMutableMapping() const override;
197+
180198
// |Mapping|
181199
bool IsDontNeedSafe() const override;
182200

@@ -204,6 +222,9 @@ class SymbolMapping final : public Mapping {
204222
// |Mapping|
205223
const uint8_t* GetMapping() const override;
206224

225+
// |Mapping|
226+
uint8_t* GetMutableMapping() const override { return nullptr; }
227+
207228
// |Mapping|
208229
bool IsDontNeedSafe() const override;
209230

fml/platform/posix/mapping_posix.cc

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,23 @@ static bool IsWritable(
4646
return false;
4747
}
4848

49+
static bool IsCopyOnWrite(
50+
const std::initializer_list<FileMapping::Flags>& flags) {
51+
for (auto flag : flags) {
52+
if (flag == FileMapping::Flags::kCopyOnWrite) {
53+
return true;
54+
}
55+
}
56+
return false;
57+
}
58+
4959
Mapping::Mapping() = default;
5060

5161
Mapping::~Mapping() = default;
5262

5363
FileMapping::FileMapping(const fml::UniqueFD& handle,
54-
std::initializer_list<Protection> protection)
64+
std::initializer_list<Protection> protection,
65+
std::initializer_list<Flags> flags)
5566
: size_(0), mapping_(nullptr) {
5667
if (!handle.is_valid()) {
5768
return;
@@ -72,7 +83,8 @@ FileMapping::FileMapping(const fml::UniqueFD& handle,
7283

7384
auto* mapping =
7485
::mmap(nullptr, stat_buffer.st_size, ToPosixProtectionFlags(protection),
75-
is_writable ? MAP_SHARED : MAP_PRIVATE, handle.get(), 0);
86+
is_writable && !IsCopyOnWrite(flags) ? MAP_SHARED : MAP_PRIVATE,
87+
handle.get(), 0);
7688

7789
if (mapping == MAP_FAILED) {
7890
return;

fml/platform/win/mapping_win.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,19 @@ static bool IsExecutable(
4040
return false;
4141
}
4242

43+
static bool IsCopyOnWrite(
44+
const std::initializer_list<FileMapping::Flags>& flags) {
45+
for (auto flag : flags) {
46+
if (flag == FileMapping::Flags::kCopyOnWrite) {
47+
return true;
48+
}
49+
}
50+
return false;
51+
}
52+
4353
FileMapping::FileMapping(const fml::UniqueFD& fd,
44-
std::initializer_list<Protection> protections)
54+
std::initializer_list<Protection> protections,
55+
std::initializer_list<Flags> flags)
4556
: size_(0), mapping_(nullptr) {
4657
if (!fd.is_valid()) {
4758
return;
@@ -82,7 +93,9 @@ FileMapping::FileMapping(const fml::UniqueFD& fd,
8293
return;
8394
}
8495

85-
const DWORD desired_access = read_only ? FILE_MAP_READ : FILE_MAP_WRITE;
96+
const DWORD desired_access =
97+
read_only ? FILE_MAP_READ
98+
: (IsCopyOnWrite(flags) ? FILE_MAP_COPY : FILE_MAP_WRITE);
8699

87100
auto mapping = reinterpret_cast<uint8_t*>(
88101
MapViewOfFile(mapping_handle_.get(), desired_access, 0, 0, mapping_size));

lib/ui/window/platform_message_response_dart.cc

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414

1515
namespace flutter {
1616

17+
namespace {
18+
void MappingFinalizer(void* isolate_callback_data, void* peer) {
19+
delete static_cast<fml::Mapping*>(peer);
20+
}
21+
} // anonymous namespace
22+
1723
PlatformMessageResponseDart::PlatformMessageResponseDart(
1824
tonic::DartPersistentValue callback,
1925
fml::RefPtr<fml::TaskRunner> ui_task_runner)
@@ -42,8 +48,22 @@ void PlatformMessageResponseDart::Complete(std::unique_ptr<fml::Mapping> data) {
4248
}
4349
tonic::DartState::Scope scope(dart_state);
4450

45-
Dart_Handle byte_buffer =
46-
tonic::DartByteData::Create(data->GetMapping(), data->GetSize());
51+
void* mapping = data->GetMutableMapping();
52+
Dart_Handle byte_buffer;
53+
if (mapping) {
54+
size_t data_size = data->GetSize();
55+
byte_buffer = Dart_NewExternalTypedDataWithFinalizer(
56+
/*type=*/Dart_TypedData_kByteData,
57+
/*data=*/mapping,
58+
/*length=*/data_size,
59+
/*peer=*/data.release(),
60+
/*external_allocation_size=*/data_size,
61+
/*callback=*/MappingFinalizer);
62+
63+
} else {
64+
byte_buffer =
65+
tonic::DartByteData::Create(data->GetMapping(), data->GetSize());
66+
}
4767
tonic::DartInvoke(callback.Release(), {byte_buffer});
4868
}));
4969
}

runtime/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ if (enable_unittests) {
142142
":libdart",
143143
":runtime",
144144
":runtime_fixtures",
145+
"//flutter/assets:assets_unittests",
145146
"//flutter/common",
146147
"//flutter/fml",
147148
"//flutter/lib/snapshot",

shell/platform/android/apk_asset_provider.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ class APKAssetMapping : public fml::Mapping {
4848
return reinterpret_cast<const uint8_t*>(AAsset_getBuffer(asset_));
4949
}
5050

51+
uint8_t* GetMutableMapping() const override { return nullptr; }
52+
5153
bool IsDontNeedSafe() const override { return !AAsset_isAllocated(asset_); }
5254

5355
private:

shell/platform/darwin/common/buffer_conversions.mm

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ explicit NSDataMapping(NSData* data) : data_([data retain]) {}
1818
return static_cast<const uint8_t*>([data_.get() bytes]);
1919
}
2020

21+
uint8_t* GetMutableMapping() const override {
22+
id id_data = data_.get();
23+
// In practice these are all NSMutableData (see ConvertMappingToNSData).
24+
FML_DCHECK([id_data respondsToSelector:@selector(mutableBytes)]);
25+
return static_cast<uint8_t*>([id_data mutableBytes]);
26+
}
27+
2128
bool IsDontNeedSafe() const override { return false; }
2229

2330
private:
@@ -33,15 +40,15 @@ explicit NSDataMapping(NSData* data) : data_([data retain]) {}
3340

3441
NSData* ConvertMappingToNSData(fml::MallocMapping buffer) {
3542
size_t size = buffer.GetSize();
36-
return [NSData dataWithBytesNoCopy:buffer.Release() length:size];
43+
return [NSMutableData dataWithBytesNoCopy:buffer.Release() length:size];
3744
}
3845

3946
std::unique_ptr<fml::Mapping> ConvertNSDataToMappingPtr(NSData* data) {
4047
return std::make_unique<NSDataMapping>(data);
4148
}
4249

4350
NSData* CopyMappingPtrToNSData(std::unique_ptr<fml::Mapping> mapping) {
44-
return [NSData dataWithBytes:mapping->GetMapping() length:mapping->GetSize()];
51+
return [NSMutableData dataWithBytes:mapping->GetMapping() length:mapping->GetSize()];
4552
}
4653

4754
} // namespace flutter

shell/platform/fuchsia/flutter/file_in_namespace_buffer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ class FileInNamespaceBuffer final : public fml::Mapping {
2222
// |fml::Mapping|
2323
const uint8_t* GetMapping() const override;
2424

25+
// |fml::Mapping|
26+
uint8_t* GetMutableMapping() const override { return nullptr; }
27+
2528
// |fml::Mapping|
2629
size_t GetSize() const override;
2730

0 commit comments

Comments
 (0)