diff --git a/Changelog b/Changelog
index 0c25b96..c09af91 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,10 @@
+2021-03-27:
+
+- faster Array.prototype.push and Array.prototype.unshift
+- added JS_UpdateStackTop()
+- fixed Windows console
+- misc bug fixes
+
2020-11-08:
- improved function parameter initializers
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..2c8fdeb
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+QuickJS Javascript Engine
+
+Copyright (c) 2017-2021 Fabrice Bellard
+Copyright (c) 2017-2021 Charlie Gordon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/Makefile b/Makefile
index e6ae827..49b1f6f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
#
# QuickJS Javascript Engine
#
-# Copyright (c) 2017-2020 Fabrice Bellard
-# Copyright (c) 2017-2020 Charlie Gordon
+# Copyright (c) 2017-2021 Fabrice Bellard
+# Copyright (c) 2017-2021 Charlie Gordon
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -179,6 +179,7 @@ LIBS=-lm
ifndef CONFIG_WIN32
LIBS+=-ldl -lpthread
endif
+LIBS+=$(EXTRA_LIBS)
$(OBJDIR):
mkdir -p $(OBJDIR) $(OBJDIR)/examples $(OBJDIR)/tests
diff --git a/TODO b/TODO
index b5500c9..2a3b3c3 100644
--- a/TODO
+++ b/TODO
@@ -66,5 +66,5 @@ Optimization ideas:
Test262o: 0/11262 errors, 463 excluded
Test262o commit: 7da91bceb9ce7613f87db47ddd1292a2dda58b42 (es5-tests branch)
-Result: 51/75119 errors, 899 excluded, 570 skipped
-Test262 commit: 1c33fdb0ca60fb9d7392403be769ed0d26209132
+Result: 35/75280 errors, 909 excluded, 585 skipped
+Test262 commit: 31126581e7290f9233c29cefd93f66c6ac78f1c9
diff --git a/VERSION b/VERSION
index 78749b0..22ffec1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2020-11-08
+2021-03-27
diff --git a/doc/quickjs.html b/doc/quickjs.html
index bb5211a..cd07ed7 100644
--- a/doc/quickjs.html
+++ b/doc/quickjs.html
@@ -1136,10 +1136,11 @@
3.4.6 JS Classes
JS_GetOpaque()
/JS_SetOpaque()
.
When defining a new JS class, it is possible to declare a finalizer
-which is called when the object is destroyed. A gc_mark
method
-can be provided so that the cycle removal algorithm can find the other
-objects referenced by this object. Other methods are available to
-define exotic object behaviors.
+which is called when the object is destroyed. The finalizer should be
+used to release C resources. It is invalid to execute JS code from
+it. A gc_mark
method can be provided so that the cycle removal
+algorithm can find the other objects referenced by this object. Other
+methods are available to define exotic object behaviors.
The Class ID are globally allocated (i.e. for all runtimes). The
JSClass are allocated per JSRuntime
. JS_SetClassProto()
diff --git a/doc/quickjs.pdf b/doc/quickjs.pdf
index fbcd97c..53c8e73 100644
Binary files a/doc/quickjs.pdf and b/doc/quickjs.pdf differ
diff --git a/doc/quickjs.texi b/doc/quickjs.texi
index 40c0bb5..9eb6354 100644
--- a/doc/quickjs.texi
+++ b/doc/quickjs.texi
@@ -896,10 +896,11 @@ set the C opaque point with
@code{JS_GetOpaque()}/@code{JS_SetOpaque()}.
When defining a new JS class, it is possible to declare a finalizer
-which is called when the object is destroyed. A @code{gc_mark} method
-can be provided so that the cycle removal algorithm can find the other
-objects referenced by this object. Other methods are available to
-define exotic object behaviors.
+which is called when the object is destroyed. The finalizer should be
+used to release C resources. It is invalid to execute JS code from
+it. A @code{gc_mark} method can be provided so that the cycle removal
+algorithm can find the other objects referenced by this object. Other
+methods are available to define exotic object behaviors.
The Class ID are globally allocated (i.e. for all runtimes). The
JSClass are allocated per @code{JSRuntime}. @code{JS_SetClassProto()}
diff --git a/libbf.c b/libbf.c
index 3bf257a..fe1628e 100644
--- a/libbf.c
+++ b/libbf.c
@@ -1,7 +1,7 @@
/*
* Tiny arbitrary precision floating point library
*
- * Copyright (c) 2017-2020 Fabrice Bellard
+ * Copyright (c) 2017-2021 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/libbf.h b/libbf.h
index 4576bf8..48e9d95 100644
--- a/libbf.h
+++ b/libbf.h
@@ -1,7 +1,7 @@
/*
* Tiny arbitrary precision floating point library
*
- * Copyright (c) 2017-2020 Fabrice Bellard
+ * Copyright (c) 2017-2021 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/qjs.c b/qjs.c
index 4dd11f8..d56b843 100644
--- a/qjs.c
+++ b/qjs.c
@@ -1,8 +1,8 @@
/*
* QuickJS stand alone interpreter
*
- * Copyright (c) 2017-2020 Fabrice Bellard
- * Copyright (c) 2017-2020 Charlie Gordon
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -156,7 +156,13 @@ static inline size_t js_trace_malloc_usable_size(void *ptr)
#endif
}
-static void __attribute__((format(printf, 2, 3)))
+static void
+#ifdef _WIN32
+/* mingw printf is used */
+__attribute__((format(gnu_printf, 2, 3)))
+#else
+__attribute__((format(printf, 2, 3)))
+#endif
js_trace_malloc_printf(JSMallocState *s, const char *fmt, ...)
{
va_list ap;
diff --git a/qjsc.c b/qjsc.c
index f5bda57..b9f1e4c 100644
--- a/qjsc.c
+++ b/qjsc.c
@@ -1,7 +1,7 @@
/*
* QuickJS command line compiler
*
- * Copyright (c) 2018-2020 Fabrice Bellard
+ * Copyright (c) 2018-2021 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/qjscalc.js b/qjscalc.js
index b7c5001..b1ad1e8 100644
--- a/qjscalc.js
+++ b/qjscalc.js
@@ -2299,8 +2299,13 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
function array_div(a, b) {
return array_mul(a, b.inverse());
}
- function array_scalar_div(a, b) {
- return a * b.inverse();
+ function array_element_wise_inverse(a) {
+ var r, i, n;
+ n = a.length;
+ r = [];
+ for(i = 0; i < n; i++)
+ r[i] = a[i].inverse();
+ return r;
}
function array_eq(a, b) {
var n, i;
@@ -2337,14 +2342,14 @@ var Integer, Float, Fraction, Complex, Mod, Polynomial, PolyMod, RationalFunctio
right: [Number, BigInt, Float, Fraction, Complex, Mod,
Polynomial, PolyMod, RationalFunction, Series],
"*": array_scalar_mul,
- "/": array_scalar_div,
+ "/"(a, b) { return a * b.inverse(); },
"**": generic_pow, /* XXX: only for integer */
},
{
left: [Number, BigInt, Float, Fraction, Complex, Mod,
Polynomial, PolyMod, RationalFunction, Series],
"*"(a, b) { return array_scalar_mul(b, a); },
- "/"(a, b) { return array_scalar_div(b, a); },
+ "/"(a, b) { return a * array_element_wise_inverse(b); },
});
add_props(Array.prototype, {
diff --git a/quickjs-libc.c b/quickjs-libc.c
index e8b81e9..e180dd0 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -1,8 +1,8 @@
/*
* QuickJS C library
*
- * Copyright (c) 2017-2020 Fabrice Bellard
- * Copyright (c) 2017-2020 Charlie Gordon
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -1663,7 +1663,7 @@ static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,
int fd;
if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION;
- return JS_NewBool(ctx, isatty(fd) == 1);
+ return JS_NewBool(ctx, (isatty(fd) != 0));
}
#if defined(_WIN32)
@@ -1689,6 +1689,10 @@ static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
return obj;
}
+/* Windows 10 built-in VT100 emulation */
+#define __ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#define __ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
+
static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -1698,8 +1702,12 @@ static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
if (JS_ToInt32(ctx, &fd, argv[0]))
return JS_EXCEPTION;
handle = (HANDLE)_get_osfhandle(fd);
-
- SetConsoleMode(handle, ENABLE_WINDOW_INPUT);
+ SetConsoleMode(handle, ENABLE_WINDOW_INPUT | __ENABLE_VIRTUAL_TERMINAL_INPUT);
+ _setmode(fd, _O_BINARY);
+ if (fd == 0) {
+ handle = (HANDLE)_get_osfhandle(1); /* corresponding output */
+ SetConsoleMode(handle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | __ENABLE_VIRTUAL_TERMINAL_PROCESSING);
+ }
return JS_UNDEFINED;
}
#else
@@ -1772,7 +1780,19 @@ static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,
filename = JS_ToCString(ctx, argv[0]);
if (!filename)
return JS_EXCEPTION;
- ret = js_get_errno(remove(filename));
+#if defined(_WIN32)
+ {
+ struct stat st;
+ if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode)) {
+ ret = rmdir(filename);
+ } else {
+ ret = unlink(filename);
+ }
+ }
+#else
+ ret = remove(filename);
+#endif
+ ret = js_get_errno(ret);
JS_FreeCString(ctx, filename);
return JS_NewInt32(ctx, ret);
}
@@ -2588,7 +2608,47 @@ static JSValue js_os_utimes(JSContext *ctx, JSValueConst this_val,
return JS_NewInt32(ctx, ret);
}
-#if !defined(_WIN32)
+/* sleep(delay_ms) */
+static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ int64_t delay;
+ int ret;
+
+ if (JS_ToInt64(ctx, &delay, argv[0]))
+ return JS_EXCEPTION;
+ if (delay < 0)
+ delay = 0;
+#if defined(_WIN32)
+ {
+ if (delay > INT32_MAX)
+ delay = INT32_MAX;
+ Sleep(delay);
+ ret = 0;
+ }
+#else
+ {
+ struct timespec ts;
+
+ ts.tv_sec = delay / 1000;
+ ts.tv_nsec = (delay % 1000) * 1000000;
+ ret = js_get_errno(nanosleep(&ts, NULL));
+ }
+#endif
+ return JS_NewInt32(ctx, ret);
+}
+
+#if defined(_WIN32)
+static char *realpath(const char *path, char *buf)
+{
+ if (!_fullpath(buf, path, PATH_MAX)) {
+ errno = ENOENT;
+ return NULL;
+ } else {
+ return buf;
+ }
+}
+#endif
/* return [path, errorcode] */
static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
@@ -2612,6 +2672,7 @@ static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
return make_string_error(ctx, buf, err);
}
+#if !defined(_WIN32)
static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -3031,22 +3092,6 @@ static JSValue js_os_kill(JSContext *ctx, JSValueConst this_val,
return JS_NewInt32(ctx, ret);
}
-/* sleep(delay_ms) */
-static JSValue js_os_sleep(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- int64_t delay;
- struct timespec ts;
- int ret;
-
- if (JS_ToInt64(ctx, &delay, argv[0]))
- return JS_EXCEPTION;
- ts.tv_sec = delay / 1000;
- ts.tv_nsec = (delay % 1000) * 1000000;
- ret = js_get_errno(nanosleep(&ts, NULL));
- return JS_NewInt32(ctx, ret);
-}
-
/* dup(fd) */
static JSValue js_os_dup(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -3598,9 +3643,10 @@ static const JSCFunctionListEntry js_os_funcs[] = {
#endif
JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
JS_CFUNC_DEF("utimes", 3, js_os_utimes ),
+ JS_CFUNC_DEF("sleep", 1, js_os_sleep ),
+ JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
#if !defined(_WIN32)
JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
- JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
JS_CFUNC_DEF("exec", 1, js_os_exec ),
@@ -3608,7 +3654,6 @@ static const JSCFunctionListEntry js_os_funcs[] = {
OS_FLAG(WNOHANG),
JS_CFUNC_DEF("pipe", 0, js_os_pipe ),
JS_CFUNC_DEF("kill", 2, js_os_kill ),
- JS_CFUNC_DEF("sleep", 1, js_os_sleep ),
JS_CFUNC_DEF("dup", 1, js_os_dup ),
JS_CFUNC_DEF("dup2", 2, js_os_dup2 ),
#endif
diff --git a/quickjs.c b/quickjs.c
index a39ff8f..48aeffc 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -1,8 +1,8 @@
/*
* QuickJS Javascript Engine
*
- * Copyright (c) 2017-2020 Fabrice Bellard
- * Copyright (c) 2017-2020 Charlie Gordon
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -36,6 +36,8 @@
#include
#elif defined(__linux__)
#include
+#elif defined(__FreeBSD__)
+#include
#endif
#include "cutils.h"
@@ -265,9 +267,10 @@ struct JSRuntime {
struct list_head string_list; /* list of JSString.link */
#endif
/* stack limitation */
- const uint8_t *stack_top;
- size_t stack_size; /* in bytes */
-
+ uintptr_t stack_size; /* in bytes, 0 if no limit */
+ uintptr_t stack_top;
+ uintptr_t stack_limit; /* lower stack limit */
+
JSValue current_exception;
/* true if inside an out of memory error, to avoid recursing */
BOOL in_out_of_memory : 8;
@@ -1569,9 +1572,9 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops)
#if !defined(CONFIG_STACK_CHECK)
/* no stack limitation */
-static inline uint8_t *js_get_stack_pointer(void)
+static inline uintptr_t js_get_stack_pointer(void)
{
- return NULL;
+ return 0;
}
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
@@ -1580,16 +1583,16 @@ static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
}
#else
/* Note: OS and CPU dependent */
-static inline uint8_t *js_get_stack_pointer(void)
+static inline uintptr_t js_get_stack_pointer(void)
{
- return __builtin_frame_address(0);
+ return (uintptr_t)__builtin_frame_address(0);
}
static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
{
- size_t size;
- size = rt->stack_top - js_get_stack_pointer();
- return unlikely((size + alloca_size) > rt->stack_size);
+ uintptr_t sp;
+ sp = js_get_stack_pointer() - alloca_size;
+ return unlikely(sp < rt->stack_limit);
}
#endif
@@ -1649,8 +1652,9 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
if (init_shape_hash(rt))
goto fail;
- rt->stack_top = js_get_stack_pointer();
rt->stack_size = JS_DEFAULT_STACK_SIZE;
+ JS_UpdateStackTop(rt);
+
rt->current_exception = JS_NULL;
return rt;
@@ -2338,9 +2342,25 @@ JSRuntime *JS_GetRuntime(JSContext *ctx)
return ctx->rt;
}
+static void update_stack_limit(JSRuntime *rt)
+{
+ if (rt->stack_size == 0) {
+ rt->stack_limit = 0; /* no limit */
+ } else {
+ rt->stack_limit = rt->stack_top - rt->stack_size;
+ }
+}
+
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size)
{
rt->stack_size = stack_size;
+ update_stack_limit(rt);
+}
+
+void JS_UpdateStackTop(JSRuntime *rt)
+{
+ rt->stack_top = js_get_stack_pointer();
+ update_stack_limit(rt);
}
static inline BOOL is_strict_mode(JSContext *ctx)
@@ -3377,6 +3397,8 @@ static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
JSClass *cl, *new_class_array;
struct list_head *el;
+ if (class_id >= (1 << 16))
+ return -1;
if (class_id < rt->class_count &&
rt->class_array[class_id].class_id != 0)
return -1;
@@ -8231,6 +8253,23 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
return TRUE;
}
+/* return -1 if exception */
+static int expand_fast_array(JSContext *ctx, JSObject *p, uint32_t new_len)
+{
+ uint32_t new_size;
+ size_t slack;
+ JSValue *new_array_prop;
+ /* XXX: potential arithmetic overflow */
+ new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
+ new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
+ if (!new_array_prop)
+ return -1;
+ new_size += slack / sizeof(*new_array_prop);
+ p->u.array.u.values = new_array_prop;
+ p->u.array.u1.size = new_size;
+ return 0;
+}
+
/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
TRUE and p->extensible = TRUE */
static int add_fast_array_element(JSContext *ctx, JSObject *p,
@@ -8253,19 +8292,10 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p,
}
}
if (unlikely(new_len > p->u.array.u1.size)) {
- uint32_t new_size;
- size_t slack;
- JSValue *new_array_prop;
- /* XXX: potential arithmetic overflow */
- new_size = max_int(new_len, p->u.array.u1.size * 3 / 2);
- new_array_prop = js_realloc2(ctx, p->u.array.u.values, sizeof(JSValue) * new_size, &slack);
- if (!new_array_prop) {
+ if (expand_fast_array(ctx, p, new_len)) {
JS_FreeValue(ctx, val);
return -1;
}
- new_size += slack / sizeof(*new_array_prop);
- p->u.array.u.values = new_array_prop;
- p->u.array.u1.size = new_size;
}
p->u.array.u.values[new_len - 1] = val;
p->u.array.count = new_len;
@@ -8279,22 +8309,24 @@ static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
JS_FreeValue(ctx, desc->value);
}
-/* generic (and slower) version of JS_SetProperty() for Reflect.set() */
+/* generic (and slower) version of JS_SetProperty() for
+ * Reflect.set(). 'obj' must be an object. */
static int JS_SetPropertyGeneric(JSContext *ctx,
- JSObject *p, JSAtom prop,
+ JSValueConst obj, JSAtom prop,
JSValue val, JSValueConst this_obj,
int flags)
{
int ret;
JSPropertyDescriptor desc;
-
- while (p != NULL) {
+ JSValue obj1;
+ JSObject *p;
+
+ obj1 = JS_DupValue(ctx, obj);
+ for(;;) {
+ p = JS_VALUE_GET_OBJ(obj1);
if (p->is_exotic) {
const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
if (em && em->set_property) {
- JSValue obj1;
- /* set_property can free the prototype */
- obj1 = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
ret = em->set_property(ctx, obj1, prop,
val, this_obj, flags);
JS_FreeValue(ctx, obj1);
@@ -8304,8 +8336,11 @@ static int JS_SetPropertyGeneric(JSContext *ctx,
}
ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
- if (ret < 0)
+ if (ret < 0) {
+ JS_FreeValue(ctx, obj1);
+ JS_FreeValue(ctx, val);
return ret;
+ }
if (ret) {
if (desc.flags & JS_PROP_GETSET) {
JSObject *setter;
@@ -8316,27 +8351,38 @@ static int JS_SetPropertyGeneric(JSContext *ctx,
ret = call_setter(ctx, setter, this_obj, val, flags);
JS_FreeValue(ctx, desc.getter);
JS_FreeValue(ctx, desc.setter);
+ JS_FreeValue(ctx, obj1);
return ret;
} else {
JS_FreeValue(ctx, desc.value);
if (!(desc.flags & JS_PROP_WRITABLE)) {
+ JS_FreeValue(ctx, obj1);
goto read_only_error;
}
}
break;
}
- p = p->shape->proto;
+ /* Note: at this point 'obj1' cannot be a proxy. XXX: may have
+ to check recursion */
+ obj1 = JS_GetPrototypeFree(ctx, obj1);
+ if (JS_IsNull(obj1))
+ break;
}
+ JS_FreeValue(ctx, obj1);
- if (!JS_IsObject(this_obj))
+ if (!JS_IsObject(this_obj)) {
+ JS_FreeValue(ctx, val);
return JS_ThrowTypeErrorOrFalse(ctx, flags, "receiver is not an object");
-
+ }
+
p = JS_VALUE_GET_OBJ(this_obj);
/* modify the property in this_obj if it already exists */
ret = JS_GetOwnPropertyInternal(ctx, &desc, p, prop);
- if (ret < 0)
+ if (ret < 0) {
+ JS_FreeValue(ctx, val);
return ret;
+ }
if (ret) {
if (desc.flags & JS_PROP_GETSET) {
JS_FreeValue(ctx, desc.getter);
@@ -15022,10 +15068,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *
static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
{
- JSObject *p, *p1;
+ JSObject *p;
JSPropertyEnum *tab_atom;
int i;
- JSValue enum_obj;
+ JSValue enum_obj, obj1;
JSForInIterator *it;
uint32_t tag, tab_atom_count;
@@ -15054,20 +15100,34 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
if (tag == JS_TAG_NULL || tag == JS_TAG_UNDEFINED)
return enum_obj;
- p = JS_VALUE_GET_OBJ(obj);
-
/* fast path: assume no enumerable properties in the prototype chain */
- p1 = p->shape->proto;
- while (p1 != NULL) {
- if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p1,
- JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY))
+ obj1 = JS_DupValue(ctx, obj);
+ for(;;) {
+ obj1 = JS_GetPrototypeFree(ctx, obj1);
+ if (JS_IsNull(obj1))
+ break;
+ if (JS_IsException(obj1))
goto fail;
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
+ JS_VALUE_GET_OBJ(obj1),
+ JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY)) {
+ JS_FreeValue(ctx, obj1);
+ goto fail;
+ }
js_free_prop_enum(ctx, tab_atom, tab_atom_count);
if (tab_atom_count != 0) {
+ JS_FreeValue(ctx, obj1);
goto slow_path;
}
- p1 = p1->shape->proto;
+ /* must check for timeout to avoid infinite loop */
+ if (js_poll_interrupts(ctx)) {
+ JS_FreeValue(ctx, obj1);
+ goto fail;
+ }
}
+
+ p = JS_VALUE_GET_OBJ(obj);
+
if (p->fast_array) {
JSShape *sh;
JSShapeProperty *prs;
@@ -15095,17 +15155,30 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
slow_path:
/* non enumerable properties hide the enumerables ones in the
prototype chain */
- while (p != NULL) {
- if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
- JS_GPN_STRING_MASK | JS_GPN_SET_ENUM))
+ obj1 = JS_DupValue(ctx, obj);
+ for(;;) {
+ if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count,
+ JS_VALUE_GET_OBJ(obj1),
+ JS_GPN_STRING_MASK | JS_GPN_SET_ENUM)) {
+ JS_FreeValue(ctx, obj1);
goto fail;
+ }
for(i = 0; i < tab_atom_count; i++) {
JS_DefinePropertyValue(ctx, enum_obj, tab_atom[i].atom, JS_NULL,
(tab_atom[i].is_enumerable ?
JS_PROP_ENUMERABLE : 0));
}
js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- p = p->shape->proto;
+ obj1 = JS_GetPrototypeFree(ctx, obj1);
+ if (JS_IsNull(obj1))
+ break;
+ if (JS_IsException(obj1))
+ goto fail;
+ /* must check for timeout to avoid infinite loop */
+ if (js_poll_interrupts(ctx)) {
+ JS_FreeValue(ctx, obj1);
+ goto fail;
+ }
}
return enum_obj;
@@ -15572,8 +15645,10 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
uint32_t i, tab_atom_count;
JSObject *p;
JSObject *pexcl = NULL;
- int ret = 0, flags;
-
+ int ret, gpn_flags;
+ JSPropertyDescriptor desc;
+ BOOL is_enumerable;
+
if (JS_VALUE_GET_TAG(source) != JS_TAG_OBJECT)
return 0;
@@ -15581,37 +15656,57 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
pexcl = JS_VALUE_GET_OBJ(excluded);
p = JS_VALUE_GET_OBJ(source);
+
+ gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY;
+ if (p->is_exotic) {
+ const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
+ /* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
+ introduces a visible change */
+ if (em && em->get_own_property_names) {
+ gpn_flags &= ~JS_GPN_ENUM_ONLY;
+ }
+ }
if (JS_GetOwnPropertyNamesInternal(ctx, &tab_atom, &tab_atom_count, p,
- JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK |
- JS_GPN_ENUM_ONLY))
+ gpn_flags))
return -1;
-
- flags = JS_PROP_C_W_E;
-
+
for (i = 0; i < tab_atom_count; i++) {
if (pexcl) {
ret = JS_GetOwnPropertyInternal(ctx, NULL, pexcl, tab_atom[i].atom);
if (ret) {
if (ret < 0)
- break;
- ret = 0;
+ goto exception;
continue;
}
}
- ret = -1;
+ if (!(gpn_flags & JS_GPN_ENUM_ONLY)) {
+ /* test if the property is enumerable */
+ ret = JS_GetOwnPropertyInternal(ctx, &desc, p, tab_atom[i].atom);
+ if (ret < 0)
+ goto exception;
+ if (!ret)
+ continue;
+ is_enumerable = (desc.flags & JS_PROP_ENUMERABLE) != 0;
+ js_free_desc(ctx, &desc);
+ if (!is_enumerable)
+ continue;
+ }
val = JS_GetProperty(ctx, source, tab_atom[i].atom);
if (JS_IsException(val))
- break;
+ goto exception;
if (setprop)
ret = JS_SetProperty(ctx, target, tab_atom[i].atom, val);
else
- ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val, flags);
+ ret = JS_DefinePropertyValue(ctx, target, tab_atom[i].atom, val,
+ JS_PROP_C_W_E);
if (ret < 0)
- break;
- ret = 0;
+ goto exception;
}
js_free_prop_enum(ctx, tab_atom, tab_atom_count);
- return ret;
+ return 0;
+ exception:
+ js_free_prop_enum(ctx, tab_atom, tab_atom_count);
+ return -1;
}
/* only valid inside C functions */
@@ -16654,7 +16749,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK;
CASE(OP_check_ctor):
if (JS_IsUndefined(new_target)) {
- JS_ThrowTypeError(caller_ctx, "class constructors must be invoked with 'new'");
+ JS_ThrowTypeError(ctx, "class constructors must be invoked with 'new'");
goto exception;
}
BREAK;
@@ -17770,8 +17865,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = JS_ValueToAtom(ctx, sp[-2]);
if (unlikely(atom == JS_ATOM_NULL))
goto exception;
- ret = JS_SetPropertyGeneric(ctx, JS_VALUE_GET_OBJ(sp[-3]),
- atom, sp[-1], sp[-4],
+ ret = JS_SetPropertyGeneric(ctx, sp[-3], atom, sp[-1], sp[-4],
JS_PROP_THROW_STRICT);
JS_FreeAtom(ctx, atom);
JS_FreeValue(ctx, sp[-4]);
@@ -22678,7 +22772,7 @@ static __exception int js_parse_left_hand_side_expr(JSParseState *s)
return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
}
-/* XXX: is there is nicer solution ? */
+/* XXX: could generate specific bytecode */
static __exception int js_parse_class_default_ctor(JSParseState *s,
BOOL has_super,
JSFunctionDef **pfd)
@@ -22691,7 +22785,8 @@ static __exception int js_parse_class_default_ctor(JSParseState *s,
js_parse_get_pos(s, &pos);
if (has_super) {
- str = "(...a){super(...a);}";
+ /* spec change: no argument evaluation */
+ str = "(){super(...arguments);}";
func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR;
} else {
str = "(){}";
@@ -34227,6 +34322,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
bc_put_leb128(s, b->cpool_count);
bc_put_leb128(s, b->byte_code_len);
if (b->vardefs) {
+ /* XXX: this field is redundant */
bc_put_leb128(s, b->arg_count + b->var_count);
for(i = 0; i < b->arg_count + b->var_count; i++) {
JSVarDef *vd = &b->vardefs[i];
@@ -35196,6 +35292,16 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
memcpy(b, &bc, offsetof(JSFunctionBytecode, debug));
b->header.ref_count = 1;
+ if (local_count != 0) {
+ b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
+ }
+ if (b->closure_var_count != 0) {
+ b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
+ }
+ if (b->cpool_count != 0) {
+ b->cpool = (void *)((uint8_t*)b + cpool_offset);
+ }
+
add_gc_object(ctx->rt, &b->header, JS_GC_OBJ_TYPE_FUNCTION_BYTECODE);
obj = JS_MKPTR(JS_TAG_FUNCTION_BYTECODE, b);
@@ -35211,7 +35317,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
if (local_count != 0) {
bc_read_trace(s, "vars {\n");
- b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
for(i = 0; i < local_count; i++) {
JSVarDef *vd = &b->vardefs[i];
if (bc_get_atom(s, &vd->var_name))
@@ -35236,7 +35341,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
}
if (b->closure_var_count != 0) {
bc_read_trace(s, "closure vars {\n");
- b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
for(i = 0; i < b->closure_var_count; i++) {
JSClosureVar *cv = &b->closure_var[i];
int var_idx;
@@ -35288,7 +35392,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
}
if (b->cpool_count != 0) {
bc_read_trace(s, "cpool {\n");
- b->cpool = (void *)((uint8_t*)b + cpool_offset);
for(i = 0; i < b->cpool_count; i++) {
JSValue val;
val = JS_ReadObjectRec(s);
@@ -37493,6 +37596,10 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
}
if (js_get_length32(ctx, &len, array_arg))
return NULL;
+ if (len > JS_MAX_LOCAL_VARS) {
+ JS_ThrowInternalError(ctx, "too many arguments");
+ return NULL;
+ }
/* avoid allocating 0 bytes */
tab = js_mallocz(ctx, sizeof(tab[0]) * max_uint32(1, len));
if (!tab)
@@ -38293,9 +38400,16 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
n = 0;
for(k = 0; k < len; k++) {
- present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
- if (present < 0)
- goto exception;
+ if (special & special_TA) {
+ val = JS_GetPropertyInt64(ctx, obj, k);
+ if (JS_IsException(val))
+ goto exception;
+ present = TRUE;
+ } else {
+ present = JS_TryGetPropertyInt64(ctx, obj, k, &val);
+ if (present < 0)
+ goto exception;
+ }
if (present) {
index_val = JS_NewInt64(ctx, k);
if (JS_IsException(index_val))
@@ -38413,18 +38527,32 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
}
k1 = (special & special_reduceRight) ? len - k - 1 : k;
k++;
- present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
- if (present < 0)
- goto exception;
- if (present)
+ if (special & special_TA) {
+ acc = JS_GetPropertyInt64(ctx, obj, k1);
+ if (JS_IsException(acc))
+ goto exception;
break;
+ } else {
+ present = JS_TryGetPropertyInt64(ctx, obj, k1, &acc);
+ if (present < 0)
+ goto exception;
+ if (present)
+ break;
+ }
}
}
for (; k < len; k++) {
k1 = (special & special_reduceRight) ? len - k - 1 : k;
- present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
- if (present < 0)
- goto exception;
+ if (special & special_TA) {
+ val = JS_GetPropertyInt64(ctx, obj, k1);
+ if (JS_IsException(val))
+ goto exception;
+ present = TRUE;
+ } else {
+ present = JS_TryGetPropertyInt64(ctx, obj, k1, &val);
+ if (present < 0)
+ goto exception;
+ }
if (present) {
index_val = JS_NewInt64(ctx, k1);
if (JS_IsException(index_val))
@@ -38829,27 +38957,64 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
int64_t len, from, newLen;
obj = JS_ToObject(ctx, this_val);
- if (js_get_length64(ctx, &len, obj))
- goto exception;
- newLen = len + argc;
- if (newLen > MAX_SAFE_INTEGER) {
- JS_ThrowTypeError(ctx, "Array loo long");
- goto exception;
- }
- from = len;
- if (unshift && argc > 0) {
- if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
+
+ if (JS_VALUE_GET_TAG(obj) == JS_TAG_OBJECT) {
+ JSObject *p = JS_VALUE_GET_OBJ(obj);
+ if (p->class_id != JS_CLASS_ARRAY ||
+ !p->fast_array || !p->extensible)
+ goto generic_case;
+ /* length must be writable */
+ if (unlikely(!(get_shape_prop(p->shape)->flags & JS_PROP_WRITABLE)))
+ goto generic_case;
+ /* check the length */
+ if (unlikely(JS_VALUE_GET_TAG(p->prop[0].u.value) != JS_TAG_INT))
+ goto generic_case;
+ len = JS_VALUE_GET_INT(p->prop[0].u.value);
+ /* we don't support holes */
+ if (unlikely(len != p->u.array.count))
+ goto generic_case;
+ newLen = len + argc;
+ if (unlikely(newLen > INT32_MAX))
+ goto generic_case;
+ if (newLen > p->u.array.u1.size) {
+ if (expand_fast_array(ctx, p, newLen))
+ goto exception;
+ }
+ if (unshift && argc > 0) {
+ memmove(p->u.array.u.values + argc, p->u.array.u.values,
+ len * sizeof(p->u.array.u.values[0]));
+ from = 0;
+ } else {
+ from = len;
+ }
+ for(i = 0; i < argc; i++) {
+ p->u.array.u.values[from + i] = JS_DupValue(ctx, argv[i]);
+ }
+ p->u.array.count = newLen;
+ p->prop[0].u.value = JS_NewInt32(ctx, newLen);
+ } else {
+ generic_case:
+ if (js_get_length64(ctx, &len, obj))
goto exception;
- from = 0;
- }
- for(i = 0; i < argc; i++) {
- if (JS_SetPropertyInt64(ctx, obj, from + i,
- JS_DupValue(ctx, argv[i])) < 0)
+ newLen = len + argc;
+ if (newLen > MAX_SAFE_INTEGER) {
+ JS_ThrowTypeError(ctx, "Array loo long");
+ goto exception;
+ }
+ from = len;
+ if (unshift && argc > 0) {
+ if (JS_CopySubArray(ctx, obj, argc, 0, len, -1))
+ goto exception;
+ from = 0;
+ }
+ for(i = 0; i < argc; i++) {
+ if (JS_SetPropertyInt64(ctx, obj, from + i,
+ JS_DupValue(ctx, argv[i])) < 0)
+ goto exception;
+ }
+ if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
goto exception;
}
- if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewInt64(ctx, newLen)) < 0)
- goto exception;
-
JS_FreeValue(ctx, obj);
return JS_NewInt64(ctx, newLen);
@@ -39079,6 +39244,11 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
int64_t sourceIndex, elementLen;
int present, is_array;
+ if (js_check_stack_overflow(ctx->rt, 0)) {
+ JS_ThrowStackOverflow(ctx);
+ return -1;
+ }
+
for (sourceIndex = 0; sourceIndex < sourceLen; sourceIndex++) {
present = JS_TryGetPropertyInt64(ctx, source, sourceIndex, &element);
if (present < 0)
@@ -41816,7 +41986,7 @@ static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val,
}
/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
- between local time and UTC time 'd' in minutes */
+ between UTC time and local time 'd' in minutes */
static int getTimezoneOffset(int64_t time) {
#if defined(_WIN32)
/* XXX: TODO */
@@ -44165,7 +44335,7 @@ static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
atom = JS_ValueToAtom(ctx, prop);
if (unlikely(atom == JS_ATOM_NULL))
return JS_EXCEPTION;
- ret = JS_SetPropertyGeneric(ctx, JS_VALUE_GET_OBJ(obj), atom,
+ ret = JS_SetPropertyGeneric(ctx, obj, atom,
JS_DupValue(ctx, val), receiver, 0);
JS_FreeAtom(ctx, atom);
if (ret < 0)
@@ -44513,7 +44683,7 @@ static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
if (!s)
return -1;
if (JS_IsUndefined(method)) {
- return JS_SetPropertyGeneric(ctx, JS_VALUE_GET_OBJ(s->target), atom,
+ return JS_SetPropertyGeneric(ctx, s->target, atom,
JS_DupValue(ctx, value), receiver,
flags);
}
@@ -48134,24 +48304,22 @@ static void string_skip_non_spaces(JSString *sp, int *pp) {
*pp += 1;
}
-/* parse a numeric field */
-static int string_get_field(JSString *sp, int *pp, int64_t *pval) {
+/* parse a numeric field with an optional sign if accept_sign is TRUE */
+static int string_get_digits(JSString *sp, int *pp, int64_t *pval) {
int64_t v = 0;
- int c, p = *pp;
-
- /* skip non digits, should only skip spaces? */
- while (p < sp->len) {
- c = string_get(sp, p);
- if (c >= '0' && c <= '9')
- break;
- p++;
- }
+ int c, p = *pp, p_start;
+
if (p >= sp->len)
return -1;
+ p_start = p;
while (p < sp->len) {
c = string_get(sp, p);
- if (!(c >= '0' && c <= '9'))
- break;
+ if (!(c >= '0' && c <= '9')) {
+ if (p == p_start)
+ return -1;
+ else
+ break;
+ }
v = v * 10 + c - '0';
p++;
}
@@ -48160,8 +48328,25 @@ static int string_get_field(JSString *sp, int *pp, int64_t *pval) {
return 0;
}
+static int string_get_signed_digits(JSString *sp, int *pp, int64_t *pval) {
+ int res, sgn, p = *pp;
+
+ if (p >= sp->len)
+ return -1;
+
+ sgn = string_get(sp, p);
+ if (sgn == '-' || sgn == '+')
+ p++;
+
+ res = string_get_digits(sp, &p, pval);
+ if (res == 0 && sgn == '-')
+ *pval = -*pval;
+ *pp = p;
+ return res;
+}
+
/* parse a fixed width numeric field */
-static int string_get_digits(JSString *sp, int *pp, int n, int64_t *pval) {
+static int string_get_fixed_width_digits(JSString *sp, int *pp, int n, int64_t *pval) {
int64_t v = 0;
int i, c, p = *pp;
@@ -48179,23 +48364,32 @@ static int string_get_digits(JSString *sp, int *pp, int n, int64_t *pval) {
return 0;
}
-/* parse a signed numeric field */
-static int string_get_signed_field(JSString *sp, int *pp, int64_t *pval) {
- int sgn, res;
-
- if (*pp >= sp->len)
+static int string_get_milliseconds(JSString *sp, int *pp, int64_t *pval) {
+ /* parse milliseconds as a fractional part, round to nearest */
+ /* XXX: the spec does not indicate which rounding should be used */
+ int mul = 1000, ms = 0, p = *pp, c, p_start;
+ if (p >= sp->len)
return -1;
-
- sgn = string_get(sp, *pp);
- if (sgn == '-' || sgn == '+')
- *pp += 1;
-
- res = string_get_field(sp, pp, pval);
- if (res == 0 && sgn == '-')
- *pval = -*pval;
- return res;
+ p_start = p;
+ while (p < sp->len) {
+ c = string_get(sp, p);
+ if (!(c >= '0' && c <= '9')) {
+ if (p == p_start)
+ return -1;
+ else
+ break;
+ }
+ if (mul == 1 && c >= '5')
+ ms += 1;
+ ms += (c - '0') * (mul /= 10);
+ p++;
+ }
+ *pval = ms;
+ *pp = p;
+ return 0;
}
+
static int find_abbrev(JSString *sp, int p, const char *list, int count) {
int n, i;
@@ -48234,7 +48428,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
double fields1[7];
int64_t tz, hh, mm;
double d;
- int p, i, c, sgn;
+ int p, i, c, sgn, l;
JSString *sp;
BOOL is_local;
@@ -48249,50 +48443,74 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
if (p < sp->len && (((c = string_get(sp, p)) >= '0' && c <= '9') || c == '+' || c == '-')) {
/* ISO format */
/* year field can be negative */
- /* XXX: could be stricter */
- if (string_get_signed_field(sp, &p, &fields[0]))
+ if (string_get_signed_digits(sp, &p, &fields[0]))
goto done;
- is_local = TRUE;
- for (i = 1; i < 6; i++) {
- if (string_get_field(sp, &p, &fields[i]))
+ for (i = 1; i < 7; i++) {
+ if (p >= sp->len)
break;
- }
- if (i <= 3) {
- /* no time: UTC by default */
- is_local = FALSE;
- } else if (i == 6 && p < sp->len && string_get(sp, p) == '.') {
- /* parse milliseconds as a fractional part, round to nearest */
- /* XXX: the spec does not indicate which rounding should be used */
- int mul = 1000, ms = 0;
- while (++p < sp->len) {
- int c = string_get(sp, p);
- if (!(c >= '0' && c <= '9'))
- break;
- if (mul == 1 && c >= '5')
- ms += 1;
- ms += (c - '0') * (mul /= 10);
+ switch(i) {
+ case 1:
+ case 2:
+ c = '-';
+ break;
+ case 3:
+ c = 'T';
+ break;
+ case 4:
+ case 5:
+ c = ':';
+ break;
+ case 6:
+ c = '.';
+ break;
+ }
+ if (string_get(sp, p) != c)
+ break;
+ p++;
+ if (i == 6) {
+ if (string_get_milliseconds(sp, &p, &fields[i]))
+ goto done;
+ } else {
+ if (string_get_digits(sp, &p, &fields[i]))
+ goto done;
}
- fields[6] = ms;
}
+ /* no time: UTC by default */
+ is_local = (i > 3);
fields[1] -= 1;
- /* parse the time zone offset if present: [+-]HH:mm */
+ /* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
tz = 0;
if (p < sp->len) {
sgn = string_get(sp, p);
if (sgn == '+' || sgn == '-') {
- if (string_get_field(sp, &p, &hh))
+ p++;
+ l = sp->len - p;
+ if (l != 4 && l != 5)
+ goto done;
+ if (string_get_fixed_width_digits(sp, &p, 2, &hh))
goto done;
- if (string_get_field(sp, &p, &mm))
+ if (l == 5) {
+ if (string_get(sp, p) != ':')
+ goto done;
+ p++;
+ }
+ if (string_get_fixed_width_digits(sp, &p, 2, &mm))
goto done;
tz = hh * 60 + mm;
if (sgn == '-')
tz = -tz;
is_local = FALSE;
} else if (sgn == 'Z') {
+ p++;
is_local = FALSE;
+ } else {
+ goto done;
}
+ /* error if extraneous characters */
+ if (p != sp->len)
+ goto done;
}
} else {
/* toString or toUTCString format */
@@ -48304,7 +48522,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
c = string_get(sp, p);
if (c >= '0' && c <= '9') {
/* day of month first */
- if (string_get_field(sp, &p, &fields[2]))
+ if (string_get_digits(sp, &p, &fields[2]))
goto done;
if (string_get_month(sp, &p, &fields[1]))
goto done;
@@ -48312,16 +48530,26 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
/* month first */
if (string_get_month(sp, &p, &fields[1]))
goto done;
- if (string_get_field(sp, &p, &fields[2]))
+ string_skip_spaces(sp, &p);
+ if (string_get_digits(sp, &p, &fields[2]))
goto done;
}
+ /* year */
string_skip_spaces(sp, &p);
- if (string_get_signed_field(sp, &p, &fields[0]))
+ if (string_get_signed_digits(sp, &p, &fields[0]))
goto done;
/* hour, min, seconds */
+ string_skip_spaces(sp, &p);
for(i = 0; i < 3; i++) {
- if (string_get_field(sp, &p, &fields[3 + i]))
+ if (i == 1 || i == 2) {
+ if (p >= sp->len)
+ goto done;
+ if (string_get(sp, p) != ':')
+ goto done;
+ p++;
+ }
+ if (string_get_digits(sp, &p, &fields[3 + i]))
goto done;
}
// XXX: parse optional milliseconds?
@@ -48333,9 +48561,9 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
sgn = string_get(sp, p);
if (sgn == '+' || sgn == '-') {
p++;
- if (string_get_digits(sp, &p, 2, &hh))
+ if (string_get_fixed_width_digits(sp, &p, 2, &hh))
goto done;
- if (string_get_digits(sp, &p, 2, &mm))
+ if (string_get_fixed_width_digits(sp, &p, 2, &mm))
goto done;
tz = hh * 60 + mm;
if (sgn == '-')
@@ -51886,10 +52114,16 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
inc = 1;
}
- if (validate_typed_array(ctx, this_val))
- goto exception;
p = JS_VALUE_GET_OBJ(this_val);
-
+ /* if the array was detached, no need to go further (but no
+ exception is raised) */
+ if (typed_array_is_detached(ctx, p)) {
+ /* "includes" scans all the properties, so "undefined" can match */
+ if (special == special_includes && JS_IsUndefined(argv[0]) && len > 0)
+ res = 0;
+ goto done;
+ }
+
is_bigint = 0;
is_int = 0; /* avoid warning */
v64 = 0; /* avoid warning */
@@ -51925,7 +52159,6 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
goto done;
}
- p = JS_VALUE_GET_OBJ(this_val);
switch (p->class_id) {
case JS_CLASS_INT8_ARRAY:
if (is_int && (int8_t)v64 == v64)
@@ -52114,13 +52347,16 @@ static JSValue js_typed_array_join(JSContext *ctx, JSValueConst this_val,
}
}
el = JS_GetPropertyUint32(ctx, this_val, i);
- if (JS_IsException(el))
- goto fail;
- if (toLocaleString) {
- el = JS_ToLocaleStringFree(ctx, el);
+ /* Can return undefined for example if the typed array is detached */
+ if (!JS_IsNull(el) && !JS_IsUndefined(el)) {
+ if (JS_IsException(el))
+ goto fail;
+ if (toLocaleString) {
+ el = JS_ToLocaleStringFree(ctx, el);
+ }
+ if (string_buffer_concat_value_free(b, el))
+ goto fail;
}
- if (string_buffer_concat_value_free(b, el))
- goto fail;
}
JS_FreeValue(ctx, sep);
return string_buffer_end(b);
diff --git a/quickjs.h b/quickjs.h
index 92457a2..d4a5cd3 100644
--- a/quickjs.h
+++ b/quickjs.h
@@ -1,8 +1,8 @@
/*
* QuickJS Javascript Engine
*
- * Copyright (c) 2017-2020 Fabrice Bellard
- * Copyright (c) 2017-2020 Charlie Gordon
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -333,7 +333,11 @@ JSRuntime *JS_NewRuntime(void);
void JS_SetRuntimeInfo(JSRuntime *rt, const char *info);
void JS_SetMemoryLimit(JSRuntime *rt, size_t limit);
void JS_SetGCThreshold(JSRuntime *rt, size_t gc_threshold);
+/* use 0 to disable maximum stack size check */
void JS_SetMaxStackSize(JSRuntime *rt, size_t stack_size);
+/* should be called when changing thread to update the stack top value
+ used to check stack overflow. */
+void JS_UpdateStackTop(JSRuntime *rt);
JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque);
void JS_FreeRuntime(JSRuntime *rt);
void *JS_GetRuntimeOpaque(JSRuntime *rt);
diff --git a/release.sh b/release.sh
index 6dc89fb..26fba1b 100755
--- a/release.sh
+++ b/release.sh
@@ -131,7 +131,8 @@ outdir="/tmp/${d}"
rm -rf $outdir
mkdir -p $outdir $outdir/doc $outdir/tests $outdir/examples
-cp Makefile VERSION TODO Changelog readme.txt release.sh unicode_download.sh \
+cp Makefile VERSION TODO Changelog readme.txt LICENSE \
+ release.sh unicode_download.sh \
qjs.c qjsc.c qjscalc.js repl.js \
quickjs.c quickjs.h quickjs-atom.h \
quickjs-libc.c quickjs-libc.h quickjs-opcode.h \
diff --git a/run-test262.c b/run-test262.c
index c860dbb..2092cac 100644
--- a/run-test262.c
+++ b/run-test262.c
@@ -1,8 +1,8 @@
/*
* ECMA Test 262 Runner for QuickJS
*
- * Copyright (c) 2017-2020 Fabrice Bellard
- * Copyright (c) 2017-2020 Charlie Gordon
+ * Copyright (c) 2017-2021 Fabrice Bellard
+ * Copyright (c) 2017-2021 Charlie Gordon
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/test262.conf b/test262.conf
index f30a4ac..6fbb579 100644
--- a/test262.conf
+++ b/test262.conf
@@ -51,10 +51,10 @@ testdir=test262/test
AggregateError
align-detached-buffer-semantics-with-web-reality
arbitrary-module-namespace-names=skip
+Array.prototype.at=skip
Array.prototype.flat
Array.prototype.flatMap
Array.prototype.flatten
-Array.prototype.item=skip
Array.prototype.values
ArrayBuffer
arrow-function
@@ -141,7 +141,7 @@ string-trimming
String.fromCodePoint
String.prototype.endsWith
String.prototype.includes
-String.prototype.item=skip
+String.prototype.at=skip
String.prototype.matchAll
String.prototype.replaceAll
String.prototype.trimEnd
@@ -166,7 +166,7 @@ tail-call-optimization=skip
template
top-level-await=skip
TypedArray
-TypedArray.prototype.item=skip
+TypedArray.prototype.at=skip
u180e
Uint16Array
Uint32Array
diff --git a/test262_errors.txt b/test262_errors.txt
index 502a650..b7f6aef 100644
--- a/test262_errors.txt
+++ b/test262_errors.txt
@@ -2,50 +2,34 @@ test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-r
test262/test/built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js:20: strict mode: Test262Error: Expected a ReferenceError but got a ReferenceError
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: SyntaxError: invalid group name
test262/test/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js:46: strict mode: SyntaxError: invalid group name
-test262/test/built-ins/TypedArray/prototype/every/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/every/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/every/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/filter/BigInt/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/filter/BigInt/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/filter/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/findIndex/BigInt/predicate-may-detach-buffer.js:36: Test262Error: throws a TypeError getting a value from the detached buffer Expected a TypeError to be thrown but no exception was thrown at all (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/findIndex/BigInt/predicate-may-detach-buffer.js:36: strict mode: Test262Error: throws a TypeError getting a value from the detached buffer Expected a TypeError to be thrown but no exception was thrown at all (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/forEach/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/forEach/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/forEach/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/map/BigInt/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/map/BigInt/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js:20: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/map/callbackfn-detachbuffer.js:20: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/reduce/BigInt/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/reduce/BigInt/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/reduce/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js:29: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/reduceRight/callbackfn-detachbuffer.js:29: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js:28: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArray/prototype/some/callbackfn-detachbuffer.js:28: strict mode: Test262Error: Expected SameValue(«1», «2») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:37: Test262Error: (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:37: strict mode: Test262Error: (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:38: Test262Error: (Testing with Float64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:38: strict mode: Test262Error: (Testing with Float64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/index-prop-desc.js:21: Test262Error: Expected SameValue(«43», «42») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/BigInt/index-prop-desc.js:21: strict mode: Test262Error: Expected SameValue(«43», «42») to be true (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/index-prop-desc.js:22: Test262Error: Expected SameValue(«43», «42») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/GetOwnProperty/index-prop-desc.js:22: strict mode: Test262Error: Expected SameValue(«43», «42») to be true (Testing with Float64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:36: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: Test262Error: (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/BigInt/detached-buffer.js:46: strict mode: Test262Error: (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: Test262Error: (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/DefineOwnProperty/detached-buffer.js:47: strict mode: Test262Error: (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:34: TypeError: cannot convert bigint to number (Testing with BigInt64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with BigInt64Array.)
-test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:36: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-minus-zero.js:20: strict mode: Test262Error: Reflect.set("new TA([42n])", "-0", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-not-integer.js:21: strict mode: Test262Error: Reflect.set("new TA([42n])", "1.1", 1n) must return true Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/key-is-out-of-bounds.js:27: strict mode: Test262Error: Reflect.set("new TA([42n])", "-1", 1n) must return false Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/BigInt/tonumber-value-detached-buffer.js:24: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with BigInt64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer-realm.js:37: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
test262/test/built-ins/TypedArrayConstructors/internals/Set/detached-buffer.js:32: strict mode: TypeError: out-of-bound numeric index (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-minus-zero.js:22: strict mode: Test262Error: Reflect.set(sample, "-0", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-not-integer.js:22: strict mode: Test262Error: Reflect.set(sample, "1.1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/key-is-out-of-bounds.js:22: strict mode: Test262Error: Reflect.set(sample, "-1", 1) must return true Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
+test262/test/built-ins/TypedArrayConstructors/internals/Set/tonumber-value-detached-buffer.js:39: strict mode: Test262Error: Expected SameValue(«false», «true») to be true (Testing with Float64Array.)
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: TypeError: $DONE() not called
test262/test/language/expressions/dynamic-import/usage-from-eval.js:26: strict mode: TypeError: $DONE() not called
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:21: TypeError: cannot read property 'c' of undefined
test262/test/language/expressions/optional-chaining/optional-call-preserves-this.js:15: strict mode: TypeError: cannot read property '_b' of undefined
+test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: unexpected error type: Test262: This statement should not be evaluated.
+test262/test/language/statements/for-of/head-lhs-async-invalid.js:14: strict mode: unexpected error type: Test262: This statement should not be evaluated.
diff --git a/tests/test_builtin.js b/tests/test_builtin.js
index c044b2c..c5c0f83 100644
--- a/tests/test_builtin.js
+++ b/tests/test_builtin.js
@@ -399,7 +399,7 @@ function test_eval()
function test_typed_array()
{
- var buffer, a, i;
+ var buffer, a, i, str;
a = new Uint8Array(4);
assert(a.length, 4);
@@ -438,8 +438,13 @@ function test_typed_array()
a[0] = 1;
a = new Uint8Array(buffer);
-
- assert(a.toString(), "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255");
+
+ str = a.toString();
+ /* test little and big endian cases */
+ if (str !== "0,0,255,255,0,0,0,0,0,0,128,63,255,255,255,255" &&
+ str !== "0,0,255,255,0,0,0,0,63,128,0,0,255,255,255,255") {
+ assert(false);
+ }
assert(a.buffer, buffer);