forked from quickjs-ng/quickjs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathQjsBinaryCodeExecutor.h
More file actions
246 lines (207 loc) · 8.42 KB
/
Copy pathQjsBinaryCodeExecutor.h
File metadata and controls
246 lines (207 loc) · 8.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#pragma once
#include <cstdint>
#include <string>
#include <vector>
#include <functional>
// 前向声明,避免包含 quickjs 头文件,减少依赖
struct JSRuntime;
struct JSContext;
/**
* @brief 执行模式枚举
*/
enum class ExecutionMode {
BINARY, // 二进制字节码模式
JS // JavaScript 源代码模式
};
/**
* @brief 简易版 QuickJS 二进制代码执行器
*
* 这个类封装了 qjs_bc.c 的核心功能,提供最简化的接口。
* 支持加载 QuickJS 编译后的二进制字节码并执行,同时支持 Worker 线程。
*/
class QjsBinaryCodeExecutor {
public:
// 构造函数和析构函数
QjsBinaryCodeExecutor();
~QjsBinaryCodeExecutor();
/**
* @brief 设置调试模式
* @param enabled true=启用调试输出,false=禁用
*/
void setDebugMode(bool enabled) { debugEnabled_ = enabled; }
/**
* @brief 获取当前调试模式状态
* @return true=已启用,false=已禁用
*/
bool isDebugEnabled() const { return debugEnabled_; }
/**
* @brief 设置入口执行文件
* @param entryFile 入口文件路径,如 "main.js" 或 "main.bc"
*/
void setEntryFile(const std::string &entryFile) { entryFile_ = entryFile; }
/**
* @brief 获取当前入口执行文件
* @return 入口文件路径
*/
const std::string &getEntryFile() const { return entryFile_; }
/**
* @brief 设置执行模式
* @param mode 执行模式(BINARY=二进制字节码,SOURCE=JS源代码)
*/
void setExecutionMode(ExecutionMode mode) { executionMode_ = mode; }
/**
* @brief 获取当前执行模式
* @return 执行模式
*/
ExecutionMode getExecutionMode() const { return executionMode_; }
// 禁止拷贝,允许移动(简化资源管理)
QjsBinaryCodeExecutor(const QjsBinaryCodeExecutor &) = delete;
QjsBinaryCodeExecutor &operator=(const QjsBinaryCodeExecutor &) = delete;
QjsBinaryCodeExecutor(QjsBinaryCodeExecutor &&) noexcept;
QjsBinaryCodeExecutor &operator=(QjsBinaryCodeExecutor &&) noexcept;
/**
* @brief 从文件加载二进制模块
* @param filename 二进制文件路径
*
* 文件格式:每模块由三部分组成
* - 1字节:load_only 标志(0=入口模块,1=预加载模块)
* - 8字节:数据长度(uint64_t)
* - N字节:实际的字节码数据
*/
void loadModulesFromFile(const std::string &filename);
/**
* @brief 执行已加载的模块
* @return 0=成功,其他=失败
*
* 执行流程:
* 1. 创建 JSRuntime 运行时环境
* 2. 创建 JSContext 上下文
* 3. 预加载所有 load_only=1 的模块(供 Worker 使用)
* 4. 执行第一个 load_only=0 的入口模块
* 5. 进入事件循环,等待异步操作完成
*/
int execute();
/**
* @brief 设置错误回调函数
* @param callback 接收错误信息的回调
*
* 示例:
* executer.onError([](const std::string& err) {
* std::cerr << "执行错误: " << err << std::endl;
* });
*/
void onError(std::function<void(JSRuntime *, JSContext *, const std::string &)> callback) {
errorCallback_ = std::move(callback);
}
void onJsError(std::function<void(JSRuntime *, JSContext *, const std::string &, const std::string &,
const std::string &)> callback) {
jsErrorCallback_ = std::move(callback);
}
/**
* @brief 设置执行后回调函数
* @param callback 在代码执行完成、事件循环结束后调用的回调
*
* 该回调会在 execute() 方法中事件循环完成后触发,
* 允许用户在执行完成后进行清理、日志记录等操作。
*
* 示例:
* executer.afterExecute([](int exitCode) {
* std::cout << "执行完成,退出码: " << exitCode << std::endl;
* });
*/
void afterExecute(std::function<void(JSRuntime *, JSContext *)> callback) {
afterExecuteCallback_ = std::move(callback);
}
/**
* @brief 设置资源释放前回调函数
* @param callback 在析构函数释放资源前调用的回调
*
* 该回调会在析构函数中 JSContext 和 JSRuntime 释放之前触发,
* 允许用户在资源释放前进行最后的清理、状态保存等操作。
*
* 示例:
* executer.beforeRelease([]() {
* std::cout << "即将释放 QuickJS 资源" << std::endl;
* });
*/
void beforeRelease(std::function<void(JSRuntime *, JSContext *)> callback) {
beforeReleaseCallback_ = std::move(callback);
}
/**
* @brief 设置上下文创建后回调函数
* @param callback 在 JSContext 创建并预加载模块后调用的回调
*
* 该回调会在 createCustomContext() 方法中 JSContext 创建完成且预加载模块后触发,
* 允许用户在上下文创建后进行自定义初始化、注册全局对象等操作。
*
* 示例:
* executer.afterContextCreate([](JSContext* ctx) {
* std::cout << "上下文已创建,正在注册自定义函数..." << std::endl;
* // 注册自定义 C 函数到 JS 上下文
* });
*/
void afterContextCreate(std::function<void(JSRuntime *, JSContext *)> callback) {
afterContextCreateCallback_ = std::move(callback);
}
void afterRuntimeCreate(std::function<void(JSRuntime *)> callback) {
afterRuntimeCreateCallback_ = std::move(callback);
}
// 获取内部 JS 运行时和上下文(用于高级操作)
JSRuntime *runtime() const noexcept { return runtime_; }
JSContext *context() const noexcept { return context_; }
// 公开的静态回调函数,供 QuickJS 的 C API 调用
static JSContext *workerContextCallback(JSRuntime *rt, void *userdata);
/**
* @brief 设置 XOR 加密密钥
* @param secret 用于加密/解密字节码的密钥字符串
*
* 如果设置为空字符串,则不进行加解密操作。
* 密钥会在保存和加载二进制文件时自动应用。
*/
void setXorSecret(const std::string &secret) { xor_secret_ = secret; }
/**
* @brief 获取当前 XOR 加密密钥
* @return 当前设置的密钥字符串
*/
const std::string &getXorSecret() const { return xor_secret_; }
uint32_t getBytecodeVersion() const { return bc_version_; }
/**
* 主要方便安卓上打印日志
* @param callback
*/
void setLogCallback(std::function<void(const std::string&)> callback) {
logCallback_ = std::move(callback);
}
private:
// 模块数据结构
struct Module {
bool load_only; // 是否为预加载模块
std::vector<uint8_t> data; // 字节码数据
};
uint32_t bc_version_ = 0; // 字节码版本号
std::string xor_secret_; // XOR 加密密钥
std::vector<Module> modules_; // 存储所有加载的模块
JSRuntime *runtime_ = nullptr; // JS 运行时实例
JSContext *context_ = nullptr; // JS 上下文实例
std::function<void(JSRuntime *, JSContext *, const std::string &)> errorCallback_; // 错误回调
std::function<void(JSRuntime *, JSContext *, const std::string &, const std::string &, const std::string &)>
jsErrorCallback_; // 错误回调
std::function<void(JSRuntime *, JSContext *)> afterExecuteCallback_; // 执行完成后回调
std::function<void(JSRuntime *, JSContext *)> beforeReleaseCallback_; // 资源释放前回调
std::function<void(JSRuntime *, JSContext *)> afterContextCreateCallback_; // 上下文创建后回调
std::function<void(JSRuntime *)> afterRuntimeCreateCallback_; // 上下文创建后回调
bool debugEnabled_ = false; // 调试模式开关
std::string entryFile_ = "main.js"; // 入口执行文件路径,默认为 main.js
ExecutionMode executionMode_ = ExecutionMode::BINARY; // 执行模式,默认为二进制模式
// 创建自定义上下文(供 Worker 线程调用)
JSContext *createCustomContext(JSRuntime *rt) const;
// 获取异常堆栈信息
void getExceptionStack() const;
// 触发错误回调
void reportError(const std::string &msg) const;
// 调试输出辅助函数
void debugLog(const std::string &msg) const;
std::function<void(const std::string&)> logCallback_; // 日志回调
// 读取文件内容到字符串
std::string readFileToString(const std::string &filepath) const;
};