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.
@@ -64,10 +64,8 @@ typedef sig_t sighandler_t;
64
64
 
65
65
  #endif
66
66
 
67
- #if !defined(_WIN32)
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
- int read_fd;
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
- JSModuleDef *js_module_loader(JSContext *ctx,
581
- const char *module_name, void *opaque)
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
- /* compile the module */
600
- func_val = JS_Eval(ctx, (char *)buf, buf_len, module_name,
601
- JS_EVAL_TYPE_MODULE | JS_EVAL_FLAG_COMPILE_ONLY);
602
- js_free(ctx, buf);
603
- if (JS_IsException(func_val))
604
- return NULL;
605
- /* XXX: could propagate the exception */
606
- js_module_set_import_meta(ctx, func_val, TRUE, FALSE);
607
- /* the module is already referenced, so we must free it */
608
- m = JS_VALUE_GET_PTR(func_val);
609
- JS_FreeValue(ctx, func_val);
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
- JS_ResetUncatchableError(ctx);
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
- #if defined(_WIN32)
2271
+ #ifdef USE_WORKER
2142
2272
 
2143
- static int js_os_poll(JSContext *ctx)
2273
+ #ifdef _WIN32
2274
+
2275
+ static int js_waker_init(JSWaker *w)
2144
2276
  {
2145
- JSRuntime *rt = JS_GetRuntime(ctx);
2146
- JSThreadState *ts = JS_GetRuntimeOpaque(rt);
2147
- int min_delay, console_fd;
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
- /* XXX: handle signals if useful */
2281
+ static void js_waker_signal(JSWaker *w)
2282
+ {
2283
+ SetEvent(w->handle);
2284
+ }
2153
2285
 
2154
- if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers))
2155
- return -1; /* no more events */
2286
+ static void js_waker_clear(JSWaker *w)
2287
+ {
2288
+ ResetEvent(w->handle);
2289
+ }
2156
2290
 
2157
- /* XXX: only timers and basic console input are supported */
2158
- if (!list_empty(&ts->os_timers)) {
2159
- cur_time = get_time_ms();
2160
- min_delay = 10000;
2161
- list_for_each(el, &ts->os_timers) {
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
- console_fd = -1;
2182
- list_for_each(el, &ts->os_rw_handlers) {
2183
- rh = list_entry(el, JSOSRWHandler, link);
2184
- if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
2185
- console_fd = rh->fd;
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
- if (console_fd >= 0) {
2191
- DWORD ti, ret;
2192
- HANDLE handle;
2193
- if (min_delay == -1)
2194
- ti = INFINITE;
2195
- else
2196
- ti = min_delay;
2197
- handle = (HANDLE)_get_osfhandle(console_fd);
2198
- ret = WaitForSingleObject(handle, ti);
2199
- if (ret == WAIT_OBJECT_0) {
2200
- list_for_each(el, &ts->os_rw_handlers) {
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
- #ifdef USE_WORKER
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
- uint8_t buf[16];
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
- done:
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
- for(i = 0; i < len; i++)
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
- close(pipe_fds[0]);
3279
- close(pipe_fds[1]);
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
- close(ps->read_fd);
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
- JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
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
- uint8_t ch = '\0';
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
- const char *str;
3813
- size_t len;
3814
-
4016
+ JSValueConst v;
4017
+
3815
4018
  for(i = 0; i < argc; i++) {
3816
4019
  if (i != 0)
3817
4020
  putchar(' ');
3818
- str = JS_ToCStringLen(ctx, &len, argv[i]);
3819
- if (!str)
3820
- return JS_EXCEPTION;
3821
- fwrite(str, 1, len, stdout);
3822
- JS_FreeCString(ctx, str);
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, js_print, "log", 1));
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
- JSValue val;
3935
- BOOL is_error;
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
- fprintf(stderr, "Possibly unhandled promise rejection: ");
3963
- js_std_dump_error1(ctx, reason);
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), &ctx1);
4238
+ err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);
3977
4239
  if (err <= 0) {
3978
- if (err < 0) {
3979
- js_std_dump_error(ctx1);
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), &ctx1);
4273
+ err = JS_ExecutePendingJob(JS_GetRuntime(ctx), NULL);
4012
4274
  if (err < 0) {
4013
- js_std_dump_error(ctx1);
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
+