mirror of
https://github.com/wgh136/flutter_qjs.git
synced 2025-09-27 05:27:23 +00:00
fix qjs memory leak
This commit is contained in:
@@ -3,8 +3,12 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-08 08:16:50
|
* @Date: 2020-08-08 08:16:50
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-10-03 00:28:18
|
* @LastEditTime: 2020-10-03 23:34:30
|
||||||
-->
|
-->
|
||||||
|
## 0.1.2
|
||||||
|
|
||||||
|
* fix qjs memory leak.
|
||||||
|
|
||||||
## 0.1.1
|
## 0.1.1
|
||||||
|
|
||||||
* run on isolate.
|
* run on isolate.
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-08 08:16:50
|
* @Date: 2020-08-08 08:16:50
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-10-03 00:36:36
|
* @LastEditTime: 2020-10-03 00:44:41
|
||||||
-->
|
-->
|
||||||
# flutter_qjs
|
# flutter_qjs
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ channel("http", ["http://example.com/"]);
|
|||||||
|
|
||||||
~~I cannot find a way to convert the sync ffi callback into an async function. So the assets files received by async function `rootBundle.loadString` cannot be used in this version. I will appreciate it if you can provide me a solution to make `ModuleHandler` async.~~
|
~~I cannot find a way to convert the sync ffi callback into an async function. So the assets files received by async function `rootBundle.loadString` cannot be used in this version. I will appreciate it if you can provide me a solution to make `ModuleHandler` async.~~
|
||||||
|
|
||||||
To use async function in module handler, try [Run on isolate thread](#isolate)
|
To use async function in module handler, try [Run on isolate thread](#Run-on-isolate-thread)
|
||||||
|
|
||||||
```dart
|
```dart
|
||||||
await engine.setModuleHandler((String module) {
|
await engine.setModuleHandler((String module) {
|
||||||
@@ -94,7 +94,7 @@ try {
|
|||||||
|
|
||||||
5. Method `recreate` can destroy quickjs runtime that can be recreated again if you call `evaluate`, `recreat` can be used to reset the module cache. Call `close` to stop `dispatch` when you do not need it.
|
5. Method `recreate` can destroy quickjs runtime that can be recreated again if you call `evaluate`, `recreat` can be used to reset the module cache. Call `close` to stop `dispatch` when you do not need it.
|
||||||
|
|
||||||
### <span id="isolate">Run on isolate thread</span>
|
### Run on isolate thread
|
||||||
|
|
||||||
1. Create a `IsolateQjs` object, pass a handler to implement js-dart interaction. The handler is used in isolate, so the function must be a top-level function or a static method.
|
1. Create a `IsolateQjs` object, pass a handler to implement js-dart interaction. The handler is used in isolate, so the function must be a top-level function or a static method.
|
||||||
|
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-09-06 18:32:45
|
* @Date: 2020-09-06 18:32:45
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-09-24 22:32:15
|
* @LastEditTime: 2020-10-03 23:26:14
|
||||||
*/
|
*/
|
||||||
#include "ffi.h"
|
#include "ffi.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -293,4 +293,9 @@ extern "C"
|
|||||||
{
|
{
|
||||||
return new JSValue(JS_NewPromiseCapability(ctx, resolving_funcs));
|
return new JSValue(JS_NewPromiseCapability(ctx, resolving_funcs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DLLEXPORT void jsFree(JSContext *ctx, void *ptab)
|
||||||
|
{
|
||||||
|
js_free(ctx, ptab);
|
||||||
|
}
|
||||||
}
|
}
|
@@ -106,4 +106,6 @@ extern "C"
|
|||||||
DLLEXPORT int32_t jsExecutePendingJob(JSRuntime *rt);
|
DLLEXPORT int32_t jsExecutePendingJob(JSRuntime *rt);
|
||||||
|
|
||||||
DLLEXPORT JSValue *jsNewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
|
DLLEXPORT JSValue *jsNewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
|
||||||
|
|
||||||
|
DLLEXPORT void jsFree(JSContext *ctx, void *ptab);
|
||||||
}
|
}
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-08 08:16:51
|
* @Date: 2020-08-08 08:16:51
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-10-03 00:38:41
|
* @LastEditTime: 2020-10-03 21:37:22
|
||||||
*/
|
*/
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
@@ -103,8 +103,8 @@ class _TestPageState extends State<TestPage> {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
_ensureEngine();
|
_ensureEngine();
|
||||||
try {
|
try {
|
||||||
resp = (await engine.evaluate(
|
resp = (await engine.evaluate(_controller.text ?? '',
|
||||||
_controller.text ?? '', "<eval>"))
|
name: "<eval>"))
|
||||||
.toString();
|
.toString();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
resp = e.toString();
|
resp = e.toString();
|
||||||
|
@@ -7,42 +7,42 @@ packages:
|
|||||||
name: async
|
name: async
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0-nullsafety"
|
version: "2.5.0-nullsafety.1"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: boolean_selector
|
name: boolean_selector
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety"
|
version: "2.1.0-nullsafety.1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: characters
|
name: characters
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety.2"
|
version: "1.1.0-nullsafety.3"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: charcode
|
name: charcode
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety"
|
version: "1.2.0-nullsafety.1"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: clock
|
name: clock
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety"
|
version: "1.1.0-nullsafety.1"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0-nullsafety.2"
|
version: "1.15.0-nullsafety.3"
|
||||||
dio:
|
dio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -56,7 +56,7 @@ packages:
|
|||||||
name: fake_async
|
name: fake_async
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety"
|
version: "1.2.0-nullsafety.1"
|
||||||
ffi:
|
ffi:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -82,7 +82,7 @@ packages:
|
|||||||
path: ".."
|
path: ".."
|
||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.1.1"
|
version: "0.1.2"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -108,21 +108,21 @@ packages:
|
|||||||
name: matcher
|
name: matcher
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.10-nullsafety"
|
version: "0.12.10-nullsafety.1"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.2"
|
version: "1.3.0-nullsafety.3"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0-nullsafety"
|
version: "1.8.0-nullsafety.1"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -134,56 +134,56 @@ packages:
|
|||||||
name: source_span
|
name: source_span
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0-nullsafety"
|
version: "1.8.0-nullsafety.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0-nullsafety"
|
version: "1.10.0-nullsafety.2"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety"
|
version: "2.1.0-nullsafety.1"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: string_scanner
|
name: string_scanner
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety"
|
version: "1.1.0-nullsafety.1"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: term_glyph
|
name: term_glyph
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety"
|
version: "1.2.0-nullsafety.1"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.19-nullsafety"
|
version: "0.2.19-nullsafety.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: typed_data
|
name: typed_data
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.2"
|
version: "1.3.0-nullsafety.3"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety.2"
|
version: "2.1.0-nullsafety.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.10.0-0.0.dev <2.10.0"
|
dart: ">=2.10.0-110 <=2.11.0-181.0.dev"
|
||||||
flutter: ">=1.20.0 <2.0.0"
|
flutter: ">=1.20.0 <2.0.0"
|
||||||
|
15
lib/ffi.dart
15
lib/ffi.dart
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-09-19 10:29:04
|
* @Date: 2020-09-19 10:29:04
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-09-27 01:12:16
|
* @LastEditTime: 2020-10-03 23:27:15
|
||||||
*/
|
*/
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
@@ -744,3 +744,16 @@ final Pointer Function(
|
|||||||
Pointer,
|
Pointer,
|
||||||
)>>("jsNewPromiseCapability")
|
)>>("jsNewPromiseCapability")
|
||||||
.asFunction();
|
.asFunction();
|
||||||
|
|
||||||
|
/// void jsFree(JSContext *ctx, void *ptab)
|
||||||
|
final void Function(
|
||||||
|
Pointer ctx,
|
||||||
|
Pointer ptab,
|
||||||
|
) jsFree = qjsLib
|
||||||
|
.lookup<
|
||||||
|
NativeFunction<
|
||||||
|
Void Function(
|
||||||
|
Pointer,
|
||||||
|
Pointer,
|
||||||
|
)>>("jsFree")
|
||||||
|
.asFunction();
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-08-08 08:29:09
|
* @Date: 2020-08-08 08:29:09
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-10-03 00:18:49
|
* @LastEditTime: 2020-10-03 21:55:07
|
||||||
*/
|
*/
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
@@ -116,9 +116,10 @@ class FlutterQjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate js script.
|
/// Evaluate js script.
|
||||||
Future<dynamic> evaluate(String command, String name) async {
|
Future<dynamic> evaluate(String command, {String name, int evalFlags}) async {
|
||||||
_ensureEngine();
|
_ensureEngine();
|
||||||
var jsval = jsEval(_ctx, command, name, JSEvalType.GLOBAL);
|
var jsval =
|
||||||
|
jsEval(_ctx, command, name ?? "<eval>", evalFlags ?? JSEvalType.GLOBAL);
|
||||||
if (jsIsException(jsval) != 0) {
|
if (jsIsException(jsval) != 0) {
|
||||||
throw Exception(parseJSException(_ctx));
|
throw Exception(parseJSException(_ctx));
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-10-02 13:49:03
|
* @Date: 2020-10-02 13:49:03
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-10-03 00:18:40
|
* @LastEditTime: 2020-10-03 22:21:31
|
||||||
*/
|
*/
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
@@ -123,18 +123,21 @@ void _runJsIsolate(Map spawnMessage) async {
|
|||||||
sendPort.send(port.sendPort);
|
sendPort.send(port.sendPort);
|
||||||
qjs.setMethodHandler(methodHandler);
|
qjs.setMethodHandler(methodHandler);
|
||||||
qjs.setModuleHandler((name) {
|
qjs.setModuleHandler((name) {
|
||||||
var ptr = allocate<Int64>();
|
var ptr = allocate<Pointer<Utf8>>();
|
||||||
|
ptr.value = Pointer.fromAddress(0);
|
||||||
sendPort.send({
|
sendPort.send({
|
||||||
'type': 'module',
|
'type': 'module',
|
||||||
'name': name,
|
'name': name,
|
||||||
'ptr': ptr.address,
|
'ptr': ptr.address,
|
||||||
});
|
});
|
||||||
ptr.value = 0;
|
while (ptr.value.address == 0) sleep(Duration.zero);
|
||||||
while (ptr.value == 0) sleep(Duration.zero);
|
if (ptr.value.address == -1) throw Exception("Module Not found");
|
||||||
print(ptr.value);
|
var ret = Utf8.fromUtf8(ptr.value);
|
||||||
if (ptr.value == -1) throw Exception("Module Not found");
|
sendPort.send({
|
||||||
var strptr = Pointer<Utf8>.fromAddress(ptr.value);
|
'type': 'release',
|
||||||
var ret = Utf8.fromUtf8(strptr);
|
'ptr': ptr.value.address,
|
||||||
|
});
|
||||||
|
free(ptr);
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
qjs.dispatch();
|
qjs.dispatch();
|
||||||
@@ -144,7 +147,11 @@ void _runJsIsolate(Map spawnMessage) async {
|
|||||||
try {
|
try {
|
||||||
switch (msg['type']) {
|
switch (msg['type']) {
|
||||||
case 'evaluate':
|
case 'evaluate':
|
||||||
data = await qjs.evaluate(msg['command'], msg['name']);
|
data = await qjs.evaluate(
|
||||||
|
msg['command'],
|
||||||
|
name: msg['name'],
|
||||||
|
evalFlags: msg['flag'],
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case 'call':
|
case 'call':
|
||||||
data = JSFunction.fromAddress(
|
data = JSFunction.fromAddress(
|
||||||
@@ -174,7 +181,7 @@ typedef JsAsyncModuleHandler = Future<String> Function(String name);
|
|||||||
typedef JsIsolateSpawn = void Function(SendPort sendPort);
|
typedef JsIsolateSpawn = void Function(SendPort sendPort);
|
||||||
|
|
||||||
class IsolateQjs {
|
class IsolateQjs {
|
||||||
SendPort _sendPort;
|
Future<SendPort> _sendPort;
|
||||||
JsMethodHandler _methodHandler;
|
JsMethodHandler _methodHandler;
|
||||||
JsAsyncModuleHandler _moduleHandler;
|
JsAsyncModuleHandler _moduleHandler;
|
||||||
|
|
||||||
@@ -182,7 +189,7 @@ class IsolateQjs {
|
|||||||
/// The function must be a top-level function or a static method
|
/// The function must be a top-level function or a static method
|
||||||
IsolateQjs(this._methodHandler);
|
IsolateQjs(this._methodHandler);
|
||||||
|
|
||||||
Future<void> _ensureEngine() async {
|
_ensureEngine() {
|
||||||
if (_sendPort != null) return;
|
if (_sendPort != null) return;
|
||||||
ReceivePort port = ReceivePort();
|
ReceivePort port = ReceivePort();
|
||||||
Isolate.spawn(
|
Isolate.spawn(
|
||||||
@@ -193,28 +200,30 @@ class IsolateQjs {
|
|||||||
},
|
},
|
||||||
errorsAreFatal: true,
|
errorsAreFatal: true,
|
||||||
);
|
);
|
||||||
var completer = Completer();
|
var completer = Completer<SendPort>();
|
||||||
port.listen((msg) async {
|
port.listen((msg) async {
|
||||||
if (msg is SendPort && !completer.isCompleted) {
|
if (msg is SendPort && !completer.isCompleted) {
|
||||||
_sendPort = msg;
|
completer.complete(msg);
|
||||||
completer.complete();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (msg['type']) {
|
switch (msg['type']) {
|
||||||
case 'module':
|
case 'module':
|
||||||
var ptr = Pointer<Int64>.fromAddress(msg['ptr']);
|
var ptr = Pointer<Pointer>.fromAddress(msg['ptr']);
|
||||||
try {
|
try {
|
||||||
ptr.value = Utf8.toUtf8(await _moduleHandler(msg['name'])).address;
|
ptr.value = Utf8.toUtf8(await _moduleHandler(msg['name']));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ptr.value = -1;
|
ptr.value = Pointer.fromAddress(-1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'release':
|
||||||
|
free(Pointer.fromAddress(msg['ptr']));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}, onDone: () {
|
}, onDone: () {
|
||||||
close();
|
close();
|
||||||
if (!completer.isCompleted) completer.completeError('isolate close');
|
if (!completer.isCompleted) completer.completeError('isolate close');
|
||||||
});
|
});
|
||||||
await completer.future;
|
_sendPort = completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a handler to manage js module.
|
/// Set a handler to manage js module.
|
||||||
@@ -223,24 +232,29 @@ class IsolateQjs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
close() {
|
close() {
|
||||||
_sendPort.send({
|
if (_sendPort == null) return;
|
||||||
|
_sendPort.then((sendPort) {
|
||||||
|
sendPort.send({
|
||||||
'type': 'close',
|
'type': 'close',
|
||||||
});
|
});
|
||||||
|
});
|
||||||
_sendPort = null;
|
_sendPort = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<dynamic> evaluate(String command, String name) async {
|
Future<dynamic> evaluate(String command, {String name, int evalFlags}) async {
|
||||||
await _ensureEngine();
|
_ensureEngine();
|
||||||
var evaluatePort = ReceivePort();
|
var evaluatePort = ReceivePort();
|
||||||
_sendPort.send({
|
var sendPort = await _sendPort;
|
||||||
|
sendPort.send({
|
||||||
'type': 'evaluate',
|
'type': 'evaluate',
|
||||||
'command': command,
|
'command': command,
|
||||||
'name': name,
|
'name': name,
|
||||||
|
'flag': evalFlags,
|
||||||
'port': evaluatePort.sendPort,
|
'port': evaluatePort.sendPort,
|
||||||
});
|
});
|
||||||
var result = await evaluatePort.first;
|
var result = await evaluatePort.first;
|
||||||
if (result['data'] != null)
|
if (result['data'] != null)
|
||||||
return _decodeData(result['data'], _sendPort);
|
return _decodeData(result['data'], sendPort);
|
||||||
else
|
else
|
||||||
throw result['error'];
|
throw result['error'];
|
||||||
}
|
}
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-09-19 22:07:47
|
* @Date: 2020-09-19 22:07:47
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-10-02 16:37:16
|
* @LastEditTime: 2020-10-03 23:27:36
|
||||||
*/
|
*/
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
@@ -84,11 +84,12 @@ class JSFunction extends JSRefValue {
|
|||||||
jsFreeValue(ctx, jsArg);
|
jsFreeValue(ctx, jsArg);
|
||||||
}
|
}
|
||||||
bool isException = jsIsException(jsRet) != 0;
|
bool isException = jsIsException(jsRet) != 0;
|
||||||
var ret = jsToDart(ctx, jsRet);
|
|
||||||
jsFreeValue(ctx, jsRet);
|
|
||||||
if (isException) {
|
if (isException) {
|
||||||
|
jsFreeValue(ctx, jsRet);
|
||||||
throw Exception(parseJSException(ctx));
|
throw Exception(parseJSException(ctx));
|
||||||
}
|
}
|
||||||
|
var ret = jsToDart(ctx, jsRet);
|
||||||
|
jsFreeValue(ctx, jsRet);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,6 +258,7 @@ dynamic jsToDart(Pointer ctx, Pointer val, {Map<int, dynamic> cache}) {
|
|||||||
jsFreeValue(ctx, jsProp);
|
jsFreeValue(ctx, jsProp);
|
||||||
jsFreeAtom(ctx, jsAtom);
|
jsFreeAtom(ctx, jsAtom);
|
||||||
}
|
}
|
||||||
|
jsFree(ctx, ptab.value);
|
||||||
free(ptab);
|
free(ptab);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
38
pubspec.lock
38
pubspec.lock
@@ -7,49 +7,49 @@ packages:
|
|||||||
name: async
|
name: async
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.5.0-nullsafety"
|
version: "2.5.0-nullsafety.1"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: boolean_selector
|
name: boolean_selector
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety"
|
version: "2.1.0-nullsafety.1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: characters
|
name: characters
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety.2"
|
version: "1.1.0-nullsafety.3"
|
||||||
charcode:
|
charcode:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: charcode
|
name: charcode
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety"
|
version: "1.2.0-nullsafety.1"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: clock
|
name: clock
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety"
|
version: "1.1.0-nullsafety.1"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: collection
|
name: collection
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0-nullsafety.2"
|
version: "1.15.0-nullsafety.3"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: fake_async
|
name: fake_async
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety"
|
version: "1.2.0-nullsafety.1"
|
||||||
ffi:
|
ffi:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -73,21 +73,21 @@ packages:
|
|||||||
name: matcher
|
name: matcher
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.10-nullsafety"
|
version: "0.12.10-nullsafety.1"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.2"
|
version: "1.3.0-nullsafety.3"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0-nullsafety"
|
version: "1.8.0-nullsafety.1"
|
||||||
sky_engine:
|
sky_engine:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -99,56 +99,56 @@ packages:
|
|||||||
name: source_span
|
name: source_span
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.0-nullsafety"
|
version: "1.8.0-nullsafety.2"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0-nullsafety"
|
version: "1.10.0-nullsafety.2"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_channel
|
name: stream_channel
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety"
|
version: "2.1.0-nullsafety.1"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: string_scanner
|
name: string_scanner
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0-nullsafety"
|
version: "1.1.0-nullsafety.1"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: term_glyph
|
name: term_glyph
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0-nullsafety"
|
version: "1.2.0-nullsafety.1"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.19-nullsafety"
|
version: "0.2.19-nullsafety.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: typed_data
|
name: typed_data
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0-nullsafety.2"
|
version: "1.3.0-nullsafety.3"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vector_math
|
name: vector_math
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0-nullsafety.2"
|
version: "2.1.0-nullsafety.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.10.0-0.0.dev <2.10.0"
|
dart: ">=2.10.0-110 <=2.11.0-181.0.dev"
|
||||||
flutter: ">=1.20.0 <2.0.0"
|
flutter: ">=1.20.0 <2.0.0"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
name: flutter_qjs
|
name: flutter_qjs
|
||||||
description: This plugin is a simple js engine for flutter using the `quickjs` project. Plugin currently supports all the platforms except web!
|
description: This plugin is a simple js engine for flutter using the `quickjs` project. Plugin currently supports all the platforms except web!
|
||||||
version: 0.1.1
|
version: 0.1.2
|
||||||
homepage: https://github.com/ekibun/flutter_qjs
|
homepage: https://github.com/ekibun/flutter_qjs
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
* @Author: ekibun
|
* @Author: ekibun
|
||||||
* @Date: 2020-09-06 13:02:46
|
* @Date: 2020-09-06 13:02:46
|
||||||
* @LastEditors: ekibun
|
* @LastEditors: ekibun
|
||||||
* @LastEditTime: 2020-10-02 17:27:52
|
* @LastEditTime: 2020-10-03 21:36:06
|
||||||
*/
|
*/
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
@@ -67,7 +67,7 @@ void main() async {
|
|||||||
(...args)=>`hello \${args}!`, a,
|
(...args)=>`hello \${args}!`, a,
|
||||||
0.1, true, false, 1, "world", module
|
0.1, true, false, 1, "world", module
|
||||||
]));
|
]));
|
||||||
""", "<eval>");
|
""", name: "<eval>");
|
||||||
print(value);
|
print(value);
|
||||||
print(await value[0]('world'));
|
print(await value[0]('world'));
|
||||||
qjs.close();
|
qjs.close();
|
||||||
|
Reference in New Issue
Block a user