未验证 提交 ccdb6819 编写于 作者: D Daco Harkes 提交者: GitHub

WeakPersistentHandle migration (#19843)

and roll Dart to 52783837369de45d3372cb6c6b7cdd63e71cd829.
上级 78a01817
......@@ -98,6 +98,7 @@ group("flutter") {
"//flutter/shell/platform/embedder:embedder_proctable_unittests",
"//flutter/shell/platform/embedder:embedder_unittests",
"//flutter/testing:testing_unittests",
"//flutter/third_party/tonic/tests:tonic_unittests",
"//flutter/third_party/txt:txt_unittests",
]
......
......@@ -34,7 +34,7 @@ vars = {
# Dart is: https://github.com/dart-lang/sdk/blob/master/DEPS.
# You can use //tools/dart/create_updated_flutter_deps.py to produce
# updated revision list of existing dependencies.
'dart_revision': 'd2577410a5016eadc111919355e19d42dd45d816',
'dart_revision': '52783837369de45d3372cb6c6b7cdd63e71cd829',
# WARNING: DO NOT EDIT MANUALLY
# The lines between blank lines above and below are generated by a script. See create_updated_flutter_deps.py
......
......@@ -1463,6 +1463,8 @@ FILE: ../../../flutter/third_party/tonic/dart_persistent_value.cc
FILE: ../../../flutter/third_party/tonic/dart_persistent_value.h
FILE: ../../../flutter/third_party/tonic/dart_state.cc
FILE: ../../../flutter/third_party/tonic/dart_state.h
FILE: ../../../flutter/third_party/tonic/dart_weak_persistent_value.cc
FILE: ../../../flutter/third_party/tonic/dart_weak_persistent_value.h
FILE: ../../../flutter/third_party/tonic/dart_wrappable.cc
FILE: ../../../flutter/third_party/tonic/dart_wrappable.h
FILE: ../../../flutter/third_party/tonic/dart_wrapper_info.h
......
Signature: c55e82fda8f939e4cdbeb9c2c004e7d9
Signature: 51a79de001f82d05f084b671f6216a31
UNUSED LICENSES:
......@@ -224,12 +224,13 @@ void ImageDecoder::Decode(fml::RefPtr<ImageDescriptor> descriptor,
FML_DCHECK(callback);
FML_DCHECK(runners_.GetUITaskRunner()->RunsTasksOnCurrentThread());
// Always service the callback on the UI thread.
auto result = [callback, ui_runner = runners_.GetUITaskRunner()](
// Always service the callback (and cleanup the descriptor) on the UI thread.
auto result = [callback, descriptor, ui_runner = runners_.GetUITaskRunner()](
SkiaGPUObject<SkImage> image,
fml::tracing::TraceFlow flow) {
ui_runner->PostTask(fml::MakeCopyable(
[callback, image = std::move(image), flow = std::move(flow)]() mutable {
ui_runner->PostTask(
fml::MakeCopyable([callback, descriptor, image = std::move(image),
flow = std::move(flow)]() mutable {
// We are going to terminate the trace flow here. Flows cannot
// terminate without a base trace. Add one explicitly.
TRACE_EVENT0("flutter", "ImageDecodeCallback");
......
......@@ -35,9 +35,7 @@ enum ImageByteFormat {
kPNG,
};
void FinalizeSkData(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
void* peer) {
void FinalizeSkData(void* isolate_callback_data, void* peer) {
SkData* buffer = reinterpret_cast<SkData*>(peer);
buffer->unref();
}
......
......@@ -981,6 +981,11 @@ void DartIsolate::AddIsolateShutdownCallback(const fml::closure& closure) {
}
void DartIsolate::OnShutdownCallback() {
tonic::DartState* state = tonic::DartState::Current();
if (state != nullptr) {
state->SetIsShuttingDown();
}
{
tonic::DartApiScope api_scope;
Dart_Handle sticky_error = Dart_GetStickyError();
......
......@@ -1922,8 +1922,7 @@ FlutterEngineResult FlutterEnginePostDartObject(
dart_object.value.as_external_typed_data.data = buffer;
dart_object.value.as_external_typed_data.peer = peer;
dart_object.value.as_external_typed_data.callback =
+[](void* unused_isolate_callback_data,
Dart_WeakPersistentHandle unused_handle, void* peer) {
+[](void* unused_isolate_callback_data, void* peer) {
auto typed_peer = reinterpret_cast<ExternalTypedDataPeer*>(peer);
typed_peer->trampoline(typed_peer->user_data);
delete typed_peer;
......
......@@ -86,6 +86,10 @@ void IsolateShutdownCallback(void* isolate_group_data, void* isolate_data) {
tonic::DartMicrotaskQueue::GetForCurrentThread()->Destroy();
async_loop_quit(loop);
}
auto state =
static_cast<std::shared_ptr<tonic::DartState>*>(isolate_group_data);
state->get()->SetIsShuttingDown();
}
void IsolateGroupCleanupCallback(void* isolate_group_data) {
......
......@@ -132,6 +132,8 @@ def RunCCTests(build_dir, filter):
RunEngineExecutable(build_dir, 'runtime_unittests', filter, shuffle_flags)
RunEngineExecutable(build_dir, 'tonic_unittests', filter, shuffle_flags)
if not IsWindows():
# https://github.com/flutter/flutter/issues/36295
RunEngineExecutable(build_dir, 'shell_unittests', filter, shuffle_flags)
......
......@@ -35,6 +35,8 @@ source_set("tonic") {
"dart_persistent_value.h",
"dart_state.cc",
"dart_state.h",
"dart_weak_persistent_value.cc",
"dart_weak_persistent_value.h",
"dart_wrappable.cc",
"dart_wrappable.h",
"dart_wrapper_info.h",
......
......@@ -27,7 +27,8 @@ DartState::DartState(int dirfd,
message_handler_(new DartMessageHandler()),
file_loader_(new FileLoader(dirfd)),
message_epilogue_(message_epilogue),
has_set_return_code_(false) {}
has_set_return_code_(false),
is_shutting_down_(false) {}
DartState::~DartState() {}
......
......@@ -5,6 +5,7 @@
#ifndef LIB_TONIC_DART_STATE_H_
#define LIB_TONIC_DART_STATE_H_
#include <atomic>
#include <functional>
#include <memory>
......@@ -68,6 +69,9 @@ class DartState : public std::enable_shared_from_this<DartState> {
void SetReturnCodeCallback(std::function<void(uint32_t)> callback);
bool has_set_return_code() const { return has_set_return_code_; }
void SetIsShuttingDown() { is_shutting_down_ = true; }
bool IsShuttingDown() { return is_shutting_down_; }
virtual void DidSetIsolate();
static Dart_Handle HandleLibraryTag(Dart_LibraryTag tag,
......@@ -83,6 +87,7 @@ class DartState : public std::enable_shared_from_this<DartState> {
std::function<void(Dart_Handle)> message_epilogue_;
std::function<void(uint32_t)> set_return_code_callback_;
bool has_set_return_code_;
std::atomic<bool> is_shutting_down_;
protected:
TONIC_DISALLOW_COPY_AND_ASSIGN(DartState);
......
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "tonic/dart_weak_persistent_value.h"
#include "tonic/dart_state.h"
#include "tonic/scopes/dart_isolate_scope.h"
namespace tonic {
DartWeakPersistentValue::DartWeakPersistentValue() : handle_(nullptr) {}
DartWeakPersistentValue::~DartWeakPersistentValue() {
Clear();
}
void DartWeakPersistentValue::Set(DartState* dart_state,
Dart_Handle object,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback) {
TONIC_DCHECK(is_empty());
dart_state_ = dart_state->GetWeakPtr();
handle_ = Dart_NewWeakPersistentHandle(object, peer, external_allocation_size,
callback);
}
void DartWeakPersistentValue::Clear() {
if (!handle_) {
return;
}
auto dart_state = dart_state_.lock();
if (!dart_state) {
// The DartVM that the handle used to belong to has been shut down and that
// handle has already been deleted.
handle_ = nullptr;
return;
}
// The DartVM frees the handles during shutdown and calls the finalizers.
// Freeing handles during shutdown would fail.
if (!dart_state->IsShuttingDown()) {
if (Dart_CurrentIsolateGroup()) {
Dart_DeleteWeakPersistentHandle(handle_);
} else {
// If we are not on the mutator thread, this will fail. The caller must
// ensure to be on the mutator thread.
DartIsolateScope scope(dart_state->isolate());
Dart_DeleteWeakPersistentHandle(handle_);
}
}
// If it's shutting down, the handle will be deleted already.
dart_state_.reset();
handle_ = nullptr;
}
Dart_Handle DartWeakPersistentValue::Get() {
auto dart_state = dart_state_.lock();
TONIC_DCHECK(dart_state);
TONIC_DCHECK(!dart_state->IsShuttingDown());
if (!handle_) {
return nullptr;
}
return Dart_HandleFromWeakPersistent(handle_);
}
} // namespace tonic
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_TONIC_DART_WEAK_PERSISTENT_VALUE_H_
#define LIB_TONIC_DART_WEAK_PERSISTENT_VALUE_H_
#include <memory>
#include "third_party/dart/runtime/include/dart_api.h"
#include "tonic/common/macros.h"
namespace tonic {
class DartState;
// DartWeakPersistentValue is a bookkeeping class to help pair calls to
// Dart_NewWeakPersistentHandle with Dart_DeleteWeakPersistentHandle even in
// the case if IsolateGroup shutdown. Consider using this class instead of
// holding a Dart_PersistentHandle directly so that you don't leak the
// Dart_WeakPersistentHandle.
class DartWeakPersistentValue {
public:
DartWeakPersistentValue();
~DartWeakPersistentValue();
Dart_WeakPersistentHandle value() const { return handle_; }
bool is_empty() const { return handle_ == nullptr; }
void Set(DartState* dart_state,
Dart_Handle object,
void* peer,
intptr_t external_allocation_size,
Dart_HandleFinalizer callback);
void Clear();
Dart_Handle Get();
const std::weak_ptr<DartState>& dart_state() const { return dart_state_; }
private:
std::weak_ptr<DartState> dart_state_;
Dart_WeakPersistentHandle handle_;
TONIC_DISALLOW_COPY_AND_ASSIGN(DartWeakPersistentValue);
};
} // namespace tonic
#endif // LIB_TONIC_DART_WEAK_PERSISTENT_VALUE_H_
......@@ -12,12 +12,17 @@
namespace tonic {
DartWrappable::~DartWrappable() {
TONIC_CHECK(!dart_wrapper_);
// Calls the destructor of dart_wrapper_ to delete WeakPersistentHandle.
}
// TODO(dnfield): Delete this. https://github.com/flutter/flutter/issues/50997
Dart_Handle DartWrappable::CreateDartWrapper(DartState* dart_state) {
TONIC_DCHECK(!dart_wrapper_);
if (!dart_wrapper_.is_empty()) {
// Any previously given out wrapper must have been GCed.
TONIC_DCHECK(Dart_IsNull(dart_wrapper_.Get()));
dart_wrapper_.Clear();
}
const DartWrapperInfo& info = GetDartWrapperInfo();
Dart_PersistentHandle type = dart_state->class_library().GetClass(info);
......@@ -36,14 +41,19 @@ Dart_Handle DartWrappable::CreateDartWrapper(DartState* dart_state) {
TONIC_DCHECK(!LogIfError(res));
this->RetainDartWrappableReference(); // Balanced in FinalizeDartWrapper.
dart_wrapper_ = Dart_NewWeakPersistentHandle(
wrapper, this, GetAllocationSize(), &FinalizeDartWrapper);
dart_wrapper_.Set(dart_state, wrapper, this, GetAllocationSize(),
&FinalizeDartWrapper);
return wrapper;
}
void DartWrappable::AssociateWithDartWrapper(Dart_Handle wrapper) {
TONIC_DCHECK(!dart_wrapper_);
if (!dart_wrapper_.is_empty()) {
// Any previously given out wrapper must have been GCed.
TONIC_DCHECK(Dart_IsNull(dart_wrapper_.Get()));
dart_wrapper_.Clear();
}
TONIC_CHECK(!LogIfError(wrapper));
const DartWrapperInfo& info = GetDartWrapperInfo();
......@@ -54,26 +64,25 @@ void DartWrappable::AssociateWithDartWrapper(Dart_Handle wrapper) {
wrapper, kWrapperInfoIndex, reinterpret_cast<intptr_t>(&info))));
this->RetainDartWrappableReference(); // Balanced in FinalizeDartWrapper.
dart_wrapper_ = Dart_NewWeakPersistentHandle(
wrapper, this, GetAllocationSize(), &FinalizeDartWrapper);
DartState* dart_state = DartState::Current();
dart_wrapper_.Set(dart_state, wrapper, this, GetAllocationSize(),
&FinalizeDartWrapper);
}
void DartWrappable::ClearDartWrapper() {
TONIC_DCHECK(dart_wrapper_);
Dart_Handle wrapper = Dart_HandleFromWeakPersistent(dart_wrapper_);
TONIC_DCHECK(!dart_wrapper_.is_empty());
Dart_Handle wrapper = dart_wrapper_.Get();
TONIC_CHECK(!LogIfError(Dart_SetNativeInstanceField(wrapper, kPeerIndex, 0)));
TONIC_CHECK(
!LogIfError(Dart_SetNativeInstanceField(wrapper, kWrapperInfoIndex, 0)));
Dart_DeleteWeakPersistentHandle(dart_wrapper_);
dart_wrapper_ = nullptr;
dart_wrapper_.Clear();
this->ReleaseDartWrappableReference();
}
void DartWrappable::FinalizeDartWrapper(void* isolate_callback_data,
Dart_WeakPersistentHandle wrapper,
void* peer) {
DartWrappable* wrappable = reinterpret_cast<DartWrappable*>(peer);
wrappable->dart_wrapper_ = nullptr;
wrappable->ReleaseDartWrappableReference(); // Balanced in CreateDartWrapper.
}
......
......@@ -9,6 +9,7 @@
#include "tonic/common/macros.h"
#include "tonic/converter/dart_converter.h"
#include "tonic/dart_state.h"
#include "tonic/dart_weak_persistent_value.h"
#include "tonic/dart_wrapper_info.h"
#include "tonic/logging/dart_error.h"
......@@ -26,7 +27,7 @@ class DartWrappable {
kNumberOfNativeFields,
};
DartWrappable() : dart_wrapper_(nullptr) {}
DartWrappable() : dart_wrapper_(DartWeakPersistentValue()) {}
// Subclasses that wish to expose a new interface must override this function
// and provide information about their wrapper. There is no need to call your
......@@ -49,7 +50,9 @@ class DartWrappable {
Dart_Handle CreateDartWrapper(DartState* dart_state);
void AssociateWithDartWrapper(Dart_Handle wrappable);
void ClearDartWrapper(); // Warning: Might delete this.
Dart_WeakPersistentHandle dart_wrapper() const { return dart_wrapper_; }
Dart_WeakPersistentHandle dart_wrapper() const {
return dart_wrapper_.value();
}
protected:
virtual ~DartWrappable();
......@@ -59,11 +62,9 @@ class DartWrappable {
const tonic::DartWrapperInfo& wrapper_info);
private:
static void FinalizeDartWrapper(void* isolate_callback_data,
Dart_WeakPersistentHandle wrapper,
void* peer);
static void FinalizeDartWrapper(void* isolate_callback_data, void* peer);
Dart_WeakPersistentHandle dart_wrapper_;
DartWeakPersistentValue dart_wrapper_;
TONIC_DISALLOW_COPY_AND_ASSIGN(DartWrappable);
};
......@@ -103,22 +104,36 @@ struct DartConverter<
typename std::enable_if<
std::is_convertible<T*, const DartWrappable*>::value>::type> {
static Dart_Handle ToDart(DartWrappable* val) {
if (!val)
if (!val) {
return Dart_Null();
if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper())
return Dart_HandleFromWeakPersistent(wrapper);
}
if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) {
auto strong_handle = Dart_HandleFromWeakPersistent(wrapper);
if (!Dart_IsNull(strong_handle)) {
return strong_handle;
}
// After the weak referenced object has been GCed, the handle points to
// Dart_Null(). Fall through create a new wrapper object.
}
return val->CreateDartWrapper(DartState::Current());
}
static void SetReturnValue(Dart_NativeArguments args,
DartWrappable* val,
bool auto_scope = true) {
if (!val)
if (!val) {
Dart_SetReturnValue(args, Dart_Null());
else if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper())
Dart_SetWeakHandleReturnValue(args, wrapper);
else
Dart_SetReturnValue(args, val->CreateDartWrapper(DartState::Current()));
return;
} else if (Dart_WeakPersistentHandle wrapper = val->dart_wrapper()) {
auto strong_handle = Dart_HandleFromWeakPersistent(wrapper);
if (!Dart_IsNull(strong_handle)) {
Dart_SetReturnValue(args, strong_handle);
return;
}
// After the weak referenced object has been GCed, the handle points to
// Dart_Null(). Fall through create a new wrapper object.
}
Dart_SetReturnValue(args, val->CreateDartWrapper(DartState::Current()));
}
static T* FromDart(Dart_Handle handle) {
......
# Copyright 2013 The Flutter Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//flutter/testing/testing.gni")
test_fixtures("tonic_fixtures") {
dart_main = "fixtures/tonic_test.dart"
fixtures = []
}
executable("tonic_unittests") {
testonly = true
public_configs = [ "//flutter:export_dynamic_symbols" ]
sources = [
"dart_state_unittest.cc",
"dart_weak_persistent_handle_unittest.cc",
]
public_deps = [
":tonic_fixtures",
"//flutter/runtime:libdart",
"//flutter/runtime:runtime",
"//flutter/testing",
"//flutter/testing:fixture_test",
"//third_party/dart/runtime:dart_api",
"//third_party/googletest:gtest",
]
deps = [ "../:tonic" ]
}
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/common/task_runners.h"
#include "flutter/runtime/dart_vm_lifecycle.h"
#include "flutter/runtime/isolate_configuration.h"
#include "flutter/testing/fixture_test.h"
namespace flutter {
namespace testing {
using DartState = FixtureTest;
TEST_F(DartState, IsShuttingDown) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
auto settings = CreateSettingsForFixture();
auto vm_ref = DartVMRef::Create(settings);
ASSERT_TRUE(vm_ref);
auto vm_data = vm_ref.GetVMData();
ASSERT_TRUE(vm_data);
TaskRunners task_runners(GetCurrentTestName(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner(), //
GetCurrentTaskRunner() //
);
auto isolate_configuration =
IsolateConfiguration::InferFromSettings(settings);
auto weak_isolate = DartIsolate::CreateRunningRootIsolate(
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
std::move(task_runners), // task runners
nullptr, // window
{}, // snapshot delegate
{}, // hint freed delegate
{}, // io manager
{}, // unref queue
{}, // image decoder
"main.dart", // advisory uri
"main", // advisory entrypoint
DartIsolate::Flags{}, // flags
settings.isolate_create_callback, // isolate create callback
settings.isolate_shutdown_callback, // isolate shutdown callback
"main", // dart entrypoint
std::nullopt, // dart entrypoint library
std::move(isolate_configuration) // isolate configuration
);
auto root_isolate = weak_isolate.lock();
ASSERT_TRUE(root_isolate);
tonic::DartState* dart_state = root_isolate.get();
ASSERT_FALSE(dart_state->IsShuttingDown());
ASSERT_TRUE(root_isolate->Shutdown());
ASSERT_TRUE(dart_state->IsShuttingDown());
}
} // namespace testing
} // namespace flutter
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/testing/dart_isolate_runner.h"
#include "flutter/testing/fixture_test.h"
namespace flutter {
namespace testing {
class DartWeakPersistentHandle : public FixtureTest {
public:
DartWeakPersistentHandle()
: settings_(CreateSettingsForFixture()),
vm_(DartVMRef::Create(settings_)) {}
~DartWeakPersistentHandle() = default;
[[nodiscard]] bool RunWithEntrypoint(const std::string& entrypoint) {
if (running_isolate_) {
return false;
}
auto thread = CreateNewThread();
TaskRunners single_threaded_task_runner(GetCurrentTestName(), thread,
thread, thread, thread);
auto isolate =
RunDartCodeInIsolate(vm_, settings_, single_threaded_task_runner,
entrypoint, {}, GetFixturesPath());
if (!isolate || isolate->get()->GetPhase() != DartIsolate::Phase::Running) {
return false;
}
running_isolate_ = std::move(isolate);
return true;
}
[[nodiscard]] bool RunInIsolateScope(std::function<bool(void)> closure) {
return running_isolate_->RunInIsolateScope(closure);
}
private:
Settings settings_;
DartVMRef vm_;
std::unique_ptr<AutoIsolateShutdown> running_isolate_;
FML_DISALLOW_COPY_AND_ASSIGN(DartWeakPersistentHandle);
};
void NopFinalizer(void* isolate_callback_data, void* peer) {}
TEST_F(DartWeakPersistentHandle, ClearImmediately) {
auto weak_persistent_value = tonic::DartWeakPersistentValue();
fml::AutoResetWaitableEvent event;
AddNativeCallback(
"GiveObjectToNative", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
auto handle = Dart_GetNativeArgument(args, 0);
auto dart_state = tonic::DartState::Current();
ASSERT_TRUE(dart_state);
ASSERT_TRUE(tonic::DartState::Current());
weak_persistent_value.Set(dart_state, handle, nullptr, 0, NopFinalizer);
weak_persistent_value.Clear();
event.Signal();
}));
ASSERT_TRUE(RunWithEntrypoint("callGiveObjectToNative"));
event.Wait();
}
TEST_F(DartWeakPersistentHandle, ClearLaterCc) {
auto weak_persistent_value = tonic::DartWeakPersistentValue();
fml::AutoResetWaitableEvent event;
AddNativeCallback(
"GiveObjectToNative", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
auto handle = Dart_GetNativeArgument(args, 0);
auto dart_state = tonic::DartState::Current();
ASSERT_TRUE(dart_state);
ASSERT_TRUE(tonic::DartState::Current());
weak_persistent_value.Set(dart_state, handle, nullptr, 0, NopFinalizer);
// Do not clear handle immediately.
event.Signal();
}));
ASSERT_TRUE(RunWithEntrypoint("callGiveObjectToNative"));
event.Wait();
ASSERT_TRUE(RunInIsolateScope([&weak_persistent_value]() -> bool {
// Clear on initiative of native.
weak_persistent_value.Clear();
return true;
}));
}
TEST_F(DartWeakPersistentHandle, ClearLaterDart) {
auto weak_persistent_value = tonic::DartWeakPersistentValue();
fml::AutoResetWaitableEvent event;
AddNativeCallback(
"GiveObjectToNative", CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
auto handle = Dart_GetNativeArgument(args, 0);
auto dart_state = tonic::DartState::Current();
ASSERT_TRUE(dart_state);
ASSERT_TRUE(tonic::DartState::Current());
weak_persistent_value.Set(dart_state, handle, nullptr, 0, NopFinalizer);
// Do not clear handle immediately.
}));
AddNativeCallback("SignalDone",
CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
// Clear on initiative of Dart.
weak_persistent_value.Clear();
event.Signal();
}));
ASSERT_TRUE(RunWithEntrypoint("testClearLater"));
event.Wait();
}
// Handle outside the test body scope so it survives until isolate shutdown.
tonic::DartWeakPersistentValue global_weak_persistent_value =
tonic::DartWeakPersistentValue();
TEST_F(DartWeakPersistentHandle, ClearOnShutdown) {
fml::AutoResetWaitableEvent event;
AddNativeCallback("GiveObjectToNative",
CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) {
auto handle = Dart_GetNativeArgument(args, 0);
auto dart_state = tonic::DartState::Current();
ASSERT_TRUE(dart_state);
ASSERT_TRUE(tonic::DartState::Current());
// The test is repeated, ensure the global var is
// cleared before use.
global_weak_persistent_value.Clear();
global_weak_persistent_value.Set(
dart_state, handle, nullptr, 0, NopFinalizer);
// Do not clear handle, so it is cleared on shutdown.
event.Signal();
}));
ASSERT_TRUE(RunWithEntrypoint("callGiveObjectToNative"));
event.Wait();
}
} // namespace testing
} // namespace flutter
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
void main() {}
class SomeClass {
int i;
SomeClass(this.i);
}
void giveObjectToNative(Object someObject) native 'GiveObjectToNative';
void signalDone() native 'SignalDone';
@pragma('vm:entry-point')
void callGiveObjectToNative() {
giveObjectToNative(SomeClass(123));
}
@pragma('vm:entry-point')
void testClearLater() {
giveObjectToNative(SomeClass(123));
signalDone();
}
......@@ -16,9 +16,7 @@ namespace {
// with a buffer allocated outside the Dart heap.
const int kExternalSizeThreshold = 1000;
void FreeFinalizer(void* isolate_callback_data,
Dart_WeakPersistentHandle handle,
void* peer) {
void FreeFinalizer(void* isolate_callback_data, void* peer) {
free(peer);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册