mirror of
https://github.com/wgh136/flutter_qjs.git
synced 2025-09-27 05:27:23 +00:00
init
This commit is contained in:
17
windows/.gitignore
vendored
Normal file
17
windows/.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
flutter/
|
||||
|
||||
# Visual Studio user-specific files.
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# Visual Studio build-related files.
|
||||
x64/
|
||||
x86/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
25
windows/CMakeLists.txt
Normal file
25
windows/CMakeLists.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
set(PROJECT_NAME "flutter_qjs")
|
||||
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
|
||||
|
||||
set(PLUGIN_NAME "${PROJECT_NAME}_plugin")
|
||||
|
||||
add_library(${PLUGIN_NAME} SHARED
|
||||
"${PLUGIN_NAME}.cpp"
|
||||
)
|
||||
apply_standard_settings(${PLUGIN_NAME})
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden)
|
||||
target_compile_definitions(${PLUGIN_NAME} PRIVATE FLUTTER_PLUGIN_IMPL)
|
||||
target_include_directories(${PLUGIN_NAME} INTERFACE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE flutter flutter_wrapper_plugin
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/quickjs/libquickjs64.a"
|
||||
)
|
||||
|
||||
# List of absolute paths to libraries that should be bundled with the plugin
|
||||
set(flutter_qjs_bundled_libraries
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/quickjs/libquickjs64.dll"
|
||||
PARENT_SCOPE
|
||||
)
|
123
windows/flutter_qjs_plugin.cpp
Normal file
123
windows/flutter_qjs_plugin.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "include/flutter_qjs/flutter_qjs_plugin.h"
|
||||
|
||||
// This must be included before many other Windows headers.
|
||||
#include <windows.h>
|
||||
|
||||
// For getPlatformVersion; remove unless needed for your plugin implementation.
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
#include <flutter/method_channel.h>
|
||||
#include <flutter/plugin_registrar_windows.h>
|
||||
#include <flutter/standard_method_codec.h>
|
||||
|
||||
#include "js_engine.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class FlutterQjsPlugin : public flutter::Plugin
|
||||
{
|
||||
public:
|
||||
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
|
||||
|
||||
FlutterQjsPlugin();
|
||||
|
||||
virtual ~FlutterQjsPlugin();
|
||||
|
||||
private:
|
||||
// Called when a method is called on this plugin's channel from Dart.
|
||||
void HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
};
|
||||
|
||||
std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel;
|
||||
|
||||
// static
|
||||
void FlutterQjsPlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarWindows *registrar)
|
||||
{
|
||||
channel =
|
||||
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
||||
registrar->messenger(), "soko.ekibun.flutter_qjs",
|
||||
&flutter::StandardMethodCodec::GetInstance());
|
||||
|
||||
auto plugin = std::make_unique<FlutterQjsPlugin>();
|
||||
|
||||
channel->SetMethodCallHandler(
|
||||
[plugin_pointer = plugin.get()](const auto &call, auto result) {
|
||||
plugin_pointer->HandleMethodCall(call, std::move(result));
|
||||
});
|
||||
|
||||
registrar->AddPlugin(std::move(plugin));
|
||||
}
|
||||
|
||||
FlutterQjsPlugin::FlutterQjsPlugin() {}
|
||||
|
||||
FlutterQjsPlugin::~FlutterQjsPlugin() {}
|
||||
|
||||
const flutter::EncodableValue &ValueOrNull(const flutter::EncodableMap &map, const char *key)
|
||||
{
|
||||
static flutter::EncodableValue null_value;
|
||||
auto it = map.find(flutter::EncodableValue(key));
|
||||
if (it == map.end())
|
||||
{
|
||||
return null_value;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
qjs::Engine *engine = nullptr;
|
||||
|
||||
void FlutterQjsPlugin::HandleMethodCall(
|
||||
const flutter::MethodCall<flutter::EncodableValue> &method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result)
|
||||
{
|
||||
// Replace "getPlatformVersion" check with your plugin's method.
|
||||
// See:
|
||||
// https://github.com/flutter/engine/tree/master/shell/platform/common/cpp/client_wrapper/include/flutter
|
||||
// and
|
||||
// https://github.com/flutter/engine/tree/master/shell/platform/glfw/client_wrapper/include/flutter
|
||||
// for the relevant Flutter APIs.
|
||||
if (method_call.method_name().compare("initEngine") == 0)
|
||||
{
|
||||
engine = new qjs::Engine(channel);
|
||||
flutter::EncodableValue response((long)engine);
|
||||
result->Success(&response);
|
||||
}
|
||||
else if (method_call.method_name().compare("evaluate") == 0)
|
||||
{
|
||||
flutter::EncodableMap args = *((flutter::EncodableMap *)method_call.arguments());
|
||||
std::string script = std::get<std::string>(ValueOrNull(args, "script"));
|
||||
std::string name = std::get<std::string>(ValueOrNull(args, "name"));
|
||||
auto presult = result.release();
|
||||
engine->commit(qjs::EngineTask{
|
||||
script, name,
|
||||
[presult](std::string resolve) {
|
||||
flutter::EncodableValue response(resolve);
|
||||
presult->Success(&response);
|
||||
},
|
||||
[presult](std::string reject) {
|
||||
presult->Error("FlutterJSException", reject);
|
||||
}});
|
||||
}
|
||||
else if (method_call.method_name().compare("close") == 0)
|
||||
{
|
||||
delete engine;
|
||||
result->Success();
|
||||
}
|
||||
else
|
||||
{
|
||||
result->NotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void FlutterQjsPluginRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar)
|
||||
{
|
||||
FlutterQjsPlugin::RegisterWithRegistrar(
|
||||
flutter::PluginRegistrarManager::GetInstance()
|
||||
->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
|
||||
}
|
23
windows/include/flutter_qjs/flutter_qjs_plugin.h
Normal file
23
windows/include/flutter_qjs/flutter_qjs_plugin.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef FLUTTER_PLUGIN_FLUTTER_JS_PLUGIN_H_
|
||||
#define FLUTTER_PLUGIN_FLUTTER_JS_PLUGIN_H_
|
||||
|
||||
#include <flutter_plugin_registrar.h>
|
||||
|
||||
#ifdef FLUTTER_PLUGIN_IMPL
|
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define FLUTTER_PLUGIN_EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
FLUTTER_PLUGIN_EXPORT void FlutterQjsPluginRegisterWithRegistrar(
|
||||
FlutterDesktopPluginRegistrarRef registrar);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // FLUTTER_PLUGIN_FLUTTER_JS_PLUGIN_H_
|
207
windows/js_dart_promise.hpp
Normal file
207
windows/js_dart_promise.hpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* @Description:
|
||||
* @Author: ekibun
|
||||
* @Date: 2020-08-07 13:55:52
|
||||
* @LastEditors: ekibun
|
||||
* @LastEditTime: 2020-08-08 16:54:23
|
||||
*/
|
||||
#pragma once
|
||||
#include "quickjs/quickjspp.hpp"
|
||||
#include "quickjs/quickjs/list.h"
|
||||
#include <flutter/method_result_functions.h>
|
||||
#include <future>
|
||||
|
||||
namespace qjs
|
||||
{
|
||||
static JSClassID js_dart_promise_class_id;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int count;
|
||||
JSValue *argv;
|
||||
} JSOSFutureArgv;
|
||||
|
||||
using JSFutureReturn = std::function<JSOSFutureArgv(JSContext *)>;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct list_head link;
|
||||
std::shared_future<JSFutureReturn> future;
|
||||
JSValue resolve;
|
||||
JSValue reject;
|
||||
} JSOSFuture;
|
||||
|
||||
typedef struct JSThreadState
|
||||
{
|
||||
struct list_head os_future; /* list of JSOSFuture.link */
|
||||
std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel;
|
||||
} JSThreadState;
|
||||
|
||||
static JSValue js_add_future(Value resolve, Value reject, std::shared_future<JSFutureReturn> future)
|
||||
{
|
||||
JSRuntime *rt = JS_GetRuntime(resolve.ctx);
|
||||
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
||||
JSValueConst jsResolve, jsReject;
|
||||
JSOSFuture *th;
|
||||
JSValue obj;
|
||||
|
||||
jsResolve = resolve.v;
|
||||
if (!JS_IsFunction(resolve.ctx, jsResolve))
|
||||
return JS_ThrowTypeError(resolve.ctx, "resolve not a function");
|
||||
jsReject = reject.v;
|
||||
if (!JS_IsFunction(reject.ctx, jsReject))
|
||||
return JS_ThrowTypeError(reject.ctx, "reject not a function");
|
||||
obj = JS_NewObjectClass(resolve.ctx, js_dart_promise_class_id);
|
||||
if (JS_IsException(obj))
|
||||
return obj;
|
||||
th = (JSOSFuture *)js_mallocz(resolve.ctx, sizeof(*th));
|
||||
if (!th)
|
||||
{
|
||||
JS_FreeValue(resolve.ctx, obj);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
th->future = future;
|
||||
th->resolve = JS_DupValue(resolve.ctx, jsResolve);
|
||||
th->reject = JS_DupValue(reject.ctx, jsReject);
|
||||
list_add_tail(&th->link, &ts->os_future);
|
||||
JS_SetOpaque(obj, th);
|
||||
return obj;
|
||||
}
|
||||
|
||||
JSValue js_dart_future(Value resolve, Value reject, std::string name, std::string args)
|
||||
{
|
||||
auto promise = new std::promise<JSFutureReturn>();
|
||||
JSRuntime *rt = JS_GetRuntime(resolve.ctx);
|
||||
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
||||
ts->channel->InvokeMethod(
|
||||
name,
|
||||
std::make_unique<flutter::EncodableValue>(args),
|
||||
std::make_unique<flutter::MethodResultFunctions<flutter::EncodableValue>>(
|
||||
(flutter::ResultHandlerSuccess<flutter::EncodableValue>)[promise](
|
||||
const flutter::EncodableValue *result) {
|
||||
promise->set_value((JSFutureReturn)[rep = std::get<std::string>(*result)](JSContext * ctx) {
|
||||
JSValue *ret = new JSValue{JS_NewString(ctx, rep.c_str())};
|
||||
return JSOSFutureArgv{1, ret};
|
||||
});
|
||||
},
|
||||
(flutter::ResultHandlerError<flutter::EncodableValue>)[promise](
|
||||
const std::string &error_code,
|
||||
const std::string &error_message,
|
||||
const flutter::EncodableValue *error_details) {
|
||||
promise->set_value((JSFutureReturn)[error_message](JSContext * ctx) {
|
||||
JSValue *ret = new JSValue{JS_NewString(ctx, error_message.c_str())};
|
||||
return JSOSFutureArgv{-1, ret};
|
||||
});
|
||||
},
|
||||
(flutter::ResultHandlerNotImplemented<flutter::EncodableValue>)[promise]() {
|
||||
promise->set_value((JSFutureReturn)[](JSContext * ctx) {
|
||||
JSValue *ret = new JSValue{JS_NewString(ctx, "NotImplemented")};
|
||||
return JSOSFutureArgv{-1, ret};
|
||||
});
|
||||
}));
|
||||
return js_add_future(resolve, reject, promise->get_future());
|
||||
}
|
||||
|
||||
static void unlink_future(JSRuntime *rt, JSOSFuture *th)
|
||||
{
|
||||
if (th->link.prev)
|
||||
{
|
||||
list_del(&th->link);
|
||||
th->link.prev = th->link.next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void free_future(JSRuntime *rt, JSOSFuture *th)
|
||||
{
|
||||
JS_FreeValueRT(rt, th->resolve);
|
||||
JS_FreeValueRT(rt, th->reject);
|
||||
js_free_rt(rt, th);
|
||||
}
|
||||
|
||||
void js_init_handlers(JSRuntime *rt, std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel)
|
||||
{
|
||||
JSThreadState *ts = (JSThreadState *)malloc(sizeof(*ts));
|
||||
if (!ts)
|
||||
{
|
||||
fprintf(stderr, "Could not allocate memory for the worker");
|
||||
exit(1);
|
||||
}
|
||||
memset(ts, 0, sizeof(*ts));
|
||||
init_list_head(&ts->os_future);
|
||||
ts->channel = channel;
|
||||
|
||||
JS_SetRuntimeOpaque(rt, ts);
|
||||
}
|
||||
|
||||
void js_free_handlers(JSRuntime *rt)
|
||||
{
|
||||
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
||||
struct list_head *el, *el1;
|
||||
|
||||
list_for_each_safe(el, el1, &ts->os_future)
|
||||
{
|
||||
JSOSFuture *th = list_entry(el, JSOSFuture, link);
|
||||
th->future.get();
|
||||
unlink_future(rt, th);
|
||||
free_future(rt, th);
|
||||
}
|
||||
ts->channel = nullptr;
|
||||
free(ts);
|
||||
JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
|
||||
}
|
||||
|
||||
static void call_handler(JSContext *ctx, JSValueConst func, int count, JSValue *argv)
|
||||
{
|
||||
JSValue ret, func1;
|
||||
/* 'func' might be destroyed when calling itself (if it frees the
|
||||
handler), so must take extra care */
|
||||
func1 = JS_DupValue(ctx, func);
|
||||
ret = JS_Call(ctx, func1, JS_UNDEFINED, count, argv);
|
||||
JS_FreeValue(ctx, func1);
|
||||
if (JS_IsException(ret))
|
||||
throw exception{};
|
||||
JS_FreeValue(ctx, ret);
|
||||
}
|
||||
|
||||
static int js_dart_poll(JSContext *ctx)
|
||||
{
|
||||
JSRuntime *rt = JS_GetRuntime(ctx);
|
||||
JSThreadState *ts = (JSThreadState *)JS_GetRuntimeOpaque(rt);
|
||||
struct list_head *el;
|
||||
|
||||
/* XXX: handle signals if useful */
|
||||
|
||||
if (list_empty(&ts->os_future))
|
||||
return -1; /* no more events */
|
||||
|
||||
/* XXX: only timers and basic console input are supported */
|
||||
if (!list_empty(&ts->os_future))
|
||||
{
|
||||
list_for_each(el, &ts->os_future)
|
||||
{
|
||||
JSOSFuture *th = list_entry(el, JSOSFuture, link);
|
||||
if (th->future._Is_ready())
|
||||
{
|
||||
JSOSFutureArgv argv = th->future.get()(ctx);
|
||||
JSValue resolve, reject;
|
||||
int64_t delay;
|
||||
/* the timer expired */
|
||||
resolve = th->resolve;
|
||||
th->resolve = JS_UNDEFINED;
|
||||
reject = th->reject;
|
||||
th->reject = JS_UNDEFINED;
|
||||
unlink_future(rt, th);
|
||||
free_future(rt, th);
|
||||
call_handler(ctx, argv.count < 0 ? reject : resolve, abs(argv.count), argv.argv);
|
||||
for (int i = 0; i < abs(argv.count); ++i)
|
||||
JS_FreeValue(ctx, argv.argv[i]);
|
||||
JS_FreeValue(ctx, resolve);
|
||||
JS_FreeValue(ctx, reject);
|
||||
delete argv.argv;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
} // namespace qjs
|
192
windows/js_engine.hpp
Normal file
192
windows/js_engine.hpp
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* @Description:
|
||||
* @Author: ekibun
|
||||
* @Date: 2020-08-08 10:30:59
|
||||
* @LastEditors: ekibun
|
||||
* @LastEditTime: 2020-08-08 17:05:22
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
|
||||
#include "js_dart_promise.hpp"
|
||||
#include "quickjs/quickjspp.hpp"
|
||||
|
||||
namespace qjs
|
||||
{
|
||||
struct EngineTask
|
||||
{
|
||||
std::string command;
|
||||
std::string name;
|
||||
std::function<void(std::string)> resolve;
|
||||
std::function<void(std::string)> reject;
|
||||
};
|
||||
|
||||
struct EngineTaskResolver
|
||||
{
|
||||
Value result;
|
||||
std::function<void(std::string)> resolve;
|
||||
std::function<void(std::string)> reject;
|
||||
};
|
||||
|
||||
std::string getStackTrack(Value exc)
|
||||
{
|
||||
std::string err = (std::string)exc;
|
||||
if ((bool)exc["stack"])
|
||||
err += "\n" + (std::string)exc["stack"];
|
||||
return err;
|
||||
}
|
||||
|
||||
class Engine
|
||||
{
|
||||
// 引擎线程
|
||||
std::thread thread;
|
||||
// 任务队列
|
||||
std::queue<EngineTask> tasks;
|
||||
// 同步
|
||||
std::mutex m_lock;
|
||||
// 是否关闭提交
|
||||
std::atomic<bool> stoped;
|
||||
|
||||
void handleException(qjs::Value exc)
|
||||
{
|
||||
std::cout << getStackTrack(exc) << std::endl;
|
||||
}
|
||||
|
||||
public:
|
||||
inline Engine(std::shared_ptr<flutter::MethodChannel<flutter::EncodableValue>> channel) : stoped{false}
|
||||
{
|
||||
thread = std::thread([this, channel] { // 工作线程函数
|
||||
// 创建运行环境
|
||||
Runtime rt;
|
||||
js_init_handlers(rt.rt, channel);
|
||||
Context ctx(rt);
|
||||
auto &module = ctx.addModule("__DartImpl");
|
||||
module.function<&js_dart_future>("__invoke");
|
||||
ctx.eval(
|
||||
R"xxx(
|
||||
import * as __DartImpl from "__DartImpl";
|
||||
globalThis.dart = (method, ...args) => new Promise((res, rej) =>
|
||||
__DartImpl.__invoke((v) => res(JSON.parse(v)), rej, method, JSON.stringify(args)));
|
||||
)xxx",
|
||||
"<dart>", JS_EVAL_TYPE_MODULE);
|
||||
std::vector<EngineTaskResolver> unresolvedTask;
|
||||
// 循环
|
||||
while (!this->stoped)
|
||||
{
|
||||
// 获取待执行的task
|
||||
EngineTask task;
|
||||
{ // 获取一个待执行的 task
|
||||
std::unique_lock<std::mutex> lock{this->m_lock}; // unique_lock 相比 lock_guard 的好处是:可以随时 unlock() 和 lock()
|
||||
if (!this->tasks.empty())
|
||||
{
|
||||
task = this->tasks.front(); // 取一个 task
|
||||
this->tasks.pop();
|
||||
}
|
||||
}
|
||||
// 执行task
|
||||
if (task.resolve)
|
||||
try
|
||||
{
|
||||
ctx.global()["__evalstr"] = JS_NewString(ctx.ctx, task.command.c_str());
|
||||
Value ret = ctx.eval(
|
||||
R"xxx(
|
||||
(() => {
|
||||
const __ret = Promise.resolve(eval(__evalstr))
|
||||
.then(v => {
|
||||
__ret.__value = v;
|
||||
__ret.__resolved = true;
|
||||
}).catch(e => {
|
||||
__ret.__error = e;
|
||||
__ret.__rejected = true;
|
||||
});
|
||||
return __ret;
|
||||
})()
|
||||
)xxx",
|
||||
task.name.c_str());
|
||||
unresolvedTask.emplace_back(EngineTaskResolver{ret, std::move(task.resolve), std::move(task.reject)});
|
||||
}
|
||||
catch (exception e)
|
||||
{
|
||||
task.reject(getStackTrack(ctx.getException()));
|
||||
}
|
||||
// 执行microtask
|
||||
JSContext *pctx;
|
||||
for (;;)
|
||||
{
|
||||
int err = JS_ExecutePendingJob(rt.rt, &pctx);
|
||||
if (err <= 0)
|
||||
{
|
||||
if (err < 0)
|
||||
std::cout << getStackTrack(ctx.getException()) << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO 检查promise状态
|
||||
for (auto it = unresolvedTask.begin(); it != unresolvedTask.end();)
|
||||
{
|
||||
bool finished = false;
|
||||
if (it->result["__resolved"])
|
||||
{
|
||||
it->resolve((std::string)it->result["__value"]);
|
||||
finished = true;
|
||||
};
|
||||
if (it->result["__rejected"])
|
||||
{
|
||||
it->reject(getStackTrack(it->result["__error"]));
|
||||
finished = true;
|
||||
};
|
||||
if (finished)
|
||||
it = unresolvedTask.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
// 检查dart交互
|
||||
bool idle = true;
|
||||
try
|
||||
{
|
||||
idle = js_dart_poll(ctx.ctx);
|
||||
}
|
||||
catch (exception e)
|
||||
{
|
||||
handleException(ctx.getException());
|
||||
}
|
||||
// 空闲时reject所有task
|
||||
if (idle && !JS_IsJobPending(rt.rt) && !unresolvedTask.empty())
|
||||
{
|
||||
for (EngineTaskResolver &task : unresolvedTask)
|
||||
{
|
||||
task.reject("Promise cannot resolve");
|
||||
}
|
||||
unresolvedTask.clear();
|
||||
}
|
||||
}
|
||||
js_free_handlers(rt.rt);
|
||||
});
|
||||
}
|
||||
inline ~Engine()
|
||||
{
|
||||
stoped.store(true);
|
||||
if (thread.joinable())
|
||||
thread.join(); // 等待任务结束, 前提:线程一定会执行完
|
||||
}
|
||||
|
||||
public:
|
||||
// 提交一个任务
|
||||
void commit(EngineTask task)
|
||||
{
|
||||
if (stoped.load()) // stop == true ??
|
||||
throw std::runtime_error("commit on stopped engine.");
|
||||
{ // 添加任务到队列
|
||||
std::lock_guard<std::mutex> lock{m_lock}; //对当前块的语句加锁 lock_guard 是 mutex 的 stack 封装类,构造的时候 lock(),析构的时候 unlock()
|
||||
tasks.emplace(task);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace qjs
|
195
windows/quickjs/libquickjs.def
Normal file
195
windows/quickjs/libquickjs.def
Normal file
@@ -0,0 +1,195 @@
|
||||
EXPORTS
|
||||
JS_AddIntrinsicAtomics
|
||||
JS_AddIntrinsicBaseObjects
|
||||
JS_AddIntrinsicBigDecimal
|
||||
JS_AddIntrinsicBigFloat
|
||||
JS_AddIntrinsicBigInt
|
||||
JS_AddIntrinsicDate
|
||||
JS_AddIntrinsicEval
|
||||
JS_AddIntrinsicJSON
|
||||
JS_AddIntrinsicMapSet
|
||||
JS_AddIntrinsicOperators
|
||||
JS_AddIntrinsicPromise
|
||||
JS_AddIntrinsicProxy
|
||||
JS_AddIntrinsicRegExp
|
||||
JS_AddIntrinsicRegExpCompiler
|
||||
JS_AddIntrinsicStringNormalize
|
||||
JS_AddIntrinsicTypedArrays
|
||||
JS_AddModuleExport
|
||||
JS_AddModuleExportList
|
||||
JS_AtomToCString
|
||||
JS_AtomToString
|
||||
JS_AtomToValue
|
||||
JS_Call
|
||||
JS_CallConstructor
|
||||
JS_CallConstructor2
|
||||
JS_ComputeMemoryUsage
|
||||
JS_DefineProperty
|
||||
JS_DefinePropertyGetSet
|
||||
JS_DefinePropertyValue
|
||||
JS_DefinePropertyValueInt64
|
||||
JS_DefinePropertyValueStr
|
||||
JS_DefinePropertyValueUint32
|
||||
JS_DefinePropertyValueValue
|
||||
JS_DeleteProperty
|
||||
JS_DeletePropertyInt64
|
||||
JS_DetachArrayBuffer
|
||||
JS_DetectModule
|
||||
JS_DumpMemoryUsage
|
||||
JS_DupAtom
|
||||
JS_DupContext
|
||||
JS_EnableBignumExt
|
||||
JS_EnqueueJob
|
||||
JS_Eval
|
||||
JS_EvalFunction
|
||||
JS_ExecutePendingJob
|
||||
JS_FreeAtom
|
||||
JS_FreeAtomRT
|
||||
JS_FreeCString
|
||||
JS_FreeContext
|
||||
JS_FreeRuntime
|
||||
JS_GetArrayBuffer
|
||||
JS_GetClassProto
|
||||
JS_GetContextOpaque
|
||||
JS_GetException
|
||||
JS_GetGlobalObject
|
||||
JS_GetImportMeta
|
||||
JS_GetModuleName
|
||||
JS_GetOpaque
|
||||
JS_GetOpaque2
|
||||
JS_GetOwnProperty
|
||||
JS_GetOwnPropertyNames
|
||||
JS_GetPropertyInternal
|
||||
JS_GetPropertyStr
|
||||
JS_GetPropertyUint32
|
||||
JS_GetPrototype
|
||||
JS_GetRuntime
|
||||
JS_GetRuntimeOpaque
|
||||
JS_GetTypedArrayBuffer
|
||||
JS_HasProperty
|
||||
JS_Invoke
|
||||
JS_IsArray
|
||||
JS_IsCFunction
|
||||
JS_IsConstructor
|
||||
JS_IsError
|
||||
JS_IsExtensible
|
||||
JS_IsFunction
|
||||
JS_IsInstanceOf
|
||||
JS_IsJobPending
|
||||
JS_IsLiveObject
|
||||
JS_IsRegisteredClass
|
||||
JS_IsUncatchableError
|
||||
JS_JSONStringify
|
||||
JS_MarkValue
|
||||
JS_NewArray
|
||||
JS_NewArrayBuffer
|
||||
JS_NewArrayBufferCopy
|
||||
JS_NewAtom
|
||||
JS_NewAtomLen
|
||||
JS_NewAtomString
|
||||
JS_NewAtomUInt32
|
||||
JS_NewBigInt64
|
||||
JS_NewBigInt64_1
|
||||
JS_NewBigUint64
|
||||
JS_NewCFunction2
|
||||
JS_NewCFunctionData
|
||||
JS_NewCModule
|
||||
JS_NewClass
|
||||
JS_NewClassID
|
||||
JS_NewContext
|
||||
JS_NewContextRaw
|
||||
JS_NewError
|
||||
JS_NewObject
|
||||
JS_NewObjectClass
|
||||
JS_NewObjectProto
|
||||
JS_NewObjectProtoClass
|
||||
JS_NewPromiseCapability
|
||||
JS_NewRuntime
|
||||
JS_NewRuntime2
|
||||
JS_NewString
|
||||
JS_NewStringLen
|
||||
JS_ParseJSON
|
||||
JS_ParseJSON2
|
||||
JS_PreventExtensions
|
||||
JS_ReadObject
|
||||
JS_ResetUncatchableError
|
||||
JS_ResolveModule
|
||||
JS_RunGC
|
||||
JS_SetCanBlock
|
||||
JS_SetClassProto
|
||||
JS_SetConstructor
|
||||
JS_SetConstructorBit
|
||||
JS_SetContextOpaque
|
||||
JS_SetGCThreshold
|
||||
JS_SetHostPromiseRejectionTracker
|
||||
JS_SetInterruptHandler
|
||||
JS_SetMaxStackSize
|
||||
JS_SetMemoryLimit
|
||||
JS_SetModuleExport
|
||||
JS_SetModuleExportList
|
||||
JS_SetModuleLoaderFunc
|
||||
JS_SetOpaque
|
||||
JS_SetPropertyFunctionList
|
||||
JS_SetPropertyInt64
|
||||
JS_SetPropertyInternal
|
||||
JS_SetPropertyStr
|
||||
JS_SetPropertyUint32
|
||||
JS_SetPrototype
|
||||
JS_SetRuntimeInfo
|
||||
JS_SetRuntimeOpaque
|
||||
JS_SetSharedArrayBufferFunctions
|
||||
JS_SetUncatchableError
|
||||
JS_Throw
|
||||
JS_ThrowInternalError
|
||||
JS_ThrowOutOfMemory
|
||||
JS_ThrowRangeError
|
||||
JS_ThrowReferenceError
|
||||
JS_ThrowSyntaxError
|
||||
JS_ThrowTypeError
|
||||
JS_ToBigInt64
|
||||
JS_ToBool
|
||||
JS_ToCStringLen2
|
||||
JS_ToFloat64
|
||||
JS_ToIndex
|
||||
JS_ToInt32
|
||||
JS_ToInt32Clamp
|
||||
JS_ToInt32Sat
|
||||
JS_ToInt64
|
||||
JS_ToInt64Clamp
|
||||
JS_ToInt64Ext
|
||||
JS_ToInt64Sat
|
||||
JS_ToPropertyKey
|
||||
JS_ToString
|
||||
JS_ToStringInternal
|
||||
JS_ValueToAtom
|
||||
JS_WriteObject
|
||||
JS_WriteObject2
|
||||
__JS_FreeValue
|
||||
__JS_FreeValueRT
|
||||
js_free
|
||||
js_free_rt
|
||||
js_init_module_os
|
||||
js_init_module_std
|
||||
js_load_file
|
||||
js_malloc
|
||||
js_malloc_rt
|
||||
js_malloc_usable_size
|
||||
js_malloc_usable_size_rt
|
||||
js_mallocz
|
||||
js_mallocz_rt
|
||||
js_module_loader
|
||||
js_module_set_import_meta
|
||||
js_parse_error
|
||||
js_realloc
|
||||
js_realloc2
|
||||
js_realloc_rt
|
||||
js_std_add_helpers
|
||||
js_std_dump_error
|
||||
js_std_eval_binary
|
||||
js_std_free_handlers
|
||||
js_std_init_handlers
|
||||
js_std_loop
|
||||
js_std_promise_rejection_tracker
|
||||
js_strdup
|
||||
js_string_codePointRange
|
||||
js_strndup
|
BIN
windows/quickjs/libquickjs32.a
Normal file
BIN
windows/quickjs/libquickjs32.a
Normal file
Binary file not shown.
BIN
windows/quickjs/libquickjs32.dll
Normal file
BIN
windows/quickjs/libquickjs32.dll
Normal file
Binary file not shown.
BIN
windows/quickjs/libquickjs64.a
Normal file
BIN
windows/quickjs/libquickjs64.a
Normal file
Binary file not shown.
BIN
windows/quickjs/libquickjs64.dll
Normal file
BIN
windows/quickjs/libquickjs64.dll
Normal file
Binary file not shown.
100
windows/quickjs/quickjs/list.h
Normal file
100
windows/quickjs/quickjs/list.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Linux klist like system
|
||||
*
|
||||
* Copyright (c) 2016-2017 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#ifndef NULL
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
struct list_head {
|
||||
struct list_head *prev;
|
||||
struct list_head *next;
|
||||
};
|
||||
|
||||
#define LIST_HEAD_INIT(el) { &(el), &(el) }
|
||||
|
||||
/* return the pointer of type 'type *' containing 'el' as field 'member' */
|
||||
#define list_entry(el, type, member) \
|
||||
((type *)((uint8_t *)(el) - offsetof(type, member)))
|
||||
|
||||
static inline void init_list_head(struct list_head *head)
|
||||
{
|
||||
head->prev = head;
|
||||
head->next = head;
|
||||
}
|
||||
|
||||
/* insert 'el' between 'prev' and 'next' */
|
||||
static inline void __list_add(struct list_head *el,
|
||||
struct list_head *prev, struct list_head *next)
|
||||
{
|
||||
prev->next = el;
|
||||
el->prev = prev;
|
||||
el->next = next;
|
||||
next->prev = el;
|
||||
}
|
||||
|
||||
/* add 'el' at the head of the list 'head' (= after element head) */
|
||||
static inline void list_add(struct list_head *el, struct list_head *head)
|
||||
{
|
||||
__list_add(el, head, head->next);
|
||||
}
|
||||
|
||||
/* add 'el' at the end of the list 'head' (= before element head) */
|
||||
static inline void list_add_tail(struct list_head *el, struct list_head *head)
|
||||
{
|
||||
__list_add(el, head->prev, head);
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *el)
|
||||
{
|
||||
struct list_head *prev, *next;
|
||||
prev = el->prev;
|
||||
next = el->next;
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
el->prev = NULL; /* fail safe */
|
||||
el->next = NULL; /* fail safe */
|
||||
}
|
||||
|
||||
static inline int list_empty(struct list_head *el)
|
||||
{
|
||||
return el->next == el;
|
||||
}
|
||||
|
||||
#define list_for_each(el, head) \
|
||||
for(el = (head)->next; el != (head); el = el->next)
|
||||
|
||||
#define list_for_each_safe(el, el1, head) \
|
||||
for(el = (head)->next, el1 = el->next; el != (head); \
|
||||
el = el1, el1 = el->next)
|
||||
|
||||
#define list_for_each_prev(el, head) \
|
||||
for(el = (head)->prev; el != (head); el = el->prev)
|
||||
|
||||
#define list_for_each_prev_safe(el, el1, head) \
|
||||
for(el = (head)->prev, el1 = el->prev; el != (head); \
|
||||
el = el1, el1 = el->prev)
|
||||
|
||||
#endif /* LIST_H */
|
58
windows/quickjs/quickjs/quickjs-libc.h
Normal file
58
windows/quickjs/quickjs/quickjs-libc.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* QuickJS C library
|
||||
*
|
||||
* Copyright (c) 2017-2018 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#ifndef QUICKJS_LIBC_H
|
||||
#define QUICKJS_LIBC_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "quickjs.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
|
||||
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
|
||||
void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
|
||||
void js_std_loop(JSContext *ctx);
|
||||
void js_std_init_handlers(JSRuntime *rt);
|
||||
void js_std_free_handlers(JSRuntime *rt);
|
||||
void js_std_dump_error(JSContext *ctx);
|
||||
uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
|
||||
int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
|
||||
JS_BOOL use_realpath, JS_BOOL is_main);
|
||||
JSModuleDef *js_module_loader(JSContext *ctx,
|
||||
const char *module_name, void *opaque);
|
||||
void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
||||
int flags);
|
||||
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
|
||||
JSValueConst reason,
|
||||
JS_BOOL is_handled, void *opaque);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" { */
|
||||
#endif
|
||||
|
||||
#endif /* QUICKJS_LIBC_H */
|
1031
windows/quickjs/quickjs/quickjs.h
Normal file
1031
windows/quickjs/quickjs/quickjs.h
Normal file
File diff suppressed because it is too large
Load Diff
1304
windows/quickjs/quickjspp.hpp
Normal file
1304
windows/quickjs/quickjspp.hpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user