Browse Source

2020-09-06 release

pull/11/head
bellard 2 years ago
parent
commit
7c312df422
  1. 9
      Changelog
  2. 4
      TODO
  3. 2
      VERSION
  4. 21
      cutils.c
  5. 4
      doc/jsbignum.html
  6. BIN
      doc/jsbignum.pdf
  7. 28
      doc/quickjs.html
  8. BIN
      doc/quickjs.pdf
  9. 23
      doc/quickjs.texi
  10. 20
      libregexp.c
  11. 1
      libregexp.h
  12. 26
      libunicode.c
  13. 43
      qjs.c
  14. 74
      qjsc.c
  15. 4
      qjscalc.js
  16. 100
      quickjs-libc.c
  17. 3
      quickjs-libc.h
  18. 3
      quickjs-opcode.h
  19. 884
      quickjs.c
  20. 10
      quickjs.h
  21. 11
      run-test262.c
  22. 5
      test262.conf
  23. 2
      tests/test_builtin.js
  24. 19
      tests/test_language.js
  25. 33
      tests/test_worker.js
  26. 31
      tests/test_worker_module.js

9
Changelog

@ -1,3 +1,12 @@
2020-09-06:
- added logical assignment operators
- added IsHTMLDDA support
- faster for-of loops
- os.Worker now takes a module filename as parameter
- qjsc: added -D option to compile dynamically loaded modules or workers
- misc bug fixes
2020-07-05:
- modified JS_GetPrototype() to return a live value

4
TODO

@ -74,5 +74,5 @@ REPL:
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
Test262: 30/71095 errors, 870 excluded, 549 skipped
Test262 commit: 281eb10b2844929a7c0ac04527f5b42ce56509fd
Test262: 30/71748 errors, 868 excluded, 474 skipped
Test262 commit: 24c67328062383079ada85f4d253eb0526fd209b

2
VERSION

@ -1 +1 @@
2020-07-05
2020-09-06

21
cutils.c

@ -258,19 +258,30 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
return c;
}
switch(c) {
case 0xc0 ... 0xdf:
case 0xc0: case 0xc1: case 0xc2: case 0xc3:
case 0xc4: case 0xc5: case 0xc6: case 0xc7:
case 0xc8: case 0xc9: case 0xca: case 0xcb:
case 0xcc: case 0xcd: case 0xce: case 0xcf:
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb:
case 0xdc: case 0xdd: case 0xde: case 0xdf:
l = 1;
break;
case 0xe0 ... 0xef:
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
case 0xe8: case 0xe9: case 0xea: case 0xeb:
case 0xec: case 0xed: case 0xee: case 0xef:
l = 2;
break;
case 0xf0 ... 0xf7:
case 0xf0: case 0xf1: case 0xf2: case 0xf3:
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
l = 3;
break;
case 0xf8 ... 0xfb:
case 0xf8: case 0xf9: case 0xfa: case 0xfb:
l = 4;
break;
case 0xfc ... 0xfd:
case 0xfc: case 0xfd:
l = 5;
break;
default:

4
doc/jsbignum.html

@ -1,8 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Javascript Bignum Extensions</title>
<meta name="description" content="Javascript Bignum Extensions">
@ -10,6 +9,7 @@
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--

BIN
doc/jsbignum.pdf

Binary file not shown.

28
doc/quickjs.html

@ -1,8 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- Created by GNU Texinfo 6.5, http://www.gnu.org/software/texinfo/ -->
<!-- Created by GNU Texinfo 6.1, http://www.gnu.org/software/texinfo/ -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>QuickJS Javascript Engine</title>
<meta name="description" content="QuickJS Javascript Engine">
@ -10,6 +9,7 @@
<meta name="resource-type" content="document">
<meta name="distribution" content="global">
<meta name="Generator" content="makeinfo">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="#SEC_Contents" rel="contents" title="Table of Contents">
<style type="text/css">
<!--
@ -237,7 +237,7 @@ source is <code>import</code>.
</dd>
<dt><code>--bignum</code></dt>
<dd><p>Enable the bignum extensions: BigDecimal object, BigFloat object and
the <code>&quot;use bigint&quot;</code> and <code>&quot;use math&quot;</code> directives.
the <code>&quot;use math&quot;</code> directive.
</p>
</dd>
<dt><code>-I file</code></dt>
@ -293,6 +293,13 @@ executable file.
<dd><p>Compile as Javascript module (default=autodetect).
</p>
</dd>
<dt><code>-D module_name</code></dt>
<dd><p>Compile a dynamically loaded module and its dependencies. This option
is needed when your code uses the <code>import</code> keyword or the
<code>os.Worker</code> constructor because the compiler cannot statically
find the name of the dynamically loaded modules.
</p>
</dd>
<dt><code>-M module_name[,cname]</code></dt>
<dd><p>Add initialization code for an external C module. See the
<code>c_module</code> example.
@ -314,7 +321,7 @@ when the <code>-fno-x</code> options are used.
</dd>
<dt><code>-fbignum</code></dt>
<dd><p>Enable the bignum extensions: BigDecimal object, BigFloat object and
the <code>&quot;use bigint&quot;</code> and <code>&quot;use math&quot;</code> directives.
the <code>&quot;use math&quot;</code> directive.
</p>
</dd>
</dl>
@ -989,13 +996,14 @@ to the timer.
<code>&quot;win32&quot;</code> or <code>&quot;js&quot;</code>.
</p>
</dd>
<dt><code>Worker(source)</code></dt>
<dt><code>Worker(module_filename)</code></dt>
<dd><p>Constructor to create a new thread (worker) with an API close to the
<code>WebWorkers</code>. <code>source</code> is a string containing the module
source which is executed in the newly created thread. Threads normally
don&rsquo;t share any data and communicate between each other with
messages. Nested workers are not supported. An example is available in
<samp>tests/test_worker.js</samp>.
<code>WebWorkers</code>. <code>module_filename</code> is a string specifying the
module filename which is executed in the newly created thread. As for
dynamically imported module, it is relative to the current script or
module path. Threads normally don&rsquo;t share any data and communicate
between each other with messages. Nested workers are not supported. An
example is available in <samp>tests/test_worker.js</samp>.
</p>
<p>The worker class has the following static properties:
</p>

BIN
doc/quickjs.pdf

Binary file not shown.

23
doc/quickjs.texi

@ -120,7 +120,7 @@ Load as ES6 script (default=autodetect).
@item --bignum
Enable the bignum extensions: BigDecimal object, BigFloat object and
the @code{"use bigint"} and @code{"use math"} directives.
the @code{"use math"} directive.
@item -I file
@item --include file
@ -167,6 +167,12 @@ Set the C name of the generated data.
@item -m
Compile as Javascript module (default=autodetect).
@item -D module_name
Compile a dynamically loaded module and its dependencies. This option
is needed when your code uses the @code{import} keyword or the
@code{os.Worker} constructor because the compiler cannot statically
find the name of the dynamically loaded modules.
@item -M module_name[,cname]
Add initialization code for an external C module. See the
@code{c_module} example.
@ -184,7 +190,7 @@ Disable selected language features to produce a smaller executable file.
@item -fbignum
Enable the bignum extensions: BigDecimal object, BigFloat object and
the @code{"use bigint"} and @code{"use math"} directives.
the @code{"use math"} directive.
@end table
@ -764,13 +770,14 @@ Cancel a timer.
Return a string representing the platform: @code{"linux"}, @code{"darwin"},
@code{"win32"} or @code{"js"}.
@item Worker(source)
@item Worker(module_filename)
Constructor to create a new thread (worker) with an API close to the
@code{WebWorkers}. @code{source} is a string containing the module
source which is executed in the newly created thread. Threads normally
don't share any data and communicate between each other with
messages. Nested workers are not supported. An example is available in
@file{tests/test_worker.js}.
@code{WebWorkers}. @code{module_filename} is a string specifying the
module filename which is executed in the newly created thread. As for
dynamically imported module, it is relative to the current script or
module path. Threads normally don't share any data and communicate
between each other with messages. Nested workers are not supported. An
example is available in @file{tests/test_worker.js}.
The worker class has the following static properties:

20
libregexp.c

@ -569,7 +569,8 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
}
}
break;
case '0' ... '7':
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
c -= '0';
if (allow_utf16 == 2) {
/* only accept \0 not followed by digit */
@ -1410,7 +1411,9 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
}
}
goto normal_char;
case '1' ... '9':
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8':
case '9':
{
const uint8_t *q = ++p;
@ -1434,7 +1437,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
}
goto normal_char;
}
return re_parse_error(s, "back reference out of range in reguar expression");
return re_parse_error(s, "back reference out of range in regular expression");
}
emit_back_reference:
last_atom_start = s->byte_code.size;
@ -2533,6 +2536,17 @@ int lre_get_flags(const uint8_t *bc_buf)
return bc_buf[RE_HEADER_FLAGS];
}
/* Return NULL if no group names. Otherwise, return a pointer to
'capture_count - 1' zero terminated UTF-8 strings. */
const char *lre_get_groupnames(const uint8_t *bc_buf)
{
uint32_t re_bytecode_len;
if ((lre_get_flags(bc_buf) & LRE_FLAG_NAMED_GROUPS) == 0)
return NULL;
re_bytecode_len = get_u32(bc_buf + 3);
return (const char *)(bc_buf + 7 + re_bytecode_len);
}
#ifdef TEST
BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)

1
libregexp.h

@ -44,6 +44,7 @@ uint8_t *lre_compile(int *plen, char *error_msg, int error_msg_size,
void *opaque);
int lre_get_capture_count(const uint8_t *bc_buf);
int lre_get_flags(const uint8_t *bc_buf);
const char *lre_get_groupnames(const uint8_t *bc_buf);
int lre_exec(uint8_t **capture,
const uint8_t *bc_buf, const uint8_t *cbuf, int cindex, int clen,
int cbuf_type, void *opaque);

26
libunicode.c

@ -527,7 +527,13 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
} else {
d = unicode_decomp_data + unicode_decomp_table2[idx];
switch(type) {
case DECOMP_TYPE_L1 ... DECOMP_TYPE_L7:
case DECOMP_TYPE_L1:
case DECOMP_TYPE_L2:
case DECOMP_TYPE_L3:
case DECOMP_TYPE_L4:
case DECOMP_TYPE_L5:
case DECOMP_TYPE_L6:
case DECOMP_TYPE_L7:
l = type - DECOMP_TYPE_L1 + 1;
d += (c - code) * l * 2;
for(i = 0; i < l; i++) {
@ -535,7 +541,8 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
return 0;
}
return l;
case DECOMP_TYPE_LL1 ... DECOMP_TYPE_LL2:
case DECOMP_TYPE_LL1:
case DECOMP_TYPE_LL2:
{
uint32_t k, p;
l = type - DECOMP_TYPE_LL1 + 1;
@ -551,7 +558,11 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
}
}
return l;
case DECOMP_TYPE_S1 ... DECOMP_TYPE_S5:
case DECOMP_TYPE_S1:
case DECOMP_TYPE_S2:
case DECOMP_TYPE_S3:
case DECOMP_TYPE_S4:
case DECOMP_TYPE_S5:
l = type - DECOMP_TYPE_S1 + 1;
d += (c - code) * l;
for(i = 0; i < l; i++) {
@ -582,7 +593,14 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
case DECOMP_TYPE_B18:
l = 18;
goto decomp_type_b;
case DECOMP_TYPE_B1 ... DECOMP_TYPE_B8:
case DECOMP_TYPE_B1:
case DECOMP_TYPE_B2:
case DECOMP_TYPE_B3:
case DECOMP_TYPE_B4:
case DECOMP_TYPE_B5:
case DECOMP_TYPE_B6:
case DECOMP_TYPE_B7:
case DECOMP_TYPE_B8:
l = type - DECOMP_TYPE_B1 + 1;
decomp_type_b:
{

43
qjs.c

@ -46,6 +46,7 @@ extern const uint32_t qjsc_repl_size;
#ifdef CONFIG_BIGNUM
extern const uint8_t qjsc_qjscalc[];
extern const uint32_t qjsc_qjscalc_size;
static int bignum_ext;
#endif
static int eval_buf(JSContext *ctx, const void *buf, int buf_len,
@ -101,6 +102,27 @@ static int eval_file(JSContext *ctx, const char *filename, int module)
return ret;
}
/* also used to initialize the worker context */
static JSContext *JS_NewCustomContext(JSRuntime *rt)
{
JSContext *ctx;
ctx = JS_NewContext(rt);
if (!ctx)
return NULL;
#ifdef CONFIG_BIGNUM
if (bignum_ext) {
JS_AddIntrinsicBigFloat(ctx);
JS_AddIntrinsicBigDecimal(ctx);
JS_AddIntrinsicOperators(ctx);
JS_EnableBignumExt(ctx, TRUE);
}
#endif
/* system modules */
js_init_module_std(ctx, "std");
js_init_module_os(ctx, "os");
return ctx;
}
#if defined(__APPLE__)
#define MALLOC_OVERHEAD 0
#else
@ -294,7 +316,7 @@ int main(int argc, char **argv)
char *include_list[32];
int i, include_count = 0;
#ifdef CONFIG_BIGNUM
int load_jscalc, bignum_ext = 0;
int load_jscalc;
#endif
size_t stack_size = 0;
@ -426,6 +448,9 @@ int main(int argc, char **argv)
}
}
if (load_jscalc)
bignum_ext = 1;
if (trace_memory) {
js_trace_malloc_init(&trace_data);
rt = JS_NewRuntime2(&trace_mf, &trace_data);
@ -440,22 +465,14 @@ int main(int argc, char **argv)
JS_SetMemoryLimit(rt, memory_limit);
if (stack_size != 0)
JS_SetMaxStackSize(rt, stack_size);
js_std_set_worker_new_context_func(JS_NewCustomContext);
js_std_init_handlers(rt);
ctx = JS_NewContext(rt);
ctx = JS_NewCustomContext(rt);
if (!ctx) {
fprintf(stderr, "qjs: cannot allocate JS context\n");
exit(2);
}
#ifdef CONFIG_BIGNUM
if (bignum_ext || load_jscalc) {
JS_AddIntrinsicBigFloat(ctx);
JS_AddIntrinsicBigDecimal(ctx);
JS_AddIntrinsicOperators(ctx);
JS_EnableBignumExt(ctx, TRUE);
}
#endif
/* loader for ES6 modules */
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
@ -472,10 +489,6 @@ int main(int argc, char **argv)
#endif
js_std_add_helpers(ctx, argc - optind, argv + optind);
/* system modules */
js_init_module_std(ctx, "std");
js_init_module_os(ctx, "os");
/* make 'std' and 'os' visible to non module code */
if (load_std) {
const char *str = "import * as std from 'std';\n"

74
qjsc.c

@ -326,6 +326,7 @@ static const char main_c_template1[] =
" JSRuntime *rt;\n"
" JSContext *ctx;\n"
" rt = JS_NewRuntime();\n"
" js_std_set_worker_new_context_func(JS_NewCustomContext);\n"
" js_std_init_handlers(rt);\n"
;
@ -349,6 +350,7 @@ void help(void)
"-o output set the output filename\n"
"-N cname set the C name of the generated data\n"
"-m compile as Javascript module (default=autodetect)\n"
"-D module_name compile a dynamically loaded module or worker\n"
"-M module_name[,cname] add initialization code for an external C module\n"
"-x byte swapped output\n"
"-p prefix set the prefix of the generated C names\n"
@ -494,6 +496,7 @@ int main(int argc, char **argv)
#ifdef CONFIG_BIGNUM
BOOL bignum_ext = FALSE;
#endif
namelist_t dynamic_module_list;
out_filename = NULL;
output_type = OUTPUT_EXECUTABLE;
@ -504,13 +507,14 @@ int main(int argc, char **argv)
verbose = 0;
use_lto = FALSE;
stack_size = 0;
memset(&dynamic_module_list, 0, sizeof(dynamic_module_list));
/* add system modules */
namelist_add(&cmodule_list, "std", "std", 0);
namelist_add(&cmodule_list, "os", "os", 0);
for(;;) {
c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:");
c = getopt(argc, argv, "ho:cN:f:mxevM:p:S:D:");
if (c == -1)
break;
switch(c) {
@ -576,6 +580,9 @@ int main(int argc, char **argv)
namelist_add(&cmodule_list, path, cname, 0);
}
break;
case 'D':
namelist_add(&dynamic_module_list, optarg, NULL, 0);
break;
case 'x':
byte_swap = TRUE;
break;
@ -656,22 +663,22 @@ int main(int argc, char **argv)
cname = NULL;
}
if (output_type != OUTPUT_C) {
fputs(main_c_template1, fo);
fprintf(fo, " ctx = JS_NewContextRaw(rt);\n");
if (stack_size != 0) {
fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
(unsigned int)stack_size);
}
/* add the module loader if necessary */
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
for(i = 0; i < dynamic_module_list.count; i++) {
if (!jsc_module_loader(ctx, dynamic_module_list.array[i].name, NULL)) {
fprintf(stderr, "Could not load dynamic module '%s'\n",
dynamic_module_list.array[i].name);
exit(1);
}
}
if (output_type != OUTPUT_C) {
fprintf(fo,
"static JSContext *JS_NewCustomContext(JSRuntime *rt)\n"
"{\n"
" JSContext *ctx = JS_NewContextRaw(rt);\n"
" if (!ctx)\n"
" return NULL;\n");
/* add the basic objects */
fprintf(fo, " JS_AddIntrinsicBaseObjects(ctx);\n");
for(i = 0; i < countof(feature_list); i++) {
if ((feature_bitmap & ((uint64_t)1 << i)) &&
@ -689,8 +696,8 @@ int main(int argc, char **argv)
" JS_EnableBignumExt(ctx, 1);\n");
}
#endif
fprintf(fo, " js_std_add_helpers(ctx, argc, argv);\n");
/* add the precompiled modules (XXX: could modify the module
loader instead) */
for(i = 0; i < init_module_list.count; i++) {
namelist_entry_t *e = &init_module_list.array[i];
/* initialize the static C modules */
@ -702,12 +709,39 @@ int main(int argc, char **argv)
" }\n",
e->short_name, e->short_name, e->name);
}
for(i = 0; i < cname_list.count; i++) {
namelist_entry_t *e = &cname_list.array[i];
if (e->flags) {
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 1);\n",
e->name, e->name);
}
}
fprintf(fo,
" return ctx;\n"
"}\n\n");
fputs(main_c_template1, fo);
if (stack_size != 0) {
fprintf(fo, " JS_SetMaxStackSize(rt, %u);\n",
(unsigned int)stack_size);
}
/* add the module loader if necessary */
if (feature_bitmap & (1 << FE_MODULE_LOADER)) {
fprintf(fo, " JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);\n");
}
fprintf(fo,
" ctx = JS_NewCustomContext(rt);\n"
" js_std_add_helpers(ctx, argc, argv);\n");
for(i = 0; i < cname_list.count; i++) {
namelist_entry_t *e = &cname_list.array[i];
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, %s);\n",
e->name, e->name,
e->flags ? "1" : "0");
if (!e->flags) {
fprintf(fo, " js_std_eval_binary(ctx, %s, %s_size, 0);\n",
e->name, e->name);
}
}
fputs(main_c_template2, fo);
}

4
qjscalc.js

@ -1826,7 +1826,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
j = emin + i;
if (j == -1) {
if (a[i] != 0)
throw RangError("cannot represent integ(1/X)");
throw RangeError("cannot represent integ(1/X)");
} else {
r[i] = a[i] / (j + 1);
}
@ -1853,7 +1853,7 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
log() {
var a = this, r;
if (a.emin != 0)
throw Range("log argument must have a non zero constant term");
throw RangeError("log argument must have a non zero constant term");
r = integ(deriv(a) / a);
/* add the constant term */
r += global.log(a[0]);

100
quickjs-libc.c

@ -2993,9 +2993,8 @@ typedef struct {
} JSWorkerData;
typedef struct {
/* source code of the worker */
char *eval_buf;
size_t eval_buf_len;
char *filename; /* module filename */
char *basename; /* module base name */
JSWorkerMessagePipe *recv_pipe, *send_pipe;
} WorkerFuncArgs;
@ -3005,6 +3004,7 @@ typedef struct {
} JSSABHeader;
static JSClassID js_worker_class_id;
static JSContext *(*js_worker_new_context_func)(JSRuntime *rt);
static int atomic_add_int(int *ptr, int v)
{
@ -3136,7 +3136,6 @@ static void *worker_func(void *opaque)
JSRuntime *rt;
JSThreadState *ts;
JSContext *ctx;
JSValue retval;
rt = JS_NewRuntime();
if (rt == NULL) {
@ -3145,12 +3144,16 @@ static void *worker_func(void *opaque)
}
js_std_init_handlers(rt);
JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);
/* set the pipe to communicate with the parent */
ts = JS_GetRuntimeOpaque(rt);
ts->recv_pipe = args->recv_pipe;
ts->send_pipe = args->send_pipe;
ctx = JS_NewContext(rt);
/* function pointer to avoid linking the whole JS_NewContext() if
not needed */
ctx = js_worker_new_context_func(rt);
if (ctx == NULL) {
fprintf(stderr, "JS_NewContext failure");
}
@ -3159,18 +3162,11 @@ static void *worker_func(void *opaque)
js_std_add_helpers(ctx, -1, NULL);
/* system modules */
js_init_module_std(ctx, "std");
js_init_module_os(ctx, "os");
retval = JS_Eval(ctx, args->eval_buf, args->eval_buf_len,
"<worker>", JS_EVAL_TYPE_MODULE);
free(args->eval_buf);
free(args);
if (JS_IsException(retval))
if (!JS_RunModule(ctx, args->basename, args->filename))
js_std_dump_error(ctx);
JS_FreeValue(ctx, retval);
free(args->filename);
free(args->basename);
free(args);
js_std_loop(ctx);
@ -3216,52 +3212,53 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSRuntime *rt = JS_GetRuntime(ctx);
WorkerFuncArgs *args;
const char *str;
size_t str_len;
WorkerFuncArgs *args = NULL;
pthread_t tid;
pthread_attr_t attr;
JSValue obj = JS_UNDEFINED;
int ret;
const char *filename = NULL, *basename;
JSAtom basename_atom;
/* XXX: in order to avoid problems with resource liberation, we
don't support creating workers inside workers */
if (!is_main_thread(rt))
return JS_ThrowTypeError(ctx, "cannot create a worker inside a worker");
/* base name, assuming the calling function is a normal JS
function */
basename_atom = JS_GetScriptOrModuleName(ctx, 1);
if (basename_atom == JS_ATOM_NULL) {
return JS_ThrowTypeError(ctx, "could not determine calling script or module name");
}
basename = JS_AtomToCString(ctx, basename_atom);
JS_FreeAtom(ctx, basename_atom);
if (!basename)
goto fail;
/* script source */
str = JS_ToCStringLen(ctx, &str_len, argv[0]);
if (!str)
return JS_EXCEPTION;
/* module name */
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
goto fail;
args = malloc(sizeof(*args));
if (!args) {
JS_ThrowOutOfMemory(ctx);
goto fail;
}
if (!args)
goto oom_fail;
memset(args, 0, sizeof(*args));
args->eval_buf = malloc(str_len + 1);
if (!args->eval_buf) {
JS_ThrowOutOfMemory(ctx);
goto fail;
}
memcpy(args->eval_buf, str, str_len + 1);
args->eval_buf_len = str_len;
JS_FreeCString(ctx, str);
str = NULL;
args->filename = strdup(filename);
args->basename = strdup(basename);
/* ports */
args->recv_pipe = js_new_message_pipe();
if (!args->recv_pipe)
goto fail;
goto oom_fail;
args->send_pipe = js_new_message_pipe();
if (!args->send_pipe)
goto fail;
goto oom_fail;
obj = js_worker_ctor_internal(ctx, new_target,
args->send_pipe, args->recv_pipe);
if (JS_IsUndefined(obj))
if (JS_IsException(obj))
goto fail;
pthread_attr_init(&attr);
@ -3273,11 +3270,17 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target,
JS_ThrowTypeError(ctx, "could not create worker");
goto fail;
}
JS_FreeCString(ctx, basename);
JS_FreeCString(ctx, filename);
return obj;
oom_fail:
JS_ThrowOutOfMemory(ctx);
fail:
JS_FreeCString(ctx, str);
JS_FreeCString(ctx, basename);
JS_FreeCString(ctx, filename);
if (args) {
free(args->eval_buf);
free(args->filename);
free(args->basename);
js_free_message_pipe(args->recv_pipe);
js_free_message_pipe(args->send_pipe);
free(args);
@ -3417,6 +3420,13 @@ static const JSCFunctionListEntry js_worker_proto_funcs[] = {
#endif /* USE_WORKER */
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt))
{
#ifdef USE_WORKER
js_worker_new_context_func = func;
#endif
}
#if defined(_WIN32)
#define OS_PLATFORM "win32"
#elif defined(__APPLE__)
@ -3668,6 +3678,12 @@ void js_std_free_handlers(JSRuntime *rt)
free_timer(rt, th);
}
#ifdef USE_WORKER
/* XXX: free port_list ? */
js_free_message_pipe(ts->recv_pipe);
js_free_message_pipe(ts->send_pipe);
#endif
free(ts);
JS_SetRuntimeOpaque(rt, NULL); /* fail safe */
}

3
quickjs-libc.h

@ -50,7 +50,8 @@ void js_std_eval_binary(JSContext *ctx, const uint8_t *buf, size_t buf_len,
void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
JSValueConst reason,
JS_BOOL is_handled, void *opaque);
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
#ifdef __cplusplus
} /* extern "C" { */
#endif

3
quickjs-opcode.h

@ -359,7 +359,8 @@ DEF( call3, 1, 1, 1, npopx)
DEF( is_undefined, 1, 1, 1, none)
DEF( is_null, 1, 1, 1, none)
DEF( is_function, 1, 1, 1, none)
DEF(typeof_is_undefined, 1, 1, 1, none)
DEF( typeof_is_function, 1, 1, 1, none)
#endif
#undef DEF

884
quickjs.c

File diff suppressed because it is too large Load Diff

10
quickjs.h

@ -412,6 +412,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
/* atom support */
#define JS_ATOM_NULL 0
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len);
JSAtom JS_NewAtom(JSContext *ctx, const char *str);
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n);
@ -835,6 +837,8 @@ typedef int JSInterruptHandler(JSRuntime *rt, void *opaque);
void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque);
/* if can_block is TRUE, Atomics.wait() can be used */
void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block);
/* set the [IsHTMLDDA] internal slot */
void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj);
typedef struct JSModuleDef JSModuleDef;
@ -886,6 +890,12 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
returns a module. */
int JS_ResolveModule(JSContext *ctx, JSValueConst obj);
/* only exported for os.Worker() */
JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels);
/* only exported for os.Worker() */
JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename,
const char *filename);
/* C function definition */
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
JS_CFUNC_generic,

11
run-test262.c

@ -743,10 +743,16 @@ static JSValue js_createRealm(JSContext *ctx, JSValue this_val,
return ret;
}
static JSValue js_IsHTMLDDA(JSContext *ctx, JSValue this_val,
int argc, JSValue *argv)
{
return JS_NULL;
}
static JSValue add_helpers1(JSContext *ctx)
{
JSValue global_obj;
JSValue obj262;
JSValue obj262, obj;
global_obj = JS_GetGlobalObject(ctx);
@ -773,6 +779,9 @@ static JSValue add_helpers1(JSContext *ctx)
JS_SetPropertyStr(ctx, obj262, "createRealm",
JS_NewCFunction(ctx, js_createRealm,
"createRealm", 0));
obj = JS_NewCFunction(ctx, js_IsHTMLDDA, "IsHTMLDDA", 0);
JS_SetIsHTMLDDA(ctx, obj);
JS_SetPropertyStr(ctx, obj262, "IsHTMLDDA", obj);
JS_SetPropertyStr(ctx, global_obj, "$262", JS_DupValue(ctx, obj262));

5
test262.conf

@ -68,6 +68,7 @@ class-methods-private
class-static-fields-public
class-static-fields-private
class-static-methods-private
cleanupSome=skip
coalesce-expression
computed-property-names
const
@ -100,10 +101,10 @@ host-gc-required=skip
import.meta
Int32Array
Int8Array
IsHTMLDDA=skip
IsHTMLDDA
json-superset
let
logical-assignment-operators=skip
logical-assignment-operators
Map
new.target
numeric-separator-literal

2
tests/test_builtin.js

@ -277,6 +277,8 @@ function test_string()
assert("aaaa".split("aaaaa", 1), [ "aaaa" ]);
assert(eval('"\0"'), "\0");
assert("abc".padStart(Infinity, ""), "abc");
}
function test_math()

19
tests/test_language.js

@ -359,6 +359,23 @@ function test_labels()
while (0) x: { break x; };
}
function test_destructuring()
{
function * g () { return 0; };
var [x] = g();
assert(x, void 0);
}
function test_spread()
{
var x;
x = [1, 2, ...[3, 4]];
assert(x.toString(), "1,2,3,4");
x = [ ...[ , ] ];
assert(Object.getOwnPropertyNames(x).toString(), "0,length");
}
test_op1();
test_cvt();
test_eq();
@ -373,3 +390,5 @@ test_template_skip();
test_object_literal();
test_regexp_skip();
test_labels();
test_destructuring();
test_spread();

33
tests/test_worker.js

@ -25,38 +25,7 @@ function test_worker()
{
var counter;
/* Note: can use std.loadFile() to read from a file */
worker = new os.Worker(`
import * as std from "std";
import * as os from "os";
var parent = os.Worker.parent;
function handle_msg(e) {
var ev = e.data;
// print("child_recv", JSON.stringify(ev));
switch(ev.type) {
case "abort":
parent.postMessage({ type: "done" });
break;
case "sab":
/* modify the SharedArrayBuffer */
ev.buf[2] = 10;
parent.postMessage({ type: "sab_done", buf: ev.buf });
break;
}
}
function worker_main() {
var i;
parent.onmessage = handle_msg;
for(i = 0; i < 10; i++) {
parent.postMessage({ type: "num", num: i });
}
}
worker_main();
`);
worker = new os.Worker("./test_worker_module.js");
counter = 0;
worker.onmessage = function (e) {

31
tests/test_worker_module.js

@ -0,0 +1,31 @@
/* Worker code for test_worker.js */
import * as std from "std";
import * as os from "os";
var parent = os.Worker.parent;
function handle_msg(e) {
var ev = e.data;
// print("child_recv", JSON.stringify(ev));
switch(ev.type) {
case "abort":
parent.postMessage({ type: "done" });
break;
case "sab":
/* modify the SharedArrayBuffer */
ev.buf[2] = 10;
parent.postMessage({ type: "sab_done", buf: ev.buf });
break;
}
}
function worker_main() {
var i;
parent.onmessage = handle_msg;
for(i = 0; i < 10; i++) {
parent.postMessage({ type: "num", num: i });
}
}
worker_main();
Loading…
Cancel
Save