@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.
Files changed (56) hide show
  1. package/README.md +7 -0
  2. package/android/build.gradle +15 -40
  3. package/android/src/main/java/com/mentra/crust/jsc/JSCRuntime.kt +13 -4
  4. package/android/src/test/java/com/mentra/crust/jsc/QuickJsLifecycleTest.kt +87 -0
  5. package/package.json +2 -2
  6. package/plugin/build/index.d.ts +2 -0
  7. package/plugin/build/index.js +2 -0
  8. package/plugin/build/withAndroid.js +39 -0
  9. package/android/quickjs-consumer-rules.pro +0 -6
  10. package/android/scripts/test-quickjs-lifecycle.py +0 -45
  11. package/android/src/main/cpp/quickjs/CMakeLists.txt +0 -20
  12. package/android/src/main/cpp/quickjs/LICENSE.quickjs-kt.txt +0 -201
  13. package/android/src/main/cpp/quickjs/README.md +0 -30
  14. package/android/src/main/cpp/quickjs/c-vector/LICENSE +0 -21
  15. package/android/src/main/cpp/quickjs/c-vector/cvector.h +0 -479
  16. package/android/src/main/cpp/quickjs/common/quickjs_version.c +0 -9
  17. package/android/src/main/cpp/quickjs/common/quickjs_version.h +0 -9
  18. package/android/src/main/cpp/quickjs/engine/LICENSE +0 -22
  19. package/android/src/main/cpp/quickjs/engine/VERSION +0 -1
  20. package/android/src/main/cpp/quickjs/engine/cutils.c +0 -631
  21. package/android/src/main/cpp/quickjs/engine/cutils.h +0 -347
  22. package/android/src/main/cpp/quickjs/engine/libbf.c +0 -8475
  23. package/android/src/main/cpp/quickjs/engine/libbf.h +0 -535
  24. package/android/src/main/cpp/quickjs/engine/libregexp-opcode.h +0 -57
  25. package/android/src/main/cpp/quickjs/engine/libregexp.c +0 -2501
  26. package/android/src/main/cpp/quickjs/engine/libregexp.h +0 -55
  27. package/android/src/main/cpp/quickjs/engine/libunicode-table.h +0 -4557
  28. package/android/src/main/cpp/quickjs/engine/libunicode.c +0 -1910
  29. package/android/src/main/cpp/quickjs/engine/libunicode.h +0 -182
  30. package/android/src/main/cpp/quickjs/engine/list.h +0 -99
  31. package/android/src/main/cpp/quickjs/engine/quickjs-atom.h +0 -273
  32. package/android/src/main/cpp/quickjs/engine/quickjs-opcode.h +0 -372
  33. package/android/src/main/cpp/quickjs/engine/quickjs.c +0 -55978
  34. package/android/src/main/cpp/quickjs/engine/quickjs.h +0 -1087
  35. package/android/src/main/cpp/quickjs/jni/binding_bridge.c +0 -488
  36. package/android/src/main/cpp/quickjs/jni/binding_bridge.h +0 -32
  37. package/android/src/main/cpp/quickjs/jni/exception_util.c +0 -64
  38. package/android/src/main/cpp/quickjs/jni/exception_util.h +0 -21
  39. package/android/src/main/cpp/quickjs/jni/jni_globals.c +0 -59
  40. package/android/src/main/cpp/quickjs/jni/jni_globals.h +0 -12
  41. package/android/src/main/cpp/quickjs/jni/jni_globals_generated.c +0 -855
  42. package/android/src/main/cpp/quickjs/jni/jni_globals_generated.h +0 -171
  43. package/android/src/main/cpp/quickjs/jni/js_value_util.c +0 -213
  44. package/android/src/main/cpp/quickjs/jni/js_value_util.h +0 -71
  45. package/android/src/main/cpp/quickjs/jni/log_util.h +0 -15
  46. package/android/src/main/cpp/quickjs/jni/mapping/jni_types_util.c +0 -27
  47. package/android/src/main/cpp/quickjs/jni/mapping/jni_types_util.h +0 -15
  48. package/android/src/main/cpp/quickjs/jni/mapping/jobject_to_js_value.c +0 -620
  49. package/android/src/main/cpp/quickjs/jni/mapping/jobject_to_js_value.h +0 -13
  50. package/android/src/main/cpp/quickjs/jni/mapping/js_value_to_jobject.c +0 -421
  51. package/android/src/main/cpp/quickjs/jni/mapping/js_value_to_jobject.h +0 -12
  52. package/android/src/main/cpp/quickjs/jni/promise_rejection_handler.c +0 -20
  53. package/android/src/main/cpp/quickjs/jni/promise_rejection_handler.h +0 -10
  54. package/android/src/main/cpp/quickjs/jni/quickjs_jni.c +0 -735
  55. package/android/src/main/cpp/quickjs/jni/quickjs_jni.h +0 -40
  56. 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
- }