summaryrefslogtreecommitdiff
path: root/quickjs.c
diff options
context:
space:
mode:
authorbellard <6490144+bellard@users.noreply.github.com>2020-09-06 19:02:03 +0200
committerbellard <6490144+bellard@users.noreply.github.com>2020-09-06 19:02:03 +0200
commit383e2b06c8af144b5cd729dc7bc4ce2e2613f178 (patch)
tree77bf320a5bf01cbcd248f9b85a804980bc89f01d /quickjs.c
parent0e8fffd4de4a10f498f46cd0e99f53da6a523542 (diff)
downloadquickjs-383e2b06c8af144b5cd729dc7bc4ce2e2613f178.tar.gz
quickjs-383e2b06c8af144b5cd729dc7bc4ce2e2613f178.zip
2020-03-16 release
Diffstat (limited to 'quickjs.c')
-rw-r--r--quickjs.c204
1 files changed, 128 insertions, 76 deletions
diff --git a/quickjs.c b/quickjs.c
index b19a4d9..cabb82b 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -284,6 +284,7 @@ struct JSRuntime {
JSNumericOperations bigdecimal_ops;
uint32_t operator_count;
#endif
+ void *user_opaque;
};
struct JSClass {
@@ -1537,6 +1538,16 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
return NULL;
}
+void *JS_GetRuntimeOpaque(JSRuntime *rt)
+{
+ return rt->user_opaque;
+}
+
+void JS_SetRuntimeOpaque(JSRuntime *rt, void *opaque)
+{
+ rt->user_opaque = opaque;
+}
+
/* default memory allocation functions with memory limitation */
static inline size_t js_def_malloc_usable_size(void *ptr)
{
@@ -2198,26 +2209,6 @@ static inline BOOL is_math_mode(JSContext *ctx)
}
#endif
-JSValue JS_NewInt64(JSContext *ctx, int64_t v)
-{
- if (v == (int32_t)v) {
- return JS_NewInt32(ctx, v);
- } else {
- return __JS_NewFloat64(ctx, (double)v);
- }
-}
-
-static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
-{
- JSValue v;
- if (val <= 0x7fffffff) {
- v = JS_MKVAL(JS_TAG_INT, val);
- } else {
- v = __JS_NewFloat64(ctx, val);
- }
- return v;
-}
-
/* JSAtom support */
#define JS_ATOM_TAG_INT (1U << 31)
@@ -9794,6 +9785,8 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
if (*p == '.' && (p > p_start || to_digit((uint8_t)p[1]) < radix)) {
is_float = TRUE;
p++;
+ if (*p == sep)
+ goto fail;
while (to_digit((uint8_t)*p) < radix ||
(*p == sep && to_digit((uint8_t)p[1]) < radix))
p++;
@@ -10129,7 +10122,6 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
ret = JS_NewInt32(ctx, 0);
} else {
/* convert -0 to +0 */
- /* XXX: should not be done here ? */
d = trunc(d) + 0.0;
ret = JS_NewFloat64(ctx, d);
}
@@ -10385,6 +10377,14 @@ int JS_ToInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
return JS_ToInt64Free(ctx, pres, JS_DupValue(ctx, val));
}
+int JS_ToInt64Ext(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+ if (JS_IsBigInt(ctx, val))
+ return JS_ToBigInt64(ctx, pres, val);
+ else
+ return JS_ToInt64(ctx, pres, val);
+}
+
/* return (<0, 0) in case of exception */
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
{
@@ -11840,7 +11840,8 @@ static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
}
/* must be kept in sync with JSOverloadableOperatorEnum */
-static const char *js_overloadable_operator_names[JS_OVOP_COUNT] = {
+/* XXX: use atoms ? */
+static const char js_overloadable_operator_names[JS_OVOP_COUNT][4] = {
"+",
"-",
"*",
@@ -12894,7 +12895,7 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
handle_bigint:
if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
goto exception;
- } else if (tag1 == JS_TAG_FLOAT64 || tag2 == JS_TAG_FLOAT64) {
+ } else {
double dr;
/* float64 result */
if (JS_ToFloat64Free(ctx, &d1, op1)) {
@@ -13031,7 +13032,11 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
} else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
if (ctx->rt->bigfloat_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
goto exception;
- } else if (tag1 == JS_TAG_FLOAT64 || tag2 == JS_TAG_FLOAT64) {
+ } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ handle_bigint:
+ if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
+ goto exception;
+ } else {
double d1, d2;
/* float64 result */
if (JS_ToFloat64Free(ctx, &d1, op1)) {
@@ -13040,10 +13045,9 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
}
if (JS_ToFloat64Free(ctx, &d2, op2))
goto exception;
+ if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
+ goto handle_bigint;
sp[-2] = __JS_NewFloat64(ctx, d1 + d2);
- } else {
- if (ctx->rt->bigint_ops.binary_arith(ctx, OP_add, sp - 2, op1, op2))
- goto exception;
}
return 0;
exception:
@@ -13642,6 +13646,28 @@ static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
#else /* !CONFIG_BIGNUM */
+static JSValue JS_ThrowUnsupportedBigint(JSContext *ctx)
+{
+ return JS_ThrowTypeError(ctx, "bigint is not supported");
+}
+
+JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
+{
+ return JS_ThrowUnsupportedBigint(ctx);
+}
+
+JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
+{
+ return JS_ThrowUnsupportedBigint(ctx);
+}
+
+int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
+{
+ JS_ThrowUnsupportedBigint(ctx);
+ *pres = 0;
+ return -1;
+}
+
static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
JSValue *sp,
OPCodeEnum op)
@@ -16280,22 +16306,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
}
BREAK;
- CASE(OP_get_super_ctor):
- {
- JSValue proto;
- proto = JS_DupValue(ctx, JS_GetPrototype(ctx, sp[-1]));
- if (JS_IsException(proto))
- goto exception;
- if (!JS_IsConstructor(ctx, proto)) {
- JS_FreeValue(ctx, proto);
- JS_ThrowTypeError(ctx, "not a constructor");
- goto exception;
- }
- JS_FreeValue(ctx, sp[-1]);
- sp[-1] = proto;
- }
- BREAK;
-
CASE(OP_get_super):
{
JSValue proto;
@@ -23821,7 +23831,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
emit_atom(s, JS_ATOM_this_active_func);
emit_u16(s, 0);
- emit_op(s, OP_get_super_ctor);
+ emit_op(s, OP_get_super);
emit_op(s, OP_scope_get_var);
emit_atom(s, JS_ATOM_new_target);
@@ -31993,10 +32003,10 @@ static __exception int js_parse_function_decl2(JSParseState *s,
js_parse_expect(s, ')');
goto fail;
}
- if (s->token.val == ',') {
- if (next_token(s))
- goto fail;
- }
+ if (s->token.val == ')')
+ break;
+ if (js_parse_expect(s, ','))
+ goto fail;
}
if ((func_type == JS_PARSE_FUNC_GETTER && fd->arg_count != 0) ||
(func_type == JS_PARSE_FUNC_SETTER && fd->arg_count != 1)) {
@@ -34381,6 +34391,10 @@ int JS_SetModuleExportList(JSContext *ctx, JSModuleDef *m,
case JS_DEF_PROP_DOUBLE:
val = __JS_NewFloat64(ctx, e->u.f64);
break;
+ case JS_DEF_OBJECT:
+ val = JS_NewObject(ctx);
+ JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
+ break;
default:
abort();
}
@@ -37357,7 +37371,8 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
JS_ThrowTypeError(ctx, "Array too long");
goto fail;
}
- if (JS_SetPropertyInt64(ctx, target, targetIndex, element) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, target, targetIndex, element,
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
return -1;
targetIndex++;
}
@@ -37754,7 +37769,6 @@ static const JSCFunctionListEntry js_array_proto_funcs[] = {
JS_CFUNC_DEF("copyWithin", 2, js_array_copyWithin ),
JS_CFUNC_MAGIC_DEF("flatMap", 1, js_array_flatten, 1 ),
JS_CFUNC_MAGIC_DEF("flat", 0, js_array_flatten, 0 ),
- JS_CFUNC_MAGIC_DEF("flatten", 0, js_array_flatten, 0 ),
JS_CFUNC_MAGIC_DEF("values", 0, js_create_array_iterator, JS_ITERATOR_KIND_VALUE ),
JS_ALIAS_DEF("[Symbol.iterator]", "values" ),
JS_CFUNC_MAGIC_DEF("keys", 0, js_create_array_iterator, JS_ITERATOR_KIND_KEY ),
@@ -39918,14 +39932,36 @@ static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
if (JS_ToFloat64(ctx, &b, argv[1]))
return JS_EXCEPTION;
r = hypot(a, b);
- } else {
+ } else if (argc == 0) {
r = 0;
+ } else {
+ double *tab, a_max;
+ tab = js_malloc(ctx, sizeof(tab[0]) * argc);
+ if (!tab)
+ return JS_EXCEPTION;
+ /* avoid overflow by taking the maximum */
+ a_max = 0;
for(i = 0; i < argc; i++) {
- if (JS_ToFloat64(ctx, &a, argv[i]))
+ if (JS_ToFloat64(ctx, &a, argv[i])) {
+ js_free(ctx, tab);
return JS_EXCEPTION;
- r += a;
+ }
+ a = fabs(a);
+ tab[i] = a;
+ if (a > a_max)
+ a_max = a;
+ }
+ if (a_max == 0 || !isfinite(a_max)) {
+ r = a_max;
+ } else {
+ r = 0;
+ for(i = 0; i < argc; i++) {
+ a = tab[i] / a_max;
+ r += a * a;
+ }
+ r = a_max * sqrt(r);
}
- r = sqrt(r);
+ js_free(ctx, tab);
}
return JS_NewFloat64(ctx, r);
}
@@ -45234,10 +45270,10 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va
}
JS_FreeValue(ctx, ret);
if (magic == 0) {
- then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 1,
+ then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
0, 1, argv);
} else {
- then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 1,
+ then_func = JS_NewCFunctionData(ctx, js_promise_finally_thrower, 0,
0, 1, argv);
}
if (JS_IsException(then_func)) {
@@ -50037,7 +50073,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int special)
{
JSObject *p;
- int len, tag, is_int, is_big, k, stop, inc, res = -1;
+ int len, tag, is_int, is_bigint, k, stop, inc, res = -1;
int64_t v64;
double d;
float f;
@@ -50080,7 +50116,11 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
inc = 1;
}
- is_big = 0;
+ if (validate_typed_array(ctx, this_val))
+ goto exception;
+ p = JS_VALUE_GET_OBJ(this_val);
+
+ is_bigint = 0;
is_int = 0; /* avoid warning */
v64 = 0; /* avoid warning */
tag = JS_VALUE_GET_NORM_TAG(argv[0]);
@@ -50095,10 +50135,20 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
is_int = (v64 == d);
} else
#ifdef CONFIG_BIGNUM
- if (tag == JS_TAG_BIG_INT || tag == JS_TAG_BIG_FLOAT) {
- /* will a generic loop for bigint and bigfloat */
- /* XXX: should use the generic loop in math_mode? */
- is_big = 1;
+ if (tag == JS_TAG_BIG_INT) {
+ JSBigFloat *p1 = JS_VALUE_GET_PTR(argv[0]);
+
+ if (p->class_id == JS_CLASS_BIG_INT64_ARRAY) {
+ if (bf_get_int64(&v64, &p1->num, 0) != 0)
+ goto done;
+ } else if (p->class_id == JS_CLASS_BIG_UINT64_ARRAY) {
+ if (bf_get_uint64((uint64_t *)&v64, &p1->num) != 0)
+ goto done;
+ } else {
+ goto done;
+ }
+ d = 0;
+ is_bigint = 1;
} else
#endif
{
@@ -50172,7 +50222,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
}
break;
case JS_CLASS_FLOAT32_ARRAY:
- if (is_big)
+ if (is_bigint)
break;
if (isnan(d)) {
const float *pv = p->u.array.u.float_ptr;
@@ -50196,7 +50246,7 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
}
break;
case JS_CLASS_FLOAT64_ARRAY:
- if (is_big)
+ if (is_bigint)
break;
if (isnan(d)) {
const double *pv = p->u.array.u.double_ptr;
@@ -50221,20 +50271,22 @@ static JSValue js_typed_array_indexOf(JSContext *ctx, JSValueConst this_val,
break;
#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT64_ARRAY:
+ if (is_bigint || (is_math_mode(ctx) && is_int &&
+ v64 >= -MAX_SAFE_INTEGER &&
+ v64 <= MAX_SAFE_INTEGER)) {
+ goto scan64;
+ }
+ break;
case JS_CLASS_BIG_UINT64_ARRAY:
- if (is_big || is_strict_mode(ctx)) {
- /* generic loop for bignums, argv[0] is a bignum != NaN */
- /* XXX: optimize with explicit values */
+ if (is_bigint || (is_math_mode(ctx) && is_int &&
+ v64 >= 0 && v64 <= MAX_SAFE_INTEGER)) {
+ const uint64_t *pv;
+ uint64_t v;
+ scan64:
+ pv = p->u.array.u.uint64_ptr;
+ v = v64;
for (; k != stop; k += inc) {
- JSValue v = JS_GetPropertyUint32(ctx, this_val, k);
- int ret;
- if (JS_IsException(v))
- goto exception;
- ret = js_same_value_zero(ctx, v, argv[0]);
- JS_FreeValue(ctx, v);
- if (ret) {
- if (ret < 0)
- goto exception;
+ if (pv[k] == v) {
res = k;
break;
}