quickjs 0.9.0 → 0.11.0
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.
- checksums.yaml +4 -4
- data/ext/quickjsrb/quickjs/cutils.c +2 -0
- data/ext/quickjsrb/quickjs/cutils.h +56 -0
- data/ext/quickjsrb/quickjs/dtoa.c +5 -11
- data/ext/quickjsrb/quickjs/libregexp-opcode.h +11 -1
- data/ext/quickjsrb/quickjs/libregexp.c +883 -132
- data/ext/quickjsrb/quickjs/libregexp.h +1 -0
- data/ext/quickjsrb/quickjs/libunicode-table.h +2211 -1619
- data/ext/quickjsrb/quickjs/libunicode.c +224 -11
- data/ext/quickjsrb/quickjs/libunicode.h +9 -5
- data/ext/quickjsrb/quickjs/qjs.c +48 -9
- data/ext/quickjsrb/quickjs/qjsc.c +216 -73
- data/ext/quickjsrb/quickjs/quickjs-atom.h +14 -0
- data/ext/quickjsrb/quickjs/quickjs-libc.c +460 -174
- data/ext/quickjsrb/quickjs/quickjs-libc.h +7 -1
- data/ext/quickjsrb/quickjs/quickjs-opcode.h +5 -4
- data/ext/quickjsrb/quickjs/quickjs.c +4503 -1614
- data/ext/quickjsrb/quickjs/quickjs.h +82 -15
- data/ext/quickjsrb/quickjs/run-test262.c +119 -33
- data/ext/quickjsrb/quickjs/unicode_gen.c +560 -6
- data/ext/quickjsrb/quickjs/unicode_gen_def.h +27 -0
- data/ext/quickjsrb/quickjsrb.c +1 -1
- data/lib/quickjs/version.rb +1 -1
- metadata +2 -2
@@ -64,10 +64,8 @@ typedef sig_t sighandler_t;
|
|
64
64
|
|
65
65
|
#endif
|
66
66
|
|
67
|
-
|
68
|
-
/* enable the os.Worker API. IT relies on POSIX threads */
|
67
|
+
/* enable the os.Worker API. It relies on POSIX threads */
|
69
68
|
#define USE_WORKER
|
70
|
-
#endif
|
71
69
|
|
72
70
|
#ifdef USE_WORKER
|
73
71
|
#include <pthread.h>
|
@@ -114,14 +112,22 @@ typedef struct {
|
|
114
112
|
size_t sab_tab_len;
|
115
113
|
} JSWorkerMessage;
|
116
114
|
|
115
|
+
typedef struct JSWaker {
|
116
|
+
#ifdef _WIN32
|
117
|
+
HANDLE handle;
|
118
|
+
#else
|
119
|
+
int read_fd;
|
120
|
+
int write_fd;
|
121
|
+
#endif
|
122
|
+
} JSWaker;
|
123
|
+
|
117
124
|
typedef struct {
|
118
125
|
int ref_count;
|
119
126
|
#ifdef USE_WORKER
|
120
127
|
pthread_mutex_t mutex;
|
121
128
|
#endif
|
122
129
|
struct list_head msg_queue; /* list of JSWorkerMessage.link */
|
123
|
-
|
124
|
-
int write_fd;
|
130
|
+
JSWaker waker;
|
125
131
|
} JSWorkerMessagePipe;
|
126
132
|
|
127
133
|
typedef struct {
|
@@ -130,11 +136,18 @@ typedef struct {
|
|
130
136
|
JSValue on_message_func;
|
131
137
|
} JSWorkerMessageHandler;
|
132
138
|
|
139
|
+
typedef struct {
|
140
|
+
struct list_head link;
|
141
|
+
JSValue promise;
|
142
|
+
JSValue reason;
|
143
|
+
} JSRejectedPromiseEntry;
|
144
|
+
|
133
145
|
typedef struct JSThreadState {
|
134
146
|
struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */
|
135
147
|
struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */
|
136
148
|
struct list_head os_timers; /* list of JSOSTimer.link */
|
137
149
|
struct list_head port_list; /* list of JSWorkerMessageHandler.link */
|
150
|
+
struct list_head rejected_promise_list; /* list of JSRejectedPromiseEntry.link */
|
138
151
|
int eval_script_recurse; /* only used in the main thread */
|
139
152
|
int next_timer_id; /* for setTimeout() */
|
140
153
|
/* not used in the main thread */
|
@@ -154,6 +167,7 @@ static BOOL my_isdigit(int c)
|
|
154
167
|
return (c >= '0' && c <= '9');
|
155
168
|
}
|
156
169
|
|
170
|
+
/* XXX: use 'o' and 'O' for object using JS_PrintValue() ? */
|
157
171
|
static JSValue js_printf_internal(JSContext *ctx,
|
158
172
|
int argc, JSValueConst *argv, FILE *fp)
|
159
173
|
{
|
@@ -577,17 +591,101 @@ int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
|
|
577
591
|
return 0;
|
578
592
|
}
|
579
593
|
|
580
|
-
|
581
|
-
|
594
|
+
static int json_module_init(JSContext *ctx, JSModuleDef *m)
|
595
|
+
{
|
596
|
+
JSValue val;
|
597
|
+
val = JS_GetModulePrivateValue(ctx, m);
|
598
|
+
JS_SetModuleExport(ctx, m, "default", val);
|
599
|
+
return 0;
|
600
|
+
}
|
601
|
+
|
602
|
+
static JSModuleDef *create_json_module(JSContext *ctx, const char *module_name, JSValue val)
|
582
603
|
{
|
583
604
|
JSModuleDef *m;
|
605
|
+
m = JS_NewCModule(ctx, module_name, json_module_init);
|
606
|
+
if (!m) {
|
607
|
+
JS_FreeValue(ctx, val);
|
608
|
+
return NULL;
|
609
|
+
}
|
610
|
+
/* only export the "default" symbol which will contain the JSON object */
|
611
|
+
JS_AddModuleExport(ctx, m, "default");
|
612
|
+
JS_SetModulePrivateValue(ctx, m, val);
|
613
|
+
return m;
|
614
|
+
}
|
584
615
|
|
616
|
+
/* in order to conform with the specification, only the keys should be
|
617
|
+
tested and not the associated values. */
|
618
|
+
int js_module_check_attributes(JSContext *ctx, void *opaque,
|
619
|
+
JSValueConst attributes)
|
620
|
+
{
|
621
|
+
JSPropertyEnum *tab;
|
622
|
+
uint32_t i, len;
|
623
|
+
int ret;
|
624
|
+
const char *cstr;
|
625
|
+
size_t cstr_len;
|
626
|
+
|
627
|
+
if (JS_GetOwnPropertyNames(ctx, &tab, &len, attributes, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK))
|
628
|
+
return -1;
|
629
|
+
ret = 0;
|
630
|
+
for(i = 0; i < len; i++) {
|
631
|
+
cstr = JS_AtomToCStringLen(ctx, &cstr_len, tab[i].atom);
|
632
|
+
if (!cstr) {
|
633
|
+
ret = -1;
|
634
|
+
break;
|
635
|
+
}
|
636
|
+
if (!(cstr_len == 4 && !memcmp(cstr, "type", cstr_len))) {
|
637
|
+
JS_ThrowTypeError(ctx, "import attribute '%s' is not supported", cstr);
|
638
|
+
ret = -1;
|
639
|
+
}
|
640
|
+
JS_FreeCString(ctx, cstr);
|
641
|
+
if (ret)
|
642
|
+
break;
|
643
|
+
}
|
644
|
+
JS_FreePropertyEnum(ctx, tab, len);
|
645
|
+
return ret;
|
646
|
+
}
|
647
|
+
|
648
|
+
/* return > 0 if the attributes indicate a JSON module */
|
649
|
+
int js_module_test_json(JSContext *ctx, JSValueConst attributes)
|
650
|
+
{
|
651
|
+
JSValue str;
|
652
|
+
const char *cstr;
|
653
|
+
size_t len;
|
654
|
+
BOOL res;
|
655
|
+
|
656
|
+
if (JS_IsUndefined(attributes))
|
657
|
+
return FALSE;
|
658
|
+
str = JS_GetPropertyStr(ctx, attributes, "type");
|
659
|
+
if (!JS_IsString(str))
|
660
|
+
return FALSE;
|
661
|
+
cstr = JS_ToCStringLen(ctx, &len, str);
|
662
|
+
JS_FreeValue(ctx, str);
|
663
|
+
if (!cstr)
|
664
|
+
return FALSE;
|
665
|
+
/* XXX: raise an error if unknown type ? */
|
666
|
+
if (len == 4 && !memcmp(cstr, "json", len)) {
|
667
|
+
res = 1;
|
668
|
+
} else if (len == 5 && !memcmp(cstr, "json5", len)) {
|
669
|
+
res = 2;
|
670
|
+
} else {
|
671
|
+
res = 0;
|
672
|
+
}
|
673
|
+
JS_FreeCString(ctx, cstr);
|
674
|
+
return res;
|
675
|
+
}
|
676
|
+
|
677
|
+
JSModuleDef *js_module_loader(JSContext *ctx,
|
678
|
+
const char *module_name, void *opaque,
|
679
|
+
JSValueConst attributes)
|
680
|
+
{
|
681
|
+
JSModuleDef *m;
|
682
|
+
int res;
|
683
|
+
|
585
684
|
if (has_suffix(module_name, ".so")) {
|
586
685
|
m = js_module_loader_so(ctx, module_name);
|
587
686
|
} else {
|
588
687
|
size_t buf_len;
|
589
688
|
uint8_t *buf;
|
590
|
-
JSValue func_val;
|
591
689
|
|
592
690
|
buf = js_load_file(ctx, &buf_len, module_name);
|
593
691
|
if (!buf) {
|
@@ -595,18 +693,36 @@ JSModuleDef *js_module_loader(JSContext *ctx,
|
|
595
693
|
module_name);
|
596
694
|
return NULL;
|
597
695
|
}
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
696
|
+
res = js_module_test_json(ctx, attributes);
|
697
|
+
if (has_suffix(module_name, ".json") || res > 0) {
|
698
|
+
/* compile as JSON or JSON5 depending on "type" */
|
699
|
+
JSValue val;
|
700
|
+
int flags;
|
701
|
+
if (res == 2)
|
702
|
+
flags = JS_PARSE_JSON_EXT;
|
703
|
+
else
|
704
|
+
flags = 0;
|
705
|
+
val = JS_ParseJSON2(ctx, (char *)buf, buf_len, module_name, flags);
|
706
|
+
js_free(ctx, buf);
|
707
|
+
if (JS_IsException(val))
|
708
|
+
return NULL;
|
709
|
+
m = create_json_module(ctx, module_name, val);
|
710
|
+
if (!m)
|
711
|
+
return NULL;
|
712
|
+
} else {
|
713
|
+
JSValue func_val;
|
714
|
+
/* compile the module */
|
715
|
+
func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
|
716
|
+
JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
|
717
|
+
js_free(ctx, buf);
|
718
|
+
if (JS_IsException(func_val))
|
719
|
+
return NULL;
|
720
|
+
/* XXX: could propagate the exception */
|
721
|
+
js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
|
722
|
+
/* the module is already referenced, so we must free it */
|
723
|
+
m = JS_VALUE_GET_PTR(func_val);
|
724
|
+
JS_FreeValue(ctx, func_val);
|
725
|
+
}
|
610
726
|
}
|
611
727
|
return m;
|
612
728
|
}
|
@@ -798,7 +914,7 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
|
|
798
914
|
/* convert the uncatchable "interrupted" error into a normal error
|
799
915
|
so that it can be caught by the REPL */
|
800
916
|
if (JS_IsException(ret))
|
801
|
-
|
917
|
+
JS_SetUncatchableException(ctx, FALSE);
|
802
918
|
}
|
803
919
|
return ret;
|
804
920
|
}
|
@@ -1077,6 +1193,19 @@ static JSValue js_std_file_printf(JSContext *ctx, JSValueConst this_val,
|
|
1077
1193
|
return js_printf_internal(ctx, argc, argv, f);
|
1078
1194
|
}
|
1079
1195
|
|
1196
|
+
static void js_print_value_write(void *opaque, const char *buf, size_t len)
|
1197
|
+
{
|
1198
|
+
FILE *fo = opaque;
|
1199
|
+
fwrite(buf, 1, len, fo);
|
1200
|
+
}
|
1201
|
+
|
1202
|
+
static JSValue js_std_file_printObject(JSContext *ctx, JSValueConst this_val,
|
1203
|
+
int argc, JSValueConst *argv)
|
1204
|
+
{
|
1205
|
+
JS_PrintValue(ctx, js_print_value_write, stdout, argv[0], NULL);
|
1206
|
+
return JS_UNDEFINED;
|
1207
|
+
}
|
1208
|
+
|
1080
1209
|
static JSValue js_std_file_flush(JSContext *ctx, JSValueConst this_val,
|
1081
1210
|
int argc, JSValueConst *argv)
|
1082
1211
|
{
|
@@ -1534,6 +1663,7 @@ static const JSCFunctionListEntry js_std_funcs[] = {
|
|
1534
1663
|
JS_PROP_INT32_DEF("SEEK_CUR", SEEK_CUR, JS_PROP_CONFIGURABLE ),
|
1535
1664
|
JS_PROP_INT32_DEF("SEEK_END", SEEK_END, JS_PROP_CONFIGURABLE ),
|
1536
1665
|
JS_OBJECT_DEF("Error", js_std_error_props, countof(js_std_error_props), JS_PROP_CONFIGURABLE),
|
1666
|
+
JS_CFUNC_DEF("__printObject", 1, js_std_file_printObject ),
|
1537
1667
|
};
|
1538
1668
|
|
1539
1669
|
static const JSCFunctionListEntry js_std_file_proto_funcs[] = {
|
@@ -2138,82 +2268,81 @@ static void call_handler(JSContext *ctx, JSValueConst func)
|
|
2138
2268
|
JS_FreeValue(ctx, ret);
|
2139
2269
|
}
|
2140
2270
|
|
2141
|
-
#
|
2271
|
+
#ifdef USE_WORKER
|
2142
2272
|
|
2143
|
-
|
2273
|
+
#ifdef _WIN32
|
2274
|
+
|
2275
|
+
static int js_waker_init(JSWaker *w)
|
2144
2276
|
{
|
2145
|
-
|
2146
|
-
|
2147
|
-
|
2148
|
-
int64_t cur_time, delay;
|
2149
|
-
JSOSRWHandler *rh;
|
2150
|
-
struct list_head *el;
|
2277
|
+
w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
|
2278
|
+
return w->handle ? 0 : -1;
|
2279
|
+
}
|
2151
2280
|
|
2152
|
-
|
2281
|
+
static void js_waker_signal(JSWaker *w)
|
2282
|
+
{
|
2283
|
+
SetEvent(w->handle);
|
2284
|
+
}
|
2153
2285
|
|
2154
|
-
|
2155
|
-
|
2286
|
+
static void js_waker_clear(JSWaker *w)
|
2287
|
+
{
|
2288
|
+
ResetEvent(w->handle);
|
2289
|
+
}
|
2156
2290
|
|
2157
|
-
|
2158
|
-
|
2159
|
-
|
2160
|
-
|
2161
|
-
|
2162
|
-
JSOSTimer *th = list_entry(el, JSOSTimer, link);
|
2163
|
-
delay = th->timeout - cur_time;
|
2164
|
-
if (delay <= 0) {
|
2165
|
-
JSValue func;
|
2166
|
-
/* the timer expired */
|
2167
|
-
func = th->func;
|
2168
|
-
th->func = JS_UNDEFINED;
|
2169
|
-
free_timer(rt, th);
|
2170
|
-
call_handler(ctx, func);
|
2171
|
-
JS_FreeValue(ctx, func);
|
2172
|
-
return 0;
|
2173
|
-
} else if (delay < min_delay) {
|
2174
|
-
min_delay = delay;
|
2175
|
-
}
|
2176
|
-
}
|
2177
|
-
} else {
|
2178
|
-
min_delay = -1;
|
2179
|
-
}
|
2291
|
+
static void js_waker_close(JSWaker *w)
|
2292
|
+
{
|
2293
|
+
CloseHandle(w->handle);
|
2294
|
+
w->handle = INVALID_HANDLE_VALUE;
|
2295
|
+
}
|
2180
2296
|
|
2181
|
-
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2297
|
+
#else // !_WIN32
|
2298
|
+
|
2299
|
+
static int js_waker_init(JSWaker *w)
|
2300
|
+
{
|
2301
|
+
int fds[2];
|
2302
|
+
|
2303
|
+
if (pipe(fds) < 0)
|
2304
|
+
return -1;
|
2305
|
+
w->read_fd = fds[0];
|
2306
|
+
w->write_fd = fds[1];
|
2307
|
+
return 0;
|
2308
|
+
}
|
2309
|
+
|
2310
|
+
static void js_waker_signal(JSWaker *w)
|
2311
|
+
{
|
2312
|
+
int ret;
|
2313
|
+
|
2314
|
+
for(;;) {
|
2315
|
+
ret = write(w->write_fd, "", 1);
|
2316
|
+
if (ret == 1)
|
2317
|
+
break;
|
2318
|
+
if (ret < 0 && (errno != EAGAIN || errno != EINTR))
|
2186
2319
|
break;
|
2187
|
-
}
|
2188
2320
|
}
|
2321
|
+
}
|
2189
2322
|
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
|
2199
|
-
if (
|
2200
|
-
|
2201
|
-
rh = list_entry(el, JSOSRWHandler, link);
|
2202
|
-
if (rh->fd == console_fd && !JS_IsNull(rh->rw_func[0])) {
|
2203
|
-
call_handler(ctx, rh->rw_func[0]);
|
2204
|
-
/* must stop because the list may have been modified */
|
2205
|
-
break;
|
2206
|
-
}
|
2207
|
-
}
|
2208
|
-
}
|
2209
|
-
} else {
|
2210
|
-
Sleep(min_delay);
|
2323
|
+
static void js_waker_clear(JSWaker *w)
|
2324
|
+
{
|
2325
|
+
uint8_t buf[16];
|
2326
|
+
int ret;
|
2327
|
+
|
2328
|
+
for(;;) {
|
2329
|
+
ret = read(w->read_fd, buf, sizeof(buf));
|
2330
|
+
if (ret >= 0)
|
2331
|
+
break;
|
2332
|
+
if (errno != EAGAIN && errno != EINTR)
|
2333
|
+
break;
|
2211
2334
|
}
|
2212
|
-
return 0;
|
2213
2335
|
}
|
2214
|
-
#else
|
2215
2336
|
|
2216
|
-
|
2337
|
+
static void js_waker_close(JSWaker *w)
|
2338
|
+
{
|
2339
|
+
close(w->read_fd);
|
2340
|
+
close(w->write_fd);
|
2341
|
+
w->read_fd = -1;
|
2342
|
+
w->write_fd = -1;
|
2343
|
+
}
|
2344
|
+
|
2345
|
+
#endif // _WIN32
|
2217
2346
|
|
2218
2347
|
static void js_free_message(JSWorkerMessage *msg);
|
2219
2348
|
|
@@ -2235,17 +2364,8 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
|
|
2235
2364
|
/* remove the message from the queue */
|
2236
2365
|
list_del(&msg->link);
|
2237
2366
|
|
2238
|
-
if (list_empty(&ps->msg_queue))
|
2239
|
-
|
2240
|
-
int ret;
|
2241
|
-
for(;;) {
|
2242
|
-
ret = read(ps->read_fd, buf, sizeof(buf));
|
2243
|
-
if (ret >= 0)
|
2244
|
-
break;
|
2245
|
-
if (errno != EAGAIN && errno != EINTR)
|
2246
|
-
break;
|
2247
|
-
}
|
2248
|
-
}
|
2367
|
+
if (list_empty(&ps->msg_queue))
|
2368
|
+
js_waker_clear(&ps->waker);
|
2249
2369
|
|
2250
2370
|
pthread_mutex_unlock(&ps->mutex);
|
2251
2371
|
|
@@ -2288,7 +2408,104 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
|
|
2288
2408
|
{
|
2289
2409
|
return 0;
|
2290
2410
|
}
|
2291
|
-
#endif
|
2411
|
+
#endif /* !USE_WORKER */
|
2412
|
+
|
2413
|
+
#if defined(_WIN32)
|
2414
|
+
|
2415
|
+
static int js_os_poll(JSContext *ctx)
|
2416
|
+
{
|
2417
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
2418
|
+
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
|
2419
|
+
int min_delay, count;
|
2420
|
+
int64_t cur_time, delay;
|
2421
|
+
JSOSRWHandler *rh;
|
2422
|
+
struct list_head *el;
|
2423
|
+
HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64
|
2424
|
+
|
2425
|
+
/* XXX: handle signals if useful */
|
2426
|
+
|
2427
|
+
if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
|
2428
|
+
list_empty(&ts->port_list)) {
|
2429
|
+
return -1; /* no more events */
|
2430
|
+
}
|
2431
|
+
|
2432
|
+
if (!list_empty(&ts->os_timers)) {
|
2433
|
+
cur_time = get_time_ms();
|
2434
|
+
min_delay = 10000;
|
2435
|
+
list_for_each(el, &ts->os_timers) {
|
2436
|
+
JSOSTimer *th = list_entry(el, JSOSTimer, link);
|
2437
|
+
delay = th->timeout - cur_time;
|
2438
|
+
if (delay <= 0) {
|
2439
|
+
JSValue func;
|
2440
|
+
/* the timer expired */
|
2441
|
+
func = th->func;
|
2442
|
+
th->func = JS_UNDEFINED;
|
2443
|
+
free_timer(rt, th);
|
2444
|
+
call_handler(ctx, func);
|
2445
|
+
JS_FreeValue(ctx, func);
|
2446
|
+
return 0;
|
2447
|
+
} else if (delay < min_delay) {
|
2448
|
+
min_delay = delay;
|
2449
|
+
}
|
2450
|
+
}
|
2451
|
+
} else {
|
2452
|
+
min_delay = -1;
|
2453
|
+
}
|
2454
|
+
|
2455
|
+
count = 0;
|
2456
|
+
list_for_each(el, &ts->os_rw_handlers) {
|
2457
|
+
rh = list_entry(el, JSOSRWHandler, link);
|
2458
|
+
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
|
2459
|
+
handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin
|
2460
|
+
if (count == (int)countof(handles))
|
2461
|
+
break;
|
2462
|
+
}
|
2463
|
+
}
|
2464
|
+
|
2465
|
+
list_for_each(el, &ts->port_list) {
|
2466
|
+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
2467
|
+
if (JS_IsNull(port->on_message_func))
|
2468
|
+
continue;
|
2469
|
+
handles[count++] = port->recv_pipe->waker.handle;
|
2470
|
+
if (count == (int)countof(handles))
|
2471
|
+
break;
|
2472
|
+
}
|
2473
|
+
|
2474
|
+
if (count > 0) {
|
2475
|
+
DWORD ret, timeout = INFINITE;
|
2476
|
+
if (min_delay != -1)
|
2477
|
+
timeout = min_delay;
|
2478
|
+
ret = WaitForMultipleObjects(count, handles, FALSE, timeout);
|
2479
|
+
|
2480
|
+
if (ret < count) {
|
2481
|
+
list_for_each(el, &ts->os_rw_handlers) {
|
2482
|
+
rh = list_entry(el, JSOSRWHandler, link);
|
2483
|
+
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
|
2484
|
+
call_handler(ctx, rh->rw_func[0]);
|
2485
|
+
/* must stop because the list may have been modified */
|
2486
|
+
goto done;
|
2487
|
+
}
|
2488
|
+
}
|
2489
|
+
|
2490
|
+
list_for_each(el, &ts->port_list) {
|
2491
|
+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
2492
|
+
if (!JS_IsNull(port->on_message_func)) {
|
2493
|
+
JSWorkerMessagePipe *ps = port->recv_pipe;
|
2494
|
+
if (ps->waker.handle == handles[ret]) {
|
2495
|
+
if (handle_posted_message(rt, ctx, port))
|
2496
|
+
goto done;
|
2497
|
+
}
|
2498
|
+
}
|
2499
|
+
}
|
2500
|
+
}
|
2501
|
+
} else {
|
2502
|
+
Sleep(min_delay);
|
2503
|
+
}
|
2504
|
+
done:
|
2505
|
+
return 0;
|
2506
|
+
}
|
2507
|
+
|
2508
|
+
#else
|
2292
2509
|
|
2293
2510
|
static int js_os_poll(JSContext *ctx)
|
2294
2511
|
{
|
@@ -2364,8 +2581,8 @@ static int js_os_poll(JSContext *ctx)
|
|
2364
2581
|
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
2365
2582
|
if (!JS_IsNull(port->on_message_func)) {
|
2366
2583
|
JSWorkerMessagePipe *ps = port->recv_pipe;
|
2367
|
-
fd_max = max_int(fd_max, ps->read_fd);
|
2368
|
-
FD_SET(ps->read_fd, &rfds);
|
2584
|
+
fd_max = max_int(fd_max, ps->waker.read_fd);
|
2585
|
+
FD_SET(ps->waker.read_fd, &rfds);
|
2369
2586
|
}
|
2370
2587
|
}
|
2371
2588
|
|
@@ -2391,14 +2608,14 @@ static int js_os_poll(JSContext *ctx)
|
|
2391
2608
|
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
2392
2609
|
if (!JS_IsNull(port->on_message_func)) {
|
2393
2610
|
JSWorkerMessagePipe *ps = port->recv_pipe;
|
2394
|
-
if (FD_ISSET(ps->read_fd, &rfds)) {
|
2611
|
+
if (FD_ISSET(ps->waker.read_fd, &rfds)) {
|
2395
2612
|
if (handle_posted_message(rt, ctx, port))
|
2396
2613
|
goto done;
|
2397
2614
|
}
|
2398
2615
|
}
|
2399
2616
|
}
|
2400
2617
|
}
|
2401
|
-
|
2618
|
+
done:
|
2402
2619
|
return 0;
|
2403
2620
|
}
|
2404
2621
|
#endif /* !_WIN32 */
|
@@ -2823,9 +3040,7 @@ static char **build_envp(JSContext *ctx, JSValueConst obj)
|
|
2823
3040
|
JS_FreeCString(ctx, str);
|
2824
3041
|
}
|
2825
3042
|
done:
|
2826
|
-
|
2827
|
-
JS_FreeAtom(ctx, tab[i].atom);
|
2828
|
-
js_free(ctx, tab);
|
3043
|
+
JS_FreePropertyEnum(ctx, tab, len);
|
2829
3044
|
return envp;
|
2830
3045
|
fail:
|
2831
3046
|
if (envp) {
|
@@ -3220,6 +3435,7 @@ typedef struct {
|
|
3220
3435
|
char *filename; /* module filename */
|
3221
3436
|
char *basename; /* module base name */
|
3222
3437
|
JSWorkerMessagePipe *recv_pipe, *send_pipe;
|
3438
|
+
int strip_flags;
|
3223
3439
|
} WorkerFuncArgs;
|
3224
3440
|
|
3225
3441
|
typedef struct {
|
@@ -3268,22 +3484,17 @@ static void js_sab_dup(void *opaque, void *ptr)
|
|
3268
3484
|
static JSWorkerMessagePipe *js_new_message_pipe(void)
|
3269
3485
|
{
|
3270
3486
|
JSWorkerMessagePipe *ps;
|
3271
|
-
int pipe_fds[2];
|
3272
|
-
|
3273
|
-
if (pipe(pipe_fds) < 0)
|
3274
|
-
return NULL;
|
3275
3487
|
|
3276
3488
|
ps = malloc(sizeof(*ps));
|
3277
|
-
if (!ps)
|
3278
|
-
|
3279
|
-
|
3489
|
+
if (!ps)
|
3490
|
+
return NULL;
|
3491
|
+
if (js_waker_init(&ps->waker)) {
|
3492
|
+
free(ps);
|
3280
3493
|
return NULL;
|
3281
3494
|
}
|
3282
3495
|
ps->ref_count = 1;
|
3283
3496
|
init_list_head(&ps->msg_queue);
|
3284
3497
|
pthread_mutex_init(&ps->mutex, NULL);
|
3285
|
-
ps->read_fd = pipe_fds[0];
|
3286
|
-
ps->write_fd = pipe_fds[1];
|
3287
3498
|
return ps;
|
3288
3499
|
}
|
3289
3500
|
|
@@ -3322,8 +3533,7 @@ static void js_free_message_pipe(JSWorkerMessagePipe *ps)
|
|
3322
3533
|
js_free_message(msg);
|
3323
3534
|
}
|
3324
3535
|
pthread_mutex_destroy(&ps->mutex);
|
3325
|
-
|
3326
|
-
close(ps->write_fd);
|
3536
|
+
js_waker_close(&ps->waker);
|
3327
3537
|
free(ps);
|
3328
3538
|
}
|
3329
3539
|
}
|
@@ -3367,9 +3577,10 @@ static void *worker_func(void *opaque)
|
|
3367
3577
|
fprintf(stderr, "JS_NewRuntime failure");
|
3368
3578
|
exit(1);
|
3369
3579
|
}
|
3580
|
+
JS_SetStripInfo(rt, args->strip_flags);
|
3370
3581
|
js_std_init_handlers(rt);
|
3371
3582
|
|
3372
|
-
|
3583
|
+
JS_SetModuleLoaderFunc2(rt, NULL, js_module_loader, js_module_check_attributes, NULL);
|
3373
3584
|
|
3374
3585
|
/* set the pipe to communicate with the parent */
|
3375
3586
|
ts = JS_GetRuntimeOpaque(rt);
|
@@ -3484,6 +3695,8 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
|
|
3484
3695
|
if (!args->send_pipe)
|
3485
3696
|
goto oom_fail;
|
3486
3697
|
|
3698
|
+
args->strip_flags = JS_GetStripInfo(rt);
|
3699
|
+
|
3487
3700
|
obj = js_worker_ctor_internal(ctx, new_target,
|
3488
3701
|
args->send_pipe, args->recv_pipe);
|
3489
3702
|
if (JS_IsException(obj))
|
@@ -3568,17 +3781,8 @@ static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
|
|
3568
3781
|
ps = worker->send_pipe;
|
3569
3782
|
pthread_mutex_lock(&ps->mutex);
|
3570
3783
|
/* indicate that data is present */
|
3571
|
-
if (list_empty(&ps->msg_queue))
|
3572
|
-
|
3573
|
-
int ret;
|
3574
|
-
for(;;) {
|
3575
|
-
ret = write(ps->write_fd, &ch, 1);
|
3576
|
-
if (ret == 1)
|
3577
|
-
break;
|
3578
|
-
if (ret < 0 && (errno != EAGAIN || errno != EINTR))
|
3579
|
-
break;
|
3580
|
-
}
|
3581
|
-
}
|
3784
|
+
if (list_empty(&ps->msg_queue))
|
3785
|
+
js_waker_signal(&ps->waker);
|
3582
3786
|
list_add_tail(&msg->link, &ps->msg_queue);
|
3583
3787
|
pthread_mutex_unlock(&ps->mutex);
|
3584
3788
|
return JS_UNDEFINED;
|
@@ -3809,25 +4013,40 @@ static JSValue js_print(JSContext *ctx, JSValueConst this_val,
|
|
3809
4013
|
int argc, JSValueConst *argv)
|
3810
4014
|
{
|
3811
4015
|
int i;
|
3812
|
-
|
3813
|
-
|
3814
|
-
|
4016
|
+
JSValueConst v;
|
4017
|
+
|
3815
4018
|
for(i = 0; i < argc; i++) {
|
3816
4019
|
if (i != 0)
|
3817
4020
|
putchar(' ');
|
3818
|
-
|
3819
|
-
if (
|
3820
|
-
|
3821
|
-
|
3822
|
-
|
4021
|
+
v = argv[i];
|
4022
|
+
if (JS_IsString(v)) {
|
4023
|
+
const char *str;
|
4024
|
+
size_t len;
|
4025
|
+
str = JS_ToCStringLen(ctx, &len, v);
|
4026
|
+
if (!str)
|
4027
|
+
return JS_EXCEPTION;
|
4028
|
+
fwrite(str, 1, len, stdout);
|
4029
|
+
JS_FreeCString(ctx, str);
|
4030
|
+
} else {
|
4031
|
+
JS_PrintValue(ctx, js_print_value_write, stdout, v, NULL);
|
4032
|
+
}
|
3823
4033
|
}
|
3824
4034
|
putchar('\n');
|
3825
4035
|
return JS_UNDEFINED;
|
3826
4036
|
}
|
3827
4037
|
|
4038
|
+
static JSValue js_console_log(JSContext *ctx, JSValueConst this_val,
|
4039
|
+
int argc, JSValueConst *argv)
|
4040
|
+
{
|
4041
|
+
JSValue ret;
|
4042
|
+
ret = js_print(ctx, this_val, argc, argv);
|
4043
|
+
fflush(stdout);
|
4044
|
+
return ret;
|
4045
|
+
}
|
4046
|
+
|
3828
4047
|
void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
|
3829
4048
|
{
|
3830
|
-
JSValue global_obj, console, args;
|
4049
|
+
JSValue global_obj, console, args, performance;
|
3831
4050
|
int i;
|
3832
4051
|
|
3833
4052
|
/* XXX: should these global definitions be enumerable? */
|
@@ -3835,9 +4054,14 @@ void js_std_add_helpers(JSContext *ctx, int argc, char **argv)
|
|
3835
4054
|
|
3836
4055
|
console = JS_NewObject(ctx);
|
3837
4056
|
JS_SetPropertyStr(ctx, console, "log",
|
3838
|
-
JS_NewCFunction(ctx,
|
4057
|
+
JS_NewCFunction(ctx, js_console_log, "log", 1));
|
3839
4058
|
JS_SetPropertyStr(ctx, global_obj, "console", console);
|
3840
4059
|
|
4060
|
+
performance = JS_NewObject(ctx);
|
4061
|
+
JS_SetPropertyStr(ctx, performance, "now",
|
4062
|
+
JS_NewCFunction(ctx, js_os_now, "now", 0));
|
4063
|
+
JS_SetPropertyStr(ctx, global_obj, "performance", performance);
|
4064
|
+
|
3841
4065
|
/* same methods as the mozilla JS shell */
|
3842
4066
|
if (argc >= 0) {
|
3843
4067
|
args = JS_NewArray(ctx);
|
@@ -3869,6 +4093,7 @@ void js_std_init_handlers(JSRuntime *rt)
|
|
3869
4093
|
init_list_head(&ts->os_signal_handlers);
|
3870
4094
|
init_list_head(&ts->os_timers);
|
3871
4095
|
init_list_head(&ts->port_list);
|
4096
|
+
init_list_head(&ts->rejected_promise_list);
|
3872
4097
|
ts->next_timer_id = 1;
|
3873
4098
|
|
3874
4099
|
JS_SetRuntimeOpaque(rt, ts);
|
@@ -3906,6 +4131,13 @@ void js_std_free_handlers(JSRuntime *rt)
|
|
3906
4131
|
free_timer(rt, th);
|
3907
4132
|
}
|
3908
4133
|
|
4134
|
+
list_for_each_safe(el, el1, &ts->rejected_promise_list) {
|
4135
|
+
JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
|
4136
|
+
JS_FreeValueRT(rt, rp->promise);
|
4137
|
+
JS_FreeValueRT(rt, rp->reason);
|
4138
|
+
free(rp);
|
4139
|
+
}
|
4140
|
+
|
3909
4141
|
#ifdef USE_WORKER
|
3910
4142
|
/* XXX: free port_list ? */
|
3911
4143
|
js_free_message_pipe(ts->recv_pipe);
|
@@ -3916,33 +4148,10 @@ void js_std_free_handlers(JSRuntime *rt)
|
|
3916
4148
|
JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
|
3917
4149
|
}
|
3918
4150
|
|
3919
|
-
static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val)
|
3920
|
-
{
|
3921
|
-
const char *str;
|
3922
|
-
|
3923
|
-
str = JS_ToCString(ctx, val);
|
3924
|
-
if (str) {
|
3925
|
-
fprintf(f, "%s\n", str);
|
3926
|
-
JS_FreeCString(ctx, str);
|
3927
|
-
} else {
|
3928
|
-
fprintf(f, "[exception]\n");
|
3929
|
-
}
|
3930
|
-
}
|
3931
|
-
|
3932
4151
|
static void js_std_dump_error1(JSContext *ctx, JSValueConst exception_val)
|
3933
4152
|
{
|
3934
|
-
|
3935
|
-
|
3936
|
-
|
3937
|
-
is_error = JS_IsError(ctx, exception_val);
|
3938
|
-
js_dump_obj(ctx, stderr, exception_val);
|
3939
|
-
if (is_error) {
|
3940
|
-
val = JS_GetPropertyStr(ctx, exception_val, "stack");
|
3941
|
-
if (!JS_IsUndefined(val)) {
|
3942
|
-
js_dump_obj(ctx, stderr, val);
|
3943
|
-
}
|
3944
|
-
JS_FreeValue(ctx, val);
|
3945
|
-
}
|
4153
|
+
JS_PrintValue(ctx, js_print_value_write, stderr, exception_val, NULL);
|
4154
|
+
fputc('\n', stderr);
|
3946
4155
|
}
|
3947
4156
|
|
3948
4157
|
void js_std_dump_error(JSContext *ctx)
|
@@ -3954,34 +4163,88 @@ void js_std_dump_error(JSContext *ctx)
|
|
3954
4163
|
JS_FreeValue(ctx, exception_val);
|
3955
4164
|
}
|
3956
4165
|
|
4166
|
+
static JSRejectedPromiseEntry *find_rejected_promise(JSContext *ctx, JSThreadState *ts,
|
4167
|
+
JSValueConst promise)
|
4168
|
+
{
|
4169
|
+
struct list_head *el;
|
4170
|
+
|
4171
|
+
list_for_each(el, &ts->rejected_promise_list) {
|
4172
|
+
JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
|
4173
|
+
if (JS_SameValue(ctx, rp->promise, promise))
|
4174
|
+
return rp;
|
4175
|
+
}
|
4176
|
+
return NULL;
|
4177
|
+
}
|
4178
|
+
|
3957
4179
|
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
|
3958
4180
|
JSValueConst reason,
|
3959
4181
|
BOOL is_handled, void *opaque)
|
3960
4182
|
{
|
4183
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
4184
|
+
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
|
4185
|
+
JSRejectedPromiseEntry *rp;
|
4186
|
+
|
3961
4187
|
if (!is_handled) {
|
3962
|
-
|
3963
|
-
|
4188
|
+
/* add a new entry if needed */
|
4189
|
+
rp = find_rejected_promise(ctx, ts, promise);
|
4190
|
+
if (!rp) {
|
4191
|
+
rp = malloc(sizeof(*rp));
|
4192
|
+
if (rp) {
|
4193
|
+
rp->promise = JS_DupValue(ctx, promise);
|
4194
|
+
rp->reason = JS_DupValue(ctx, reason);
|
4195
|
+
list_add_tail(&rp->link, &ts->rejected_promise_list);
|
4196
|
+
}
|
4197
|
+
}
|
4198
|
+
} else {
|
4199
|
+
/* the rejection is handled, so the entry can be removed if present */
|
4200
|
+
rp = find_rejected_promise(ctx, ts, promise);
|
4201
|
+
if (rp) {
|
4202
|
+
JS_FreeValue(ctx, rp->promise);
|
4203
|
+
JS_FreeValue(ctx, rp->reason);
|
4204
|
+
list_del(&rp->link);
|
4205
|
+
free(rp);
|
4206
|
+
}
|
4207
|
+
}
|
4208
|
+
}
|
4209
|
+
|
4210
|
+
/* check if there are pending promise rejections. It must be done
|
4211
|
+
asynchrously in case a rejected promise is handled later. Currently
|
4212
|
+
we do it once the application is about to sleep. It could be done
|
4213
|
+
more often if needed. */
|
4214
|
+
static void js_std_promise_rejection_check(JSContext *ctx)
|
4215
|
+
{
|
4216
|
+
JSRuntime *rt = JS_GetRuntime(ctx);
|
4217
|
+
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
|
4218
|
+
struct list_head *el;
|
4219
|
+
|
4220
|
+
if (unlikely(!list_empty(&ts->rejected_promise_list))) {
|
4221
|
+
list_for_each(el, &ts->rejected_promise_list) {
|
4222
|
+
JSRejectedPromiseEntry *rp = list_entry(el, JSRejectedPromiseEntry, link);
|
4223
|
+
fprintf(stderr, "Possibly unhandled promise rejection: ");
|
4224
|
+
js_std_dump_error1(ctx, rp->reason);
|
4225
|
+
}
|
4226
|
+
exit(1);
|
3964
4227
|
}
|
3965
4228
|
}
|
3966
4229
|
|
3967
4230
|
/* main loop which calls the user JS callbacks */
|
3968
4231
|
void js_std_loop(JSContext *ctx)
|
3969
4232
|
{
|
3970
|
-
JSContext *ctx1;
|
3971
4233
|
int err;
|
3972
4234
|
|
3973
4235
|
for(;;) {
|
3974
4236
|
/* execute the pending jobs */
|
3975
4237
|
for(;;) {
|
3976
|
-
err = JS_ExecutePendingJob(JS_GetRuntime(ctx),
|
4238
|
+
err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);
|
3977
4239
|
if (err <= 0) {
|
3978
|
-
if (err < 0)
|
3979
|
-
js_std_dump_error(
|
3980
|
-
}
|
4240
|
+
if (err < 0)
|
4241
|
+
js_std_dump_error(ctx);
|
3981
4242
|
break;
|
3982
4243
|
}
|
3983
4244
|
}
|
3984
4245
|
|
4246
|
+
js_std_promise_rejection_check(ctx);
|
4247
|
+
|
3985
4248
|
if (!os_poll_func || os_poll_func(ctx))
|
3986
4249
|
break;
|
3987
4250
|
}
|
@@ -4006,14 +4269,17 @@ JSValue js_std_await(JSContext *ctx, JSValue obj)
|
|
4006
4269
|
JS_FreeValue(ctx, obj);
|
4007
4270
|
break;
|
4008
4271
|
} else if (state == JS_PROMISE_PENDING) {
|
4009
|
-
JSContext *ctx1;
|
4010
4272
|
int err;
|
4011
|
-
err = JS_ExecutePendingJob(JS_GetRuntime(ctx),
|
4273
|
+
err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);
|
4012
4274
|
if (err < 0) {
|
4013
|
-
js_std_dump_error(
|
4275
|
+
js_std_dump_error(ctx);
|
4276
|
+
}
|
4277
|
+
if (err == 0) {
|
4278
|
+
js_std_promise_rejection_check(ctx);
|
4279
|
+
|
4280
|
+
if (os_poll_func)
|
4281
|
+
os_poll_func(ctx);
|
4014
4282
|
}
|
4015
|
-
if (os_poll_func)
|
4016
|
-
os_poll_func(ctx);
|
4017
4283
|
} else {
|
4018
4284
|
/* not a promise */
|
4019
4285
|
ret = obj;
|
@@ -4034,6 +4300,7 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
|
4034
4300
|
if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
|
4035
4301
|
js_module_set_import_meta(ctx, obj, FALSE, FALSE);
|
4036
4302
|
}
|
4303
|
+
JS_FreeValue(ctx, obj);
|
4037
4304
|
} else {
|
4038
4305
|
if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
|
4039
4306
|
if (JS_ResolveModule(ctx, obj) < 0) {
|
@@ -4054,3 +4321,22 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
|
|
4054
4321
|
JS_FreeValue(ctx, val);
|
4055
4322
|
}
|
4056
4323
|
}
|
4324
|
+
|
4325
|
+
void js_std_eval_binary_json_module(JSContext *ctx,
|
4326
|
+
const uint8_t *buf, size_t buf_len,
|
4327
|
+
const char *module_name)
|
4328
|
+
{
|
4329
|
+
JSValue obj;
|
4330
|
+
JSModuleDef *m;
|
4331
|
+
|
4332
|
+
obj = JS_ReadObject(ctx, buf, buf_len, 0);
|
4333
|
+
if (JS_IsException(obj))
|
4334
|
+
goto exception;
|
4335
|
+
m = create_json_module(ctx, module_name, obj);
|
4336
|
+
if (!m) {
|
4337
|
+
exception:
|
4338
|
+
js_std_dump_error(ctx);
|
4339
|
+
exit(1);
|
4340
|
+
}
|
4341
|
+
}
|
4342
|
+
|