History

2020-07-05 release

bellard committed 6 years ago

Commit 89007661 parent 172275830 files · +3715 −1669Browse files

Unified · Split

30 files
  1. Changelog +9 −0
  2. Makefile +17 −10
  3. TODO +4 −4
  4. VERSION +1 −1
  5. cutils.h +4 −0
  6. doc/jsbignum.html +2 −2
  7. doc/jsbignum.pdf +0 −0
  8. doc/quickjs.html +77 −18
  9. doc/quickjs.pdf +0 −0
  10. doc/quickjs.texi +63 −7
  11. examples/point.c +1 −1
  12. libbf.c +51 −24
  13. libregexp.c +36 −13
  14. qjs.c +14 −1
  15. qjsc.c +15 −2
  16. quickjs-atom.h +1 −0
  17. quickjs-libc.c +1036 −302
  18. quickjs-libc.h +9 −0
  19. quickjs.c +2058 −1253
  20. quickjs.h +25 −4
  21. repl.js +58 −14
  22. test262.conf +1 −0
  23. test262_errors.txt +4 −2
  24. tests/bjson.c +12 −4
  25. tests/microbench.js +14 −0
  26. tests/test_bjson.js +73 −7
  27. tests/test_builtin.js +4 −0
  28. tests/test_language.js +14 −2
  29. tests/test_std.js +21 −0
  30. tests/test_worker.js +93 −0
Changelog+9−0
@@ -1,3 +1,12 @@
1+2020-07-05:
2+
3+- modified JS_GetPrototype() to return a live value
4+- REPL: support unicode characters larger than 16 bits
5+- added os.Worker
6+- improved object serialization
7+- added std.parseExtJSON
8+- misc bug fixes
9+
110 2020-04-12:
211
312 - added cross realm support
Makefile+17−10
@@ -99,6 +99,10 @@ DEFINES:=-D_GNU_SOURCE -DCONFIG_VERSION=\"$(shell cat VERSION)\" · 98 unmodified lines
9999 ifdef CONFIG_BIGNUM
100100 DEFINES+=-DCONFIG_BIGNUM
101101 endif
102+ifdef CONFIG_WIN32
103+DEFINES+=-D__USE_MINGW_ANSI_STDIO # for standard snprintf behavior
104+endif
105+
102106 CFLAGS+=$(DEFINES)
103107 CFLAGS_DEBUG=$(CFLAGS) -O0
104108 CFLAGS_SMALL=$(CFLAGS) -Os
@@ -115,8 +119,8 @@ CFLAGS+=-p · 10 unmodified lines
115119 LDFLAGS+=-p
116120 endif
117121 ifdef CONFIG_ASAN
118−CFLAGS+=-fsanitize=address
119−LDFLAGS+=-fsanitize=address
122+CFLAGS+=-fsanitize=address -fno-omit-frame-pointer
123+LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer
120124 endif
121125 ifdef CONFIG_WIN32
122126 LDEXPORT=
@@ -166,9 +170,10 @@ QJS_LIB_OBJS+=$(OBJDIR)/libbf.o · 43 unmodified lines
166170 QJS_OBJS+=$(OBJDIR)/qjscalc.o
167171 endif
168172
173+HOST_LIBS=-lm -ldl -lpthread
169174 LIBS=-lm
170175 ifndef CONFIG_WIN32
171−LIBS+=-ldl
176+LIBS+=-ldl -lpthread
172177 endif
173178
174179 $(OBJDIR):
@@ -187,7 +192,7 @@ ifneq ($(CROSS_PREFIX),) · 12 unmodified lines
187192
188193 $(QJSC): $(OBJDIR)/qjsc.host.o \
189194 $(patsubst %.o, %.host.o, $(QJS_LIB_OBJS))
190− $(HOST_CC) $(LDFLAGS) -o $@ $^ $(LIBS)
195+ $(HOST_CC) $(LDFLAGS) -o $@ $^ $(HOST_LIBS)
191196
192197 endif #CROSS_PREFIX
193198
@@ -239,13 +244,13 @@ libunicode-table.h: unicode_gen · 45 unmodified lines
239244 endif
240245
241246 run-test262: $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS)
242− $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
247+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
243248
244249 run-test262-debug: $(patsubst %.o, %.debug.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
245− $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
250+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
246251
247252 run-test262-32: $(patsubst %.o, %.m32.o, $(OBJDIR)/run-test262.o $(QJS_LIB_OBJS))
248− $(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS) -lpthread
253+ $(CC) -m32 $(LDFLAGS) -o $@ $^ $(LIBS)
249254
250255 # object suffix order: nolto, [m32|m32s]
251256
@@ -285,7 +290,7 @@ unicode_gen: $(OBJDIR)/unicode_gen.host.o $(OBJDIR)/cutils.host.o libunicode.c u · 33 unmodified lines
285290 clean:
286291 rm -f repl.c qjscalc.c out.c
287292 rm -f *.a *.o *.d *~ jscompress unicode_gen regexp_test $(PROGS)
288− rm -f hello.c hello_module.c test_fib.c
293+ rm -f hello.c test_fib.c
289294 rm -f examples/*.so tests/*.so
290295 rm -rf $(OBJDIR)/ *.dSYM/ qjs-debug
291296 rm -rf run-test262-debug run-test262-32
@@ -379,10 +384,11 @@ endif · 87 unmodified lines
379384
380385 test: qjs
381386 ./qjs tests/test_closure.js
382− ./qjs tests/test_op.js
387+ ./qjs tests/test_language.js
383388 ./qjs tests/test_builtin.js
384389 ./qjs tests/test_loop.js
385390 ./qjs tests/test_std.js
391+ ./qjs tests/test_worker.js
386392 ifndef CONFIG_DARWIN
387393 ifdef CONFIG_BIGNUM
388394 ./qjs --bignum tests/test_bjson.js
@@ -398,10 +404,11 @@ ifdef CONFIG_BIGNUM · 9 unmodified lines
398404 endif
399405 ifdef CONFIG_M32
400406 ./qjs32 tests/test_closure.js
401− ./qjs32 tests/test_op.js
407+ ./qjs32 tests/test_language.js
402408 ./qjs32 tests/test_builtin.js
403409 ./qjs32 tests/test_loop.js
404410 ./qjs32 tests/test_std.js
411+ ./qjs32 tests/test_worker.js
405412 ifdef CONFIG_BIGNUM
406413 ./qjs32 --bignum tests/test_op_overloading.js
407414 ./qjs32 --bignum tests/test_bignum.js
TODO+4−4
@@ -1,4 +1,5 @@
11 Misc:
2+- use realpath in module name normalizer and put it in quickjs-libc
23 - use custom printf to avoid C library compatibility issues
34 - rename CONFIG_ALL_UNICODE, CONFIG_BIGNUM, CONFIG_ATOMICS, CONFIG_CHECK_JSVALUE ?
45 - unify coding style and naming conventions
@@ -56,12 +57,12 @@ Extensions: · 51 unmodified lines
5657 handle #if, #ifdef, #line, limited support for #define
5758 - get rid of __loadScript, use more common name
5859 - BSD sockets
59−- Workers
6060
6161 REPL:
6262 - debugger
6363 - readline: support MS Windows terminal
6464 - readline: handle dynamic terminal resizing
65+- readline: handle double width unicode characters
6566 - multiline editing
6667 - runtime object and function inspectors
6768 - interactive object browser
@@ -73,6 +74,5 @@ REPL: · 5 unmodified lines
7374 Test262o: 0/11262 errors, 463 excluded
7475 Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
7576
76−Test262: 28/70829 errors, 877 excluded, 425 skipped
77−Test262 commit: 4a8e49b3ca7f9f74a4cafe6621ff9ba548ccc353
78−
77+Test262: 30/71095 errors, 870 excluded, 549 skipped
78+Test262 commit: 281eb10b2844929a7c0ac04527f5b42ce56509fd
VERSION+1−1
@@ -1 +1 @@
1−2020-04-12
1+2020-07-05
cutils.h+4−0
@@ -268,6 +268,10 @@ void dbuf_free(DynBuf *s); · 267 unmodified lines
268268 static inline BOOL dbuf_error(DynBuf *s) {
269269 return s->error;
270270 }
271+static inline void dbuf_set_error(DynBuf *s)
272+{
273+ s->error = TRUE;
274+}
271275
272276 #define UTF8_CHAR_LEN_MAX 6
273277
doc/jsbignum.html+2−2
@@ -1,7 +1,8 @@
11 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
22 <html>
3−<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
3+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
44 <head>
5+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
56 <title>Javascript Bignum Extensions</title>
67
78 <meta name="description" content="Javascript Bignum Extensions">
@@ -9,7 +10,6 @@ · 1 unmodified line
910 <meta name="resource-type" content="document">
1011 <meta name="distribution" content="global">
1112 <meta name="Generator" content="makeinfo">
12−<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
1313 <link href="#SEC_Contents" rel="contents" title="Table of Contents">
1414 <style type="text/css">
1515 <!--
doc/jsbignum.pdf+0−0

Binary file not shown.

doc/quickjs.html+77−18
@@ -1,7 +1,8 @@
11 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
22 <html>
3−<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
3+<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
44 <head>
5+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
56 <title>QuickJS Javascript Engine</title>
67
78 <meta name="description" content="QuickJS Javascript Engine">
@@ -9,7 +10,6 @@ · 1 unmodified line
910 <meta name="resource-type" content="document">
1011 <meta name="distribution" content="global">
1112 <meta name="Generator" content="makeinfo">
12−<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
1313 <link href="#SEC_Contents" rel="contents" title="Table of Contents">
1414 <style type="text/css">
1515 <!--
@@ -73,10 +73,9 @@ ul.no-bullet {list-style: none} · 57 unmodified lines
7373 <li><a name="toc-Language-support" href="#Language-support">3.1 Language support</a>
7474 <ul class="no-bullet">
7575 <li><a name="toc-ES2020-support" href="#ES2020-support">3.1.1 ES2020 support</a></li>
76− <li><a name="toc-JSON" href="#JSON">3.1.2 JSON</a></li>
77− <li><a name="toc-ECMA402" href="#ECMA402">3.1.3 ECMA402</a></li>
78− <li><a name="toc-Extensions" href="#Extensions">3.1.4 Extensions</a></li>
79− <li><a name="toc-Mathematical-extensions" href="#Mathematical-extensions">3.1.5 Mathematical extensions</a></li>
76+ <li><a name="toc-ECMA402" href="#ECMA402">3.1.2 ECMA402</a></li>
77+ <li><a name="toc-Extensions" href="#Extensions">3.1.3 Extensions</a></li>
78+ <li><a name="toc-Mathematical-extensions" href="#Mathematical-extensions">3.1.4 Mathematical extensions</a></li>
8079 </ul></li>
8180 <li><a name="toc-Modules" href="#Modules">3.2 Modules</a></li>
8281 <li><a name="toc-Standard-library" href="#Standard-library">3.3 Standard library</a>
@@ -407,18 +406,13 @@ B (legacy web compatibility) and the Unicode related features. · 324 unmodified lines
407406
408407 </li></ul>
409408
410−<a name="JSON"></a>
411−<h4 class="subsection">3.1.2 JSON</h4>
412−
413−<p>The JSON parser is currently more tolerant than the specification.
414−</p>
415409 <a name="ECMA402"></a>
416−<h4 class="subsection">3.1.3 ECMA402</h4>
410+<h4 class="subsection">3.1.2 ECMA402</h4>
417411
418412 <p>ECMA402 (Internationalization API) is not supported.
419413 </p>
420414 <a name="Extensions"></a>
421−<h4 class="subsection">3.1.4 Extensions</h4>
415+<h4 class="subsection">3.1.3 Extensions</h4>
422416
423417 <ul>
424418 <li> The directive <code>&quot;use strip&quot;</code> indicates that the debug information (including the source code of the functions) should not be retained to save memory. As <code>&quot;use strict&quot;</code>, the directive can be global to a script or local to a function.
@@ -428,7 +422,7 @@ B (legacy web compatibility) and the Unicode related features. · 3 unmodified lines
428422 </li></ul>
429423
430424 <a name="Mathematical-extensions"></a>
431−<h4 class="subsection">3.1.5 Mathematical extensions</h4>
425+<h4 class="subsection">3.1.4 Mathematical extensions</h4>
432426
433427 <p>The mathematical extensions are fully backward compatible with
434428 standard Javascript. See <code>jsbignum.pdf</code> for more information.
@@ -557,7 +551,7 @@ no error occured. · 122 unmodified lines
557551 </p>
558552 </dd>
559553 <dt><code>printf(fmt, ...args)</code></dt>
560−<dd><p>Equivalent to <code>std.out.printf(fmt, ...args)</code>
554+<dd><p>Equivalent to <code>std.out.printf(fmt, ...args)</code>.
561555 </p>
562556 </dd>
563557 <dt><code>sprintf(fmt, ...args)</code></dt>
@@ -636,6 +630,21 @@ optional properties: · 72 unmodified lines
636630 </dd>
637631 </dl>
638632
633+</dd>
634+<dt><code>parseExtJSON(str)</code></dt>
635+<dd>
636+<p>Parse <code>str</code> using a superset of <code>JSON.parse</code>. The
637+ following extensions are accepted:
638+</p>
639+<ul>
640+<li> Single line and multiline comments
641+ </li><li> unquoted properties (ASCII-only Javascript identifiers)
642+ </li><li> trailing comma in array and object definitions
643+ </li><li> single quoted strings
644+ </li><li> <code>\f</code> and <code>\v</code> are accepted as space characters
645+ </li><li> leading plus in numbers
646+ </li><li> octal (<code>0o</code> prefix) and hexadecimal (<code>0x</code> prefix) numbers
647+ </li></ul>
639648 </dd>
640649 </dl>
641650
@@ -649,8 +658,14 @@ optional properties: · 7 unmodified lines
649658 <dd><p>Outputs the string with the UTF-8 encoding.
650659 </p></dd>
651660 <dt><code>printf(fmt, ...args)</code></dt>
652−<dd><p>Formatted printf, same formats as the libc printf.
653−</p></dd>
661+<dd><p>Formatted printf.
662+</p>
663+<p>The same formats as the standard C library <code>printf</code> are
664+supported. Integer format types (e.g. <code>%d</code>) truncate the Numbers
665+or BigInts to 32 bits. Use the <code>l</code> modifier (e.g. <code>%ld</code>) to
666+truncate to 64 bits.
667+</p>
668+</dd>
654669 <dt><code>flush()</code></dt>
655670 <dd><p>Flush the buffered file.
656671 </p></dd>
@@ -718,6 +733,7 @@ is read up its end. · 61 unmodified lines
718733 </li><li> signals
719734 </li><li> timers
720735 </li><li> asynchronous I/O
736+</li><li> workers (threads)
721737 </li></ul>
722738
723739 <p>The OS functions usually return 0 if OK or an OS specific negative
@@ -869,7 +885,7 @@ the handler. · 145 unmodified lines
869885 <dd><p>Call the function <code>func</code> when the signal <code>signal</code>
870886 happens. Only a single handler per signal number is supported. Use
871887 <code>null</code> to set the default handler or <code>undefined</code> to ignore
872−the signal.
888+the signal. Signal handlers can only be defined in the main thread.
873889 </p>
874890 </dd>
875891 <dt><code>SIGINT</code></dt>
@@ -972,6 +988,49 @@ to the timer. · 96 unmodified lines
972988 <dd><p>Return a string representing the platform: <code>&quot;linux&quot;</code>, <code>&quot;darwin&quot;</code>,
973989 <code>&quot;win32&quot;</code> or <code>&quot;js&quot;</code>.
974990 </p>
991+</dd>
992+<dt><code>Worker(source)</code></dt>
993+<dd><p>Constructor to create a new thread (worker) with an API close to the
994+<code>WebWorkers</code>. <code>source</code> is a string containing the module
995+source which is executed in the newly created thread. Threads normally
996+don&rsquo;t share any data and communicate between each other with
997+messages. Nested workers are not supported. An example is available in
998+<samp>tests/test_worker.js</samp>.
999+</p>
1000+<p>The worker class has the following static properties:
1001+</p>
1002+<dl compact="compact">
1003+<dt><code>parent</code></dt>
1004+<dd><p>In the created worker, <code>Worker.parent</code> represents the parent
1005+ worker and is used to send or receive messages.
1006+ </p></dd>
1007+</dl>
1008+
1009+<p>The worker instances have the following properties:
1010+</p>
1011+<dl compact="compact">
1012+<dt><code>postMessage(msg)</code></dt>
1013+<dd>
1014+<p>Send a message to the corresponding worker. <code>msg</code> is cloned in
1015+ the destination worker using an algorithm similar to the <code>HTML</code>
1016+ structured clone algorithm. <code>SharedArrayBuffer</code> are shared
1017+ between workers.
1018+</p>
1019+<p>Current limitations: <code>Map</code> and <code>Set</code> are not supported
1020+ yet.
1021+</p>
1022+</dd>
1023+<dt><code>onmessage</code></dt>
1024+<dd>
1025+<p>Getter and setter. Set a function which is called each time a
1026+ message is received. The function is called with a single
1027+ argument. It is an object with a <code>data</code> property containing the
1028+ received message. The thread is not terminated if there is at least
1029+ one non <code>null</code> <code>onmessage</code> handler.
1030+</p>
1031+</dd>
1032+</dl>
1033+
9751034 </dd>
9761035 </dl>
9771036
doc/quickjs.pdf+0−0

Binary file not shown.

doc/quickjs.texi+63−7
@@ -272,10 +272,6 @@ The following features are not supported yet: · 271 unmodified lines
272272
273273 @end itemize
274274
275−@subsection JSON
276−
277−The JSON parser is currently more tolerant than the specification.
278−
279275 @subsection ECMA402
280276
281277 ECMA402 (Internationalization API) is not supported.
@@ -405,7 +401,7 @@ no error occured. · 123 unmodified lines
405401 Equivalent to @code{std.out.puts(str)}.
406402
407403 @item printf(fmt, ...args)
408−Equivalent to @code{std.out.printf(fmt, ...args)}
404+Equivalent to @code{std.out.printf(fmt, ...args)}.
409405
410406 @item sprintf(fmt, ...args)
411407 Equivalent to the libc sprintf().
@@ -474,6 +470,20 @@ optional properties: · 62 unmodified lines
474470
475471 @end table
476472
473+@item parseExtJSON(str)
474+
475+ Parse @code{str} using a superset of @code{JSON.parse}. The
476+ following extensions are accepted:
477+
478+ @itemize
479+ @item Single line and multiline comments
480+ @item unquoted properties (ASCII-only Javascript identifiers)
481+ @item trailing comma in array and object definitions
482+ @item single quoted strings
483+ @item @code{\f} and @code{\v} are accepted as space characters
484+ @item leading plus in numbers
485+ @item octal (@code{0o} prefix) and hexadecimal (@code{0x} prefix) numbers
486+ @end itemize
477487 @end table
478488
479489 FILE prototype:
@@ -484,7 +494,13 @@ Close the file. Return 0 if OK or @code{-errno} in case of I/O error. · 4 unmodified lines
484494 @item puts(str)
485495 Outputs the string with the UTF-8 encoding.
486496 @item printf(fmt, ...args)
487−Formatted printf, same formats as the libc printf.
497+Formatted printf.
498+
499+The same formats as the standard C library @code{printf} are
500+supported. Integer format types (e.g. @code{%d}) truncate the Numbers
501+or BigInts to 32 bits. Use the @code{l} modifier (e.g. @code{%ld}) to
502+truncate to 64 bits.
503+
488504 @item flush()
489505 Flush the buffered file.
490506 @item seek(offset, whence)
@@ -537,6 +553,7 @@ The @code{os} module provides Operating System specific functions: · 46 unmodified lines
537553 @item signals
538554 @item timers
539555 @item asynchronous I/O
556+@item workers (threads)
540557 @end itemize
541558
542559 The OS functions usually return 0 if OK or an OS specific negative
@@ -664,7 +681,7 @@ the handler. · 121 unmodified lines
664681 Call the function @code{func} when the signal @code{signal}
665682 happens. Only a single handler per signal number is supported. Use
666683 @code{null} to set the default handler or @code{undefined} to ignore
667−the signal.
684+the signal. Signal handlers can only be defined in the main thread.
668685
669686 @item SIGINT
670687 @item SIGABRT
@@ -747,6 +764,45 @@ Cancel a timer. · 76 unmodified lines
747764 Return a string representing the platform: @code{"linux"}, @code{"darwin"},
748765 @code{"win32"} or @code{"js"}.
749766
767+@item Worker(source)
768+Constructor to create a new thread (worker) with an API close to the
769+@code{WebWorkers}. @code{source} is a string containing the module
770+source which is executed in the newly created thread. Threads normally
771+don't share any data and communicate between each other with
772+messages. Nested workers are not supported. An example is available in
773+@file{tests/test_worker.js}.
774+
775+The worker class has the following static properties:
776+
777+ @table @code
778+ @item parent
779+ In the created worker, @code{Worker.parent} represents the parent
780+ worker and is used to send or receive messages.
781+ @end table
782+
783+The worker instances have the following properties:
784+
785+ @table @code
786+ @item postMessage(msg)
787+
788+ Send a message to the corresponding worker. @code{msg} is cloned in
789+ the destination worker using an algorithm similar to the @code{HTML}
790+ structured clone algorithm. @code{SharedArrayBuffer} are shared
791+ between workers.
792+
793+ Current limitations: @code{Map} and @code{Set} are not supported
794+ yet.
795+
796+ @item onmessage
797+
798+ Getter and setter. Set a function which is called each time a
799+ message is received. The function is called with a single
800+ argument. It is an object with a @code{data} property containing the
801+ received message. The thread is not terminated if there is at least
802+ one non @code{null} @code{onmessage} handler.
803+
804+ @end table
805+
750806 @end table
751807
752808 @section QuickJS C API
examples/point.c+1−1
@@ -130,11 +130,11 @@ static int js_point_init(JSContext *ctx, JSModuleDef *m) · 129 unmodified lines
130130
131131 point_proto = JS_NewObject(ctx);
132132 JS_SetPropertyFunctionList(ctx, point_proto, js_point_proto_funcs, countof(js_point_proto_funcs));
133− JS_SetClassProto(ctx, js_point_class_id, point_proto);
134133
135134 point_class = JS_NewCFunction2(ctx, js_point_ctor, "Point", 2, JS_CFUNC_constructor, 0);
136135 /* set proto.constructor and ctor.prototype */
137136 JS_SetConstructor(ctx, point_class, point_proto);
137+ JS_SetClassProto(ctx, js_point_class_id, point_proto);
138138
139139 JS_SetModuleExport(ctx, m, "Point", point_class);
140140 return 0;
libbf.c+51−24
@@ -3370,12 +3370,14 @@ slimb_t bf_mul_log2_radix(slimb_t a1, unsigned int radix, int is_inv, · 3369 unmodified lines
33703370 }
33713371
33723372 /* 'n' is the number of output limbs */
3373−static void bf_integer_to_radix_rec(bf_t *pow_tab,
3374− limb_t *out, const bf_t *a, limb_t n,
3375− int level, limb_t n0, limb_t radixl,
3376− unsigned int radixl_bits)
3373+static int bf_integer_to_radix_rec(bf_t *pow_tab,
3374+ limb_t *out, const bf_t *a, limb_t n,
3375+ int level, limb_t n0, limb_t radixl,
3376+ unsigned int radixl_bits)
33773377 {
33783378 limb_t n1, n2, q_prec;
3379+ int ret;
3380+
33793381 assert(n >= 1);
33803382 if (n == 1) {
33813383 out[0] = get_bits(a->tab, a->len, a->len * LIMB_BITS - a->expn);
@@ -3402,63 +3404,81 @@ static void bf_integer_to_radix_rec(bf_t *pow_tab, · 20 unmodified lines
34023404 n1 = n - n2;
34033405 B = &pow_tab[2 * level];
34043406 B_inv = &pow_tab[2 * level + 1];
3407+ ret = 0;
34053408 if (B->len == 0) {
34063409 /* compute BASE^n2 */
3407− bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ);
3410+ ret |= bf_pow_ui_ui(B, radixl, n2, BF_PREC_INF, BF_RNDZ);
34083411 /* we use enough bits for the maximum possible 'n1' value,
34093412 i.e. n2 + 1 */
3410− bf_set_ui(&R, 1);
3411− bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);
3413+ ret |= bf_set_ui(&R, 1);
3414+ ret |= bf_div(B_inv, &R, B, (n2 + 1) * radixl_bits + 2, BF_RNDN);
34123415 }
34133416 // printf("%d: n1=% " PRId64 " n2=%" PRId64 "\n", level, n1, n2);
34143417 q_prec = n1 * radixl_bits;
3415− bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);
3416− bf_rint(&Q, BF_RNDZ);
3418+ ret |= bf_mul(&Q, a, B_inv, q_prec, BF_RNDN);
3419+ ret |= bf_rint(&Q, BF_RNDZ);
34173420
3418− bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ);
3419− bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ);
3421+ ret |= bf_mul(&R, &Q, B, BF_PREC_INF, BF_RNDZ);
3422+ ret |= bf_sub(&R, a, &R, BF_PREC_INF, BF_RNDZ);
3423+
3424+ if (ret & BF_ST_MEM_ERROR)
3425+ goto fail;
34203426 /* adjust if necessary */
34213427 q_add = 0;
34223428 while (R.sign && R.len != 0) {
3423− bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ);
3429+ if (bf_add(&R, &R, B, BF_PREC_INF, BF_RNDZ))
3430+ goto fail;
34243431 q_add--;
34253432 }
34263433 while (bf_cmpu(&R, B) >= 0) {
3427− bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ);
3434+ if (bf_sub(&R, &R, B, BF_PREC_INF, BF_RNDZ))
3435+ goto fail;
34283436 q_add++;
34293437 }
34303438 if (q_add != 0) {
3431− bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ);
3439+ if (bf_add_si(&Q, &Q, q_add, BF_PREC_INF, BF_RNDZ))
3440+ goto fail;
3441+ }
3442+ if (bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0,
3443+ radixl, radixl_bits))
3444+ goto fail;
3445+ if (bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0,
3446+ radixl, radixl_bits)) {
3447+ fail:
3448+ bf_delete(&Q);
3449+ bf_delete(&R);
3450+ return -1;
34323451 }
3433− bf_integer_to_radix_rec(pow_tab, out + n2, &Q, n1, level + 1, n0,
3434− radixl, radixl_bits);
3435− bf_integer_to_radix_rec(pow_tab, out, &R, n2, level + 1, n0,
3436− radixl, radixl_bits);
34373452 bf_delete(&Q);
34383453 bf_delete(&R);
34393454 }
3455+ return 0;
34403456 }
34413457
3442−static void bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl)
3458+/* return 0 if OK != 0 if memory error */
3459+static int bf_integer_to_radix(bf_t *r, const bf_t *a, limb_t radixl)
34433460 {
34443461 bf_context_t *s = r->ctx;
34453462 limb_t r_len;
34463463 bf_t *pow_tab;
3447− int i, pow_tab_len;
3464+ int i, pow_tab_len, ret;
34483465
34493466 r_len = r->len;
34503467 pow_tab_len = (ceil_log2(r_len) + 2) * 2; /* XXX: check */
34513468 pow_tab = bf_malloc(s, sizeof(pow_tab[0]) * pow_tab_len);
3469+ if (!pow_tab)
3470+ return -1;
34523471 for(i = 0; i < pow_tab_len; i++)
34533472 bf_init(r->ctx, &pow_tab[i]);
34543473
3455− bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,
3456− ceil_log2(radixl));
3474+ ret = bf_integer_to_radix_rec(pow_tab, r->tab, a, r_len, 0, r_len, radixl,
3475+ ceil_log2(radixl));
34573476
34583477 for(i = 0; i < pow_tab_len; i++) {
34593478 bf_delete(&pow_tab[i]);
34603479 }
34613480 bf_free(s, pow_tab);
3481+ return ret;
34623482 }
34633483
34643484 /* a must be >= 0. 'P' is the wanted number of digits in radix
@@ -3625,8 +3645,14 @@ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits, · 160 unmodified lines
36253645 a = &a_s;
36263646 bf_init(a1->ctx, a);
36273647 n = (n_digits + digits_per_limb - 1) / digits_per_limb;
3628− bf_resize(a, n);
3629− bf_integer_to_radix(a, a1, radixl);
3648+ if (bf_resize(a, n)) {
3649+ dbuf_set_error(s);
3650+ goto done;
3651+ }
3652+ if (bf_integer_to_radix(a, a1, radixl)) {
3653+ dbuf_set_error(s);
3654+ goto done;
3655+ }
36303656 radix_bits = 0;
36313657 pos = n;
36323658 pos_incr = 1;
@@ -3659,6 +3685,7 @@ static void output_digits(DynBuf *s, const bf_t *a1, int radix, limb_t n_digits, · 26 unmodified lines
36593685 buf_pos += l;
36603686 i += l;
36613687 }
3688+ done:
36623689 if (a != a1)
36633690 bf_delete(a);
36643691 }
libregexp.c+36−13
@@ -110,12 +110,14 @@ static inline int is_digit(int c) { · 109 unmodified lines
110110 return c >= '0' && c <= '9';
111111 }
112112
113−/* insert 'len' bytes at position 'pos' */
114−static void dbuf_insert(DynBuf *s, int pos, int len)
113+/* insert 'len' bytes at position 'pos'. Return < 0 if error. */
114+static int dbuf_insert(DynBuf *s, int pos, int len)
115115 {
116− dbuf_realloc(s, s->size + len);
116+ if (dbuf_realloc(s, s->size + len))
117+ return -1;
117118 memmove(s->buf + pos + len, s->buf + pos, s->size - pos);
118119 s->size += len;
120+ return 0;
119121 }
120122
121123 /* canonicalize with the specific JS regexp rules */
@@ -434,6 +436,11 @@ static int __attribute__((format(printf, 2, 3))) re_parse_error(REParseState *s, · 312 unmodified lines
434436 return -1;
435437 }
436438
439+static int re_parse_out_of_memory(REParseState *s)
440+{
441+ return re_parse_error(s, "out of memory");
442+}
443+
437444 /* If allow_overflow is false, return -1 in case of
438445 overflow. Otherwise return INT32_MAX. */
439446 static int parse_digits(const uint8_t **pp, BOOL allow_overflow)
@@ -693,7 +700,7 @@ static int parse_unicode_property(REParseState *s, CharRange *cr, · 253 unmodified lines
693700 *pp = p;
694701 return 0;
695702 out_of_memory:
696− return re_parse_error(s, "out of memory");
703+ return re_parse_out_of_memory(s);
697704 }
698705 #endif /* CONFIG_ALL_UNICODE */
699706
@@ -928,7 +935,7 @@ static int re_parse_char_class(REParseState *s, const uint8_t **pp) · 228 unmodified lines
928935 *pp = p;
929936 return 0;
930937 memory_error:
931− re_parse_error(s, "out of memory");
938+ re_parse_out_of_memory(s);
932939 fail:
933940 cr_free(cr);
934941 return -1;
@@ -1295,6 +1302,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) · 360 unmodified lines
12951302 return -1;
12961303 re_emit_op(s, REOP_match);
12971304 /* jump after the 'match' after the lookahead is successful */
1305+ if (dbuf_error(&s->byte_code))
1306+ return -1;
12981307 put_u32(s->byte_code.buf + pos, s->byte_code.size - (pos + 4));
12991308 } else if (p[2] == '<') {
13001309 p += 3;
@@ -1548,12 +1557,15 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) · 247 unmodified lines
15481557
15491558 if (quant_max > 0) {
15501559 /* specific optimization for simple quantifiers */
1560+ if (dbuf_error(&s->byte_code))
1561+ goto out_of_memory;
15511562 len = re_is_simple_quantifier(s->byte_code.buf + last_atom_start,
15521563 s->byte_code.size - last_atom_start);
15531564 if (len > 0) {
15541565 re_emit_op(s, REOP_match);
15551566
1556− dbuf_insert(&s->byte_code, last_atom_start, 17);
1567+ if (dbuf_insert(&s->byte_code, last_atom_start, 17))
1568+ goto out_of_memory;
15571569 pos = last_atom_start;
15581570 s->byte_code.buf[pos++] = REOP_simple_greedy_quant;
15591571 put_u32(&s->byte_code.buf[pos],
@@ -1569,6 +1581,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) · 9 unmodified lines
15691581 }
15701582 }
15711583
1584+ if (dbuf_error(&s->byte_code))
1585+ goto out_of_memory;
15721586 add_zero_advance_check = (re_check_advance(s->byte_code.buf + last_atom_start,
15731587 s->byte_code.size - last_atom_start) == 0);
15741588 } else {
@@ -1582,7 +1596,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) · 7 unmodified lines
15821596 /* need to reset the capture in case the atom is
15831597 not executed */
15841598 if (last_capture_count != s->capture_count) {
1585− dbuf_insert(&s->byte_code, last_atom_start, 3);
1599+ if (dbuf_insert(&s->byte_code, last_atom_start, 3))
1600+ goto out_of_memory;
15861601 s->byte_code.buf[last_atom_start++] = REOP_save_reset;
15871602 s->byte_code.buf[last_atom_start++] = last_capture_count;
15881603 s->byte_code.buf[last_atom_start++] = s->capture_count - 1;
@@ -1590,12 +1605,14 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) · 1 unmodified line
15901605 if (quant_max == 0) {
15911606 s->byte_code.size = last_atom_start;
15921607 } else if (quant_max == 1) {
1593− dbuf_insert(&s->byte_code, last_atom_start, 5);
1608+ if (dbuf_insert(&s->byte_code, last_atom_start, 5))
1609+ goto out_of_memory;
15941610 s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
15951611 greedy;
15961612 put_u32(s->byte_code.buf + last_atom_start + 1, len);
15971613 } else if (quant_max == INT32_MAX) {
1598− dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check);
1614+ if (dbuf_insert(&s->byte_code, last_atom_start, 5 + add_zero_advance_check))
1615+ goto out_of_memory;
15991616 s->byte_code.buf[last_atom_start] = REOP_split_goto_first +
16001617 greedy;
16011618 put_u32(s->byte_code.buf + last_atom_start + 1,
@@ -1611,7 +1628,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) · 9 unmodified lines
16111628 re_emit_goto(s, REOP_goto, last_atom_start);
16121629 }
16131630 } else {
1614− dbuf_insert(&s->byte_code, last_atom_start, 10);
1631+ if (dbuf_insert(&s->byte_code, last_atom_start, 10))
1632+ goto out_of_memory;
16151633 pos = last_atom_start;
16161634 s->byte_code.buf[pos++] = REOP_push_i32;
16171635 put_u32(s->byte_code.buf + pos, quant_max);
@@ -1629,7 +1647,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) · 11 unmodified lines
16291647 if (quant_min == 1) {
16301648 /* nothing to add */
16311649 } else {
1632− dbuf_insert(&s->byte_code, last_atom_start, 5);
1650+ if (dbuf_insert(&s->byte_code, last_atom_start, 5))
1651+ goto out_of_memory;
16331652 s->byte_code.buf[last_atom_start] = REOP_push_i32;
16341653 put_u32(s->byte_code.buf + last_atom_start + 1,
16351654 quant_min);
@@ -1670,6 +1689,8 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir) · 34 unmodified lines
16701689 done:
16711690 s->buf_ptr = p;
16721691 return 0;
1692+ out_of_memory:
1693+ return re_parse_out_of_memory(s);
16731694 }
16741695
16751696 static int re_parse_alternative(REParseState *s, BOOL is_backward_dir)
@@ -1719,7 +1740,9 @@ static int re_parse_disjunction(REParseState *s, BOOL is_backward_dir) · 43 unmodified lines
17191740 len = s->byte_code.size - start;
17201741
17211742 /* insert a split before the first alternative */
1722− dbuf_insert(&s->byte_code, start, 5);
1743+ if (dbuf_insert(&s->byte_code, start, 5)) {
1744+ return re_parse_out_of_memory(s);
1745+ }
17231746 s->byte_code.buf[start] = REOP_split_next_first;
17241747 put_u32(s->byte_code.buf + start + 1, len + 5);
17251748
@@ -1844,7 +1867,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size, · 118 unmodified lines
18441867 }
18451868
18461869 if (dbuf_error(&s->byte_code)) {
1847− re_parse_error(s, "out of memory");
1870+ re_parse_out_of_memory(s);
18481871 goto error;
18491872 }
18501873
qjs.c+14−1
@@ -270,6 +270,7 @@ void help(void) · 269 unmodified lines
270270 "-T --trace trace memory allocation\n"
271271 "-d --dump dump the memory usage stats\n"
272272 " --memory-limit n limit the memory usage to 'n' bytes\n"
273+ " --stack-size n limit the stack size to 'n' bytes\n"
273274 " --unhandled-rejection dump unhandled promise rejections\n"
274275 "-q --quit just instantiate the interpreter and quit\n");
275276 exit(1);
@@ -295,7 +296,8 @@ int main(int argc, char **argv) · 19 unmodified lines
295296 #ifdef CONFIG_BIGNUM
296297 int load_jscalc, bignum_ext = 0;
297298 #endif
298−
299+ size_t stack_size = 0;
300+
299301 #ifdef CONFIG_BIGNUM
300302 /* load jscalc runtime if invoked as 'qjscalc' */
301303 {
@@ -407,6 +409,14 @@ int main(int argc, char **argv) · 105 unmodified lines
407409 memory_limit = (size_t)strtod(argv[optind++], NULL);
408410 continue;
409411 }
412+ if (!strcmp(longopt, "stack-size")) {
413+ if (optind >= argc) {
414+ fprintf(stderr, "expecting stack size");
415+ exit(1);
416+ }
417+ stack_size = (size_t)strtod(argv[optind++], NULL);
418+ continue;
419+ }
410420 if (opt) {
411421 fprintf(stderr, "qjs: unknown option '-%c'\n", opt);
412422 } else {
@@ -428,6 +438,9 @@ int main(int argc, char **argv) · 15 unmodified lines
428438 }
429439 if (memory_limit != 0)
430440 JS_SetMemoryLimit(rt, memory_limit);
441+ if (stack_size != 0)
442+ JS_SetMaxStackSize(rt, stack_size);
443+ js_std_init_handlers(rt);
431444 ctx = JS_NewContext(rt);
432445 if (!ctx) {
433446 fprintf(stderr, "qjs: cannot allocate JS context\n");
qjsc.c+15−2
@@ -326,6 +326,7 @@ static const char main_c_template1[] = · 325 unmodified lines
326326 " JSRuntime *rt;\n"
327327 " JSContext *ctx;\n"
328328 " rt = JS_NewRuntime();\n"
329+ " js_std_init_handlers(rt);\n"
329330 ;
330331
331332 static const char main_c_template2[] =
@@ -351,7 +352,8 @@ void help(void) · 19 unmodified lines
351352 "-M module_name[,cname] add initialization code for an external C module\n"
352353 "-x byte swapped output\n"
353354 "-p prefix set the prefix of the generated C names\n"
354− );
355+ "-S n set the maximum stack size to 'n' bytes (default=%d)\n",
356+ JS_DEFAULT_STACK_SIZE);
355357 #ifdef CONFIG_LTO
356358 {
357359 int i;
@@ -447,6 +449,7 @@ static int output_executable(const char *out_filename, const char *cfilename, · 89 unmodified lines
447449 *arg++ = libjsname;
448450 *arg++ = "-lm";
449451 *arg++ = "-ldl";
452+ *arg++ = "-lpthread";
450453 *arg = NULL;
451454
452455 if (verbose) {
@@ -487,6 +490,7 @@ int main(int argc, char **argv) · 34 unmodified lines
487490 BOOL use_lto;
488491 int module;
489492 OutputTypeEnum output_type;
493+ size_t stack_size;
490494 #ifdef CONFIG_BIGNUM
491495 BOOL bignum_ext = FALSE;
492496 #endif
@@ -499,13 +503,14 @@ int main(int argc, char **argv) · 6 unmodified lines
499503 byte_swap = FALSE;
500504 verbose = 0;
501505 use_lto = FALSE;
506+ stack_size = 0;
502507
503508 /* add system modules */
504509 namelist_add(&cmodule_list, "std", "std", 0);
505510 namelist_add(&cmodule_list, "os", "os", 0);
506511
507512 for(;;) {
508− c = getopt(argc, argv, "ho:cN:f:mxevM:p:");
513+ c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:");
509514 if (c == -1)
510515 break;
511516 switch(c) {
@@ -580,6 +585,9 @@ int main(int argc, char **argv) · 68 unmodified lines
580585 case 'p':
581586 c_ident_prefix = optarg;
582587 break;
588+ case 'S':
589+ stack_size = (size_t)strtod(optarg, NULL);
590+ break;
583591 default:
584592 break;
585593 }
@@ -652,6 +660,11 @@ int main(int argc, char **argv) · 66 unmodified lines
652660 fputs(main_c_template1, fo);
653661 fprintf(fo, " ctx = JS_NewContextRaw(rt);\n");
654662
663+ if (stack_size != 0) {
664+ fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
665+ (unsigned int)stack_size);
666+ }
667+
655668 /* add the module loader if necessary */
656669 if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
657670 fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
quickjs-atom.h+1−0
@@ -82,6 +82,7 @@ DEF(length, "length") · 81 unmodified lines
8282 DEF(fileName, "fileName")
8383 DEF(lineNumber, "lineNumber")
8484 DEF(message, "message")
85+DEF(errors, "errors")
8586 DEF(stack, "stack")
8687 DEF(name, "name")
8788 DEF(toString, "toString")
quickjs-libc.c+1036−302
@@ -40,28 +40,38 @@ · 39 unmodified lines
4040 #if defined(_WIN32)
4141 #include <windows.h>
4242 #include <conio.h>
43+#include <utime.h>
4344 #else
4445 #include <dlfcn.h>
4546 #include <termios.h>
4647 #include <sys/ioctl.h>
4748 #include <sys/wait.h>
49+
4850 #if defined(__APPLE__)
4951 typedef sig_t sighandler_t;
52+#if !defined(environ)
53+#include <crt_externs.h>
54+#define environ (*_NSGetEnviron())
55+#endif
56+#endif /* __APPLE__ */
57+
58+#endif
59+
60+#if !defined(_WIN32)
61+/* enable the os.Worker API. IT relies on POSIX threads */
62+#define USE_WORKER
5063 #endif
64+
65+#ifdef USE_WORKER
66+#include <pthread.h>
67+#include <stdatomic.h>
5168 #endif
5269
5370 #include "cutils.h"
5471 #include "list.h"
5572 #include "quickjs-libc.h"
5673
57−static void js_std_dbuf_init(JSContext *ctx, DynBuf *s)
58−{
59− dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt);
60−}
61−
6274 /* TODO:
63− - add worker
64− - add minimal VT100 emulation for win32
6575 - add socket calls
6676 */
6777
@@ -84,14 +94,54 @@ typedef struct { · 16 unmodified lines
8494 JSValue func;
8595 } JSOSTimer;
8696
87−/* initialize the lists so js_std_free_handlers() can always be called */
88−static struct list_head os_rw_handlers = LIST_HEAD_INIT(os_rw_handlers);
89−static struct list_head os_signal_handlers = LIST_HEAD_INIT(os_signal_handlers);
90−static struct list_head os_timers = LIST_HEAD_INIT(os_timers);
97+typedef struct {
98+ struct list_head link;
99+ uint8_t *data;
100+ size_t data_len;
101+ /* list of SharedArrayBuffers, necessary to free the message */
102+ uint8_t **sab_tab;
103+ size_t sab_tab_len;
104+} JSWorkerMessage;
105+
106+typedef struct {
107+ int ref_count;
108+#ifdef USE_WORKER
109+ pthread_mutex_t mutex;
110+#endif
111+ struct list_head msg_queue; /* list of JSWorkerMessage.link */
112+ int read_fd;
113+ int write_fd;
114+} JSWorkerMessagePipe;
115+
116+typedef struct {
117+ struct list_head link;
118+ JSWorkerMessagePipe *recv_pipe;
119+ JSValue on_message_func;
120+} JSWorkerMessageHandler;
121+
122+typedef struct JSThreadState {
123+ struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */
124+ struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */
125+ struct list_head os_timers; /* list of JSOSTimer.link */
126+ struct list_head port_list; /* list of JSWorkerMessageHandler.link */
127+ int eval_script_recurse; /* only used in the main thread */
128+ /* not used in the main thread */
129+ JSWorkerMessagePipe *recv_pipe, *send_pipe;
130+} JSThreadState;
131+
91132 static uint64_t os_pending_signals;
92−static int eval_script_recurse;
93133 static int (*os_poll_func)(JSContext *ctx);
94134
135+static void js_std_dbuf_init(JSContext *ctx, DynBuf *s)
136+{
137+ dbuf_init2(s, JS_GetRuntime(ctx), (DynBufReallocFunc *)js_realloc_rt);
138+}
139+
140+static BOOL my_isdigit(int c)
141+{
142+ return (c >= '0' && c <= '9');
143+}
144+
95145 static JSValue js_printf_internal(JSContext *ctx,
96146 int argc, JSValueConst *argv, FILE *fp)
97147 {
@@ -103,14 +153,12 @@ static JSValue js_printf_internal(JSContext *ctx, · 5 unmodified lines
103153 const uint8_t *fmt, *fmt_end;
104154 const uint8_t *p;
105155 char *q;
106− int i, c, len;
156+ int i, c, len, mod;
107157 size_t fmt_len;
108158 int32_t int32_arg;
109159 int64_t int64_arg;
110160 double double_arg;
111161 const char *string_arg;
112− enum { PART_FLAGS, PART_WIDTH, PART_DOT, PART_PREC, PART_MODIFIER } part;
113− int modsize;
114162 /* Use indirect call to dbuf_printf to prevent gcc warning */
115163 int (*dbuf_printf_fun)(DynBuf *s, const char *fmt, ...) = (void*)dbuf_printf;
116164
@@ -132,150 +180,162 @@ static JSValue js_printf_internal(JSContext *ctx, · 15 unmodified lines
132180 break;
133181 q = fmtbuf;
134182 *q++ = *fmt++; /* copy '%' */
135− part = PART_FLAGS;
136− modsize = 0;
137− for (;;) {
138− if (q >= fmtbuf + sizeof(fmtbuf) - 1)
139− goto invalid;
140−
141− c = *fmt++;
142− *q++ = c;
143− *q = '\0';
144−
145− switch (c) {
146− case '1': case '2': case '3':
147− case '4': case '5': case '6':
148− case '7': case '8': case '9':
149− if (part != PART_PREC) {
150− if (part <= PART_WIDTH)
151− part = PART_WIDTH;
152− else
153− goto invalid;
154− }
155− continue;
156−
157− case '0': case '#': case '+': case '-': case ' ': case '\'':
158− if (part > PART_FLAGS)
159− goto invalid;
160− continue;
161−
162− case '.':
163− if (part > PART_DOT)
183+
184+ /* flags */
185+ for(;;) {
186+ c = *fmt;
187+ if (c == '0' || c == '#' || c == '+' || c == '-' || c == ' ' ||
188+ c == '\'') {
189+ if (q >= fmtbuf + sizeof(fmtbuf) - 1)
164190 goto invalid;
165− part = PART_DOT;
166− continue;
167−
168− case '*':
169− if (part < PART_WIDTH)
170− part = PART_DOT;
171− else if (part == PART_DOT)
172− part = PART_MODIFIER;
173− else
191+ *q++ = c;
192+ fmt++;
193+ } else {
194+ break;
195+ }
196+ }
197+ /* width */
198+ if (*fmt == '*') {
199+ if (i >= argc)
200+ goto missing;
201+ if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
202+ goto fail;
203+ q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
204+ fmt++;
205+ } else {
206+ while (my_isdigit(*fmt)) {
207+ if (q >= fmtbuf + sizeof(fmtbuf) - 1)
174208 goto invalid;
175−
209+ *q++ = *fmt++;
210+ }
211+ }
212+ if (*fmt == '.') {
213+ if (q >= fmtbuf + sizeof(fmtbuf) - 1)
214+ goto invalid;
215+ *q++ = *fmt++;
216+ if (*fmt == '*') {
176217 if (i >= argc)
177218 goto missing;
178−
179219 if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
180220 goto fail;
181221 q += snprintf(q, fmtbuf + sizeof(fmtbuf) - q, "%d", int32_arg);
182− continue;
183−
184− case 'h':
185− if (modsize != 0 && modsize != -1)
186− goto invalid;
187− modsize--;
188− part = PART_MODIFIER;
189− continue;
190− case 'l':
191− q--;
192− if (modsize != 0 && modsize != 1)
193− goto invalid;
194− modsize++;
195− part = PART_MODIFIER;
196− continue;
197−
198− case 'c':
199− if (i >= argc)
200− goto missing;
201− if (JS_IsString(argv[i])) {
202− string_arg = JS_ToCString(ctx, argv[i++]);
203− if (!string_arg)
204− goto fail;
205− int32_arg = unicode_from_utf8((uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);
206− JS_FreeCString(ctx, string_arg);
207− } else {
208− if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
209− goto fail;
210− }
211− /* handle utf-8 encoding explicitly */
212− if ((unsigned)int32_arg > 0x10FFFF)
213− int32_arg = 0xFFFD;
214− /* ignore conversion flags, width and precision */
215− len = unicode_to_utf8(cbuf, int32_arg);
216− dbuf_put(&dbuf, cbuf, len);
217− break;
218−
219− case 'd':
220− case 'i':
221− case 'o':
222− case 'u':
223− case 'x':
224− case 'X':
225− if (i >= argc)
226− goto missing;
227− if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
228− goto fail;
229− if (modsize > 0) {
230− q[1] = q[-1];
231− q[-1] = q[0] = 'l';
232− q[2] = '\0';
233− dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);
234− } else {
235− dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
222+ fmt++;
223+ } else {
224+ while (my_isdigit(*fmt)) {
225+ if (q >= fmtbuf + sizeof(fmtbuf) - 1)
226+ goto invalid;
227+ *q++ = *fmt++;
236228 }
237− break;
229+ }
230+ }
238231
239− case 's':
240− if (i >= argc)
241− goto missing;
242− /* XXX: handle strings containing null characters */
232+ /* we only support the "l" modifier for 64 bit numbers */
233+ mod = ' ';
234+ if (*fmt == 'l') {
235+ mod = *fmt++;
236+ }
237+
238+ /* type */
239+ c = *fmt++;
240+ if (q >= fmtbuf + sizeof(fmtbuf) - 1)
241+ goto invalid;
242+ *q++ = c;
243+ *q = '\0';
244+
245+ switch (c) {
246+ case 'c':
247+ if (i >= argc)
248+ goto missing;
249+ if (JS_IsString(argv[i])) {
243250 string_arg = JS_ToCString(ctx, argv[i++]);
244251 if (!string_arg)
245252 goto fail;
246− dbuf_printf_fun(&dbuf, fmtbuf, string_arg);
253+ int32_arg = unicode_from_utf8((uint8_t *)string_arg, UTF8_CHAR_LEN_MAX, &p);
247254 JS_FreeCString(ctx, string_arg);
248− break;
249−
250− case 'e':
251− case 'f':
252− case 'g':
253− case 'a':
254− case 'E':
255− case 'F':
256− case 'G':
257− case 'A':
258− if (i >= argc)
259− goto missing;
260− if (JS_ToFloat64(ctx, &double_arg, argv[i++]))
255+ } else {
256+ if (JS_ToInt32(ctx, &int32_arg, argv[i++]))
261257 goto fail;
262− dbuf_printf_fun(&dbuf, fmtbuf, double_arg);
263− break;
264−
265− case '%':
266− dbuf_putc(&dbuf, '%');
267− break;
258+ }
259+ /* handle utf-8 encoding explicitly */
260+ if ((unsigned)int32_arg > 0x10FFFF)
261+ int32_arg = 0xFFFD;
262+ /* ignore conversion flags, width and precision */
263+ len = unicode_to_utf8(cbuf, int32_arg);
264+ dbuf_put(&dbuf, cbuf, len);
265+ break;
266+
267+ case 'd':
268+ case 'i':
269+ case 'o':
270+ case 'u':
271+ case 'x':
272+ case 'X':
273+ if (i >= argc)
274+ goto missing;
275+ if (JS_ToInt64Ext(ctx, &int64_arg, argv[i++]))
276+ goto fail;
277+ if (mod == 'l') {
278+ /* 64 bit number */
279+#if defined(_WIN32)
280+ if (q >= fmtbuf + sizeof(fmtbuf) - 3)
281+ goto invalid;
282+ q[2] = q[-1];
283+ q[-1] = 'I';
284+ q[0] = '6';
285+ q[1] = '4';
286+ q[3] = '\0';
287+ dbuf_printf_fun(&dbuf, fmtbuf, (int64_t)int64_arg);
288+#else
289+ if (q >= fmtbuf + sizeof(fmtbuf) - 2)
290+ goto invalid;
291+ q[1] = q[-1];
292+ q[-1] = q[0] = 'l';
293+ q[2] = '\0';
294+ dbuf_printf_fun(&dbuf, fmtbuf, (long long)int64_arg);
295+#endif
296+ } else {
297+ dbuf_printf_fun(&dbuf, fmtbuf, (int)int64_arg);
298+ }
299+ break;
268300
269− default:
270− /* XXX: should support an extension mechanism */
271− invalid:
272− JS_ThrowTypeError(ctx, "invalid conversion specifier in format string");
301+ case 's':
302+ if (i >= argc)
303+ goto missing;
304+ /* XXX: handle strings containing null characters */
305+ string_arg = JS_ToCString(ctx, argv[i++]);
306+ if (!string_arg)
273307 goto fail;
274− missing:
275− JS_ThrowReferenceError(ctx, "missing argument for conversion specifier");
308+ dbuf_printf_fun(&dbuf, fmtbuf, string_arg);
309+ JS_FreeCString(ctx, string_arg);
310+ break;
311+
312+ case 'e':
313+ case 'f':
314+ case 'g':
315+ case 'a':
316+ case 'E':
317+ case 'F':
318+ case 'G':
319+ case 'A':
320+ if (i >= argc)
321+ goto missing;
322+ if (JS_ToFloat64(ctx, &double_arg, argv[i++]))
276323 goto fail;
277− }
324+ dbuf_printf_fun(&dbuf, fmtbuf, double_arg);
325+ break;
326+
327+ case '%':
328+ dbuf_putc(&dbuf, '%');
278329 break;
330+
331+ default:
332+ /* XXX: should support an extension mechanism */
333+ invalid:
334+ JS_ThrowTypeError(ctx, "invalid conversion specifier in format string");
335+ goto fail;
336+ missing:
337+ JS_ThrowReferenceError(ctx, "missing argument for conversion specifier");
338+ goto fail;
279339 }
280340 }
281341 JS_FreeCString(ctx, fmt_str);
@@ -593,6 +653,8 @@ static int get_bool_option(JSContext *ctx, BOOL *pbool, · 311 unmodified lines
593653 static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val,
594654 int argc, JSValueConst *argv)
595655 {
656+ JSRuntime *rt = JS_GetRuntime(ctx);
657+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
596658 const char *str;
597659 size_t len;
598660 JSValue ret;
@@ -610,7 +672,7 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val, · 11 unmodified lines
610672 str = JS_ToCStringLen(ctx, &len, argv[0]);
611673 if (!str)
612674 return JS_EXCEPTION;
613− if (++eval_script_recurse == 1) {
675+ if (!ts->recv_pipe && ++ts->eval_script_recurse == 1) {
614676 /* install the interrupt handler */
615677 JS_SetInterruptHandler(JS_GetRuntime(ctx), interrupt_handler, NULL);
616678 }
@@ -619,7 +681,7 @@ static JSValue js_evalScript(JSContext *ctx, JSValueConst this_val, · 2 unmodified lines
619681 flags |= JS_EVAL_FLAG_BACKTRACE_BARRIER;
620682 ret = JS_Eval(ctx, str, len, "<evalScript>", flags);
621683 JS_FreeCString(ctx, str);
622− if (--eval_script_recurse == 0) {
684+ if (!ts->recv_pipe && --ts->eval_script_recurse == 0) {
623685 /* remove the interrupt handler */
624686 JS_SetInterruptHandler(JS_GetRuntime(ctx), NULL, NULL);
625687 os_pending_signals &= ~((uint64_t)1 << SIGINT);
@@ -669,6 +731,21 @@ static JSValue js_std_strerror(JSContext *ctx, JSValueConst this_val, · 43 unmodified lines
669731 return JS_NewString(ctx, strerror(err));
670732 }
671733
734+static JSValue js_std_parseExtJSON(JSContext *ctx, JSValueConst this_val,
735+ int argc, JSValueConst *argv)
736+{
737+ JSValue obj;
738+ const char *str;
739+ size_t len;
740+
741+ str = JS_ToCStringLen(ctx, &len, argv[0]);
742+ if (!str)
743+ return JS_EXCEPTION;
744+ obj = JS_ParseJSON2(ctx, str, len, "<input>", JS_PARSE_JSON_EXT);
745+ JS_FreeCString(ctx, str);
746+ return obj;
747+}
748+
672749 static JSValue js_new_std_file(JSContext *ctx, FILE *f,
673750 BOOL close_in_finalizer,
674751 BOOL is_popen)
@@ -1321,6 +1398,7 @@ static const JSCFunctionListEntry js_std_funcs[] = { · 646 unmodified lines
13211398 JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
13221399 JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
13231400 JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
1401+ JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ),
13241402
13251403 /* FILE I/O */
13261404 JS_CFUNC_DEF("open", 2, js_std_open ),
@@ -1626,11 +1704,18 @@ static JSValue js_os_rename(JSContext *ctx, JSValueConst this_val, · 299 unmodified lines
16261704 return JS_NewInt32(ctx, ret);
16271705 }
16281706
1629−static JSOSRWHandler *find_rh(int fd)
1707+static BOOL is_main_thread(JSRuntime *rt)
1708+{
1709+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
1710+ return !ts->recv_pipe;
1711+}
1712+
1713+static JSOSRWHandler *find_rh(JSThreadState *ts, int fd)
16301714 {
16311715 JSOSRWHandler *rh;
16321716 struct list_head *el;
1633− list_for_each(el, &os_rw_handlers) {
1717+
1718+ list_for_each(el, &ts->os_rw_handlers) {
16341719 rh = list_entry(el, JSOSRWHandler, link);
16351720 if (rh->fd == fd)
16361721 return rh;
@@ -1651,6 +1736,8 @@ static void free_rw_handler(JSRuntime *rt, JSOSRWHandler *rh) · 14 unmodified lines
16511736 static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val,
16521737 int argc, JSValueConst *argv, int magic)
16531738 {
1739+ JSRuntime *rt = JS_GetRuntime(ctx);
1740+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
16541741 JSOSRWHandler *rh;
16551742 int fd;
16561743 JSValueConst func;
@@ -1659,7 +1746,7 @@ static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val, · 2 unmodified lines
16591746 return JS_EXCEPTION;
16601747 func = argv[1];
16611748 if (JS_IsNull(func)) {
1662− rh = find_rh(fd);
1749+ rh = find_rh(ts, fd);
16631750 if (rh) {
16641751 JS_FreeValue(ctx, rh->rw_func[magic]);
16651752 rh->rw_func[magic] = JS_NULL;
@@ -1672,7 +1759,7 @@ static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val, · 6 unmodified lines
16721759 } else {
16731760 if (!JS_IsFunction(ctx, func))
16741761 return JS_ThrowTypeError(ctx, "not a function");
1675− rh = find_rh(fd);
1762+ rh = find_rh(ts, fd);
16761763 if (!rh) {
16771764 rh = js_mallocz(ctx, sizeof(*rh));
16781765 if (!rh)
@@ -1680,7 +1767,7 @@ static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val, · 1 unmodified line
16801767 rh->fd = fd;
16811768 rh->rw_func[0] = JS_NULL;
16821769 rh->rw_func[1] = JS_NULL;
1683− list_add_tail(&rh->link, &os_rw_handlers);
1770+ list_add_tail(&rh->link, &ts->os_rw_handlers);
16841771 }
16851772 JS_FreeValue(ctx, rh->rw_func[magic]);
16861773 rh->rw_func[magic] = JS_DupValue(ctx, func);
@@ -1688,11 +1775,11 @@ static JSValue js_os_setReadHandler(JSContext *ctx, JSValueConst this_val, · 1 unmodified line
16881775 return JS_UNDEFINED;
16891776 }
16901777
1691−static JSOSSignalHandler *find_sh(int sig_num)
1778+static JSOSSignalHandler *find_sh(JSThreadState *ts, int sig_num)
16921779 {
16931780 JSOSSignalHandler *sh;
16941781 struct list_head *el;
1695− list_for_each(el, &os_signal_handlers) {
1782+ list_for_each(el, &ts->os_signal_handlers) {
16961783 sh = list_entry(el, JSOSSignalHandler, link);
16971784 if (sh->sig_num == sig_num)
16981785 return sh;
@@ -1719,10 +1806,15 @@ typedef void (*sighandler_t)(int sig_num); · 20 unmodified lines
17191806 static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,
17201807 int argc, JSValueConst *argv)
17211808 {
1809+ JSRuntime *rt = JS_GetRuntime(ctx);
1810+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
17221811 JSOSSignalHandler *sh;
17231812 uint32_t sig_num;
17241813 JSValueConst func;
17251814 sighandler_t handler;
1815+
1816+ if (!is_main_thread(rt))
1817+ return JS_ThrowTypeError(ctx, "signal handler can only be set in the main thread");
17261818
17271819 if (JS_ToUint32(ctx, &sig_num, argv[0]))
17281820 return JS_EXCEPTION;
@@ -1731,7 +1823,7 @@ static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val, · 2 unmodified lines
17311823 func = argv[1];
17321824 /* func = null: SIG_DFL, func = undefined, SIG_IGN */
17331825 if (JS_IsNull(func) || JS_IsUndefined(func)) {
1734− sh = find_sh(sig_num);
1826+ sh = find_sh(ts, sig_num);
17351827 if (sh) {
17361828 free_sh(JS_GetRuntime(ctx), sh);
17371829 }
@@ -1743,13 +1835,13 @@ static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val, · 5 unmodified lines
17431835 } else {
17441836 if (!JS_IsFunction(ctx, func))
17451837 return JS_ThrowTypeError(ctx, "not a function");
1746− sh = find_sh(sig_num);
1838+ sh = find_sh(ts, sig_num);
17471839 if (!sh) {
17481840 sh = js_mallocz(ctx, sizeof(*sh));
17491841 if (!sh)
17501842 return JS_EXCEPTION;
17511843 sh->sig_num = sig_num;
1752− list_add_tail(&sh->link, &os_signal_handlers);
1844+ list_add_tail(&sh->link, &ts->os_signal_handlers);
17531845 }
17541846 JS_FreeValue(ctx, sh->func);
17551847 sh->func = JS_DupValue(ctx, func);
@@ -1813,6 +1905,8 @@ static void js_os_timer_mark(JSRuntime *rt, JSValueConst val, · 57 unmodified lines
18131905 static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,
18141906 int argc, JSValueConst *argv)
18151907 {
1908+ JSRuntime *rt = JS_GetRuntime(ctx);
1909+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
18161910 int64_t delay;
18171911 JSValueConst func;
18181912 JSOSTimer *th;
@@ -1834,7 +1928,7 @@ static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val, · 15 unmodified lines
18341928 th->has_object = TRUE;
18351929 th->timeout = get_time_ms() + delay;
18361930 th->func = JS_DupValue(ctx, func);
1837− list_add_tail(&th->link, &os_timers);
1931+ list_add_tail(&th->link, &ts->os_timers);
18381932 JS_SetOpaque(obj, th);
18391933 return obj;
18401934 }
@@ -1872,6 +1966,8 @@ static void call_handler(JSContext *ctx, JSValueConst func) · 31 unmodified lines
18721966
18731967 static int js_os_poll(JSContext *ctx)
18741968 {
1969+ JSRuntime *rt = JS_GetRuntime(ctx);
1970+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
18751971 int min_delay, console_fd;
18761972 int64_t cur_time, delay;
18771973 JSOSRWHandler *rh;
@@ -1879,14 +1975,14 @@ static int js_os_poll(JSContext *ctx) · 1 unmodified line
18791975
18801976 /* XXX: handle signals if useful */
18811977
1882− if (list_empty(&os_rw_handlers) && list_empty(&os_timers))
1978+ if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers))
18831979 return -1; /* no more events */
18841980
18851981 /* XXX: only timers and basic console input are supported */
1886− if (!list_empty(&os_timers)) {
1982+ if (!list_empty(&ts->os_timers)) {
18871983 cur_time = get_time_ms();
18881984 min_delay = 10000;
1889− list_for_each(el, &os_timers) {
1985+ list_for_each(el, &ts->os_timers) {
18901986 JSOSTimer *th = list_entry(el, JSOSTimer, link);
18911987 delay = th->timeout - cur_time;
18921988 if (delay <= 0) {
@@ -1894,9 +1990,9 @@ static int js_os_poll(JSContext *ctx) · 1 unmodified line
18941990 /* the timer expired */
18951991 func = th->func;
18961992 th->func = JS_UNDEFINED;
1897− unlink_timer(JS_GetRuntime(ctx), th);
1993+ unlink_timer(rt, th);
18981994 if (!th->has_object)
1899− free_timer(JS_GetRuntime(ctx), th);
1995+ free_timer(rt, th);
19001996 call_handler(ctx, func);
19011997 JS_FreeValue(ctx, func);
19021998 return 0;
@@ -1909,7 +2005,7 @@ static int js_os_poll(JSContext *ctx) · 6 unmodified lines
19092005 }
19102006
19112007 console_fd = -1;
1912− list_for_each(el, &os_rw_handlers) {
2008+ list_for_each(el, &ts->os_rw_handlers) {
19132009 rh = list_entry(el, JSOSRWHandler, link);
19142010 if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
19152011 console_fd = rh->fd;
@@ -1927,7 +2023,7 @@ static int js_os_poll(JSContext *ctx) · 11 unmodified lines
19272023 handle = (HANDLE)_get_osfhandle(console_fd);
19282024 ret = WaitForSingleObject(handle, ti);
19292025 if (ret == WAIT_OBJECT_0) {
1930− list_for_each(el, &os_rw_handlers) {
2026+ list_for_each(el, &ts->os_rw_handlers) {
19312027 rh = list_entry(el, JSOSRWHandler, link);
19322028 if (rh->fd == console_fd && !JS_IsNull(rh->rw_func[0])) {
19332029 call_handler(ctx, rh->rw_func[0]);
@@ -1942,8 +2038,88 @@ static int js_os_poll(JSContext *ctx) · 8 unmodified lines
19422038 return 0;
19432039 }
19442040 #else
2041+
2042+#ifdef USE_WORKER
2043+
2044+static void js_free_message(JSWorkerMessage *msg);
2045+
2046+/* return 1 if a message was handled, 0 if no message */
2047+static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
2048+ JSWorkerMessageHandler *port)
2049+{
2050+ JSWorkerMessagePipe *ps = port->recv_pipe;
2051+ int ret;
2052+ struct list_head *el;
2053+ JSWorkerMessage *msg;
2054+ JSValue obj, data_obj, func, retval;
2055+
2056+ pthread_mutex_lock(&ps->mutex);
2057+ if (!list_empty(&ps->msg_queue)) {
2058+ el = ps->msg_queue.next;
2059+ msg = list_entry(el, JSWorkerMessage, link);
2060+
2061+ /* remove the message from the queue */
2062+ list_del(&msg->link);
2063+
2064+ if (list_empty(&ps->msg_queue)) {
2065+ uint8_t buf[16];
2066+ int ret;
2067+ for(;;) {
2068+ ret = read(ps->read_fd, buf, sizeof(buf));
2069+ if (ret >= 0)
2070+ break;
2071+ if (errno != EAGAIN && errno != EINTR)
2072+ break;
2073+ }
2074+ }
2075+
2076+ pthread_mutex_unlock(&ps->mutex);
2077+
2078+ data_obj = JS_ReadObject(ctx, msg->data, msg->data_len,
2079+ JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE);
2080+
2081+ js_free_message(msg);
2082+
2083+ if (JS_IsException(data_obj))
2084+ goto fail;
2085+ obj = JS_NewObject(ctx);
2086+ if (JS_IsException(obj)) {
2087+ JS_FreeValue(ctx, data_obj);
2088+ goto fail;
2089+ }
2090+ JS_DefinePropertyValueStr(ctx, obj, "data", data_obj, JS_PROP_C_W_E);
2091+
2092+ /* 'func' might be destroyed when calling itself (if it frees the
2093+ handler), so must take extra care */
2094+ func = JS_DupValue(ctx, port->on_message_func);
2095+ retval = JS_Call(ctx, func, JS_UNDEFINED, 1, (JSValueConst *)&obj);
2096+ JS_FreeValue(ctx, obj);
2097+ JS_FreeValue(ctx, func);
2098+ if (JS_IsException(retval)) {
2099+ fail:
2100+ js_std_dump_error(ctx);
2101+ } else {
2102+ JS_FreeValue(ctx, retval);
2103+ }
2104+ ret = 1;
2105+ } else {
2106+ pthread_mutex_unlock(&ps->mutex);
2107+ ret = 0;
2108+ }
2109+ return ret;
2110+}
2111+#else
2112+static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
2113+ JSWorkerMessageHandler *port)
2114+{
2115+ return 0;
2116+}
2117+#endif
2118+
19452119 static int js_os_poll(JSContext *ctx)
19462120 {
2121+ JSRuntime *rt = JS_GetRuntime(ctx);
2122+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
19472123 int ret, fd_max, min_delay;
19482124 int64_t cur_time, delay;
19492125 fd_set rfds, wfds;
@@ -1951,11 +2127,13 @@ static int js_os_poll(JSContext *ctx) · 1 unmodified line
19512127 struct list_head *el;
19522128 struct timeval tv, *tvp;
19532129
1954− if (unlikely(os_pending_signals != 0)) {
2130+ /* only check signals in the main thread */
2131+ if (!ts->recv_pipe &&
2132+ unlikely(os_pending_signals != 0)) {
19552133 JSOSSignalHandler *sh;
19562134 uint64_t mask;
19572135
1958− list_for_each(el, &os_signal_handlers) {
2136+ list_for_each(el, &ts->os_signal_handlers) {
19592137 sh = list_entry(el, JSOSSignalHandler, link);
19602138 mask = (uint64_t)1 << sh->sig_num;
19612139 if (os_pending_signals & mask) {
@@ -1965,14 +2143,15 @@ static int js_os_poll(JSContext *ctx) · 3 unmodified lines
19652143 }
19662144 }
19672145 }
1968−
1969− if (list_empty(&os_rw_handlers) && list_empty(&os_timers))
2146+
2147+ if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
2148+ list_empty(&ts->port_list))
19702149 return -1; /* no more events */
19712150
1972− if (!list_empty(&os_timers)) {
2151+ if (!list_empty(&ts->os_timers)) {
19732152 cur_time = get_time_ms();
19742153 min_delay = 10000;
1975− list_for_each(el, &os_timers) {
2154+ list_for_each(el, &ts->os_timers) {
19762155 JSOSTimer *th = list_entry(el, JSOSTimer, link);
19772156 delay = th->timeout - cur_time;
19782157 if (delay <= 0) {
@@ -1980,9 +2159,9 @@ static int js_os_poll(JSContext *ctx) · 1 unmodified line
19802159 /* the timer expired */
19812160 func = th->func;
19822161 th->func = JS_UNDEFINED;
1983− unlink_timer(JS_GetRuntime(ctx), th);
2162+ unlink_timer(rt, th);
19842163 if (!th->has_object)
1985− free_timer(JS_GetRuntime(ctx), th);
2164+ free_timer(rt, th);
19862165 call_handler(ctx, func);
19872166 JS_FreeValue(ctx, func);
19882167 return 0;
@@ -2000,7 +2179,7 @@ static int js_os_poll(JSContext *ctx) · 11 unmodified lines
20002179 FD_ZERO(&rfds);
20012180 FD_ZERO(&wfds);
20022181 fd_max = -1;
2003− list_for_each(el, &os_rw_handlers) {
2182+ list_for_each(el, &ts->os_rw_handlers) {
20042183 rh = list_entry(el, JSOSRWHandler, link);
20052184 fd_max = max_int(fd_max, rh->fd);
20062185 if (!JS_IsNull(rh->rw_func[0]))
@@ -2008,25 +2187,46 @@ static int js_os_poll(JSContext *ctx) · 1 unmodified line
20082187 if (!JS_IsNull(rh->rw_func[1]))
20092188 FD_SET(rh->fd, &wfds);
20102189 }
2011−
2190+
2191+ list_for_each(el, &ts->port_list) {
2192+ JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
2193+ if (!JS_IsNull(port->on_message_func)) {
2194+ JSWorkerMessagePipe *ps = port->recv_pipe;
2195+ fd_max = max_int(fd_max, ps->read_fd);
2196+ FD_SET(ps->read_fd, &rfds);
2197+ }
2198+ }
2199+
20122200 ret = select(fd_max + 1, &rfds, &wfds, NULL, tvp);
20132201 if (ret > 0) {
2014− list_for_each(el, &os_rw_handlers) {
2202+ list_for_each(el, &ts->os_rw_handlers) {
20152203 rh = list_entry(el, JSOSRWHandler, link);
20162204 if (!JS_IsNull(rh->rw_func[0]) &&
20172205 FD_ISSET(rh->fd, &rfds)) {
20182206 call_handler(ctx, rh->rw_func[0]);
20192207 /* must stop because the list may have been modified */
2020− break;
2208+ goto done;
20212209 }
2022− if (!JS_IsNull(rh->rw_func[1])) {
2023− FD_SET(rh->fd, &wfds);
2210+ if (!JS_IsNull(rh->rw_func[1]) &&
2211+ FD_ISSET(rh->fd, &wfds)) {
20242212 call_handler(ctx, rh->rw_func[1]);
20252213 /* must stop because the list may have been modified */
2026− break;
2214+ goto done;
2215+ }
2216+ }
2217+
2218+ list_for_each(el, &ts->port_list) {
2219+ JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
2220+ if (!JS_IsNull(port->on_message_func)) {
2221+ JSWorkerMessagePipe *ps = port->recv_pipe;
2222+ if (FD_ISSET(ps->read_fd, &rfds)) {
2223+ if (handle_posted_message(rt, ctx, port))
2224+ goto done;
2225+ }
20272226 }
20282227 }
20292228 }
2229+ done:
20302230 return 0;
20312231 }
20322232 #endif /* !_WIN32 */
@@ -2071,8 +2271,6 @@ static JSValue js_os_getcwd(JSContext *ctx, JSValueConst this_val, · 38 unmodified lines
20712271 return make_string_error(ctx, buf, err);
20722272 }
20732273
2074−#if !defined(_WIN32)
2075−
20762274 static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val,
20772275 int argc, JSValueConst *argv)
20782276 {
@@ -2087,28 +2285,6 @@ static JSValue js_os_chdir(JSContext *ctx, JSValueConst this_val, · 8 unmodified lines
20872285 return JS_NewInt32(ctx, err);
20882286 }
20892287
2090−/* return [path, errorcode] */
2091−static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
2092− int argc, JSValueConst *argv)
2093−{
2094− const char *path;
2095− char buf[PATH_MAX], *res;
2096− int err;
2097−
2098− path = JS_ToCString(ctx, argv[0]);
2099− if (!path)
2100− return JS_EXCEPTION;
2101− res = realpath(path, buf);
2102− JS_FreeCString(ctx, path);
2103− if (!res) {
2104− buf[0] = '\0';
2105− err = errno;
2106− } else {
2107− err = 0;
2108− }
2109− return make_string_error(ctx, buf, err);
2110−}
2111−
21122288 static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val,
21132289 int argc, JSValueConst *argv)
21142290 {
@@ -2124,15 +2300,66 @@ static JSValue js_os_mkdir(JSContext *ctx, JSValueConst this_val, · 9 unmodified lines
21242300 path = JS_ToCString(ctx, argv[0]);
21252301 if (!path)
21262302 return JS_EXCEPTION;
2303+#if defined(_WIN32)
2304+ (void)mode;
2305+ ret = js_get_errno(mkdir(path));
2306+#else
21272307 ret = js_get_errno(mkdir(path, mode));
2308+#endif
21282309 JS_FreeCString(ctx, path);
21292310 return JS_NewInt32(ctx, ret);
21302311 }
21312312
2313+/* return [array, errorcode] */
2314+static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
2315+ int argc, JSValueConst *argv)
2316+{
2317+ const char *path;
2318+ DIR *f;
2319+ struct dirent *d;
2320+ JSValue obj;
2321+ int err;
2322+ uint32_t len;
2323+
2324+ path = JS_ToCString(ctx, argv[0]);
2325+ if (!path)
2326+ return JS_EXCEPTION;
2327+ obj = JS_NewArray(ctx);
2328+ if (JS_IsException(obj)) {
2329+ JS_FreeCString(ctx, path);
2330+ return JS_EXCEPTION;
2331+ }
2332+ f = opendir(path);
2333+ if (!f)
2334+ err = errno;
2335+ else
2336+ err = 0;
2337+ JS_FreeCString(ctx, path);
2338+ if (!f)
2339+ goto done;
2340+ len = 0;
2341+ for(;;) {
2342+ errno = 0;
2343+ d = readdir(f);
2344+ if (!d) {
2345+ err = errno;
2346+ break;
2347+ }
2348+ JS_DefinePropertyValueUint32(ctx, obj, len++,
2349+ JS_NewString(ctx, d->d_name),
2350+ JS_PROP_C_W_E);
2351+ }
2352+ closedir(f);
2353+ done:
2354+ return make_obj_error(ctx, obj, err);
2355+}
2356+
2357+#if !defined(_WIN32)
21322358 static int64_t timespec_to_ms(const struct timespec *tv)
21332359 {
21342360 return (int64_t)tv->tv_sec * 1000 + (tv->tv_nsec / 1000000);
21352361 }
2362+#endif
21362363
21372364 /* return [obj, errcode] */
21382365 static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val,
@@ -2146,10 +2373,14 @@ static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val, · 7 unmodified lines
21462373 path = JS_ToCString(ctx, argv[0]);
21472374 if (!path)
21482375 return JS_EXCEPTION;
2376+#if defined(_WIN32)
2377+ res = stat(path, &st);
2378+#else
21492379 if (is_lstat)
21502380 res = lstat(path, &st);
21512381 else
21522382 res = stat(path, &st);
2383+#endif
21532384 JS_FreeCString(ctx, path);
21542385 if (res < 0) {
21552386 err = errno;
@@ -2183,10 +2414,22 @@ static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val, · 27 unmodified lines
21832414 JS_DefinePropertyValueStr(ctx, obj, "size",
21842415 JS_NewInt64(ctx, st.st_size),
21852416 JS_PROP_C_W_E);
2417+#if !defined(_WIN32)
21862418 JS_DefinePropertyValueStr(ctx, obj, "blocks",
21872419 JS_NewInt64(ctx, st.st_blocks),
21882420 JS_PROP_C_W_E);
2189−#if defined(__APPLE__)
2421+#endif
2422+#if defined(_WIN32)
2423+ JS_DefinePropertyValueStr(ctx, obj, "atime",
2424+ JS_NewInt64(ctx, (int64_t)st.st_atime * 1000),
2425+ JS_PROP_C_W_E);
2426+ JS_DefinePropertyValueStr(ctx, obj, "mtime",
2427+ JS_NewInt64(ctx, (int64_t)st.st_mtime * 1000),
2428+ JS_PROP_C_W_E);
2429+ JS_DefinePropertyValueStr(ctx, obj, "ctime",
2430+ JS_NewInt64(ctx, (int64_t)st.st_ctime * 1000),
2431+ JS_PROP_C_W_E);
2432+#elif defined(__APPLE__)
21902433 JS_DefinePropertyValueStr(ctx, obj, "atime",
21912434 JS_NewInt64(ctx, timespec_to_ms(&st.st_atimespec)),
21922435 JS_PROP_C_W_E);
@@ -2211,120 +2454,113 @@ static JSValue js_os_stat(JSContext *ctx, JSValueConst this_val, · 18 unmodified lines
22112454 return make_obj_error(ctx, obj, err);
22122455 }
22132456
2214−static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
2215− int argc, JSValueConst *argv)
2457+#if !defined(_WIN32)
2458+static void ms_to_timeval(struct timeval *tv, uint64_t v)
22162459 {
2217− const char *target, *linkpath;
2218− int err;
2219−
2220− target = JS_ToCString(ctx, argv[0]);
2221− if (!target)
2222− return JS_EXCEPTION;
2223− linkpath = JS_ToCString(ctx, argv[1]);
2224− if (!linkpath) {
2225− JS_FreeCString(ctx, target);
2226− return JS_EXCEPTION;
2227− }
2228− err = js_get_errno(symlink(target, linkpath));
2229− JS_FreeCString(ctx, target);
2230− JS_FreeCString(ctx, linkpath);
2231− return JS_NewInt32(ctx, err);
2460+ tv->tv_sec = v / 1000;
2461+ tv->tv_usec = (v % 1000) * 1000;
22322462 }
2463+#endif
22332464
2234−/* return [path, errorcode] */
2235−static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
2236− int argc, JSValueConst *argv)
2465+static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
2466+ int argc, JSValueConst *argv)
22372467 {
22382468 const char *path;
2239− char buf[PATH_MAX];
2240− int err;
2241− ssize_t res;
2469+ int64_t atime, mtime;
2470+ int ret;
22422471
2472+ if (JS_ToInt64(ctx, &atime, argv[1]))
2473+ return JS_EXCEPTION;
2474+ if (JS_ToInt64(ctx, &mtime, argv[2]))
2475+ return JS_EXCEPTION;
22432476 path = JS_ToCString(ctx, argv[0]);
22442477 if (!path)
22452478 return JS_EXCEPTION;
2246− res = readlink(path, buf, sizeof(buf) - 1);
2247− if (res < 0) {
2248− buf[0] = '\0';
2249− err = errno;
2250− } else {
2251− buf[res] = '\0';
2252− err = 0;
2479+#if defined(_WIN32)
2480+ {
2481+ struct _utimbuf times;
2482+ times.actime = atime / 1000;
2483+ times.modtime = mtime / 1000;
2484+ ret = js_get_errno(_utime(path, &times));
2485+ }
2486+#else
2487+ {
2488+ struct timeval times[2];
2489+ ms_to_timeval(&times[0], atime);
2490+ ms_to_timeval(&times[1], mtime);
2491+ ret = js_get_errno(utimes(path, times));
22532492 }
2493+#endif
22542494 JS_FreeCString(ctx, path);
2255− return make_string_error(ctx, buf, err);
2495+ return JS_NewInt32(ctx, ret);
22562496 }
22572497
2258−/* return [array, errorcode] */
2259−static JSValue js_os_readdir(JSContext *ctx, JSValueConst this_val,
2260− int argc, JSValueConst *argv)
2498+#if !defined(_WIN32)
2499+
2500+/* return [path, errorcode] */
2501+static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
2502+ int argc, JSValueConst *argv)
22612503 {
22622504 const char *path;
2263− DIR *f;
2264− struct dirent *d;
2265− JSValue obj;
2505+ char buf[PATH_MAX], *res;
22662506 int err;
2267− uint32_t len;
2268−
2507+
22692508 path = JS_ToCString(ctx, argv[0]);
22702509 if (!path)
22712510 return JS_EXCEPTION;
2272− obj = JS_NewArray(ctx);
2273− if (JS_IsException(obj)) {
2274− JS_FreeCString(ctx, path);
2275− return JS_EXCEPTION;
2276− }
2277− f = opendir(path);
2278− if (!f)
2511+ res = realpath(path, buf);
2512+ JS_FreeCString(ctx, path);
2513+ if (!res) {
2514+ buf[0] = '\0';
22792515 err = errno;
2280− else
2516+ } else {
22812517 err = 0;
2282− JS_FreeCString(ctx, path);
2283− if (!f)
2284− goto done;
2285− len = 0;
2286− for(;;) {
2287− errno = 0;
2288− d = readdir(f);
2289− if (!d) {
2290− err = errno;
2291− break;
2292− }
2293− JS_DefinePropertyValueUint32(ctx, obj, len++,
2294− JS_NewString(ctx, d->d_name),
2295− JS_PROP_C_W_E);
22962518 }
2297− closedir(f);
2298− done:
2299− return make_obj_error(ctx, obj, err);
2519+ return make_string_error(ctx, buf, err);
23002520 }
23012521
2302−static void ms_to_timeval(struct timeval *tv, uint64_t v)
2522+static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
2523+ int argc, JSValueConst *argv)
23032524 {
2304− tv->tv_sec = v / 1000;
2305− tv->tv_usec = (v % 1000) * 1000;
2525+ const char *target, *linkpath;
2526+ int err;
2527+
2528+ target = JS_ToCString(ctx, argv[0]);
2529+ if (!target)
2530+ return JS_EXCEPTION;
2531+ linkpath = JS_ToCString(ctx, argv[1]);
2532+ if (!linkpath) {
2533+ JS_FreeCString(ctx, target);
2534+ return JS_EXCEPTION;
2535+ }
2536+ err = js_get_errno(symlink(target, linkpath));
2537+ JS_FreeCString(ctx, target);
2538+ JS_FreeCString(ctx, linkpath);
2539+ return JS_NewInt32(ctx, err);
23062540 }
23072541
2308−static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
2309− int argc, JSValueConst *argv)
2542+/* return [path, errorcode] */
2543+static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
2544+ int argc, JSValueConst *argv)
23102545 {
23112546 const char *path;
2312− int64_t atime, mtime;
2313− int ret;
2314− struct timeval times[2];
2547+ char buf[PATH_MAX];
2548+ int err;
2549+ ssize_t res;
23152550
2316− if (JS_ToInt64(ctx, &atime, argv[1]))
2317− return JS_EXCEPTION;
2318− if (JS_ToInt64(ctx, &mtime, argv[2]))
2319− return JS_EXCEPTION;
23202551 path = JS_ToCString(ctx, argv[0]);
23212552 if (!path)
23222553 return JS_EXCEPTION;
2323− ms_to_timeval(&times[0], atime);
2324− ms_to_timeval(&times[1], mtime);
2325− ret = js_get_errno(utimes(path, times));
2554+ res = readlink(path, buf, sizeof(buf) - 1);
2555+ if (res < 0) {
2556+ buf[0] = '\0';
2557+ err = errno;
2558+ } else {
2559+ buf[res] = '\0';
2560+ err = 0;
2561+ }
23262562 JS_FreeCString(ctx, path);
2327− return JS_NewInt32(ctx, ret);
2563+ return make_string_error(ctx, buf, err);
23282564 }
23292565
23302566 static char **build_envp(JSContext *ctx, JSValueConst obj)
@@ -2404,7 +2640,7 @@ static int my_execvpe(const char *filename, char **argv, char **envp) · 73 unmodified lines
24042640
24052641 path = getenv("PATH");
24062642 if (!path)
2407− path = "/bin:/usr/bin";
2643+ path = (char *)"/bin:/usr/bin";
24082644 eacces_error = FALSE;
24092645 p = path;
24102646 for(p = path; p != NULL; p = p_next) {
@@ -2746,6 +2982,441 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val, · 335 unmodified lines
27462982
27472983 #endif /* !_WIN32 */
27482984
2985+#ifdef USE_WORKER
2986+
2987+/* Worker */
2988+
2989+typedef struct {
2990+ JSWorkerMessagePipe *recv_pipe;
2991+ JSWorkerMessagePipe *send_pipe;
2992+ JSWorkerMessageHandler *msg_handler;
2993+} JSWorkerData;
2994+
2995+typedef struct {
2996+ /* source code of the worker */
2997+ char *eval_buf;
2998+ size_t eval_buf_len;
2999+ JSWorkerMessagePipe *recv_pipe, *send_pipe;
3000+} WorkerFuncArgs;
3001+
3002+typedef struct {
3003+ int ref_count;
3004+ uint64_t buf[0];
3005+} JSSABHeader;
3006+
3007+static JSClassID js_worker_class_id;
3008+
3009+static int atomic_add_int(int *ptr, int v)
3010+{
3011+ return atomic_fetch_add((_Atomic(uint32_t) *)ptr, v) + v;
3012+}
3013+
3014+/* shared array buffer allocator */
3015+static void *js_sab_alloc(void *opaque, size_t size)
3016+{
3017+ JSSABHeader *sab;
3018+ sab = malloc(sizeof(JSSABHeader) + size);
3019+ if (!sab)
3020+ return NULL;
3021+ sab->ref_count = 1;
3022+ return sab->buf;
3023+}
3024+
3025+static void js_sab_free(void *opaque, void *ptr)
3026+{
3027+ JSSABHeader *sab;
3028+ int ref_count;
3029+ sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
3030+ ref_count = atomic_add_int(&sab->ref_count, -1);
3031+ assert(ref_count >= 0);
3032+ if (ref_count == 0) {
3033+ free(sab);
3034+ }
3035+}
3036+
3037+static void js_sab_dup(void *opaque, void *ptr)
3038+{
3039+ JSSABHeader *sab;
3040+ sab = (JSSABHeader *)((uint8_t *)ptr - sizeof(JSSABHeader));
3041+ atomic_add_int(&sab->ref_count, 1);
3042+}
3043+
3044+static JSWorkerMessagePipe *js_new_message_pipe(void)
3045+{
3046+ JSWorkerMessagePipe *ps;
3047+ int pipe_fds[2];
3048+
3049+ if (pipe(pipe_fds) < 0)
3050+ return NULL;
3051+
3052+ ps = malloc(sizeof(*ps));
3053+ if (!ps) {
3054+ close(pipe_fds[0]);
3055+ close(pipe_fds[1]);
3056+ return NULL;
3057+ }
3058+ ps->ref_count = 1;
3059+ init_list_head(&ps->msg_queue);
3060+ pthread_mutex_init(&ps->mutex, NULL);
3061+ ps->read_fd = pipe_fds[0];
3062+ ps->write_fd = pipe_fds[1];
3063+ return ps;
3064+}
3065+
3066+static JSWorkerMessagePipe *js_dup_message_pipe(JSWorkerMessagePipe *ps)
3067+{
3068+ atomic_add_int(&ps->ref_count, 1);
3069+ return ps;
3070+}
3071+
3072+static void js_free_message(JSWorkerMessage *msg)
3073+{
3074+ size_t i;
3075+ /* free the SAB */
3076+ for(i = 0; i < msg->sab_tab_len; i++) {
3077+ js_sab_free(NULL, msg->sab_tab[i]);
3078+ }
3079+ free(msg->sab_tab);
3080+ free(msg->data);
3081+ free(msg);
3082+}
3083+
3084+static void js_free_message_pipe(JSWorkerMessagePipe *ps)
3085+{
3086+ struct list_head *el, *el1;
3087+ JSWorkerMessage *msg;
3088+ int ref_count;
3089+
3090+ if (!ps)
3091+ return;
3092+
3093+ ref_count = atomic_add_int(&ps->ref_count, -1);
3094+ assert(ref_count >= 0);
3095+ if (ref_count == 0) {
3096+ list_for_each_safe(el, el1, &ps->msg_queue) {
3097+ msg = list_entry(el, JSWorkerMessage, link);
3098+ js_free_message(msg);
3099+ }
3100+ pthread_mutex_destroy(&ps->mutex);
3101+ close(ps->read_fd);
3102+ close(ps->write_fd);
3103+ free(ps);
3104+ }
3105+}
3106+
3107+static void js_free_port(JSRuntime *rt, JSWorkerMessageHandler *port)
3108+{
3109+ if (port) {
3110+ js_free_message_pipe(port->recv_pipe);
3111+ JS_FreeValueRT(rt, port->on_message_func);
3112+ list_del(&port->link);
3113+ js_free_rt(rt, port);
3114+ }
3115+}
3116+
3117+static void js_worker_finalizer(JSRuntime *rt, JSValue val)
3118+{
3119+ JSWorkerData *worker = JS_GetOpaque(val, js_worker_class_id);
3120+ if (worker) {
3121+ js_free_message_pipe(worker->recv_pipe);
3122+ js_free_message_pipe(worker->send_pipe);
3123+ js_free_port(rt, worker->msg_handler);
3124+ js_free_rt(rt, worker);
3125+ }
3126+}
3127+
3128+static JSClassDef js_worker_class = {
3129+ "Worker",
3130+ .finalizer = js_worker_finalizer,
3131+};
3132+
3133+static void *worker_func(void *opaque)
3134+{
3135+ WorkerFuncArgs *args = opaque;
3136+ JSRuntime *rt;
3137+ JSThreadState *ts;
3138+ JSContext *ctx;
3139+ JSValue retval;
3140+
3141+ rt = JS_NewRuntime();
3142+ if (rt == NULL) {
3143+ fprintf(stderr, "JS_NewRuntime failure");
3144+ exit(1);
3145+ }
3146+ js_std_init_handlers(rt);
3147+
3148+ /* set the pipe to communicate with the parent */
3149+ ts = JS_GetRuntimeOpaque(rt);
3150+ ts->recv_pipe = args->recv_pipe;
3151+ ts->send_pipe = args->send_pipe;
3152+
3153+ ctx = JS_NewContext(rt);
3154+ if (ctx == NULL) {
3155+ fprintf(stderr, "JS_NewContext failure");
3156+ }
3157+
3158+ JS_SetCanBlock(rt, TRUE);
3159+
3160+ js_std_add_helpers(ctx, -1, NULL);
3161+
3162+ /* system modules */
3163+ js_init_module_std(ctx, "std");
3164+ js_init_module_os(ctx, "os");
3165+
3166+ retval = JS_Eval(ctx, args->eval_buf, args->eval_buf_len,
3167+ "<worker>", JS_EVAL_TYPE_MODULE);
3168+ free(args->eval_buf);
3169+ free(args);
3170+
3171+ if (JS_IsException(retval))
3172+ js_std_dump_error(ctx);
3173+ JS_FreeValue(ctx, retval);
3174+
3175+ js_std_loop(ctx);
3176+
3177+ JS_FreeContext(ctx);
3178+ js_std_free_handlers(rt);
3179+ JS_FreeRuntime(rt);
3180+ return NULL;
3181+}
3182+
3183+static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target,
3184+ JSWorkerMessagePipe *recv_pipe,
3185+ JSWorkerMessagePipe *send_pipe)
3186+{
3187+ JSValue obj = JS_UNDEFINED, proto;
3188+ JSWorkerData *s;
3189+
3190+ /* create the object */
3191+ if (JS_IsUndefined(new_target)) {
3192+ proto = JS_GetClassProto(ctx, js_worker_class_id);
3193+ } else {
3194+ proto = JS_GetPropertyStr(ctx, new_target, "prototype");
3195+ if (JS_IsException(proto))
3196+ goto fail;
3197+ }
3198+ obj = JS_NewObjectProtoClass(ctx, proto, js_worker_class_id);
3199+ JS_FreeValue(ctx, proto);
3200+ if (JS_IsException(obj))
3201+ goto fail;
3202+ s = js_mallocz(ctx, sizeof(*s));
3203+ if (!s)
3204+ goto fail;
3205+ s->recv_pipe = js_dup_message_pipe(recv_pipe);
3206+ s->send_pipe = js_dup_message_pipe(send_pipe);
3207+
3208+ JS_SetOpaque(obj, s);
3209+ return obj;
3210+ fail:
3211+ JS_FreeValue(ctx, obj);
3212+ return JS_EXCEPTION;
3213+}
3214+
3215+static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
3216+ int argc, JSValueConst *argv)
3217+{
3218+ JSRuntime *rt = JS_GetRuntime(ctx);
3219+ WorkerFuncArgs *args;
3220+ const char *str;
3221+ size_t str_len;
3222+ pthread_t tid;
3223+ pthread_attr_t attr;
3224+ JSValue obj = JS_UNDEFINED;
3225+ int ret;
3226+
3227+ /* XXX: in order to avoid problems with resource liberation, we
3228+ don't support creating workers inside workers */
3229+ if (!is_main_thread(rt))
3230+ return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker");
3231+
3232+ /* script source */
3233+
3234+ str = JS_ToCStringLen(ctx, &str_len, argv[0]);
3235+ if (!str)
3236+ return JS_EXCEPTION;
3237+
3238+ args = malloc(sizeof(*args));
3239+ if (!args) {
3240+ JS_ThrowOutOfMemory(ctx);
3241+ goto fail;
3242+ }
3243+ memset(args, 0, sizeof(*args));
3244+ args->eval_buf = malloc(str_len + 1);
3245+ if (!args->eval_buf) {
3246+ JS_ThrowOutOfMemory(ctx);
3247+ goto fail;
3248+ }
3249+ memcpy(args->eval_buf, str, str_len + 1);
3250+ args->eval_buf_len = str_len;
3251+ JS_FreeCString(ctx, str);
3252+ str = NULL;
3253+
3254+ /* ports */
3255+ args->recv_pipe = js_new_message_pipe();
3256+ if (!args->recv_pipe)
3257+ goto fail;
3258+ args->send_pipe = js_new_message_pipe();
3259+ if (!args->send_pipe)
3260+ goto fail;
3261+
3262+ obj = js_worker_ctor_internal(ctx, new_target,
3263+ args->send_pipe, args->recv_pipe);
3264+ if (JS_IsUndefined(obj))
3265+ goto fail;
3266+
3267+ pthread_attr_init(&attr);
3268+ /* no join at the end */
3269+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
3270+ ret = pthread_create(&tid, &attr, worker_func, args);
3271+ pthread_attr_destroy(&attr);
3272+ if (ret != 0) {
3273+ JS_ThrowTypeError(ctx, "could not create worker");
3274+ goto fail;
3275+ }
3276+ return obj;
3277+ fail:
3278+ JS_FreeCString(ctx, str);
3279+ if (args) {
3280+ free(args->eval_buf);
3281+ js_free_message_pipe(args->recv_pipe);
3282+ js_free_message_pipe(args->send_pipe);
3283+ free(args);
3284+ }
3285+ JS_FreeValue(ctx, obj);
3286+ return JS_EXCEPTION;
3287+}
3288+
3289+static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
3290+ int argc, JSValueConst *argv)
3291+{
3292+ JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
3293+ JSWorkerMessagePipe *ps;
3294+ size_t data_len, sab_tab_len, i;
3295+ uint8_t *data;
3296+ JSWorkerMessage *msg;
3297+ uint8_t **sab_tab;
3298+
3299+ if (!worker)
3300+ return JS_EXCEPTION;
3301+
3302+ data = JS_WriteObject2(ctx, &data_len, argv[0],
3303+ JS_WRITE_OBJ_SAB | JS_WRITE_OBJ_REFERENCE,
3304+ &sab_tab, &sab_tab_len);
3305+ if (!data)
3306+ return JS_EXCEPTION;
3307+
3308+ msg = malloc(sizeof(*msg));
3309+ if (!msg)
3310+ goto fail;
3311+ msg->data = NULL;
3312+ msg->sab_tab = NULL;
3313+
3314+ /* must reallocate because the allocator may be different */
3315+ msg->data = malloc(data_len);
3316+ if (!msg->data)
3317+ goto fail;
3318+ memcpy(msg->data, data, data_len);
3319+ msg->data_len = data_len;
3320+
3321+ msg->sab_tab = malloc(sizeof(msg->sab_tab[0]) * sab_tab_len);
3322+ if (!msg->sab_tab)
3323+ goto fail;
3324+ memcpy(msg->sab_tab, sab_tab, sizeof(msg->sab_tab[0]) * sab_tab_len);
3325+ msg->sab_tab_len = sab_tab_len;
3326+
3327+ js_free(ctx, data);
3328+ js_free(ctx, sab_tab);
3329+
3330+ /* increment the SAB reference counts */
3331+ for(i = 0; i < msg->sab_tab_len; i++) {
3332+ js_sab_dup(NULL, msg->sab_tab[i]);
3333+ }
3334+
3335+ ps = worker->send_pipe;
3336+ pthread_mutex_lock(&ps->mutex);
3337+ /* indicate that data is present */
3338+ if (list_empty(&ps->msg_queue)) {
3339+ uint8_t ch = '\0';
3340+ int ret;
3341+ for(;;) {
3342+ ret = write(ps->write_fd, &ch, 1);
3343+ if (ret == 1)
3344+ break;
3345+ if (ret < 0 && (errno != EAGAIN || errno != EINTR))
3346+ break;
3347+ }
3348+ }
3349+ list_add_tail(&msg->link, &ps->msg_queue);
3350+ pthread_mutex_unlock(&ps->mutex);
3351+ return JS_UNDEFINED;
3352+ fail:
3353+ if (msg) {
3354+ free(msg->data);
3355+ free(msg->sab_tab);
3356+ free(msg);
3357+ }
3358+ js_free(ctx, data);
3359+ js_free(ctx, sab_tab);
3360+ return JS_EXCEPTION;
3361+
3362+}
3363+
3364+static JSValue js_worker_set_onmessage(JSContext *ctx, JSValueConst this_val,
3365+ JSValueConst func)
3366+{
3367+ JSRuntime *rt = JS_GetRuntime(ctx);
3368+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
3369+ JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
3370+ JSWorkerMessageHandler *port;
3371+
3372+ if (!worker)
3373+ return JS_EXCEPTION;
3374+
3375+ port = worker->msg_handler;
3376+ if (JS_IsNull(func)) {
3377+ if (port) {
3378+ js_free_port(rt, port);
3379+ worker->msg_handler = NULL;
3380+ }
3381+ } else {
3382+ if (!JS_IsFunction(ctx, func))
3383+ return JS_ThrowTypeError(ctx, "not a function");
3384+ if (!port) {
3385+ port = js_mallocz(ctx, sizeof(*port));
3386+ if (!port)
3387+ return JS_EXCEPTION;
3388+ port->recv_pipe = js_dup_message_pipe(worker->recv_pipe);
3389+ port->on_message_func = JS_NULL;
3390+ list_add_tail(&port->link, &ts->port_list);
3391+ worker->msg_handler = port;
3392+ }
3393+ JS_FreeValue(ctx, port->on_message_func);
3394+ port->on_message_func = JS_DupValue(ctx, func);
3395+ }
3396+ return JS_UNDEFINED;
3397+}
3398+
3399+static JSValue js_worker_get_onmessage(JSContext *ctx, JSValueConst this_val)
3400+{
3401+ JSWorkerData *worker = JS_GetOpaque2(ctx, this_val, js_worker_class_id);
3402+ JSWorkerMessageHandler *port;
3403+ if (!worker)
3404+ return JS_EXCEPTION;
3405+ port = worker->msg_handler;
3406+ if (port) {
3407+ return JS_DupValue(ctx, port->on_message_func);
3408+ } else {
3409+ return JS_NULL;
3410+ }
3411+}
3412+
3413+static const JSCFunctionListEntry js_worker_proto_funcs[] = {
3414+ JS_CFUNC_DEF("postMessage", 1, js_worker_postMessage ),
3415+ JS_CGETSET_DEF("onmessage", js_worker_get_onmessage, js_worker_set_onmessage ),
3416+};
3417+
3418+#endif /* USE_WORKER */
3419+
27493420 #if defined(_WIN32)
27503421 #define OS_PLATFORM "win32"
27513422 #elif defined(__APPLE__)
@@ -2806,12 +3477,9 @@ static const JSCFunctionListEntry js_os_funcs[] = { · 54 unmodified lines
28063477 JS_CFUNC_DEF("clearTimeout", 1, js_os_clearTimeout ),
28073478 JS_PROP_STRING_DEF("platform", OS_PLATFORM, 0 ),
28083479 JS_CFUNC_DEF("getcwd", 0, js_os_getcwd ),
2809−#if !defined(_WIN32)
28103480 JS_CFUNC_DEF("chdir", 0, js_os_chdir ),
2811− JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
28123481 JS_CFUNC_DEF("mkdir", 1, js_os_mkdir ),
2813− JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
2814− JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
3482+ JS_CFUNC_DEF("readdir", 1, js_os_readdir ),
28153483 /* st_mode constants */
28163484 OS_FLAG(S_IFMT),
28173485 OS_FLAG(S_IFIFO),
@@ -2819,14 +3487,19 @@ static const JSCFunctionListEntry js_os_funcs[] = { · 1 unmodified line
28193487 OS_FLAG(S_IFDIR),
28203488 OS_FLAG(S_IFBLK),
28213489 OS_FLAG(S_IFREG),
3490+#if !defined(_WIN32)
28223491 OS_FLAG(S_IFSOCK),
28233492 OS_FLAG(S_IFLNK),
28243493 OS_FLAG(S_ISGID),
28253494 OS_FLAG(S_ISUID),
3495+#endif
3496+ JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
3497+ JS_CFUNC_DEF("utimes", 3, js_os_utimes ),
3498+#if !defined(_WIN32)
3499+ JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
3500+ JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
28263501 JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
28273502 JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
2828− JS_CFUNC_DEF("readdir", 1, js_os_readdir ),
2829− JS_CFUNC_DEF("utimes", 3, js_os_utimes ),
28303503 JS_CFUNC_DEF("exec", 1, js_os_exec ),
28313504 JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ),
28323505 OS_FLAG(WNOHANG),
@@ -2845,7 +3518,35 @@ static int js_os_init(JSContext *ctx, JSModuleDef *m) · 12 unmodified lines
28453518 /* OSTimer class */
28463519 JS_NewClassID(&js_os_timer_class_id);
28473520 JS_NewClass(JS_GetRuntime(ctx), js_os_timer_class_id, &js_os_timer_class);
2848−
3521+
3522+#ifdef USE_WORKER
3523+ {
3524+ JSRuntime *rt = JS_GetRuntime(ctx);
3525+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
3526+ JSValue proto, obj;
3527+ /* Worker class */
3528+ JS_NewClassID(&js_worker_class_id);
3529+ JS_NewClass(JS_GetRuntime(ctx), js_worker_class_id, &js_worker_class);
3530+ proto = JS_NewObject(ctx);
3531+ JS_SetPropertyFunctionList(ctx, proto, js_worker_proto_funcs, countof(js_worker_proto_funcs));
3532+
3533+ obj = JS_NewCFunction2(ctx, js_worker_ctor, "Worker", 1,
3534+ JS_CFUNC_constructor, 0);
3535+ JS_SetConstructor(ctx, obj, proto);
3536+
3537+ JS_SetClassProto(ctx, js_worker_class_id, proto);
3538+
3539+ /* set 'Worker.parent' if necessary */
3540+ if (ts->recv_pipe && ts->send_pipe) {
3541+ JS_DefinePropertyValueStr(ctx, obj, "parent",
3542+ js_worker_ctor_internal(ctx, JS_UNDEFINED, ts->recv_pipe, ts->send_pipe),
3543+ JS_PROP_C_W_E);
3544+ }
3545+
3546+ JS_SetModuleExport(ctx, m, "Worker", obj);
3547+ }
3548+#endif /* USE_WORKER */
3549+
28493550 return JS_SetModuleExportList(ctx, m, js_os_funcs,
28503551 countof(js_os_funcs));
28513552 }
@@ -2857,6 +3558,9 @@ JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name) · 5 unmodified lines
28573558 if (!m)
28583559 return NULL;
28593560 JS_AddModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));
3561+#ifdef USE_WORKER
3562+ JS_AddModuleExport(ctx, m, "Worker");
3563+#endif
28603564 return m;
28613565 }
28623566
@@ -2896,46 +3600,76 @@ void js_std_add_helpers(JSContext *ctx, int argc, char **argv) · 33 unmodified lines
28963600 JS_SetPropertyStr(ctx, global_obj, "console", console);
28973601
28983602 /* same methods as the mozilla JS shell */
2899− args = JS_NewArray(ctx);
2900− for(i = 0; i < argc; i++) {
2901− JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i]));
3603+ if (argc >= 0) {
3604+ args = JS_NewArray(ctx);
3605+ for(i = 0; i < argc; i++) {
3606+ JS_SetPropertyUint32(ctx, args, i, JS_NewString(ctx, argv[i]));
3607+ }
3608+ JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args);
29023609 }
2903− JS_SetPropertyStr(ctx, global_obj, "scriptArgs", args);
2904−
3610+
29053611 JS_SetPropertyStr(ctx, global_obj, "print",
29063612 JS_NewCFunction(ctx, js_print, "print", 1));
29073613 JS_SetPropertyStr(ctx, global_obj, "__loadScript",
29083614 JS_NewCFunction(ctx, js_loadScript, "__loadScript", 1));
29093615
29103616 JS_FreeValue(ctx, global_obj);
3617+}
3618+
3619+void js_std_init_handlers(JSRuntime *rt)
3620+{
3621+ JSThreadState *ts;
3622+
3623+ ts = malloc(sizeof(*ts));
3624+ if (!ts) {
3625+ fprintf(stderr, "Could not allocate memory for the worker");
3626+ exit(1);
3627+ }
3628+ memset(ts, 0, sizeof(*ts));
3629+ init_list_head(&ts->os_rw_handlers);
3630+ init_list_head(&ts->os_signal_handlers);
3631+ init_list_head(&ts->os_timers);
3632+ init_list_head(&ts->port_list);
3633+
3634+ JS_SetRuntimeOpaque(rt, ts);
29113635
2912− /* XXX: not multi-context */
2913− init_list_head(&os_rw_handlers);
2914− init_list_head(&os_signal_handlers);
2915− init_list_head(&os_timers);
2916− os_pending_signals = 0;
3636+#ifdef USE_WORKER
3637+ /* set the SharedArrayBuffer memory handlers */
3638+ {
3639+ JSSharedArrayBufferFunctions sf;
3640+ memset(&sf, 0, sizeof(sf));
3641+ sf.sab_alloc = js_sab_alloc;
3642+ sf.sab_free = js_sab_free;
3643+ sf.sab_dup = js_sab_dup;
3644+ JS_SetSharedArrayBufferFunctions(rt, &sf);
3645+ }
3646+#endif
29173647 }
29183648
29193649 void js_std_free_handlers(JSRuntime *rt)
29203650 {
3651+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
29213652 struct list_head *el, *el1;
29223653
2923− list_for_each_safe(el, el1, &os_rw_handlers) {
3654+ list_for_each_safe(el, el1, &ts->os_rw_handlers) {
29243655 JSOSRWHandler *rh = list_entry(el, JSOSRWHandler, link);
29253656 free_rw_handler(rt, rh);
29263657 }
29273658
2928− list_for_each_safe(el, el1, &os_signal_handlers) {
3659+ list_for_each_safe(el, el1, &ts->os_signal_handlers) {
29293660 JSOSSignalHandler *sh = list_entry(el, JSOSSignalHandler, link);
29303661 free_sh(rt, sh);
29313662 }
29323663
2933− list_for_each_safe(el, el1, &os_timers) {
3664+ list_for_each_safe(el, el1, &ts->os_timers) {
29343665 JSOSTimer *th = list_entry(el, JSOSTimer, link);
29353666 unlink_timer(rt, th);
29363667 if (!th->has_object)
29373668 free_timer(rt, th);
29383669 }
3670+
3671+ free(ts);
3672+ JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
29393673 }
29403674
29413675 static void js_dump_obj(JSContext *ctx, FILE *f, JSValueConst val)
quickjs-libc.h+9−0
@@ -29,10 +29,15 @@ · 28 unmodified lines
2929
3030 #include "quickjs.h"
3131
32+#ifdef __cplusplus
33+extern "C" {
34+#endif
35+
3236 JSModuleDef *js_init_module_std(JSContext *ctx, const char *module_name);
3337 JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name);
3438 void js_std_add_helpers(JSContext *ctx, int argc, char **argv);
3539 void js_std_loop(JSContext *ctx);
40+void js_std_init_handlers(JSRuntime *rt);
3641 void js_std_free_handlers(JSRuntime *rt);
3742 void js_std_dump_error(JSContext *ctx);
3843 uint8_t *js_load_file(JSContext *ctx, size_t *pbuf_len, const char *filename);
@@ -46,4 +51,8 @@ void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise, · 7 unmodified lines
4651 JSValueConst reason,
4752 JS_BOOL is_handled, void *opaque);
4853
54+#ifdef __cplusplus
55+} /* extern "C" { */
56+#endif
57+
4958 #endif /* QUICKJS_LIBC_H */
quickjs.c+2058−1253
@@ -71,6 +71,12 @@ · 70 unmodified lines
7171 #define CONFIG_ATOMICS
7272 #endif
7373
74+#if !defined(EMSCRIPTEN)
75+/* enable stack limitation */
76+#define CONFIG_STACK_CHECK
77+#endif
78+
79+
7480 /* dump object free */
7581 //#define DUMP_FREE
7682 //#define DUMP_CLOSURE
@@ -281,7 +287,9 @@ struct JSRuntime { · 204 unmodified lines
281287 void *module_loader_opaque;
282288
283289 BOOL can_block : 8; /* TRUE if Atomics.wait can block */
284−
290+ /* used to allocate, free and clone SharedArrayBuffers */
291+ JSSharedArrayBufferFunctions sab_funcs;
292+
285293 /* Shape hash table */
286294 int shape_hash_bits;
287295 int shape_hash_size;
@@ -392,7 +400,7 @@ typedef struct JSBigDecimal { · 104 unmodified lines
392400 typedef enum {
393401 JS_AUTOINIT_ID_PROTOTYPE,
394402 JS_AUTOINIT_ID_MODULE_NS,
395− JS_AUTOINIT_ID_PROP, /* must be last */
403+ JS_AUTOINIT_ID_PROP,
396404 } JSAutoInitIDEnum;
397405
398406 /* must be large enough to have a negligible runtime cost and small
@@ -625,7 +633,6 @@ typedef struct JSRegExp { · 226 unmodified lines
625633 typedef struct JSProxyData {
626634 JSValue target;
627635 JSValue handler;
628− JSValue proto;
629636 uint8_t is_func;
630637 uint8_t is_revoked;
631638 } JSProxyData;
@@ -770,6 +777,7 @@ struct JSModuleDef { · 138 unmodified lines
770777 JSValue func_obj; /* only used for JS modules */
771778 JSModuleInitFunc *init_func; /* only used for C modules */
772779 BOOL resolved : 8;
780+ BOOL func_created : 8;
773781 BOOL instantiated : 8;
774782 BOOL evaluated : 8;
775783 BOOL eval_mark : 8; /* temporary use during js_evaluate_module() */
@@ -799,10 +807,8 @@ typedef struct JSProperty { · 23 unmodified lines
799807 struct { /* JS_PROP_AUTOINIT */
800808 /* in order to use only 2 pointers, we compress the realm
801809 and the init function pointer */
802− union {
803− JSContext *realm; /* for JS_AUTOINIT_ID_PROP */
804− uintptr_t init_id; /* JS_AUTOINIT_ID_x */
805− } u;
810+ uintptr_t realm_and_id; /* realm and init_id (JS_AUTOINIT_ID_x)
811+ in the 2 low bits */
806812 void *opaque;
807813 } init;
808814 } u;
@@ -832,11 +838,13 @@ struct JSShape { · 23 unmodified lines
832838 uint32_t hash; /* current hash value */
833839 uint32_t prop_hash_mask;
834840 int prop_size; /* allocated properties */
835− int prop_count;
841+ int prop_count; /* include deleted properties */
842+ int deleted_prop_count;
836843 JSShape *shape_hash_next; /* in JSRuntime.shape_hash[h] list */
837844 JSObject *proto;
838845 JSShapeProperty prop[0]; /* prop_size elements */
839846 };
847+
840848 struct JSObject {
841849 union {
842850 JSGCObjectHeader header;
@@ -850,7 +858,6 @@ struct JSObject { · 7 unmodified lines
850858 uint8_t fast_array : 1; /* TRUE if u.array is used for get/put */
851859 uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
852860 uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
853− uint8_t is_class : 1; /* TRUE if object is a class constructor */
854861 uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
855862 uint16_t class_id; /* see JS_CLASS_x */
856863 };
@@ -1124,7 +1131,7 @@ static bfdec_t *JS_ToBigDecimal(JSContext *ctx, JSValueConst val); · 267 unmodified lines
11241131 #endif
11251132 JSValue JS_ThrowOutOfMemory(JSContext *ctx);
11261133 static JSValue JS_ThrowTypeErrorRevokedProxy(JSContext *ctx);
1127−static JSValueConst js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
1134+static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj);
11281135 static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
11291136 JSValueConst proto_val, BOOL throw_flag);
11301137 static int js_proxy_isExtensible(JSContext *ctx, JSValueConst obj);
@@ -1136,6 +1143,17 @@ static int JS_CreateProperty(JSContext *ctx, JSObject *p, · 5 unmodified lines
11361143 int flags);
11371144 static int js_string_memcmp(const JSString *p1, const JSString *p2, int len);
11381145 static void reset_weak_ref(JSRuntime *rt, JSObject *p);
1146+static JSValue js_array_buffer_constructor3(JSContext *ctx,
1147+ JSValueConst new_target,
1148+ uint64_t len, JSClassID class_id,
1149+ uint8_t *buf,
1150+ JSFreeArrayBufferDataFunc *free_func,
1151+ void *opaque, BOOL alloc_flag);
1152+static JSArrayBuffer *js_get_array_buffer(JSContext *ctx, JSValueConst obj);
1153+static JSValue js_typed_array_constructor(JSContext *ctx,
1154+ JSValueConst this_val,
1155+ int argc, JSValueConst *argv,
1156+ int classid);
11391157 static BOOL typed_array_is_detached(JSContext *ctx, JSObject *p);
11401158 static uint32_t typed_array_get_length(JSContext *ctx, JSObject *p);
11411159 static JSValue JS_ThrowTypeErrorDetachedArrayBuffer(JSContext *ctx);
@@ -1212,6 +1230,7 @@ static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom, · 70 unmodified lines
12121230 void *opaque);
12131231 static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
12141232 JSAtom atom, void *opaque);
1233+void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag);
12151234
12161235 static const JSClassExoticMethods js_arguments_exotic_methods;
12171236 static const JSClassExoticMethods js_string_exotic_methods;
@@ -1361,6 +1380,33 @@ char *js_strdup(JSContext *ctx, const char *str) · 143 unmodified lines
13611380 return js_strndup(ctx, str, strlen(str));
13621381 }
13631382
1383+static no_inline int js_realloc_array(JSContext *ctx, void **parray,
1384+ int elem_size, int *psize, int req_size)
1385+{
1386+ int new_size;
1387+ size_t slack;
1388+ void *new_array;
1389+ /* XXX: potential arithmetic overflow */
1390+ new_size = max_int(req_size, *psize * 3 / 2);
1391+ new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
1392+ if (!new_array)
1393+ return -1;
1394+ new_size += slack / elem_size;
1395+ *psize = new_size;
1396+ *parray = new_array;
1397+ return 0;
1398+}
1399+
1400+/* resize the array and update its size if req_size > *psize */
1401+static inline int js_resize_array(JSContext *ctx, void **parray, int elem_size,
1402+ int *psize, int req_size)
1403+{
1404+ if (unlikely(req_size > *psize))
1405+ return js_realloc_array(ctx, parray, elem_size, psize, req_size);
1406+ else
1407+ return 0;
1408+}
1409+
13641410 static inline void js_dbuf_init(JSContext *ctx, DynBuf *s)
13651411 {
13661412 dbuf_init2(s, ctx->rt, (DynBufReallocFunc *)js_realloc_rt);
@@ -1379,7 +1425,7 @@ typedef struct JSClassShortDef { · 12 unmodified lines
13791425 static JSClassShortDef const js_std_class_def[] = {
13801426 { JS_ATOM_Object, NULL, NULL }, /* JS_CLASS_OBJECT */
13811427 { JS_ATOM_Array, js_array_finalizer, js_array_mark }, /* JS_CLASS_ARRAY */
1382− { JS_ATOM_Error, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_ERROR */
1428+ { JS_ATOM_Error, NULL, NULL }, /* JS_CLASS_ERROR */
13831429 { JS_ATOM_Number, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_NUMBER */
13841430 { JS_ATOM_String, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_STRING */
13851431 { JS_ATOM_Boolean, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BOOLEAN */
@@ -1426,7 +1472,7 @@ static JSClassShortDef const js_std_class_def[] = { · 40 unmodified lines
14261472 { JS_ATOM_Set_Iterator, js_map_iterator_finalizer, js_map_iterator_mark }, /* JS_CLASS_SET_ITERATOR */
14271473 { JS_ATOM_Array_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_ARRAY_ITERATOR */
14281474 { JS_ATOM_String_Iterator, js_array_iterator_finalizer, js_array_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
1429− { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_STRING_ITERATOR */
1475+ { JS_ATOM_RegExp_String_Iterator, js_regexp_string_iterator_finalizer, js_regexp_string_iterator_mark }, /* JS_CLASS_REGEXP_STRING_ITERATOR */
14301476 { JS_ATOM_Generator, js_generator_finalizer, js_generator_mark }, /* JS_CLASS_GENERATOR */
14311477 };
14321478
@@ -1505,8 +1551,8 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops) · 72 unmodified lines
15051551
15061552 #endif /* CONFIG_BIGNUM */
15071553
1508−#if defined(EMSCRIPTEN)
1509−/* currently no stack limitation */
1554+#if !defined(CONFIG_STACK_CHECK)
1555+/* no stack limitation */
15101556 static inline uint8_t *js_get_stack_pointer(void)
15111557 {
15121558 return NULL;
@@ -1729,6 +1775,12 @@ void JS_SetCanBlock(JSRuntime *rt, BOOL can_block) · 216 unmodified lines
17291775 rt->can_block = can_block;
17301776 }
17311777
1778+void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
1779+ const JSSharedArrayBufferFunctions *sf)
1780+{
1781+ rt->sab_funcs = *sf;
1782+}
1783+
17321784 /* return 0 if OK, < 0 if exception */
17331785 int JS_EnqueueJob(JSContext *ctx, JSJobFunc *job_func,
17341786 int argc, JSValueConst *argv)
@@ -4262,9 +4314,10 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, · 2527 unmodified lines
42624314 memset(sh->prop_hash_end - hash_size, 0, sizeof(sh->prop_hash_end[0]) *
42634315 hash_size);
42644316 sh->prop_hash_mask = hash_size - 1;
4265− sh->prop_count = 0;
42664317 sh->prop_size = prop_size;
4267−
4318+ sh->prop_count = 0;
4319+ sh->deleted_prop_count = 0;
4320+
42684321 /* insert in the hash table */
42694322 sh->hash = shape_initial_hash(proto);
42704323 sh->is_hashed = TRUE;
@@ -4415,6 +4468,74 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, · 144 unmodified lines
44154468 return 0;
44164469 }
44174470
4471+/* remove the deleted properties. */
4472+static int compact_properties(JSContext *ctx, JSObject *p)
4473+{
4474+ JSShape *sh, *old_sh;
4475+ void *sh_alloc;
4476+ intptr_t h;
4477+ uint32_t new_hash_size, i, j, new_hash_mask, new_size;
4478+ JSShapeProperty *old_pr, *pr;
4479+ JSProperty *prop, *new_prop;
4480+
4481+ sh = p->shape;
4482+ assert(!sh->is_hashed);
4483+
4484+ new_size = max_int(JS_PROP_INITIAL_SIZE,
4485+ sh->prop_count - sh->deleted_prop_count);
4486+ assert(new_size <= sh->prop_size);
4487+
4488+ new_hash_size = sh->prop_hash_mask + 1;
4489+ while ((new_hash_size / 2) >= new_size)
4490+ new_hash_size = new_hash_size / 2;
4491+ new_hash_mask = new_hash_size - 1;
4492+
4493+ /* resize the hash table and the properties */
4494+ old_sh = sh;
4495+ sh_alloc = js_malloc(ctx, get_shape_size(new_hash_size, new_size));
4496+ if (!sh_alloc)
4497+ return -1;
4498+ sh = get_shape_from_alloc(sh_alloc, new_hash_size);
4499+ list_del(&old_sh->header.link);
4500+ memcpy(sh, old_sh, sizeof(JSShape));
4501+ list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list);
4502+
4503+ memset(sh->prop_hash_end - new_hash_size, 0,
4504+ sizeof(sh->prop_hash_end[0]) * new_hash_size);
4505+
4506+ j = 0;
4507+ old_pr = old_sh->prop;
4508+ pr = sh->prop;
4509+ prop = p->prop;
4510+ for(i = 0; i < sh->prop_count; i++) {
4511+ if (old_pr->atom != JS_ATOM_NULL) {
4512+ pr->atom = old_pr->atom;
4513+ pr->flags = old_pr->flags;
4514+ h = ((uintptr_t)old_pr->atom & new_hash_mask);
4515+ pr->hash_next = sh->prop_hash_end[-h - 1];
4516+ sh->prop_hash_end[-h - 1] = j + 1;
4517+ prop[j] = prop[i];
4518+ j++;
4519+ pr++;
4520+ }
4521+ old_pr++;
4522+ }
4523+ assert(j == (sh->prop_count - sh->deleted_prop_count));
4524+ sh->prop_hash_mask = new_hash_mask;
4525+ sh->prop_size = new_size;
4526+ sh->deleted_prop_count = 0;
4527+ sh->prop_count = j;
4528+
4529+ p->shape = sh;
4530+ js_free(ctx, get_alloc_from_shape(old_sh));
4531+
4532+ /* reduce the size of the object properties */
4533+ new_prop = js_realloc(ctx, p->prop, sizeof(new_prop[0]) * new_size);
4534+ if (new_prop)
4535+ p->prop = new_prop;
4536+ return 0;
4537+}
4538+
44184539 static int add_shape_property(JSContext *ctx, JSShape **psh,
44194540 JSObject *p, JSAtom atom, int prop_flags)
44204541 {
@@ -4571,7 +4692,6 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas · 150 unmodified lines
45714692 p->fast_array = 0;
45724693 p->is_constructor = 0;
45734694 p->is_uncatchable_error = 0;
4574− p->is_class = 0;
45754695 p->tmp_mark = 0;
45764696 p->first_weak_ref = NULL;
45774697 p->u.opaque = NULL;
@@ -4621,7 +4741,6 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas · 43 unmodified lines
46214741 p->u.array.u.ptr = NULL;
46224742 p->u.array.count = 0;
46234743 break;
4624− case JS_CLASS_ERROR:
46254744 case JS_CLASS_NUMBER:
46264745 case JS_CLASS_STRING:
46274746 case JS_CLASS_BOOLEAN:
@@ -4967,19 +5086,25 @@ JSValue JS_NewCFunctionData(JSContext *ctx, JSCFunctionData *func, · 339 unmodified lines
49675086 return func_obj;
49685087 }
49695088
5089+static JSContext *js_autoinit_get_realm(JSProperty *pr)
5090+{
5091+ return (JSContext *)(pr->u.init.realm_and_id & ~3);
5092+}
5093+
5094+static JSAutoInitIDEnum js_autoinit_get_id(JSProperty *pr)
5095+{
5096+ return pr->u.init.realm_and_id & 3;
5097+}
5098+
49705099 static void js_autoinit_free(JSRuntime *rt, JSProperty *pr)
49715100 {
4972− if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) {
4973− JS_FreeContext(pr->u.init.u.realm);
4974− }
5101+ JS_FreeContext(js_autoinit_get_realm(pr));
49755102 }
49765103
49775104 static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
49785105 JS_MarkFunc *mark_func)
49795106 {
4980− if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) {
4981− mark_func(rt, &pr->u.init.u.realm->header);
4982− }
5107+ mark_func(rt, &js_autoinit_get_realm(pr)->header);
49835108 }
49845109
49855110 static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
@@ -6331,7 +6456,7 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, · 1345 unmodified lines
63316456 backtrace_barrier = FALSE;
63326457 if (js_class_has_bytecode(p->class_id)) {
63336458 JSFunctionBytecode *b;
6334− char atom_buf[ATOM_GET_STR_BUF_SIZE];
6459+ const char *atom_str;
63356460 int line_num1;
63366461
63376462 b = p->u.func.function_bytecode;
@@ -6339,9 +6464,10 @@ static void build_backtrace(JSContext *ctx, JSValueConst error_obj, · 1 unmodified line
63396464 if (b->has_debug) {
63406465 line_num1 = find_line_num(ctx, b,
63416466 sf->cur_pc - b->byte_code_buf - 1);
6467+ atom_str = JS_AtomToCString(ctx, b->debug.filename);
63426468 dbuf_printf(&dbuf, " (%s",
6343− JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf),
6344− b->debug.filename));
6469+ atom_str ? atom_str : "<null>");
6470+ JS_FreeCString(ctx, atom_str);
63456471 if (line_num1 != -1)
63466472 dbuf_printf(&dbuf, ":%d", line_num1);
63476473 dbuf_putc(&dbuf, ')');
@@ -6459,13 +6585,32 @@ static int __attribute__((format(printf, 3, 4))) JS_ThrowTypeErrorOrFalse(JSCont · 111 unmodified lines
64596585 }
64606586 }
64616587
6588+/* never use it directly */
6589+static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowTypeErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
6590+{
6591+ char buf[ATOM_GET_STR_BUF_SIZE];
6592+ return JS_ThrowTypeError(ctx, fmt,
6593+ JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6594+}
6595+
6596+/* never use it directly */
6597+static JSValue __attribute__((format(printf, 3, 4))) __JS_ThrowSyntaxErrorAtom(JSContext *ctx, JSAtom atom, const char *fmt, ...)
6598+{
6599+ char buf[ATOM_GET_STR_BUF_SIZE];
6600+ return JS_ThrowSyntaxError(ctx, fmt,
6601+ JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6602+}
6603+
6604+/* %s is replaced by 'atom'. The macro is used so that gcc can check
6605+ the format string. */
6606+#define JS_ThrowTypeErrorAtom(ctx, fmt, atom) __JS_ThrowTypeErrorAtom(ctx, atom, fmt, "")
6607+#define JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) __JS_ThrowSyntaxErrorAtom(ctx, atom, fmt, "")
6608+
64626609 static int JS_ThrowTypeErrorReadOnly(JSContext *ctx, int flags, JSAtom atom)
64636610 {
64646611 if ((flags & JS_PROP_THROW) ||
64656612 ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
6466− char buf[ATOM_GET_STR_BUF_SIZE];
6467− JS_ThrowTypeError(ctx, "%s is read-only",
6468− JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
6613+ JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
64696614 return -1;
64706615 } else {
64716616 return FALSE;
@@ -6534,7 +6679,7 @@ static JSValue JS_ThrowTypeErrorNotASymbol(JSContext *ctx) · 62 unmodified lines
65346679 static JSValue JS_ThrowReferenceErrorNotDefined(JSContext *ctx, JSAtom name)
65356680 {
65366681 char buf[ATOM_GET_STR_BUF_SIZE];
6537− return JS_ThrowReferenceError(ctx, "%s is not defined",
6682+ return JS_ThrowReferenceError(ctx, "'%s' is not defined",
65386683 JS_AtomGetStr(ctx, buf, sizeof(buf), name));
65396684 }
65406685
@@ -6549,11 +6694,33 @@ static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name) · 8 unmodified lines
65496694 static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
65506695 {
65516696 JSRuntime *rt = ctx->rt;
6552− char buf[ATOM_GET_STR_BUF_SIZE];
65536697 JSAtom name;
65546698 name = rt->class_array[class_id].class_name;
6555− return JS_ThrowTypeError(ctx, "%s object expected",
6556− JS_AtomGetStr(ctx, buf, sizeof(buf), name));
6699+ return JS_ThrowTypeErrorAtom(ctx, "%s object expected", name);
6700+}
6701+
6702+static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
6703+{
6704+ JSRuntime *rt = ctx->rt;
6705+ ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
6706+ if (rt->interrupt_handler) {
6707+ if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
6708+ /* XXX: should set a specific flag to avoid catching */
6709+ JS_ThrowInternalError(ctx, "interrupted");
6710+ JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
6711+ return -1;
6712+ }
6713+ }
6714+ return 0;
6715+}
6716+
6717+static inline __exception int js_poll_interrupts(JSContext *ctx)
6718+{
6719+ if (unlikely(--ctx->interrupt_counter <= 0)) {
6720+ return __js_poll_interrupts(ctx);
6721+ } else {
6722+ return 0;
6723+ }
65576724 }
65586725
65596726 /* return -1 (exception) or TRUE/FALSE */
@@ -6633,11 +6800,9 @@ int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val) · 73 unmodified lines
66336800 return JS_SetPrototypeInternal(ctx, obj, proto_val, TRUE);
66346801 }
66356802
6636−/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
6637−JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val)
6803+/* Only works for primitive types, otherwise return JS_NULL. */
6804+static JSValueConst JS_GetPrototypePrimitive(JSContext *ctx, JSValueConst val)
66386805 {
6639− JSObject *p;
6640−
66416806 switch(JS_VALUE_GET_NORM_TAG(val)) {
66426807 #ifdef CONFIG_BIGNUM
66436808 case JS_TAG_BIG_INT:
@@ -6664,26 +6829,45 @@ JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val) · 20 unmodified lines
66646829 val = ctx->class_proto[JS_CLASS_SYMBOL];
66656830 break;
66666831 case JS_TAG_OBJECT:
6667− p = JS_VALUE_GET_OBJ(val);
6832+ case JS_TAG_NULL:
6833+ case JS_TAG_UNDEFINED:
6834+ default:
6835+ val = JS_NULL;
6836+ break;
6837+ }
6838+ return val;
6839+}
6840+
6841+/* Return an Object, JS_NULL or JS_EXCEPTION in case of Proxy object. */
6842+JSValue JS_GetPrototype(JSContext *ctx, JSValueConst obj)
6843+{
6844+ JSValue val;
6845+ if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
6846+ JSObject *p;
6847+ p = JS_VALUE_GET_OBJ(obj);
66686848 if (unlikely(p->class_id == JS_CLASS_PROXY)) {
6669− val = js_proxy_getPrototypeOf(ctx, val);
6849+ val = js_proxy_getPrototypeOf(ctx, obj);
66706850 } else {
66716851 p = p->shape->proto;
66726852 if (!p)
66736853 val = JS_NULL;
66746854 else
6675− val = JS_MKPTR(JS_TAG_OBJECT, p);
6855+ val = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
66766856 }
6677− break;
6678− case JS_TAG_NULL:
6679− case JS_TAG_UNDEFINED:
6680− default:
6681− val = JS_NULL;
6682− break;
6857+ } else {
6858+ val = JS_DupValue(ctx, JS_GetPrototypePrimitive(ctx, obj));
66836859 }
66846860 return val;
66856861 }
66866862
6863+static JSValue JS_GetPrototypeFree(JSContext *ctx, JSValue obj)
6864+{
6865+ JSValue obj1;
6866+ obj1 = JS_GetPrototype(ctx, obj);
6867+ JS_FreeValue(ctx, obj);
6868+ return obj1;
6869+}
6870+
66876871 /* return TRUE, FALSE or (-1) in case of exception */
66886872 static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val,
66896873 JSValueConst obj)
@@ -6704,7 +6888,6 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, · 14 unmodified lines
67046888 /* Only explicitly boxed values are instances of constructors */
67056889 if (JS_VALUE_GET_TAG(val) != JS_TAG_OBJECT)
67066890 return FALSE;
6707− ret = FALSE;
67086891 obj_proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
67096892 if (JS_VALUE_GET_TAG(obj_proto) != JS_TAG_OBJECT) {
67106893 if (!JS_IsException(obj_proto))
@@ -6717,19 +6900,36 @@ static int JS_OrdinaryIsInstanceOf(JSContext *ctx, JSValueConst val, · 6 unmodified lines
67176900 for(;;) {
67186901 proto1 = p->shape->proto;
67196902 if (!proto1) {
6720− if (p->class_id == JS_CLASS_PROXY) {
6721− JSValueConst proto_val;
6722− proto_val = JS_GetPrototype(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
6723− if (JS_IsException(proto_val)) {
6724− ret = -1;
6725− goto done;
6903+ /* slow case if proxy in the prototype chain */
6904+ if (unlikely(p->class_id == JS_CLASS_PROXY)) {
6905+ JSValue obj1;
6906+ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, (JSObject *)p));
6907+ for(;;) {
6908+ obj1 = JS_GetPrototypeFree(ctx, obj1);
6909+ if (JS_IsException(obj1)) {
6910+ ret = -1;
6911+ break;
6912+ }
6913+ if (JS_IsNull(obj1)) {
6914+ ret = FALSE;
6915+ break;
6916+ }
6917+ if (proto == JS_VALUE_GET_OBJ(obj1)) {
6918+ JS_FreeValue(ctx, obj1);
6919+ ret = TRUE;
6920+ break;
6921+ }
6922+ /* must check for timeout to avoid infinite loop */
6923+ if (js_poll_interrupts(ctx)) {
6924+ JS_FreeValue(ctx, obj1);
6925+ ret = -1;
6926+ break;
6927+ }
67266928 }
6727− proto1 = JS_VALUE_GET_OBJ(proto_val);
6728− if (!proto1)
6729− break;
67306929 } else {
6731− break;
6930+ ret = FALSE;
67326931 }
6932+ break;
67336933 }
67346934 p = proto1;
67356935 if (proto == p) {
@@ -6767,28 +6967,24 @@ int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj) · 31 unmodified lines
67676967 return JS_OrdinaryIsInstanceOf(ctx, val, obj);
67686968 }
67696969
6770−static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop, JSProperty *pr)
6970+typedef int JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
6971+
6972+static JSAutoInitFunc *js_autoinit_func_table[] = {
6973+ js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
6974+ js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
6975+ JS_InstantiateFunctionListItem, /* JS_AUTOINIT_ID_PROP */
6976+};
6977+
6978+static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
6979+ JSProperty *pr)
67716980 {
67726981 int ret;
67736982 JSContext *realm;
6774−
6775− if (pr->u.init.u.init_id >= JS_AUTOINIT_ID_PROP) {
6776− realm = pr->u.init.u.realm;
6777− ret = JS_InstantiateFunctionListItem(realm, p, prop, pr->u.init.opaque);
6778− if (ret)
6779− return ret;
6780− } else {
6781− switch(pr->u.init.u.init_id) {
6782− case JS_AUTOINIT_ID_PROTOTYPE:
6783− ret = js_instantiate_prototype(ctx, p, prop, pr->u.init.opaque);
6784− break;
6785− case JS_AUTOINIT_ID_MODULE_NS:
6786− ret = js_module_ns_autoinit(ctx, p, prop, pr->u.init.opaque);
6787− break;
6788− default:
6789− abort();
6790− }
6791− }
6983+ JSAutoInitFunc *func;
6984+
6985+ realm = js_autoinit_get_realm(pr);
6986+ func = js_autoinit_func_table[js_autoinit_get_id(pr)];
6987+ ret = func(realm, p, prop, pr->u.init.opaque);
67926988 return ret;
67936989 }
67946990
@@ -6805,8 +7001,9 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, · 10 unmodified lines
68057001 if (unlikely(tag != JS_TAG_OBJECT)) {
68067002 switch(tag) {
68077003 case JS_TAG_NULL:
7004+ return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
68087005 case JS_TAG_UNDEFINED:
6809− return JS_ThrowTypeError(ctx, "value has no property");
7006+ return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
68107007 case JS_TAG_EXCEPTION:
68117008 return JS_EXCEPTION;
68127009 case JS_TAG_STRING:
@@ -6831,7 +7028,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, · 18 unmodified lines
68317028 break;
68327029 }
68337030 /* cannot raise an exception */
6834− p = JS_VALUE_GET_OBJ(JS_GetPrototype(ctx, obj));
7031+ p = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, obj));
68357032 if (!p)
68367033 return JS_UNDEFINED;
68377034 } else {
@@ -6896,15 +7093,25 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, · 58 unmodified lines
68967093 const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
68977094 if (em) {
68987095 if (em->get_property) {
7096+ JSValue obj1, retval;
68997097 /* XXX: should pass throw_ref_error */
6900− return em->get_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p),
6901− prop, this_obj);
7098+ /* Note: if 'p' is a prototype, it can be
7099+ freed in the called function */
7100+ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7101+ retval = em->get_property(ctx, obj1, prop, this_obj);
7102+ JS_FreeValue(ctx, obj1);
7103+ return retval;
69027104 }
69037105 if (em->get_own_property) {
69047106 JSPropertyDescriptor desc;
69057107 int ret;
7108+ JSValue obj1;
69067109
6907− ret = em->get_own_property(ctx, &desc, JS_MKPTR(JS_TAG_OBJECT, p), prop);
7110+ /* Note: if 'p' is a prototype, it can be
7111+ freed in the called function */
7112+ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7113+ ret = em->get_own_property(ctx, &desc, obj1, prop);
7114+ JS_FreeValue(ctx, obj1);
69087115 if (ret < 0)
69097116 return JS_EXCEPTION;
69107117 if (ret) {
@@ -6932,9 +7139,8 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj, · 21 unmodified lines
69327139
69337140 static JSValue JS_ThrowTypeErrorPrivateNotFound(JSContext *ctx, JSAtom atom)
69347141 {
6935− char buf[ATOM_GET_STR_BUF_SIZE];
6936− return JS_ThrowTypeError(ctx, "private class field %s does not exist",
6937− JS_AtomGetStr(ctx, buf, sizeof(buf), atom));
7142+ return JS_ThrowTypeErrorAtom(ctx, "private class field '%s' does not exist",
7143+ atom);
69387144 }
69397145
69407146 /* Private fields can be added even on non extensible objects or
@@ -6960,9 +7166,8 @@ static int JS_DefinePrivateField(JSContext *ctx, JSValueConst obj, · 19 unmodified lines
69607166 p = JS_VALUE_GET_OBJ(obj);
69617167 prs = find_own_property(&pr, p, prop);
69627168 if (prs) {
6963− char buf[ATOM_GET_STR_BUF_SIZE];
6964− JS_ThrowTypeError(ctx, "private class field %s already exists",
6965− JS_AtomGetStr(ctx, buf, sizeof(buf), prop));
7169+ JS_ThrowTypeErrorAtom(ctx, "private class field '%s' already exists",
7170+ prop);
69667171 goto fail;
69677172 }
69687173 pr = add_property(ctx, p, prop, JS_PROP_C_W_E);
@@ -7211,7 +7416,9 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, · 242 unmodified lines
72117416 JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
72127417 return -1;
72137418 }
7214− num_keys_count += p->u.array.count;
7419+ if (flags & JS_GPN_STRING_MASK) {
7420+ num_keys_count += p->u.array.count;
7421+ }
72157422 } else {
72167423 const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
72177424 if (em && em->get_own_property_names) {
@@ -7293,15 +7500,17 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx, · 75 unmodified lines
72937500
72947501 if (p->is_exotic) {
72957502 if (p->fast_array) {
7296− for(i = 0; i < p->u.array.count; i++) {
7297− tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
7298− if (tab_atom[num_index].atom == JS_ATOM_NULL) {
7299− js_free_prop_enum(ctx, tab_exotic, exotic_count);
7300− js_free_prop_enum(ctx, tab_atom, num_index);
7301− return -1;
7503+ if (flags & JS_GPN_STRING_MASK) {
7504+ for(i = 0; i < p->u.array.count; i++) {
7505+ tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
7506+ if (tab_atom[num_index].atom == JS_ATOM_NULL) {
7507+ js_free_prop_enum(ctx, tab_exotic, exotic_count);
7508+ js_free_prop_enum(ctx, tab_atom, num_index);
7509+ return -1;
7510+ }
7511+ tab_atom[num_index].is_enumerable = TRUE;
7512+ num_index++;
73027513 }
7303− tab_atom[num_index].is_enumerable = TRUE;
7304− num_index++;
73057514 }
73067515 }
73077516 if (exotic_count > 0) {
@@ -7492,6 +7701,7 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) · 184 unmodified lines
74927701 {
74937702 JSObject *p;
74947703 int ret;
7704+ JSValue obj1;
74957705
74967706 if (unlikely(JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT))
74977707 return FALSE;
@@ -7499,10 +7709,18 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop) · 1 unmodified line
74997709 for(;;) {
75007710 if (p->is_exotic) {
75017711 const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
7502− if (em && em->has_property)
7503− return em->has_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), prop);
7712+ if (em && em->has_property) {
7713+ /* has_property can free the prototype */
7714+ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
7715+ ret = em->has_property(ctx, obj1, prop);
7716+ JS_FreeValue(ctx, obj1);
7717+ return ret;
7718+ }
75047719 }
7720+ /* JS_GetOwnPropertyInternal can free the prototype */
7721+ JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
75057722 ret = JS_GetOwnPropertyInternal(ctx, NULL, p, prop);
7723+ JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
75067724 if (ret != 0)
75077725 return ret;
75087726 if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
@@ -7799,6 +8017,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) · 290 unmodified lines
77998017 } else {
78008018 sh->prop_hash_end[-h1 - 1] = pr->hash_next;
78018019 }
8020+ sh->deleted_prop_count++;
78028021 /* free the entry */
78038022 pr1 = &p->prop[h - 1];
78048023 free_property(ctx->rt, pr1, pr->flags);
@@ -7807,6 +8026,12 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) · 2 unmodified lines
78078026 pr->flags = 0;
78088027 pr->atom = JS_ATOM_NULL;
78098028 pr1->u.value = JS_UNDEFINED;
8029+
8030+ /* compact the properties if too many deleted properties */
8031+ if (sh->deleted_prop_count >= 8 &&
8032+ sh->deleted_prop_count >= ((unsigned)sh->prop_count / 2)) {
8033+ compact_properties(ctx, p);
8034+ }
78108035 return TRUE;
78118036 }
78128037 lpr = pr;
@@ -8016,8 +8241,12 @@ static int JS_SetPropertyGeneric(JSContext *ctx, · 203 unmodified lines
80168241 if (p->is_exotic) {
80178242 const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
80188243 if (em && em->set_property) {
8019− ret = em->set_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p), prop,
8244+ JSValue obj1;
8245+ /* set_property can free the prototype */
8246+ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
8247+ ret = em->set_property(ctx, obj1, prop,
80208248 val, this_obj, flags);
8249+ JS_FreeValue(ctx, obj1);
80218250 JS_FreeValue(ctx, val);
80228251 return ret;
80238252 }
@@ -8110,14 +8339,17 @@ int JS_SetPropertyInternal(JSContext *ctx, JSValueConst this_obj, · 86 unmodified lines
81108339 if (unlikely(tag != JS_TAG_OBJECT)) {
81118340 switch(tag) {
81128341 case JS_TAG_NULL:
8342+ JS_FreeValue(ctx, val);
8343+ JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of null", prop);
8344+ return -1;
81138345 case JS_TAG_UNDEFINED:
81148346 JS_FreeValue(ctx, val);
8115− JS_ThrowTypeError(ctx, "value has no property");
8347+ JS_ThrowTypeErrorAtom(ctx, "cannot set property '%s' of undefined", prop);
81168348 return -1;
81178349 default:
81188350 /* even on a primitive type we can have setters on the prototype */
81198351 p = NULL;
8120− p1 = JS_VALUE_GET_OBJ(JS_GetPrototype(ctx, this_obj));
8352+ p1 = JS_VALUE_GET_OBJ(JS_GetPrototypePrimitive(ctx, this_obj));
81218353 goto prototype_lookup;
81228354 }
81238355 }
@@ -8195,15 +8427,22 @@ retry: · 71 unmodified lines
81958427 } else {
81968428 const JSClassExoticMethods *em = ctx->rt->class_array[p1->class_id].exotic;
81978429 if (em) {
8430+ JSValue obj1;
81988431 if (em->set_property) {
8199− ret = em->set_property(ctx, JS_MKPTR(JS_TAG_OBJECT, p1), prop,
8432+ /* set_property can free the prototype */
8433+ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
8434+ ret = em->set_property(ctx, obj1, prop,
82008435 val, this_obj, flags);
8436+ JS_FreeValue(ctx, obj1);
82018437 JS_FreeValue(ctx, val);
82028438 return ret;
82038439 }
82048440 if (em->get_own_property) {
8441+ /* get_own_property can free the prototype */
8442+ obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p1));
82058443 ret = em->get_own_property(ctx, &desc,
8206− JS_MKPTR(JS_TAG_OBJECT, p1), prop);
8444+ obj1, prop);
8445+ JS_FreeValue(ctx, obj1);
82078446 if (ret < 0) {
82088447 JS_FreeValue(ctx, val);
82098448 return ret;
@@ -8973,11 +9212,10 @@ static int JS_DefineAutoInitProperty(JSContext *ctx, JSValueConst this_obj, · 763 unmodified lines
89739212 pr = add_property(ctx, p, prop, (flags & JS_PROP_C_W_E) | JS_PROP_AUTOINIT);
89749213 if (unlikely(!pr))
89759214 return -1;
8976− if (id == JS_AUTOINIT_ID_PROP) {
8977− pr->u.init.u.realm = JS_DupContext(ctx);
8978− } else {
8979− pr->u.init.u.init_id = id;
8980− }
9215+ pr->u.init.realm_and_id = (uintptr_t)JS_DupContext(ctx);
9216+ assert((pr->u.init.realm_and_id & 3) == 0);
9217+ assert(id <= 3);
9218+ pr->u.init.realm_and_id |= id;
89819219 pr->u.init.opaque = opaque;
89829220 return TRUE;
89839221 }
@@ -9114,9 +9352,7 @@ static int JS_DefineObjectNameComputed(JSContext *ctx, JSValueConst obj, · 130 unmodified lines
91149352
91159353 static JSValue JS_ThrowSyntaxErrorVarRedeclaration(JSContext *ctx, JSAtom prop)
91169354 {
9117− char buf[ATOM_GET_STR_BUF_SIZE];
9118− return JS_ThrowSyntaxError(ctx, "redeclaration of %s",
9119− JS_AtomGetStr(ctx, buf, sizeof(buf), prop));
9355+ return JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
91209356 }
91219357
91229358 /* flags is 0, DEFINE_GLOBAL_LEX_VAR or DEFINE_GLOBAL_FUNC_VAR */
@@ -9125,7 +9361,6 @@ static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags) · 2 unmodified lines
91259361 {
91269362 JSObject *p;
91279363 JSShapeProperty *prs;
9128− char buf[ATOM_GET_STR_BUF_SIZE];
91299364
91309365 p = JS_VALUE_GET_OBJ(ctx->global_obj);
91319366 prs = find_own_property1(p, prop);
@@ -9143,8 +9378,8 @@ static int JS_CheckDefineGlobalVar(JSContext *ctx, JSAtom prop, int flags) · 11 unmodified lines
91439378 ((prs->flags & (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)) !=
91449379 (JS_PROP_WRITABLE | JS_PROP_ENUMERABLE)))) {
91459380 define_error:
9146− JS_ThrowTypeError(ctx, "cannot define variable %s",
9147− JS_AtomGetStr(ctx, buf, sizeof(buf), prop));
9381+ JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'",
9382+ prop);
91489383 return -1;
91499384 }
91509385 }
@@ -11395,7 +11630,9 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) · 2244 unmodified lines
1139511630 } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
1139611631 printf("[varref %p]", (void *)pr->u.var_ref);
1139711632 } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
11398− printf("[autoinit %p %p]", (void *)pr->u.init.u.realm,
11633+ printf("[autoinit %p %d %p]",
11634+ (void *)js_autoinit_get_realm(pr),
11635+ js_autoinit_get_id(pr),
1139911636 (void *)pr->u.init.opaque);
1140011637 } else {
1140111638 JS_DumpValueShort(rt, pr->u.value);
@@ -15726,30 +15963,6 @@ static JSValue js_call_bound_function(JSContext *ctx, JSValueConst func_obj, · 4324 unmodified lines
1572615963 }
1572715964 }
1572815965
15729−static no_inline __exception int __js_poll_interrupts(JSContext *ctx)
15730−{
15731− JSRuntime *rt = ctx->rt;
15732− ctx->interrupt_counter = JS_INTERRUPT_COUNTER_INIT;
15733− if (rt->interrupt_handler) {
15734− if (rt->interrupt_handler(rt, rt->interrupt_opaque)) {
15735− /* XXX: should set a specific flag to avoid catching */
15736− JS_ThrowInternalError(ctx, "interrupted");
15737− JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
15738− return -1;
15739− }
15740− }
15741− return 0;
15742−}
15743−
15744−static inline __exception int js_poll_interrupts(JSContext *ctx)
15745−{
15746− if (unlikely(--ctx->interrupt_counter <= 0)) {
15747− return __js_poll_interrupts(ctx);
15748− } else {
15749− return 0;
15750− }
15751−}
15752−
1575315966 /* argument of OP_special_object */
1575415967 typedef enum {
1575515968 OP_SPECIAL_OBJECT_ARGUMENTS,
@@ -16440,7 +16653,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, · 684 unmodified lines
1644016653 CASE(OP_get_super):
1644116654 {
1644216655 JSValue proto;
16443− proto = JS_DupValue(ctx, JS_GetPrototype(ctx, sp[-1]));
16656+ proto = JS_GetPrototype(ctx, sp[-1]);
1644416657 if (JS_IsException(proto))
1644516658 goto exception;
1644616659 JS_FreeValue(ctx, sp[-1]);
@@ -18543,6 +18756,9 @@ static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s) · 2096 unmodified lines
1854318756 {
1854418757 JSValue func_obj;
1854518758
18759+ if (js_check_stack_overflow(ctx->rt, 0))
18760+ return JS_ThrowStackOverflow(ctx);
18761+
1854618762 /* the tag does not matter provided it is not an object */
1854718763 func_obj = JS_MKPTR(JS_TAG_INT, s);
1854818764 return JS_CallInternal(ctx, func_obj, s->this_val, JS_UNDEFINED,
@@ -19670,8 +19886,8 @@ typedef struct JSFunctionDef { · 1121 unmodified lines
1967019886
1967119887 /* constant pool (strings, functions, numbers) */
1967219888 JSValue *cpool;
19673− uint32_t cpool_count;
19674− uint32_t cpool_size;
19889+ int cpool_count;
19890+ int cpool_size;
1967519891
1967619892 /* list of variables in the closure */
1967719893 int closure_var_count;
@@ -19741,6 +19957,7 @@ typedef struct JSParseState { · 63 unmodified lines
1974119957 JSFunctionDef *cur_func;
1974219958 BOOL is_module; /* parsing a module */
1974319959 BOOL allow_html_comments;
19960+ BOOL ext_json; /* true if accepting JSON superset */
1974419961 } JSParseState;
1974519962
1974619963 typedef struct JSOpCode {
@@ -20308,23 +20525,18 @@ static __exception int next_token(JSParseState *s) · 561 unmodified lines
2030820525 c = *p;
2030920526 switch(c) {
2031020527 case 0:
20311− s->token.val = TOK_EOF;
20312− break;
20313− case '`':
20314− if (!s->cur_func) {
20315− /* JSON does not accept templates */
20528+ if (p >= s->buf_end) {
20529+ s->token.val = TOK_EOF;
20530+ } else {
2031620531 goto def_token;
2031720532 }
20533+ break;
20534+ case '`':
2031820535 if (js_parse_template_part(s, p + 1))
2031920536 goto fail;
2032020537 p = s->buf_ptr;
2032120538 break;
2032220539 case '\'':
20323− if (!s->cur_func) {
20324− /* JSON does not accept single quoted strings */
20325− goto def_token;
20326− }
20327− /* fall through */
2032820540 case '\"':
2032920541 if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
2033020542 goto fail;
@@ -20342,11 +20554,6 @@ static __exception int next_token(JSParseState *s) · 11 unmodified lines
2034220554 goto redo;
2034320555 case '\f':
2034420556 case '\v':
20345− if (!s->cur_func) {
20346− /* JSONWhitespace does not match <VT>, nor <FF> */
20347− goto def_token;
20348− }
20349− /* fall through */
2035020557 case ' ':
2035120558 case '\t':
2035220559 p++;
@@ -20443,16 +20650,15 @@ static __exception int next_token(JSParseState *s) · 90 unmodified lines
2044320650 s->token.u.ident.is_reserved = FALSE;
2044420651 if (s->token.u.ident.atom <= JS_ATOM_LAST_KEYWORD ||
2044520652 (s->token.u.ident.atom <= JS_ATOM_LAST_STRICT_KEYWORD &&
20446− s->cur_func && (s->cur_func->js_mode & JS_MODE_STRICT)) ||
20447− (s->token.u.ident.atom == JS_ATOM_yield && s->cur_func &&
20653+ (s->cur_func->js_mode & JS_MODE_STRICT)) ||
20654+ (s->token.u.ident.atom == JS_ATOM_yield &&
2044820655 ((s->cur_func->func_kind & JS_FUNC_GENERATOR) ||
2044920656 (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
2045020657 !s->cur_func->in_function_body && s->cur_func->parent &&
2045120658 (s->cur_func->parent->func_kind & JS_FUNC_GENERATOR)))) ||
2045220659 (s->token.u.ident.atom == JS_ATOM_await &&
2045320660 (s->is_module ||
20454− (s->cur_func &&
20455− ((s->cur_func->func_kind & JS_FUNC_ASYNC) ||
20661+ (((s->cur_func->func_kind & JS_FUNC_ASYNC) ||
2045620662 (s->cur_func->func_type == JS_PARSE_FUNC_ARROW &&
2045720663 !s->cur_func->in_function_body && s->cur_func->parent &&
2045820664 (s->cur_func->parent->func_kind & JS_FUNC_ASYNC))))))) {
@@ -20505,9 +20711,8 @@ static __exception int next_token(JSParseState *s) · 46 unmodified lines
2050520711 }
2050620712 break;
2050720713 case '0':
20508− /* in strict or JSON parsing mode, octal literals are not accepted */
20509− if (is_digit(p[1]) && (!s->cur_func ||
20510− (s->cur_func->js_mode & JS_MODE_STRICT))) {
20714+ /* in strict mode, octal literals are not accepted */
20715+ if (is_digit(p[1]) && (s->cur_func->js_mode & JS_MODE_STRICT)) {
2051120716 js_parse_error(s, "octal literals are deprecated in strict mode");
2051220717 goto fail;
2051320718 }
@@ -20519,22 +20724,17 @@ static __exception int next_token(JSParseState *s) · 5 unmodified lines
2051920724 JSValue ret;
2052020725 const uint8_t *p1;
2052120726 int flags, radix;
20522− if (!s->cur_func) {
20523− flags = 0;
20524− radix = 10;
20525− } else {
20526− flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
20527− ATOD_ACCEPT_UNDERSCORES;
20727+ flags = ATOD_ACCEPT_BIN_OCT | ATOD_ACCEPT_LEGACY_OCTAL |
20728+ ATOD_ACCEPT_UNDERSCORES;
2052820729 #ifdef CONFIG_BIGNUM
20529− flags |= ATOD_ACCEPT_SUFFIX;
20530− if (s->cur_func->js_mode & JS_MODE_MATH) {
20531− flags |= ATOD_MODE_BIGINT;
20532− if (s->cur_func->js_mode & JS_MODE_MATH)
20533− flags |= ATOD_TYPE_BIG_FLOAT;
20534− }
20535−#endif
20536− radix = 0;
20730+ flags |= ATOD_ACCEPT_SUFFIX;
20731+ if (s->cur_func->js_mode & JS_MODE_MATH) {
20732+ flags |= ATOD_MODE_BIGINT;
20733+ if (s->cur_func->js_mode & JS_MODE_MATH)
20734+ flags |= ATOD_TYPE_BIG_FLOAT;
2053720735 }
20736+#endif
20737+ radix = 0;
2053820738 #ifdef CONFIG_BIGNUM
2053920739 s->token.u.num.exponent = 0;
2054020740 ret = js_atof2(s->ctx, (const char *)p, (const char **)&p, radix,
@@ -20699,7 +20899,7 @@ static __exception int next_token(JSParseState *s) · 158 unmodified lines
2069920899 case '^':
2070020900 if (p[1] == '=') {
2070120901 p += 2;
20702− if (s->cur_func && (s->cur_func->js_mode & JS_MODE_MATH))
20902+ if (s->cur_func->js_mode & JS_MODE_MATH)
2070320903 s->token.val = TOK_MATH_POW_ASSIGN;
2070420904 else
2070520905 s->token.val = TOK_XOR_ASSIGN;
@@ -20713,7 +20913,7 @@ static __exception int next_token(JSParseState *s) · 7 unmodified lines
2071320913 }
2071420914 } else {
2071520915 p++;
20716− if (s->cur_func && (s->cur_func->js_mode & JS_MODE_MATH))
20916+ if (s->cur_func->js_mode & JS_MODE_MATH)
2071720917 s->token.val = TOK_MATH_POW;
2071820918 else
2071920919 s->token.val = '^';
@@ -20758,22 +20958,12 @@ static __exception int next_token(JSParseState *s) · 38 unmodified lines
2075820958 switch(c) {
2075920959 case CP_PS:
2076020960 case CP_LS:
20761− if (!s->cur_func) {
20762− /* <PS> and <LS> are not JSONWhitespace */
20763− goto def_token;
20764− } else {
20765− /* XXX: should avoid incrementing line_number, but
20766− needed to handle HTML comments */
20767− goto line_terminator;
20768− }
20961+ /* XXX: should avoid incrementing line_number, but
20962+ needed to handle HTML comments */
20963+ goto line_terminator;
2076920964 default:
2077020965 if (lre_is_space(c)) {
20771− if (!s->cur_func) {
20772− /* category z spaces are not JSONWhitespace */
20773− goto def_token;
20774− } else {
20775− goto redo;
20776− }
20966+ goto redo;
2077720967 } else if (lre_js_is_ident_first(c)) {
2077820968 ident_has_escape = FALSE;
2077920969 goto has_ident;
@@ -20798,6 +20988,220 @@ static __exception int next_token(JSParseState *s) · 18 unmodified lines
2079820988 return -1;
2079920989 }
2080020990
20991+/* 'c' is the first character. Return JS_ATOM_NULL in case of error */
20992+static JSAtom json_parse_ident(JSParseState *s, const uint8_t **pp, int c)
20993+{
20994+ const uint8_t *p;
20995+ char ident_buf[128], *buf;
20996+ size_t ident_size, ident_pos;
20997+ JSAtom atom;
20998+
20999+ p = *pp;
21000+ buf = ident_buf;
21001+ ident_size = sizeof(ident_buf);
21002+ ident_pos = 0;
21003+ for(;;) {
21004+ buf[ident_pos++] = c;
21005+ c = *p;
21006+ if (c >= 128 ||
21007+ !((lre_id_continue_table_ascii[c >> 5] >> (c & 31)) & 1))
21008+ break;
21009+ p++;
21010+ if (unlikely(ident_pos >= ident_size - UTF8_CHAR_LEN_MAX)) {
21011+ if (ident_realloc(s->ctx, &buf, &ident_size, ident_buf)) {
21012+ atom = JS_ATOM_NULL;
21013+ goto done;
21014+ }
21015+ }
21016+ }
21017+ atom = JS_NewAtomLen(s->ctx, buf, ident_pos);
21018+ done:
21019+ if (unlikely(buf != ident_buf))
21020+ js_free(s->ctx, buf);
21021+ *pp = p;
21022+ return atom;
21023+}
21024+
21025+static __exception int json_next_token(JSParseState *s)
21026+{
21027+ const uint8_t *p;
21028+ int c;
21029+ JSAtom atom;
21030+
21031+ if (js_check_stack_overflow(s->ctx->rt, 0)) {
21032+ return js_parse_error(s, "stack overflow");
21033+ }
21034+
21035+ free_token(s, &s->token);
21036+
21037+ p = s->last_ptr = s->buf_ptr;
21038+ s->last_line_num = s->token.line_num;
21039+ redo:
21040+ s->token.line_num = s->line_num;
21041+ s->token.ptr = p;
21042+ c = *p;
21043+ switch(c) {
21044+ case 0:
21045+ if (p >= s->buf_end) {
21046+ s->token.val = TOK_EOF;
21047+ } else {
21048+ goto def_token;
21049+ }
21050+ break;
21051+ case '\'':
21052+ if (!s->ext_json) {
21053+ /* JSON does not accept single quoted strings */
21054+ goto def_token;
21055+ }
21056+ /* fall through */
21057+ case '\"':
21058+ if (js_parse_string(s, c, TRUE, p + 1, &s->token, &p))
21059+ goto fail;
21060+ break;
21061+ case '\r': /* accept DOS and MAC newline sequences */
21062+ if (p[1] == '\n') {
21063+ p++;
21064+ }
21065+ /* fall thru */
21066+ case '\n':
21067+ p++;
21068+ s->line_num++;
21069+ goto redo;
21070+ case '\f':
21071+ case '\v':
21072+ if (!s->ext_json) {
21073+ /* JSONWhitespace does not match <VT>, nor <FF> */
21074+ goto def_token;
21075+ }
21076+ /* fall through */
21077+ case ' ':
21078+ case '\t':
21079+ p++;
21080+ goto redo;
21081+ case '/':
21082+ if (!s->ext_json) {
21083+ /* JSON does not accept comments */
21084+ goto def_token;
21085+ }
21086+ if (p[1] == '*') {
21087+ /* comment */
21088+ p += 2;
21089+ for(;;) {
21090+ if (*p == '\0' && p >= s->buf_end) {
21091+ js_parse_error(s, "unexpected end of comment");
21092+ goto fail;
21093+ }
21094+ if (p[0] == '*' && p[1] == '/') {
21095+ p += 2;
21096+ break;
21097+ }
21098+ if (*p == '\n') {
21099+ s->line_num++;
21100+ p++;
21101+ } else if (*p == '\r') {
21102+ p++;
21103+ } else if (*p >= 0x80) {
21104+ c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21105+ if (c == -1) {
21106+ p++; /* skip invalid UTF-8 */
21107+ }
21108+ } else {
21109+ p++;
21110+ }
21111+ }
21112+ goto redo;
21113+ } else if (p[1] == '/') {
21114+ /* line comment */
21115+ p += 2;
21116+ for(;;) {
21117+ if (*p == '\0' && p >= s->buf_end)
21118+ break;
21119+ if (*p == '\r' || *p == '\n')
21120+ break;
21121+ if (*p >= 0x80) {
21122+ c = unicode_from_utf8(p, UTF8_CHAR_LEN_MAX, &p);
21123+ /* LS or PS are considered as line terminator */
21124+ if (c == CP_LS || c == CP_PS) {
21125+ break;
21126+ } else if (c == -1) {
21127+ p++; /* skip invalid UTF-8 */
21128+ }
21129+ } else {
21130+ p++;
21131+ }
21132+ }
21133+ goto redo;
21134+ } else {
21135+ goto def_token;
21136+ }
21137+ break;
21138+ case 'a' ... 'z':
21139+ case 'A' ... 'Z':
21140+ case '_':
21141+ case '$':
21142+ /* identifier : only pure ascii characters are accepted */
21143+ p++;
21144+ atom = json_parse_ident(s, &p, c);
21145+ if (atom == JS_ATOM_NULL)
21146+ goto fail;
21147+ s->token.u.ident.atom = atom;
21148+ s->token.u.ident.has_escape = FALSE;
21149+ s->token.u.ident.is_reserved = FALSE;
21150+ s->token.val = TOK_IDENT;
21151+ break;
21152+ case '+':
21153+ if (!s->ext_json || !is_digit(p[1]))
21154+ goto def_token;
21155+ goto parse_number;
21156+ case '0':
21157+ if (is_digit(p[1]))
21158+ goto def_token;
21159+ goto parse_number;
21160+ case '-':
21161+ if (!is_digit(p[1]))
21162+ goto def_token;
21163+ goto parse_number;
21164+ case '1' ... '9':
21165+ /* number */
21166+ parse_number:
21167+ {
21168+ JSValue ret;
21169+ int flags, radix;
21170+ if (!s->ext_json) {
21171+ flags = 0;
21172+ radix = 10;
21173+ } else {
21174+ flags = ATOD_ACCEPT_BIN_OCT;
21175+ radix = 0;
21176+ }
21177+ ret = js_atof(s->ctx, (const char *)p, (const char **)&p, radix,
21178+ flags);
21179+ if (JS_IsException(ret))
21180+ goto fail;
21181+ s->token.val = TOK_NUMBER;
21182+ s->token.u.num.val = ret;
21183+ }
21184+ break;
21185+ default:
21186+ if (c >= 128) {
21187+ js_parse_error(s, "unexpected character");
21188+ goto fail;
21189+ }
21190+ def_token:
21191+ s->token.val = c;
21192+ p++;
21193+ break;
21194+ }
21195+ s->buf_ptr = p;
21196+
21197+ // dump_token(s, &s->token);
21198+ return 0;
21199+
21200+ fail:
21201+ s->token.val = TOK_ERROR;
21202+ return -1;
21203+}
21204+
2080121205 /* only used for ':' and '=>', 'let' or 'function' look-ahead. *pp is
2080221206 only set if TOK_IMPORT is returned */
2080321207 /* XXX: handle all unicode cases */
@@ -20858,6 +21262,12 @@ static int simple_next_token(const uint8_t **pp, BOOL no_line_terminator) · 54 unmodified lines
2085821262 }
2085921263 } else if (c == 'o' && *p == 'f' && !lre_js_is_ident_next(p[1])) {
2086021264 return TOK_OF;
21265+ } else if (c == 'e' &&
21266+ p[0] == 'x' && p[1] == 'p' && p[2] == 'o' &&
21267+ p[3] == 'r' && p[4] == 't' &&
21268+ !lre_js_is_ident_next(p[5])) {
21269+ *pp = p + 5;
21270+ return TOK_EXPORT;
2086121271 } else if (c == 'f' && p[0] == 'u' && p[1] == 'n' &&
2086221272 p[2] == 'c' && p[3] == 't' && p[4] == 'i' &&
2086321273 p[5] == 'o' && p[6] == 'n' && !lre_js_is_ident_next(p[7])) {
@@ -20881,16 +21291,21 @@ static int peek_token(JSParseState *s, BOOL no_line_terminator) · 17 unmodified lines
2088121291 (heuristic). 'input' must be a zero terminated.
2088221292
2088321293 Heuristic: skip comments and expect 'import' keyword not followed
20884− by '(' or '.'
21294+ by '(' or '.' or export keyword.
2088521295 */
2088621296 BOOL JS_DetectModule(const char *input, size_t input_len)
2088721297 {
2088821298 const uint8_t *p = (const uint8_t *)input;
2088921299 int tok;
20890− if (simple_next_token(&p, FALSE) != TOK_IMPORT)
21300+ switch(simple_next_token(&p, FALSE)) {
21301+ case TOK_IMPORT:
21302+ tok = simple_next_token(&p, FALSE);
21303+ return (tok != '.' && tok != '(');
21304+ case TOK_EXPORT:
21305+ return TRUE;
21306+ default:
2089121307 return FALSE;
20892− tok = simple_next_token(&p, FALSE);
20893− return (tok != '.' && tok != '(');
21308+ }
2089421309 }
2089521310
2089621311 static inline int get_prev_opcode(JSFunctionDef *fd) {
@@ -20974,20 +21389,10 @@ static int new_label_fd(JSFunctionDef *fd, int label) · 77 unmodified lines
2097421389 LabelSlot *ls;
2097521390
2097621391 if (label < 0) {
20977− if (fd->label_count >= fd->label_size) {
20978− int new_size;
20979− size_t slack;
20980− LabelSlot *new_tab;
20981−
20982− /* XXX: potential arithmetic overflow */
20983− new_size = fd->label_size * 3 / 2 + 4;
20984− new_tab = js_realloc2(fd->ctx, fd->label_slots, new_size * sizeof(*new_tab), &slack);
20985− if (!new_tab)
20986− return -1;
20987− new_size += slack / sizeof(*new_tab);
20988− fd->label_slots = new_tab;
20989− fd->label_size = new_size;
20990− }
21392+ if (js_resize_array(fd->ctx, (void *)&fd->label_slots,
21393+ sizeof(fd->label_slots[0]),
21394+ &fd->label_size, fd->label_count + 1))
21395+ return -1;
2099121396 label = fd->label_count++;
2099221397 ls = &fd->label_slots[label];
2099321398 ls->ref_count = 0;
@@ -21035,19 +21440,10 @@ static int emit_goto(JSParseState *s, int opcode, int label) · 41 unmodified lines
2103521440 static int cpool_add(JSParseState *s, JSValue val)
2103621441 {
2103721442 JSFunctionDef *fd = s->cur_func;
21038− if (fd->cpool_count >= fd->cpool_size) {
21039− int new_size;
21040− size_t slack;
21041− JSValue *new_tab;
21042− /* XXX: potential arithmetic overflow */
21043− new_size = max_int(fd->cpool_count + 1, fd->cpool_size * 3 / 2);
21044− new_tab = js_realloc2(s->ctx, fd->cpool, new_size * sizeof(JSValue), &slack);
21045− if (!new_tab)
21046− return -1;
21047− new_size += slack / sizeof(*new_tab);
21048− fd->cpool = new_tab;
21049− fd->cpool_size = new_size;
21050− }
21443+
21444+ if (js_resize_array(s->ctx, (void *)&fd->cpool, sizeof(fd->cpool[0]),
21445+ &fd->cpool_size, fd->cpool_count + 1))
21446+ return -1;
2105121447 fd->cpool[fd->cpool_count++] = val;
2105221448 return fd->cpool_count - 1;
2105321449 }
@@ -21246,18 +21642,9 @@ static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) · 192 unmodified lines
2124621642 JS_ThrowInternalError(ctx, "too many local variables");
2124721643 return -1;
2124821644 }
21249− if ((fd->var_count + 1) > fd->var_size) {
21250− int new_size;
21251− size_t slack;
21252− JSVarDef *new_buf;
21253− new_size = max_int(fd->var_count + 1, fd->var_size * 3 / 2);
21254− new_buf = js_realloc2(ctx, fd->vars, new_size * sizeof(*fd->vars), &slack);
21255− if (!new_buf)
21256− return -1;
21257− new_size += slack / sizeof(*new_buf);
21258− fd->vars = new_buf;
21259− fd->var_size = new_size;
21260− }
21645+ if (js_resize_array(ctx, (void **)&fd->vars, sizeof(fd->vars[0]),
21646+ &fd->var_size, fd->var_count + 1))
21647+ return -1;
2126121648 vd = &fd->vars[fd->var_count++];
2126221649 memset(vd, 0, sizeof(*vd));
2126321650 vd->var_name = JS_DupAtom(ctx, name);
@@ -21309,18 +21696,9 @@ static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name) · 45 unmodified lines
2130921696 JS_ThrowInternalError(ctx, "too many arguments");
2131021697 return -1;
2131121698 }
21312− if ((fd->arg_count + 1) > fd->arg_size) {
21313− int new_size;
21314− size_t slack;
21315− JSVarDef *new_buf;
21316− new_size = max_int(fd->arg_count + 1, fd->arg_size * 3 / 2);
21317− new_buf = js_realloc2(ctx, fd->args, new_size * sizeof(*fd->args), &slack);
21318− if (!new_buf)
21319− return -1;
21320− new_size += slack / sizeof(*new_buf);
21321− fd->args = new_buf;
21322− fd->arg_size = new_size;
21323− }
21699+ if (js_resize_array(ctx, (void **)&fd->args, sizeof(fd->args[0]),
21700+ &fd->arg_size, fd->arg_count + 1))
21701+ return -1;
2132421702 vd = &fd->args[fd->arg_count++];
2132521703 memset(vd, 0, sizeof(*vd));
2132621704 vd->var_name = JS_DupAtom(ctx, name);
@@ -21335,19 +21713,10 @@ static JSHoistedDef *add_hoisted_def(JSContext *ctx, · 8 unmodified lines
2133521713 {
2133621714 JSHoistedDef *hf;
2133721715
21338− if (s->hoisted_def_count >= s->hoisted_def_size) {
21339− int new_size;
21340− size_t slack;
21341− JSHoistedDef *new_tab;
21342− new_size = max_int(s->hoisted_def_count + 1,
21343− s->hoisted_def_size * 3 / 2);
21344− new_tab = js_realloc2(ctx, s->hoisted_def, new_size * sizeof(s->hoisted_def[0]), &slack);
21345− if (!new_tab)
21346− return NULL;
21347− new_size += slack / sizeof(*new_tab);
21348− s->hoisted_def = new_tab;
21349− s->hoisted_def_size = new_size;
21350− }
21716+ if (js_resize_array(ctx, (void **)&s->hoisted_def,
21717+ sizeof(s->hoisted_def[0]),
21718+ &s->hoisted_def_size, s->hoisted_def_count + 1))
21719+ return NULL;
2135121720 hf = &s->hoisted_def[s->hoisted_def_count++];
2135221721 hf->cpool_idx = cpool_idx;
2135321722 hf->force_init = 0;
@@ -21639,7 +22008,7 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) · 285 unmodified lines
2163922008 goto done;
2164022009 if (next_token(s))
2164122010 return -1;
21642− if (js_parse_assign_expr(s, TRUE))
22011+ if (js_parse_expr(s))
2164322012 return -1;
2164422013 depth++;
2164522014 if (s->token.val != '}') {
@@ -21647,7 +22016,8 @@ static __exception int js_parse_template(JSParseState *s, int call, int *argc) · 1 unmodified line
2164722016 }
2164822017 /* XXX: should convert to string at this stage? */
2164922018 free_token(s, &s->token);
21650− /* Resume TOK_TEMPLATE parsing (s->token.line_num and s->token.ptr are OK) */
22019+ /* Resume TOK_TEMPLATE parsing (s->token.line_num and
22020+ * s->token.ptr are OK) */
2165122021 s->got_lf = FALSE;
2165222022 s->last_line_num = s->token.line_num;
2165322023 if (js_parse_template_part(s, s->buf_ptr))
@@ -21875,7 +22245,7 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_ · 221 unmodified lines
2187522245 size_t level = 0;
2187622246 JSParsePos pos;
2187722247 int last_tok, tok = TOK_EOF;
21878− int tok_len, bits = 0;
22248+ int c, tok_len, bits = 0;
2187922249
2188022250 /* protect from underflow */
2188122251 state[level++] = 0;
@@ -21900,8 +22270,30 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_ · 18 unmodified lines
2190022270 goto done;
2190122271 break;
2190222272 case '}':
21903− if (state[--level] != '{')
22273+ c = state[--level];
22274+ if (c == '`') {
22275+ /* continue the parsing of the template */
22276+ free_token(s, &s->token);
22277+ /* Resume TOK_TEMPLATE parsing (s->token.line_num and
22278+ * s->token.ptr are OK) */
22279+ s->got_lf = FALSE;
22280+ s->last_line_num = s->token.line_num;
22281+ if (js_parse_template_part(s, s->buf_ptr))
22282+ goto done;
22283+ goto handle_template;
22284+ } else if (c != '{') {
2190422285 goto done;
22286+ }
22287+ break;
22288+ case TOK_TEMPLATE:
22289+ handle_template:
22290+ if (s->token.u.str.sep != '`') {
22291+ /* '${' inside the template : closing '}' and continue
22292+ parsing the template */
22293+ if (level >= sizeof(state))
22294+ goto done;
22295+ state[level++] = '`';
22296+ }
2190522297 break;
2190622298 case TOK_EOF:
2190722299 goto done;
@@ -24005,7 +24397,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen · 2097 unmodified lines
2400524397 int scope;
2400624398 name = get_u32(fd->byte_code.buf + fd->last_opcode_pos + 1);
2400724399 scope = get_u16(fd->byte_code.buf + fd->last_opcode_pos + 5);
24008− if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL) {
24400+ if (name == JS_ATOM_eval && call_type == FUNC_CALL_NORMAL && !has_optional_chain) {
2400924401 /* direct 'eval' */
2401024402 opcode = OP_eval;
2401124403 } else {
@@ -26318,26 +26710,6 @@ static void js_free_module_def(JSContext *ctx, JSModuleDef *m) · 2306 unmodified lines
2631826710 js_free(ctx, m);
2631926711 }
2632026712
26321−static int js_resize_array(JSContext *ctx, void **parray, int elem_size,
26322− int *psize, int *pcount, int new_count)
26323−{
26324− if (unlikely(new_count > *psize)) {
26325− int new_size;
26326− size_t slack;
26327− void *new_array;
26328− /* XXX: potential arithmetic overflow */
26329− new_size = max_int(new_count, *psize * 3 / 2);
26330− new_array = js_realloc2(ctx, *parray, new_size * elem_size, &slack);
26331− if (!new_array)
26332− return -1;
26333− new_size += slack / elem_size;
26334− *psize = new_size;
26335− *parray = new_array;
26336− }
26337− *pcount = new_count;
26338− return 0;
26339−}
26340−
2634126713 static int add_req_module_entry(JSContext *ctx, JSModuleDef *m,
2634226714 JSAtom module_name)
2634326715 {
@@ -26353,11 +26725,10 @@ static int add_req_module_entry(JSContext *ctx, JSModuleDef *m, · 9 unmodified lines
2635326725
2635426726 if (js_resize_array(ctx, (void **)&m->req_module_entries,
2635526727 sizeof(JSReqModuleEntry),
26356− &m->req_module_entries_size, &m->req_module_entries_count,
26728+ &m->req_module_entries_size,
2635726729 m->req_module_entries_count + 1))
2635826730 return -1;
26359− i = m->req_module_entries_count - 1;
26360− rme = &m->req_module_entries[i];
26731+ rme = &m->req_module_entries[m->req_module_entries_count++];
2636126732 rme->module_name = JS_DupAtom(ctx, module_name);
2636226733 rme->module = NULL;
2636326734 return i;
@@ -26389,18 +26760,17 @@ static JSExportEntry *add_export_entry2(JSContext *ctx, · 25 unmodified lines
2638926760 js_parse_error(s, "duplicate exported name '%s'",
2639026761 JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
2639126762 } else {
26392− JS_ThrowSyntaxError(ctx, "duplicate exported name '%s'",
26393− JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name));
26763+ JS_ThrowSyntaxErrorAtom(ctx, "duplicate exported name '%s'", export_name);
2639426764 }
2639526765 return NULL;
2639626766 }
2639726767
2639826768 if (js_resize_array(ctx, (void **)&m->export_entries,
2639926769 sizeof(JSExportEntry),
26400− &m->export_entries_size, &m->export_entries_count,
26770+ &m->export_entries_size,
2640126771 m->export_entries_count + 1))
2640226772 return NULL;
26403− me = &m->export_entries[m->export_entries_count - 1];
26773+ me = &m->export_entries[m->export_entries_count++];
2640426774 memset(me, 0, sizeof(*me));
2640526775 me->local_name = JS_DupAtom(ctx, local_name);
2640626776 me->export_name = JS_DupAtom(ctx, export_name);
@@ -26423,10 +26793,10 @@ static int add_star_export_entry(JSContext *ctx, JSModuleDef *m, · 16 unmodified lines
2642326793
2642426794 if (js_resize_array(ctx, (void **)&m->star_export_entries,
2642526795 sizeof(JSStarExportEntry),
26426− &m->star_export_entries_size, &m->star_export_entries_count,
26796+ &m->star_export_entries_size,
2642726797 m->star_export_entries_count + 1))
2642826798 return -1;
26429− se = &m->star_export_entries[m->star_export_entries_count - 1];
26799+ se = &m->star_export_entries[m->star_export_entries_count++];
2643026800 se->req_module_idx = req_module_idx;
2643126801 return 0;
2643226802 }
@@ -26652,10 +27022,9 @@ static int add_resolve_entry(JSContext *ctx, JSResolveState *s, · 219 unmodified lines
2665227022
2665327023 if (js_resize_array(ctx, (void **)&s->array,
2665427024 sizeof(JSResolveEntry),
26655− &s->size, &s->count,
26656− s->count + 1))
27025+ &s->size, s->count + 1))
2665727026 return -1;
26658− re = &s->array[s->count - 1];
27027+ re = &s->array[s->count++];
2665927028 re->module = m;
2666027029 re->name = JS_DupAtom(ctx, name);
2666127030 return 0;
@@ -26780,17 +27149,17 @@ static void js_resolve_export_throw_error(JSContext *ctx, · 118 unmodified lines
2678027149 break;
2678127150 default:
2678227151 case JS_RESOLVE_RES_NOT_FOUND:
26783− JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
27152+ JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
2678427153 JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
2678527154 JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
2678627155 break;
2678727156 case JS_RESOLVE_RES_CIRCULAR:
26788− JS_ThrowSyntaxError(ctx, "Could not find export '%s' in module '%s'",
27157+ JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
2678927158 JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
2679027159 JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
2679127160 break;
2679227161 case JS_RESOLVE_RES_AMBIGUOUS:
26793− JS_ThrowSyntaxError(ctx, "circular reference when looking for export '%s' in module '%s'",
27162+ JS_ThrowSyntaxError(ctx, "export '%s' in module '%s' is ambiguous",
2679427163 JS_AtomGetStr(ctx, buf1, sizeof(buf1), export_name),
2679527164 JS_AtomGetStr(ctx, buf2, sizeof(buf2), m->module_name));
2679627165 break;
@@ -26847,9 +27216,9 @@ static __exception int get_exported_names(JSContext *ctx, · 50 unmodified lines
2684727216 return 0;
2684827217 }
2684927218 if (js_resize_array(ctx, (void **)&s->modules, sizeof(s->modules[0]),
26850− &s->modules_size, &s->modules_count, s->modules_count + 1))
27219+ &s->modules_size, s->modules_count + 1))
2685127220 return -1;
26852− s->modules[s->modules_count - 1] = m;
27221+ s->modules[s->modules_count++] = m;
2685327222
2685427223 for(i = 0; i < m->export_entries_count; i++) {
2685527224 JSExportEntry *me = &m->export_entries[i];
@@ -26858,9 +27227,10 @@ static __exception int get_exported_names(JSContext *ctx, · 2 unmodified lines
2685827227 j = find_exported_name(s, me->export_name);
2685927228 if (j < 0) {
2686027229 if (js_resize_array(ctx, (void **)&s->exported_names, sizeof(s->exported_names[0]),
26861− &s->exported_names_size, &s->exported_names_count, s->exported_names_count + 1))
27230+ &s->exported_names_size,
27231+ s->exported_names_count + 1))
2686227232 return -1;
26863− en = &s->exported_names[s->exported_names_count - 1];
27233+ en = &s->exported_names[s->exported_names_count++];
2686427234 en->export_name = me->export_name;
2686527235 /* avoid a second lookup for simple module exports */
2686627236 if (from_star || me->export_type != JS_EXPORT_TYPE_LOCAL)
@@ -27096,7 +27466,7 @@ static JSVarRef *js_create_module_var(JSContext *ctx, BOOL is_lexical) · 229 unmodified lines
2709627466 }
2709727467
2709827468 /* Create the <eval> function associated with the module */
27099−static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
27469+static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
2710027470 {
2710127471 JSFunctionBytecode *b;
2710227472 int i;
@@ -27147,20 +27517,15 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m) · 44 unmodified lines
2714727517 return -1;
2714827518 }
2714927519
27150−/* Prepare a module to be executed by resolving all the imported
27151− variables. */
27152−static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
27520+/* must be done before js_instantiate_module() because of cyclic references */
27521+static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
2715327522 {
27154− int i;
27155− JSImportEntry *mi;
27156− JSModuleDef *m1;
27157− JSVarRef **var_refs, *var_ref;
27158− JSObject *p;
2715927523 BOOL is_c_module;
27160−
27161− if (m->instantiated)
27524+ int i;
27525+ JSVarRef *var_ref;
27526+
27527+ if (m->func_created)
2716227528 return 0;
27163− m->instantiated = TRUE;
2716427529
2716527530 is_c_module = (m->init_func != NULL);
2716627531
@@ -27171,14 +27536,49 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) · 4 unmodified lines
2717127536 if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
2717227537 var_ref = js_create_module_var(ctx, FALSE);
2717327538 if (!var_ref)
27174− goto fail;
27539+ return -1;
2717527540 me->u.local.var_ref = var_ref;
2717627541 }
2717727542 }
2717827543 } else {
27179− if (js_create_module_function(ctx, m) < 0)
27180− goto fail;
27544+ if (js_create_module_bytecode_function(ctx, m))
27545+ return -1;
2718127546 }
27547+ m->func_created = TRUE;
27548+
27549+ /* do it on the dependencies */
27550+
27551+ for(i = 0; i < m->req_module_entries_count; i++) {
27552+ JSReqModuleEntry *rme = &m->req_module_entries[i];
27553+ if (js_create_module_function(ctx, rme->module) < 0)
27554+ return -1;
27555+ }
27556+
27557+ return 0;
27558+}
27559+
27560+
27561+/* Prepare a module to be executed by resolving all the imported
27562+ variables. */
27563+static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
27564+{
27565+ int i;
27566+ JSImportEntry *mi;
27567+ JSModuleDef *m1;
27568+ JSVarRef **var_refs, *var_ref;
27569+ JSObject *p;
27570+ BOOL is_c_module;
27571+
27572+ if (m->instantiated)
27573+ return 0;
27574+ m->instantiated = TRUE;
27575+
27576+#ifdef DUMP_MODULE_RESOLVE
27577+ {
27578+ char buf1[ATOM_GET_STR_BUF_SIZE];
27579+ printf("start instantiating module '%s':\n", JS_AtomGetStr(ctx, buf1, sizeof(buf1), m->module_name));
27580+ }
27581+#endif
2718227582
2718327583 for(i = 0; i < m->req_module_entries_count; i++) {
2718427584 JSReqModuleEntry *rme = &m->req_module_entries[i];
@@ -27221,6 +27621,8 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) · 36 unmodified lines
2722127621 }
2722227622 #endif
2722327623
27624+ is_c_module = (m->init_func != NULL);
27625+
2722427626 if (!is_c_module) {
2722527627 p = JS_VALUE_GET_OBJ(m->func_obj);
2722627628 var_refs = p->u.func.var_refs;
@@ -27740,10 +28142,10 @@ static int add_import(JSParseState *s, JSModuleDef *m, · 513 unmodified lines
2774028142 return -1;
2774128143 if (js_resize_array(ctx, (void **)&m->import_entries,
2774228144 sizeof(JSImportEntry),
27743− &m->import_entries_size, &m->import_entries_count,
28145+ &m->import_entries_size,
2774428146 m->import_entries_count + 1))
2774528147 return -1;
27746− mi = &m->import_entries[m->import_entries_count - 1];
28148+ mi = &m->import_entries[m->import_entries_count++];
2774728149 mi->import_name = JS_DupAtom(ctx, import_name);
2774828150 mi->var_idx = var_idx;
2774928151 return 0;
@@ -28474,20 +28876,10 @@ static int add_closure_var(JSContext *ctx, JSFunctionDef *s, · 724 unmodified lines
2847428876 return -1;
2847528877 }
2847628878
28477− if (s->closure_var_count >= s->closure_var_size) {
28478− JSClosureVar *new_tab;
28479− int new_size;
28480− size_t slack;
28481− new_size = max_int(s->closure_var_count + 1,
28482− s->closure_var_size * 3 / 2);
28483− new_tab = js_realloc2(ctx, s->closure_var,
28484− new_size * sizeof(JSClosureVar), &slack);
28485− if (!new_tab)
28486− return -1;
28487− new_size += slack / sizeof(*new_tab);
28488− s->closure_var = new_tab;
28489− s->closure_var_size = new_size;
28490− }
28879+ if (js_resize_array(ctx, (void **)&s->closure_var,
28880+ sizeof(s->closure_var[0]),
28881+ &s->closure_var_size, s->closure_var_count + 1))
28882+ return -1;
2849128883 cv = &s->closure_var[s->closure_var_count++];
2849228884 cv->is_local = is_local;
2849328885 cv->is_arg = is_arg;
@@ -29243,8 +29635,6 @@ static int resolve_scope_private_field1(JSContext *ctx, · 749 unmodified lines
2924329635 }
2924429636 scope_level = fd->parent_scope_level;
2924529637 if (!fd->parent) {
29246− char buf[ATOM_GET_STR_BUF_SIZE];
29247−
2924829638 if (fd->is_eval) {
2924929639 /* closure of the eval function (top level) */
2925029640 for (idx = 0; idx < fd->closure_var_count; idx++) {
@@ -29267,8 +29657,8 @@ static int resolve_scope_private_field1(JSContext *ctx, · 16 unmodified lines
2926729657 }
2926829658 }
2926929659 /* XXX: no line number info */
29270− JS_ThrowSyntaxError(ctx, "undefined private field %s",
29271− JS_AtomGetStr(ctx, buf, sizeof(buf), var_name));
29660+ JS_ThrowSyntaxErrorAtom(ctx, "undefined private field '%s'",
29661+ var_name);
2927229662 return -1;
2927329663 } else {
2927429664 fd = fd->parent;
@@ -31535,9 +31925,8 @@ static int add_module_variables(JSContext *ctx, JSFunctionDef *fd) · 2260 unmodified lines
3153531925 if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
3153631926 idx = find_closure_var(ctx, fd, me->local_name);
3153731927 if (idx < 0) {
31538− char buf1[ATOM_GET_STR_BUF_SIZE];
31539− JS_ThrowSyntaxError(ctx, "exported variable '%s' does not exist",
31540− JS_AtomGetStr(ctx, buf1, sizeof(buf1), me->local_name));
31928+ JS_ThrowSyntaxErrorAtom(ctx, "exported variable '%s' does not exist",
31929+ me->local_name);
3154131930 return -1;
3154231931 }
3154331932 me->u.local.var_idx = idx;
@@ -32559,6 +32948,8 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj, · 1015 unmodified lines
3255932948 m = JS_VALUE_GET_PTR(fun_obj);
3256032949 /* the module refcount should be >= 2 */
3256132950 JS_FreeValue(ctx, fun_obj);
32951+ if (js_create_module_function(ctx, m) < 0)
32952+ goto fail;
3256232953 if (js_instantiate_module(ctx, m) < 0)
3256332954 goto fail;
3256432955 ret_val = js_evaluate_module(ctx, m);
@@ -32769,6 +33160,110 @@ int JS_ResolveModule(JSContext *ctx, JSValueConst obj) · 204 unmodified lines
3276933160 return 0;
3277033161 }
3277133162
33163+/*******************************************************************/
33164+/* object list */
33165+
33166+typedef struct {
33167+ JSObject *obj;
33168+ uint32_t hash_next; /* -1 if no next entry */
33169+} JSObjectListEntry;
33170+
33171+/* XXX: reuse it to optimize weak references */
33172+typedef struct {
33173+ JSObjectListEntry *object_tab;
33174+ int object_count;
33175+ int object_size;
33176+ uint32_t *hash_table;
33177+ uint32_t hash_size;
33178+} JSObjectList;
33179+
33180+static void js_object_list_init(JSObjectList *s)
33181+{
33182+ memset(s, 0, sizeof(*s));
33183+}
33184+
33185+static uint32_t js_object_list_get_hash(JSObject *p, uint32_t hash_size)
33186+{
33187+ return ((uintptr_t)p * 3163) & (hash_size - 1);
33188+}
33189+
33190+static int js_object_list_resize_hash(JSContext *ctx, JSObjectList *s,
33191+ uint32_t new_hash_size)
33192+{
33193+ JSObjectListEntry *e;
33194+ uint32_t i, h, *new_hash_table;
33195+
33196+ new_hash_table = js_malloc(ctx, sizeof(new_hash_table[0]) * new_hash_size);
33197+ if (!new_hash_table)
33198+ return -1;
33199+ js_free(ctx, s->hash_table);
33200+ s->hash_table = new_hash_table;
33201+ s->hash_size = new_hash_size;
33202+
33203+ for(i = 0; i < s->hash_size; i++) {
33204+ s->hash_table[i] = -1;
33205+ }
33206+ for(i = 0; i < s->object_count; i++) {
33207+ e = &s->object_tab[i];
33208+ h = js_object_list_get_hash(e->obj, s->hash_size);
33209+ e->hash_next = s->hash_table[h];
33210+ s->hash_table[h] = i;
33211+ }
33212+ return 0;
33213+}
33214+
33215+/* the reference count of 'obj' is not modified. Return 0 if OK, -1 if
33216+ memory error */
33217+static int js_object_list_add(JSContext *ctx, JSObjectList *s, JSObject *obj)
33218+{
33219+ JSObjectListEntry *e;
33220+ uint32_t h, new_hash_size;
33221+
33222+ if (js_resize_array(ctx, (void *)&s->object_tab,
33223+ sizeof(s->object_tab[0]),
33224+ &s->object_size, s->object_count + 1))
33225+ return -1;
33226+ if (unlikely((s->object_count + 1) >= s->hash_size)) {
33227+ new_hash_size = max_uint32(s->hash_size, 4);
33228+ while (new_hash_size <= s->object_count)
33229+ new_hash_size *= 2;
33230+ if (js_object_list_resize_hash(ctx, s, new_hash_size))
33231+ return -1;
33232+ }
33233+ e = &s->object_tab[s->object_count++];
33234+ h = js_object_list_get_hash(obj, s->hash_size);
33235+ e->obj = obj;
33236+ e->hash_next = s->hash_table[h];
33237+ s->hash_table[h] = s->object_count - 1;
33238+ return 0;
33239+}
33240+
33241+/* return -1 if not present or the object index */
33242+static int js_object_list_find(JSContext *ctx, JSObjectList *s, JSObject *obj)
33243+{
33244+ JSObjectListEntry *e;
33245+ uint32_t h, p;
33246+
33247+ /* must test empty size because there is no hash table */
33248+ if (s->object_count == 0)
33249+ return -1;
33250+ h = js_object_list_get_hash(obj, s->hash_size);
33251+ p = s->hash_table[h];
33252+ while (p != -1) {
33253+ e = &s->object_tab[p];
33254+ if (e->obj == obj)
33255+ return p;
33256+ p = e->hash_next;
33257+ }
33258+ return -1;
33259+}
33260+
33261+static void js_object_list_end(JSContext *ctx, JSObjectList *s)
33262+{
33263+ js_free(ctx, s->object_tab);
33264+ js_free(ctx, s->hash_table);
33265+}
33266+
3277233267 /*******************************************************************/
3277333268 /* binary object writer & reader */
3277433269
@@ -32788,6 +33283,12 @@ typedef enum BCTagEnum { · 13 unmodified lines
3278833283 BC_TAG_TEMPLATE_OBJECT,
3278933284 BC_TAG_FUNCTION_BYTECODE,
3279033285 BC_TAG_MODULE,
33286+ BC_TAG_TYPED_ARRAY,
33287+ BC_TAG_ARRAY_BUFFER,
33288+ BC_TAG_SHARED_ARRAY_BUFFER,
33289+ BC_TAG_DATE,
33290+ BC_TAG_OBJECT_VALUE,
33291+ BC_TAG_OBJECT_REFERENCE,
3279133292 } BCTagEnum;
3279233293
3279333294 #ifdef CONFIG_BIGNUM
@@ -32805,14 +33306,21 @@ typedef enum BCTagEnum { · 11 unmodified lines
3280533306 typedef struct BCWriterState {
3280633307 JSContext *ctx;
3280733308 DynBuf dbuf;
32808− BOOL byte_swap;
32809− BOOL allow_bytecode;
33309+ BOOL byte_swap : 8;
33310+ BOOL allow_bytecode : 8;
33311+ BOOL allow_sab : 8;
33312+ BOOL allow_reference : 8;
3281033313 uint32_t first_atom;
3281133314 uint32_t *atom_to_idx;
3281233315 int atom_to_idx_size;
3281333316 JSAtom *idx_to_atom;
3281433317 int idx_to_atom_count;
3281533318 int idx_to_atom_size;
33319+ uint8_t **sab_tab;
33320+ int sab_tab_len;
33321+ int sab_tab_size;
33322+ /* list of referenced objects (used if allow_reference = TRUE) */
33323+ JSObjectList object_list;
3281633324 } BCWriterState;
3281733325
3281833326 #ifdef DUMP_READ_OBJECT
@@ -32833,6 +33341,12 @@ static const char * const bc_tag_str[] = { · 14 unmodified lines
3283333341 "template",
3283433342 "function",
3283533343 "module",
33344+ "TypedArray",
33345+ "ArrayBuffer",
33346+ "SharedArrayBuffer",
33347+ "Date",
33348+ "ObjectValue",
33349+ "ObjectReference",
3283633350 };
3283733351 #endif
3283833352
@@ -32892,36 +33406,20 @@ static int bc_atom_to_idx(BCWriterState *s, uint32_t *pres, JSAtom atom) · 53 unmodified lines
3289233406 return 0;
3289333407 }
3289433408 if (atom >= s->atom_to_idx_size) {
32895− size_t new_size, i, slack;
32896− uint32_t *new_tab;
32897− /* XXX: potential arithmetic overflow */
32898− new_size = s->atom_to_idx_size * 3 / 2;
32899− if ((atom + 1) > new_size)
32900− new_size = atom + 1;
32901− new_tab = js_realloc2(s->ctx, s->atom_to_idx,
32902− new_size * sizeof(s->atom_to_idx[0]), &slack);
32903− if (!new_tab)
32904− goto fail;
32905− new_size += slack / sizeof(*new_tab);
32906− for(i = s->atom_to_idx_size; i < new_size; i++)
32907− new_tab[i] = 0;
32908− s->atom_to_idx = new_tab;
32909− s->atom_to_idx_size = new_size;
32910− }
32911− if ((s->idx_to_atom_count + 1) > s->idx_to_atom_size) {
32912− size_t new_size, slack;
32913− JSAtom *new_tab;
32914− new_size = s->idx_to_atom_size * 3 / 2;
32915− if ((s->idx_to_atom_count + 1) > new_size)
32916− new_size = s->idx_to_atom_count + 1;
32917− new_tab = js_realloc2(s->ctx, s->idx_to_atom,
32918− new_size * sizeof(s->idx_to_atom[0]), &slack);
32919− if (!new_tab)
32920− goto fail;
32921− new_size += slack / sizeof(*new_tab);
32922− s->idx_to_atom = new_tab;
32923− s->idx_to_atom_size = new_size;
33409+ int old_size, i;
33410+ old_size = s->atom_to_idx_size;
33411+ if (js_resize_array(s->ctx, (void **)&s->atom_to_idx,
33412+ sizeof(s->atom_to_idx[0]), &s->atom_to_idx_size,
33413+ atom + 1))
33414+ return -1;
33415+ /* XXX: could add a specific js_resize_array() function to do it */
33416+ for(i = old_size; i < s->atom_to_idx_size; i++)
33417+ s->atom_to_idx[i] = 0;
3292433418 }
33419+ if (js_resize_array(s->ctx, (void **)&s->idx_to_atom,
33420+ sizeof(s->idx_to_atom[0]),
33421+ &s->idx_to_atom_size, s->idx_to_atom_count + 1))
33422+ goto fail;
3292533423
3292633424 v = s->idx_to_atom_count++;
3292733425 s->idx_to_atom[v] = atom + s->first_atom;
@@ -33204,10 +33702,276 @@ static int JS_WriteBigNum(BCWriterState *s, JSValueConst obj) · 276 unmodified lines
3320433702 }
3320533703 #endif /* CONFIG_BIGNUM */
3320633704
33705+static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj);
33706+
33707+static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
33708+{
33709+ JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
33710+ uint32_t flags;
33711+ int idx, i;
33712+
33713+ bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
33714+ flags = idx = 0;
33715+ bc_set_flags(&flags, &idx, b->has_prototype, 1);
33716+ bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
33717+ bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
33718+ bc_set_flags(&flags, &idx, b->need_home_object, 1);
33719+ bc_set_flags(&flags, &idx, b->func_kind, 2);
33720+ bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
33721+ bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
33722+ bc_set_flags(&flags, &idx, b->super_allowed, 1);
33723+ bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
33724+ bc_set_flags(&flags, &idx, b->has_debug, 1);
33725+ bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
33726+ assert(idx <= 16);
33727+ bc_put_u16(s, flags);
33728+ bc_put_u8(s, b->js_mode);
33729+ bc_put_atom(s, b->func_name);
33730+
33731+ bc_put_leb128(s, b->arg_count);
33732+ bc_put_leb128(s, b->var_count);
33733+ bc_put_leb128(s, b->defined_arg_count);
33734+ bc_put_leb128(s, b->stack_size);
33735+ bc_put_leb128(s, b->closure_var_count);
33736+ bc_put_leb128(s, b->cpool_count);
33737+ bc_put_leb128(s, b->byte_code_len);
33738+ if (b->vardefs) {
33739+ bc_put_leb128(s, b->arg_count + b->var_count);
33740+ for(i = 0; i < b->arg_count + b->var_count; i++) {
33741+ JSVarDef *vd = &b->vardefs[i];
33742+ bc_put_atom(s, vd->var_name);
33743+ bc_put_leb128(s, vd->scope_level);
33744+ bc_put_leb128(s, vd->scope_next + 1);
33745+ flags = idx = 0;
33746+ bc_set_flags(&flags, &idx, vd->var_kind, 4);
33747+ bc_set_flags(&flags, &idx, vd->is_func_var, 1);
33748+ bc_set_flags(&flags, &idx, vd->is_const, 1);
33749+ bc_set_flags(&flags, &idx, vd->is_lexical, 1);
33750+ bc_set_flags(&flags, &idx, vd->is_captured, 1);
33751+ assert(idx <= 8);
33752+ bc_put_u8(s, flags);
33753+ }
33754+ } else {
33755+ bc_put_leb128(s, 0);
33756+ }
33757+
33758+ for(i = 0; i < b->closure_var_count; i++) {
33759+ JSClosureVar *cv = &b->closure_var[i];
33760+ bc_put_atom(s, cv->var_name);
33761+ bc_put_leb128(s, cv->var_idx);
33762+ flags = idx = 0;
33763+ bc_set_flags(&flags, &idx, cv->is_local, 1);
33764+ bc_set_flags(&flags, &idx, cv->is_arg, 1);
33765+ bc_set_flags(&flags, &idx, cv->is_const, 1);
33766+ bc_set_flags(&flags, &idx, cv->is_lexical, 1);
33767+ bc_set_flags(&flags, &idx, cv->var_kind, 4);
33768+ assert(idx <= 8);
33769+ bc_put_u8(s, flags);
33770+ }
33771+
33772+ if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
33773+ goto fail;
33774+
33775+ if (b->has_debug) {
33776+ bc_put_atom(s, b->debug.filename);
33777+ bc_put_leb128(s, b->debug.line_num);
33778+ bc_put_leb128(s, b->debug.pc2line_len);
33779+ dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
33780+ }
33781+
33782+ for(i = 0; i < b->cpool_count; i++) {
33783+ if (JS_WriteObjectRec(s, b->cpool[i]))
33784+ goto fail;
33785+ }
33786+ return 0;
33787+ fail:
33788+ return -1;
33789+}
33790+
33791+static int JS_WriteModule(BCWriterState *s, JSValueConst obj)
33792+{
33793+ JSModuleDef *m = JS_VALUE_GET_PTR(obj);
33794+ int i;
33795+
33796+ bc_put_u8(s, BC_TAG_MODULE);
33797+ bc_put_atom(s, m->module_name);
33798+
33799+ bc_put_leb128(s, m->req_module_entries_count);
33800+ for(i = 0; i < m->req_module_entries_count; i++) {
33801+ JSReqModuleEntry *rme = &m->req_module_entries[i];
33802+ bc_put_atom(s, rme->module_name);
33803+ }
33804+
33805+ bc_put_leb128(s, m->export_entries_count);
33806+ for(i = 0; i < m->export_entries_count; i++) {
33807+ JSExportEntry *me = &m->export_entries[i];
33808+ bc_put_u8(s, me->export_type);
33809+ if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
33810+ bc_put_leb128(s, me->u.local.var_idx);
33811+ } else {
33812+ bc_put_leb128(s, me->u.req_module_idx);
33813+ bc_put_atom(s, me->local_name);
33814+ }
33815+ bc_put_atom(s, me->export_name);
33816+ }
33817+
33818+ bc_put_leb128(s, m->star_export_entries_count);
33819+ for(i = 0; i < m->star_export_entries_count; i++) {
33820+ JSStarExportEntry *se = &m->star_export_entries[i];
33821+ bc_put_leb128(s, se->req_module_idx);
33822+ }
33823+
33824+ bc_put_leb128(s, m->import_entries_count);
33825+ for(i = 0; i < m->import_entries_count; i++) {
33826+ JSImportEntry *mi = &m->import_entries[i];
33827+ bc_put_leb128(s, mi->var_idx);
33828+ bc_put_atom(s, mi->import_name);
33829+ bc_put_leb128(s, mi->req_module_idx);
33830+ }
33831+
33832+ if (JS_WriteObjectRec(s, m->func_obj))
33833+ goto fail;
33834+ return 0;
33835+ fail:
33836+ return -1;
33837+}
33838+
33839+static int JS_WriteArray(BCWriterState *s, JSValueConst obj)
33840+{
33841+ JSObject *p = JS_VALUE_GET_OBJ(obj);
33842+ uint32_t i, len;
33843+ JSValue val;
33844+ int ret;
33845+ BOOL is_template;
33846+
33847+ if (s->allow_bytecode && !p->extensible) {
33848+ /* not extensible array: we consider it is a
33849+ template when we are saving bytecode */
33850+ bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
33851+ is_template = TRUE;
33852+ } else {
33853+ bc_put_u8(s, BC_TAG_ARRAY);
33854+ is_template = FALSE;
33855+ }
33856+ if (js_get_length32(s->ctx, &len, obj))
33857+ goto fail1;
33858+ bc_put_leb128(s, len);
33859+ for(i = 0; i < len; i++) {
33860+ val = JS_GetPropertyUint32(s->ctx, obj, i);
33861+ if (JS_IsException(val))
33862+ goto fail1;
33863+ ret = JS_WriteObjectRec(s, val);
33864+ JS_FreeValue(s->ctx, val);
33865+ if (ret)
33866+ goto fail1;
33867+ }
33868+ if (is_template) {
33869+ val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
33870+ if (JS_IsException(val))
33871+ goto fail1;
33872+ ret = JS_WriteObjectRec(s, val);
33873+ JS_FreeValue(s->ctx, val);
33874+ if (ret)
33875+ goto fail1;
33876+ }
33877+ return 0;
33878+ fail1:
33879+ return -1;
33880+}
33881+
33882+static int JS_WriteObjectTag(BCWriterState *s, JSValueConst obj)
33883+{
33884+ JSObject *p = JS_VALUE_GET_OBJ(obj);
33885+ uint32_t i, prop_count;
33886+ JSShape *sh;
33887+ JSShapeProperty *pr;
33888+ int pass;
33889+ JSAtom atom;
33890+
33891+ bc_put_u8(s, BC_TAG_OBJECT);
33892+ prop_count = 0;
33893+ sh = p->shape;
33894+ for(pass = 0; pass < 2; pass++) {
33895+ if (pass == 1)
33896+ bc_put_leb128(s, prop_count);
33897+ for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
33898+ atom = pr->atom;
33899+ if (atom != JS_ATOM_NULL &&
33900+ JS_AtomIsString(s->ctx, atom) &&
33901+ (pr->flags & JS_PROP_ENUMERABLE)) {
33902+ if (pr->flags & JS_PROP_TMASK) {
33903+ JS_ThrowTypeError(s->ctx, "only value properties are supported");
33904+ goto fail;
33905+ }
33906+ if (pass == 0) {
33907+ prop_count++;
33908+ } else {
33909+ bc_put_atom(s, atom);
33910+ if (JS_WriteObjectRec(s, p->prop[i].u.value))
33911+ goto fail;
33912+ }
33913+ }
33914+ }
33915+ }
33916+ return 0;
33917+ fail:
33918+ return -1;
33919+}
33920+
33921+static int JS_WriteTypedArray(BCWriterState *s, JSValueConst obj)
33922+{
33923+ JSObject *p = JS_VALUE_GET_OBJ(obj);
33924+ JSTypedArray *ta = p->u.typed_array;
33925+
33926+ bc_put_u8(s, BC_TAG_TYPED_ARRAY);
33927+ bc_put_u8(s, p->class_id - JS_CLASS_UINT8C_ARRAY);
33928+ bc_put_leb128(s, p->u.array.count);
33929+ bc_put_leb128(s, ta->offset);
33930+ if (JS_WriteObjectRec(s, JS_MKPTR(JS_TAG_OBJECT, ta->buffer)))
33931+ return -1;
33932+ return 0;
33933+}
33934+
33935+static int JS_WriteArrayBuffer(BCWriterState *s, JSValueConst obj)
33936+{
33937+ JSObject *p = JS_VALUE_GET_OBJ(obj);
33938+ JSArrayBuffer *abuf = p->u.array_buffer;
33939+ if (abuf->detached) {
33940+ JS_ThrowTypeErrorDetachedArrayBuffer(s->ctx);
33941+ return -1;
33942+ }
33943+ bc_put_u8(s, BC_TAG_ARRAY_BUFFER);
33944+ bc_put_leb128(s, abuf->byte_length);
33945+ dbuf_put(&s->dbuf, abuf->data, abuf->byte_length);
33946+ return 0;
33947+}
33948+
33949+static int JS_WriteSharedArrayBuffer(BCWriterState *s, JSValueConst obj)
33950+{
33951+ JSObject *p = JS_VALUE_GET_OBJ(obj);
33952+ JSArrayBuffer *abuf = p->u.array_buffer;
33953+ assert(!abuf->detached); /* SharedArrayBuffer are never detached */
33954+ bc_put_u8(s, BC_TAG_SHARED_ARRAY_BUFFER);
33955+ bc_put_leb128(s, abuf->byte_length);
33956+ bc_put_u64(s, (uintptr_t)abuf->data);
33957+ if (js_resize_array(s->ctx, (void **)&s->sab_tab, sizeof(s->sab_tab[0]),
33958+ &s->sab_tab_size, s->sab_tab_len + 1))
33959+ return -1;
33960+ /* keep the SAB pointer so that the user can clone it or free it */
33961+ s->sab_tab[s->sab_tab_len++] = abuf->data;
33962+ return 0;
33963+}
33964+
3320733965 static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj)
3320833966 {
33209− uint32_t tag = JS_VALUE_GET_NORM_TAG(obj);
33967+ uint32_t tag;
33968+
33969+ if (js_check_stack_overflow(s->ctx->rt, 0)) {
33970+ JS_ThrowStackOverflow(s->ctx);
33971+ return -1;
33972+ }
3321033973
33974+ tag = JS_VALUE_GET_NORM_TAG(obj);
3321133975 switch(tag) {
3321233976 case JS_TAG_NULL:
3321333977 bc_put_u8(s, BC_TAG_NULL);
@@ -33238,218 +34002,82 @@ static int JS_WriteObjectRec(BCWriterState *s, JSValueConst obj) · 24 unmodified lines
3323834002 }
3323934003 break;
3324034004 case JS_TAG_FUNCTION_BYTECODE:
33241− {
33242− JSFunctionBytecode *b = JS_VALUE_GET_PTR(obj);
33243− uint32_t flags;
33244− int idx, i;
33245−
33246− if (!s->allow_bytecode)
33247− goto invalid_tag;
33248− bc_put_u8(s, BC_TAG_FUNCTION_BYTECODE);
33249− flags = idx = 0;
33250− bc_set_flags(&flags, &idx, b->has_prototype, 1);
33251− bc_set_flags(&flags, &idx, b->has_simple_parameter_list, 1);
33252− bc_set_flags(&flags, &idx, b->is_derived_class_constructor, 1);
33253− bc_set_flags(&flags, &idx, b->need_home_object, 1);
33254− bc_set_flags(&flags, &idx, b->func_kind, 2);
33255− bc_set_flags(&flags, &idx, b->new_target_allowed, 1);
33256− bc_set_flags(&flags, &idx, b->super_call_allowed, 1);
33257− bc_set_flags(&flags, &idx, b->super_allowed, 1);
33258− bc_set_flags(&flags, &idx, b->arguments_allowed, 1);
33259− bc_set_flags(&flags, &idx, b->has_debug, 1);
33260− bc_set_flags(&flags, &idx, b->backtrace_barrier, 1);
33261− assert(idx <= 16);
33262− bc_put_u16(s, flags);
33263− bc_put_u8(s, b->js_mode);
33264− bc_put_atom(s, b->func_name);
33265−
33266− bc_put_leb128(s, b->arg_count);
33267− bc_put_leb128(s, b->var_count);
33268− bc_put_leb128(s, b->defined_arg_count);
33269− bc_put_leb128(s, b->stack_size);
33270− bc_put_leb128(s, b->closure_var_count);
33271− bc_put_leb128(s, b->cpool_count);
33272− bc_put_leb128(s, b->byte_code_len);
33273− if (b->vardefs) {
33274− bc_put_leb128(s, b->arg_count + b->var_count);
33275− for(i = 0; i < b->arg_count + b->var_count; i++) {
33276− JSVarDef *vd = &b->vardefs[i];
33277− bc_put_atom(s, vd->var_name);
33278− bc_put_leb128(s, vd->scope_level);
33279− bc_put_leb128(s, vd->scope_next + 1);
33280− flags = idx = 0;
33281− bc_set_flags(&flags, &idx, vd->var_kind, 4);
33282− bc_set_flags(&flags, &idx, vd->is_func_var, 1);
33283− bc_set_flags(&flags, &idx, vd->is_const, 1);
33284− bc_set_flags(&flags, &idx, vd->is_lexical, 1);
33285− bc_set_flags(&flags, &idx, vd->is_captured, 1);
33286− assert(idx <= 8);
33287− bc_put_u8(s, flags);
33288− }
33289− } else {
33290− bc_put_leb128(s, 0);
33291− }
33292−
33293− for(i = 0; i < b->closure_var_count; i++) {
33294− JSClosureVar *cv = &b->closure_var[i];
33295− bc_put_atom(s, cv->var_name);
33296− bc_put_leb128(s, cv->var_idx);
33297− flags = idx = 0;
33298− bc_set_flags(&flags, &idx, cv->is_local, 1);
33299− bc_set_flags(&flags, &idx, cv->is_arg, 1);
33300− bc_set_flags(&flags, &idx, cv->is_const, 1);
33301− bc_set_flags(&flags, &idx, cv->is_lexical, 1);
33302− bc_set_flags(&flags, &idx, cv->var_kind, 4);
33303− assert(idx <= 8);
33304− bc_put_u8(s, flags);
33305− }
33306−
33307− if (JS_WriteFunctionBytecode(s, b->byte_code_buf, b->byte_code_len))
33308− goto fail;
33309−
33310− if (b->has_debug) {
33311− bc_put_atom(s, b->debug.filename);
33312− bc_put_leb128(s, b->debug.line_num);
33313− bc_put_leb128(s, b->debug.pc2line_len);
33314− dbuf_put(&s->dbuf, b->debug.pc2line_buf, b->debug.pc2line_len);
33315− }
33316−
33317− for(i = 0; i < b->cpool_count; i++) {
33318− if (JS_WriteObjectRec(s, b->cpool[i]))
33319− goto fail;
33320− }
33321− }
34005+ if (!s->allow_bytecode)
34006+ goto invalid_tag;
34007+ if (JS_WriteFunctionTag(s, obj))
34008+ goto fail;
3332234009 break;
3332334010 case JS_TAG_MODULE:
33324− {
33325− JSModuleDef *m = JS_VALUE_GET_PTR(obj);
33326− int i;
33327−
33328− if (!s->allow_bytecode)
33329− goto invalid_tag;
33330− bc_put_u8(s, BC_TAG_MODULE);
33331− bc_put_atom(s, m->module_name);
33332−
33333− bc_put_leb128(s, m->req_module_entries_count);
33334− for(i = 0; i < m->req_module_entries_count; i++) {
33335− JSReqModuleEntry *rme = &m->req_module_entries[i];
33336− bc_put_atom(s, rme->module_name);
33337− }
33338−
33339− bc_put_leb128(s, m->export_entries_count);
33340− for(i = 0; i < m->export_entries_count; i++) {
33341− JSExportEntry *me = &m->export_entries[i];
33342− bc_put_u8(s, me->export_type);
33343− if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
33344− bc_put_leb128(s, me->u.local.var_idx);
33345− } else {
33346− bc_put_leb128(s, me->u.req_module_idx);
33347− bc_put_atom(s, me->local_name);
33348− }
33349− bc_put_atom(s, me->export_name);
33350− }
33351−
33352− bc_put_leb128(s, m->star_export_entries_count);
33353− for(i = 0; i < m->star_export_entries_count; i++) {
33354− JSStarExportEntry *se = &m->star_export_entries[i];
33355− bc_put_leb128(s, se->req_module_idx);
33356− }
33357−
33358− bc_put_leb128(s, m->import_entries_count);
33359− for(i = 0; i < m->import_entries_count; i++) {
33360− JSImportEntry *mi = &m->import_entries[i];
33361− bc_put_leb128(s, mi->var_idx);
33362− bc_put_atom(s, mi->import_name);
33363− bc_put_leb128(s, mi->req_module_idx);
33364− }
33365−
33366− if (JS_WriteObjectRec(s, m->func_obj))
33367− goto fail;
33368− }
34011+ if (!s->allow_bytecode)
34012+ goto invalid_tag;
34013+ if (JS_WriteModule(s, obj))
34014+ goto fail;
3336934015 break;
3337034016 case JS_TAG_OBJECT:
3337134017 {
3337234018 JSObject *p = JS_VALUE_GET_OBJ(obj);
33373− uint32_t i, prop_count, len;
33374− JSShape *sh;
33375− JSShapeProperty *pr;
33376− JSValue val;
33377− int ret, pass;
33378− BOOL is_template;
33379− JSAtom atom;
33380−
33381− if (p->class_id != JS_CLASS_ARRAY &&
33382− p->class_id != JS_CLASS_OBJECT) {
33383− JS_ThrowTypeError(s->ctx, "unsupported object class");
33384− goto fail;
33385− }
33386− if (p->tmp_mark) {
33387− JS_ThrowTypeError(s->ctx, "circular reference");
33388− goto fail;
33389− }
33390− p->tmp_mark = 1;
33391− if (p->class_id == JS_CLASS_ARRAY) {
33392− if (s->allow_bytecode && !p->extensible) {
33393− /* not extensible array: we consider it is a
33394− template when we are saving bytecode */
33395− bc_put_u8(s, BC_TAG_TEMPLATE_OBJECT);
33396− is_template = TRUE;
34019+ int ret, idx;
34020+
34021+ if (s->allow_reference) {
34022+ idx = js_object_list_find(s->ctx, &s->object_list, p);
34023+ if (idx >= 0) {
34024+ bc_put_u8(s, BC_TAG_OBJECT_REFERENCE);
34025+ bc_put_leb128(s, idx);
34026+ break;
3339734027 } else {
33398− bc_put_u8(s, BC_TAG_ARRAY);
33399− is_template = FALSE;
33400− }
33401− if (js_get_length32(s->ctx, &len, obj))
33402− goto fail1;
33403− bc_put_leb128(s, len);
33404− for(i = 0; i < len; i++) {
33405− val = JS_GetPropertyUint32(s->ctx, obj, i);
33406− if (JS_IsException(val))
33407− goto fail1;
33408− ret = JS_WriteObjectRec(s, val);
33409− JS_FreeValue(s->ctx, val);
33410− if (ret)
33411− goto fail1;
33412− }
33413− if (is_template) {
33414− val = JS_GetProperty(s->ctx, obj, JS_ATOM_raw);
33415− if (JS_IsException(val))
33416− goto fail1;
33417− ret = JS_WriteObjectRec(s, val);
33418− JS_FreeValue(s->ctx, val);
33419− if (ret)
33420− goto fail1;
34028+ if (js_object_list_add(s->ctx, &s->object_list, p))
34029+ goto fail;
3342134030 }
3342234031 } else {
33423− bc_put_u8(s, BC_TAG_OBJECT);
33424− prop_count = 0;
33425− sh = p->shape;
33426− for(pass = 0; pass < 2; pass++) {
33427− if (pass == 1)
33428− bc_put_leb128(s, prop_count);
33429− for(i = 0, pr = get_shape_prop(sh); i < sh->prop_count; i++, pr++) {
33430− atom = pr->atom;
33431− if (atom != JS_ATOM_NULL &&
33432− JS_AtomIsString(s->ctx, atom) &&
33433− (pr->flags & JS_PROP_ENUMERABLE)) {
33434− if (pr->flags & JS_PROP_TMASK) {
33435− JS_ThrowTypeError(s->ctx, "only value properties are supported");
33436− goto fail;
33437− }
33438− if (pass == 0) {
33439− prop_count++;
33440− } else {
33441− bc_put_atom(s, atom);
33442− if (JS_WriteObjectRec(s, p->prop[i].u.value)) {
33443− fail1:
33444− p->tmp_mark = 0;
33445− goto fail;
33446− }
33447− }
33448− }
33449− }
34032+ if (p->tmp_mark) {
34033+ JS_ThrowTypeError(s->ctx, "circular reference");
34034+ goto fail;
34035+ }
34036+ p->tmp_mark = 1;
34037+ }
34038+ switch(p->class_id) {
34039+ case JS_CLASS_ARRAY:
34040+ ret = JS_WriteArray(s, obj);
34041+ break;
34042+ case JS_CLASS_OBJECT:
34043+ ret = JS_WriteObjectTag(s, obj);
34044+ break;
34045+ case JS_CLASS_ARRAY_BUFFER:
34046+ ret = JS_WriteArrayBuffer(s, obj);
34047+ break;
34048+ case JS_CLASS_SHARED_ARRAY_BUFFER:
34049+ if (!s->allow_sab)
34050+ goto invalid_tag;
34051+ ret = JS_WriteSharedArrayBuffer(s, obj);
34052+ break;
34053+ case JS_CLASS_DATE:
34054+ bc_put_u8(s, BC_TAG_DATE);
34055+ ret = JS_WriteObjectRec(s, p->u.object_data);
34056+ break;
34057+ case JS_CLASS_NUMBER:
34058+ case JS_CLASS_STRING:
34059+ case JS_CLASS_BOOLEAN:
34060+#ifdef CONFIG_BIGNUM
34061+ case JS_CLASS_BIG_INT:
34062+ case JS_CLASS_BIG_FLOAT:
34063+ case JS_CLASS_BIG_DECIMAL:
34064+#endif
34065+ bc_put_u8(s, BC_TAG_OBJECT_VALUE);
34066+ ret = JS_WriteObjectRec(s, p->u.object_data);
34067+ break;
34068+ default:
34069+ if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
34070+ p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
34071+ ret = JS_WriteTypedArray(s, obj);
34072+ } else {
34073+ JS_ThrowTypeError(s->ctx, "unsupported object class");
34074+ ret = -1;
3345034075 }
34076+ break;
3345134077 }
3345234078 p->tmp_mark = 0;
34079+ if (ret)
34080+ goto fail;
3345334081 }
3345434082 break;
3345534083 #ifdef CONFIG_BIGNUM
@@ -33511,8 +34139,8 @@ static int JS_WriteObjectAtoms(BCWriterState *s) · 55 unmodified lines
3351134139 return -1;
3351234140 }
3351334141
33514−uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
33515− int flags)
34142+uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
34143+ int flags, uint8_t ***psab_tab, size_t *psab_tab_len)
3351634144 {
3351734145 BCWriterState ss, *s = &ss;
3351834146
@@ -33521,29 +34149,48 @@ uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj, · 2 unmodified lines
3352134149 /* XXX: byte swapped output is untested */
3352234150 s->byte_swap = ((flags & JS_WRITE_OBJ_BSWAP) != 0);
3352334151 s->allow_bytecode = ((flags & JS_WRITE_OBJ_BYTECODE) != 0);
34152+ s->allow_sab = ((flags & JS_WRITE_OBJ_SAB) != 0);
34153+ s->allow_reference = ((flags & JS_WRITE_OBJ_REFERENCE) != 0);
3352434154 /* XXX: could use a different version when bytecode is included */
3352534155 if (s->allow_bytecode)
3352634156 s->first_atom = JS_ATOM_END;
3352734157 else
3352834158 s->first_atom = 1;
3352934159 js_dbuf_init(ctx, &s->dbuf);
33530−
34160+ js_object_list_init(&s->object_list);
34161+
3353134162 if (JS_WriteObjectRec(s, obj))
3353234163 goto fail;
3353334164 if (JS_WriteObjectAtoms(s))
3353434165 goto fail;
34166+ js_object_list_end(ctx, &s->object_list);
3353534167 js_free(ctx, s->atom_to_idx);
3353634168 js_free(ctx, s->idx_to_atom);
3353734169 *psize = s->dbuf.size;
34170+ if (psab_tab)
34171+ *psab_tab = s->sab_tab;
34172+ if (psab_tab_len)
34173+ *psab_tab_len = s->sab_tab_len;
3353834174 return s->dbuf.buf;
3353934175 fail:
34176+ js_object_list_end(ctx, &s->object_list);
3354034177 js_free(ctx, s->atom_to_idx);
3354134178 js_free(ctx, s->idx_to_atom);
3354234179 dbuf_free(&s->dbuf);
3354334180 *psize = 0;
34181+ if (psab_tab)
34182+ *psab_tab = NULL;
34183+ if (psab_tab_len)
34184+ *psab_tab_len = 0;
3354434185 return NULL;
3354534186 }
3354634187
34188+uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
34189+ int flags)
34190+{
34191+ return JS_WriteObject2(ctx, psize, obj, flags, NULL, NULL);
34192+}
34193+
3354734194 typedef struct BCReaderState {
3354834195 JSContext *ctx;
3354934196 const uint8_t *buf_start, *ptr, *buf_end;
@@ -33551,8 +34198,15 @@ typedef struct BCReaderState { · 1 unmodified line
3355134198 uint32_t idx_to_atom_count;
3355234199 JSAtom *idx_to_atom;
3355334200 int error_state;
33554− BOOL allow_bytecode;
33555− BOOL is_rom_data;
34201+ BOOL allow_sab : 8;
34202+ BOOL allow_bytecode : 8;
34203+ BOOL is_rom_data : 8;
34204+ BOOL allow_reference : 8;
34205+ /* object references */
34206+ JSObject **objects;
34207+ int objects_count;
34208+ int objects_size;
34209+
3355634210 #ifdef DUMP_READ_OBJECT
3355734211 const uint8_t *ptr_last;
3355834212 int level;
@@ -33756,7 +34410,7 @@ static JSString *JS_ReadString(BCReaderState *s) · 197 unmodified lines
3375634410 p->u.str8[size] = '\0'; /* add the trailing zero for 8 bit strings */
3375734411 }
3375834412 #ifdef DUMP_READ_OBJECT
33759− bc_read_trace(s, "string: "); JS_DumpString(s->ctx->rt, p); printf("\n");
34413+ JS_DumpString(s->ctx->rt, p); printf("\n");
3376034414 #endif
3376134415 return p;
3376234416 }
@@ -33838,8 +34492,6 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) · 75 unmodified lines
3383834492 bf_t *a;
3383934493 int bpos, d;
3384034494
33841− bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
33842−
3384334495 p = js_new_bf(s->ctx);
3384434496 if (!p)
3384534497 goto fail;
@@ -33961,28 +34613,560 @@ static JSValue JS_ReadBigNum(BCReaderState *s, int tag) · 115 unmodified lines
3396134613 }
3396234614 #endif /* CONFIG_BIGNUM */
3396334615
34616+static JSValue JS_ReadObjectRec(BCReaderState *s);
34617+
34618+static int BC_add_object_ref1(BCReaderState *s, JSObject *p)
34619+{
34620+ if (s->allow_reference) {
34621+ if (js_resize_array(s->ctx, (void *)&s->objects,
34622+ sizeof(s->objects[0]),
34623+ &s->objects_size, s->objects_count + 1))
34624+ return -1;
34625+ s->objects[s->objects_count++] = p;
34626+ }
34627+ return 0;
34628+}
34629+
34630+static int BC_add_object_ref(BCReaderState *s, JSValueConst obj)
34631+{
34632+ return BC_add_object_ref1(s, JS_VALUE_GET_OBJ(obj));
34633+}
34634+
34635+static JSValue JS_ReadFunctionTag(BCReaderState *s)
34636+{
34637+ JSContext *ctx = s->ctx;
34638+ JSFunctionBytecode bc, *b;
34639+ JSValue obj = JS_UNDEFINED;
34640+ uint16_t v16;
34641+ uint8_t v8;
34642+ int idx, i, local_count;
34643+ int function_size, cpool_offset, byte_code_offset;
34644+ int closure_var_offset, vardefs_offset;
34645+
34646+ memset(&bc, 0, sizeof(bc));
34647+ bc.header.ref_count = 1;
34648+ //bc.gc_header.mark = 0;
34649+
34650+ if (bc_get_u16(s, &v16))
34651+ goto fail;
34652+ idx = 0;
34653+ bc.has_prototype = bc_get_flags(v16, &idx, 1);
34654+ bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
34655+ bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
34656+ bc.need_home_object = bc_get_flags(v16, &idx, 1);
34657+ bc.func_kind = bc_get_flags(v16, &idx, 2);
34658+ bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
34659+ bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
34660+ bc.super_allowed = bc_get_flags(v16, &idx, 1);
34661+ bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
34662+ bc.has_debug = bc_get_flags(v16, &idx, 1);
34663+ bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
34664+ bc.read_only_bytecode = s->is_rom_data;
34665+ if (bc_get_u8(s, &v8))
34666+ goto fail;
34667+ bc.js_mode = v8;
34668+ if (bc_get_atom(s, &bc.func_name)) //@ atom leak if failure
34669+ goto fail;
34670+ if (bc_get_leb128_u16(s, &bc.arg_count))
34671+ goto fail;
34672+ if (bc_get_leb128_u16(s, &bc.var_count))
34673+ goto fail;
34674+ if (bc_get_leb128_u16(s, &bc.defined_arg_count))
34675+ goto fail;
34676+ if (bc_get_leb128_u16(s, &bc.stack_size))
34677+ goto fail;
34678+ if (bc_get_leb128_int(s, &bc.closure_var_count))
34679+ goto fail;
34680+ if (bc_get_leb128_int(s, &bc.cpool_count))
34681+ goto fail;
34682+ if (bc_get_leb128_int(s, &bc.byte_code_len))
34683+ goto fail;
34684+ if (bc_get_leb128_int(s, &local_count))
34685+ goto fail;
34686+
34687+ if (bc.has_debug) {
34688+ function_size = sizeof(*b);
34689+ } else {
34690+ function_size = offsetof(JSFunctionBytecode, debug);
34691+ }
34692+ cpool_offset = function_size;
34693+ function_size += bc.cpool_count * sizeof(*bc.cpool);
34694+ vardefs_offset = function_size;
34695+ function_size += local_count * sizeof(*bc.vardefs);
34696+ closure_var_offset = function_size;
34697+ function_size += bc.closure_var_count * sizeof(*bc.closure_var);
34698+ byte_code_offset = function_size;
34699+ if (!bc.read_only_bytecode) {
34700+ function_size += bc.byte_code_len;
34701+ }
34702+
34703+ b = js_mallocz(ctx, function_size);
34704+ if (!b)
34705+ return JS_EXCEPTION;
34706+
34707+ memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
34708+ b->header.ref_count = 1;
34709+ add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
34710+
34711+ obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
34712+
34713+#ifdef DUMP_READ_OBJECT
34714+ bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n");
34715+#endif
34716+ bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
34717+ b->arg_count, b->var_count, b->defined_arg_count,
34718+ b->closure_var_count, b->cpool_count);
34719+ bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
34720+ b->stack_size, b->byte_code_len, local_count);
34721+
34722+ if (local_count != 0) {
34723+ bc_read_trace(s, "vars {\n");
34724+ b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
34725+ for(i = 0; i < local_count; i++) {
34726+ JSVarDef *vd = &b->vardefs[i];
34727+ if (bc_get_atom(s, &vd->var_name))
34728+ goto fail;
34729+ if (bc_get_leb128_int(s, &vd->scope_level))
34730+ goto fail;
34731+ if (bc_get_leb128_int(s, &vd->scope_next))
34732+ goto fail;
34733+ vd->scope_next--;
34734+ if (bc_get_u8(s, &v8))
34735+ goto fail;
34736+ idx = 0;
34737+ vd->var_kind = bc_get_flags(v8, &idx, 4);
34738+ vd->is_func_var = bc_get_flags(v8, &idx, 1);
34739+ vd->is_const = bc_get_flags(v8, &idx, 1);
34740+ vd->is_lexical = bc_get_flags(v8, &idx, 1);
34741+ vd->is_captured = bc_get_flags(v8, &idx, 1);
34742+#ifdef DUMP_READ_OBJECT
34743+ bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
34744+#endif
34745+ }
34746+ bc_read_trace(s, "}\n");
34747+ }
34748+ if (b->closure_var_count != 0) {
34749+ bc_read_trace(s, "closure vars {\n");
34750+ b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
34751+ for(i = 0; i < b->closure_var_count; i++) {
34752+ JSClosureVar *cv = &b->closure_var[i];
34753+ int var_idx;
34754+ if (bc_get_atom(s, &cv->var_name))
34755+ goto fail;
34756+ if (bc_get_leb128_int(s, &var_idx))
34757+ goto fail;
34758+ cv->var_idx = var_idx;
34759+ if (bc_get_u8(s, &v8))
34760+ goto fail;
34761+ idx = 0;
34762+ cv->is_local = bc_get_flags(v8, &idx, 1);
34763+ cv->is_arg = bc_get_flags(v8, &idx, 1);
34764+ cv->is_const = bc_get_flags(v8, &idx, 1);
34765+ cv->is_lexical = bc_get_flags(v8, &idx, 1);
34766+ cv->var_kind = bc_get_flags(v8, &idx, 4);
34767+#ifdef DUMP_READ_OBJECT
34768+ bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n");
34769+#endif
34770+ }
34771+ bc_read_trace(s, "}\n");
34772+ }
34773+ {
34774+ bc_read_trace(s, "bytecode {\n");
34775+ if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
34776+ goto fail;
34777+ bc_read_trace(s, "}\n");
34778+ }
34779+ if (b->has_debug) {
34780+ /* read optional debug information */
34781+ bc_read_trace(s, "debug {\n");
34782+ if (bc_get_atom(s, &b->debug.filename))
34783+ goto fail;
34784+ if (bc_get_leb128_int(s, &b->debug.line_num))
34785+ goto fail;
34786+ if (bc_get_leb128_int(s, &b->debug.pc2line_len))
34787+ goto fail;
34788+ if (b->debug.pc2line_len) {
34789+ b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
34790+ if (!b->debug.pc2line_buf)
34791+ goto fail;
34792+ if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
34793+ goto fail;
34794+ }
34795+#ifdef DUMP_READ_OBJECT
34796+ bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
34797+#endif
34798+ bc_read_trace(s, "}\n");
34799+ }
34800+ if (b->cpool_count != 0) {
34801+ bc_read_trace(s, "cpool {\n");
34802+ b->cpool = (void *)((uint8_t*)b + cpool_offset);
34803+ for(i = 0; i < b->cpool_count; i++) {
34804+ JSValue val;
34805+ val = JS_ReadObjectRec(s);
34806+ if (JS_IsException(val))
34807+ goto fail;
34808+ b->cpool[i] = val;
34809+ }
34810+ bc_read_trace(s, "}\n");
34811+ }
34812+ b->realm = JS_DupContext(ctx);
34813+ return obj;
34814+ fail:
34815+ JS_FreeValue(ctx, obj);
34816+ return JS_EXCEPTION;
34817+}
34818+
34819+static JSValue JS_ReadModule(BCReaderState *s)
34820+{
34821+ JSContext *ctx = s->ctx;
34822+ JSValue obj;
34823+ JSModuleDef *m = NULL;
34824+ JSAtom module_name;
34825+ int i;
34826+ uint8_t v8;
34827+
34828+ if (bc_get_atom(s, &module_name))
34829+ goto fail;
34830+#ifdef DUMP_READ_OBJECT
34831+ bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n");
34832+#endif
34833+ m = js_new_module_def(ctx, module_name);
34834+ if (!m)
34835+ goto fail;
34836+ obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
34837+ if (bc_get_leb128_int(s, &m->req_module_entries_count))
34838+ goto fail;
34839+ if (m->req_module_entries_count != 0) {
34840+ m->req_module_entries_size = m->req_module_entries_count;
34841+ m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
34842+ if (!m->req_module_entries)
34843+ goto fail;
34844+ for(i = 0; i < m->req_module_entries_count; i++) {
34845+ JSReqModuleEntry *rme = &m->req_module_entries[i];
34846+ if (bc_get_atom(s, &rme->module_name))
34847+ goto fail;
34848+ }
34849+ }
34850+
34851+ if (bc_get_leb128_int(s, &m->export_entries_count))
34852+ goto fail;
34853+ if (m->export_entries_count != 0) {
34854+ m->export_entries_size = m->export_entries_count;
34855+ m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
34856+ if (!m->export_entries)
34857+ goto fail;
34858+ for(i = 0; i < m->export_entries_count; i++) {
34859+ JSExportEntry *me = &m->export_entries[i];
34860+ if (bc_get_u8(s, &v8))
34861+ goto fail;
34862+ me->export_type = v8;
34863+ if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
34864+ if (bc_get_leb128_int(s, &me->u.local.var_idx))
34865+ goto fail;
34866+ } else {
34867+ if (bc_get_leb128_int(s, &me->u.req_module_idx))
34868+ goto fail;
34869+ if (bc_get_atom(s, &me->local_name))
34870+ goto fail;
34871+ }
34872+ if (bc_get_atom(s, &me->export_name))
34873+ goto fail;
34874+ }
34875+ }
34876+
34877+ if (bc_get_leb128_int(s, &m->star_export_entries_count))
34878+ goto fail;
34879+ if (m->star_export_entries_count != 0) {
34880+ m->star_export_entries_size = m->star_export_entries_count;
34881+ m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
34882+ if (!m->star_export_entries)
34883+ goto fail;
34884+ for(i = 0; i < m->star_export_entries_count; i++) {
34885+ JSStarExportEntry *se = &m->star_export_entries[i];
34886+ if (bc_get_leb128_int(s, &se->req_module_idx))
34887+ goto fail;
34888+ }
34889+ }
34890+
34891+ if (bc_get_leb128_int(s, &m->import_entries_count))
34892+ goto fail;
34893+ if (m->import_entries_count != 0) {
34894+ m->import_entries_size = m->import_entries_count;
34895+ m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
34896+ if (!m->import_entries)
34897+ goto fail;
34898+ for(i = 0; i < m->import_entries_count; i++) {
34899+ JSImportEntry *mi = &m->import_entries[i];
34900+ if (bc_get_leb128_int(s, &mi->var_idx))
34901+ goto fail;
34902+ if (bc_get_atom(s, &mi->import_name))
34903+ goto fail;
34904+ if (bc_get_leb128_int(s, &mi->req_module_idx))
34905+ goto fail;
34906+ }
34907+ }
34908+
34909+ m->func_obj = JS_ReadObjectRec(s);
34910+ if (JS_IsException(m->func_obj))
34911+ goto fail;
34912+ return obj;
34913+ fail:
34914+ if (m) {
34915+ js_free_module_def(ctx, m);
34916+ }
34917+ return JS_EXCEPTION;
34918+}
34919+
34920+static JSValue JS_ReadObjectTag(BCReaderState *s)
34921+{
34922+ JSContext *ctx = s->ctx;
34923+ JSValue obj;
34924+ uint32_t prop_count, i;
34925+ JSAtom atom;
34926+ JSValue val;
34927+ int ret;
34928+
34929+ obj = JS_NewObject(ctx);
34930+ if (BC_add_object_ref(s, obj))
34931+ goto fail;
34932+ if (bc_get_leb128(s, &prop_count))
34933+ goto fail;
34934+ for(i = 0; i < prop_count; i++) {
34935+ if (bc_get_atom(s, &atom))
34936+ goto fail;
34937+#ifdef DUMP_READ_OBJECT
34938+ bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n");
34939+#endif
34940+ val = JS_ReadObjectRec(s);
34941+ if (JS_IsException(val)) {
34942+ JS_FreeAtom(ctx, atom);
34943+ goto fail;
34944+ }
34945+ ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
34946+ JS_FreeAtom(ctx, atom);
34947+ if (ret < 0)
34948+ goto fail;
34949+ }
34950+ return obj;
34951+ fail:
34952+ JS_FreeValue(ctx, obj);
34953+ return JS_EXCEPTION;
34954+}
34955+
34956+static JSValue JS_ReadArray(BCReaderState *s, int tag)
34957+{
34958+ JSContext *ctx = s->ctx;
34959+ JSValue obj;
34960+ uint32_t len, i;
34961+ JSValue val;
34962+ int ret, prop_flags;
34963+ BOOL is_template;
34964+
34965+ obj = JS_NewArray(ctx);
34966+ if (BC_add_object_ref(s, obj))
34967+ goto fail;
34968+ is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
34969+ if (bc_get_leb128(s, &len))
34970+ goto fail;
34971+ for(i = 0; i < len; i++) {
34972+ val = JS_ReadObjectRec(s);
34973+ if (JS_IsException(val))
34974+ goto fail;
34975+ if (is_template)
34976+ prop_flags = JS_PROP_ENUMERABLE;
34977+ else
34978+ prop_flags = JS_PROP_C_W_E;
34979+ ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
34980+ prop_flags);
34981+ if (ret < 0)
34982+ goto fail;
34983+ }
34984+ if (is_template) {
34985+ val = JS_ReadObjectRec(s);
34986+ if (JS_IsException(val))
34987+ goto fail;
34988+ if (!JS_IsUndefined(val)) {
34989+ ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
34990+ if (ret < 0)
34991+ goto fail;
34992+ }
34993+ JS_PreventExtensions(ctx, obj);
34994+ }
34995+ return obj;
34996+ fail:
34997+ JS_FreeValue(ctx, obj);
34998+ return JS_EXCEPTION;
34999+}
35000+
35001+static JSValue JS_ReadTypedArray(BCReaderState *s)
35002+{
35003+ JSContext *ctx = s->ctx;
35004+ JSValue obj = JS_UNDEFINED, array_buffer = JS_UNDEFINED;
35005+ uint8_t array_tag;
35006+ JSValueConst args[3];
35007+ uint32_t offset, len, idx;
35008+
35009+ if (bc_get_u8(s, &array_tag))
35010+ return JS_EXCEPTION;
35011+ if (array_tag >= JS_TYPED_ARRAY_COUNT)
35012+ return JS_ThrowTypeError(ctx, "invalid typed array");
35013+ if (bc_get_leb128(s, &len))
35014+ return JS_EXCEPTION;
35015+ if (bc_get_leb128(s, &offset))
35016+ return JS_EXCEPTION;
35017+ /* XXX: this hack could be avoided if the typed array could be
35018+ created before the array buffer */
35019+ idx = s->objects_count;
35020+ if (BC_add_object_ref1(s, NULL))
35021+ goto fail;
35022+ array_buffer = JS_ReadObjectRec(s);
35023+ if (JS_IsException(array_buffer))
35024+ return JS_EXCEPTION;
35025+ if (!js_get_array_buffer(ctx, array_buffer)) {
35026+ JS_FreeValue(ctx, array_buffer);
35027+ return JS_EXCEPTION;
35028+ }
35029+ args[0] = array_buffer;
35030+ args[1] = JS_NewInt64(ctx, offset);
35031+ args[2] = JS_NewInt64(ctx, len);
35032+ obj = js_typed_array_constructor(ctx, JS_UNDEFINED,
35033+ 3, args,
35034+ JS_CLASS_UINT8C_ARRAY + array_tag);
35035+ if (JS_IsException(obj))
35036+ goto fail;
35037+ if (s->allow_reference) {
35038+ s->objects[idx] = JS_VALUE_GET_OBJ(obj);
35039+ }
35040+ JS_FreeValue(ctx, array_buffer);
35041+ return obj;
35042+ fail:
35043+ JS_FreeValue(ctx, array_buffer);
35044+ JS_FreeValue(ctx, obj);
35045+ return JS_EXCEPTION;
35046+}
35047+
35048+static JSValue JS_ReadArrayBuffer(BCReaderState *s)
35049+{
35050+ JSContext *ctx = s->ctx;
35051+ uint32_t byte_length;
35052+ JSValue obj;
35053+
35054+ if (bc_get_leb128(s, &byte_length))
35055+ return JS_EXCEPTION;
35056+ if (unlikely(s->buf_end - s->ptr < byte_length)) {
35057+ bc_read_error_end(s);
35058+ return JS_EXCEPTION;
35059+ }
35060+ obj = JS_NewArrayBufferCopy(ctx, s->ptr, byte_length);
35061+ if (JS_IsException(obj))
35062+ goto fail;
35063+ if (BC_add_object_ref(s, obj))
35064+ goto fail;
35065+ s->ptr += byte_length;
35066+ return obj;
35067+ fail:
35068+ JS_FreeValue(ctx, obj);
35069+ return JS_EXCEPTION;
35070+}
35071+
35072+static JSValue JS_ReadSharedArrayBuffer(BCReaderState *s)
35073+{
35074+ JSContext *ctx = s->ctx;
35075+ uint32_t byte_length;
35076+ uint8_t *data_ptr;
35077+ JSValue obj;
35078+ uint64_t u64;
35079+
35080+ if (bc_get_leb128(s, &byte_length))
35081+ return JS_EXCEPTION;
35082+ if (bc_get_u64(s, &u64))
35083+ return JS_EXCEPTION;
35084+ data_ptr = (uint8_t *)(uintptr_t)u64;
35085+ /* the SharedArrayBuffer is cloned */
35086+ obj = js_array_buffer_constructor3(ctx, JS_UNDEFINED, byte_length,
35087+ JS_CLASS_SHARED_ARRAY_BUFFER,
35088+ data_ptr,
35089+ NULL, NULL, FALSE);
35090+ if (JS_IsException(obj))
35091+ goto fail;
35092+ if (BC_add_object_ref(s, obj))
35093+ goto fail;
35094+ return obj;
35095+ fail:
35096+ JS_FreeValue(ctx, obj);
35097+ return JS_EXCEPTION;
35098+}
35099+
35100+static JSValue JS_ReadDate(BCReaderState *s)
35101+{
35102+ JSContext *ctx = s->ctx;
35103+ JSValue val, obj = JS_UNDEFINED;
35104+
35105+ val = JS_ReadObjectRec(s);
35106+ if (JS_IsException(val))
35107+ goto fail;
35108+ if (!JS_IsNumber(val)) {
35109+ JS_ThrowTypeError(ctx, "Number tag expected for date");
35110+ goto fail;
35111+ }
35112+ obj = JS_NewObjectProtoClass(ctx, ctx->class_proto[JS_CLASS_DATE],
35113+ JS_CLASS_DATE);
35114+ if (JS_IsException(obj))
35115+ goto fail;
35116+ if (BC_add_object_ref(s, obj))
35117+ goto fail;
35118+ JS_SetObjectData(ctx, obj, val);
35119+ return obj;
35120+ fail:
35121+ JS_FreeValue(ctx, val);
35122+ JS_FreeValue(ctx, obj);
35123+ return JS_EXCEPTION;
35124+}
35125+
35126+static JSValue JS_ReadObjectValue(BCReaderState *s)
35127+{
35128+ JSContext *ctx = s->ctx;
35129+ JSValue val, obj = JS_UNDEFINED;
35130+
35131+ val = JS_ReadObjectRec(s);
35132+ if (JS_IsException(val))
35133+ goto fail;
35134+ obj = JS_ToObject(ctx, val);
35135+ if (JS_IsException(obj))
35136+ goto fail;
35137+ if (BC_add_object_ref(s, obj))
35138+ goto fail;
35139+ JS_FreeValue(ctx, val);
35140+ return obj;
35141+ fail:
35142+ JS_FreeValue(ctx, val);
35143+ JS_FreeValue(ctx, obj);
35144+ return JS_EXCEPTION;
35145+}
35146+
3396435147 static JSValue JS_ReadObjectRec(BCReaderState *s)
3396535148 {
3396635149 JSContext *ctx = s->ctx;
3396735150 uint8_t tag;
3396835151 JSValue obj = JS_UNDEFINED;
33969− JSModuleDef *m = NULL;
35152+
35153+ if (js_check_stack_overflow(ctx->rt, 0))
35154+ return JS_ThrowStackOverflow(ctx);
3397035155
3397135156 if (bc_get_u8(s, &tag))
3397235157 return JS_EXCEPTION;
3397335158
35159+ bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
35160+
3397435161 switch(tag) {
3397535162 case BC_TAG_NULL:
33976− bc_read_trace(s, "null\n");
3397735163 obj = JS_NULL;
3397835164 break;
3397935165 case BC_TAG_UNDEFINED:
33980− bc_read_trace(s, "undefined\n");
3398135166 obj = JS_UNDEFINED;
3398235167 break;
3398335168 case BC_TAG_BOOL_FALSE:
3398435169 case BC_TAG_BOOL_TRUE:
33985− bc_read_trace(s, "%s\n", bc_tag_str[tag]);
3398635170 obj = JS_NewBool(ctx, tag - BC_TAG_BOOL_FALSE);
3398735171 break;
3398835172 case BC_TAG_INT32:
@@ -33990,7 +35174,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) · 1 unmodified line
3399035174 int32_t val;
3399135175 if (bc_get_sleb128(s, &val))
3399235176 return JS_EXCEPTION;
33993− bc_read_trace(s, "int32 %d\n", val);
35177+ bc_read_trace(s, "%d\n", val);
3399435178 obj = JS_NewInt32(ctx, val);
3399535179 }
3399635180 break;
@@ -33999,7 +35183,7 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) · 2 unmodified lines
3399935183 JSFloat64Union u;
3400035184 if (bc_get_u64(s, &u.u64))
3400135185 return JS_EXCEPTION;
34002− bc_read_trace(s, "float64 %g\n", u.d);
35186+ bc_read_trace(s, "%g\n", u.d);
3400335187 obj = __JS_NewFloat64(ctx, u.d);
3400435188 }
3400535189 break;
@@ -34013,378 +35197,68 @@ static JSValue JS_ReadObjectRec(BCReaderState *s) · 7 unmodified lines
3401335197 }
3401435198 break;
3401535199 case BC_TAG_FUNCTION_BYTECODE:
34016− {
34017− JSFunctionBytecode bc, *b;
34018− uint16_t v16;
34019− uint8_t v8;
34020− int idx, i, local_count;
34021− int function_size, cpool_offset, byte_code_offset;
34022− int closure_var_offset, vardefs_offset;
34023−
34024− if (!s->allow_bytecode)
34025− goto invalid_tag;
34026− bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
34027−
34028− memset(&bc, 0, sizeof(bc));
34029− bc.header.ref_count = 1;
34030− //bc.gc_header.mark = 0;
34031−
34032− if (bc_get_u16(s, &v16))
34033− goto fail;
34034− idx = 0;
34035− bc.has_prototype = bc_get_flags(v16, &idx, 1);
34036− bc.has_simple_parameter_list = bc_get_flags(v16, &idx, 1);
34037− bc.is_derived_class_constructor = bc_get_flags(v16, &idx, 1);
34038− bc.need_home_object = bc_get_flags(v16, &idx, 1);
34039− bc.func_kind = bc_get_flags(v16, &idx, 2);
34040− bc.new_target_allowed = bc_get_flags(v16, &idx, 1);
34041− bc.super_call_allowed = bc_get_flags(v16, &idx, 1);
34042− bc.super_allowed = bc_get_flags(v16, &idx, 1);
34043− bc.arguments_allowed = bc_get_flags(v16, &idx, 1);
34044− bc.has_debug = bc_get_flags(v16, &idx, 1);
34045− bc.backtrace_barrier = bc_get_flags(v16, &idx, 1);
34046− bc.read_only_bytecode = s->is_rom_data;
34047− if (bc_get_u8(s, &v8))
34048− goto fail;
34049− bc.js_mode = v8;
34050− if (bc_get_atom(s, &bc.func_name)) //@ atom leak if failure
34051− goto fail;
34052− if (bc_get_leb128_u16(s, &bc.arg_count))
34053− goto fail;
34054− if (bc_get_leb128_u16(s, &bc.var_count))
34055− goto fail;
34056− if (bc_get_leb128_u16(s, &bc.defined_arg_count))
34057− goto fail;
34058− if (bc_get_leb128_u16(s, &bc.stack_size))
34059− goto fail;
34060− if (bc_get_leb128_int(s, &bc.closure_var_count))
34061− goto fail;
34062− if (bc_get_leb128_int(s, &bc.cpool_count))
34063− goto fail;
34064− if (bc_get_leb128_int(s, &bc.byte_code_len))
34065− goto fail;
34066− if (bc_get_leb128_int(s, &local_count))
34067− goto fail;
34068−
34069− if (bc.has_debug) {
34070− function_size = sizeof(*b);
34071− } else {
34072− function_size = offsetof(JSFunctionBytecode, debug);
34073− }
34074− cpool_offset = function_size;
34075− function_size += bc.cpool_count * sizeof(*bc.cpool);
34076− vardefs_offset = function_size;
34077− function_size += local_count * sizeof(*bc.vardefs);
34078− closure_var_offset = function_size;
34079− function_size += bc.closure_var_count * sizeof(*bc.closure_var);
34080− byte_code_offset = function_size;
34081− if (!bc.read_only_bytecode) {
34082− function_size += bc.byte_code_len;
34083− }
34084−
34085− b = js_mallocz(ctx, function_size);
34086− if (!b)
34087− return JS_EXCEPTION;
34088−
34089− memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
34090− b->header.ref_count = 1;
34091− add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
34092−
34093− obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
34094−
34095−#ifdef DUMP_READ_OBJECT
34096− bc_read_trace(s, "name: "); print_atom(s->ctx, b->func_name); printf("\n");
34097−#endif
34098− bc_read_trace(s, "args=%d vars=%d defargs=%d closures=%d cpool=%d\n",
34099− b->arg_count, b->var_count, b->defined_arg_count,
34100− b->closure_var_count, b->cpool_count);
34101− bc_read_trace(s, "stack=%d bclen=%d locals=%d\n",
34102− b->stack_size, b->byte_code_len, local_count);
34103−
34104− if (local_count != 0) {
34105− bc_read_trace(s, "vars {\n");
34106− b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
34107− for(i = 0; i < local_count; i++) {
34108− JSVarDef *vd = &b->vardefs[i];
34109− if (bc_get_atom(s, &vd->var_name))
34110− goto fail;
34111− if (bc_get_leb128_int(s, &vd->scope_level))
34112− goto fail;
34113− if (bc_get_leb128_int(s, &vd->scope_next))
34114− goto fail;
34115− vd->scope_next--;
34116− if (bc_get_u8(s, &v8))
34117− goto fail;
34118− idx = 0;
34119− vd->var_kind = bc_get_flags(v8, &idx, 4);
34120− vd->is_func_var = bc_get_flags(v8, &idx, 1);
34121− vd->is_const = bc_get_flags(v8, &idx, 1);
34122− vd->is_lexical = bc_get_flags(v8, &idx, 1);
34123− vd->is_captured = bc_get_flags(v8, &idx, 1);
34124−#ifdef DUMP_READ_OBJECT
34125− bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
34126−#endif
34127− }
34128− bc_read_trace(s, "}\n");
34129− }
34130− if (b->closure_var_count != 0) {
34131− bc_read_trace(s, "closure vars {\n");
34132− b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
34133− for(i = 0; i < b->closure_var_count; i++) {
34134− JSClosureVar *cv = &b->closure_var[i];
34135− int var_idx;
34136− if (bc_get_atom(s, &cv->var_name))
34137− goto fail;
34138− if (bc_get_leb128_int(s, &var_idx))
34139− goto fail;
34140− cv->var_idx = var_idx;
34141− if (bc_get_u8(s, &v8))
34142− goto fail;
34143− idx = 0;
34144− cv->is_local = bc_get_flags(v8, &idx, 1);
34145− cv->is_arg = bc_get_flags(v8, &idx, 1);
34146− cv->is_const = bc_get_flags(v8, &idx, 1);
34147− cv->is_lexical = bc_get_flags(v8, &idx, 1);
34148− cv->var_kind = bc_get_flags(v8, &idx, 4);
34149−#ifdef DUMP_READ_OBJECT
34150− bc_read_trace(s, "name: "); print_atom(s->ctx, cv->var_name); printf("\n");
34151−#endif
34152− }
34153− bc_read_trace(s, "}\n");
34154− }
34155− {
34156− bc_read_trace(s, "bytecode {\n");
34157− if (JS_ReadFunctionBytecode(s, b, byte_code_offset, b->byte_code_len))
34158− goto fail;
34159− bc_read_trace(s, "}\n");
34160− }
34161− if (b->has_debug) {
34162− /* read optional debug information */
34163− bc_read_trace(s, "debug {\n");
34164− if (bc_get_atom(s, &b->debug.filename))
34165− goto fail;
34166− if (bc_get_leb128_int(s, &b->debug.line_num))
34167− goto fail;
34168− if (bc_get_leb128_int(s, &b->debug.pc2line_len))
34169− goto fail;
34170− if (b->debug.pc2line_len) {
34171− b->debug.pc2line_buf = js_mallocz(ctx, b->debug.pc2line_len);
34172− if (!b->debug.pc2line_buf)
34173− goto fail;
34174− if (bc_get_buf(s, b->debug.pc2line_buf, b->debug.pc2line_len))
34175− goto fail;
34176− }
34177−#ifdef DUMP_READ_OBJECT
34178− bc_read_trace(s, "filename: "); print_atom(s->ctx, b->debug.filename); printf("\n");
34179−#endif
34180− bc_read_trace(s, "}\n");
34181− }
34182− if (b->cpool_count != 0) {
34183− bc_read_trace(s, "cpool {\n");
34184− b->cpool = (void *)((uint8_t*)b + cpool_offset);
34185− for(i = 0; i < b->cpool_count; i++) {
34186− JSValue val;
34187− val = JS_ReadObjectRec(s);
34188− if (JS_IsException(val))
34189− goto fail;
34190− b->cpool[i] = val;
34191− }
34192− bc_read_trace(s, "}\n");
34193− }
34194− bc_read_trace(s, "}\n");
34195− b->realm = JS_DupContext(ctx);
34196− }
35200+ if (!s->allow_bytecode)
35201+ goto invalid_tag;
35202+ obj = JS_ReadFunctionTag(s);
3419735203 break;
3419835204 case BC_TAG_MODULE:
34199− {
34200− JSAtom module_name;
34201− int i;
34202− uint8_t v8;
34203−
34204− if (!s->allow_bytecode)
34205− goto invalid_tag;
34206− bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
34207− if (bc_get_atom(s, &module_name))
34208− goto fail;
34209−#ifdef DUMP_READ_OBJECT
34210− bc_read_trace(s, "name: "); print_atom(s->ctx, module_name); printf("\n");
34211−#endif
34212− m = js_new_module_def(ctx, module_name);
34213− if (!m)
34214− goto fail;
34215− obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m));
34216− if (bc_get_leb128_int(s, &m->req_module_entries_count))
34217− goto fail;
34218− if (m->req_module_entries_count != 0) {
34219− m->req_module_entries_size = m->req_module_entries_count;
34220− m->req_module_entries = js_mallocz(ctx, sizeof(m->req_module_entries[0]) * m->req_module_entries_size);
34221− if (!m->req_module_entries)
34222− goto fail;
34223− for(i = 0; i < m->req_module_entries_count; i++) {
34224− JSReqModuleEntry *rme = &m->req_module_entries[i];
34225− if (bc_get_atom(s, &rme->module_name))
34226− goto fail;
34227− }
34228− }
34229−
34230− if (bc_get_leb128_int(s, &m->export_entries_count))
34231− goto fail;
34232− if (m->export_entries_count != 0) {
34233− m->export_entries_size = m->export_entries_count;
34234− m->export_entries = js_mallocz(ctx, sizeof(m->export_entries[0]) * m->export_entries_size);
34235− if (!m->export_entries)
34236− goto fail;
34237− for(i = 0; i < m->export_entries_count; i++) {
34238− JSExportEntry *me = &m->export_entries[i];
34239− if (bc_get_u8(s, &v8))
34240− goto fail;
34241− me->export_type = v8;
34242− if (me->export_type == JS_EXPORT_TYPE_LOCAL) {
34243− if (bc_get_leb128_int(s, &me->u.local.var_idx))
34244− goto fail;
34245− } else {
34246− if (bc_get_leb128_int(s, &me->u.req_module_idx))
34247− goto fail;
34248− if (bc_get_atom(s, &me->local_name))
34249− goto fail;
34250− }
34251− if (bc_get_atom(s, &me->export_name))
34252− goto fail;
34253− }
34254− }
34255−
34256− if (bc_get_leb128_int(s, &m->star_export_entries_count))
34257− goto fail;
34258− if (m->star_export_entries_count != 0) {
34259− m->star_export_entries_size = m->star_export_entries_count;
34260− m->star_export_entries = js_mallocz(ctx, sizeof(m->star_export_entries[0]) * m->star_export_entries_size);
34261− if (!m->star_export_entries)
34262− goto fail;
34263− for(i = 0; i < m->star_export_entries_count; i++) {
34264− JSStarExportEntry *se = &m->star_export_entries[i];
34265− if (bc_get_leb128_int(s, &se->req_module_idx))
34266− goto fail;
34267− }
34268− }
34269−
34270− if (bc_get_leb128_int(s, &m->import_entries_count))
34271− goto fail;
34272− if (m->import_entries_count != 0) {
34273− m->import_entries_size = m->import_entries_count;
34274− m->import_entries = js_mallocz(ctx, sizeof(m->import_entries[0]) * m->import_entries_size);
34275− if (!m->import_entries)
34276− goto fail;
34277− for(i = 0; i < m->import_entries_count; i++) {
34278− JSImportEntry *mi = &m->import_entries[i];
34279− if (bc_get_leb128_int(s, &mi->var_idx))
34280− goto fail;
34281− if (bc_get_atom(s, &mi->import_name))
34282− goto fail;
34283− if (bc_get_leb128_int(s, &mi->req_module_idx))
34284− goto fail;
34285− }
34286− }
34287−
34288− m->func_obj = JS_ReadObjectRec(s);
34289− if (JS_IsException(m->func_obj))
34290− goto fail;
34291− bc_read_trace(s, "}\n");
34292− }
35205+ if (!s->allow_bytecode)
35206+ goto invalid_tag;
35207+ obj = JS_ReadModule(s);
3429335208 break;
3429435209 case BC_TAG_OBJECT:
34295− {
34296− uint32_t prop_count, i;
34297− JSAtom atom;
34298− JSValue val;
34299− int ret;
34300−
34301− bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
34302−
34303− obj = JS_NewObject(ctx);
34304− if (bc_get_leb128(s, &prop_count))
34305− goto fail;
34306− for(i = 0; i < prop_count; i++) {
34307− if (bc_get_atom(s, &atom))
34308− goto fail;
34309−#ifdef DUMP_READ_OBJECT
34310− bc_read_trace(s, "propname: "); print_atom(s->ctx, atom); printf("\n");
34311−#endif
34312− val = JS_ReadObjectRec(s);
34313− if (JS_IsException(val)) {
34314− JS_FreeAtom(ctx, atom);
34315− goto fail;
34316− }
34317− ret = JS_DefinePropertyValue(ctx, obj, atom, val, JS_PROP_C_W_E);
34318− JS_FreeAtom(ctx, atom);
34319− if (ret < 0)
34320− goto fail;
34321− }
34322− bc_read_trace(s, "}\n");
34323− }
35210+ obj = JS_ReadObjectTag(s);
3432435211 break;
3432535212 case BC_TAG_ARRAY:
3432635213 case BC_TAG_TEMPLATE_OBJECT:
34327− {
34328− uint32_t len, i;
34329− JSValue val;
34330− int ret, prop_flags;
34331− BOOL is_template;
34332−
34333− bc_read_trace(s, "%s {\n", bc_tag_str[tag]);
34334−
34335− obj = JS_NewArray(ctx);
34336− is_template = (tag == BC_TAG_TEMPLATE_OBJECT);
34337− if (bc_get_leb128(s, &len))
34338− goto fail;
34339− for(i = 0; i < len; i++) {
34340− val = JS_ReadObjectRec(s);
34341− if (JS_IsException(val))
34342− goto fail;
34343− if (is_template)
34344− prop_flags = JS_PROP_ENUMERABLE;
34345− else
34346− prop_flags = JS_PROP_C_W_E;
34347− ret = JS_DefinePropertyValueUint32(ctx, obj, i, val,
34348− prop_flags);
34349− if (ret < 0)
34350− goto fail;
34351− }
34352− if (is_template) {
34353− val = JS_ReadObjectRec(s);
34354− if (JS_IsException(val))
34355− goto fail;
34356− if (!JS_IsUndefined(val)) {
34357− ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_raw, val, 0);
34358− if (ret < 0)
34359− goto fail;
34360− }
34361− JS_PreventExtensions(ctx, obj);
34362− }
34363− bc_read_trace(s, "}\n");
34364− }
35214+ obj = JS_ReadArray(s, tag);
35215+ break;
35216+ case BC_TAG_TYPED_ARRAY:
35217+ obj = JS_ReadTypedArray(s);
35218+ break;
35219+ case BC_TAG_ARRAY_BUFFER:
35220+ obj = JS_ReadArrayBuffer(s);
35221+ break;
35222+ case BC_TAG_SHARED_ARRAY_BUFFER:
35223+ if (!s->allow_sab || !ctx->rt->sab_funcs.sab_dup)
35224+ goto invalid_tag;
35225+ obj = JS_ReadSharedArrayBuffer(s);
35226+ break;
35227+ case BC_TAG_DATE:
35228+ obj = JS_ReadDate(s);
35229+ break;
35230+ case BC_TAG_OBJECT_VALUE:
35231+ obj = JS_ReadObjectValue(s);
3436535232 break;
3436635233 #ifdef CONFIG_BIGNUM
3436735234 case BC_TAG_BIG_INT:
3436835235 case BC_TAG_BIG_FLOAT:
3436935236 case BC_TAG_BIG_DECIMAL:
3437035237 obj = JS_ReadBigNum(s, tag);
34371− if (JS_IsException(obj))
34372− goto fail;
3437335238 break;
3437435239 #endif
35240+ case BC_TAG_OBJECT_REFERENCE:
35241+ {
35242+ uint32_t val;
35243+ if (!s->allow_reference)
35244+ return JS_ThrowSyntaxError(ctx, "object references are not allowed");
35245+ if (bc_get_leb128(s, &val))
35246+ return JS_EXCEPTION;
35247+ bc_read_trace(s, "%u\n", val);
35248+ if (val >= s->objects_count) {
35249+ return JS_ThrowSyntaxError(ctx, "invalid object reference (%u >= %u)",
35250+ val, s->objects_count);
35251+ }
35252+ obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, s->objects[val]));
35253+ }
35254+ break;
3437535255 default:
3437635256 invalid_tag:
3437735257 return JS_ThrowSyntaxError(ctx, "invalid tag (tag=%d pos=%u)",
3437835258 tag, (unsigned int)(s->ptr - s->buf_start));
3437935259 }
35260+ bc_read_trace(s, "}\n");
3438035261 return obj;
34381− fail:
34382− if (m) {
34383− js_free_module_def(ctx, m);
34384− } else {
34385− JS_FreeValue(ctx, obj);
34386− }
34387− return JS_EXCEPTION;
3438835262 }
3438935263
3439035264 static int JS_ReadObjectAtoms(BCReaderState *s)
@@ -34437,10 +35311,11 @@ static void bc_reader_free(BCReaderState *s) · 46 unmodified lines
3443735311 }
3443835312 js_free(s->ctx, s->idx_to_atom);
3443935313 }
35314+ js_free(s->ctx, s->objects);
3444035315 }
3444135316
3444235317 JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
34443− int flags)
35318+ int flags)
3444435319 {
3444535320 BCReaderState ss, *s = &ss;
3444635321 JSValue obj;
@@ -34455,6 +35330,8 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len, · 8 unmodified lines
3445535330 s->ptr = buf;
3445635331 s->allow_bytecode = ((flags & JS_READ_OBJ_BYTECODE) != 0);
3445735332 s->is_rom_data = ((flags & JS_READ_OBJ_ROM_DATA) != 0);
35333+ s->allow_sab = ((flags & JS_READ_OBJ_SAB) != 0);
35334+ s->allow_reference = ((flags & JS_READ_OBJ_REFERENCE) != 0);
3445835335 if (s->allow_bytecode)
3445935336 s->first_atom = JS_ATOM_END;
3446035337 else
@@ -34944,7 +35821,7 @@ static __exception int JS_ObjectDefineProperties(JSContext *ctx, · 483 unmodified lines
3494435821 if (JS_IsException(props))
3494535822 return -1;
3494635823 p = JS_VALUE_GET_OBJ(props);
34947− if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK) < 0)
35824+ if (JS_GetOwnPropertyNamesInternal(ctx, &atoms, &len, p, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK) < 0)
3494835825 goto exception;
3494935826 for(i = 0; i < len; i++) {
3495035827 JS_FreeValue(ctx, desc);
@@ -35021,7 +35898,7 @@ static JSValue js_object_getPrototypeOf(JSContext *ctx, JSValueConst this_val, · 70 unmodified lines
3502135898 JS_VALUE_GET_TAG(val) == JS_TAG_UNDEFINED)
3502235899 return JS_ThrowTypeErrorNotAnObject(ctx);
3502335900 }
35024− return JS_DupValue(ctx, JS_GetPrototype(ctx, val));
35901+ return JS_GetPrototype(ctx, val);
3502535902 }
3502635903
3502735904 static JSValue js_object_setPrototypeOf(JSContext *ctx, JSValueConst this_val,
@@ -35815,7 +36692,7 @@ static JSValue js_object_get___proto__(JSContext *ctx, JSValueConst this_val) · 787 unmodified lines
3581536692 val = JS_ToObject(ctx, this_val);
3581636693 if (JS_IsException(val))
3581736694 return val;
35818− ret = JS_DupValue(ctx, JS_GetPrototype(ctx, val));
36695+ ret = JS_GetPrototype(ctx, val);
3581936696 JS_FreeValue(ctx, val);
3582036697 return ret;
3582136698 }
@@ -35836,9 +36713,9 @@ static JSValue js_object_set___proto__(JSContext *ctx, JSValueConst this_val, · 14 unmodified lines
3583636713 static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val,
3583736714 int argc, JSValueConst *argv)
3583836715 {
35839− JSValue obj;
36716+ JSValue obj, v1;
3584036717 JSValueConst v;
35841− int max_depth = 1000, res = -1;
36718+ int res;
3584236719
3584336720 v = argv[0];
3584436721 if (!JS_IsObject(v))
@@ -35846,27 +36723,29 @@ static JSValue js_object_isPrototypeOf(JSContext *ctx, JSValueConst this_val, · 1 unmodified line
3584636723 obj = JS_ToObject(ctx, this_val);
3584736724 if (JS_IsException(obj))
3584836725 return JS_EXCEPTION;
35849− while (--max_depth > 0) {
35850− v = JS_GetPrototype(ctx, v);
35851− if (JS_IsException(v))
36726+ v1 = JS_DupValue(ctx, v);
36727+ for(;;) {
36728+ v1 = JS_GetPrototypeFree(ctx, v1);
36729+ if (JS_IsException(v1))
3585236730 goto exception;
35853− if (JS_IsNull(v)) {
36731+ if (JS_IsNull(v1)) {
3585436732 res = FALSE;
3585536733 break;
3585636734 }
35857− if (js_strict_eq2(ctx, JS_DupValue(ctx, obj), JS_DupValue(ctx, v),
35858− JS_EQ_STRICT)) {
36735+ if (JS_VALUE_GET_OBJ(obj) == JS_VALUE_GET_OBJ(v1)) {
3585936736 res = TRUE;
3586036737 break;
3586136738 }
36739+ /* avoid infinite loop (possible with proxies) */
36740+ if (js_poll_interrupts(ctx))
36741+ goto exception;
3586236742 }
36743+ JS_FreeValue(ctx, v1);
3586336744 JS_FreeValue(ctx, obj);
35864− if (res < 0)
35865− return JS_ThrowInternalError(ctx, "prototype chain cycle");
35866− else
35867− return JS_NewBool(ctx, res);
36745+ return JS_NewBool(ctx, res);
3586836746
3586936747 exception:
36748+ JS_FreeValue(ctx, v1);
3587036749 JS_FreeValue(ctx, obj);
3587136750 return JS_EXCEPTION;
3587236751 }
@@ -35906,7 +36785,6 @@ static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, · 33 unmodified lines
3590636785 int argc, JSValueConst *argv, int setter)
3590736786 {
3590836787 JSValue obj, res = JS_EXCEPTION;
35909− JSValueConst v;
3591036788 JSAtom prop = JS_ATOM_NULL;
3591136789 JSPropertyDescriptor desc;
3591236790 int has_prop;
@@ -35918,8 +36796,8 @@ static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, · 5 unmodified lines
3591836796 if (unlikely(prop == JS_ATOM_NULL))
3591936797 goto exception;
3592036798
35921− for (v = obj;;) {
35922− has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(v), prop);
36799+ for (;;) {
36800+ has_prop = JS_GetOwnPropertyInternal(ctx, &desc, JS_VALUE_GET_OBJ(obj), prop);
3592336801 if (has_prop < 0)
3592436802 goto exception;
3592536803 if (has_prop) {
@@ -35930,13 +36808,16 @@ static JSValue js_object___lookupGetter__(JSContext *ctx, JSValueConst this_val, · 4 unmodified lines
3593036808 js_free_desc(ctx, &desc);
3593136809 break;
3593236810 }
35933− v = JS_GetPrototype(ctx, v);
35934− if (JS_IsException(v))
36811+ obj = JS_GetPrototypeFree(ctx, obj);
36812+ if (JS_IsException(obj))
3593536813 goto exception;
35936− if (JS_IsNull(v)) {
36814+ if (JS_IsNull(obj)) {
3593736815 res = JS_UNDEFINED;
3593836816 break;
3593936817 }
36818+ /* avoid infinite loop (possible with proxies) */
36819+ if (js_poll_interrupts(ctx))
36820+ goto exception;
3594036821 }
3594136822
3594236823 exception:
@@ -36002,59 +36883,12 @@ static JSValue js_function_proto(JSContext *ctx, JSValueConst this_val, · 59 unmodified lines
3600236883 return JS_UNDEFINED;
3600336884 }
3600436885
36005−/* insert a '\n' at unicode character position 'pos' in the source of
36006− 'func_obj' */
36007−static int patch_function_constructor_source(JSContext *ctx,
36008− JSValueConst func_obj,
36009− size_t pos)
36010−{
36011− JSObject *p;
36012− JSFunctionBytecode *b;
36013− char *r, *r_end, *new_source;
36014− int c;
36015− size_t idx, len;
36016−
36017− if (JS_VALUE_GET_TAG(func_obj) != JS_TAG_OBJECT)
36018− return 0;
36019− p = JS_VALUE_GET_OBJ(func_obj);
36020− if (!js_class_has_bytecode(p->class_id))
36021− return 0;
36022− b = p->u.func.function_bytecode;
36023− if (!b->has_debug)
36024− return 0;
36025− r = b->debug.source;
36026− r_end = b->debug.source + b->debug.source_len;
36027− idx = 0;
36028− while (r < r_end) {
36029− if (idx == pos) {
36030− /* add the '\n' */
36031− new_source = js_realloc(ctx, b->debug.source,
36032− b->debug.source_len + 2);
36033− if (!new_source)
36034− return -1;
36035− len = r - b->debug.source;
36036− memmove(new_source + len + 1, new_source + len,
36037− b->debug.source_len + 1 - len);
36038− new_source[len] = '\n';
36039− b->debug.source = new_source;
36040− b->debug.source_len++;
36041− break;
36042− }
36043− c = unicode_from_utf8((const uint8_t *)r, UTF8_CHAR_LEN_MAX,
36044− (const uint8_t **)&r);
36045− if (c < 0)
36046− break;
36047− idx++;
36048− }
36049− return 0;
36050−}
36051−
3605236886 /* XXX: add a specific eval mode so that Function("}), ({") is rejected */
3605336887 static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target,
3605436888 int argc, JSValueConst *argv, int magic)
3605536889 {
3605636890 JSFunctionKindEnum func_kind = magic;
36057− int i, n, ret, func_start_pos;
36891+ int i, n, ret;
3605836892 JSValue s, proto, obj = JS_UNDEFINED;
3605936893 StringBuffer b_s, *b = &b_s;
3606036894
@@ -36079,13 +36913,7 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, · 18 unmodified lines
3607936913 if (string_buffer_concat_value(b, argv[i]))
3608036914 goto fail;
3608136915 }
36082− string_buffer_puts8(b, "\n) {");
36083− /* Annex B HTML comments: We don't add a '\n' after "{" so that
36084− "-->" is not considered as an HTML comment. It is necessary
36085− because in the spec the function body is parsed separately. */
36086− /* XXX: find a simpler way or be deliberately incompatible to
36087− simplify the code ? */
36088− func_start_pos = b->len - 1; /* the leading '(' is not in the source */
36916+ string_buffer_puts8(b, "\n) {\n");
3608936917 if (n >= 0) {
3609036918 if (string_buffer_concat_value(b, argv[n]))
3609136919 goto fail;
@@ -36099,8 +36927,6 @@ static JSValue js_function_constructor(JSContext *ctx, JSValueConst new_target, · 7 unmodified lines
3609936927 JS_FreeValue(ctx, s);
3610036928 if (JS_IsException(obj))
3610136929 goto fail1;
36102− if (patch_function_constructor_source(ctx, obj, func_start_pos) < 0)
36103− goto fail1;
3610436930 if (!JS_IsUndefined(new_target)) {
3610536931 /* set the prototype */
3610636932 proto = JS_GetProperty(ctx, new_target, JS_ATOM_prototype);
@@ -36315,27 +37141,22 @@ static JSValue js_function_toString(JSContext *ctx, JSValueConst this_val, · 208 unmodified lines
3631537141 JSValue name;
3631637142 const char *pref, *suff;
3631737143
36318− if (p->is_class) {
36319− pref = "class ";
36320− suff = " {\n [native code]\n}";
36321− } else {
36322− switch(func_kind) {
36323− default:
36324− case JS_FUNC_NORMAL:
36325− pref = "function ";
36326− break;
36327− case JS_FUNC_GENERATOR:
36328− pref = "function *";
36329− break;
36330− case JS_FUNC_ASYNC:
36331− pref = "async function ";
36332− break;
36333− case JS_FUNC_ASYNC_GENERATOR:
36334− pref = "async function *";
36335− break;
36336− }
36337− suff = "() {\n [native code]\n}";
37144+ switch(func_kind) {
37145+ default:
37146+ case JS_FUNC_NORMAL:
37147+ pref = "function ";
37148+ break;
37149+ case JS_FUNC_GENERATOR:
37150+ pref = "function *";
37151+ break;
37152+ case JS_FUNC_ASYNC:
37153+ pref = "async function ";
37154+ break;
37155+ case JS_FUNC_ASYNC_GENERATOR:
37156+ pref = "async function *";
37157+ break;
3633837158 }
37159+ suff = "() {\n [native code]\n}";
3633937160 name = JS_GetProperty(ctx, this_val, JS_ATOM_name);
3634037161 if (JS_IsUndefined(name))
3634137162 name = JS_AtomToString(ctx, JS_ATOM_empty_string);
@@ -36435,12 +37256,6 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, · 93 unmodified lines
3643537256 if (JS_IsException(obj))
3643637257 return obj;
3643737258 if (magic == JS_AGGREGATE_ERROR) {
36438− JSObject *p;
36439− JSValue error_list = iterator_to_array(ctx, argv[0]);
36440− if (JS_IsException(error_list))
36441− goto exception;
36442− p = JS_VALUE_GET_OBJ(obj);
36443− p->u.object_data = error_list;
3644437259 message = argv[1];
3644537260 } else {
3644637261 message = argv[0];
@@ -36448,17 +37263,26 @@ static JSValue js_error_constructor(JSContext *ctx, JSValueConst new_target, · 1 unmodified line
3644837263
3644937264 if (!JS_IsUndefined(message)) {
3645037265 msg = JS_ToString(ctx, message);
36451− if (unlikely(JS_IsException(msg))) {
36452− exception:
36453− JS_FreeValue(ctx, obj);
36454− return JS_EXCEPTION;
36455− }
37266+ if (unlikely(JS_IsException(msg)))
37267+ goto exception;
3645637268 JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, msg,
3645737269 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
3645837270 }
37271+
37272+ if (magic == JS_AGGREGATE_ERROR) {
37273+ JSValue error_list = iterator_to_array(ctx, argv[0]);
37274+ if (JS_IsException(error_list))
37275+ goto exception;
37276+ JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, error_list,
37277+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
37278+ }
37279+
3645937280 /* skip the Error() function in the backtrace */
3646037281 build_backtrace(ctx, obj, NULL, 0, JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL);
3646137282 return obj;
37283+ exception:
37284+ JS_FreeValue(ctx, obj);
37285+ return JS_EXCEPTION;
3646237286 }
3646337287
3646437288 static JSValue js_error_toString(JSContext *ctx, JSValueConst this_val,
@@ -36498,56 +37322,22 @@ static const JSCFunctionListEntry js_error_proto_funcs[] = { · 33 unmodified lines
3649837322
3649937323 /* AggregateError */
3650037324
36501−/* used by C code. 'errors' must be a fast array. */
37325+/* used by C code. */
3650237326 static JSValue js_aggregate_error_constructor(JSContext *ctx,
3650337327 JSValueConst errors)
3650437328 {
3650537329 JSValue obj;
36506− JSObject *p;
3650737330
3650837331 obj = JS_NewObjectProtoClass(ctx,
3650937332 ctx->native_error_proto[JS_AGGREGATE_ERROR],
3651037333 JS_CLASS_ERROR);
3651137334 if (JS_IsException(obj))
3651237335 return obj;
36513− p = JS_VALUE_GET_OBJ(obj);
36514− p->u.object_data = JS_DupValue(ctx, errors);
37336+ JS_DefinePropertyValue(ctx, obj, JS_ATOM_errors, JS_DupValue(ctx, errors),
37337+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
3651537338 return obj;
3651637339 }
3651737340
36518−static JSValue js_aggregate_error_errors(JSContext *ctx, JSValueConst this_val)
36519−{
36520− JSObject *p;
36521− JSValue r, *arr;
36522− uint32_t len, i;
36523−
36524− if (JS_VALUE_GET_TAG(this_val) != JS_TAG_OBJECT)
36525− goto invalid_type;
36526− p = JS_VALUE_GET_OBJ(this_val);
36527− if (p->class_id != JS_CLASS_ERROR)
36528− goto invalid_type;
36529− if (!js_get_fast_array(ctx, p->u.object_data, &arr, &len)) {
36530− invalid_type:
36531− return JS_ThrowTypeError(ctx, "not an AggregateError");
36532− }
36533− r = JS_NewArray(ctx);
36534− if (JS_IsException(r))
36535− goto exception;
36536− for(i = 0; i < len; i++) {
36537− if (JS_DefinePropertyValueInt64(ctx, r, i, JS_DupValue(ctx, arr[i]),
36538− JS_PROP_C_W_E | JS_PROP_THROW) < 0)
36539− goto exception;
36540− }
36541− return r;
36542− exception:
36543− JS_FreeValue(ctx, r);
36544− return JS_EXCEPTION;
36545−}
36546−
36547−static const JSCFunctionListEntry js_aggregate_error_proto_funcs[] = {
36548− JS_CGETSET_DEF("errors", js_aggregate_error_errors, NULL),
36549−};
36550−
3655137341 /* Array */
3655237342
3655337343 static int JS_CopySubArray(JSContext *ctx,
@@ -39130,22 +39920,25 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, · 2576 unmodified lines
3913039920 p1 = JS_VALUE_GET_STRING(v);
3913139921 len = p->len;
3913239922 v_len = p1->len;
39133− pos = (magic & 2) ? len : 0;
39923+ pos = (magic == 2) ? len : 0;
3913439924 if (argc > 1 && !JS_IsUndefined(argv[1])) {
3913539925 if (JS_ToInt32Clamp(ctx, &pos, argv[1], 0, len, 0))
3913639926 goto fail;
3913739927 }
3913839928 len -= v_len;
39139− start = pos;
39140− stop = len;
39141− if (magic & 1) {
39142− stop = pos;
39143− }
39144− if (magic & 2) {
39145− pos -= v_len;
39929+ ret = 0;
39930+ if (magic == 0) {
39931+ start = pos;
39932+ stop = len;
39933+ } else {
39934+ if (magic == 1) {
39935+ if (pos > len)
39936+ goto done;
39937+ } else {
39938+ pos -= v_len;
39939+ }
3914639940 start = stop = pos;
3914739941 }
39148− ret = 0;
3914939942 if (start >= 0 && start <= stop) {
3915039943 for (i = start;; i++) {
3915139944 if (!string_cmp(p, p1, i, 0, v_len)) {
@@ -39156,6 +39949,7 @@ static JSValue js_string_includes(JSContext *ctx, JSValueConst this_val, · 4 unmodified lines
3915639949 break;
3915739950 }
3915839951 }
39952+ done:
3915939953 JS_FreeValue(ctx, str);
3916039954 JS_FreeValue(ctx, v);
3916139955 return JS_NewBool(ctx, ret);
@@ -40372,46 +41166,23 @@ static double js_math_round(double a) · 1210 unmodified lines
4037241166 static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
4037341167 int argc, JSValueConst *argv)
4037441168 {
40375− double r, a, b;
41169+ double r, a;
4037641170 int i;
4037741171
40378− if (argc == 2) {
40379− /* use the more precise built-in function when possible */
40380− if (JS_ToFloat64(ctx, &a, argv[0]))
40381− return JS_EXCEPTION;
40382− if (JS_ToFloat64(ctx, &b, argv[1]))
40383− return JS_EXCEPTION;
40384− r = hypot(a, b);
40385− } else if (argc == 0) {
40386− r = 0;
40387− } else {
40388− double *tab, a_max;
40389− tab = js_malloc(ctx, sizeof(tab[0]) * argc);
40390− if (!tab)
41172+ r = 0;
41173+ if (argc > 0) {
41174+ if (JS_ToFloat64(ctx, &r, argv[0]))
4039141175 return JS_EXCEPTION;
40392− /* avoid overflow by taking the maximum */
40393− a_max = 0;
40394− for(i = 0; i < argc; i++) {
40395− if (JS_ToFloat64(ctx, &a, argv[i])) {
40396− js_free(ctx, tab);
40397− return JS_EXCEPTION;
40398− }
40399− a = fabs(a);
40400− tab[i] = a;
40401− if (a > a_max)
40402− a_max = a;
40403− }
40404− if (a_max == 0 || !isfinite(a_max)) {
40405− r = a_max;
41176+ if (argc == 1) {
41177+ r = fabs(r);
4040641178 } else {
40407− r = 0;
40408− for(i = 0; i < argc; i++) {
40409− a = tab[i] / a_max;
40410− r += a * a;
41179+ /* use the built-in function to minimize precision loss */
41180+ for (i = 1; i < argc; i++) {
41181+ if (JS_ToFloat64(ctx, &a, argv[i]))
41182+ return JS_EXCEPTION;
41183+ r = hypot(r, a);
4041141184 }
40412− r = a_max * sqrt(r);
4041341185 }
40414− js_free(ctx, tab);
4041541186 }
4041641187 return JS_NewFloat64(ctx, r);
4041741188 }
@@ -42093,58 +42864,69 @@ void JS_AddIntrinsicRegExp(JSContext *ctx) · 1675 unmodified lines
4209342864
4209442865 /* JSON */
4209542866
42096−/* XXX: this parser is less strict than the JSON standard because we
42097− reuse the Javascript tokenizer. It could be improved by adding a
42098− specific JSON parse flag. */
42867+static int json_parse_expect(JSParseState *s, int tok)
42868+{
42869+ if (s->token.val != tok) {
42870+ /* XXX: dump token correctly in all cases */
42871+ return js_parse_error(s, "expecting '%c'", tok);
42872+ }
42873+ return json_next_token(s);
42874+}
42875+
4209942876 static JSValue json_parse_value(JSParseState *s)
4210042877 {
4210142878 JSContext *ctx = s->ctx;
4210242879 JSValue val = JS_NULL;
42103− BOOL is_neg;
4210442880 int ret;
4210542881
4210642882 switch(s->token.val) {
4210742883 case '{':
4210842884 {
42109− JSValue prop_val, prop_str;
42110−
42111− if (next_token(s))
42885+ JSValue prop_val;
42886+ JSAtom prop_name;
42887+
42888+ if (json_next_token(s))
4211242889 goto fail;
4211342890 val = JS_NewObject(ctx);
4211442891 if (JS_IsException(val))
4211542892 goto fail;
4211642893 if (s->token.val != '}') {
4211742894 for(;;) {
42118− if (s->token.val != TOK_STRING) {
42895+ if (s->token.val == TOK_STRING) {
42896+ prop_name = JS_ValueToAtom(ctx, s->token.u.str.str);
42897+ if (prop_name == JS_ATOM_NULL)
42898+ goto fail;
42899+ } else if (s->ext_json && s->token.val == TOK_IDENT) {
42900+ prop_name = JS_DupAtom(ctx, s->token.u.ident.atom);
42901+ } else {
4211942902 js_parse_error(s, "expecting property name");
4212042903 goto fail;
4212142904 }
42122− prop_str = JS_DupValue(ctx, s->token.u.str.str);
42123− if (next_token(s)) {
42124− JS_FreeValue(ctx, prop_str);
42125− goto fail;
42126− }
42127− if (js_parse_expect(s, ':')) {
42128− JS_FreeValue(ctx, prop_str);
42129− goto fail;
42130− }
42905+ if (json_next_token(s))
42906+ goto fail1;
42907+ if (json_parse_expect(s, ':'))
42908+ goto fail1;
4213142909 prop_val = json_parse_value(s);
4213242910 if (JS_IsException(prop_val)) {
42133− JS_FreeValue(ctx, prop_str);
42911+ fail1:
42912+ JS_FreeAtom(ctx, prop_name);
4213442913 goto fail;
4213542914 }
42136− ret = JS_DefinePropertyValueValue(ctx, val, prop_str,
42137− prop_val, JS_PROP_C_W_E);
42915+ ret = JS_DefinePropertyValue(ctx, val, prop_name,
42916+ prop_val, JS_PROP_C_W_E);
42917+ JS_FreeAtom(ctx, prop_name);
4213842918 if (ret < 0)
4213942919 goto fail;
4214042920
4214142921 if (s->token.val != ',')
4214242922 break;
42143− if (next_token(s))
42923+ if (json_next_token(s))
4214442924 goto fail;
42925+ if (s->ext_json && s->token.val == '}')
42926+ break;
4214542927 }
4214642928 }
42147− if (js_parse_expect(s, '}'))
42929+ if (json_parse_expect(s, '}'))
4214842930 goto fail;
4214942931 }
4215042932 break;
@@ -42153,7 +42935,7 @@ static JSValue json_parse_value(JSParseState *s) · 2 unmodified lines
4215342935 JSValue el;
4215442936 uint32_t idx;
4215542937
42156− if (next_token(s))
42938+ if (json_next_token(s))
4215742939 goto fail;
4215842940 val = JS_NewArray(ctx);
4215942941 if (JS_IsException(val))
@@ -42169,52 +42951,41 @@ static JSValue json_parse_value(JSParseState *s) · 9 unmodified lines
4216942951 goto fail;
4217042952 if (s->token.val != ',')
4217142953 break;
42172− if (next_token(s))
42954+ if (json_next_token(s))
4217342955 goto fail;
4217442956 idx++;
42957+ if (s->ext_json && s->token.val == ']')
42958+ break;
4217542959 }
4217642960 }
42177− if (js_parse_expect(s, ']'))
42961+ if (json_parse_expect(s, ']'))
4217842962 goto fail;
4217942963 }
4218042964 break;
4218142965 case TOK_STRING:
4218242966 val = JS_DupValue(ctx, s->token.u.str.str);
42183− if (next_token(s))
42967+ if (json_next_token(s))
4218442968 goto fail;
4218542969 break;
4218642970 case TOK_NUMBER:
42187− is_neg = 0;
42188− goto number;
42189− case '-':
42190− if (next_token(s))
42191− goto fail;
42192− if (s->token.val != TOK_NUMBER) {
42193− js_parse_error(s, "number expected");
42194− goto fail;
42195− }
42196− is_neg = 1;
42197− number:
4219842971 val = s->token.u.num.val;
42199− if (is_neg) {
42200− double d;
42201− JS_ToFloat64(ctx, &d, val); /* no exception possible */
42202− val = JS_NewFloat64(ctx, -d);
42203− }
42204− if (next_token(s))
42972+ if (json_next_token(s))
4220542973 goto fail;
4220642974 break;
42207− case TOK_FALSE:
42208− case TOK_TRUE:
42209− val = JS_NewBool(ctx, s->token.val - TOK_FALSE);
42210− if (next_token(s))
42211− goto fail;
42212− break;
42213− case TOK_NULL:
42214− if (next_token(s))
42975+ case TOK_IDENT:
42976+ if (s->token.u.ident.atom == JS_ATOM_false ||
42977+ s->token.u.ident.atom == JS_ATOM_true) {
42978+ val = JS_NewBool(ctx, (s->token.u.ident.atom == JS_ATOM_true));
42979+ } else if (s->token.u.ident.atom == JS_ATOM_null) {
42980+ val = JS_NULL;
42981+ } else {
42982+ goto def_token;
42983+ }
42984+ if (json_next_token(s))
4221542985 goto fail;
4221642986 break;
4221742987 default:
42988+ def_token:
4221842989 if (s->token.val == TOK_EOF) {
4221942990 js_parse_error(s, "unexpected end of input");
4222042991 } else {
@@ -42229,15 +43000,15 @@ static JSValue json_parse_value(JSParseState *s) · 8 unmodified lines
4222943000 return JS_EXCEPTION;
4223043001 }
4223143002
42232−JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
42233− const char *filename)
43003+JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
43004+ const char *filename, int flags)
4223443005 {
4223543006 JSParseState s1, *s = &s1;
42236− JSValue val;
43007+ JSValue val = JS_UNDEFINED;
4223743008
4223843009 js_parse_init(ctx, s, buf, buf_len, filename);
42239−
42240− if (next_token(s))
43010+ s->ext_json = ((flags & JS_PARSE_JSON_EXT) != 0);
43011+ if (json_next_token(s))
4224143012 goto fail;
4224243013 val = json_parse_value(s);
4224343014 if (JS_IsException(val))
@@ -42248,10 +43019,17 @@ JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len, · 4 unmodified lines
4224843019 }
4224943020 return val;
4225043021 fail:
43022+ JS_FreeValue(ctx, val);
4225143023 free_token(s, &s->token);
4225243024 return JS_EXCEPTION;
4225343025 }
4225443026
43027+JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
43028+ const char *filename)
43029+{
43030+ return JS_ParseJSON2(ctx, buf, buf_len, filename, 0);
43031+}
43032+
4225543033 static JSValue internalize_json_property(JSContext *ctx, JSValueConst holder,
4225643034 JSAtom name, JSValueConst reviver)
4225743035 {
@@ -42960,7 +43738,6 @@ static void js_proxy_finalizer(JSRuntime *rt, JSValue val) · 702 unmodified lines
4296043738 if (s) {
4296143739 JS_FreeValueRT(rt, s->target);
4296243740 JS_FreeValueRT(rt, s->handler);
42963− JS_FreeValueRT(rt, s->proto);
4296443741 js_free_rt(rt, s);
4296543742 }
4296643743 }
@@ -42972,7 +43749,6 @@ static void js_proxy_mark(JSRuntime *rt, JSValueConst val, · 5 unmodified lines
4297243749 if (s) {
4297343750 JS_MarkValue(rt, s->target, mark_func);
4297443751 JS_MarkValue(rt, s->handler, mark_func);
42975− JS_MarkValue(rt, s->proto, mark_func);
4297643752 }
4297743753 }
4297843754
@@ -43007,17 +43783,12 @@ static JSProxyData *get_proxy_method(JSContext *ctx, JSValue *pmethod, · 28 unmodified lines
4300743783 return s;
4300843784 }
4300943785
43010−static JSValueConst js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
43786+static JSValue js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj)
4301143787 {
4301243788 JSProxyData *s;
43013− JSValue method, ret;
43014− JSValueConst proto1;
43789+ JSValue method, ret, proto1;
4301543790 int res;
4301643791
43017− /* must check for timeout to avoid infinite loop in instanceof */
43018− if (js_poll_interrupts(ctx))
43019− return JS_EXCEPTION;
43020−
4302143792 s = get_proxy_method(ctx, &method, obj, JS_ATOM_getPrototypeOf);
4302243793 if (!s)
4302343794 return JS_EXCEPTION;
@@ -43043,22 +43814,22 @@ static JSValueConst js_proxy_getPrototypeOf(JSContext *ctx, JSValueConst obj) · 19 unmodified lines
4304343814 return JS_EXCEPTION;
4304443815 }
4304543816 if (JS_VALUE_GET_OBJ(proto1) != JS_VALUE_GET_OBJ(ret)) {
43817+ JS_FreeValue(ctx, proto1);
4304643818 fail:
4304743819 JS_FreeValue(ctx, ret);
4304843820 return JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
4304943821 }
43822+ JS_FreeValue(ctx, proto1);
4305043823 }
43051− /* store the prototype in the proxy so that its refcount is at least 1 */
43052− set_value(ctx, &s->proto, ret);
43053− return (JSValueConst)ret;
43824+ return ret;
4305443825 }
4305543826
4305643827 static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj,
4305743828 JSValueConst proto_val, BOOL throw_flag)
4305843829 {
4305943830 JSProxyData *s;
43060− JSValue method, ret;
43061− JSValueConst args[2], proto1;
43831+ JSValue method, ret, proto1;
43832+ JSValueConst args[2];
4306243833 BOOL res;
4306343834 int res2;
4306443835
@@ -43089,9 +43860,11 @@ static int js_proxy_setPrototypeOf(JSContext *ctx, JSValueConst obj, · 24 unmodified lines
4308943860 if (JS_IsException(proto1))
4309043861 return -1;
4309143862 if (JS_VALUE_GET_OBJ(proto_val) != JS_VALUE_GET_OBJ(proto1)) {
43863+ JS_FreeValue(ctx, proto1);
4309243864 JS_ThrowTypeError(ctx, "proxy: inconsistent prototype");
4309343865 return -1;
4309443866 }
43867+ JS_FreeValue(ctx, proto1);
4309543868 }
4309643869 return TRUE;
4309743870 }
@@ -43829,7 +44602,6 @@ static JSValue js_proxy_constructor(JSContext *ctx, JSValueConst this_val, · 731 unmodified lines
4382944602 }
4383044603 s->target = JS_DupValue(ctx, target);
4383144604 s->handler = JS_DupValue(ctx, handler);
43832− s->proto = JS_NULL;
4383344605 s->is_func = JS_IsFunction(ctx, target);
4383444606 s->is_revoked = FALSE;
4383544607 JS_SetOpaque(obj, s);
@@ -45414,10 +46186,10 @@ static JSValue js_promise_all_resolve_element(JSContext *ctx, · 1578 unmodified lines
4541446186 static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val,
4541546187 int argc, JSValueConst *argv, int magic)
4541646188 {
45417− JSValue result_promise, resolving_funcs[2], iter, item, next_promise, ret;
46189+ JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
4541846190 JSValue next_method = JS_UNDEFINED, values = JS_UNDEFINED;
4541946191 JSValue resolve_element_env = JS_UNDEFINED, resolve_element, reject_element;
45420− JSValue promise_resolve = JS_UNDEFINED;
46192+ JSValue promise_resolve = JS_UNDEFINED, iter = JS_UNDEFINED;
4542146193 JSValueConst then_args[2], resolve_element_data[5];
4542246194 BOOL done;
4542346195 int index, is_zero, is_promise_any = (magic == PROMISE_MAGIC_any);
@@ -45427,6 +46199,10 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, · 3 unmodified lines
4542746199 result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
4542846200 if (JS_IsException(result_promise))
4542946201 return result_promise;
46202+ promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
46203+ if (JS_IsException(promise_resolve) ||
46204+ check_function(ctx, promise_resolve))
46205+ goto fail_reject;
4543046206 iter = JS_GetIterator(ctx, argv[0], FALSE);
4543146207 if (JS_IsException(iter)) {
4543246208 JSValue error;
@@ -45454,11 +46230,6 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, · 21 unmodified lines
4545446230 JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
4545546231 goto fail_reject;
4545646232
45457− promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
45458− if (JS_IsException(promise_resolve) ||
45459− check_function(ctx, promise_resolve))
45460− goto fail_reject1;
45461−
4546246233 index = 0;
4546346234 for(;;) {
4546446235 /* XXX: conformance: should close the iterator if error on 'done'
@@ -45560,8 +46331,8 @@ static JSValue js_promise_all(JSContext *ctx, JSValueConst this_val, · 95 unmodified lines
4556046331 static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val,
4556146332 int argc, JSValueConst *argv)
4556246333 {
45563− JSValue result_promise, resolving_funcs[2], iter, item, next_promise, ret;
45564− JSValue next_method = JS_UNDEFINED;
46334+ JSValue result_promise, resolving_funcs[2], item, next_promise, ret;
46335+ JSValue next_method = JS_UNDEFINED, iter = JS_UNDEFINED;
4556546336 JSValue promise_resolve = JS_UNDEFINED;
4556646337 BOOL done;
4556746338
@@ -45570,6 +46341,10 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, · 2 unmodified lines
4557046341 result_promise = js_new_promise_capability(ctx, resolving_funcs, this_val);
4557146342 if (JS_IsException(result_promise))
4557246343 return result_promise;
46344+ promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
46345+ if (JS_IsException(promise_resolve) ||
46346+ check_function(ctx, promise_resolve))
46347+ goto fail_reject;
4557346348 iter = JS_GetIterator(ctx, argv[0], FALSE);
4557446349 if (JS_IsException(iter)) {
4557546350 JSValue error;
@@ -45586,11 +46361,6 @@ static JSValue js_promise_race(JSContext *ctx, JSValueConst this_val, · 10 unmodified lines
4558646361 if (JS_IsException(next_method))
4558746362 goto fail_reject;
4558846363
45589− promise_resolve = JS_GetProperty(ctx, this_val, JS_ATOM_resolve);
45590− if (JS_IsException(promise_resolve) ||
45591− check_function(ctx, promise_resolve))
45592− goto fail_reject1;
45593−
4559446364 for(;;) {
4559546365 /* XXX: conformance: should close the iterator if error on 'done'
4559646366 access, but not on 'value' access */
@@ -49385,9 +50155,6 @@ static void JS_AddIntrinsicBasicObjects(JSContext *ctx) · 3788 unmodified lines
4938550155 JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
4938650156 ctx->native_error_proto[i] = proto;
4938750157 }
49388− JS_SetPropertyFunctionList(ctx, ctx->native_error_proto[JS_AGGREGATE_ERROR],
49389− js_aggregate_error_proto_funcs,
49390− countof(js_aggregate_error_proto_funcs));
4939150158
4939250159 /* the array prototype is an array */
4939350160 ctx->class_proto[JS_CLASS_ARRAY] =
@@ -49621,6 +50388,7 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx, · 227 unmodified lines
4962150388 JSFreeArrayBufferDataFunc *free_func,
4962250389 void *opaque, BOOL alloc_flag)
4962350390 {
50391+ JSRuntime *rt = ctx->rt;
4962450392 JSValue obj;
4962550393 JSArrayBuffer *abuf = NULL;
4962650394
@@ -49637,11 +50405,24 @@ static JSValue js_array_buffer_constructor3(JSContext *ctx, · 10 unmodified lines
4963750405 goto fail;
4963850406 abuf->byte_length = len;
4963950407 if (alloc_flag) {
49640− /* the allocation must be done after the object creation */
49641− abuf->data = js_mallocz(ctx, max_int(len, 1));
49642− if (!abuf->data)
49643− goto fail;
50408+ if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
50409+ rt->sab_funcs.sab_alloc) {
50410+ abuf->data = rt->sab_funcs.sab_alloc(rt->sab_funcs.sab_opaque,
50411+ max_int(len, 1));
50412+ if (!abuf->data)
50413+ goto fail;
50414+ memset(abuf->data, 0, len);
50415+ } else {
50416+ /* the allocation must be done after the object creation */
50417+ abuf->data = js_mallocz(ctx, max_int(len, 1));
50418+ if (!abuf->data)
50419+ goto fail;
50420+ }
4964450421 } else {
50422+ if (class_id == JS_CLASS_SHARED_ARRAY_BUFFER &&
50423+ rt->sab_funcs.sab_dup) {
50424+ rt->sab_funcs.sab_dup(rt->sab_funcs.sab_opaque, buf);
50425+ }
4964550426 abuf->data = buf;
4964650427 }
4964750428 init_list_head(&abuf->array_list);
@@ -49731,8 +50512,12 @@ static void js_array_buffer_finalizer(JSRuntime *rt, JSValue val) · 83 unmodified lines
4973150512 array finalizers using it, so abuf->array_list is not
4973250513 necessarily empty. */
4973350514 // assert(list_empty(&abuf->array_list));
49734− if (abuf->free_func)
49735− abuf->free_func(rt, abuf->opaque, abuf->data);
50515+ if (abuf->shared && rt->sab_funcs.sab_free) {
50516+ rt->sab_funcs.sab_free(rt->sab_funcs.sab_opaque, abuf->data);
50517+ } else {
50518+ if (abuf->free_func)
50519+ abuf->free_func(rt, abuf->opaque, abuf->data);
50520+ }
4973650521 js_free_rt(rt, abuf);
4973750522 }
4973850523 }
@@ -50208,11 +50993,6 @@ static JSValue js_typed_array___getLength(JSContext *ctx, · 469 unmodified lines
5020850993 }
5020950994 #endif
5021050995
50211−static JSValue js_typed_array_constructor(JSContext *ctx,
50212− JSValueConst this_val,
50213− int argc, JSValueConst *argv,
50214− int classid);
50215−
5021650996 static JSValue js_typed_array_create(JSContext *ctx, JSValueConst ctor,
5021750997 int argc, JSValueConst *argv)
5021850998 {
@@ -51967,9 +52747,10 @@ typedef enum AtomicsOpEnum { · 1748 unmodified lines
5196752747 } AtomicsOpEnum;
5196852748
5196952749 static void *js_atomics_get_ptr(JSContext *ctx,
52750+ JSArrayBuffer **pabuf,
5197052751 int *psize_log2, JSClassID *pclass_id,
5197152752 JSValueConst obj, JSValueConst idx_val,
51972− BOOL is_waitable)
52753+ int is_waitable)
5197352754 {
5197452755 JSObject *p;
5197552756 JSTypedArray *ta;
@@ -52004,18 +52785,27 @@ static void *js_atomics_get_ptr(JSContext *ctx, · 28 unmodified lines
5200452785 ta = p->u.typed_array;
5200552786 abuf = ta->buffer->u.array_buffer;
5200652787 if (!abuf->shared) {
52007− JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
52008− return NULL;
52788+ if (is_waitable == 2) {
52789+ JS_ThrowTypeError(ctx, "not a SharedArrayBuffer TypedArray");
52790+ return NULL;
52791+ }
52792+ if (abuf->detached) {
52793+ JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
52794+ return NULL;
52795+ }
5200952796 }
5201052797 if (JS_ToIndex(ctx, &idx, idx_val)) {
5201152798 return NULL;
5201252799 }
52800+ /* if the array buffer is detached, p->u.array.count = 0 */
5201352801 if (idx >= p->u.array.count) {
5201452802 JS_ThrowRangeError(ctx, "out-of-bound access");
5201552803 return NULL;
5201652804 }
5201752805 size_log2 = typed_array_size_log2(p->class_id);
5201852806 ptr = p->u.array.u.uint8_ptr + ((uintptr_t)idx << size_log2);
52807+ if (pabuf)
52808+ *pabuf = abuf;
5201952809 if (psize_log2)
5202052810 *psize_log2 = size_log2;
5202152811 if (pclass_id)
@@ -52036,17 +52826,18 @@ static JSValue js_atomics_op(JSContext *ctx, · 14 unmodified lines
5203652826 void *ptr;
5203752827 JSValue ret;
5203852828 JSClassID class_id;
52829+ JSArrayBuffer *abuf;
5203952830
52040− ptr = js_atomics_get_ptr(ctx, &size_log2, &class_id,
52041− argv[0], argv[1], FALSE);
52831+ ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, &class_id,
52832+ argv[0], argv[1], 0);
5204252833 if (!ptr)
5204352834 return JS_EXCEPTION;
5204452835 rep_val = 0;
5204552836 if (op == ATOMICS_OP_LOAD) {
5204652837 v = 0;
52047− } else
52838+ } else {
5204852839 #ifdef CONFIG_BIGNUM
52049− if (size_log2 == 3) {
52840+ if (size_log2 == 3) {
5205052841 int64_t v64;
5205152842 if (JS_ToBigInt64(ctx, &v64, argv[2]))
5205252843 return JS_EXCEPTION;
@@ -52056,19 +52847,23 @@ static JSValue js_atomics_op(JSContext *ctx, · 3 unmodified lines
5205652847 return JS_EXCEPTION;
5205752848 rep_val = v64;
5205852849 }
52059− } else
52850+ } else
5206052851 #endif
52061− {
52062− uint32_t v32;
52063− if (JS_ToUint32(ctx, &v32, argv[2]))
52064− return JS_EXCEPTION;
52065− v = v32;
52066− if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
52067− if (JS_ToUint32(ctx, &v32, argv[3]))
52068− return JS_EXCEPTION;
52069− rep_val = v32;
52070− }
52852+ {
52853+ uint32_t v32;
52854+ if (JS_ToUint32(ctx, &v32, argv[2]))
52855+ return JS_EXCEPTION;
52856+ v = v32;
52857+ if (op == ATOMICS_OP_COMPARE_EXCHANGE) {
52858+ if (JS_ToUint32(ctx, &v32, argv[3]))
52859+ return JS_EXCEPTION;
52860+ rep_val = v32;
52861+ }
52862+ }
52863+ if (abuf->detached)
52864+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
5207152865 }
52866+
5207252867 switch(op | (size_log2 << 3)) {
5207352868
5207452869 #ifdef CONFIG_BIGNUM
@@ -52195,8 +52990,10 @@ static JSValue js_atomics_store(JSContext *ctx, · 120 unmodified lines
5219552990 int size_log2;
5219652991 void *ptr;
5219752992 JSValue ret;
52993+ JSArrayBuffer *abuf;
5219852994
52199− ptr = js_atomics_get_ptr(ctx, &size_log2, NULL, argv[0], argv[1], FALSE);
52995+ ptr = js_atomics_get_ptr(ctx, &abuf, &size_log2, NULL,
52996+ argv[0], argv[1], 0);
5220052997 if (!ptr)
5220152998 return JS_EXCEPTION;
5220252999 #ifdef CONFIG_BIGNUM
@@ -52209,6 +53006,8 @@ static JSValue js_atomics_store(JSContext *ctx, · 6 unmodified lines
5220953006 JS_FreeValue(ctx, ret);
5221053007 return JS_EXCEPTION;
5221153008 }
53009+ if (abuf->detached)
53010+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
5221253011 atomic_store((_Atomic(uint64_t) *)ptr, v64);
5221353012 } else
5221453013 #endif
@@ -52222,6 +53021,8 @@ static JSValue js_atomics_store(JSContext *ctx, · 7 unmodified lines
5222253021 JS_FreeValue(ctx, ret);
5222353022 return JS_EXCEPTION;
5222453023 }
53024+ if (abuf->detached)
53025+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
5222553026 switch(size_log2) {
5222653027 case 0:
5222753028 atomic_store((_Atomic(uint8_t) *)ptr, v);
@@ -52278,7 +53079,8 @@ static JSValue js_atomics_wait(JSContext *ctx, · 50 unmodified lines
5227853079 int ret, size_log2, res;
5227953080 double d;
5228053081
52281− ptr = js_atomics_get_ptr(ctx, &size_log2, NULL, argv[0], argv[1], TRUE);
53082+ ptr = js_atomics_get_ptr(ctx, NULL, &size_log2, NULL,
53083+ argv[0], argv[1], 2);
5228253084 if (!ptr)
5228353085 return JS_EXCEPTION;
5228453086 #ifdef CONFIG_BIGNUM
@@ -52357,8 +53159,9 @@ static JSValue js_atomics_notify(JSContext *ctx, · 72 unmodified lines
5235753159 int32_t count, n;
5235853160 void *ptr;
5235953161 JSAtomicsWaiter *waiter;
53162+ JSArrayBuffer *abuf;
5236053163
52361− ptr = js_atomics_get_ptr(ctx, NULL, NULL, argv[0], argv[1], TRUE);
53164+ ptr = js_atomics_get_ptr(ctx, &abuf, NULL, NULL, argv[0], argv[1], 1);
5236253165 if (!ptr)
5236353166 return JS_EXCEPTION;
5236453167
@@ -52368,9 +53171,11 @@ static JSValue js_atomics_notify(JSContext *ctx, · 3 unmodified lines
5236853171 if (JS_ToInt32Clamp(ctx, &count, argv[2], 0, INT32_MAX, 0))
5236953172 return JS_EXCEPTION;
5237053173 }
53174+ if (abuf->detached)
53175+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
5237153176
5237253177 n = 0;
52373− if (count > 0) {
53178+ if (abuf->shared && count > 0) {
5237453179 pthread_mutex_lock(&js_atomics_mutex);
5237553180 init_list_head(&waiter_list);
5237653181 list_for_each_safe(el, el1, &js_atomics_waiter_list) {
quickjs.h+25−4
@@ -498,7 +498,7 @@ int JS_IsRegisteredClass(JSRuntime *rt, JSClassID class_id); · 497 unmodified lines
498498
499499 static js_force_inline JSValue JS_NewBool(JSContext *ctx, JS_BOOL val)
500500 {
501− return JS_MKVAL(JS_TAG_BOOL, val);
501+ return JS_MKVAL(JS_TAG_BOOL, (val != 0));
502502 }
503503
504504 static js_force_inline JSValue JS_NewInt32(JSContext *ctx, int32_t val)
@@ -746,7 +746,7 @@ int JS_IsExtensible(JSContext *ctx, JSValueConst obj); · 241 unmodified lines
746746 int JS_PreventExtensions(JSContext *ctx, JSValueConst obj);
747747 int JS_DeleteProperty(JSContext *ctx, JSValueConst obj, JSAtom prop, int flags);
748748 int JS_SetPrototype(JSContext *ctx, JSValueConst obj, JSValueConst proto_val);
749−JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val);
749+JSValue JS_GetPrototype(JSContext *ctx, JSValueConst val);
750750
751751 #define JS_GPN_STRING_MASK (1 << 0)
752752 #define JS_GPN_SYMBOL_MASK (1 << 1)
@@ -796,6 +796,9 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id); · 43 unmodified lines
796796 /* 'buf' must be zero terminated i.e. buf[buf_len] = '\0'. */
797797 JSValue JS_ParseJSON(JSContext *ctx, const char *buf, size_t buf_len,
798798 const char *filename);
799+#define JS_PARSE_JSON_EXT (1 << 0) /* allow extended JSON */
800+JSValue JS_ParseJSON2(JSContext *ctx, const char *buf, size_t buf_len,
801+ const char *filename, int flags);
799802 JSValue JS_JSONStringify(JSContext *ctx, JSValueConst obj,
800803 JSValueConst replacer, JSValueConst space0);
801804
@@ -810,6 +813,14 @@ JSValue JS_GetTypedArrayBuffer(JSContext *ctx, JSValueConst obj, · 8 unmodified lines
810813 size_t *pbyte_offset,
811814 size_t *pbyte_length,
812815 size_t *pbytes_per_element);
816+typedef struct {
817+ void *(*sab_alloc)(void *opaque, size_t size);
818+ void (*sab_free)(void *opaque, void *ptr);
819+ void (*sab_dup)(void *opaque, void *ptr);
820+ void *sab_opaque;
821+} JSSharedArrayBufferFunctions;
822+void JS_SetSharedArrayBufferFunctions(JSRuntime *rt,
823+ const JSSharedArrayBufferFunctions *sf);
813824
814825 JSValue JS_NewPromiseCapability(JSContext *ctx, JSValue *resolving_funcs);
815826
@@ -853,14 +864,24 @@ JS_BOOL JS_IsJobPending(JSRuntime *rt); · 37 unmodified lines
853864 int JS_ExecutePendingJob(JSRuntime *rt, JSContext **pctx);
854865
855866 /* Object Writer/Reader (currently only used to handle precompiled code) */
856−#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
857−#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
867+#define JS_WRITE_OBJ_BYTECODE (1 << 0) /* allow function/module */
868+#define JS_WRITE_OBJ_BSWAP (1 << 1) /* byte swapped output */
869+#define JS_WRITE_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
870+#define JS_WRITE_OBJ_REFERENCE (1 << 3) /* allow object references to
871+ encode arbitrary object
872+ graph */
858873 uint8_t *JS_WriteObject(JSContext *ctx, size_t *psize, JSValueConst obj,
859874 int flags);
875+uint8_t *JS_WriteObject2(JSContext *ctx, size_t *psize, JSValueConst obj,
876+ int flags, uint8_t ***psab_tab, size_t *psab_tab_len);
877+
860878 #define JS_READ_OBJ_BYTECODE (1 << 0) /* allow function/module */
861879 #define JS_READ_OBJ_ROM_DATA (1 << 1) /* avoid duplicating 'buf' data */
880+#define JS_READ_OBJ_SAB (1 << 2) /* allow SharedArrayBuffer */
881+#define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */
862882 JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
863883 int flags);
884+
864885 /* load the dependencies of the module 'obj'. Useful when JS_ReadObject()
865886 returns a module. */
866887 int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
repl.js+58−14
@@ -209,6 +209,29 @@ import * as os from "os"; · 208 unmodified lines
209209 (is_alpha(c) || is_digit(c) || c == '_' || c == '$');
210210 }
211211
212+ function ucs_length(str) {
213+ var len, c, i, str_len = str.length;
214+ len = 0;
215+ /* we never count the trailing surrogate to have the
216+ following property: ucs_length(str) =
217+ ucs_length(str.substring(0, a)) + ucs_length(str.substring(a,
218+ str.length)) for 0 <= a <= str.length */
219+ for(i = 0; i < str_len; i++) {
220+ c = str.charCodeAt(i);
221+ if (c < 0xdc00 || c >= 0xe000)
222+ len++;
223+ }
224+ return len;
225+ }
226+
227+ function is_trailing_surrogate(c) {
228+ var d;
229+ if (typeof c !== "string")
230+ return false;
231+ d = c.codePointAt(0); /* can be NaN if empty string */
232+ return d >= 0xdc00 && d < 0xe000;
233+ }
234+
212235 function is_balanced(a, b) {
213236 switch (a + b) {
214237 case "()":
@@ -235,6 +258,7 @@ import * as os from "os"; · 20 unmodified lines
235258 std.puts("\x1b[" + ((n != 1) ? n : "") + code);
236259 }
237260
261+ /* XXX: handle double-width characters */
238262 function move_cursor(delta) {
239263 var i, l;
240264 if (delta > 0) {
@@ -269,15 +293,16 @@ import * as os from "os"; · 28 unmodified lines
269293 }
270294
271295 function update() {
272− var i;
273−
296+ var i, cmd_len;
297+ /* cursor_pos is the position in 16 bit characters inside the
298+ UTF-16 string 'cmd' */
274299 if (cmd != last_cmd) {
275300 if (!show_colors && last_cmd.substring(0, last_cursor_pos) == cmd.substring(0, last_cursor_pos)) {
276301 /* optimize common case */
277302 std.puts(cmd.substring(last_cursor_pos));
278303 } else {
279304 /* goto the start of the line */
280− move_cursor(-last_cursor_pos);
305+ move_cursor(-ucs_length(last_cmd.substring(0, last_cursor_pos)));
281306 if (show_colors) {
282307 var str = mexpr ? mexpr + '\n' + cmd : cmd;
283308 var start = str.length - cmd.length;
@@ -287,8 +312,7 @@ import * as os from "os"; · 3 unmodified lines
287312 std.puts(cmd);
288313 }
289314 }
290− /* Note: assuming no surrogate pairs */
291− term_cursor_x = (term_cursor_x + cmd.length) % term_width;
315+ term_cursor_x = (term_cursor_x + ucs_length(cmd)) % term_width;
292316 if (term_cursor_x == 0) {
293317 /* show the cursor on the next line */
294318 std.puts(" \x08");
@@ -298,7 +322,11 @@ import * as os from "os"; · 3 unmodified lines
298322 last_cmd = cmd;
299323 last_cursor_pos = cmd.length;
300324 }
301− move_cursor(cursor_pos - last_cursor_pos);
325+ if (cursor_pos > last_cursor_pos) {
326+ move_cursor(ucs_length(cmd.substring(last_cursor_pos, cursor_pos)));
327+ } else if (cursor_pos < last_cursor_pos) {
328+ move_cursor(-ucs_length(cmd.substring(cursor_pos, last_cursor_pos)));
329+ }
302330 last_cursor_pos = cursor_pos;
303331 std.out.flush();
304332 }
@@ -333,13 +361,19 @@ import * as os from "os"; · 28 unmodified lines
333361 }
334362
335363 function forward_char() {
336− if (cursor_pos < cmd.length)
364+ if (cursor_pos < cmd.length) {
337365 cursor_pos++;
366+ while (is_trailing_surrogate(cmd.charAt(cursor_pos)))
367+ cursor_pos++;
368+ }
338369 }
339370
340371 function backward_char() {
341− if (cursor_pos > 0)
372+ if (cursor_pos > 0) {
342373 cursor_pos--;
374+ while (is_trailing_surrogate(cmd.charAt(cursor_pos)))
375+ cursor_pos--;
376+ }
343377 }
344378
345379 function skip_word_forward(pos) {
@@ -419,8 +453,18 @@ import * as os from "os"; · 73 unmodified lines
419453 }
420454
421455 function delete_char_dir(dir) {
422− var start = cursor_pos - (dir < 0);
423− var end = start + 1;
456+ var start, end;
457+
458+ start = cursor_pos;
459+ if (dir < 0) {
460+ start--;
461+ while (is_trailing_surrogate(cmd.charAt(start)))
462+ start--;
463+ }
464+ end = start + 1;
465+ while (is_trailing_surrogate(cmd.charAt(end)))
466+ end++;
467+
424468 if (start >= 0 && start < cmd.length) {
425469 if (last_fun === kill_region) {
426470 kill_region(start, end, dir);
@@ -752,7 +796,7 @@ import * as os from "os"; · 325 unmodified lines
752796 function readline_print_prompt()
753797 {
754798 std.puts(prompt);
755− term_cursor_x = prompt.length % term_width;
799+ term_cursor_x = ucs_length(prompt) % term_width;
756800 last_cmd = "";
757801 last_cursor_pos = 0;
758802 }
@@ -785,7 +829,7 @@ import * as os from "os"; · 26 unmodified lines
785829
786830 function handle_char(c1) {
787831 var c;
788− c = String.fromCharCode(c1);
832+ c = String.fromCodePoint(c1);
789833 switch(readline_state) {
790834 case 0:
791835 if (c == '\x1b') { /* '^[' - ESC */
@@ -825,7 +869,7 @@ import * as os from "os"; · 33 unmodified lines
825869 var fun;
826870
827871 if (quote_flag) {
828− if (keys.length === 1)
872+ if (ucs_length(keys) === 1)
829873 insert(keys);
830874 quote_flag = false;
831875 } else if (fun = commands[keys]) {
@@ -845,7 +889,7 @@ import * as os from "os"; · 13 unmodified lines
845889 return;
846890 }
847891 last_fun = this_fun;
848− } else if (keys.length === 1 && keys >= ' ') {
892+ } else if (ucs_length(keys) === 1 && keys >= ' ') {
849893 insert(keys);
850894 last_fun = insert;
851895 } else {
test262.conf+1−0
@@ -58,6 +58,7 @@ arrow-function · 57 unmodified lines
5858 async-functions
5959 async-iteration
6060 Atomics
61+Atomics.waitAsync=skip
6162 BigInt
6263 caller
6364 class
test262_errors.txt+4−2
@@ -2,6 +2,8 @@ test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-r · 1 unmodified line
22 test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
33 test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
44 test262/test/built-ins/Proxy/ownKeys/trap-is-undefined-target-is-proxy.js:29: strict mode: Test262Error: Expected [0, length, foo, Symbol()] and [Symbol(), length, foo, 0] to have the same contents.
5+test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
6+test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
57 test262/test/language/expressions/arrow-function/eval-var-scope-syntax-err.js:47: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
68 test262/test/language/expressions/async-arrow-function/eval-var-scope-syntax-err.js:49: TypeError: $DONE() not called
79 test262/test/language/expressions/async-function/named-eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
@@ -18,8 +20,8 @@ test262/test/language/expressions/object/method-definition/async-gen-meth-eval-v · 10 unmodified lines
1820 test262/test/language/expressions/object/method-definition/async-meth-eval-var-scope-syntax-err.js:36: TypeError: $DONE() not called
1921 test262/test/language/expressions/object/method-definition/gen-meth-eval-var-scope-syntax-err.js:54: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
2022 test262/test/language/expressions/object/method-definition/meth-eval-var-scope-syntax-err.js:50: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
21−test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: value has no property
22−test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: value has no property
23+test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
24+test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined
2325 test262/test/language/statements/async-function/eval-var-scope-syntax-err.js:33: TypeError: $DONE() not called
2426 test262/test/language/statements/async-generator/eval-var-scope-syntax-err.js:28: Test262Error: Expected a SyntaxError to be thrown but no exception was thrown at all
2527 test262/test/language/statements/class/elements/grammar-private-field-optional-chaining.js:26: SyntaxError: expecting field name
tests/bjson.c+12−4
@@ -31,6 +31,7 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val, · 30 unmodified lines
3131 uint64_t pos, len;
3232 JSValue obj;
3333 size_t size;
34+ int flags;
3435
3536 if (JS_ToIndex(ctx, &pos, argv[1]))
3637 return JS_EXCEPTION;
@@ -41,7 +42,10 @@ static JSValue js_bjson_read(JSContext *ctx, JSValueConst this_val, · 4 unmodified lines
4142 return JS_EXCEPTION;
4243 if (pos + len > size)
4344 return JS_ThrowRangeError(ctx, "array buffer overflow");
44− obj = JS_ReadObject(ctx, buf + pos, len, 0);
45+ flags = 0;
46+ if (JS_ToBool(ctx, argv[3]))
47+ flags |= JS_READ_OBJ_REFERENCE;
48+ obj = JS_ReadObject(ctx, buf + pos, len, flags);
4549 return obj;
4650 }
4751
@@ -51,8 +55,12 @@ static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val, · 3 unmodified lines
5155 size_t len;
5256 uint8_t *buf;
5357 JSValue array;
58+ int flags;
5459
55− buf = JS_WriteObject(ctx, &len, argv[0], 0);
60+ flags = 0;
61+ if (JS_ToBool(ctx, argv[1]))
62+ flags |= JS_WRITE_OBJ_REFERENCE;
63+ buf = JS_WriteObject(ctx, &len, argv[0], flags);
5664 if (!buf)
5765 return JS_EXCEPTION;
5866 array = JS_NewArrayBufferCopy(ctx, buf, len);
@@ -61,8 +69,8 @@ static JSValue js_bjson_write(JSContext *ctx, JSValueConst this_val, · 2 unmodified lines
6169 }
6270
6371 static const JSCFunctionListEntry js_bjson_funcs[] = {
64− JS_CFUNC_DEF("read", 3, js_bjson_read ),
65− JS_CFUNC_DEF("write", 1, js_bjson_write ),
72+ JS_CFUNC_DEF("read", 4, js_bjson_read ),
73+ JS_CFUNC_DEF("write", 2, js_bjson_write ),
6674 };
6775
6876 static int js_bjson_init(JSContext *ctx, JSModuleDef *m)
tests/microbench.js+14−0
@@ -228,6 +228,19 @@ function prop_create(n) · 227 unmodified lines
228228 return n * 4;
229229 }
230230
231+function prop_delete(n)
232+{
233+ var obj, j;
234+ obj = {};
235+ for(j = 0; j < n; j++) {
236+ obj[j] = 1;
237+ }
238+ for(j = 0; j < n; j++) {
239+ delete obj[j];
240+ }
241+ return n;
242+}
243+
231244 function array_read(n)
232245 {
233246 var tab, len, sum, i, j;
@@ -945,6 +958,7 @@ function main(argc, argv, g) · 711 unmodified lines
945958 prop_read,
946959 prop_write,
947960 prop_create,
961+ prop_delete,
948962 array_read,
949963 array_write,
950964 array_prop_create,
tests/test_bjson.js+73−7
@@ -1,12 +1,20 @@
11 import * as bjson from "./bjson.so";
22
3−function assert(b, str)
4−{
5− if (b) {
3+function assert(actual, expected, message) {
4+ if (arguments.length == 1)
5+ expected = true;
6+
7+ if (actual === expected)
68 return;
7− } else {
8− throw Error("assertion failed: " + str);
9− }
9+
10+ if (actual !== null && expected !== null
11+ && typeof actual == 'object' && typeof expected == 'object'
12+ && actual.toString() === expected.toString())
13+ return;
14+
15+ throw Error("assertion failed: got |" + actual + "|" +
16+ ", expected |" + expected + "|" +
17+ (message ? " (" + message + ")" : ""));
1018 }
1119
1220 function toHex(a)
@@ -24,6 +32,20 @@ function toHex(a) · 11 unmodified lines
2432 return s;
2533 }
2634
35+function isArrayLike(a)
36+{
37+ return Array.isArray(a) ||
38+ (a instanceof Uint8ClampedArray) ||
39+ (a instanceof Uint8Array) ||
40+ (a instanceof Uint16Array) ||
41+ (a instanceof Uint32Array) ||
42+ (a instanceof Int8Array) ||
43+ (a instanceof Int16Array) ||
44+ (a instanceof Int32Array) ||
45+ (a instanceof Float32Array) ||
46+ (a instanceof Float64Array);
47+}
48+
2749 function toStr(a)
2850 {
2951 var s, i, props, prop;
@@ -32,7 +54,15 @@ function toStr(a) · 2 unmodified lines
3254 case "object":
3355 if (a === null)
3456 return "null";
35− if (Array.isArray(a)) {
57+ if (a instanceof Date) {
58+ s = "Date(" + toStr(a.valueOf()) + ")";
59+ } else if (a instanceof Number) {
60+ s = "Number(" + toStr(a.valueOf()) + ")";
61+ } else if (a instanceof String) {
62+ s = "String(" + toStr(a.valueOf()) + ")";
63+ } else if (a instanceof Boolean) {
64+ s = "Boolean(" + toStr(a.valueOf()) + ")";
65+ } else if (isArrayLike(a)) {
3666 s = "[";
3767 for(i = 0; i < a.length; i++) {
3868 if (i != 0)
@@ -85,6 +115,35 @@ function bjson_test(a) · 46 unmodified lines
85115 }
86116 }
87117
118+/* test multiple references to an object including circular
119+ references */
120+function bjson_test_reference()
121+{
122+ var array, buf, i, n, array_buffer;
123+ n = 16;
124+ array = [];
125+ for(i = 0; i < n; i++)
126+ array[i] = {};
127+ array_buffer = new ArrayBuffer(n);
128+ for(i = 0; i < n; i++) {
129+ array[i].next = array[(i + 1) % n];
130+ array[i].idx = i;
131+ array[i].typed_array = new Uint8Array(array_buffer, i, 1);
132+ }
133+ buf = bjson.write(array, true);
134+
135+ array = bjson.read(buf, 0, buf.byteLength, true);
136+
137+ /* check the result */
138+ for(i = 0; i < n; i++) {
139+ assert(array[i].next, array[(i + 1) % n]);
140+ assert(array[i].idx, i);
141+ assert(array[i].typed_array.buffer, array_buffer);
142+ assert(array[i].typed_array.length, 1);
143+ assert(array[i].typed_array.byteOffset, i);
144+ }
145+}
146+
88147 function bjson_test_all()
89148 {
90149 var obj;
@@ -111,6 +170,11 @@ function bjson_test_all() · 20 unmodified lines
111170 BigDecimal("1.233e-1000")]);
112171 }
113172
173+ bjson_test([new Date(1234), new String("abc"), new Number(-12.1), new Boolean(true)]);
174+
175+ bjson_test(new Int32Array([123123, 222111, -32222]));
176+ bjson_test(new Float64Array([123123, 222111.5]));
177+
114178 /* tested with a circular reference */
115179 obj = {};
116180 obj.x = obj;
@@ -120,6 +184,8 @@ function bjson_test_all() · 3 unmodified lines
120184 } catch(e) {
121185 assert(e instanceof TypeError);
122186 }
187+
188+ bjson_test_reference();
123189 }
124190
125191 bjson_test_all();
tests/test_builtin.js+4−0
@@ -287,6 +287,10 @@ function test_math() · 286 unmodified lines
287287 assert(Math.ceil(a), 2);
288288 assert(Math.imul(0x12345678, 123), -1088058456);
289289 assert(Math.fround(0.1), 0.10000000149011612);
290+ assert(Math.hypot() == 0);
291+ assert(Math.hypot(-2) == 2);
292+ assert(Math.hypot(3, 4) == 5);
293+ assert(Math.abs(Math.hypot(3, 4, 5) - 7.0710678118654755) <= 1e-15);
290294 }
291295
292296 function test_number()
tests/test_language.jsrenamed from tests/test_op.js+14−2
@@ -311,10 +311,21 @@ function test_template() · 310 unmodified lines
311311 var a, b;
312312 b = 123;
313313 a = `abc${b}d`;
314− assert(a === "abc123d");
314+ assert(a, "abc123d");
315315
316316 a = String.raw `abc${b}d`;
317− assert(a === "abc123d");
317+ assert(a, "abc123d");
318+
319+ a = "aaa";
320+ b = "bbb";
321+ assert(`aaa${a, b}ccc`, "aaabbbccc");
322+}
323+
324+function test_template_skip()
325+{
326+ var a = "Bar";
327+ var { b = `${a + `a${a}` }baz` } = {};
328+ assert(b, "BaraBarbaz");
318329 }
319330
320331 function test_object_literal()
@@ -358,6 +369,7 @@ test_prototype(); · 37 unmodified lines
358369 test_arguments();
359370 test_class();
360371 test_template();
372+test_template_skip();
361373 test_object_literal();
362374 test_regexp_skip();
363375 test_labels();
tests/test_std.js+21−0
@@ -26,6 +26,12 @@ try { std.loadScript("test_assert.js"); } catch(e) {} · 25 unmodified lines
2626 function test_printf()
2727 {
2828 assert(std.sprintf("a=%d s=%s", 123, "abc"), "a=123 s=abc");
29+ assert(std.sprintf("%010d", 123), "0000000123");
30+ assert(std.sprintf("%x", -2), "fffffffe");
31+ assert(std.sprintf("%lx", -2), "fffffffffffffffe");
32+ assert(std.sprintf("%10.1f", 2.1), " 2.1");
33+ assert(std.sprintf("%*.*f", 10, 2, -2.13), " -2.13");
34+ assert(std.sprintf("%#lx", 0x7fffffffffffffffn), "0x7fffffffffffffff");
2935 }
3036
3137 function test_file1()
@@ -119,6 +125,20 @@ function test_popen() · 87 unmodified lines
119125 os.remove(fname);
120126 }
121127
128+function test_ext_json()
129+{
130+ var expected, input, obj;
131+ expected = '{"x":false,"y":true,"z2":null,"a":[1,8,160],"s":"str"}';
132+ input = `{ "x":false, /*comments are allowed */
133+ "y":true, // also a comment
134+ z2:null, // unquoted property names
135+ "a":[+1,0o10,0xa0,], // plus prefix, octal, hexadecimal
136+ "s":"str",} // trailing comma in objects and arrays
137+ `;
138+ obj = std.parseExtJSON(input);
139+ assert(JSON.stringify(obj), expected);
140+}
141+
122142 function test_os()
123143 {
124144 var fd, fpath, fname, fdir, buf, buf2, i, files, err, fdate, st, link_path;
@@ -258,3 +278,4 @@ test_popen(); · 133 unmodified lines
258278 test_os();
259279 test_os_exec();
260280 test_timer();
281+test_ext_json();
tests/test_worker.js+93−0
@@ -0,0 +1,93 @@
1+/* os.Worker API test */
2+import * as std from "std";
3+import * as os from "os";
4+
5+function assert(actual, expected, message) {
6+ if (arguments.length == 1)
7+ expected = true;
8+
9+ if (actual === expected)
10+ return;
11+
12+ if (actual !== null && expected !== null
13+ && typeof actual == 'object' && typeof expected == 'object'
14+ && actual.toString() === expected.toString())
15+ return;
16+
17+ throw Error("assertion failed: got |" + actual + "|" +
18+ ", expected |" + expected + "|" +
19+ (message ? " (" + message + ")" : ""));
20+}
21+
22+var worker;
23+
24+function test_worker()
25+{
26+ var counter;
27+
28+ /* Note: can use std.loadFile() to read from a file */
29+ worker = new os.Worker(`
30+ import * as std from "std";
31+ import * as os from "os";
32+
33+ var parent = os.Worker.parent;
34+
35+ function handle_msg(e) {
36+ var ev = e.data;
37+// print("child_recv", JSON.stringify(ev));
38+ switch(ev.type) {
39+ case "abort":
40+ parent.postMessage({ type: "done" });
41+ break;
42+ case "sab":
43+ /* modify the SharedArrayBuffer */
44+ ev.buf[2] = 10;
45+ parent.postMessage({ type: "sab_done", buf: ev.buf });
46+ break;
47+ }
48+ }
49+
50+ function worker_main() {
51+ var i;
52+
53+ parent.onmessage = handle_msg;
54+ for(i = 0; i < 10; i++) {
55+ parent.postMessage({ type: "num", num: i });
56+ }
57+ }
58+ worker_main();
59+`);
60+
61+ counter = 0;
62+ worker.onmessage = function (e) {
63+ var ev = e.data;
64+// print("recv", JSON.stringify(ev));
65+ switch(ev.type) {
66+ case "num":
67+ assert(ev.num, counter);
68+ counter++;
69+ if (counter == 10) {
70+ /* test SharedArrayBuffer modification */
71+ let sab = new SharedArrayBuffer(10);
72+ let buf = new Uint8Array(sab);
73+ worker.postMessage({ type: "sab", buf: buf });
74+ }
75+ break;
76+ case "sab_done":
77+ {
78+ let buf = ev.buf;
79+ /* check that the SharedArrayBuffer was modified */
80+ assert(buf[2], 10);
81+ worker.postMessage({ type: "abort" });
82+ }
83+ break;
84+ case "done":
85+ /* terminate */
86+ worker.onmessage = null;
87+ break;
88+ }
89+ };
90+}
91+
92+
93+test_worker();

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t