2020-09-06 release

This commit is contained in:
bellard 2020-09-06 19:10:15 +02:00
parent 8900766099
commit 7c312df422
26 changed files with 912 additions and 476 deletions

View file

@ -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: 2020-07-05:
- modified JS_GetPrototype() to return a live value - modified JS_GetPrototype() to return a live value

4
TODO
View file

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

View file

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

View file

@ -258,19 +258,30 @@ int unicode_from_utf8(const uint8_t *p, int max_len, const uint8_t **pp)
return c; return c;
} }
switch(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; l = 1;
break; 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; l = 2;
break; break;
case 0xf0 ... 0xf7: case 0xf0: case 0xf1: case 0xf2: case 0xf3:
case 0xf4: case 0xf5: case 0xf6: case 0xf7:
l = 3; l = 3;
break; break;
case 0xf8 ... 0xfb: case 0xf8: case 0xf9: case 0xfa: case 0xfb:
l = 4; l = 4;
break; break;
case 0xfc ... 0xfd: case 0xfc: case 0xfd:
l = 5; l = 5;
break; break;
default: default:

View file

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

Binary file not shown.

View file

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

Binary file not shown.

View file

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

View file

@ -569,7 +569,8 @@ int lre_parse_escape(const uint8_t **pp, int allow_utf16)
} }
} }
break; break;
case '0' ... '7': case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
c -= '0'; c -= '0';
if (allow_utf16 == 2) { if (allow_utf16 == 2) {
/* only accept \0 not followed by digit */ /* 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; 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; const uint8_t *q = ++p;
@ -1434,7 +1437,7 @@ static int re_parse_term(REParseState *s, BOOL is_backward_dir)
} }
goto normal_char; 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: emit_back_reference:
last_atom_start = s->byte_code.size; 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 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 #ifdef TEST
BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size) BOOL lre_check_stack_overflow(void *opaque, size_t alloca_size)

View file

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

View file

@ -527,7 +527,13 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
} else { } else {
d = unicode_decomp_data + unicode_decomp_table2[idx]; d = unicode_decomp_data + unicode_decomp_table2[idx];
switch(type) { 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; l = type - DECOMP_TYPE_L1 + 1;
d += (c - code) * l * 2; d += (c - code) * l * 2;
for(i = 0; i < l; i++) { for(i = 0; i < l; i++) {
@ -535,7 +541,8 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
return 0; return 0;
} }
return l; return l;
case DECOMP_TYPE_LL1 ... DECOMP_TYPE_LL2: case DECOMP_TYPE_LL1:
case DECOMP_TYPE_LL2:
{ {
uint32_t k, p; uint32_t k, p;
l = type - DECOMP_TYPE_LL1 + 1; l = type - DECOMP_TYPE_LL1 + 1;
@ -551,7 +558,11 @@ static int unicode_decomp_entry(uint32_t *res, uint32_t c,
} }
} }
return l; 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; l = type - DECOMP_TYPE_S1 + 1;
d += (c - code) * l; d += (c - code) * l;
for(i = 0; i < l; i++) { 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: case DECOMP_TYPE_B18:
l = 18; l = 18;
goto decomp_type_b; 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; l = type - DECOMP_TYPE_B1 + 1;
decomp_type_b: decomp_type_b:
{ {

43
qjs.c
View file

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

74
qjsc.c
View file

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

View file

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

View file

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

View file

@ -50,6 +50,7 @@ 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, void js_std_promise_rejection_tracker(JSContext *ctx, JSValueConst promise,
JSValueConst reason, JSValueConst reason,
JS_BOOL is_handled, void *opaque); JS_BOOL is_handled, void *opaque);
void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt));
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" { */ } /* extern "C" { */

View file

@ -359,7 +359,8 @@ DEF( call3, 1, 1, 1, npopx)
DEF( is_undefined, 1, 1, 1, none) DEF( is_undefined, 1, 1, 1, none)
DEF( is_null, 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 #endif
#undef DEF #undef DEF

910
quickjs.c

File diff suppressed because it is too large Load diff

View file

@ -412,6 +412,8 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s);
void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt); void JS_DumpMemoryUsage(FILE *fp, const JSMemoryUsage *s, JSRuntime *rt);
/* atom support */ /* atom support */
#define JS_ATOM_NULL 0
JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len); JSAtom JS_NewAtomLen(JSContext *ctx, const char *str, size_t len);
JSAtom JS_NewAtom(JSContext *ctx, const char *str); JSAtom JS_NewAtom(JSContext *ctx, const char *str);
JSAtom JS_NewAtomUInt32(JSContext *ctx, uint32_t n); 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); void JS_SetInterruptHandler(JSRuntime *rt, JSInterruptHandler *cb, void *opaque);
/* if can_block is TRUE, Atomics.wait() can be used */ /* if can_block is TRUE, Atomics.wait() can be used */
void JS_SetCanBlock(JSRuntime *rt, JS_BOOL can_block); 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; typedef struct JSModuleDef JSModuleDef;
@ -886,6 +890,12 @@ JSValue JS_ReadObject(JSContext *ctx, const uint8_t *buf, size_t buf_len,
returns a module. */ returns a module. */
int JS_ResolveModule(JSContext *ctx, JSValueConst obj); 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 */ /* C function definition */
typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */ typedef enum JSCFunctionEnum { /* XXX: should rename for namespace isolation */
JS_CFUNC_generic, JS_CFUNC_generic,

View file

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

View file

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

View file

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

View file

@ -359,6 +359,23 @@ function test_labels()
while (0) x: { break x; }; 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_op1();
test_cvt(); test_cvt();
test_eq(); test_eq();
@ -373,3 +390,5 @@ test_template_skip();
test_object_literal(); test_object_literal();
test_regexp_skip(); test_regexp_skip();
test_labels(); test_labels();
test_destructuring();
test_spread();

View file

@ -25,38 +25,7 @@ function test_worker()
{ {
var counter; var counter;
/* Note: can use std.loadFile() to read from a file */ worker = new os.Worker("./test_worker_module.js");
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();
`);
counter = 0; counter = 0;
worker.onmessage = function (e) { worker.onmessage = function (e) {

View file

@ -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();