From 31d56a973bbad90230f3aba67c070644f78b49fb Mon Sep 17 00:00:00 2001 From: andycall Date: Wed, 25 Dec 2024 13:36:41 +0800 Subject: [PATCH] feat: using std::atomic value types for disposed checks of NativeBindingObject. --- bridge/core/binding_object.cc | 2 +- bridge/core/binding_object.h | 6 ++- bridge/include/webf_bridge.h | 6 +++ bridge/webf_bridge.cc | 10 ++++ webf/lib/src/bridge/binding.dart | 6 +-- webf/lib/src/bridge/native_types.dart | 56 ++++++++++++++++---- webf/lib/src/gesture/gesture_dispatcher.dart | 3 +- 7 files changed, 73 insertions(+), 16 deletions(-) diff --git a/bridge/core/binding_object.cc b/bridge/core/binding_object.cc index 3d32da15d3..856385ecbb 100644 --- a/bridge/core/binding_object.cc +++ b/bridge/core/binding_object.cc @@ -77,7 +77,7 @@ void NativeBindingObject::HandleCallFromDartSide(const DartIsolateContext* dart_ BindingObject::BindingObject(JSContext* ctx) : ScriptWrappable(ctx), binding_object_(new NativeBindingObject(this)) {} BindingObject::~BindingObject() { // Set below properties to nullptr to avoid dart callback to native. - binding_object_->disposed_ = true; + binding_object_->disposed_.store(true, std::memory_order_release); binding_object_->binding_target_ = nullptr; binding_object_->invoke_binding_methods_from_dart = nullptr; binding_object_->invoke_bindings_methods_from_native = nullptr; diff --git a/bridge/core/binding_object.h b/bridge/core/binding_object.h index c308b0fe18..bd09dc6e75 100644 --- a/bridge/core/binding_object.h +++ b/bridge/core/binding_object.h @@ -54,12 +54,14 @@ struct NativeBindingObject : public DartReadable { const NativeValue* argv, Dart_PersistentHandle dart_object, DartInvokeResultCallback result_callback); - - bool disposed_{false}; + static bool IsDisposed(const NativeBindingObject* native_binding_object) { + return native_binding_object->disposed_.load(std::memory_order_acquire); + } BindingObject* binding_target_{nullptr}; InvokeBindingMethodsFromDart invoke_binding_methods_from_dart{nullptr}; InvokeBindingsMethodsFromNative invoke_bindings_methods_from_native{nullptr}; void* extra{nullptr}; + std::atomic disposed_{false}; }; enum BindingMethodCallOperations { diff --git a/bridge/include/webf_bridge.h b/bridge/include/webf_bridge.h index 2900e42ec5..ac3af6146b 100644 --- a/bridge/include/webf_bridge.h +++ b/bridge/include/webf_bridge.h @@ -123,6 +123,12 @@ void collectNativeProfileData(void* ptr, const char** data, uint32_t* len); WEBF_EXPORT_C void clearNativeProfileData(void* ptr); +WEBF_EXPORT_C +void* allocateNativeBindingObject(); + +WEBF_EXPORT_C +bool isNativeBindingObjectDisposed(void* native_binding_object); + WEBF_EXPORT_C WebFInfo* getWebFInfo(); WEBF_EXPORT_C diff --git a/bridge/webf_bridge.cc b/bridge/webf_bridge.cc index 22f95160e1..c19c3c500a 100644 --- a/bridge/webf_bridge.cc +++ b/bridge/webf_bridge.cc @@ -3,6 +3,8 @@ */ #include "include/webf_bridge.h" +#include + #include "core/dart_isolate_context.h" #include "core/html/parser/html_parser.h" #include "core/page.h" @@ -260,6 +262,14 @@ void clearNativeProfileData(void* ptr) { dart_isolate_context->profiler()->clear(); } +void* allocateNativeBindingObject() { + return new webf::NativeBindingObject(nullptr); +} + +bool isNativeBindingObjectDisposed(void* native_binding_object) { + return webf::NativeBindingObject::IsDisposed(static_cast(native_binding_object)); +} + void dispatchUITask(void* page_, void* context, void* callback) { auto page = reinterpret_cast(page_); reinterpret_cast(callback)(context); diff --git a/webf/lib/src/bridge/binding.dart b/webf/lib/src/bridge/binding.dart index deb63f072a..e5aba00ec2 100644 --- a/webf/lib/src/bridge/binding.dart +++ b/webf/lib/src/bridge/binding.dart @@ -110,8 +110,8 @@ Future _dispatchEventToNative(Event event, bool isCapture) async { if (contextId != null && pointer != null && pointer.ref.invokeBindingMethodFromDart != nullptr && - event.target?.pointer?.ref.disposed != true && - event.currentTarget?.pointer?.ref.disposed != true + !isBindingObjectDisposed(event.target?.pointer) && + !isBindingObjectDisposed(event.currentTarget?.pointer) ) { Completer completer = Completer(); @@ -204,7 +204,7 @@ abstract class BindingBridge { view.setBindingObject(nativeBindingObject, object); } - if (!nativeBindingObject.ref.disposed) { + if (!isBindingObjectDisposed(nativeBindingObject)) { nativeBindingObject.ref.invokeBindingMethodFromNative = _invokeBindingMethodFromNative; } } diff --git a/webf/lib/src/bridge/native_types.dart b/webf/lib/src/bridge/native_types.dart index d0adbe8454..8707ebfc5a 100644 --- a/webf/lib/src/bridge/native_types.dart +++ b/webf/lib/src/bridge/native_types.dart @@ -6,6 +6,7 @@ import 'dart:ffi'; import 'package:ffi/ffi.dart'; +import 'package:webf/bridge.dart'; import 'native_value.dart'; @@ -109,27 +110,64 @@ class NativeTouch extends Struct { external double azimuthAngle; } -typedef InvokeBindingsMethodsFromNative = Void Function(Double contextId, Int64 profileId, Pointer binding_object, - Pointer return_value, Pointer method, Int32 argc, Pointer argv); +typedef InvokeBindingsMethodsFromNative = Void Function( + Double contextId, + Int64 profileId, + Pointer binding_object, + Pointer return_value, + Pointer method, + Int32 argc, + Pointer argv); typedef NativeInvokeResultCallback = Void Function(Handle object, Pointer result); -typedef InvokeBindingMethodsFromDart = Void Function(Pointer binding_object, Int64 profileId, Pointer method, Int32 argc, Pointer argv, Handle bindingDartObject, Pointer> result_callback); -typedef DartInvokeBindingMethodsFromDart = void Function(Pointer binding_object, int profileId, Pointer method, int argc, Pointer argv, Object bindingDartObject, Pointer> result_callback); +typedef InvokeBindingMethodsFromDart = Void Function( + Pointer binding_object, + Int64 profileId, + Pointer method, + Int32 argc, + Pointer argv, + Handle bindingDartObject, + Pointer> result_callback); +typedef DartInvokeBindingMethodsFromDart = void Function( + Pointer binding_object, + int profileId, + Pointer method, + int argc, + Pointer argv, + Object bindingDartObject, + Pointer> result_callback); class NativeBindingObject extends Struct { - @Bool() - external bool disposed; external Pointer instance; external Pointer> invokeBindingMethodFromDart; // Shared method called by JS side. external Pointer> invokeBindingMethodFromNative; external Pointer extra; + @Bool() + external bool _disposed; } +typedef NativeAllocateNativeBindingObject = Pointer Function(); +typedef DartAllocateNativeBindingObject = Pointer Function(); + +final DartAllocateNativeBindingObject _allocateNativeBindingObject = WebFDynamicLibrary.ref + .lookup>('allocateNativeBindingObject') + .asFunction(); + +typedef NativeIsNativeBindingObjectDisposed = Bool Function(Pointer); +typedef DartIsNativeBindingObjectDisposed = bool Function(Pointer); + +final DartIsNativeBindingObjectDisposed _isNativeBindingObjectDisposed = WebFDynamicLibrary.ref + .lookup>('isNativeBindingObjectDisposed') + .asFunction(); + Pointer allocateNewBindingObject() { - Pointer pointer = malloc.allocate(sizeOf()); - pointer.ref.disposed = false; - return pointer; + return _allocateNativeBindingObject(); +} + +bool isBindingObjectDisposed(Pointer? nativeBindingObject) { + if (nativeBindingObject == null) return true; + return _isNativeBindingObjectDisposed(nativeBindingObject); } class NativePerformanceEntry extends Struct { diff --git a/webf/lib/src/gesture/gesture_dispatcher.dart b/webf/lib/src/gesture/gesture_dispatcher.dart index 963c199a92..7d05dd04ba 100644 --- a/webf/lib/src/gesture/gesture_dispatcher.dart +++ b/webf/lib/src/gesture/gesture_dispatcher.dart @@ -11,6 +11,7 @@ import 'package:flutter/material.dart'; import 'package:webf/dom.dart'; import 'package:webf/gesture.dart'; import 'package:webf/html.dart'; +import 'package:webf/bridge.dart'; class _DragEventInfo extends Drag { _DragEventInfo(this.gestureDispatcher); @@ -432,7 +433,7 @@ class GestureDispatcher { // The touch target might be eliminated from the DOM tree and collected by JavaScript GC, // resulting in it becoming invisible and inaccessible, yet this change is not synchronized with Dart instantly. // Therefore, refrain from triggering events on these unavailable DOM targets. - if (touch.target.pointer?.ref.disposed == true) { + if (isBindingObjectDisposed(touch.target.pointer)) { continue; }