[vm] Native API: Make Dart_NewWeakPersistentHandle not auto delete
Changes Dart_NewWeakPersistentHandle to no longer auto delete the weak persistent handle. Changes the signatures of WeakPersistentHandleFinalizers to no longer have access to the handle. Flutter PR: https://github.com/flutter/engine/pull/19843 g3 presubmit: cl/318028238 Issue: https://github.com/dart-lang/sdk/issues/42312 TEST=runtime/vm/dart_api_impl_test.cc Change-Id: I3f77db9954d9486759f903b78c03a494f73c68ba Cq-Include-Trybots:dart/try:vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64-try,app-kernel-linux-debug-x64-try,vm-kernel-linux-debug-ia32-try,vm-kernel-win-debug-x64-try,vm-kernel-win-debug-ia32-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-android-release-arm64-try,vm-kernel-asan-linux-release-x64-try,vm-kernel-msan-linux-release-x64-try,vm-kernel-precomp-msan-linux-release-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-precomp-android-release-arm_x64-try,vm-kernel-precomp-obfuscate-linux-release-x64-try,dart-sdk-linux-try,analyzer-analysis-server-linux-try,analyzer-linux-release-try,front-end-linux-release-x64-try,vm-kernel-precomp-win-release-x64-try,vm-kernel-mac-debug-x64-try,vm-precomp-ffi-qemu-linux-release-arm-try,vm-kernel-nnbd-linux-debug-x64-try,analyzer-nnbd-linux-release-try,front-end-nnbd-linux-release-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/151525 Commit-Queue: Daco Harkes <dacoharkes@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
6cfd46e177
commit
5278383736
@@ -27,6 +27,16 @@ opted out of null safety by adding `// @dart=2.9` to the beginning of the file.
|
||||
|
||||
### Dart VM
|
||||
|
||||
* **Breaking Change** [#42312][]: `Dart_WeakPersistentHandle`s will no longer
|
||||
auto-delete themselves when the referenced object is garbage collected to
|
||||
avoid race conditions, but they are still automatically deleted when the
|
||||
isolate group shuts down.
|
||||
* **Breaking Change** [#42312][]: `Dart_WeakPersistentHandleFinalizer`
|
||||
is renamed to `Dart_HandleFinalizer` and had its `handle` argument removed.
|
||||
All api functions using that type have been updated.
|
||||
|
||||
[#42312]: https://github.com/dart-lang/sdk/issues/42312
|
||||
|
||||
### Dart2JS
|
||||
|
||||
* Removed `--no-defer-class-types` and `--no-new-deferred-split`.
|
||||
|
||||
@@ -905,11 +905,10 @@ Dart_CObject* CObject::NewUint32Array(intptr_t length) {
|
||||
return cobject;
|
||||
}
|
||||
|
||||
Dart_CObject* CObject::NewExternalUint8Array(
|
||||
intptr_t length,
|
||||
uint8_t* data,
|
||||
void* peer,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
Dart_CObject* CObject::NewExternalUint8Array(intptr_t length,
|
||||
uint8_t* data,
|
||||
void* peer,
|
||||
Dart_HandleFinalizer callback) {
|
||||
Dart_CObject* cobject = New(Dart_CObject_kExternalTypedData);
|
||||
cobject->value.as_external_typed_data.type = Dart_TypedData_kUint8;
|
||||
cobject->value.as_external_typed_data.length = length;
|
||||
@@ -937,7 +936,7 @@ Dart_CObject* CObject::NewIOBuffer(int64_t length) {
|
||||
void CObject::FreeIOBufferData(Dart_CObject* cobject) {
|
||||
ASSERT(cobject->type == Dart_CObject_kExternalTypedData);
|
||||
cobject->value.as_external_typed_data.callback(
|
||||
NULL, NULL, cobject->value.as_external_typed_data.peer);
|
||||
NULL, cobject->value.as_external_typed_data.peer);
|
||||
cobject->value.as_external_typed_data.data = NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -344,11 +344,10 @@ class CObject {
|
||||
static Dart_CObject* NewArray(intptr_t length);
|
||||
static Dart_CObject* NewUint8Array(intptr_t length);
|
||||
static Dart_CObject* NewUint32Array(intptr_t length);
|
||||
static Dart_CObject* NewExternalUint8Array(
|
||||
intptr_t length,
|
||||
uint8_t* data,
|
||||
void* peer,
|
||||
Dart_WeakPersistentHandleFinalizer callback);
|
||||
static Dart_CObject* NewExternalUint8Array(intptr_t length,
|
||||
uint8_t* data,
|
||||
void* peer,
|
||||
Dart_HandleFinalizer callback);
|
||||
|
||||
static Dart_CObject* NewIOBuffer(int64_t length);
|
||||
static void FreeIOBufferData(Dart_CObject* object);
|
||||
@@ -571,7 +570,7 @@ class CObjectExternalUint8Array : public CObject {
|
||||
}
|
||||
uint8_t* Data() const { return cobject_->value.as_external_typed_data.data; }
|
||||
void* Peer() const { return cobject_->value.as_external_typed_data.peer; }
|
||||
Dart_WeakPersistentHandleFinalizer Callback() const {
|
||||
Dart_HandleFinalizer Callback() const {
|
||||
return cobject_->value.as_external_typed_data.callback;
|
||||
}
|
||||
|
||||
|
||||
@@ -475,7 +475,7 @@ DART_EXPORT void ExecuteCallback(Work* work_ptr) {
|
||||
|
||||
Dart_Port send_port_;
|
||||
|
||||
static void FreeFinalizer(void*, Dart_WeakPersistentHandle, void* value) {
|
||||
static void FreeFinalizer(void*, void* value) {
|
||||
free(value);
|
||||
}
|
||||
|
||||
@@ -776,9 +776,7 @@ DART_EXPORT void ThreadPoolTest_BarrierSync(
|
||||
// vmspecific_handle_test.dart (statically linked).
|
||||
// vmspecific_handle_dynamically_linked_test.dart (dynamically linked).
|
||||
|
||||
static void RunFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
static void RunFinalizer(void* isolate_callback_data, void* peer) {
|
||||
printf("Running finalizer for weak handle.\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,7 @@ class IOBuffer {
|
||||
static void Free(void* buffer) { free(buffer); }
|
||||
|
||||
// Function for finalizing external byte arrays used as IO buffers.
|
||||
static void Finalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* buffer) {
|
||||
static void Finalizer(void* isolate_callback_data, void* buffer) {
|
||||
Free(buffer);
|
||||
}
|
||||
|
||||
|
||||
+26
-33
@@ -244,8 +244,9 @@ typedef struct _Dart_IsolateGroup* Dart_IsolateGroup;
|
||||
* the object is garbage collected. It is never safe to use these handles
|
||||
* unless you know the object is still reachable.
|
||||
*
|
||||
* WeakPersistentHandles are persistent handles which are auto deleted
|
||||
* when the object is garbage collected.
|
||||
* WeakPersistentHandles are persistent handles which are automatically set
|
||||
* to point Dart_Null when the object is garbage collected. They are not auto
|
||||
* deleted, so it is safe to use them after the object has become unreachable.
|
||||
*/
|
||||
typedef struct _Dart_Handle* Dart_Handle;
|
||||
typedef Dart_Handle Dart_PersistentHandle;
|
||||
@@ -254,10 +255,6 @@ typedef struct _Dart_FinalizableHandle* Dart_FinalizableHandle;
|
||||
// These structs are versioned by DART_API_DL_MAJOR_VERSION, bump the
|
||||
// version when changing this struct.
|
||||
|
||||
typedef void (*Dart_WeakPersistentHandleFinalizer)(
|
||||
void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer);
|
||||
typedef void (*Dart_HandleFinalizer)(void* isolate_callback_data, void* peer);
|
||||
|
||||
/**
|
||||
@@ -423,6 +420,8 @@ DART_EXPORT Dart_Handle Dart_HandleFromPersistent(Dart_PersistentHandle object);
|
||||
|
||||
/**
|
||||
* Allocates a handle in the current scope from a weak persistent handle.
|
||||
*
|
||||
* This will be a handle to Dart_Null if the object has been garbage collected.
|
||||
*/
|
||||
DART_EXPORT Dart_Handle
|
||||
Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object);
|
||||
@@ -461,24 +460,18 @@ DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object);
|
||||
/**
|
||||
* Allocates a weak persistent handle for an object.
|
||||
*
|
||||
* This handle has the lifetime of the current isolate unless the object
|
||||
* pointed to by the handle is garbage collected, in this case the VM
|
||||
* automatically deletes the handle after invoking the callback associated
|
||||
* with the handle. The handle can also be explicitly deallocated by
|
||||
* calling Dart_DeleteWeakPersistentHandle.
|
||||
* This handle has the lifetime of the current isolate. The handle can also be
|
||||
* explicitly deallocated by calling Dart_DeleteWeakPersistentHandle.
|
||||
*
|
||||
* If the object becomes unreachable the callback is invoked with the weak
|
||||
* persistent handle and the peer as arguments. The callback can be executed on
|
||||
* any thread, will have an isolate group, but will not have a current isolate.
|
||||
* The callback can only call Dart_DeletePersistentHandle or
|
||||
* Dart_DeleteWeakPersistentHandle. The callback must not call
|
||||
* Dart_DeleteWeakPersistentHandle for the handle being finalized, as it is
|
||||
* automatically deleted by the VM after the callback returns. This gives the
|
||||
* embedder the ability to cleanup data associated with the object and clear
|
||||
* out any cached references to the handle. All references to this handle after
|
||||
* the callback will be invalid. It is illegal to call into the VM with any
|
||||
* other Dart_* functions from the callback. If the handle is deleted before
|
||||
* the object becomes unreachable, the callback is never invoked.
|
||||
* If the object becomes unreachable the callback is invoked with the peer as
|
||||
* argument. The callback can be executed on any thread, will have a current
|
||||
* isolate group, but will not have a current isolate. The callback can only
|
||||
* call Dart_DeletePersistentHandle or Dart_DeleteWeakPersistentHandle. This
|
||||
* gives the embedder the ability to cleanup data associated with the object.
|
||||
* The handle will point to the Dart_Null object after the finalizer has been
|
||||
* run. It is illegal to call into the VM with any other Dart_* functions from
|
||||
* the callback. If the handle is deleted before the object becomes
|
||||
* unreachable, the callback is never invoked.
|
||||
*
|
||||
* Requires there to be a current isolate.
|
||||
*
|
||||
@@ -498,7 +491,7 @@ DART_EXPORT Dart_WeakPersistentHandle
|
||||
Dart_NewWeakPersistentHandle(Dart_Handle object,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback);
|
||||
Dart_HandleFinalizer callback);
|
||||
|
||||
/**
|
||||
* Deletes the given weak persistent [object] handle.
|
||||
@@ -2046,7 +2039,7 @@ Dart_NewExternalLatin1String(const uint8_t* latin1_array,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback);
|
||||
Dart_HandleFinalizer callback);
|
||||
|
||||
/**
|
||||
* Returns a String which references an external array of UTF-16 encoded
|
||||
@@ -2067,7 +2060,7 @@ Dart_NewExternalUTF16String(const uint16_t* utf16_array,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback);
|
||||
Dart_HandleFinalizer callback);
|
||||
|
||||
/**
|
||||
* Gets the C string representation of a String.
|
||||
@@ -2440,13 +2433,13 @@ DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type,
|
||||
* \return The TypedData object if no error occurs. Otherwise returns
|
||||
* an error handle.
|
||||
*/
|
||||
DART_EXPORT Dart_Handle Dart_NewExternalTypedDataWithFinalizer(
|
||||
Dart_TypedData_Type type,
|
||||
void* data,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback);
|
||||
DART_EXPORT Dart_Handle
|
||||
Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type,
|
||||
void* data,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_HandleFinalizer callback);
|
||||
|
||||
/**
|
||||
* Returns a ByteBuffer object for the typed data.
|
||||
|
||||
@@ -84,7 +84,7 @@ typedef void (*Dart_NativeMessageHandler_DL)(Dart_Port_DL dest_port_id,
|
||||
F(Dart_DeletePersistentHandle, void, (Dart_PersistentHandle object)) \
|
||||
F(Dart_NewWeakPersistentHandle, Dart_WeakPersistentHandle, \
|
||||
(Dart_Handle object, void* peer, intptr_t external_allocation_size, \
|
||||
Dart_WeakPersistentHandleFinalizer callback)) \
|
||||
Dart_HandleFinalizer callback)) \
|
||||
F(Dart_DeleteWeakPersistentHandle, void, (Dart_WeakPersistentHandle object)) \
|
||||
F(Dart_UpdateExternalSize, void, \
|
||||
(Dart_WeakPersistentHandle object, intptr_t external_allocation_size)) \
|
||||
|
||||
@@ -31,8 +31,7 @@
|
||||
* The data for kTypedData is copied on message send and ownership remains with
|
||||
* the caller. The ownership of data for kExternalTyped is passed to the VM on
|
||||
* message send and returned when the VM invokes the
|
||||
* Dart_WeakPersistentHandleFinalizer callback; a non-NULL callback must be
|
||||
* provided.
|
||||
* Dart_HandleFinalizer callback; a non-NULL callback must be provided.
|
||||
*/
|
||||
typedef enum {
|
||||
Dart_CObject_kNull = 0,
|
||||
@@ -79,7 +78,7 @@ typedef struct _Dart_CObject {
|
||||
intptr_t length;
|
||||
uint8_t* data;
|
||||
void* peer;
|
||||
Dart_WeakPersistentHandleFinalizer callback;
|
||||
Dart_HandleFinalizer callback;
|
||||
} as_external_typed_data;
|
||||
} value;
|
||||
} Dart_CObject;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
// On breaking changes the major version is increased.
|
||||
// On backwards compatible changes the minor version is increased.
|
||||
// The versioning covers the symbols exposed in dart_api_dl.h
|
||||
#define DART_API_DL_MAJOR_VERSION 1
|
||||
#define DART_API_DL_MINOR_VERSION 1
|
||||
#define DART_API_DL_MAJOR_VERSION 2
|
||||
#define DART_API_DL_MINOR_VERSION 0
|
||||
|
||||
#endif /* RUNTIME_INCLUDE_DART_VERSION_H_ */ /* NOLINT */
|
||||
|
||||
@@ -72,7 +72,7 @@ DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 0, 1) {
|
||||
DEFINE_NATIVE_ENTRY(VMService_SendObjectRootServiceMessage, 0, 1) {
|
||||
#ifndef PRODUCT
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
|
||||
return Service::HandleObjectRootMessage(message);
|
||||
return Service::HandleObjectRootMessage(message);
|
||||
#endif
|
||||
return Object::null();
|
||||
}
|
||||
@@ -307,16 +307,12 @@ class TarArchive {
|
||||
DISALLOW_COPY_AND_ASSIGN(TarArchive);
|
||||
};
|
||||
|
||||
static void ContentsFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
static void ContentsFinalizer(void* isolate_callback_data, void* peer) {
|
||||
uint8_t* data = reinterpret_cast<uint8_t*>(peer);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
static void FilenameFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
static void FilenameFinalizer(void* isolate_callback_data, void* peer) {
|
||||
char* filename = reinterpret_cast<char*>(peer);
|
||||
delete[] filename;
|
||||
}
|
||||
|
||||
@@ -201,9 +201,7 @@ BENCHMARK(UseDartApi) {
|
||||
benchmark->set_score(elapsed_time);
|
||||
}
|
||||
|
||||
static void NoopFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
//
|
||||
// Measure time accessing internal and external strings.
|
||||
|
||||
+41
-43
@@ -711,25 +711,22 @@ void FinalizablePersistentHandle::Finalize(
|
||||
if (!handle->raw()->IsHeapObject()) {
|
||||
return; // Free handle.
|
||||
}
|
||||
Dart_HandleFinalizer callback = handle->callback();
|
||||
ASSERT(callback != NULL);
|
||||
void* peer = handle->peer();
|
||||
ApiState* state = isolate_group->api_state();
|
||||
ASSERT(state != NULL);
|
||||
|
||||
ASSERT(handle->auto_delete());
|
||||
|
||||
if (handle->callback_signature_ == CallbackSignature::kHandleFinalizer) {
|
||||
Dart_HandleFinalizer callback = handle->callback();
|
||||
ASSERT(callback != NULL);
|
||||
(*callback)(isolate_group->embedder_data(), peer);
|
||||
} else {
|
||||
Dart_WeakPersistentHandleFinalizer callback =
|
||||
handle->CallbackWeakFinalizer();
|
||||
ASSERT(callback != NULL);
|
||||
Dart_WeakPersistentHandle object = handle->ApiWeakPersistentHandle();
|
||||
(*callback)(isolate_group->embedder_data(), object, peer);
|
||||
if (!handle->auto_delete()) {
|
||||
// Clear handle before running finalizer, finalizer can free the handle.
|
||||
state->ClearWeakPersistentHandle(handle);
|
||||
}
|
||||
|
||||
state->FreeWeakPersistentHandle(handle);
|
||||
(*callback)(isolate_group->embedder_data(), peer);
|
||||
|
||||
if (handle->auto_delete()) {
|
||||
state->FreeWeakPersistentHandle(handle);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Handles ---
|
||||
@@ -942,6 +939,9 @@ Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object) {
|
||||
NoSafepointScope no_safepoint_scope;
|
||||
FinalizablePersistentHandle* weak_ref =
|
||||
FinalizablePersistentHandle::Cast(object);
|
||||
if (weak_ref->IsFinalizedNotFreed()) {
|
||||
return Dart_Null();
|
||||
}
|
||||
return Api::NewHandle(thread, weak_ref->raw());
|
||||
}
|
||||
|
||||
@@ -986,14 +986,14 @@ static Dart_WeakPersistentHandle AllocateWeakPersistentHandle(
|
||||
const Object& ref,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
Dart_HandleFinalizer callback) {
|
||||
if (!ref.raw()->IsHeapObject()) {
|
||||
return NULL;
|
||||
}
|
||||
FinalizablePersistentHandle* finalizable_ref =
|
||||
FinalizablePersistentHandle::New(thread->isolate(), ref, peer, callback,
|
||||
external_allocation_size,
|
||||
/*auto_delete=*/true);
|
||||
/*auto_delete=*/false);
|
||||
return finalizable_ref->ApiWeakPersistentHandle();
|
||||
}
|
||||
|
||||
@@ -1002,7 +1002,7 @@ static Dart_WeakPersistentHandle AllocateWeakPersistentHandle(
|
||||
Dart_Handle object,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
Dart_HandleFinalizer callback) {
|
||||
REUSABLE_OBJECT_HANDLESCOPE(thread);
|
||||
Object& ref = thread->ObjectHandle();
|
||||
ref = Api::UnwrapHandle(object);
|
||||
@@ -1044,7 +1044,7 @@ DART_EXPORT Dart_WeakPersistentHandle
|
||||
Dart_NewWeakPersistentHandle(Dart_Handle object,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
Dart_HandleFinalizer callback) {
|
||||
Thread* thread = Thread::Current();
|
||||
CHECK_ISOLATE(thread->isolate());
|
||||
if (callback == NULL) {
|
||||
@@ -2961,7 +2961,7 @@ Dart_NewExternalLatin1String(const uint8_t* latin1_array,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
Dart_HandleFinalizer callback) {
|
||||
DARTSCOPE(Thread::Current());
|
||||
API_TIMELINE_DURATION(T);
|
||||
if (latin1_array == NULL && length != 0) {
|
||||
@@ -2983,7 +2983,7 @@ Dart_NewExternalUTF16String(const uint16_t* utf16_array,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
Dart_HandleFinalizer callback) {
|
||||
DARTSCOPE(Thread::Current());
|
||||
if (utf16_array == NULL && length != 0) {
|
||||
RETURN_NULL_ERROR(utf16_array);
|
||||
@@ -3933,14 +3933,13 @@ static Dart_Handle NewTypedData(Thread* thread, intptr_t cid, intptr_t length) {
|
||||
return Api::NewHandle(thread, TypedData::New(cid, length));
|
||||
}
|
||||
|
||||
static Dart_Handle NewExternalTypedData(
|
||||
Thread* thread,
|
||||
intptr_t cid,
|
||||
void* data,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
static Dart_Handle NewExternalTypedData(Thread* thread,
|
||||
intptr_t cid,
|
||||
void* data,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_HandleFinalizer callback) {
|
||||
CHECK_LENGTH(length, ExternalTypedData::MaxElements(cid));
|
||||
Zone* zone = thread->zone();
|
||||
intptr_t bytes = length * ExternalTypedData::ElementSizeInBytes(cid);
|
||||
@@ -3952,19 +3951,18 @@ static Dart_Handle NewExternalTypedData(
|
||||
result = ExternalTypedData::New(cid, reinterpret_cast<uint8_t*>(data), length,
|
||||
thread->heap()->SpaceForExternal(bytes));
|
||||
if (callback != nullptr) {
|
||||
AllocateWeakPersistentHandle(thread, result, peer, external_allocation_size,
|
||||
callback);
|
||||
AllocateFinalizableHandle(thread, result, peer, external_allocation_size,
|
||||
callback);
|
||||
}
|
||||
return Api::NewHandle(thread, result.raw());
|
||||
}
|
||||
|
||||
static Dart_Handle NewExternalByteData(
|
||||
Thread* thread,
|
||||
void* data,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
static Dart_Handle NewExternalByteData(Thread* thread,
|
||||
void* data,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_HandleFinalizer callback) {
|
||||
Zone* zone = thread->zone();
|
||||
Dart_Handle ext_data =
|
||||
NewExternalTypedData(thread, kExternalTypedDataUint8ArrayCid, data,
|
||||
@@ -4049,13 +4047,13 @@ DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type,
|
||||
NULL);
|
||||
}
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_NewExternalTypedDataWithFinalizer(
|
||||
Dart_TypedData_Type type,
|
||||
void* data,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback) {
|
||||
DART_EXPORT Dart_Handle
|
||||
Dart_NewExternalTypedDataWithFinalizer(Dart_TypedData_Type type,
|
||||
void* data,
|
||||
intptr_t length,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_HandleFinalizer callback) {
|
||||
DARTSCOPE(Thread::Current());
|
||||
if (data == NULL && length != 0) {
|
||||
RETURN_NULL_ERROR(data);
|
||||
|
||||
@@ -1430,9 +1430,7 @@ TEST_CASE(DartAPI_ArrayValues) {
|
||||
}
|
||||
}
|
||||
|
||||
static void NoopFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
TEST_CASE(DartAPI_IsString) {
|
||||
uint8_t latin1[] = {'o', 'n', 'e', 0xC2, 0xA2};
|
||||
@@ -1581,7 +1579,6 @@ TEST_CASE(DartAPI_MalformedStringToUTF8) {
|
||||
}
|
||||
|
||||
static void ExternalStringCallbackFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
*static_cast<int*>(peer) *= 2;
|
||||
}
|
||||
@@ -2258,9 +2255,7 @@ TEST_CASE(DartAPI_ExternalByteDataAccess) {
|
||||
}
|
||||
|
||||
static bool byte_data_finalizer_run = false;
|
||||
void ByteDataFinalizer(void* isolate_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
void ByteDataFinalizer(void* isolate_data, void* peer) {
|
||||
ASSERT(!byte_data_finalizer_run);
|
||||
free(peer);
|
||||
byte_data_finalizer_run = true;
|
||||
@@ -2789,22 +2784,13 @@ TEST_CASE(DartAPI_ExternalUint8ClampedArrayAccess) {
|
||||
EXPECT(value);
|
||||
}
|
||||
|
||||
static void NopCallback(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void NopCallback(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
static void UnreachedCallback(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
static void UnreachedCallback(void* isolate_callback_data, void* peer) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static void ExternalTypedDataFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
*static_cast<int*>(peer) = 42;
|
||||
}
|
||||
@@ -2855,22 +2841,24 @@ TEST_CASE(DartAPI_SlowFinalizer) {
|
||||
EXPECT_EQ(20, count);
|
||||
}
|
||||
|
||||
static void SlowWeakPersistentHandle(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
static void SlowWeakPersistentHandle(void* isolate_callback_data, void* peer) {
|
||||
OS::Sleep(10);
|
||||
intptr_t* count = reinterpret_cast<intptr_t*>(peer);
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_SlowWeakPersistenhandle) {
|
||||
Dart_WeakPersistentHandle handles[20];
|
||||
intptr_t count = 0;
|
||||
|
||||
for (intptr_t i = 0; i < 10; i++) {
|
||||
Dart_EnterScope();
|
||||
Dart_Handle str1 = Dart_NewStringFromCString("Live fast");
|
||||
Dart_NewWeakPersistentHandle(str1, &count, 0, SlowWeakPersistentHandle);
|
||||
handles[i] =
|
||||
Dart_NewWeakPersistentHandle(str1, &count, 0, SlowWeakPersistentHandle);
|
||||
Dart_Handle str2 = Dart_NewStringFromCString("Die young");
|
||||
Dart_NewWeakPersistentHandle(str2, &count, 0, SlowWeakPersistentHandle);
|
||||
handles[i + 10] =
|
||||
Dart_NewWeakPersistentHandle(str2, &count, 0, SlowWeakPersistentHandle);
|
||||
Dart_ExitScope();
|
||||
|
||||
{
|
||||
@@ -2880,6 +2868,10 @@ TEST_CASE(DartAPI_SlowWeakPersistenhandle) {
|
||||
}
|
||||
|
||||
EXPECT_EQ(20, count);
|
||||
|
||||
for (intptr_t i = 0; i < 20; i++) {
|
||||
Dart_DeleteWeakPersistentHandle(handles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckFloat32x4Data(Dart_Handle obj) {
|
||||
@@ -3119,27 +3111,9 @@ static Dart_Handle AsHandle(Dart_WeakPersistentHandle weak) {
|
||||
return Dart_HandleFromWeakPersistent(weak);
|
||||
}
|
||||
|
||||
static Dart_WeakPersistentHandle weak_new_ref = NULL;
|
||||
static Dart_WeakPersistentHandle weak_old_ref = NULL;
|
||||
|
||||
static void WeakPersistentHandleCallback(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
if (handle == weak_new_ref) {
|
||||
weak_new_ref = NULL;
|
||||
} else if (handle == weak_old_ref) {
|
||||
weak_old_ref = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_WeakPersistentHandle) {
|
||||
Dart_Handle local_new_ref = Dart_Null();
|
||||
weak_new_ref = Dart_NewWeakPersistentHandle(local_new_ref, NULL, 0,
|
||||
WeakPersistentHandleCallback);
|
||||
|
||||
Dart_Handle local_old_ref = Dart_Null();
|
||||
weak_old_ref = Dart_NewWeakPersistentHandle(local_old_ref, NULL, 0,
|
||||
WeakPersistentHandleCallback);
|
||||
Dart_WeakPersistentHandle weak_new_ref = nullptr;
|
||||
Dart_WeakPersistentHandle weak_old_ref = nullptr;
|
||||
|
||||
{
|
||||
Dart_EnterScope();
|
||||
@@ -3159,14 +3133,15 @@ TEST_CASE(DartAPI_WeakPersistentHandle) {
|
||||
EXPECT_VALID(old_ref);
|
||||
|
||||
// Create a weak ref to the new space object.
|
||||
weak_new_ref = Dart_NewWeakPersistentHandle(new_ref, NULL, 0,
|
||||
WeakPersistentHandleCallback);
|
||||
weak_new_ref =
|
||||
Dart_NewWeakPersistentHandle(new_ref, nullptr, 0, NopCallback);
|
||||
EXPECT_VALID(AsHandle(weak_new_ref));
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak_new_ref)));
|
||||
|
||||
// Create a weak ref to the old space object.
|
||||
weak_old_ref = Dart_NewWeakPersistentHandle(old_ref, NULL, 0,
|
||||
WeakPersistentHandleCallback);
|
||||
weak_old_ref =
|
||||
Dart_NewWeakPersistentHandle(old_ref, nullptr, 0, NopCallback);
|
||||
|
||||
EXPECT_VALID(AsHandle(weak_old_ref));
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
|
||||
}
|
||||
@@ -3224,7 +3199,8 @@ TEST_CASE(DartAPI_WeakPersistentHandle) {
|
||||
{
|
||||
Dart_EnterScope();
|
||||
// Weak ref to new space object should now be cleared.
|
||||
EXPECT(weak_new_ref == NULL);
|
||||
EXPECT_VALID(AsHandle(weak_new_ref));
|
||||
EXPECT(Dart_IsNull(AsHandle(weak_new_ref)));
|
||||
EXPECT_VALID(AsHandle(weak_old_ref));
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
|
||||
Dart_ExitScope();
|
||||
@@ -3239,8 +3215,10 @@ TEST_CASE(DartAPI_WeakPersistentHandle) {
|
||||
{
|
||||
Dart_EnterScope();
|
||||
// Weak ref to old space object should now be cleared.
|
||||
EXPECT(weak_new_ref == NULL);
|
||||
EXPECT(weak_old_ref == NULL);
|
||||
EXPECT_VALID(AsHandle(weak_new_ref));
|
||||
EXPECT(Dart_IsNull(AsHandle(weak_new_ref)));
|
||||
EXPECT_VALID(AsHandle(weak_old_ref));
|
||||
EXPECT(Dart_IsNull(AsHandle(weak_old_ref)));
|
||||
Dart_ExitScope();
|
||||
}
|
||||
|
||||
@@ -3249,6 +3227,9 @@ TEST_CASE(DartAPI_WeakPersistentHandle) {
|
||||
// Garbage collect one last time to revisit deleted handles.
|
||||
GCTestHelper::CollectAllGarbage();
|
||||
}
|
||||
|
||||
Dart_DeleteWeakPersistentHandle(weak_new_ref);
|
||||
Dart_DeleteWeakPersistentHandle(weak_old_ref);
|
||||
}
|
||||
|
||||
static Dart_FinalizableHandle finalizable_new_ref = nullptr;
|
||||
@@ -3384,7 +3365,7 @@ TEST_CASE(DartAPI_WeakPersistentHandleErrors) {
|
||||
Dart_Handle obj2 = Dart_NewInteger(0);
|
||||
EXPECT_VALID(obj2);
|
||||
Dart_WeakPersistentHandle ref2 =
|
||||
Dart_NewWeakPersistentHandle(obj2, NULL, 0, WeakPersistentHandleCallback);
|
||||
Dart_NewWeakPersistentHandle(obj2, NULL, 0, NopCallback);
|
||||
EXPECT_EQ(ref2, static_cast<void*>(NULL));
|
||||
|
||||
Dart_ExitScope();
|
||||
@@ -3416,17 +3397,12 @@ static Dart_WeakPersistentHandle weak_persistent_handle3;
|
||||
|
||||
static void WeakPersistentHandlePeerCleanupFinalizer(
|
||||
void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
Dart_DeletePersistentHandle(persistent_handle1);
|
||||
Dart_DeleteWeakPersistentHandle(weak_persistent_handle2);
|
||||
*static_cast<int*>(peer) = 42;
|
||||
}
|
||||
|
||||
static void WeakPersistentHandleNoopCallback(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
|
||||
TEST_CASE(DartAPI_WeakPersistentHandleCleanupFinalizer) {
|
||||
Heap* heap = Isolate::Current()->heap();
|
||||
|
||||
@@ -3437,8 +3413,8 @@ TEST_CASE(DartAPI_WeakPersistentHandleCleanupFinalizer) {
|
||||
persistent_handle1 = Dart_NewPersistentHandle(ref1);
|
||||
Dart_Handle ref2 = Dart_NewStringFromCString(kTestString1);
|
||||
int peer2 = 0;
|
||||
weak_persistent_handle2 = Dart_NewWeakPersistentHandle(
|
||||
ref2, &peer2, 0, WeakPersistentHandleNoopCallback);
|
||||
weak_persistent_handle2 =
|
||||
Dart_NewWeakPersistentHandle(ref2, &peer2, 0, NopCallback);
|
||||
int peer3 = 0;
|
||||
{
|
||||
Dart_EnterScope();
|
||||
@@ -3454,6 +3430,8 @@ TEST_CASE(DartAPI_WeakPersistentHandleCleanupFinalizer) {
|
||||
EXPECT(peer3 == 42);
|
||||
}
|
||||
Dart_ExitScope();
|
||||
|
||||
Dart_DeleteWeakPersistentHandle(weak_persistent_handle3);
|
||||
}
|
||||
|
||||
static Dart_FinalizableHandle finalizable_handle3;
|
||||
@@ -3495,7 +3473,6 @@ TEST_CASE(DartAPI_FinalizableHandleCleanupFinalizer) {
|
||||
}
|
||||
|
||||
static void WeakPersistentHandlePeerFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
*static_cast<int*>(peer) = 42;
|
||||
}
|
||||
@@ -3520,6 +3497,7 @@ TEST_CASE(DartAPI_WeakPersistentHandleCallback) {
|
||||
GCTestHelper::CollectNewSpace();
|
||||
EXPECT(peer == 42);
|
||||
}
|
||||
Dart_DeleteWeakPersistentHandle(weak_ref);
|
||||
}
|
||||
|
||||
static void FinalizableHandlePeerFinalizer(void* isolate_callback_data,
|
||||
@@ -3599,13 +3577,53 @@ TEST_CASE(DartAPI_FinalizableHandleNoCallback) {
|
||||
|
||||
Dart_WeakPersistentHandle delete_on_finalization;
|
||||
|
||||
static void DeleteWeakHandleOnFinalization(void* isolate_callback_data,
|
||||
void* peer) {
|
||||
*static_cast<int*>(peer) = 42;
|
||||
Dart_DeleteWeakPersistentHandle(delete_on_finalization);
|
||||
delete_on_finalization = nullptr;
|
||||
}
|
||||
|
||||
static void DontDeleteWeakHandleOnFinalization(void* isolate_callback_data,
|
||||
void* peer) {
|
||||
*static_cast<int*>(peer) = 42;
|
||||
delete_on_finalization = nullptr;
|
||||
}
|
||||
|
||||
// Mimicking the old handle behavior by deleting the handle itself in the
|
||||
// finalizer.
|
||||
TEST_CASE(DartAPI_WeakPersistentHandleCallbackSelfDelete) {
|
||||
int peer = 0;
|
||||
{
|
||||
Dart_EnterScope();
|
||||
Dart_Handle obj = NewString("new string");
|
||||
EXPECT_VALID(obj);
|
||||
delete_on_finalization = Dart_NewWeakPersistentHandle(
|
||||
obj, &peer, 0, DeleteWeakHandleOnFinalization);
|
||||
EXPECT_VALID(AsHandle(delete_on_finalization));
|
||||
EXPECT(peer == 0);
|
||||
Dart_ExitScope();
|
||||
}
|
||||
{
|
||||
TransitionNativeToVM transition(thread);
|
||||
GCTestHelper::CollectOldSpace();
|
||||
EXPECT(peer == 0);
|
||||
GCTestHelper::CollectNewSpace();
|
||||
EXPECT(peer == 42);
|
||||
ASSERT(delete_on_finalization == nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Checking that the finalizer gets run on shutdown, but that the delete
|
||||
// handle does not get invoked. (The handles have already been deleted by
|
||||
// releasing the LocalApiState.)
|
||||
VM_UNIT_TEST_CASE(DartAPI_WeakPersistentHandlesCallbackShutdown) {
|
||||
TestCase::CreateTestIsolate();
|
||||
Dart_EnterScope();
|
||||
Dart_Handle ref = Dart_True();
|
||||
int peer = 1234;
|
||||
Dart_NewWeakPersistentHandle(ref, &peer, 0,
|
||||
WeakPersistentHandlePeerFinalizer);
|
||||
delete_on_finalization = Dart_NewWeakPersistentHandle(
|
||||
ref, &peer, 0, DontDeleteWeakHandleOnFinalization);
|
||||
Dart_ExitScope();
|
||||
Dart_ShutdownIsolate();
|
||||
EXPECT(peer == 42);
|
||||
@@ -3668,6 +3686,8 @@ TEST_CASE(DartAPI_WeakPersistentHandleExternalAllocationSize) {
|
||||
GCTestHelper::CollectOldSpace();
|
||||
EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
|
||||
}
|
||||
Dart_DeleteWeakPersistentHandle(weak1);
|
||||
Dart_DeleteWeakPersistentHandle(weak2);
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_FinalizableHandleExternalAllocationSize) {
|
||||
@@ -3827,7 +3847,8 @@ TEST_CASE(DartAPI_WeakPersistentHandleExternalAllocationSizeOldspaceGC) {
|
||||
}
|
||||
// Large enough to trigger GC in old space. Not actually allocated.
|
||||
const intptr_t kHugeExternalSize = (kWordSize == 4) ? 513 * MB : 1025 * MB;
|
||||
Dart_NewWeakPersistentHandle(live, NULL, kHugeExternalSize, NopCallback);
|
||||
Dart_WeakPersistentHandle weak2 =
|
||||
Dart_NewWeakPersistentHandle(live, NULL, kHugeExternalSize, NopCallback);
|
||||
{
|
||||
TransitionNativeToVM transition(thread);
|
||||
GCTestHelper::WaitForGCTasks(); // Finalize GC for accurate live size.
|
||||
@@ -3836,6 +3857,8 @@ TEST_CASE(DartAPI_WeakPersistentHandleExternalAllocationSizeOldspaceGC) {
|
||||
isolate->heap()->ExternalInWords(Heap::kOld) * kWordSize);
|
||||
}
|
||||
Dart_ExitScope();
|
||||
Dart_DeleteWeakPersistentHandle(weak);
|
||||
Dart_DeleteWeakPersistentHandle(weak2);
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_FinalizableHandleExternalAllocationSizeOldspaceGC) {
|
||||
@@ -3984,13 +4007,11 @@ static Dart_NativeFunction ExampleResourceNativeResolver(
|
||||
}
|
||||
|
||||
struct ExampleResource {
|
||||
Dart_WeakPersistentHandle self;
|
||||
Dart_FinalizableHandle self;
|
||||
void* lots_of_memory;
|
||||
};
|
||||
|
||||
void ExampleResourceFinalizer(void* isolate_peer,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
void ExampleResourceFinalizer(void* isolate_peer, void* peer) {
|
||||
ExampleResource* resource = reinterpret_cast<ExampleResource*>(peer);
|
||||
free(resource->lots_of_memory);
|
||||
delete resource;
|
||||
@@ -4001,8 +4022,8 @@ void FUNCTION_NAME(ExampleResource_Allocate)(Dart_NativeArguments native_args) {
|
||||
intptr_t external_size = 10 * MB;
|
||||
ExampleResource* resource = new ExampleResource();
|
||||
resource->lots_of_memory = malloc(external_size);
|
||||
resource->self = Dart_NewWeakPersistentHandle(
|
||||
receiver, resource, external_size, ExampleResourceFinalizer);
|
||||
resource->self = Dart_NewFinalizableHandle(receiver, resource, external_size,
|
||||
ExampleResourceFinalizer);
|
||||
EXPECT_VALID(Dart_SetNativeInstanceField(
|
||||
receiver, 0, reinterpret_cast<intptr_t>(resource)));
|
||||
// Some pretend resource initialization.
|
||||
@@ -4032,7 +4053,7 @@ void FUNCTION_NAME(ExampleResource_Dispose)(Dart_NativeArguments native_args) {
|
||||
if (resource->lots_of_memory != nullptr) {
|
||||
free(resource->lots_of_memory);
|
||||
resource->lots_of_memory = nullptr;
|
||||
Dart_UpdateExternalSize(resource->self, 0);
|
||||
Dart_UpdateFinalizableExternalSize(resource->self, receiver, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4072,13 +4093,12 @@ static Dart_WeakPersistentHandle weak2 = NULL;
|
||||
static Dart_WeakPersistentHandle weak3 = NULL;
|
||||
|
||||
static void ImplicitReferencesCallback(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
if (handle == weak1) {
|
||||
if (peer == &weak1) {
|
||||
weak1 = NULL;
|
||||
} else if (handle == weak2) {
|
||||
} else if (peer == &weak2) {
|
||||
weak2 = NULL;
|
||||
} else if (handle == weak3) {
|
||||
} else if (peer == &weak3) {
|
||||
weak3 = NULL;
|
||||
}
|
||||
}
|
||||
@@ -4103,19 +4123,19 @@ TEST_CASE(DartAPI_ImplicitReferencesOldSpace) {
|
||||
|
||||
weak1 =
|
||||
Dart_NewWeakPersistentHandle(AllocateOldString("weakly reachable 1"),
|
||||
NULL, 0, ImplicitReferencesCallback);
|
||||
&weak1, 0, ImplicitReferencesCallback);
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak1)));
|
||||
EXPECT_VALID(AsHandle(weak1));
|
||||
|
||||
weak2 =
|
||||
Dart_NewWeakPersistentHandle(AllocateOldString("weakly reachable 2"),
|
||||
NULL, 0, ImplicitReferencesCallback);
|
||||
&weak2, 0, ImplicitReferencesCallback);
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak2)));
|
||||
EXPECT_VALID(AsHandle(weak2));
|
||||
|
||||
weak3 =
|
||||
Dart_NewWeakPersistentHandle(AllocateOldString("weakly reachable 3"),
|
||||
NULL, 0, ImplicitReferencesCallback);
|
||||
&weak3, 0, ImplicitReferencesCallback);
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak3)));
|
||||
EXPECT_VALID(AsHandle(weak3));
|
||||
}
|
||||
@@ -4144,6 +4164,11 @@ TEST_CASE(DartAPI_ImplicitReferencesOldSpace) {
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak3)));
|
||||
Dart_ExitScope();
|
||||
}
|
||||
|
||||
Dart_DeleteWeakPersistentHandle(strong_weak);
|
||||
Dart_DeleteWeakPersistentHandle(weak1);
|
||||
Dart_DeleteWeakPersistentHandle(weak2);
|
||||
Dart_DeleteWeakPersistentHandle(weak3);
|
||||
}
|
||||
|
||||
TEST_CASE(DartAPI_ImplicitReferencesNewSpace) {
|
||||
@@ -4166,19 +4191,19 @@ TEST_CASE(DartAPI_ImplicitReferencesNewSpace) {
|
||||
|
||||
weak1 =
|
||||
Dart_NewWeakPersistentHandle(AllocateNewString("weakly reachable 1"),
|
||||
NULL, 0, ImplicitReferencesCallback);
|
||||
&weak1, 0, ImplicitReferencesCallback);
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak1)));
|
||||
EXPECT_VALID(AsHandle(weak1));
|
||||
|
||||
weak2 =
|
||||
Dart_NewWeakPersistentHandle(AllocateNewString("weakly reachable 2"),
|
||||
NULL, 0, ImplicitReferencesCallback);
|
||||
&weak2, 0, ImplicitReferencesCallback);
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak2)));
|
||||
EXPECT_VALID(AsHandle(weak2));
|
||||
|
||||
weak3 =
|
||||
Dart_NewWeakPersistentHandle(AllocateNewString("weakly reachable 3"),
|
||||
NULL, 0, ImplicitReferencesCallback);
|
||||
&weak3, 0, ImplicitReferencesCallback);
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak3)));
|
||||
EXPECT_VALID(AsHandle(weak3));
|
||||
}
|
||||
@@ -4206,6 +4231,11 @@ TEST_CASE(DartAPI_ImplicitReferencesNewSpace) {
|
||||
EXPECT(!Dart_IsNull(AsHandle(weak3)));
|
||||
Dart_ExitScope();
|
||||
}
|
||||
|
||||
Dart_DeleteWeakPersistentHandle(strong_weak);
|
||||
Dart_DeleteWeakPersistentHandle(weak1);
|
||||
Dart_DeleteWeakPersistentHandle(weak2);
|
||||
Dart_DeleteWeakPersistentHandle(weak3);
|
||||
}
|
||||
|
||||
// Unit test for creating multiple scopes and local handles within them.
|
||||
@@ -7379,9 +7409,7 @@ TEST_CASE(DartAPI_IllegalPost) {
|
||||
EXPECT(!success);
|
||||
}
|
||||
|
||||
static void UnreachableFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {
|
||||
static void UnreachableFinalizer(void* isolate_callback_data, void* peer) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
@@ -8970,10 +8998,7 @@ TEST_CASE(DartAPI_InvokeVMServiceMethod) {
|
||||
|
||||
Dart_Handle bytes = Dart_NewExternalTypedDataWithFinalizer(
|
||||
Dart_TypedData_kUint8, response_json, response_json_length, response_json,
|
||||
response_json_length,
|
||||
[](void* ignored, Dart_WeakPersistentHandle handle, void* peer) {
|
||||
free(peer);
|
||||
});
|
||||
response_json_length, [](void* ignored, void* peer) { free(peer); });
|
||||
EXPECT_VALID(bytes);
|
||||
|
||||
// We don't have a C++ JSON decoder so we'll invoke dart to validate the
|
||||
|
||||
@@ -1124,7 +1124,7 @@ bool ApiMessageWriter::WriteCObjectInlined(Dart_CObject* object,
|
||||
}
|
||||
uint8_t* data = object->value.as_external_typed_data.data;
|
||||
void* peer = object->value.as_external_typed_data.peer;
|
||||
Dart_WeakPersistentHandleFinalizer callback =
|
||||
Dart_HandleFinalizer callback =
|
||||
object->value.as_external_typed_data.callback;
|
||||
if (callback == NULL) {
|
||||
return false;
|
||||
|
||||
+25
-77
@@ -190,23 +190,6 @@ class PersistentHandle {
|
||||
// dart API.
|
||||
class FinalizablePersistentHandle {
|
||||
public:
|
||||
// TODO(http://dartbug.com/42312): Delete this on migrating signature
|
||||
// Dart_NewWeakPersistentHandle to Dart_HandleFinalizer.
|
||||
enum class CallbackSignature {
|
||||
// Uses a Dart_WeakPersistentHandleFinalizer.
|
||||
kWeakPersistentHandleFinalizer = 0,
|
||||
// Uses a Dart_HandleFinalizer.
|
||||
kHandleFinalizer = 1,
|
||||
};
|
||||
|
||||
static FinalizablePersistentHandle* New(
|
||||
Isolate* isolate,
|
||||
const Object& object,
|
||||
void* peer,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
intptr_t external_size,
|
||||
bool auto_delete);
|
||||
|
||||
static FinalizablePersistentHandle* New(Isolate* isolate,
|
||||
const Object& object,
|
||||
void* peer,
|
||||
@@ -221,18 +204,7 @@ class FinalizablePersistentHandle {
|
||||
return OFFSET_OF(FinalizablePersistentHandle, raw_);
|
||||
}
|
||||
void* peer() const { return peer_; }
|
||||
Dart_WeakPersistentHandleFinalizer CallbackWeakFinalizer() const {
|
||||
ASSERT(callback_signature_ ==
|
||||
CallbackSignature::kWeakPersistentHandleFinalizer);
|
||||
return callback_.weak_persistent;
|
||||
}
|
||||
Dart_HandleFinalizer callback() const {
|
||||
ASSERT(callback_signature_ == CallbackSignature::kHandleFinalizer);
|
||||
return callback_.finalizable;
|
||||
}
|
||||
uword callback_address() const {
|
||||
return reinterpret_cast<uword>(callback_.finalizable);
|
||||
}
|
||||
Dart_HandleFinalizer callback() const { return callback_; }
|
||||
Dart_WeakPersistentHandle ApiWeakPersistentHandle() {
|
||||
return reinterpret_cast<Dart_WeakPersistentHandle>(this);
|
||||
}
|
||||
@@ -242,6 +214,10 @@ class FinalizablePersistentHandle {
|
||||
|
||||
bool auto_delete() const { return auto_delete_; }
|
||||
|
||||
bool IsFinalizedNotFreed() const {
|
||||
return raw_ == static_cast<ObjectPtr>(reinterpret_cast<uword>(this));
|
||||
}
|
||||
|
||||
intptr_t external_size() const {
|
||||
return ExternalSizeInWordsBits::decode(external_data_) * kWordSize;
|
||||
}
|
||||
@@ -298,15 +274,6 @@ class FinalizablePersistentHandle {
|
||||
kExternalSizeBitsSize = (kBitsPerWord - 1),
|
||||
};
|
||||
|
||||
union HandleFinalizer {
|
||||
Dart_HandleFinalizer finalizable;
|
||||
Dart_WeakPersistentHandleFinalizer weak_persistent;
|
||||
HandleFinalizer(Dart_HandleFinalizer finalizer) : finalizable(finalizer) {}
|
||||
HandleFinalizer(Dart_WeakPersistentHandleFinalizer finalizer)
|
||||
: weak_persistent(finalizer) {}
|
||||
HandleFinalizer() : finalizable(nullptr) {}
|
||||
};
|
||||
|
||||
// This part of external_data_ is the number of externally allocated bytes.
|
||||
class ExternalSizeInWordsBits : public BitField<uword,
|
||||
intptr_t,
|
||||
@@ -320,10 +287,7 @@ class FinalizablePersistentHandle {
|
||||
friend class FinalizablePersistentHandles;
|
||||
|
||||
FinalizablePersistentHandle()
|
||||
: raw_(nullptr),
|
||||
peer_(NULL),
|
||||
external_data_(0),
|
||||
callback_(HandleFinalizer()) {}
|
||||
: raw_(nullptr), peer_(NULL), external_data_(0), callback_(NULL) {}
|
||||
~FinalizablePersistentHandle() {}
|
||||
|
||||
static void Finalize(IsolateGroup* isolate_group,
|
||||
@@ -340,6 +304,11 @@ class FinalizablePersistentHandle {
|
||||
ASSERT(!raw_->IsHeapObject());
|
||||
}
|
||||
|
||||
void SetFinalizedNotFreed() {
|
||||
// `handle->raw_ != Object::null()` or the GC will finalize again.
|
||||
SetNext(this);
|
||||
}
|
||||
|
||||
void FreeHandle(FinalizablePersistentHandle* free_list) {
|
||||
Clear();
|
||||
SetNext(free_list);
|
||||
@@ -347,11 +316,10 @@ class FinalizablePersistentHandle {
|
||||
|
||||
void Clear() {
|
||||
raw_ = Object::null();
|
||||
peer_ = NULL;
|
||||
peer_ = nullptr;
|
||||
external_data_ = 0;
|
||||
callback_ = HandleFinalizer();
|
||||
callback_ = nullptr;
|
||||
auto_delete_ = false;
|
||||
callback_signature_ = CallbackSignature::kWeakPersistentHandleFinalizer;
|
||||
}
|
||||
|
||||
void set_raw(ObjectPtr raw) { raw_ = raw; }
|
||||
@@ -360,11 +328,7 @@ class FinalizablePersistentHandle {
|
||||
|
||||
void set_peer(void* peer) { peer_ = peer; }
|
||||
|
||||
void set_callback_signature(CallbackSignature callback_signature) {
|
||||
callback_signature_ = callback_signature;
|
||||
}
|
||||
|
||||
void set_callback(HandleFinalizer callback) { callback_ = callback; }
|
||||
void set_callback(Dart_HandleFinalizer callback) { callback_ = callback; }
|
||||
|
||||
void set_auto_delete(bool auto_delete) { auto_delete_ = auto_delete; }
|
||||
|
||||
@@ -396,9 +360,8 @@ class FinalizablePersistentHandle {
|
||||
ObjectPtr raw_;
|
||||
void* peer_;
|
||||
uword external_data_;
|
||||
HandleFinalizer callback_;
|
||||
Dart_HandleFinalizer callback_;
|
||||
bool auto_delete_;
|
||||
CallbackSignature callback_signature_;
|
||||
|
||||
DISALLOW_ALLOCATION(); // Allocated through AllocateHandle methods.
|
||||
DISALLOW_COPY_AND_ASSIGN(FinalizablePersistentHandle);
|
||||
@@ -608,6 +571,11 @@ class FinalizablePersistentHandles
|
||||
return handle;
|
||||
}
|
||||
|
||||
void ClearHandle(FinalizablePersistentHandle* handle) {
|
||||
handle->Clear();
|
||||
handle->SetFinalizedNotFreed();
|
||||
}
|
||||
|
||||
void FreeHandle(FinalizablePersistentHandle* handle) {
|
||||
handle->FreeHandle(free_list());
|
||||
set_free_list(handle);
|
||||
@@ -805,7 +773,10 @@ class ApiState {
|
||||
MutexLocker ml(&mutex_);
|
||||
return weak_persistent_handles_.AllocateHandle();
|
||||
}
|
||||
|
||||
void ClearWeakPersistentHandle(FinalizablePersistentHandle* weak_ref) {
|
||||
MutexLocker ml(&mutex_);
|
||||
weak_persistent_handles_.ClearHandle(weak_ref);
|
||||
}
|
||||
void FreeWeakPersistentHandle(FinalizablePersistentHandle* weak_ref) {
|
||||
MutexLocker ml(&mutex_);
|
||||
weak_persistent_handles_.FreeHandle(weak_ref);
|
||||
@@ -892,28 +863,6 @@ class ApiState {
|
||||
DISALLOW_COPY_AND_ASSIGN(ApiState);
|
||||
};
|
||||
|
||||
inline FinalizablePersistentHandle* FinalizablePersistentHandle::New(
|
||||
Isolate* isolate,
|
||||
const Object& object,
|
||||
void* peer,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
intptr_t external_size,
|
||||
bool auto_delete) {
|
||||
ApiState* state = isolate->group()->api_state();
|
||||
ASSERT(state != NULL);
|
||||
ASSERT(callback != NULL);
|
||||
FinalizablePersistentHandle* ref = state->AllocateWeakPersistentHandle();
|
||||
ref->set_raw(object);
|
||||
ref->set_peer(peer);
|
||||
ref->set_callback_signature(
|
||||
CallbackSignature::kWeakPersistentHandleFinalizer);
|
||||
ref->set_callback(HandleFinalizer(callback));
|
||||
ref->set_auto_delete(auto_delete);
|
||||
// This may trigger GC, so it must be called last.
|
||||
ref->SetExternalSize(external_size, isolate->group());
|
||||
return ref;
|
||||
}
|
||||
|
||||
inline FinalizablePersistentHandle* FinalizablePersistentHandle::New(
|
||||
Isolate* isolate,
|
||||
const Object& object,
|
||||
@@ -926,8 +875,7 @@ inline FinalizablePersistentHandle* FinalizablePersistentHandle::New(
|
||||
FinalizablePersistentHandle* ref = state->AllocateWeakPersistentHandle();
|
||||
ref->set_raw(object);
|
||||
ref->set_peer(peer);
|
||||
ref->set_callback_signature(CallbackSignature::kHandleFinalizer);
|
||||
ref->set_callback(HandleFinalizer(callback));
|
||||
ref->set_callback(callback);
|
||||
ref->set_auto_delete(auto_delete);
|
||||
// This may trigger GC, so it must be called last.
|
||||
ref->SetExternalSize(external_size, isolate->group());
|
||||
|
||||
@@ -14,8 +14,8 @@ namespace dart {
|
||||
struct FinalizableData {
|
||||
void* data;
|
||||
void* peer;
|
||||
Dart_WeakPersistentHandleFinalizer callback;
|
||||
Dart_WeakPersistentHandleFinalizer successful_write_callback;
|
||||
Dart_HandleFinalizer callback;
|
||||
Dart_HandleFinalizer successful_write_callback;
|
||||
};
|
||||
|
||||
class MessageFinalizableData {
|
||||
@@ -25,19 +25,18 @@ class MessageFinalizableData {
|
||||
|
||||
~MessageFinalizableData() {
|
||||
for (intptr_t i = take_position_; i < records_.length(); i++) {
|
||||
records_[i].callback(nullptr, nullptr, records_[i].peer);
|
||||
records_[i].callback(nullptr, records_[i].peer);
|
||||
}
|
||||
}
|
||||
|
||||
/// If [successful_write_callback] is provided, it's invoked when message
|
||||
/// was serialized successfully.
|
||||
/// [callback] is invoked when serialization failed.
|
||||
void Put(
|
||||
intptr_t external_size,
|
||||
void* data,
|
||||
void* peer,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Dart_WeakPersistentHandleFinalizer successful_write_callback = nullptr) {
|
||||
void Put(intptr_t external_size,
|
||||
void* data,
|
||||
void* peer,
|
||||
Dart_HandleFinalizer callback,
|
||||
Dart_HandleFinalizer successful_write_callback = nullptr) {
|
||||
FinalizableData finalizable_data;
|
||||
finalizable_data.data = data;
|
||||
finalizable_data.peer = peer;
|
||||
@@ -64,8 +63,7 @@ class MessageFinalizableData {
|
||||
void SerializationSucceeded() {
|
||||
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);
|
||||
records_[i].successful_write_callback(nullptr, records_[i].peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +77,7 @@ ISOLATE_UNIT_TEST_CASE(AllocateScopeHandle) {
|
||||
EXPECT_EQ(handle_count, VMHandles::ScopedHandleCount());
|
||||
}
|
||||
|
||||
static void NoopCallback(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void NoopCallback(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
// Unit test for handle validity checks.
|
||||
TEST_CASE(CheckHandleValidity) {
|
||||
|
||||
@@ -184,9 +184,7 @@ void JSONStream::PostNullReply(Dart_Port port) {
|
||||
Message::New(port, Object::null(), Message::kNormalPriority));
|
||||
}
|
||||
|
||||
static void Finalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* buffer) {
|
||||
static void Finalizer(void* isolate_callback_data, void* buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -401,9 +401,7 @@ static void ReleaseFilesPairs(const Dart_CObject& files) {
|
||||
delete[] files.value.as_array.values;
|
||||
}
|
||||
|
||||
static void PassThroughFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void PassThroughFinalizer(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
MallocGrowableArray<char*>* KernelIsolate::experimental_flags_ =
|
||||
new MallocGrowableArray<char*>();
|
||||
|
||||
+10
-14
@@ -21845,7 +21845,7 @@ StringPtr String::NewExternal(const uint8_t* characters,
|
||||
intptr_t len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Dart_HandleFinalizer callback,
|
||||
Heap::Space space) {
|
||||
return ExternalOneByteString::New(characters, len, peer,
|
||||
external_allocation_size, callback, space);
|
||||
@@ -21855,7 +21855,7 @@ StringPtr String::NewExternal(const uint16_t* characters,
|
||||
intptr_t len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Dart_HandleFinalizer callback,
|
||||
Heap::Space space) {
|
||||
return ExternalTwoByteString::New(characters, len, peer,
|
||||
external_allocation_size, callback, space);
|
||||
@@ -22239,11 +22239,10 @@ void String::ToUTF8(uint8_t* utf8_array, intptr_t array_len) const {
|
||||
Utf8::Encode(*this, reinterpret_cast<char*>(utf8_array), array_len);
|
||||
}
|
||||
|
||||
static FinalizablePersistentHandle* AddFinalizer(
|
||||
const Object& referent,
|
||||
void* peer,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
intptr_t external_size) {
|
||||
static FinalizablePersistentHandle* AddFinalizer(const Object& referent,
|
||||
void* peer,
|
||||
Dart_HandleFinalizer callback,
|
||||
intptr_t external_size) {
|
||||
ASSERT(callback != NULL);
|
||||
return FinalizablePersistentHandle::New(Isolate::Current(), referent, peer,
|
||||
callback, external_size,
|
||||
@@ -22856,7 +22855,7 @@ ExternalOneByteStringPtr ExternalOneByteString::New(
|
||||
intptr_t len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Dart_HandleFinalizer callback,
|
||||
Heap::Space space) {
|
||||
ASSERT(Isolate::Current()->object_store()->external_one_byte_string_class() !=
|
||||
Class::null());
|
||||
@@ -22885,7 +22884,7 @@ ExternalTwoByteStringPtr ExternalTwoByteString::New(
|
||||
intptr_t len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Dart_HandleFinalizer callback,
|
||||
Heap::Space space) {
|
||||
ASSERT(Isolate::Current()->object_store()->external_two_byte_string_class() !=
|
||||
Class::null());
|
||||
@@ -23658,7 +23657,7 @@ const char* TypedData::ToCString() const {
|
||||
|
||||
FinalizablePersistentHandle* ExternalTypedData::AddFinalizer(
|
||||
void* peer,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Dart_HandleFinalizer callback,
|
||||
intptr_t external_size) const {
|
||||
return dart::AddFinalizer(*this, peer, callback, external_size);
|
||||
}
|
||||
@@ -23696,10 +23695,7 @@ ExternalTypedDataPtr ExternalTypedData::NewFinalizeWithFree(uint8_t* data,
|
||||
ExternalTypedData& result = ExternalTypedData::Handle(ExternalTypedData::New(
|
||||
kExternalTypedDataUint8ArrayCid, data, len, Heap::kOld));
|
||||
result.AddFinalizer(
|
||||
data,
|
||||
[](void* isolate_callback_data, Dart_WeakPersistentHandle handle,
|
||||
void* data) { free(data); },
|
||||
len);
|
||||
data, [](void* isolate_callback_data, void* data) { free(data); }, len);
|
||||
return result.raw();
|
||||
}
|
||||
|
||||
|
||||
+17
-20
@@ -8765,7 +8765,7 @@ class String : public Instance {
|
||||
intptr_t array_len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Dart_HandleFinalizer callback,
|
||||
Heap::Space = Heap::kNew);
|
||||
|
||||
// Creates a new External String object using the specified array of
|
||||
@@ -8774,7 +8774,7 @@ class String : public Instance {
|
||||
intptr_t array_len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Dart_HandleFinalizer callback,
|
||||
Heap::Space = Heap::kNew);
|
||||
|
||||
static void Copy(const String& dst,
|
||||
@@ -9214,13 +9214,12 @@ class ExternalOneByteString : public AllStatic {
|
||||
return String::RoundedAllocationSize(sizeof(ExternalOneByteStringLayout));
|
||||
}
|
||||
|
||||
static ExternalOneByteStringPtr New(
|
||||
const uint8_t* characters,
|
||||
intptr_t len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Heap::Space space);
|
||||
static ExternalOneByteStringPtr New(const uint8_t* characters,
|
||||
intptr_t len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_HandleFinalizer callback,
|
||||
Heap::Space space);
|
||||
|
||||
static ExternalOneByteStringPtr null() {
|
||||
return static_cast<ExternalOneByteStringPtr>(Object::null());
|
||||
@@ -9313,13 +9312,12 @@ class ExternalTwoByteString : public AllStatic {
|
||||
return String::RoundedAllocationSize(sizeof(ExternalTwoByteStringLayout));
|
||||
}
|
||||
|
||||
static ExternalTwoByteStringPtr New(
|
||||
const uint16_t* characters,
|
||||
intptr_t len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
Heap::Space space = Heap::kNew);
|
||||
static ExternalTwoByteStringPtr New(const uint16_t* characters,
|
||||
intptr_t len,
|
||||
void* peer,
|
||||
intptr_t external_allocation_size,
|
||||
Dart_HandleFinalizer callback,
|
||||
Heap::Space space = Heap::kNew);
|
||||
|
||||
static ExternalTwoByteStringPtr null() {
|
||||
return static_cast<ExternalTwoByteStringPtr>(Object::null());
|
||||
@@ -10103,10 +10101,9 @@ class ExternalTypedData : public TypedDataBase {
|
||||
|
||||
#undef TYPED_GETTER_SETTER
|
||||
|
||||
FinalizablePersistentHandle* AddFinalizer(
|
||||
void* peer,
|
||||
Dart_WeakPersistentHandleFinalizer callback,
|
||||
intptr_t external_size) const;
|
||||
FinalizablePersistentHandle* AddFinalizer(void* peer,
|
||||
Dart_HandleFinalizer callback,
|
||||
intptr_t external_size) const;
|
||||
|
||||
static intptr_t data_offset() {
|
||||
return OFFSET_OF(ExternalTypedDataLayout, data_);
|
||||
|
||||
@@ -990,7 +990,7 @@ class Pass2Visitor : public ObjectVisitor,
|
||||
writer_->WriteUnsigned(weak_persistent_handle->external_size());
|
||||
// Attempt to include a native symbol name.
|
||||
auto const name = NativeSymbolResolver::LookupSymbolName(
|
||||
weak_persistent_handle->callback_address(), nullptr);
|
||||
reinterpret_cast<uword>(weak_persistent_handle->callback()), nullptr);
|
||||
writer_->WriteUtf8((name == nullptr) ? "Unknown native function" : name);
|
||||
if (name != nullptr) {
|
||||
NativeSymbolResolver::FreeSymbolName(name);
|
||||
|
||||
@@ -142,9 +142,7 @@ ISOLATE_UNIT_TEST_CASE(ObjectGraph) {
|
||||
}
|
||||
}
|
||||
|
||||
static void WeakHandleFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void WeakHandleFinalizer(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(RetainingPathGCRoot) {
|
||||
Dart_PersistentHandle persistent_handle;
|
||||
|
||||
@@ -1624,9 +1624,7 @@ ISOLATE_UNIT_TEST_CASE(StringEqualsUTF32) {
|
||||
EXPECT(!th_str.Equals(chars, 3));
|
||||
}
|
||||
|
||||
static void NoopFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(ExternalOneByteString) {
|
||||
uint8_t characters[] = {0xF6, 0xF1, 0xE9};
|
||||
|
||||
@@ -1374,7 +1374,6 @@ ExternalTypedDataPtr ExternalTypedData::ReadFrom(SnapshotReader* reader,
|
||||
|
||||
// This function's name can appear in Observatory.
|
||||
static void IsolateMessageTypedDataFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
@@ -1707,9 +1706,9 @@ void TransferableTypedDataLayout::WriteTo(SnapshotWriter* writer,
|
||||
length, data, tpeer,
|
||||
// Finalizer does nothing - in case of failure to serialize,
|
||||
// [data] remains wrapped in sender's [TransferableTypedData].
|
||||
[](void* data, Dart_WeakPersistentHandle handle, void* peer) {},
|
||||
[](void* data, void* peer) {},
|
||||
// This is invoked on successful serialization of the message
|
||||
[](void* data, Dart_WeakPersistentHandle handle, void* peer) {
|
||||
[](void* data, void* peer) {
|
||||
TransferableTypedDataPeer* tpeer =
|
||||
reinterpret_cast<TransferableTypedDataPeer*>(peer);
|
||||
tpeer->handle()->EnsureFreedExternal(IsolateGroup::Current());
|
||||
|
||||
@@ -64,9 +64,7 @@ ISOLATE_UNIT_TEST_CASE(RegExp_TwoByteString) {
|
||||
EXPECT_EQ(3, smi_2.Value());
|
||||
}
|
||||
|
||||
static void NoopFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void NoopFinalizer(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(RegExp_ExternalOneByteString) {
|
||||
uint8_t chars[] = {'a', 'b', 'c', 'b', 'a'};
|
||||
|
||||
@@ -974,9 +974,7 @@ ErrorPtr Service::HandleIsolateMessage(Isolate* isolate, const Array& msg) {
|
||||
return MaybePause(isolate, error);
|
||||
}
|
||||
|
||||
static void Finalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* buffer) {
|
||||
static void Finalizer(void* isolate_callback_data, void* buffer) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -4356,11 +4354,12 @@ class PersistentHandleVisitor : public HandleVisitor {
|
||||
obj.AddPropertyF(
|
||||
"peer", "0x%" Px "",
|
||||
reinterpret_cast<uintptr_t>(weak_persistent_handle->peer()));
|
||||
obj.AddPropertyF("callbackAddress", "0x%" Px "",
|
||||
weak_persistent_handle->callback_address());
|
||||
obj.AddPropertyF(
|
||||
"callbackAddress", "0x%" Px "",
|
||||
reinterpret_cast<uintptr_t>(weak_persistent_handle->callback()));
|
||||
// Attempt to include a native symbol name.
|
||||
char* name = NativeSymbolResolver::LookupSymbolName(
|
||||
weak_persistent_handle->callback_address(), nullptr);
|
||||
reinterpret_cast<uword>(weak_persistent_handle->callback()), nullptr);
|
||||
obj.AddProperty("callbackSymbolName", (name == nullptr) ? "" : name);
|
||||
if (name != nullptr) {
|
||||
NativeSymbolResolver::FreeSymbolName(name);
|
||||
|
||||
@@ -485,9 +485,7 @@ ISOLATE_UNIT_TEST_CASE(Service_LocalVarDescriptors) {
|
||||
EXPECT_SUBSTRING("\"members\":[", handler.msg());
|
||||
}
|
||||
|
||||
static void WeakHandleFinalizer(void* isolate_callback_data,
|
||||
Dart_WeakPersistentHandle handle,
|
||||
void* peer) {}
|
||||
static void WeakHandleFinalizer(void* isolate_callback_data, void* peer) {}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(Service_PersistentHandles) {
|
||||
const char* kScript =
|
||||
|
||||
@@ -28,8 +28,8 @@ main() async {
|
||||
print("C T2 = Some C thread executing C.");
|
||||
print("C = C T1 or C T2.");
|
||||
print("Dart: Setup.");
|
||||
Expect.isTrue(NativeApi.majorVersion == 1);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 1);
|
||||
Expect.isTrue(NativeApi.majorVersion == 2);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 0);
|
||||
final initializeApi = dl.lookupFunction<IntPtr Function(Pointer<Void>),
|
||||
int Function(Pointer<Void>)>("InitDartApiDL");
|
||||
Expect.isTrue(initializeApi(NativeApi.initializeApiDLData) == 0);
|
||||
|
||||
@@ -37,8 +37,8 @@ main() async {
|
||||
print("C T2 = Some C thread executing C.");
|
||||
print("C = C T1 or C T2.");
|
||||
print("Dart: Setup.");
|
||||
Expect.isTrue(NativeApi.majorVersion == 1);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 1);
|
||||
Expect.isTrue(NativeApi.majorVersion == 2);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 0);
|
||||
final initializeApi = dl.lookupFunction<IntPtr Function(Pointer<Void>),
|
||||
int Function(Pointer<Void>)>("InitDartApiDL");
|
||||
Expect.isTrue(initializeApi(NativeApi.initializeApiDLData) == 0);
|
||||
|
||||
@@ -55,8 +55,8 @@ final closureCallbackPointer =
|
||||
Pointer.fromFunction<Void Function(Handle)>(doClosureCallback);
|
||||
|
||||
void doDynamicLinking() {
|
||||
Expect.isTrue(NativeApi.majorVersion == 1);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 1);
|
||||
Expect.isTrue(NativeApi.majorVersion == 2);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 0);
|
||||
final initializeApi = testLibrary.lookupFunction<
|
||||
IntPtr Function(Pointer<Void>),
|
||||
int Function(Pointer<Void>)>("InitDartApiDL");
|
||||
|
||||
@@ -16,8 +16,8 @@ void main() {
|
||||
}
|
||||
|
||||
void doDynamicLinking() {
|
||||
Expect.isTrue(NativeApi.majorVersion == 1);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 1);
|
||||
Expect.isTrue(NativeApi.majorVersion == 2);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 0);
|
||||
final initializeApi = testLibrary.lookupFunction<
|
||||
IntPtr Function(Pointer<Void>),
|
||||
int Function(Pointer<Void>)>("InitDartApiDL");
|
||||
|
||||
@@ -16,8 +16,8 @@ void main() {
|
||||
}
|
||||
|
||||
void doDynamicLinking() {
|
||||
Expect.isTrue(NativeApi.majorVersion == 1);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 1);
|
||||
Expect.isTrue(NativeApi.majorVersion == 2);
|
||||
Expect.isTrue(NativeApi.minorVersion >= 0);
|
||||
final initializeApi = testLibrary.lookupFunction<
|
||||
IntPtr Function(Pointer<Void>),
|
||||
int Function(Pointer<Void>)>("InitDartApiDL");
|
||||
|
||||
@@ -0,0 +1,804 @@
|
||||
diff --git a/BUILD.gn b/BUILD.gn
|
||||
index edbeb6803..e280ae901 100644
|
||||
--- a/BUILD.gn
|
||||
+++ b/BUILD.gn
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter
|
||||
index f13271aa9..6b84f6a83 100755
|
||||
--- a/ci/licenses_golden/licenses_flutter
|
||||
+++ b/ci/licenses_golden/licenses_flutter
|
||||
@@ -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
|
||||
diff --git a/lib/ui/painting/image_decoder.cc b/lib/ui/painting/image_decoder.cc
|
||||
index d6c4a668f..b6ffb20f5 100644
|
||||
--- a/lib/ui/painting/image_decoder.cc
|
||||
+++ b/lib/ui/painting/image_decoder.cc
|
||||
@@ -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");
|
||||
diff --git a/lib/ui/painting/image_encoding.cc b/lib/ui/painting/image_encoding.cc
|
||||
index c17a784c5..8a7653f0b 100644
|
||||
--- a/lib/ui/painting/image_encoding.cc
|
||||
+++ b/lib/ui/painting/image_encoding.cc
|
||||
@@ -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();
|
||||
}
|
||||
diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc
|
||||
index b834957a9..8a6215110 100644
|
||||
--- a/runtime/dart_isolate.cc
|
||||
+++ b/runtime/dart_isolate.cc
|
||||
@@ -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();
|
||||
diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc
|
||||
index ae9849a5a..b0c61a1b5 100644
|
||||
--- a/shell/platform/embedder/embedder.cc
|
||||
+++ b/shell/platform/embedder/embedder.cc
|
||||
@@ -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;
|
||||
diff --git a/shell/platform/fuchsia/dart_runner/dart_runner.cc b/shell/platform/fuchsia/dart_runner/dart_runner.cc
|
||||
index 76d85405a..415d2885c 100644
|
||||
--- a/shell/platform/fuchsia/dart_runner/dart_runner.cc
|
||||
+++ b/shell/platform/fuchsia/dart_runner/dart_runner.cc
|
||||
@@ -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) {
|
||||
diff --git a/testing/run_tests.py b/testing/run_tests.py
|
||||
index 06b8256d0..8bdd114f4 100755
|
||||
--- a/testing/run_tests.py
|
||||
+++ b/testing/run_tests.py
|
||||
@@ -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)
|
||||
diff --git a/third_party/tonic/BUILD.gn b/third_party/tonic/BUILD.gn
|
||||
index f5bedda8d..9a6abda8b 100644
|
||||
--- a/third_party/tonic/BUILD.gn
|
||||
+++ b/third_party/tonic/BUILD.gn
|
||||
@@ -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",
|
||||
diff --git a/third_party/tonic/dart_state.cc b/third_party/tonic/dart_state.cc
|
||||
index b711a2297..3f37685c5 100644
|
||||
--- a/third_party/tonic/dart_state.cc
|
||||
+++ b/third_party/tonic/dart_state.cc
|
||||
@@ -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() {}
|
||||
|
||||
diff --git a/third_party/tonic/dart_state.h b/third_party/tonic/dart_state.h
|
||||
index 845914937..1984a66bf 100644
|
||||
--- a/third_party/tonic/dart_state.h
|
||||
+++ b/third_party/tonic/dart_state.h
|
||||
@@ -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);
|
||||
diff --git a/third_party/tonic/dart_weak_persistent_value.cc b/third_party/tonic/dart_weak_persistent_value.cc
|
||||
new file mode 100644
|
||||
index 000000000..a2664d3e0
|
||||
--- /dev/null
|
||||
+++ b/third_party/tonic/dart_weak_persistent_value.cc
|
||||
@@ -0,0 +1,70 @@
|
||||
+// 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
|
||||
diff --git a/third_party/tonic/dart_weak_persistent_value.h b/third_party/tonic/dart_weak_persistent_value.h
|
||||
new file mode 100644
|
||||
index 000000000..5f8aed5ee
|
||||
--- /dev/null
|
||||
+++ b/third_party/tonic/dart_weak_persistent_value.h
|
||||
@@ -0,0 +1,48 @@
|
||||
+// 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_
|
||||
diff --git a/third_party/tonic/dart_wrappable.cc b/third_party/tonic/dart_wrappable.cc
|
||||
index 3bdfe3e6e..858215c11 100644
|
||||
--- a/third_party/tonic/dart_wrappable.cc
|
||||
+++ b/third_party/tonic/dart_wrappable.cc
|
||||
@@ -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.
|
||||
}
|
||||
|
||||
diff --git a/third_party/tonic/dart_wrappable.h b/third_party/tonic/dart_wrappable.h
|
||||
index a036abb85..f944dacef 100644
|
||||
--- a/third_party/tonic/dart_wrappable.h
|
||||
+++ b/third_party/tonic/dart_wrappable.h
|
||||
@@ -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) {
|
||||
diff --git a/third_party/tonic/tests/BUILD.gn b/third_party/tonic/tests/BUILD.gn
|
||||
new file mode 100644
|
||||
index 000000000..359deb13b
|
||||
--- /dev/null
|
||||
+++ b/third_party/tonic/tests/BUILD.gn
|
||||
@@ -0,0 +1,33 @@
|
||||
+# 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" ]
|
||||
+}
|
||||
diff --git a/third_party/tonic/tests/dart_state_unittest.cc b/third_party/tonic/tests/dart_state_unittest.cc
|
||||
new file mode 100644
|
||||
index 000000000..3d053de40
|
||||
--- /dev/null
|
||||
+++ b/third_party/tonic/tests/dart_state_unittest.cc
|
||||
@@ -0,0 +1,61 @@
|
||||
+// 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
|
||||
diff --git a/third_party/tonic/tests/dart_weak_persistent_handle_unittest.cc b/third_party/tonic/tests/dart_weak_persistent_handle_unittest.cc
|
||||
new file mode 100644
|
||||
index 000000000..65d5e116c
|
||||
--- /dev/null
|
||||
+++ b/third_party/tonic/tests/dart_weak_persistent_handle_unittest.cc
|
||||
@@ -0,0 +1,167 @@
|
||||
+// 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
|
||||
diff --git a/third_party/tonic/tests/fixtures/tonic_test.dart b/third_party/tonic/tests/fixtures/tonic_test.dart
|
||||
new file mode 100644
|
||||
index 000000000..83e92d4dc
|
||||
--- /dev/null
|
||||
+++ b/third_party/tonic/tests/fixtures/tonic_test.dart
|
||||
@@ -0,0 +1,25 @@
|
||||
+// 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();
|
||||
+}
|
||||
diff --git a/third_party/tonic/typed_data/dart_byte_data.cc b/third_party/tonic/typed_data/dart_byte_data.cc
|
||||
index dc312de3f..cfb07399f 100644
|
||||
--- a/third_party/tonic/typed_data/dart_byte_data.cc
|
||||
+++ b/third_party/tonic/typed_data/dart_byte_data.cc
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user