Skip to content

Commit

Permalink
feat: using std::atomic value types for disposed checks of NativeBind…
Browse files Browse the repository at this point in the history
…ingObject.
  • Loading branch information
andycall committed Dec 30, 2024
1 parent 7bd227b commit d6b97cd
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 16 deletions.
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

0 comments on commit d6b97cd

Please sign in to comment.