mirror of
https://github.com/bellard/quickjs.git
synced 2024-12-12 09:44:33 +08:00
2020-09-06 release
This commit is contained in:
parent
8900766099
commit
7c312df422
@ -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
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
|
||||
|
21
cutils.c
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:
|
||||
|
@ -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
BIN
doc/jsbignum.pdf
Binary file not shown.
@ -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>"use bigint"</code> and <code>"use math"</code> directives.
|
||||
the <code>"use math"</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>"use bigint"</code> and <code>"use math"</code> directives.
|
||||
the <code>"use math"</code> directive.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
@ -989,13 +996,14 @@ to the timer.
|
||||
<code>"win32"</code> or <code>"js"</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’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’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
BIN
doc/quickjs.pdf
Binary file not shown.
@ -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
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)
|
||||
|
@ -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
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
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
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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
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 */
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
10
quickjs.h
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,
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
|
@ -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
Normal file
31
tests/test_worker_module.js
Normal 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();
|
Loading…
Reference in New Issue
Block a user