Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: using std::atomic value types for disposed checks of NativeBindingObject. #699

Merged
merged 1 commit into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bridge/core/binding_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions bridge/core/binding_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool> disposed_{false};
};

enum BindingMethodCallOperations {
Expand Down
6 changes: 6 additions & 0 deletions bridge/include/webf_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions bridge/webf_bridge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
*/

#include "include/webf_bridge.h"
#include <core/binding_object.h>

#include "core/dart_isolate_context.h"
#include "core/html/parser/html_parser.h"
#include "core/page.h"
Expand Down Expand Up @@ -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<webf::NativeBindingObject*>(native_binding_object));
}

void dispatchUITask(void* page_, void* context, void* callback) {
auto page = reinterpret_cast<webf::WebFPage*>(page_);
reinterpret_cast<void (*)(void*)>(callback)(context);
Expand Down
6 changes: 3 additions & 3 deletions webf/lib/src/bridge/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ Future<void> _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();

Expand Down Expand Up @@ -204,7 +204,7 @@ abstract class BindingBridge {
view.setBindingObject(nativeBindingObject, object);
}

if (!nativeBindingObject.ref.disposed) {
if (!isBindingObjectDisposed(nativeBindingObject)) {
nativeBindingObject.ref.invokeBindingMethodFromNative = _invokeBindingMethodFromNative;
}
}
Expand Down
56 changes: 47 additions & 9 deletions webf/lib/src/bridge/native_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:webf/bridge.dart';

import 'native_value.dart';

Expand Down Expand Up @@ -109,27 +110,64 @@ class NativeTouch extends Struct {
external double azimuthAngle;
}

typedef InvokeBindingsMethodsFromNative = Void Function(Double contextId, Int64 profileId, Pointer<NativeBindingObject> binding_object,
Pointer<NativeValue> return_value, Pointer<NativeValue> method, Int32 argc, Pointer<NativeValue> argv);
typedef InvokeBindingsMethodsFromNative = Void Function(
Double contextId,
Int64 profileId,
Pointer<NativeBindingObject> binding_object,
Pointer<NativeValue> return_value,
Pointer<NativeValue> method,
Int32 argc,
Pointer<NativeValue> argv);
typedef NativeInvokeResultCallback = Void Function(Handle object, Pointer<NativeValue> result);

typedef InvokeBindingMethodsFromDart = Void Function(Pointer<NativeBindingObject> binding_object, Int64 profileId, Pointer<NativeValue> method, Int32 argc, Pointer<NativeValue> argv, Handle bindingDartObject, Pointer<NativeFunction<NativeInvokeResultCallback>> result_callback);
typedef DartInvokeBindingMethodsFromDart = void Function(Pointer<NativeBindingObject> binding_object, int profileId, Pointer<NativeValue> method, int argc, Pointer<NativeValue> argv, Object bindingDartObject, Pointer<NativeFunction<NativeInvokeResultCallback>> result_callback);
typedef InvokeBindingMethodsFromDart = Void Function(
Pointer<NativeBindingObject> binding_object,
Int64 profileId,
Pointer<NativeValue> method,
Int32 argc,
Pointer<NativeValue> argv,
Handle bindingDartObject,
Pointer<NativeFunction<NativeInvokeResultCallback>> result_callback);
typedef DartInvokeBindingMethodsFromDart = void Function(
Pointer<NativeBindingObject> binding_object,
int profileId,
Pointer<NativeValue> method,
int argc,
Pointer<NativeValue> argv,
Object bindingDartObject,
Pointer<NativeFunction<NativeInvokeResultCallback>> result_callback);

class NativeBindingObject extends Struct {
@Bool()
external bool disposed;
external Pointer<Void> instance;
external Pointer<NativeFunction<InvokeBindingMethodsFromDart>> invokeBindingMethodFromDart;
// Shared method called by JS side.
external Pointer<NativeFunction<InvokeBindingsMethodsFromNative>> invokeBindingMethodFromNative;
external Pointer<Void> extra;
@Bool()
external bool _disposed;
}

typedef NativeAllocateNativeBindingObject = Pointer<NativeBindingObject> Function();
typedef DartAllocateNativeBindingObject = Pointer<NativeBindingObject> Function();

final DartAllocateNativeBindingObject _allocateNativeBindingObject = WebFDynamicLibrary.ref
.lookup<NativeFunction<NativeAllocateNativeBindingObject>>('allocateNativeBindingObject')
.asFunction();

typedef NativeIsNativeBindingObjectDisposed = Bool Function(Pointer<NativeBindingObject>);
typedef DartIsNativeBindingObjectDisposed = bool Function(Pointer<NativeBindingObject>);

final DartIsNativeBindingObjectDisposed _isNativeBindingObjectDisposed = WebFDynamicLibrary.ref
.lookup<NativeFunction<NativeIsNativeBindingObjectDisposed>>('isNativeBindingObjectDisposed')
.asFunction();

Pointer<NativeBindingObject> allocateNewBindingObject() {
Pointer<NativeBindingObject> pointer = malloc.allocate(sizeOf<NativeBindingObject>());
pointer.ref.disposed = false;
return pointer;
return _allocateNativeBindingObject();
}

bool isBindingObjectDisposed(Pointer<NativeBindingObject>? nativeBindingObject) {
if (nativeBindingObject == null) return true;
return _isNativeBindingObjectDisposed(nativeBindingObject);
}

class NativePerformanceEntry extends Struct {
Expand Down
3 changes: 2 additions & 1 deletion webf/lib/src/gesture/gesture_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down
Loading