mirror of
https://github.com/wgh136/flutter_qjs.git
synced 2025-09-27 05:27:23 +00:00
remove dart object when jsfree.
This commit is contained in:
59
lib/ffi.dart
59
lib/ffi.dart
@@ -113,13 +113,14 @@ class RuntimeOpaque {
|
||||
List<JSRef> ref = [];
|
||||
ReceivePort port;
|
||||
Future Function(Pointer) promiseToFuture;
|
||||
Pointer Function(Object) objectWrapper;
|
||||
int dartObjectClassId;
|
||||
}
|
||||
|
||||
final Map<Pointer, RuntimeOpaque> runtimeOpaques = Map();
|
||||
|
||||
Pointer channelDispacher(Pointer ctx, Pointer method, Pointer argv) {
|
||||
return runtimeOpaques[jsGetRuntime(ctx)].channel(ctx, method, argv);
|
||||
Pointer rt = method.address == 0 ? ctx : jsGetRuntime(ctx);
|
||||
return runtimeOpaques[rt]?.channel(ctx, method, argv);
|
||||
}
|
||||
|
||||
Pointer jsNewRuntime(
|
||||
@@ -518,6 +519,60 @@ String jsToCString(
|
||||
return str;
|
||||
}
|
||||
|
||||
/// DLLEXPORT uint32_t jsNewClass(JSContext *ctx, const char *name)
|
||||
final int Function(
|
||||
Pointer ctx,
|
||||
Pointer<Utf8> name,
|
||||
) _jsNewClass = qjsLib
|
||||
.lookup<
|
||||
NativeFunction<
|
||||
Uint32 Function(
|
||||
Pointer,
|
||||
Pointer<Utf8>,
|
||||
)>>("jsNewClass")
|
||||
.asFunction();
|
||||
|
||||
int jsNewClass(
|
||||
Pointer ctx,
|
||||
String name,
|
||||
) {
|
||||
var utf8name = Utf8.toUtf8(name);
|
||||
var val = _jsNewClass(
|
||||
ctx,
|
||||
utf8name,
|
||||
);
|
||||
free(utf8name);
|
||||
return val;
|
||||
}
|
||||
|
||||
/// DLLEXPORT JSValue *jsNewObjectClass(JSContext *ctx, uint32_t QJSClassId, void *opaque)
|
||||
final Pointer Function(
|
||||
Pointer ctx,
|
||||
int classId,
|
||||
int opaque,
|
||||
) jsNewObjectClass = qjsLib
|
||||
.lookup<
|
||||
NativeFunction<
|
||||
Pointer Function(
|
||||
Pointer,
|
||||
Uint32,
|
||||
IntPtr,
|
||||
)>>("jsNewObjectClass")
|
||||
.asFunction();
|
||||
|
||||
/// DLLEXPORT void *jsGetObjectOpaque(JSValue *obj, uint32_t classid)
|
||||
final int Function(
|
||||
Pointer obj,
|
||||
int classid,
|
||||
) jsGetObjectOpaque = qjsLib
|
||||
.lookup<
|
||||
NativeFunction<
|
||||
IntPtr Function(
|
||||
Pointer,
|
||||
Uint32,
|
||||
)>>("jsGetObjectOpaque")
|
||||
.asFunction();
|
||||
|
||||
/// uint8_t *jsGetArrayBuffer(JSContext *ctx, size_t *psize, JSValueConst *obj)
|
||||
final Pointer<Uint8> Function(
|
||||
Pointer ctx,
|
||||
|
@@ -44,7 +44,14 @@ class FlutterQjs {
|
||||
if (_rt != null) return;
|
||||
_rt = jsNewRuntime((ctx, method, argv) {
|
||||
try {
|
||||
if (method.address != 0) {
|
||||
if (method.address == 0) {
|
||||
Pointer rt = ctx;
|
||||
DartObject obj = DartObject.fromAddress(rt, argv.address);
|
||||
obj?.release();
|
||||
runtimeOpaques[rt]?.ref?.remove(obj);
|
||||
return Pointer.fromAddress(0);
|
||||
}
|
||||
if (argv.address != 0 && method.address != 0) {
|
||||
if (methodHandler == null) throw Exception("No MethodHandler");
|
||||
var argvs = jsToDart(ctx, argv);
|
||||
return dartToJs(
|
||||
@@ -55,7 +62,8 @@ class FlutterQjs {
|
||||
));
|
||||
}
|
||||
if (moduleHandler == null) throw Exception("No ModuleHandler");
|
||||
var ret = Utf8.toUtf8(moduleHandler(Utf8.fromUtf8(argv.cast<Utf8>())));
|
||||
var ret =
|
||||
Utf8.toUtf8(moduleHandler(Utf8.fromUtf8(method.cast<Utf8>())));
|
||||
Future.microtask(() {
|
||||
free(ret);
|
||||
});
|
||||
|
@@ -44,15 +44,16 @@ class DartObject implements JSRef {
|
||||
runtimeOpaques[jsGetRuntime(ctx)]?.ref?.add(this);
|
||||
}
|
||||
|
||||
static DartObject fromAddress(Pointer ctx, int val) {
|
||||
return runtimeOpaques[jsGetRuntime(ctx)]?.ref?.firstWhere(
|
||||
static DartObject fromAddress(Pointer rt, int val) {
|
||||
return runtimeOpaques[rt]?.ref?.firstWhere(
|
||||
(e) => identityHashCode(e) == val,
|
||||
orElse: null,
|
||||
orElse: () => null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void release() {
|
||||
obj = null;
|
||||
ctx = null;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +217,14 @@ Pointer dartToJs(Pointer ctx, dynamic val, {Map<dynamic, dynamic> cache}) {
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return runtimeOpaques[jsGetRuntime(ctx)]?.objectWrapper(val) ?? jsUNDEFINED();
|
||||
int dartObjectClassId =
|
||||
runtimeOpaques[jsGetRuntime(ctx)]?.dartObjectClassId ?? 0;
|
||||
if (dartObjectClassId == 0) return jsUNDEFINED();
|
||||
return jsNewObjectClass(
|
||||
ctx,
|
||||
dartObjectClassId,
|
||||
identityHashCode(DartObject(ctx, val)),
|
||||
);
|
||||
}
|
||||
|
||||
dynamic jsToDart(Pointer ctx, Pointer val, {Map<int, dynamic> cache}) {
|
||||
@@ -233,6 +241,13 @@ dynamic jsToDart(Pointer ctx, Pointer val, {Map<int, dynamic> cache}) {
|
||||
case JSTag.STRING:
|
||||
return jsToCString(ctx, val);
|
||||
case JSTag.OBJECT:
|
||||
final rt = jsGetRuntime(ctx);
|
||||
final dartObjectClassId = runtimeOpaques[rt].dartObjectClassId;
|
||||
if (dartObjectClassId != 0) {
|
||||
final dartObject = DartObject.fromAddress(
|
||||
rt, jsGetObjectOpaque(val, dartObjectClassId));
|
||||
if (dartObject != null) return dartObject.obj;
|
||||
}
|
||||
Pointer<IntPtr> psize = allocate<IntPtr>();
|
||||
Pointer<Uint8> buf = jsGetArrayBuffer(ctx, psize, val);
|
||||
int size = psize.value;
|
||||
@@ -247,7 +262,7 @@ dynamic jsToDart(Pointer ctx, Pointer val, {Map<int, dynamic> cache}) {
|
||||
if (jsIsFunction(ctx, val) != 0) {
|
||||
return JSFunction(ctx, val);
|
||||
} else if (jsIsPromise(ctx, val) != 0) {
|
||||
return runtimeOpaques[jsGetRuntime(ctx)]?.promiseToFuture(val);
|
||||
return runtimeOpaques[rt]?.promiseToFuture(val);
|
||||
} else if (jsIsArray(ctx, val) != 0) {
|
||||
Pointer jslength = jsGetPropertyStr(ctx, val, "length");
|
||||
int length = jsToInt64(ctx, jslength);
|
||||
@@ -283,10 +298,6 @@ dynamic jsToDart(Pointer ctx, Pointer val, {Map<int, dynamic> cache}) {
|
||||
}
|
||||
jsFree(ctx, ptab.value);
|
||||
free(ptab);
|
||||
final objHash = ret["__dart_obj_hash__"];
|
||||
if (objHash is int) {
|
||||
return DartObject.fromAddress(ctx, objHash)?.obj ?? ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
@@ -318,23 +329,9 @@ Pointer jsNewContextWithPromsieWrapper(Pointer rt) {
|
||||
""",
|
||||
"<future>",
|
||||
JSEvalFlag.GLOBAL);
|
||||
var jsObjectWrapper = jsEval(
|
||||
ctx,
|
||||
"""
|
||||
(objHash, type) => {
|
||||
const ret = {
|
||||
"__dart_obj_hash__": objHash,
|
||||
};
|
||||
ret.__proto__.toString = ()=> "" + type;
|
||||
return ret;
|
||||
};
|
||||
""",
|
||||
"<future>",
|
||||
JSEvalFlag.GLOBAL);
|
||||
runtimeOpaque.dartObjectClassId = jsNewClass(ctx, "DartObject");
|
||||
final promiseWrapper = JSRefValue(ctx, jsPromiseWrapper);
|
||||
jsFreeValue(ctx, jsPromiseWrapper);
|
||||
final objectWrapper = JSRefValue(ctx, jsObjectWrapper);
|
||||
jsFreeValue(ctx, jsObjectWrapper);
|
||||
runtimeOpaque.promiseToFuture = (promise) {
|
||||
var completer = Completer();
|
||||
var wrapper = promiseWrapper.val;
|
||||
@@ -345,16 +342,5 @@ Pointer jsNewContextWithPromsieWrapper(Pointer rt) {
|
||||
jsFreeValue(ctx, jsPromise);
|
||||
return wrapPromise.completer.future;
|
||||
};
|
||||
runtimeOpaque.objectWrapper = (obj) {
|
||||
var jsObjHash = jsNewInt64(ctx, identityHashCode(DartObject(ctx, obj)));
|
||||
var jsTypeString = jsNewString(ctx, obj.toString());
|
||||
var wrapper = objectWrapper.val;
|
||||
if (wrapper == null) throw Exception("Runtime has been released!");
|
||||
var ret = jsCall(ctx, wrapper, null, [jsObjHash, jsTypeString]);
|
||||
jsFreeValue(ctx, jsObjHash);
|
||||
jsFreeValue(ctx, jsTypeString);
|
||||
return ret;
|
||||
};
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
Reference in New Issue
Block a user