@mentra/crust 3.3.0-dev.656 → 3.3.0-dev.658
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/android/build.gradle +15 -40
- package/android/src/main/java/com/mentra/crust/jsc/JSCRuntime.kt +13 -4
- package/android/src/test/java/com/mentra/crust/jsc/QuickJsLifecycleTest.kt +87 -0
- package/package.json +2 -2
- package/plugin/build/index.d.ts +2 -0
- package/plugin/build/index.js +2 -0
- package/plugin/build/withAndroid.js +39 -0
- package/android/quickjs-consumer-rules.pro +0 -6
- package/android/scripts/test-quickjs-lifecycle.py +0 -45
- package/android/src/main/cpp/quickjs/CMakeLists.txt +0 -20
- package/android/src/main/cpp/quickjs/LICENSE.quickjs-kt.txt +0 -201
- package/android/src/main/cpp/quickjs/README.md +0 -30
- package/android/src/main/cpp/quickjs/c-vector/LICENSE +0 -21
- package/android/src/main/cpp/quickjs/c-vector/cvector.h +0 -479
- package/android/src/main/cpp/quickjs/common/quickjs_version.c +0 -9
- package/android/src/main/cpp/quickjs/common/quickjs_version.h +0 -9
- package/android/src/main/cpp/quickjs/engine/LICENSE +0 -22
- package/android/src/main/cpp/quickjs/engine/VERSION +0 -1
- package/android/src/main/cpp/quickjs/engine/cutils.c +0 -631
- package/android/src/main/cpp/quickjs/engine/cutils.h +0 -347
- package/android/src/main/cpp/quickjs/engine/libbf.c +0 -8475
- package/android/src/main/cpp/quickjs/engine/libbf.h +0 -535
- package/android/src/main/cpp/quickjs/engine/libregexp-opcode.h +0 -57
- package/android/src/main/cpp/quickjs/engine/libregexp.c +0 -2501
- package/android/src/main/cpp/quickjs/engine/libregexp.h +0 -55
- package/android/src/main/cpp/quickjs/engine/libunicode-table.h +0 -4557
- package/android/src/main/cpp/quickjs/engine/libunicode.c +0 -1910
- package/android/src/main/cpp/quickjs/engine/libunicode.h +0 -182
- package/android/src/main/cpp/quickjs/engine/list.h +0 -99
- package/android/src/main/cpp/quickjs/engine/quickjs-atom.h +0 -273
- package/android/src/main/cpp/quickjs/engine/quickjs-opcode.h +0 -372
- package/android/src/main/cpp/quickjs/engine/quickjs.c +0 -55978
- package/android/src/main/cpp/quickjs/engine/quickjs.h +0 -1087
- package/android/src/main/cpp/quickjs/jni/binding_bridge.c +0 -488
- package/android/src/main/cpp/quickjs/jni/binding_bridge.h +0 -32
- package/android/src/main/cpp/quickjs/jni/exception_util.c +0 -64
- package/android/src/main/cpp/quickjs/jni/exception_util.h +0 -21
- package/android/src/main/cpp/quickjs/jni/jni_globals.c +0 -59
- package/android/src/main/cpp/quickjs/jni/jni_globals.h +0 -12
- package/android/src/main/cpp/quickjs/jni/jni_globals_generated.c +0 -855
- package/android/src/main/cpp/quickjs/jni/jni_globals_generated.h +0 -171
- package/android/src/main/cpp/quickjs/jni/js_value_util.c +0 -213
- package/android/src/main/cpp/quickjs/jni/js_value_util.h +0 -71
- package/android/src/main/cpp/quickjs/jni/log_util.h +0 -15
- package/android/src/main/cpp/quickjs/jni/mapping/jni_types_util.c +0 -27
- package/android/src/main/cpp/quickjs/jni/mapping/jni_types_util.h +0 -15
- package/android/src/main/cpp/quickjs/jni/mapping/jobject_to_js_value.c +0 -620
- package/android/src/main/cpp/quickjs/jni/mapping/jobject_to_js_value.h +0 -13
- package/android/src/main/cpp/quickjs/jni/mapping/js_value_to_jobject.c +0 -421
- package/android/src/main/cpp/quickjs/jni/mapping/js_value_to_jobject.h +0 -12
- package/android/src/main/cpp/quickjs/jni/promise_rejection_handler.c +0 -20
- package/android/src/main/cpp/quickjs/jni/promise_rejection_handler.h +0 -10
- package/android/src/main/cpp/quickjs/jni/quickjs_jni.c +0 -735
- package/android/src/main/cpp/quickjs/jni/quickjs_jni.h +0 -40
- package/android/src/testNative/QuickJsLifecycleTest.kt +0 -56
|
@@ -1,735 +0,0 @@
|
|
|
1
|
-
#include <string.h>
|
|
2
|
-
#include "jni.h"
|
|
3
|
-
#include "quickjs.h"
|
|
4
|
-
#include "quickjs_jni.h"
|
|
5
|
-
#include "jni_globals.h"
|
|
6
|
-
#include "jni_globals_generated.h"
|
|
7
|
-
#include "binding_bridge.h"
|
|
8
|
-
#include "exception_util.h"
|
|
9
|
-
#include "log_util.h"
|
|
10
|
-
#include "js_value_to_jobject.h"
|
|
11
|
-
#include "jobject_to_js_value.h"
|
|
12
|
-
#include "js_value_util.h"
|
|
13
|
-
#include "quickjs_version.h"
|
|
14
|
-
#include "promise_rejection_handler.h"
|
|
15
|
-
|
|
16
|
-
JSRuntime *runtime_from_ptr(JNIEnv *env, jlong ptr) {
|
|
17
|
-
if (ptr == 0) {
|
|
18
|
-
jni_throw_qjs_exception(env, "JS runtime is destroyed.");
|
|
19
|
-
return NULL;
|
|
20
|
-
}
|
|
21
|
-
return (JSRuntime *) ptr;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
JSContext *context_from_ptr(JNIEnv *env, jlong ptr) {
|
|
25
|
-
if (ptr == 0) {
|
|
26
|
-
jni_throw_qjs_exception(env, "JS context is destroyed.");
|
|
27
|
-
return NULL;
|
|
28
|
-
}
|
|
29
|
-
return (JSContext *) ptr;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
Globals *globals_from_ptr(JNIEnv *env, jlong ptr) {
|
|
33
|
-
if (ptr == 0) {
|
|
34
|
-
jni_throw_qjs_exception(env, "Globals is destroyed.");
|
|
35
|
-
return NULL;
|
|
36
|
-
}
|
|
37
|
-
return (Globals *) ptr;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Initialize global resources.
|
|
42
|
-
*/
|
|
43
|
-
JNIEXPORT jlong JNICALL Java_com_dokar_quickjs_QuickJs_initGlobals(JNIEnv *env,
|
|
44
|
-
jobject this,
|
|
45
|
-
jlong runtime_ptr) {
|
|
46
|
-
// Suppress lint: We will free it in releaseGlobals()
|
|
47
|
-
#pragma clang diagnostic push
|
|
48
|
-
#pragma ide diagnostic ignored "MemoryLeak"
|
|
49
|
-
Globals *globals = malloc(sizeof(Globals));
|
|
50
|
-
#pragma clang diagnostic pop
|
|
51
|
-
|
|
52
|
-
globals->managed_js_values = NULL;
|
|
53
|
-
globals->defined_js_objects = NULL;
|
|
54
|
-
globals->global_object_refs = NULL;
|
|
55
|
-
globals->created_js_functions = NULL;
|
|
56
|
-
globals->evaluate_result_promise = NULL;
|
|
57
|
-
|
|
58
|
-
pthread_mutex_init(&globals->js_mutex, NULL);
|
|
59
|
-
|
|
60
|
-
cache_java_vm(env);
|
|
61
|
-
|
|
62
|
-
JSRuntime *runtime = runtime_from_ptr(env, runtime_ptr);
|
|
63
|
-
jobject global_host_ref = (*env)->NewGlobalRef(env, this);
|
|
64
|
-
cvector_push_back(globals->global_object_refs, global_host_ref);
|
|
65
|
-
// Handle unhandled promise rejections
|
|
66
|
-
JS_SetHostPromiseRejectionTracker(runtime, promise_rejection_handler,
|
|
67
|
-
global_host_ref);
|
|
68
|
-
|
|
69
|
-
return (jlong) globals;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Create a new QuickJS JavaScript runtime.
|
|
74
|
-
*
|
|
75
|
-
* @return Runtime pointer.
|
|
76
|
-
*/
|
|
77
|
-
JNIEXPORT jlong JNICALL Java_com_dokar_quickjs_QuickJs_newRuntime(JNIEnv *env, jobject this) {
|
|
78
|
-
JSRuntime *runtime = JS_NewRuntime();
|
|
79
|
-
return (jlong) runtime;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Create a new QuickJS JavaScript Context from the given runtime pointer.
|
|
84
|
-
*
|
|
85
|
-
* @param runtime_ptr The runtime pointer.
|
|
86
|
-
* @return Context pointer.
|
|
87
|
-
*/
|
|
88
|
-
JNIEXPORT jlong JNICALL
|
|
89
|
-
Java_com_dokar_quickjs_QuickJs_newContext(JNIEnv *env, jobject this, jlong runtime_ptr) {
|
|
90
|
-
JSRuntime *runtime = runtime_from_ptr(env, runtime_ptr);
|
|
91
|
-
if (runtime == NULL) {
|
|
92
|
-
return 0;
|
|
93
|
-
}
|
|
94
|
-
JSContext *context = JS_NewContext(runtime);
|
|
95
|
-
return (jlong) context;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Release globals.
|
|
100
|
-
*/
|
|
101
|
-
JNIEXPORT void JNICALL
|
|
102
|
-
Java_com_dokar_quickjs_QuickJs_releaseGlobals(JNIEnv *env, jobject this, jlong context_ptr,
|
|
103
|
-
jlong globals_ptr) {
|
|
104
|
-
if (globals_ptr == 0) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
108
|
-
if (context == NULL) {
|
|
109
|
-
jni_throw_qjs_exception(env, "Context is already destroyed.");
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
114
|
-
|
|
115
|
-
cvector_vector_type(JSValue)created_js_functions = globals->created_js_functions;
|
|
116
|
-
if (created_js_functions != NULL) {
|
|
117
|
-
size_t size = cvector_size(created_js_functions);
|
|
118
|
-
for (uint32_t i = 0; i < size; i++) {
|
|
119
|
-
JSValue item = created_js_functions[i];
|
|
120
|
-
JS_FreeValue(context, item);
|
|
121
|
-
}
|
|
122
|
-
cvector_free(created_js_functions);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Check and free js values that are used by bindings
|
|
126
|
-
cvector_vector_type(JSValue)managed_js_values = globals->managed_js_values;
|
|
127
|
-
if (managed_js_values != NULL) {
|
|
128
|
-
size_t size = cvector_size(managed_js_values);
|
|
129
|
-
for (uint32_t i = 0; i < size; i++) {
|
|
130
|
-
JSValue value = managed_js_values[i];
|
|
131
|
-
JS_FreeValue(context, value);
|
|
132
|
-
}
|
|
133
|
-
cvector_free(managed_js_values);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (globals->defined_js_objects != NULL) {
|
|
137
|
-
cvector_free(globals->defined_js_objects);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Check and free global jni object refs
|
|
141
|
-
cvector_vector_type(jobject)global_object_refs = globals->global_object_refs;
|
|
142
|
-
if (global_object_refs != NULL) {
|
|
143
|
-
size_t size = cvector_size(global_object_refs);
|
|
144
|
-
for (uint32_t i = 0; i < size; i++) {
|
|
145
|
-
(*env)->DeleteGlobalRef(env, global_object_refs[i]);
|
|
146
|
-
}
|
|
147
|
-
cvector_free(global_object_refs);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (globals->evaluate_result_promise != NULL) {
|
|
151
|
-
// Free the result promise even if someone hasn't used it
|
|
152
|
-
JS_FreeValue(context, *(globals->evaluate_result_promise));
|
|
153
|
-
globals->evaluate_result_promise = NULL;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Destroy js mutex
|
|
157
|
-
pthread_mutex_destroy(&globals->js_mutex);
|
|
158
|
-
|
|
159
|
-
// Clear Env, class, methodId, fieldId
|
|
160
|
-
release_shared_jni_resources(env);
|
|
161
|
-
|
|
162
|
-
// Free the globals struct
|
|
163
|
-
free(globals);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Release JavaScript context.
|
|
168
|
-
*/
|
|
169
|
-
JNIEXPORT void JNICALL
|
|
170
|
-
Java_com_dokar_quickjs_QuickJs_releaseContext(JNIEnv *env, jobject this, jlong context_ptr) {
|
|
171
|
-
if (context_ptr == 0) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
175
|
-
JS_FreeContext(context);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Release JavaScript runtime.
|
|
180
|
-
*/
|
|
181
|
-
JNIEXPORT void JNICALL
|
|
182
|
-
Java_com_dokar_quickjs_QuickJs_releaseRuntime(JNIEnv *env, jobject this, jlong runtime_ptr) {
|
|
183
|
-
if (runtime_ptr == 0) {
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
JSRuntime *runtime = runtime_from_ptr(env, runtime_ptr);
|
|
187
|
-
JS_FreeRuntime(runtime);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Define an object to the 'parent'.
|
|
192
|
-
*/
|
|
193
|
-
JNIEXPORT jlong JNICALL
|
|
194
|
-
Java_com_dokar_quickjs_QuickJs_defineObject(JNIEnv *env, jobject this,
|
|
195
|
-
jlong globals_ptr,
|
|
196
|
-
jlong context_ptr,
|
|
197
|
-
jlong parent,
|
|
198
|
-
jstring name,
|
|
199
|
-
jobjectArray properties,
|
|
200
|
-
jobjectArray function_names) {
|
|
201
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
202
|
-
if (globals == NULL) {
|
|
203
|
-
return -1;
|
|
204
|
-
}
|
|
205
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
206
|
-
if (context == NULL) {
|
|
207
|
-
return -1;
|
|
208
|
-
}
|
|
209
|
-
int64_t parent_index = parent;
|
|
210
|
-
uint32_t defined_size = cvector_size(globals->defined_js_objects);
|
|
211
|
-
if (parent_index >= defined_size) {
|
|
212
|
-
jni_throw_qjs_exception(env, "Parent handle out of the bounds.");
|
|
213
|
-
return -1;
|
|
214
|
-
}
|
|
215
|
-
JSValue *parent_val = parent_index < 0 ? NULL : &globals->defined_js_objects[parent_index];
|
|
216
|
-
// The global js value index
|
|
217
|
-
int64_t handle = defined_size;
|
|
218
|
-
JSValue result = define_js_object(env,
|
|
219
|
-
context,
|
|
220
|
-
globals,
|
|
221
|
-
this,
|
|
222
|
-
parent_val,
|
|
223
|
-
handle,
|
|
224
|
-
name,
|
|
225
|
-
properties,
|
|
226
|
-
function_names);
|
|
227
|
-
// Insert at the target index
|
|
228
|
-
cvector_push_back(globals->defined_js_objects, result);
|
|
229
|
-
// Return the handle
|
|
230
|
-
return handle;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* Define an object to the 'parent'.
|
|
235
|
-
*/
|
|
236
|
-
JNIEXPORT void JNICALL
|
|
237
|
-
Java_com_dokar_quickjs_QuickJs_defineFunction(JNIEnv *env, jobject this,
|
|
238
|
-
jlong globals_ptr,
|
|
239
|
-
jlong context_ptr,
|
|
240
|
-
jstring name,
|
|
241
|
-
jboolean is_async) {
|
|
242
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
243
|
-
if (globals == NULL) {
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
247
|
-
if (context == NULL) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
define_js_function(env, context, globals, this, name, is_async);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* Run QuickJS GC.
|
|
255
|
-
*/
|
|
256
|
-
JNIEXPORT void JNICALL
|
|
257
|
-
Java_com_dokar_quickjs_QuickJs_gc(JNIEnv *env, jobject this, jlong runtime_ptr, jlong globals_ptr) {
|
|
258
|
-
JSRuntime *runtime = runtime_from_ptr(env, runtime_ptr);
|
|
259
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
260
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
261
|
-
JS_UpdateStackTop(runtime);
|
|
262
|
-
JS_RunGC(runtime);
|
|
263
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Get QuickJS version.
|
|
268
|
-
*/
|
|
269
|
-
JNIEXPORT jstring JNICALL
|
|
270
|
-
Java_com_dokar_quickjs_QuickJs_nativeGetVersion(JNIEnv *env, jobject this) {
|
|
271
|
-
return (*env)->NewStringUTF(env, quickjs_version());
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Set memory limit for the runtime.
|
|
276
|
-
*/
|
|
277
|
-
JNIEXPORT void JNICALL
|
|
278
|
-
Java_com_dokar_quickjs_QuickJs_setMemoryLimit(JNIEnv *env, jobject this, jlong runtime_ptr,
|
|
279
|
-
jlong globals_ptr,
|
|
280
|
-
jlong byte_count) {
|
|
281
|
-
JSRuntime *runtime = runtime_from_ptr(env, runtime_ptr);
|
|
282
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
283
|
-
|
|
284
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
285
|
-
|
|
286
|
-
JS_UpdateStackTop(runtime);
|
|
287
|
-
JS_SetMemoryLimit(runtime, byte_count);
|
|
288
|
-
|
|
289
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Set max stack size for the runtime.
|
|
294
|
-
*/
|
|
295
|
-
JNIEXPORT void JNICALL
|
|
296
|
-
Java_com_dokar_quickjs_QuickJs_setMaxStackSize(JNIEnv *env, jobject this, jlong runtime_ptr,
|
|
297
|
-
jlong globals_ptr,
|
|
298
|
-
jlong byte_count) {
|
|
299
|
-
JSRuntime *runtime = runtime_from_ptr(env, runtime_ptr);
|
|
300
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
301
|
-
|
|
302
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
303
|
-
|
|
304
|
-
JS_UpdateStackTop(runtime);
|
|
305
|
-
JS_SetMaxStackSize(runtime, byte_count);
|
|
306
|
-
|
|
307
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Get the runtime memory usage.
|
|
312
|
-
*/
|
|
313
|
-
JNIEXPORT jobject JNICALL
|
|
314
|
-
Java_com_dokar_quickjs_QuickJs_getMemoryUsage(JNIEnv *env, jobject this,
|
|
315
|
-
jlong runtime_ptr,
|
|
316
|
-
jlong globals_ptr) {
|
|
317
|
-
JSMemoryUsage memory_usage;
|
|
318
|
-
JSRuntime *runtime = runtime_from_ptr(env, runtime_ptr);
|
|
319
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
320
|
-
|
|
321
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
322
|
-
|
|
323
|
-
JS_UpdateStackTop(runtime);
|
|
324
|
-
JS_ComputeMemoryUsage(runtime, &memory_usage);
|
|
325
|
-
jclass cls = cls_memory_usage(env);
|
|
326
|
-
jobject usage = (*env)->NewObject(env, cls, method_memory_usage_init(env),
|
|
327
|
-
memory_usage.malloc_limit,
|
|
328
|
-
memory_usage.malloc_count,
|
|
329
|
-
memory_usage.malloc_size,
|
|
330
|
-
memory_usage.memory_used_count,
|
|
331
|
-
memory_usage.memory_used_size,
|
|
332
|
-
memory_usage.atom_count, memory_usage.atom_size,
|
|
333
|
-
memory_usage.str_count, memory_usage.str_size,
|
|
334
|
-
memory_usage.obj_count, memory_usage.obj_size,
|
|
335
|
-
memory_usage.prop_count, memory_usage.prop_size,
|
|
336
|
-
memory_usage.shape_count, memory_usage.shape_size,
|
|
337
|
-
memory_usage.js_func_count, memory_usage.js_func_size,
|
|
338
|
-
memory_usage.js_func_code_size,
|
|
339
|
-
memory_usage.js_func_pc2line_count,
|
|
340
|
-
memory_usage.js_func_pc2line_size,
|
|
341
|
-
memory_usage.c_func_count, memory_usage.array_count,
|
|
342
|
-
memory_usage.fast_array_count,
|
|
343
|
-
memory_usage.fast_array_elements,
|
|
344
|
-
memory_usage.binary_object_count,
|
|
345
|
-
memory_usage.binary_object_size);
|
|
346
|
-
|
|
347
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
348
|
-
|
|
349
|
-
return usage;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
jobject handle_eval_result(JNIEnv *env,
|
|
353
|
-
JSContext *context,
|
|
354
|
-
Globals *globals,
|
|
355
|
-
JSValue value,
|
|
356
|
-
int async) {
|
|
357
|
-
if (check_js_context_exception(env, context)) {
|
|
358
|
-
JS_FreeValue(context, value);
|
|
359
|
-
return NULL;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (JS_IsException(value)) {
|
|
363
|
-
// TODO: Handle this case
|
|
364
|
-
return NULL;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
int tag = JS_VALUE_GET_NORM_TAG(value);
|
|
368
|
-
int is_compiled_value = tag == JS_TAG_FUNCTION_BYTECODE || tag == JS_TAG_MODULE;
|
|
369
|
-
if (async && !is_compiled_value) {
|
|
370
|
-
// Ensure the result is a promise
|
|
371
|
-
if (!js_is_promise(context, value)) {
|
|
372
|
-
jni_throw_qjs_exception(env, "Require the async eval flag.");
|
|
373
|
-
JS_FreeValue(context, value);
|
|
374
|
-
return NULL;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (globals->evaluate_result_promise != NULL) {
|
|
378
|
-
// Free the unused result, if any
|
|
379
|
-
JS_FreeValue(context, *globals->evaluate_result_promise);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
// Save it to the globals
|
|
383
|
-
// Suppress the warning, we know that value will live long enough
|
|
384
|
-
globals->evaluate_result_promise = malloc(sizeof(JSValue));
|
|
385
|
-
*globals->evaluate_result_promise = value;
|
|
386
|
-
|
|
387
|
-
// This result should not be used
|
|
388
|
-
return NULL;
|
|
389
|
-
} else {
|
|
390
|
-
jobject result = js_value_to_jobject(env, context, value);
|
|
391
|
-
JS_FreeValue(context, value);
|
|
392
|
-
return result;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
jobject eval(JNIEnv *env, jlong context_ptr,
|
|
397
|
-
jlong globals_ptr,
|
|
398
|
-
jstring jfilename,
|
|
399
|
-
jstring jcode,
|
|
400
|
-
int eval_flags) {
|
|
401
|
-
const char *filename = (*env)->GetStringUTFChars(env, jfilename, NULL);
|
|
402
|
-
if (filename == NULL) {
|
|
403
|
-
jni_throw_qjs_exception(env, "Cannot read filename.");
|
|
404
|
-
return NULL;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
const char *code = (*env)->GetStringUTFChars(env, jcode, NULL);
|
|
408
|
-
if (code == NULL) {
|
|
409
|
-
jni_throw_qjs_exception(env, "Cannot read code.");
|
|
410
|
-
return NULL;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
414
|
-
if (context == NULL) {
|
|
415
|
-
return NULL;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
419
|
-
if (globals == NULL) {
|
|
420
|
-
return NULL;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
424
|
-
|
|
425
|
-
// Update the stack top pointer before running the code, otherwise, when calling
|
|
426
|
-
// this in a different thread rather than the initialization, unexpected stack overflow
|
|
427
|
-
// errors may occur.
|
|
428
|
-
JS_UpdateStackTop(JS_GetRuntime(context));
|
|
429
|
-
|
|
430
|
-
// Run code
|
|
431
|
-
JSValue value = JS_Eval(context, code, strlen(code), filename, eval_flags);
|
|
432
|
-
|
|
433
|
-
// Free strings
|
|
434
|
-
(*env)->ReleaseStringUTFChars(env, jfilename, filename);
|
|
435
|
-
(*env)->ReleaseStringUTFChars(env, jcode, code);
|
|
436
|
-
|
|
437
|
-
int async = (eval_flags & JS_EVAL_FLAG_ASYNC) != 0;
|
|
438
|
-
|
|
439
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
440
|
-
|
|
441
|
-
return handle_eval_result(env, context, globals, value, async);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
/**
|
|
445
|
-
* Compile JavaScript code to bytecode.
|
|
446
|
-
*/
|
|
447
|
-
JNIEXPORT jbyteArray JNICALL
|
|
448
|
-
Java_com_dokar_quickjs_QuickJs_compile(JNIEnv *env, jobject this, jlong context_ptr,
|
|
449
|
-
jlong globals_ptr,
|
|
450
|
-
jstring jfilename,
|
|
451
|
-
jstring jcode,
|
|
452
|
-
jboolean as_module) {
|
|
453
|
-
int eval_flags = JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_FLAG_ASYNC;
|
|
454
|
-
if (as_module) {
|
|
455
|
-
eval_flags |= JS_EVAL_TYPE_MODULE;
|
|
456
|
-
}
|
|
457
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
458
|
-
if (globals == NULL) {
|
|
459
|
-
return NULL;
|
|
460
|
-
}
|
|
461
|
-
return eval(env, context_ptr, globals_ptr, jfilename, jcode, eval_flags);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* Evaluate JavaScript code.
|
|
466
|
-
*/
|
|
467
|
-
JNIEXPORT jobject JNICALL
|
|
468
|
-
Java_com_dokar_quickjs_QuickJs_evaluate(JNIEnv *env,
|
|
469
|
-
jobject this,
|
|
470
|
-
jlong context_ptr,
|
|
471
|
-
jlong globals_ptr,
|
|
472
|
-
jstring jfilename,
|
|
473
|
-
jstring jcode,
|
|
474
|
-
jboolean as_module) {
|
|
475
|
-
int eval_flags = JS_EVAL_FLAG_ASYNC;
|
|
476
|
-
eval_flags |= as_module ? JS_EVAL_TYPE_MODULE : JS_EVAL_TYPE_GLOBAL;
|
|
477
|
-
return eval(env, context_ptr, globals_ptr, jfilename, jcode, eval_flags);
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Evaluate compiled bytecode.
|
|
482
|
-
*/
|
|
483
|
-
JNIEXPORT jobject JNICALL
|
|
484
|
-
Java_com_dokar_quickjs_QuickJs_evaluateBytecode(JNIEnv *env, jobject this, jlong context_ptr,
|
|
485
|
-
jlong globals_ptr,
|
|
486
|
-
jbyteArray jbuffer) {
|
|
487
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
488
|
-
if (context == NULL) {
|
|
489
|
-
return NULL;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
493
|
-
if (globals == NULL) {
|
|
494
|
-
return NULL;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
jlong buf_len = (*env)->GetArrayLength(env, jbuffer);
|
|
498
|
-
jbyte *buffer = (*env)->GetByteArrayElements(env, jbuffer, NULL);
|
|
499
|
-
|
|
500
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
501
|
-
|
|
502
|
-
JS_UpdateStackTop(JS_GetRuntime(context));
|
|
503
|
-
|
|
504
|
-
// Read buffer
|
|
505
|
-
JSValue bytecode = JS_ReadObject(context, (uint8_t *) buffer, buf_len, JS_READ_OBJ_BYTECODE);
|
|
506
|
-
if (JS_IsException(bytecode)) {
|
|
507
|
-
(*env)->ReleaseByteArrayElements(env, jbuffer, buffer, 0);
|
|
508
|
-
jni_throw_qjs_exception(env, "Cannot read buffer as bytecode.");
|
|
509
|
-
|
|
510
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
511
|
-
|
|
512
|
-
return NULL;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
// Eval
|
|
516
|
-
JSValue value = JS_EvalFunction(context, bytecode);
|
|
517
|
-
|
|
518
|
-
(*env)->ReleaseByteArrayElements(env, jbuffer, buffer, 0);
|
|
519
|
-
|
|
520
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
521
|
-
|
|
522
|
-
return handle_eval_result(env, context, globals, value, 1);
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Call a JavaScript function.
|
|
527
|
-
*
|
|
528
|
-
* Promise resolve() and reject() handles are passed as the first two parameters to onCallFunction.
|
|
529
|
-
* Other functions not currently supported.
|
|
530
|
-
*/
|
|
531
|
-
JNIEXPORT void JNICALL
|
|
532
|
-
Java_com_dokar_quickjs_QuickJs_invokeJsFunction(JNIEnv *env,
|
|
533
|
-
jobject this,
|
|
534
|
-
jlong context_ptr,
|
|
535
|
-
jlong globals_ptr,
|
|
536
|
-
jlong handle,
|
|
537
|
-
jobjectArray args) {
|
|
538
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
539
|
-
if (context == NULL) {
|
|
540
|
-
return;
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
if (handle < 0) {
|
|
544
|
-
jni_throw_qjs_exception(env, "Invalid handle: %ld", handle);
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
549
|
-
if (globals == NULL) {
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
if (globals->created_js_functions == NULL) {
|
|
554
|
-
jni_throw_qjs_exception(env, "Function not found.");
|
|
555
|
-
return;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
size_t size = cvector_size(globals->created_js_functions);
|
|
559
|
-
uint64_t index = (uint64_t) handle;
|
|
560
|
-
if (index >= size) {
|
|
561
|
-
jni_throw_qjs_exception(env, "Invalid handle: %ld", handle);
|
|
562
|
-
return;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
JSValue func = globals->created_js_functions[index];
|
|
566
|
-
if (!JS_IsFunction(context, func)) {
|
|
567
|
-
jni_throw_qjs_exception(env, "Can't get a valid function.");
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
572
|
-
|
|
573
|
-
JS_UpdateStackTop(JS_GetRuntime(context));
|
|
574
|
-
|
|
575
|
-
// Map args
|
|
576
|
-
int argc = args != NULL ? (*env)->GetArrayLength(env, args) : 0;
|
|
577
|
-
JSValue argv[argc];
|
|
578
|
-
for (int i = 0; i < argc; ++i) {
|
|
579
|
-
jobject element = (*env)->GetObjectArrayElement(env, args, i);
|
|
580
|
-
JSValue item = jobject_to_js_value(env, context, NULL, element);
|
|
581
|
-
if (JS_IsException(item)) {
|
|
582
|
-
// Mapping has failed, cleanup and return
|
|
583
|
-
for (int j = 0; j < i; ++j) {
|
|
584
|
-
JS_FreeValue(context, argv[j]);
|
|
585
|
-
}
|
|
586
|
-
(*env)->DeleteLocalRef(env, element);
|
|
587
|
-
|
|
588
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
589
|
-
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
argv[i] = item;
|
|
593
|
-
(*env)->DeleteLocalRef(env, element);
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
JSValue result = JS_Call(context, func, JS_NULL, argc, argv);
|
|
597
|
-
|
|
598
|
-
// Free arguments
|
|
599
|
-
for (int i = 0; i < argc; ++i) {
|
|
600
|
-
JS_FreeValue(context, argv[i]);
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// Do nothing with the result
|
|
604
|
-
JS_FreeValue(context, result);
|
|
605
|
-
|
|
606
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
/**
|
|
610
|
-
* Try to execute a pending JS job.
|
|
611
|
-
*
|
|
612
|
-
* @return true if executed, false if no job, or failed to execute.
|
|
613
|
-
*/
|
|
614
|
-
JNIEXPORT jboolean JNICALL
|
|
615
|
-
Java_com_dokar_quickjs_QuickJs_executePendingJob(JNIEnv *env,
|
|
616
|
-
jobject this,
|
|
617
|
-
jlong context_ptr,
|
|
618
|
-
jlong globals_ptr) {
|
|
619
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
620
|
-
if (context == NULL) {
|
|
621
|
-
return JNI_FALSE;
|
|
622
|
-
}
|
|
623
|
-
JSRuntime *runtime = JS_GetRuntime(context);
|
|
624
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
625
|
-
|
|
626
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
627
|
-
|
|
628
|
-
JS_UpdateStackTop(runtime);
|
|
629
|
-
if (check_js_context_exception(env, context)) {
|
|
630
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
631
|
-
|
|
632
|
-
return JNI_FALSE;
|
|
633
|
-
}
|
|
634
|
-
JSContext *ctx;
|
|
635
|
-
int ret = JS_ExecutePendingJob(runtime, &ctx);
|
|
636
|
-
if (ret == 0) {
|
|
637
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
638
|
-
|
|
639
|
-
// No jobs
|
|
640
|
-
return JNI_FALSE;
|
|
641
|
-
}
|
|
642
|
-
if (ret < 0) {
|
|
643
|
-
jni_throw_qjs_exception(env, "Failed to execute pending jobs.");
|
|
644
|
-
|
|
645
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
646
|
-
|
|
647
|
-
return JNI_FALSE;
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
651
|
-
|
|
652
|
-
return JNI_TRUE;
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
/**
|
|
656
|
-
* Try get result from the evaluate result promise. This function cannot be called multiple times.
|
|
657
|
-
*/
|
|
658
|
-
JNIEXPORT jobject JNICALL
|
|
659
|
-
Java_com_dokar_quickjs_QuickJs_getEvaluateResult(JNIEnv *env,
|
|
660
|
-
jobject this,
|
|
661
|
-
jlong context_ptr,
|
|
662
|
-
jlong globals_ptr) {
|
|
663
|
-
JSContext *context = context_from_ptr(env, context_ptr);
|
|
664
|
-
if (context == NULL) {
|
|
665
|
-
return NULL;
|
|
666
|
-
}
|
|
667
|
-
Globals *globals = globals_from_ptr(env, globals_ptr);
|
|
668
|
-
if (globals == NULL) {
|
|
669
|
-
return NULL;
|
|
670
|
-
}
|
|
671
|
-
if (globals->evaluate_result_promise == NULL) {
|
|
672
|
-
jni_throw_qjs_exception(env, "Result promise not found. Have you evaluated a script?");
|
|
673
|
-
return NULL;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
JSRuntime *runtime = JS_GetRuntime(context);
|
|
677
|
-
|
|
678
|
-
pthread_mutex_lock(&globals->js_mutex);
|
|
679
|
-
|
|
680
|
-
JS_UpdateStackTop(runtime);
|
|
681
|
-
|
|
682
|
-
JSValue result_promise = *globals->evaluate_result_promise;
|
|
683
|
-
if (!js_is_promise(context, result_promise)) {
|
|
684
|
-
JS_FreeValue(context, result_promise);
|
|
685
|
-
globals->evaluate_result_promise = NULL;
|
|
686
|
-
jni_throw_qjs_exception(env, "Invalid result promise object.");
|
|
687
|
-
|
|
688
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
689
|
-
|
|
690
|
-
return NULL;
|
|
691
|
-
}
|
|
692
|
-
JSPromiseStateEnum state = JS_PromiseState(context, result_promise);
|
|
693
|
-
jobject result;
|
|
694
|
-
if (state == JS_PROMISE_FULFILLED) {
|
|
695
|
-
JSValue js_result = js_promise_get_fulfilled_value(context, result_promise);
|
|
696
|
-
if (JS_IsException(js_result)) {
|
|
697
|
-
// Is it safe to ignore the exception? This happens when executing a compiled module.
|
|
698
|
-
result = NULL;
|
|
699
|
-
} else {
|
|
700
|
-
result = js_value_to_jobject(env, context, js_result);
|
|
701
|
-
}
|
|
702
|
-
JS_FreeValue(context, js_result);
|
|
703
|
-
} else if (state == JS_PROMISE_REJECTED) {
|
|
704
|
-
JSValue js_result = JS_PromiseResult(context, result_promise);
|
|
705
|
-
result = js_value_to_jobject(env, context, js_result);
|
|
706
|
-
|
|
707
|
-
// Avoid resetting jni exception to null
|
|
708
|
-
if (!JS_IsNull(js_result)) {
|
|
709
|
-
jthrowable error;
|
|
710
|
-
if ((*env)->IsInstanceOf(env, result, cls_throwable(env))) {
|
|
711
|
-
error = (jthrowable) result;
|
|
712
|
-
} else {
|
|
713
|
-
const char *str = JS_ToCString(context, js_result);
|
|
714
|
-
error = new_qjs_exception(env, str);
|
|
715
|
-
JS_FreeCString(context, str);
|
|
716
|
-
}
|
|
717
|
-
// Set exception
|
|
718
|
-
jmethodID set_exception_method = method_quick_js_set_eval_exception(env);
|
|
719
|
-
(*env)->CallVoidMethod(env, this, set_exception_method, error);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
JS_FreeValue(context, js_result);
|
|
723
|
-
} else {
|
|
724
|
-
// Code bug!
|
|
725
|
-
log("The result promise is still pending, it may be a bug in the bridge library.");
|
|
726
|
-
result = (*env)->NewStringUTF(env, "Promise { <state>: \"pending\" }");
|
|
727
|
-
}
|
|
728
|
-
// Clear the promise
|
|
729
|
-
JS_FreeValue(context, result_promise);
|
|
730
|
-
globals->evaluate_result_promise = NULL;
|
|
731
|
-
|
|
732
|
-
pthread_mutex_unlock(&globals->js_mutex);
|
|
733
|
-
|
|
734
|
-
return result;
|
|
735
|
-
}
|