summaryrefslogtreecommitdiff
path: root/quickjs.c
diff options
context:
space:
mode:
authorbellard <6490144+bellard@users.noreply.github.com>2020-09-06 18:57:11 +0200
committerbellard <6490144+bellard@users.noreply.github.com>2020-09-06 18:57:11 +0200
commit0e8fffd4de4a10f498f46cd0e99f53da6a523542 (patch)
treefc80c9b15e5816b84ae7d012a1106f7f46a70332 /quickjs.c
parent91459fb6723e29e923380cec0023af93819ae69d (diff)
downloadquickjs-0e8fffd4de4a10f498f46cd0e99f53da6a523542.tar.gz
quickjs-0e8fffd4de4a10f498f46cd0e99f53da6a523542.zip
2020-01-19 release
Diffstat (limited to 'quickjs.c')
-rw-r--r--quickjs.c3206
1 files changed, 1788 insertions, 1418 deletions
diff --git a/quickjs.c b/quickjs.c
index 646af8a..b19a4d9 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -42,10 +42,6 @@
#include "list.h"
#include "quickjs.h"
#include "libregexp.h"
-
-/* enable bignums */
-#define CONFIG_BIGNUM
-
#ifdef CONFIG_BIGNUM
#include "libbf.h"
#endif
@@ -151,7 +147,8 @@ enum {
JS_CLASS_BIG_INT, /* u.object_data */
JS_CLASS_BIG_FLOAT, /* u.object_data */
JS_CLASS_FLOAT_ENV, /* u.float_env */
- JS_CLASS_BIG_DECIMAL, /* u.object_data */
+ JS_CLASS_BIG_DECIMAL, /* u.object_data */
+ JS_CLASS_OPERATOR_SET, /* u.operator_set */
#endif
JS_CLASS_MAP, /* u.map_state */
JS_CLASS_SET, /* u.map_state */
@@ -285,6 +282,7 @@ struct JSRuntime {
JSNumericOperations bigint_ops;
JSNumericOperations bigfloat_ops;
JSNumericOperations bigdecimal_ops;
+ uint32_t operator_count;
#endif
};
@@ -300,8 +298,7 @@ struct JSClass {
#define JS_MODE_STRICT (1 << 0)
#define JS_MODE_STRIP (1 << 1)
-#define JS_MODE_BIGINT (1 << 2)
-#define JS_MODE_MATH (1 << 3)
+#define JS_MODE_MATH (1 << 2)
typedef struct JSStackFrame {
struct JSStackFrame *prev_frame; /* NULL if first stack frame */
@@ -312,7 +309,7 @@ typedef struct JSStackFrame {
const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
instruction after the call */
int arg_count;
- int js_mode; /* 0 or JS_MODE_BIGINT for C functions */
+ int js_mode; /* 0 or JS_MODE_MATH for C functions */
/* only used in generators. Current stack pointer value. NULL if
the function is running. */
JSValue *cur_sp;
@@ -419,8 +416,8 @@ struct JSContext {
#ifdef CONFIG_BIGNUM
bf_context_t *bf_ctx; /* points to rt->bf_ctx, shared by all contexts */
JSFloatEnv fp_env; /* global FP environment */
- BOOL bignum_ext; /* enable bigint mode, math mode and operator
- overloading */
+ BOOL bignum_ext : 8; /* enable math mode */
+ BOOL allow_operator_overloading : 8;
#endif
/* when the counter reaches zero, JSRutime.interrupt_handler is called */
int interrupt_counter;
@@ -653,6 +650,53 @@ typedef struct JSAsyncFunctionData {
JSAsyncFunctionState func_state;
} JSAsyncFunctionData;
+typedef enum {
+ /* binary operators */
+ JS_OVOP_ADD,
+ JS_OVOP_SUB,
+ JS_OVOP_MUL,
+ JS_OVOP_DIV,
+ JS_OVOP_MOD,
+ JS_OVOP_POW,
+ JS_OVOP_OR,
+ JS_OVOP_AND,
+ JS_OVOP_XOR,
+ JS_OVOP_SHL,
+ JS_OVOP_SAR,
+ JS_OVOP_SHR,
+ JS_OVOP_EQ,
+ JS_OVOP_LESS,
+
+ JS_OVOP_BINARY_COUNT,
+ /* unary operators */
+ JS_OVOP_POS = JS_OVOP_BINARY_COUNT,
+ JS_OVOP_NEG,
+ JS_OVOP_INC,
+ JS_OVOP_DEC,
+ JS_OVOP_NOT,
+
+ JS_OVOP_COUNT,
+} JSOverloadableOperatorEnum;
+
+typedef struct {
+ uint32_t operator_index;
+ JSObject *ops[JS_OVOP_BINARY_COUNT]; /* self operators */
+} JSBinaryOperatorDefEntry;
+
+typedef struct {
+ int count;
+ JSBinaryOperatorDefEntry *tab;
+} JSBinaryOperatorDef;
+
+typedef struct {
+ uint32_t operator_counter;
+ BOOL is_primitive; /* OperatorSet for a primitive type */
+ /* NULL if no operator is defined */
+ JSObject *self_ops[JS_OVOP_COUNT]; /* self operators */
+ JSBinaryOperatorDef left;
+ JSBinaryOperatorDef right;
+} JSOperatorSetData;
+
typedef struct JSReqModuleEntry {
JSAtom module_name;
JSModuleDef *module; /* used using resolution */
@@ -808,6 +852,7 @@ struct JSObject {
struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
#ifdef CONFIG_BIGNUM
struct JSFloatEnv *float_env; /* JS_CLASS_FLOAT_ENV */
+ struct JSOperatorSetData *operator_set; /* JS_CLASS_OPERATOR_SET */
#endif
struct JSMapState *map_state; /* JS_CLASS_MAP..JS_CLASS_WEAKSET */
struct JSMapIteratorData *map_iterator_data; /* JS_CLASS_MAP_ITERATOR, JS_CLASS_SET_ITERATOR */
@@ -991,6 +1036,11 @@ static void js_promise_mark(JSRuntime *rt, JSValueConst val,
static void js_promise_resolve_function_finalizer(JSRuntime *rt, JSValue val);
static void js_promise_resolve_function_mark(JSRuntime *rt, JSValueConst val,
JS_MarkFunc *mark_func);
+#ifdef CONFIG_BIGNUM
+static void js_operator_set_finalizer(JSRuntime *rt, JSValue val);
+static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
+ JS_MarkFunc *mark_func);
+#endif
static JSValue JS_ToStringFree(JSContext *ctx, JSValue val);
static int JS_ToBoolFree(JSContext *ctx, JSValue val);
static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val);
@@ -1021,10 +1071,27 @@ static JSProperty *add_property(JSContext *ctx,
JSObject *p, JSAtom prop, int prop_flags);
#ifdef CONFIG_BIGNUM
static void js_float_env_finalizer(JSRuntime *rt, JSValue val);
-static JSValue JS_NewBigFloat(JSContext *ctx, bf_t *a);
-static JSValue JS_NewBigDecimal(JSContext *ctx, bfdec_t *a);
-static JSValue JS_NewBigInt2(JSContext *ctx, bf_t *a, BOOL force_bigint);
-static JSValue JS_NewBigInt(JSContext *ctx, bf_t *a);
+static JSValue JS_NewBigFloat(JSContext *ctx);
+static inline bf_t *JS_GetBigFloat(JSValueConst val)
+{
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ return &p->num;
+}
+static JSValue JS_NewBigDecimal(JSContext *ctx);
+static inline bfdec_t *JS_GetBigDecimal(JSValueConst val)
+{
+ JSBigDecimal *p = JS_VALUE_GET_PTR(val);
+ return &p->num;
+}
+static JSValue JS_NewBigInt(JSContext *ctx);
+static inline bf_t *JS_GetBigInt(JSValueConst val)
+{
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ return &p->num;
+}
+static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
+ BOOL convert_to_safe_integer);
+static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val);
static int JS_ToBigInt64Free(JSContext *ctx, int64_t *pres, JSValue val);
static bf_t *JS_ToBigInt(JSContext *ctx, bf_t *buf, JSValueConst val);
static void JS_FreeBigInt(JSContext *ctx, bf_t *a, bf_t *buf);
@@ -1123,19 +1190,6 @@ static const JSClassExoticMethods js_proxy_exotic_methods;
static const JSClassExoticMethods js_module_ns_exotic_methods;
static JSClassID js_class_id_alloc = JS_CLASS_INIT_COUNT;
-JS_BOOL JS_IsNumber(JSValueConst v)
-{
-#ifdef CONFIG_BIGNUM
- /* XXX: check the bignum case. Should use a different function */
- int tag = JS_VALUE_GET_TAG(v);
- return tag == JS_TAG_INT || tag == JS_TAG_BIG_INT ||
- tag == JS_TAG_BIG_FLOAT || JS_TAG_IS_FLOAT64(tag);
-#else
- int tag = JS_VALUE_GET_TAG(v);
- return tag == JS_TAG_INT || JS_TAG_IS_FLOAT64(tag);
-#endif
-}
-
static void js_trigger_gc(JSRuntime *rt, size_t size)
{
BOOL force_gc;
@@ -1333,6 +1387,7 @@ static JSClassShortDef const js_std_class_def[] = {
{ JS_ATOM_BigFloat, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_FLOAT */
{ JS_ATOM_BigFloatEnv, js_float_env_finalizer, NULL }, /* JS_CLASS_FLOAT_ENV */
{ JS_ATOM_BigDecimal, js_object_data_finalizer, js_object_data_mark }, /* JS_CLASS_BIG_DECIMAL */
+ { JS_ATOM_OperatorSet, js_operator_set_finalizer, js_operator_set_mark }, /* JS_CLASS_OPERATOR_SET */
#endif
{ JS_ATOM_Map, js_map_finalizer, js_map_mark }, /* JS_CLASS_MAP */
{ JS_ATOM_Set, js_map_finalizer, js_map_mark }, /* JS_CLASS_SET */
@@ -2136,10 +2191,10 @@ static inline BOOL is_strict_mode(JSContext *ctx)
}
#ifdef CONFIG_BIGNUM
-static inline BOOL is_bigint_mode(JSContext *ctx)
+static inline BOOL is_math_mode(JSContext *ctx)
{
JSStackFrame *sf = ctx->current_stack_frame;
- return (sf && (sf->js_mode & JS_MODE_BIGINT));
+ return (sf && (sf->js_mode & JS_MODE_MATH));
}
#endif
@@ -2148,25 +2203,12 @@ JSValue JS_NewInt64(JSContext *ctx, int64_t v)
if (v == (int32_t)v) {
return JS_NewInt32(ctx, v);
} else {
-#ifdef CONFIG_BIGNUM
- if (is_bigint_mode(ctx)) {
- bf_t a_s, *a = &a_s;
- bf_init(ctx->bf_ctx, a);
- bf_set_si(a, v);
- return JS_NewBigInt(ctx, a);
- } else
-#endif
- {
- return __JS_NewFloat64(ctx, (double)v);
- }
+ return __JS_NewFloat64(ctx, (double)v);
}
}
static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
{
-#ifdef CONFIG_BIGNUM
- return JS_NewInt64(ctx, val);
-#else
JSValue v;
if (val <= 0x7fffffff) {
v = JS_MKVAL(JS_TAG_INT, val);
@@ -2174,7 +2216,6 @@ static force_inline JSValue JS_NewUint32(JSContext *ctx, uint32_t val)
v = __JS_NewFloat64(ctx, val);
}
return v;
-#endif
}
/* JSAtom support */
@@ -5720,6 +5761,7 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
#ifdef CONFIG_BIGNUM
case JS_CLASS_BIG_INT: /* u.object_data */
case JS_CLASS_BIG_FLOAT: /* u.object_data */
+ case JS_CLASS_BIG_DECIMAL: /* u.object_data */
#endif
compute_value_size(p->u.object_data, hp);
break;
@@ -6515,28 +6557,17 @@ JSValueConst JS_GetPrototype(JSContext *ctx, JSValueConst val)
case JS_TAG_BIG_INT:
val = ctx->class_proto[JS_CLASS_BIG_INT];
break;
- case JS_TAG_INT:
- if (is_bigint_mode(ctx)) {
- val = ctx->class_proto[JS_CLASS_BIG_INT];
- } else {
- val = ctx->class_proto[JS_CLASS_NUMBER];
- }
- break;
- case JS_TAG_FLOAT64:
- val = ctx->class_proto[JS_CLASS_NUMBER];
- break;
case JS_TAG_BIG_FLOAT:
val = ctx->class_proto[JS_CLASS_BIG_FLOAT];
break;
case JS_TAG_BIG_DECIMAL:
val = ctx->class_proto[JS_CLASS_BIG_DECIMAL];
break;
-#else
+#endif
case JS_TAG_INT:
case JS_TAG_FLOAT64:
val = ctx->class_proto[JS_CLASS_NUMBER];
break;
-#endif
case JS_TAG_BOOL:
val = ctx->class_proto[JS_CLASS_BOOLEAN];
break;
@@ -7750,11 +7781,7 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSProperty *prop,
}
p->u.array.count = len;
}
-#ifdef CONFIG_BIGNUM
- set_value(ctx, &prop->u.value, JS_NewUint32(ctx, len));
-#else
prop->u.value = JS_NewUint32(ctx, len);
-#endif
} else {
/* Note: length is always a uint32 because the object is an
array */
@@ -9352,9 +9379,6 @@ void *JS_GetOpaque2(JSContext *ctx, JSValueConst obj, JSClassID class_id)
#define HINT_STRING 0
#define HINT_NUMBER 1
#define HINT_NONE 2
-#ifdef CONFIG_BIGNUM
-#define HINT_INTEGER 3
-#endif
/* don't try Symbol.toPrimitive */
#define HINT_FORCE_ORDINARY (1 << 4)
@@ -9389,11 +9413,6 @@ static JSValue JS_ToPrimitiveFree(JSContext *ctx, JSValue val, int hint)
case HINT_NONE:
atom = JS_ATOM_default;
break;
-#ifdef CONFIG_BIGNUM
- case HINT_INTEGER:
- atom = JS_ATOM_integer;
- break;
-#endif
}
arg = JS_AtomToString(ctx, atom);
ret = JS_CallFree(ctx, method, val, 1, (JSValueConst *)&arg);
@@ -9605,22 +9624,31 @@ static JSValue js_string_to_bigint(JSContext *ctx, const char *buf,
{
bf_t a_s, *a = &a_s;
int ret;
- bf_init(ctx->bf_ctx, a);
+ JSValue val;
+ val = JS_NewBigInt(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigInt(val);
ret = bf_atof(a, buf, NULL, radix, BF_PREC_INF, BF_RNDZ);
if (ret & BF_ST_MEM_ERROR) {
- bf_delete(a);
+ JS_FreeValue(ctx, val);
return JS_ThrowOutOfMemory(ctx);
}
- return JS_NewBigInt2(ctx, a, !(flags & ATOD_MODE_BIGINT));
+ val = JS_CompactBigInt1(ctx, val, (flags & ATOD_MODE_BIGINT) != 0);
+ return val;
}
static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
int radix, int flags, slimb_t *pexponent)
{
- bf_t a_s, *a = &a_s;
+ bf_t *a;
int ret;
-
- bf_init(ctx->bf_ctx, a);
+ JSValue val;
+
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigFloat(val);
if (flags & ATOD_ACCEPT_SUFFIX) {
/* return the exponent to get infinite precision */
ret = bf_atof2(a, pexponent, buf, NULL, radix, BF_PREC_INF,
@@ -9630,25 +9658,30 @@ static JSValue js_string_to_bigfloat(JSContext *ctx, const char *buf,
ctx->fp_env.flags);
}
if (ret & BF_ST_MEM_ERROR) {
- bf_delete(a);
+ JS_FreeValue(ctx, val);
return JS_ThrowOutOfMemory(ctx);
}
- return JS_NewBigFloat(ctx, a);
+ return val;
}
static JSValue js_string_to_bigdecimal(JSContext *ctx, const char *buf,
int radix, int flags, slimb_t *pexponent)
{
- bfdec_t a_s, *a = &a_s;
+ bfdec_t *a;
int ret;
- bfdec_init(ctx->bf_ctx, a);
+ JSValue val;
+
+ val = JS_NewBigDecimal(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigDecimal(val);
ret = bfdec_atof(a, buf, NULL, BF_PREC_INF,
BF_RNDZ | BF_ATOF_NO_NAN_INF);
if (ret & BF_ST_MEM_ERROR) {
- bfdec_delete(a);
+ JS_FreeValue(ctx, val);
return JS_ThrowOutOfMemory(ctx);
}
- return JS_NewBigDecimal(ctx, a);
+ return val;
}
#endif
@@ -9730,10 +9763,12 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
strstart(p, "Infinity", &p)) {
#ifdef CONFIG_BIGNUM
if (atod_type == ATOD_TYPE_BIG_FLOAT) {
- bf_t a_s, *a = &a_s;
- bf_init(ctx->bf_ctx, a);
+ bf_t *a;
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ goto done;
+ a = JS_GetBigFloat(val);
bf_set_inf(a, is_neg);
- val = JS_NewBigFloat(ctx, a);
} else
#endif
{
@@ -9810,7 +9845,7 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
} else if (*p == 'l') {
p++;
atod_type = ATOD_TYPE_BIG_FLOAT;
- } else if (*p == 'd') {
+ } else if (*p == 'm') {
p++;
atod_type = ATOD_TYPE_BIG_DECIMAL;
} else {
@@ -9901,7 +9936,6 @@ static JSValue js_atof(JSContext *ctx, const char *str, const char **pp,
typedef enum JSToNumberHintEnum {
TON_FLAG_NUMBER,
- TON_FLAG_INTEGER,
TON_FLAG_NUMERIC,
} JSToNumberHintEnum;
@@ -9910,7 +9944,6 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
{
uint32_t tag;
JSValue ret;
- int hint;
redo:
tag = JS_VALUE_GET_NORM_TAG(val);
@@ -9924,12 +9957,19 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
ret = val;
break;
case JS_TAG_BIG_INT:
- if (flag == TON_FLAG_NUMBER && !is_bigint_mode(ctx)) {
+ if (flag != TON_FLAG_NUMERIC) {
JS_FreeValue(ctx, val);
return JS_ThrowTypeError(ctx, "cannot convert bigint to number");
}
- /* fall thru */
+ ret = val;
+ break;
case JS_TAG_BIG_FLOAT:
+ if (flag != TON_FLAG_NUMERIC) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowTypeError(ctx, "cannot convert bigfloat to number");
+ }
+ ret = val;
+ break;
#endif
case JS_TAG_FLOAT64:
case JS_TAG_INT:
@@ -9944,12 +9984,7 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
ret = JS_NAN;
break;
case JS_TAG_OBJECT:
-#ifdef CONFIG_BIGNUM
- hint = flag == TON_FLAG_INTEGER ? HINT_INTEGER : HINT_NUMBER;
-#else
- hint = HINT_NUMBER;
-#endif
- val = JS_ToPrimitiveFree(ctx, val, hint);
+ val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
if (JS_IsException(val))
return JS_EXCEPTION;
goto redo;
@@ -9969,10 +10004,6 @@ static JSValue JS_ToNumberHintFree(JSContext *ctx, JSValue val,
ret = JS_NewInt32(ctx, 0);
} else {
int flags = ATOD_ACCEPT_BIN_OCT;
-#ifdef CONFIG_BIGNUM
- if (is_bigint_mode(ctx))
- flags |= ATOD_MODE_BIGINT;
-#endif
ret = js_atof(ctx, p, &p, 0, flags);
if (!JS_IsException(ret)) {
p += skip_spaces(p);
@@ -10001,7 +10032,6 @@ static JSValue JS_ToNumberFree(JSContext *ctx, JSValue val)
return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMBER);
}
-#ifdef CONFIG_BIGNUM
static JSValue JS_ToNumericFree(JSContext *ctx, JSValue val)
{
return JS_ToNumberHintFree(ctx, val, TON_FLAG_NUMERIC);
@@ -10011,7 +10041,6 @@ static JSValue JS_ToNumeric(JSContext *ctx, JSValueConst val)
{
return JS_ToNumericFree(ctx, JS_DupValue(ctx, val));
}
-#endif
static __exception int __JS_ToFloat64Free(JSContext *ctx, double *pres,
JSValue val)
@@ -10078,6 +10107,7 @@ static JSValue JS_ToNumber(JSContext *ctx, JSValueConst val)
return JS_ToNumberFree(ctx, JS_DupValue(ctx, val));
}
+/* same as JS_ToNumber() but return 0 in case of NaN/Undefined */
static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
{
uint32_t tag;
@@ -10106,11 +10136,6 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
}
break;
#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_INT:
- if (!is_bigint_mode(ctx))
- goto to_number;
- ret = val;
- break;
case JS_TAG_BIG_FLOAT:
{
bf_t a_s, *a, r_s, *r = &r_s;
@@ -10124,10 +10149,13 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
else
ret = JS_DupValue(ctx, val);
} else {
- bf_init(ctx->bf_ctx, r);
- bf_set(r, a);
- bf_rint(r, BF_RNDZ);
- ret = JS_NewBigInt(ctx, r);
+ ret = JS_NewBigInt(ctx);
+ if (!JS_IsException(ret)) {
+ r = JS_GetBigInt(ret);
+ bf_set(r, a);
+ bf_rint(r, BF_RNDZ);
+ ret = JS_CompactBigInt(ctx, ret);
+ }
}
if (a == &a_s)
bf_delete(a);
@@ -10136,9 +10164,6 @@ static __maybe_unused JSValue JS_ToIntegerFree(JSContext *ctx, JSValue val)
break;
#endif
default:
-#ifdef CONFIG_BIGNUM
- to_number:
-#endif
val = JS_ToNumberFree(ctx, val);
if (JS_IsException(val))
return val;
@@ -10182,17 +10207,12 @@ static int JS_ToInt32SatFree(JSContext *ctx, int *pres, JSValue val)
break;
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
- to_bf:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
bf_get_int32(&ret, &p->num, 0);
JS_FreeValue(ctx, val);
}
break;
- case JS_TAG_BIG_INT:
- if (is_bigint_mode(ctx))
- goto to_bf;
- /* fall thru */
#endif
default:
val = JS_ToNumberFree(ctx, val);
@@ -10261,17 +10281,12 @@ static int JS_ToInt64SatFree(JSContext *ctx, int64_t *pres, JSValue val)
return 0;
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
- to_bf:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
bf_get_int64(pres, &p->num, 0);
JS_FreeValue(ctx, val);
}
return 0;
- case JS_TAG_BIG_INT:
- if (is_bigint_mode(ctx))
- goto to_bf;
- /* fall thru */
#endif
default:
val = JS_ToNumberFree(ctx, val);
@@ -10346,17 +10361,12 @@ static int JS_ToInt64Free(JSContext *ctx, int64_t *pres, JSValue val)
break;
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
- to_bf:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
bf_get_int64(&ret, &p->num, BF_GET_INT_MOD);
JS_FreeValue(ctx, val);
}
break;
- case JS_TAG_BIG_INT:
- if (is_bigint_mode(ctx))
- goto to_bf;
- /* fall thru */
#endif
default:
val = JS_ToNumberFree(ctx, val);
@@ -10418,17 +10428,12 @@ static int JS_ToInt32Free(JSContext *ctx, int32_t *pres, JSValue val)
break;
#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_FLOAT:
- to_bf:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
bf_get_int32(&ret, &p->num, BF_GET_INT_MOD);
JS_FreeValue(ctx, val);
}
break;
- case JS_TAG_BIG_INT:
- if (is_bigint_mode(ctx))
- goto to_bf;
- /* fall thru */
#endif
default:
val = JS_ToNumberFree(ctx, val);
@@ -10486,15 +10491,6 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
}
break;
#ifdef CONFIG_BIGNUM
- case JS_TAG_BIG_INT:
- {
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- if (!is_bigint_mode(ctx))
- goto to_number;
- bf_get_int32(&res, &p->num, 0);
- JS_FreeValue(ctx, val);
- }
- goto int_clamp;
case JS_TAG_BIG_FLOAT:
{
JSBigFloat *p = JS_VALUE_GET_PTR(val);
@@ -10509,9 +10505,6 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
goto int_clamp;
#endif
default:
-#ifdef CONFIG_BIGNUM
- to_number:
-#endif
val = JS_ToNumberFree(ctx, val);
if (JS_IsException(val)) {
*pres = 0;
@@ -10584,6 +10577,12 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
#define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
+static BOOL is_safe_integer(double d)
+{
+ return isfinite(d) && floor(d) == d &&
+ fabs(d) <= (double)MAX_SAFE_INTEGER;
+}
+
int JS_ToIndex(JSContext *ctx, uint64_t *plen, JSValueConst val)
{
int64_t v;
@@ -10609,7 +10608,6 @@ static __exception int JS_ToLengthFree(JSContext *ctx, int64_t *plen,
}
/* Note: can return an exception */
-/* XXX: bignum case */
static int JS_NumberIsInteger(JSContext *ctx, JSValueConst val)
{
double d;
@@ -10753,7 +10751,8 @@ static JSValue js_bigfloat_to_string(JSContext *ctx, JSValueConst val)
return js_ftoa(ctx, val, 10, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
}
-static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
+static JSValue js_bigdecimal_to_string1(JSContext *ctx, JSValueConst val,
+ limb_t prec, int flags)
{
JSValue ret;
bfdec_t *a;
@@ -10764,8 +10763,7 @@ static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
saved_sign = a->sign;
if (a->expn == BF_EXP_ZERO)
a->sign = 0;
- str = bfdec_ftoa(NULL, a, 0, BF_RNDZ | BF_FTOA_FORMAT_FREE |
- BF_FTOA_JS_QUIRKS);
+ str = bfdec_ftoa(NULL, a, prec, flags | BF_FTOA_JS_QUIRKS);
a->sign = saved_sign;
if (!str)
return JS_ThrowOutOfMemory(ctx);
@@ -10774,6 +10772,12 @@ static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
return ret;
}
+static JSValue js_bigdecimal_to_string(JSContext *ctx, JSValueConst val)
+{
+ return js_bigdecimal_to_string1(ctx, val, 0,
+ BF_RNDZ | BF_FTOA_FORMAT_FREE);
+}
+
#endif /* CONFIG_BIGNUM */
/* 2 <= base <= 36 */
@@ -11478,30 +11482,48 @@ static double js_pow(double a, double b)
#ifdef CONFIG_BIGNUM
+JSValue JS_NewBigInt64_1(JSContext *ctx, int64_t v)
+{
+ JSValue val;
+ bf_t *a;
+ val = JS_NewBigInt(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigInt(val);
+ if (bf_set_si(a, v)) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowOutOfMemory(ctx);
+ }
+ return val;
+}
+
JSValue JS_NewBigInt64(JSContext *ctx, int64_t v)
{
- BOOL is_bignum = is_bigint_mode(ctx);
- if (is_bignum && v == (int32_t)v) {
- return JS_NewInt32(ctx, v);
+ if (is_math_mode(ctx) &&
+ v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
+ return JS_NewInt64(ctx, v);
} else {
- bf_t a_s, *a = &a_s;
- bf_init(ctx->bf_ctx, a);
- bf_set_si(a, v);
- return JS_NewBigInt2(ctx, a, TRUE);
+ return JS_NewBigInt64_1(ctx, v);
}
}
JSValue JS_NewBigUint64(JSContext *ctx, uint64_t v)
{
- BOOL is_bignum = is_bigint_mode(ctx);
- if (is_bignum && v == (int32_t)v) {
- return JS_NewInt32(ctx, v);
+ JSValue val;
+ if (is_math_mode(ctx) && v <= MAX_SAFE_INTEGER) {
+ val = JS_NewInt64(ctx, v);
} else {
- bf_t a_s, *a = &a_s;
- bf_init(ctx->bf_ctx, a);
- bf_set_ui(a, v);
- return JS_NewBigInt2(ctx, a, TRUE);
+ bf_t *a;
+ val = JS_NewBigInt(ctx);
+ if (JS_IsException(val))
+ return val;
+ a = JS_GetBigInt(val);
+ if (bf_set_ui(a, v)) {
+ JS_FreeValue(ctx, val);
+ return JS_ThrowOutOfMemory(ctx);
+ }
}
+ return val;
}
/* if the returned bigfloat is allocated it is equal to
@@ -11582,13 +11604,10 @@ static JSValue JS_StringToBigInt(JSContext *ctx, JSValue val)
p = str;
p += skip_spaces(p);
if ((p - str) == len) {
- bf_t a_s, *a = &a_s;
- bf_init(ctx->bf_ctx, a);
- bf_set_si(a, 0);
- val = JS_NewBigInt(ctx, a);
+ val = JS_NewBigInt64(ctx, 0);
} else {
flags = ATOD_INT_ONLY | ATOD_ACCEPT_BIN_OCT | ATOD_TYPE_BIG_INT;
- if (is_bigint_mode(ctx))
+ if (is_math_mode(ctx))
flags |= ATOD_MODE_BIGINT;
val = js_atof(ctx, p, &p, 0, flags);
p += skip_spaces(p);
@@ -11625,7 +11644,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
case JS_TAG_INT:
case JS_TAG_NULL:
case JS_TAG_UNDEFINED:
- if (!is_bigint_mode(ctx))
+ if (!is_math_mode(ctx))
goto fail;
/* fall tru */
case JS_TAG_BOOL:
@@ -11636,7 +11655,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
case JS_TAG_FLOAT64:
{
double d = JS_VALUE_GET_FLOAT64(val);
- if (!is_bigint_mode(ctx))
+ if (!is_math_mode(ctx))
goto fail;
if (!isfinite(d))
goto fail;
@@ -11651,7 +11670,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
r = &p->num;
break;
case JS_TAG_BIG_FLOAT:
- if (!is_bigint_mode(ctx))
+ if (!is_math_mode(ctx))
goto fail;
p = JS_VALUE_GET_PTR(val);
if (!bf_is_finite(&p->num))
@@ -11668,8 +11687,7 @@ static bf_t *JS_ToBigIntFree(JSContext *ctx, bf_t *buf, JSValue val)
return NULL;
goto redo;
case JS_TAG_OBJECT:
- val = JS_ToPrimitiveFree(ctx, val,
- is_bigint_mode(ctx) ? HINT_INTEGER : HINT_NUMBER);
+ val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
if (JS_IsException(val))
return NULL;
goto redo;
@@ -11692,21 +11710,26 @@ static __maybe_unused JSValue JS_ToBigIntValueFree(JSContext *ctx, JSValue val)
if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_INT) {
return val;
} else {
- bf_t a_s, *a, b_s, *b;
+ bf_t a_s, *a, *r;
int ret;
-
+ JSValue res;
+
+ res = JS_NewBigInt(ctx);
+ if (JS_IsException(res))
+ return JS_EXCEPTION;
a = JS_ToBigIntFree(ctx, &a_s, val);
- if (!a)
+ if (!a) {
+ JS_FreeValue(ctx, res);
return JS_EXCEPTION;
- b = &b_s;
- bf_init(ctx->bf_ctx, b);
- ret = bf_set(b, a);
+ }
+ r = JS_GetBigInt(res);
+ ret = bf_set(r, a);
JS_FreeBigInt(ctx, a, &a_s);
if (ret) {
- bf_delete(b);
+ JS_FreeValue(ctx, res);
return JS_ThrowOutOfMemory(ctx);
}
- return JS_NewBigInt2(ctx, b, TRUE);
+ return JS_CompactBigInt(ctx, res);
}
}
@@ -11745,7 +11768,7 @@ int JS_ToBigInt64(JSContext *ctx, int64_t *pres, JSValueConst val)
static JSBigFloat *js_new_bf(JSContext *ctx)
{
JSBigFloat *p;
- p = js_mallocz(ctx, sizeof(*p));
+ p = js_malloc(ctx, sizeof(*p));
if (!p)
return NULL;
p->header.ref_count = 1;
@@ -11753,224 +11776,387 @@ static JSBigFloat *js_new_bf(JSContext *ctx)
return p;
}
-/* WARNING: 'a' is freed */
-static JSValue JS_NewBigFloat(JSContext *ctx, bf_t *a)
+static JSValue JS_NewBigFloat(JSContext *ctx)
{
- JSValue ret;
JSBigFloat *p;
-
- p = js_new_bf(ctx);
- bf_memcpy(&p->num, a);
- ret = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
- return ret;
+ p = js_malloc(ctx, sizeof(*p));
+ if (!p)
+ return JS_EXCEPTION;
+ p->header.ref_count = 1;
+ bf_init(ctx->bf_ctx, &p->num);
+ return JS_MKPTR(JS_TAG_BIG_FLOAT, p);
}
-/* WARNING: 'a' is freed */
-static JSValue JS_NewBigDecimal(JSContext *ctx, bfdec_t *a)
+static JSValue JS_NewBigDecimal(JSContext *ctx)
{
- JSValue ret;
JSBigDecimal *p;
-
- p = js_mallocz(ctx, sizeof(*p));
+ p = js_malloc(ctx, sizeof(*p));
if (!p)
return JS_EXCEPTION;
p->header.ref_count = 1;
bfdec_init(ctx->bf_ctx, &p->num);
- bfdec_memcpy(&p->num, a);
- ret = JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
- return ret;
+ return JS_MKPTR(JS_TAG_BIG_DECIMAL, p);
}
-/* WARNING: 'a' is freed */
-static JSValue JS_NewBigInt2(JSContext *ctx, bf_t *a, BOOL force_bigint)
+static JSValue JS_NewBigInt(JSContext *ctx)
{
- JSValue ret;
JSBigFloat *p;
- int32_t v;
-
- if (!force_bigint && bf_get_int32(&v, a, 0) == 0) {
- /* can fit in an int32 */
- ret = JS_NewInt32(ctx, v);
- bf_delete(a);
- } else {
- p = js_new_bf(ctx);
- bf_memcpy(&p->num, a);
- /* normalize the zero representation */
- if (bf_is_zero(&p->num))
- p->num.sign = 0;
- ret = JS_MKPTR(JS_TAG_BIG_INT, p);
- }
- return ret;
+ p = js_malloc(ctx, sizeof(*p));
+ if (!p)
+ return JS_EXCEPTION;
+ p->header.ref_count = 1;
+ bf_init(ctx->bf_ctx, &p->num);
+ return JS_MKPTR(JS_TAG_BIG_INT, p);
}
-static JSValue JS_NewBigInt(JSContext *ctx, bf_t *a)
+static JSValue JS_CompactBigInt1(JSContext *ctx, JSValue val,
+ BOOL convert_to_safe_integer)
{
- return JS_NewBigInt2(ctx, a, !is_bigint_mode(ctx));
+ int64_t v;
+ bf_t *a;
+
+ if (JS_VALUE_GET_TAG(val) != JS_TAG_BIG_INT)
+ return val; /* fail safe */
+ a = JS_GetBigInt(val);
+ if (convert_to_safe_integer && bf_get_int64(&v, a, 0) == 0 &&
+ v >= -MAX_SAFE_INTEGER && v <= MAX_SAFE_INTEGER) {
+ JS_FreeValue(ctx, val);
+ return JS_NewInt64(ctx, v);
+ } else if (a->expn == BF_EXP_ZERO && a->sign) {
+ JSBigFloat *p = JS_VALUE_GET_PTR(val);
+ assert(p->header.ref_count == 1);
+ a->sign = 0;
+ }
+ return val;
}
-/* return < 0 if exception, 0 if overloading method, 1 if overloading
- operator called */
-static __exception int js_call_binary_op_fallback(JSContext *ctx,
- JSValue *pret,
- JSValueConst op1,
- JSValueConst op2,
- OPCodeEnum op)
-{
- JSAtom op_name;
- JSValue method, ret, c1, c2;
- BOOL bool_result, swap_op;
- JSValueConst args[2];
+/* Convert the big int to a safe integer if in math mode. normalize
+ the zero representation. Could also be used to convert the bigint
+ to a short bigint value. The reference count of the value must be
+ 1. Cannot fail */
+static JSValue JS_CompactBigInt(JSContext *ctx, JSValue val)
+{
+ return JS_CompactBigInt1(ctx, val, is_math_mode(ctx));
+}
+
+/* must be kept in sync with JSOverloadableOperatorEnum */
+static const char *js_overloadable_operator_names[JS_OVOP_COUNT] = {
+ "+",
+ "-",
+ "*",
+ "/",
+ "%",
+ "**",
+ "|",
+ "&",
+ "^",
+ "<<",
+ ">>",
+ ">>>",
+ "==",
+ "<",
+ "pos",
+ "neg",
+ "++",
+ "--",
+ "~",
+};
- bool_result = FALSE;
- swap_op = FALSE;
- c1 = JS_UNDEFINED;
- c2 = JS_UNDEFINED;
+static int get_ovop_from_opcode(OPCodeEnum op)
+{
switch(op) {
case OP_add:
- op_name = JS_ATOM_Symbol_operatorAdd;
- break;
+ return JS_OVOP_ADD;
case OP_sub:
- op_name = JS_ATOM_Symbol_operatorSub;
- break;
+ return JS_OVOP_SUB;
case OP_mul:
- op_name = JS_ATOM_Symbol_operatorMul;
- break;
+ return JS_OVOP_MUL;
case OP_div:
- case OP_math_div:
- op_name = JS_ATOM_Symbol_operatorDiv;
- break;
+ return JS_OVOP_DIV;
case OP_mod:
- op_name = JS_ATOM_Symbol_operatorMod;
- break;
- case OP_pow:
- case OP_math_pow:
- op_name = JS_ATOM_Symbol_operatorPow;
- break;
case OP_math_mod:
- op_name = JS_ATOM_Symbol_operatorMathMod;
- break;
- case OP_shl:
- op_name = JS_ATOM_Symbol_operatorShl;
- break;
- case OP_sar:
- op_name = JS_ATOM_Symbol_operatorShr;
- break;
- case OP_and:
- op_name = JS_ATOM_Symbol_operatorAnd;
- break;
+ return JS_OVOP_MOD;
+ case OP_pow:
+ return JS_OVOP_POW;
case OP_or:
- op_name = JS_ATOM_Symbol_operatorOr;
- break;
+ return JS_OVOP_OR;
+ case OP_and:
+ return JS_OVOP_AND;
case OP_xor:
- op_name = JS_ATOM_Symbol_operatorXor;
- break;
+ return JS_OVOP_XOR;
+ case OP_shl:
+ return JS_OVOP_SHL;
+ case OP_sar:
+ return JS_OVOP_SAR;
+ case OP_shr:
+ return JS_OVOP_SHR;
+ case OP_eq:
+ case OP_neq:
+ return JS_OVOP_EQ;
case OP_lt:
- op_name = JS_ATOM_Symbol_operatorCmpLT;
- bool_result = TRUE;
- break;
case OP_lte:
- op_name = JS_ATOM_Symbol_operatorCmpLE;
- bool_result = TRUE;
- break;
case OP_gt:
- op_name = JS_ATOM_Symbol_operatorCmpLT;
- bool_result = TRUE;
- swap_op = TRUE;
- break;
case OP_gte:
- op_name = JS_ATOM_Symbol_operatorCmpLE;
- bool_result = TRUE;
- swap_op = TRUE;
- break;
- case OP_eq:
- case OP_neq:
- op_name = JS_ATOM_Symbol_operatorCmpEQ;
- bool_result = TRUE;
- break;
+ return JS_OVOP_LESS;
+ case OP_plus:
+ return JS_OVOP_POS;
+ case OP_neg:
+ return JS_OVOP_NEG;
+ case OP_inc:
+ return JS_OVOP_INC;
+ case OP_dec:
+ return JS_OVOP_DEC;
default:
- goto fail;
+ abort();
}
- c1 = JS_GetProperty(ctx, op1, JS_ATOM_constructor);
- if (JS_IsException(c1))
+}
+
+/* return NULL if not present */
+static JSObject *find_binary_op(JSBinaryOperatorDef *def,
+ uint32_t operator_index,
+ JSOverloadableOperatorEnum op)
+{
+ JSBinaryOperatorDefEntry *ent;
+ int i;
+ for(i = 0; i < def->count; i++) {
+ ent = &def->tab[i];
+ if (ent->operator_index == operator_index)
+ return ent->ops[op];
+ }
+ return NULL;
+}
+
+/* return -1 if exception, 0 if no operator overloading, 1 if
+ overloaded operator called */
+static __exception int js_call_binary_op_fallback(JSContext *ctx,
+ JSValue *pret,
+ JSValueConst op1,
+ JSValueConst op2,
+ OPCodeEnum op,
+ BOOL is_numeric,
+ int hint)
+{
+ JSValue opset1_obj, opset2_obj, method, ret, new_op1, new_op2;
+ JSOperatorSetData *opset1, *opset2;
+ JSOverloadableOperatorEnum ovop;
+ JSObject *p;
+ JSValueConst args[2];
+
+ if (!ctx->allow_operator_overloading)
+ return 0;
+
+ opset2_obj = JS_UNDEFINED;
+ opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset1_obj))
goto exception;
- c2 = JS_GetProperty(ctx, op2, JS_ATOM_constructor);
- if (JS_IsException(c2))
+ if (JS_IsUndefined(opset1_obj))
+ return 0;
+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset1)
goto exception;
- if (JS_VALUE_GET_TAG(c1) != JS_TAG_OBJECT ||
- JS_VALUE_GET_TAG(c2) != JS_TAG_OBJECT)
- goto fail;
- if (JS_VALUE_GET_OBJ(c1) == JS_VALUE_GET_OBJ(c2)) {
- /* if same constructor, there is no ambiguity */
- method = JS_GetProperty(ctx, c1, op_name);
+
+ opset2_obj = JS_GetProperty(ctx, op2, JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset2_obj))
+ goto exception;
+ if (JS_IsUndefined(opset2_obj)) {
+ JS_FreeValue(ctx, opset1_obj);
+ return 0;
+ }
+ opset2 = JS_GetOpaque2(ctx, opset2_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset2)
+ goto exception;
+
+ if (opset1->is_primitive && opset2->is_primitive) {
+ JS_FreeValue(ctx, opset1_obj);
+ JS_FreeValue(ctx, opset2_obj);
+ return 0;
+ }
+
+ ovop = get_ovop_from_opcode(op);
+
+ if (opset1->operator_counter == opset2->operator_counter) {
+ p = opset1->self_ops[ovop];
+ } else if (opset1->operator_counter > opset2->operator_counter) {
+ p = find_binary_op(&opset1->left, opset2->operator_counter, ovop);
} else {
- JSValue val;
- int order1, order2;
+ p = find_binary_op(&opset2->right, opset1->operator_counter, ovop);
+ }
+ if (!p) {
+ JS_ThrowTypeError(ctx, "operator %s: no function defined",
+ js_overloadable_operator_names[ovop]);
+ goto exception;
+ }
- /* different constructors: we use a user-defined ordering */
- val = JS_GetProperty(ctx, c1, JS_ATOM_Symbol_operatorOrder);
- if (JS_IsException(val))
- goto exception;
- if (JS_IsUndefined(val))
- goto undef_order;
- if (JS_ToInt32Free(ctx, &order1, val))
- goto exception;
- val = JS_GetProperty(ctx, c2, JS_ATOM_Symbol_operatorOrder);
- if (JS_IsException(val))
- goto exception;
- if (JS_IsUndefined(val)) {
- undef_order:
- JS_FreeValue(ctx, c1);
- JS_FreeValue(ctx, c2);
- *pret = JS_UNDEFINED;
- return 0;
+ if (opset1->is_primitive) {
+ if (is_numeric) {
+ new_op1 = JS_ToNumeric(ctx, op1);
+ } else {
+ new_op1 = JS_ToPrimitive(ctx, op1, hint);
}
- if (JS_ToInt32Free(ctx, &order2, val))
- goto exception;
- /* ambiguous priority: error */
- if (order1 == order2) {
- JS_ThrowTypeError(ctx, "operator_order is identical in both constructors");
+ if (JS_IsException(new_op1))
goto exception;
- }
- if (order1 > order2) {
- val = c1;
+ } else {
+ new_op1 = JS_DupValue(ctx, op1);
+ }
+
+ if (opset2->is_primitive) {
+ if (is_numeric) {
+ new_op2 = JS_ToNumeric(ctx, op2);
} else {
- val = c2;
+ new_op2 = JS_ToPrimitive(ctx, op2, hint);
}
- method = JS_GetProperty(ctx, val, op_name);
- }
- JS_FreeValue(ctx, c1);
- JS_FreeValue(ctx, c2);
- c1 = JS_UNDEFINED;
- c2 = JS_UNDEFINED;
- if (JS_IsException(method))
- goto exception;
- if (JS_IsUndefined(method) || JS_IsNull(method)) {
- *pret = JS_UNDEFINED;
- return 0;
+ if (JS_IsException(new_op2)) {
+ JS_FreeValue(ctx, new_op1);
+ goto exception;
+ }
+ } else {
+ new_op2 = JS_DupValue(ctx, op2);
}
- if (swap_op) {
- args[0] = op2;
- args[1] = op1;
+
+ /* XXX: could apply JS_ToPrimitive() if primitive type so that the
+ operator function does not get a value object */
+
+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ if (ovop == JS_OVOP_LESS && (op == OP_lte || op == OP_gt)) {
+ args[0] = new_op2;
+ args[1] = new_op1;
} else {
- args[0] = op1;
- args[1] = op2;
+ args[0] = new_op1;
+ args[1] = new_op2;
}
ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
+ JS_FreeValue(ctx, new_op1);
+ JS_FreeValue(ctx, new_op2);
if (JS_IsException(ret))
goto exception;
- if (bool_result) {
+ if (ovop == JS_OVOP_EQ) {
BOOL res = JS_ToBoolFree(ctx, ret);
if (op == OP_neq)
res ^= 1;
ret = JS_NewBool(ctx, res);
+ } else if (ovop == JS_OVOP_LESS) {
+ if (JS_IsUndefined(ret)) {
+ ret = JS_FALSE;
+ } else {
+ BOOL res = JS_ToBoolFree(ctx, ret);
+ if (op == OP_lte || op == OP_gte)
+ res ^= 1;
+ ret = JS_NewBool(ctx, res);
+ }
}
+ JS_FreeValue(ctx, opset1_obj);
+ JS_FreeValue(ctx, opset2_obj);
*pret = ret;
return 1;
- fail:
- JS_ThrowTypeError(ctx, "invalid types for binary operator");
exception:
- JS_FreeValue(ctx, c1);
- JS_FreeValue(ctx, c2);
+ JS_FreeValue(ctx, opset1_obj);
+ JS_FreeValue(ctx, opset2_obj);
+ *pret = JS_UNDEFINED;
+ return -1;
+}
+
+/* try to call the operation on the operatorSet field of 'obj'. Only
+ used for "/" and "**" on the BigInt prototype in math mode */
+static __exception int js_call_binary_op_simple(JSContext *ctx,
+ JSValue *pret,
+ JSValueConst obj,
+ JSValueConst op1,
+ JSValueConst op2,
+ OPCodeEnum op)
+{
+ JSValue opset1_obj, method, ret, new_op1, new_op2;
+ JSOperatorSetData *opset1;
+ JSOverloadableOperatorEnum ovop;
+ JSObject *p;
+ JSValueConst args[2];
+
+ opset1_obj = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset1_obj))
+ goto exception;
+ if (JS_IsUndefined(opset1_obj))
+ return 0;
+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset1)
+ goto exception;
+ ovop = get_ovop_from_opcode(op);
+
+ p = opset1->self_ops[ovop];
+ if (!p) {
+ JS_FreeValue(ctx, opset1_obj);
+ return 0;
+ }
+
+ new_op1 = JS_ToNumeric(ctx, op1);
+ if (JS_IsException(new_op1))
+ goto exception;
+ new_op2 = JS_ToNumeric(ctx, op2);
+ if (JS_IsException(new_op2)) {
+ JS_FreeValue(ctx, new_op1);
+ goto exception;
+ }
+
+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ args[0] = new_op1;
+ args[1] = new_op2;
+ ret = JS_CallFree(ctx, method, JS_UNDEFINED, 2, args);
+ JS_FreeValue(ctx, new_op1);
+ JS_FreeValue(ctx, new_op2);
+ if (JS_IsException(ret))
+ goto exception;
+ JS_FreeValue(ctx, opset1_obj);
+ *pret = ret;
+ return 1;
+ exception:
+ JS_FreeValue(ctx, opset1_obj);
+ *pret = JS_UNDEFINED;
+ return -1;
+}
+
+/* return -1 if exception, 0 if no operator overloading, 1 if
+ overloaded operator called */
+static __exception int js_call_unary_op_fallback(JSContext *ctx,
+ JSValue *pret,
+ JSValueConst op1,
+ OPCodeEnum op)
+{
+ JSValue opset1_obj, method, ret;
+ JSOperatorSetData *opset1;
+ JSOverloadableOperatorEnum ovop;
+ JSObject *p;
+
+ if (!ctx->allow_operator_overloading)
+ return 0;
+
+ opset1_obj = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset1_obj))
+ goto exception;
+ if (JS_IsUndefined(opset1_obj))
+ return 0;
+ opset1 = JS_GetOpaque2(ctx, opset1_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset1)
+ goto exception;
+ if (opset1->is_primitive) {
+ JS_FreeValue(ctx, opset1_obj);
+ return 0;
+ }
+
+ ovop = get_ovop_from_opcode(op);
+
+ p = opset1->self_ops[ovop];
+ if (!p) {
+ JS_ThrowTypeError(ctx, "no overloaded operator %s",
+ js_overloadable_operator_names[ovop]);
+ goto exception;
+ }
+ method = JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ ret = JS_CallFree(ctx, method, JS_UNDEFINED, 1, &op1);
+ if (JS_IsException(ret))
+ goto exception;
+ JS_FreeValue(ctx, opset1_obj);
+ *pret = ret;
+ return 1;
+ exception:
+ JS_FreeValue(ctx, opset1_obj);
*pret = JS_UNDEFINED;
return -1;
}
@@ -11993,16 +12179,22 @@ static JSValue throw_bf_exception(JSContext *ctx, int status)
static int js_unary_arith_bigint(JSContext *ctx,
JSValue *pres, OPCodeEnum op, JSValue op1)
{
- bf_t a_s, r_s, *r = &r_s, *a;
+ bf_t a_s, *r, *a;
int ret, v;
+ JSValue res;
- if (op == OP_plus && !is_bigint_mode(ctx)) {
+ if (op == OP_plus && !is_math_mode(ctx)) {
JS_ThrowTypeError(ctx, "bigint argument with unary +");
JS_FreeValue(ctx, op1);
return -1;
}
+ res = JS_NewBigInt(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ r = JS_GetBigInt(res);
a = JS_ToBigInt(ctx, &a_s, op1);
- bf_init(ctx->bf_ctx, r);
ret = 0;
switch(op) {
case OP_inc:
@@ -12027,28 +12219,35 @@ static int js_unary_arith_bigint(JSContext *ctx,
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeValue(ctx, op1);
if (unlikely(ret)) {
- bf_delete(r);
+ JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
- *pres = JS_NewBigInt(ctx, r);
+ res = JS_CompactBigInt(ctx, res);
+ *pres = res;
return 0;
}
static int js_unary_arith_bigfloat(JSContext *ctx,
JSValue *pres, OPCodeEnum op, JSValue op1)
{
- bf_t a_s, r_s, *r = &r_s, *a;
+ bf_t a_s, *r, *a;
int ret, v;
+ JSValue res;
- if (op == OP_plus && !is_bigint_mode(ctx)) {
+ if (op == OP_plus && !is_math_mode(ctx)) {
JS_ThrowTypeError(ctx, "bigfloat argument with unary +");
JS_FreeValue(ctx, op1);
return -1;
}
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ r = JS_GetBigFloat(res);
a = JS_ToBigFloat(ctx, &a_s, op1);
- bf_init(ctx->bf_ctx, r);
ret = 0;
switch(op) {
case OP_inc:
@@ -12070,28 +12269,34 @@ static int js_unary_arith_bigfloat(JSContext *ctx,
bf_delete(a);
JS_FreeValue(ctx, op1);
if (unlikely(ret & BF_ST_MEM_ERROR)) {
- bf_delete(r);
+ JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
- *pres = JS_NewBigFloat(ctx, r);
+ *pres = res;
return 0;
}
static int js_unary_arith_bigdecimal(JSContext *ctx,
JSValue *pres, OPCodeEnum op, JSValue op1)
{
- bfdec_t r_s, *r = &r_s, *a;
+ bfdec_t *r, *a;
int ret, v;
-
- if (op == OP_plus && !is_bigint_mode(ctx)) {
+ JSValue res;
+
+ if (op == OP_plus && !is_math_mode(ctx)) {
JS_ThrowTypeError(ctx, "bigdecimal argument with unary +");
JS_FreeValue(ctx, op1);
return -1;
}
+ res = JS_NewBigDecimal(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeValue(ctx, op1);
+ return -1;
+ }
+ r = JS_GetBigDecimal(res);
a = JS_ToBigDecimal(ctx, op1);
- bfdec_init(ctx->bf_ctx, r);
ret = 0;
switch(op) {
case OP_inc:
@@ -12111,11 +12316,11 @@ static int js_unary_arith_bigdecimal(JSContext *ctx,
}
JS_FreeValue(ctx, op1);
if (unlikely(ret)) {
- bfdec_delete(r);
+ JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
- *pres = JS_NewBigDecimal(ctx, r);
+ *pres = res;
return 0;
}
@@ -12123,112 +12328,93 @@ static no_inline __exception int js_unary_arith_slow(JSContext *ctx,
JSValue *sp,
OPCodeEnum op)
{
- JSValue op1, val, method;
- BOOL is_legacy;
- JSAtom op_name;
- int v;
+ JSValue op1, val;
+ int v, ret;
uint32_t tag;
op1 = sp[-1];
/* fast path for float64 */
if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(op1)))
goto handle_float64;
- if (JS_IsObject(op1) && ctx->bignum_ext) {
- switch(op) {
- case OP_plus:
- op_name = JS_ATOM_Symbol_operatorPlus;
- break;
- case OP_neg:
- op_name = JS_ATOM_Symbol_operatorNeg;
- break;
- case OP_inc:
- op_name = JS_ATOM_Symbol_operatorInc;
- break;
- case OP_dec:
- op_name = JS_ATOM_Symbol_operatorDec;
- break;
- default:
- abort();
- }
- method = JS_GetProperty(ctx, op1, op_name);
- if (JS_IsException(method))
- return -1;
- if (JS_IsUndefined(method) || JS_IsNull(method))
- goto to_number;
- val = JS_CallFree(ctx, method, op1, 0, NULL);
- if (JS_IsException(val))
+ if (JS_IsObject(op1)) {
+ ret = js_call_unary_op_fallback(ctx, &val, op1, op);
+ if (ret < 0)
return -1;
- JS_FreeValue(ctx, op1);
- sp[-1] = val;
- } else {
- to_number:
- op1 = JS_ToNumericFree(ctx, op1);
- if (JS_IsException(op1))
- goto exception;
- is_legacy = is_bigint_mode(ctx) ^ 1;
- tag = JS_VALUE_GET_TAG(op1);
- switch(tag) {
- case JS_TAG_INT:
- {
- int64_t v64;
- v64 = JS_VALUE_GET_INT(op1);
- switch(op) {
- case OP_inc:
- case OP_dec:
- v = 2 * (op - OP_dec) - 1;
- v64 += v;
- break;
- case OP_plus:
- break;
- case OP_neg:
- if (v64 == 0 && is_legacy) {
- sp[-1] = __JS_NewFloat64(ctx, -0.0);
- return 0;
- } else {
- v64 = -v64;
- }
- break;
- default:
- abort();
+ if (ret) {
+ JS_FreeValue(ctx, op1);
+ sp[-1] = val;
+ return 0;
+ }
+ }
+
+ op1 = JS_ToNumericFree(ctx, op1);
+ if (JS_IsException(op1))
+ goto exception;
+ tag = JS_VALUE_GET_TAG(op1);
+ switch(tag) {
+ case JS_TAG_INT:
+ {
+ int64_t v64;
+ v64 = JS_VALUE_GET_INT(op1);
+ switch(op) {
+ case OP_inc:
+ case OP_dec:
+ v = 2 * (op - OP_dec) - 1;
+ v64 += v;
+ break;
+ case OP_plus:
+ break;
+ case OP_neg:
+ if (v64 == 0) {
+ sp[-1] = __JS_NewFloat64(ctx, -0.0);
+ return 0;
+ } else {
+ v64 = -v64;
}
- sp[-1] = JS_NewInt64(ctx, v64);
+ break;
+ default:
+ abort();
}
- break;
- case JS_TAG_BIG_INT:
- if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
- goto exception;
- break;
- case JS_TAG_BIG_FLOAT:
- if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
- goto exception;
- break;
- case JS_TAG_BIG_DECIMAL:
- if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
- goto exception;
- break;
- default:
- handle_float64:
- {
- double d;
- d = JS_VALUE_GET_FLOAT64(op1);
- switch(op) {
- case OP_inc:
- case OP_dec:
- v = 2 * (op - OP_dec) - 1;
- d += v;
- break;
- case OP_plus:
- break;
- case OP_neg:
- d = -d;
- break;
- default:
- abort();
- }
- sp[-1] = __JS_NewFloat64(ctx, d);
+ sp[-1] = JS_NewInt64(ctx, v64);
+ }
+ break;
+ case JS_TAG_BIG_INT:
+ handle_bigint:
+ if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, op, op1))
+ goto exception;
+ break;
+ case JS_TAG_BIG_FLOAT:
+ if (ctx->rt->bigfloat_ops.unary_arith(ctx, sp - 1, op, op1))
+ goto exception;
+ break;
+ case JS_TAG_BIG_DECIMAL:
+ if (ctx->rt->bigdecimal_ops.unary_arith(ctx, sp - 1, op, op1))
+ goto exception;
+ break;
+ default:
+ handle_float64:
+ {
+ double d;
+ if (is_math_mode(ctx))
+ goto handle_bigint;
+ d = JS_VALUE_GET_FLOAT64(op1);
+ switch(op) {
+ case OP_inc:
+ case OP_dec:
+ v = 2 * (op - OP_dec) - 1;
+ d += v;
+ break;
+ case OP_plus:
+ break;
+ case OP_neg:
+ d = -d;
+ break;
+ default:
+ abort();
}
- break;
+ sp[-1] = __JS_NewFloat64(ctx, d);
}
+ break;
}
return 0;
exception:
@@ -12255,39 +12441,33 @@ static __exception int js_post_inc_slow(JSContext *ctx,
static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
{
- JSValue op1, method, val;
-
+ JSValue op1, val;
+ int ret;
+
op1 = sp[-1];
if (JS_IsObject(op1)) {
- if (!ctx->bignum_ext)
- goto to_number;
- method = JS_GetProperty(ctx, op1, JS_ATOM_Symbol_operatorNot);
- if (JS_IsException(method))
- return -1;
- if (JS_IsUndefined(method) || JS_IsNull(method))
- goto to_number;
- val = JS_CallFree(ctx, method, op1, 0, NULL);
- if (JS_IsException(val))
+ ret = js_call_unary_op_fallback(ctx, &val, op1, OP_not);
+ if (ret < 0)
return -1;
- JS_FreeValue(ctx, op1);
- sp[-1] = val;
- } else {
- if (JS_IsString(op1)) {
- to_number:
- op1 = JS_ToNumberHintFree(ctx, op1, TON_FLAG_INTEGER);
- if (JS_IsException(op1))
- goto exception;
- }
- if (is_bigint_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
- if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
- goto exception;
- } else {
- int32_t v1;
- if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
- goto exception;
- sp[-1] = JS_NewInt32(ctx, ~v1);
+ if (ret) {
+ JS_FreeValue(ctx, op1);
+ sp[-1] = val;
+ return 0;
}
}
+
+ op1 = JS_ToNumericFree(ctx, op1);
+ if (JS_IsException(op1))
+ goto exception;
+ if (is_math_mode(ctx) || JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT) {
+ if (ctx->rt->bigint_ops.unary_arith(ctx, sp - 1, OP_not, op1))
+ goto exception;
+ } else {
+ int32_t v1;
+ if (unlikely(JS_ToInt32Free(ctx, &v1, op1)))
+ goto exception;
+ sp[-1] = JS_NewInt32(ctx, ~v1);
+ }
return 0;
exception:
sp[-1] = JS_UNDEFINED;
@@ -12297,12 +12477,19 @@ static no_inline int js_not_slow(JSContext *ctx, JSValue *sp)
static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
JSValue *pres, JSValue op1, JSValue op2)
{
- bf_t a_s, b_s, r_s, *r, *a, *b;
- int ret, rnd_mode;
+ bf_t a_s, b_s, *r, *a, *b;
+ int ret;
+ JSValue res;
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return -1;
+ }
+ r = JS_GetBigFloat(res);
a = JS_ToBigFloat(ctx, &a_s, op1);
b = JS_ToBigFloat(ctx, &b_s, op2);
- r = &r_s;
bf_init(ctx->bf_ctx, r);
switch(op) {
case OP_add:
@@ -12314,29 +12501,21 @@ static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
case OP_mul:
ret = bf_mul(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
break;
- case OP_math_div:
case OP_div:
ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags);
break;
case OP_math_mod:
/* Euclidian remainder */
- rnd_mode = BF_DIVREM_EUCLIDIAN;
- goto do_mod;
+ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
+ BF_DIVREM_EUCLIDIAN);
+ break;
case OP_mod:
- rnd_mode = BF_RNDZ;
- do_mod:
- {
- bf_t q_s, *q = &q_s;
- bf_init(ctx->bf_ctx, q);
- ret = bf_divrem(q, r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
- rnd_mode);
- bf_delete(q);
- }
+ ret = bf_rem(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags,
+ BF_RNDZ);
break;
case OP_pow:
- case OP_math_pow:
ret = bf_pow(r, a, b, ctx->fp_env.prec,
- ctx->fp_env.flags | BF_POW_JS_QUICKS);
+ ctx->fp_env.flags | BF_POW_JS_QUIRKS);
break;
default:
abort();
@@ -12348,21 +12527,24 @@ static int js_binary_arith_bigfloat(JSContext *ctx, OPCodeEnum op,
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (unlikely(ret & BF_ST_MEM_ERROR)) {
- bf_delete(r);
+ JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
- *pres = JS_NewBigFloat(ctx, r);
+ *pres = res;
return 0;
}
static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
JSValue *pres, JSValue op1, JSValue op2)
{
- bf_t a_s, b_s, r_s, *r, *a, *b;
- int ret, rnd_mode;
+ bf_t a_s, b_s, *r, *a, *b;
+ int ret;
JSValue res;
+ res = JS_NewBigInt(ctx);
+ if (JS_IsException(res))
+ goto fail;
a = JS_ToBigInt(ctx, &a_s, op1);
if (!a)
goto fail;
@@ -12371,8 +12553,7 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
JS_FreeBigInt(ctx, a, &a_s);
goto fail;
}
- r = &r_s;
- bf_init(ctx->bf_ctx, r);
+ r = JS_GetBigInt(res);
ret = 0;
switch(op) {
case OP_add:
@@ -12384,73 +12565,75 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
case OP_mul:
ret = bf_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
- case OP_math_div:
- goto op_fallback;
case OP_div:
- if (!is_bigint_mode(ctx)) {
+ if (!is_math_mode(ctx)) {
bf_t rem_s, *rem = &rem_s;
bf_init(ctx->bf_ctx, rem);
ret = bf_divrem(r, rem, a, b, BF_PREC_INF, BF_RNDZ,
BF_RNDZ);
bf_delete(rem);
} else {
- bf_div(r, a, b, 53, bf_set_exp_bits(11) |
- BF_RNDN | BF_FLAG_SUBNORMAL);
- goto float64_result;
+ goto math_mode_div_pow;
}
break;
case OP_math_mod:
/* Euclidian remainder */
- rnd_mode = BF_DIVREM_EUCLIDIAN;
- goto do_int_mod;
+ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
+ BF_DIVREM_EUCLIDIAN) & BF_ST_INVALID_OP;
+ break;
case OP_mod:
- rnd_mode = BF_RNDZ;
- do_int_mod:
- {
- bf_t q_s, *q = &q_s;
- bf_init(ctx->bf_ctx, q);
- ret = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ,
- rnd_mode) & BF_ST_INVALID_OP;
- bf_delete(q);
- }
+ ret = bf_rem(r, a, b, BF_PREC_INF, BF_RNDZ,
+ BF_RNDZ) & BF_ST_INVALID_OP;
break;
case OP_pow:
- case OP_math_pow:
if (b->sign) {
- if (!is_bigint_mode(ctx)) {
+ if (!is_math_mode(ctx)) {
ret = BF_ST_INVALID_OP;
- } else if (op == OP_math_pow) {
- op_fallback:
- bf_delete(r);
+ } else {
+ math_mode_div_pow:
+ JS_FreeValue(ctx, res);
+ ret = js_call_binary_op_simple(ctx, &res, ctx->class_proto[JS_CLASS_BIG_INT], op1, op2, op);
+ if (ret != 0) {
+ JS_FreeBigInt(ctx, a, &a_s);
+ JS_FreeBigInt(ctx, b, &b_s);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ if (ret < 0) {
+ return -1;
+ } else {
+ *pres = res;
+ return 0;
+ }
+ }
+ /* if no BigInt power operator defined, return a
+ bigfloat */
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res)) {
+ JS_FreeBigInt(ctx, a, &a_s);
+ JS_FreeBigInt(ctx, b, &b_s);
+ goto fail;
+ }
+ r = JS_GetBigFloat(res);
+ if (op == OP_div) {
+ ret = bf_div(r, a, b, ctx->fp_env.prec, ctx->fp_env.flags) & BF_ST_MEM_ERROR;
+ } else {
+ ret = bf_pow(r, a, b, ctx->fp_env.prec,
+ ctx->fp_env.flags | BF_POW_JS_QUIRKS) & BF_ST_MEM_ERROR;
+ }
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeBigInt(ctx, b, &b_s);
- ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
- if (ret < 0) {
- return -1;
- } else if (ret == 0) {
- JS_ThrowTypeError(ctx, "operator must be defined for exact division or power");
+ if (unlikely(ret)) {
+ JS_FreeValue(ctx, res);
+ throw_bf_exception(ctx, ret);
return -1;
}
*pres = res;
return 0;
- } else {
- double dr;
- bf_pow(r, a, b, 53, bf_set_exp_bits(11) |
- BF_RNDN | BF_FLAG_SUBNORMAL);
- float64_result:
- bf_get_float64(r, &dr, BF_RNDN);
- bf_delete(r);
- JS_FreeBigInt(ctx, a, &a_s);
- JS_FreeBigInt(ctx, b, &b_s);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- *pres = __JS_NewFloat64(ctx, dr);
- return 0;
}
} else {
- ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUICKS);
+ ret = bf_pow(r, a, b, BF_PREC_INF, BF_RNDZ | BF_POW_JS_QUIRKS);
}
break;
@@ -12494,13 +12677,14 @@ static int js_binary_arith_bigint(JSContext *ctx, OPCodeEnum op,
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (unlikely(ret)) {
- bf_delete(r);
+ JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
- *pres = JS_NewBigInt(ctx, r);
+ *pres = JS_CompactBigInt(ctx, res);
return 0;
fail:
+ JS_FreeValue(ctx, res);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
return -1;
@@ -12536,18 +12720,21 @@ static int js_bfdec_pow(bfdec_t *r, const bfdec_t *a, const bfdec_t *b)
static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
JSValue *pres, JSValue op1, JSValue op2)
{
- bfdec_t r_s, *r, *a, *b;
- int ret, rnd_mode;
-
- /* big decimal result */
+ bfdec_t *r, *a, *b;
+ int ret;
+ JSValue res;
+
+ res = JS_NewBigDecimal(ctx);
+ if (JS_IsException(res))
+ goto fail;
+ r = JS_GetBigDecimal(res);
+
a = JS_ToBigDecimal(ctx, op1);
if (!a)
goto fail;
b = JS_ToBigDecimal(ctx, op2);
if (!b)
goto fail;
- r = &r_s;
- bfdec_init(ctx->bf_ctx, r);
switch(op) {
case OP_add:
ret = bfdec_add(r, a, b, BF_PREC_INF, BF_RNDZ);
@@ -12558,26 +12745,17 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
case OP_mul:
ret = bfdec_mul(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
- case OP_math_div:
case OP_div:
ret = bfdec_div(r, a, b, BF_PREC_INF, BF_RNDZ);
break;
case OP_math_mod:
/* Euclidian remainder */
- rnd_mode = BF_DIVREM_EUCLIDIAN;
- goto do_mod_dec;
+ ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_DIVREM_EUCLIDIAN);
+ break;
case OP_mod:
- rnd_mode = BF_RNDZ;
- do_mod_dec:
- {
- bfdec_t q_s, *q = &q_s;
- bfdec_init(ctx->bf_ctx, q);
- ret = bfdec_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, rnd_mode);
- bfdec_delete(q);
- }
+ ret = bfdec_rem(r, a, b, BF_PREC_INF, BF_RNDZ, BF_RNDZ);
break;
case OP_pow:
- case OP_math_pow:
ret = js_bfdec_pow(r, a, b);
break;
default:
@@ -12586,13 +12764,14 @@ static int js_binary_arith_bigdecimal(JSContext *ctx, OPCodeEnum op,
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
if (unlikely(ret)) {
- bfdec_delete(r);
+ JS_FreeValue(ctx, res);
throw_bf_exception(ctx, ret);
return -1;
}
- *pres = JS_NewBigDecimal(ctx, r);
+ *pres = res;
return 0;
fail:
+ JS_FreeValue(ctx, res);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
return -1;
@@ -12602,7 +12781,6 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
OPCodeEnum op)
{
JSValue op1, op2, res;
- BOOL is_legacy;
uint32_t tag1, tag2;
int ret;
double d1, d2;
@@ -12619,12 +12797,11 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
}
/* try to call an overloaded operator */
- if (((tag1 == JS_TAG_OBJECT &&
- (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
- (tag2 == JS_TAG_OBJECT &&
- (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&
- ctx->bignum_ext) {
- ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
+ if ((tag1 == JS_TAG_OBJECT &&
+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
if (ret != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -12655,23 +12832,23 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
int64_t v;
v1 = JS_VALUE_GET_INT(op1);
v2 = JS_VALUE_GET_INT(op2);
- is_legacy = is_bigint_mode(ctx) ^ 1;
switch(op) {
case OP_sub:
v = (int64_t)v1 - (int64_t)v2;
break;
case OP_mul:
v = (int64_t)v1 * (int64_t)v2;
- if (is_legacy && v == 0 && (v1 | v2) < 0) {
+ if (is_math_mode(ctx) &&
+ (v < -MAX_SAFE_INTEGER || v > MAX_SAFE_INTEGER))
+ goto handle_bigint;
+ if (v == 0 && (v1 | v2) < 0) {
sp[-2] = __JS_NewFloat64(ctx, -0.0);
return 0;
}
break;
- case OP_math_div:
- if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
- goto exception;
- return 0;
case OP_div:
+ if (is_math_mode(ctx))
+ goto handle_bigint;
sp[-2] = __JS_NewFloat64(ctx, (double)v1 / (double)v2);
return 0;
case OP_math_mod:
@@ -12688,26 +12865,19 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
}
break;
case OP_mod:
- if (is_legacy && (v1 < 0 || v2 <= 0)) {
+ if (v1 < 0 || v2 <= 0) {
sp[-2] = JS_NewFloat64(ctx, fmod(v1, v2));
return 0;
} else {
- if (unlikely(v2 == 0)) {
- throw_bf_exception(ctx, BF_ST_DIVIDE_ZERO);
- goto exception;
- }
v = (int64_t)v1 % (int64_t)v2;
}
break;
case OP_pow:
- case OP_math_pow:
- if (is_legacy) {
+ if (!is_math_mode(ctx)) {
sp[-2] = JS_NewFloat64(ctx, js_pow(v1, v2));
return 0;
} else {
- if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
- goto exception;
- return 0;
+ goto handle_bigint;
}
break;
default:
@@ -12720,6 +12890,10 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
} else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) {
if (ctx->rt->bigfloat_ops.binary_arith(ctx, op, sp - 2, op1, op2))
goto exception;
+ } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ 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) {
double dr;
/* float64 result */
@@ -12730,6 +12904,8 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
if (JS_ToFloat64Free(ctx, &d2, op2))
goto exception;
handle_float64:
+ if (is_math_mode(ctx) && is_safe_integer(d1) && is_safe_integer(d2))
+ goto handle_bigint;
switch(op) {
case OP_sub:
dr = d1 - d2;
@@ -12738,7 +12914,6 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
dr = d1 * d2;
break;
case OP_div:
- case OP_math_div:
dr = d1 / d2;
break;
case OP_mod:
@@ -12752,16 +12927,12 @@ static no_inline __exception int js_binary_arith_slow(JSContext *ctx, JSValue *s
dr += d2;
break;
case OP_pow:
- case OP_math_pow:
dr = js_pow(d1, d2);
break;
default:
abort();
}
sp[-2] = __JS_NewFloat64(ctx, dr);
- } else {
- if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
- goto exception;
}
return 0;
exception:
@@ -12792,12 +12963,14 @@ static no_inline __exception int js_add_slow(JSContext *ctx, JSValue *sp)
if (tag1 == JS_TAG_OBJECT || tag2 == JS_TAG_OBJECT) {
/* try to call an overloaded operator */
- if (((tag1 == JS_TAG_OBJECT &&
- (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
- (tag2 == JS_TAG_OBJECT &&
- (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&
- ctx->bignum_ext) {
- ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add);
+ if ((tag1 == JS_TAG_OBJECT &&
+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED &&
+ tag2 != JS_TAG_STRING)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED &&
+ tag1 != JS_TAG_STRING))) {
+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, OP_add,
+ FALSE, HINT_NONE);
if (ret != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -12886,6 +13059,7 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
JSValue op1, op2, res;
int ret;
uint32_t tag1, tag2;
+ uint32_t v1, v2, r;
op1 = sp[-2];
op2 = sp[-1];
@@ -12893,12 +13067,11 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
tag2 = JS_VALUE_GET_NORM_TAG(op2);
/* try to call an overloaded operator */
- if (((tag1 == JS_TAG_OBJECT &&
- (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
- (tag2 == JS_TAG_OBJECT &&
- (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&
- ctx->bignum_ext) {
- ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op);
+ if ((tag1 == JS_TAG_OBJECT &&
+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+ ret = js_call_binary_op_fallback(ctx, &res, op1, op2, op, TRUE, 0);
if (ret != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -12911,63 +13084,60 @@ static no_inline __exception int js_binary_logic_slow(JSContext *ctx,
}
}
- op1 = JS_ToNumberHintFree(ctx, op1, TON_FLAG_INTEGER);
+ op1 = JS_ToNumericFree(ctx, op1);
if (JS_IsException(op1)) {
JS_FreeValue(ctx, op2);
goto exception;
}
- op2 = JS_ToNumberHintFree(ctx, op2, TON_FLAG_INTEGER);
+ op2 = JS_ToNumericFree(ctx, op2);
if (JS_IsException(op2)) {
JS_FreeValue(ctx, op1);
goto exception;
}
- if (!is_bigint_mode(ctx)) {
- uint32_t v1, v2, r;
+ if (is_math_mode(ctx))
+ goto bigint_op;
- tag1 = JS_VALUE_GET_TAG(op1);
- tag2 = JS_VALUE_GET_TAG(op2);
- if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
- if (tag1 != tag2) {
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- JS_ThrowTypeError(ctx, "both operands must be bigint");
- goto exception;
- } else {
- goto bigint_op;
- }
+ tag1 = JS_VALUE_GET_TAG(op1);
+ tag2 = JS_VALUE_GET_TAG(op2);
+ if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) {
+ if (tag1 != tag2) {
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ JS_ThrowTypeError(ctx, "both operands must be bigint");
+ goto exception;
} else {
- if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
- JS_FreeValue(ctx, op2);
- goto exception;
- }
- if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
+ bigint_op:
+ if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
goto exception;
- switch(op) {
- case OP_shl:
- r = v1 << (v2 & 0x1f);
- break;
- case OP_sar:
- r = (int)v1 >> (v2 & 0x1f);
- break;
- case OP_and:
- r = v1 & v2;
- break;
- case OP_or:
- r = v1 | v2;
- break;
- case OP_xor:
- r = v1 ^ v2;
- break;
- default:
- abort();
- }
- sp[-2] = JS_NewInt32(ctx, r);
}
} else {
- bigint_op:
- if (ctx->rt->bigint_ops.binary_arith(ctx, op, sp - 2, op1, op2))
+ if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v1, op1))) {
+ JS_FreeValue(ctx, op2);
+ goto exception;
+ }
+ if (unlikely(JS_ToInt32Free(ctx, (int32_t *)&v2, op2)))
goto exception;
+ switch(op) {
+ case OP_shl:
+ r = v1 << (v2 & 0x1f);
+ break;
+ case OP_sar:
+ r = (int)v1 >> (v2 & 0x1f);
+ break;
+ case OP_and:
+ r = v1 & v2;
+ break;
+ case OP_or:
+ r = v1 | v2;
+ break;
+ case OP_xor:
+ r = v1 ^ v2;
+ break;
+ default:
+ abort();
+ }
+ sp[-2] = JS_NewInt32(ctx, r);
}
return 0;
exception:
@@ -13081,12 +13251,12 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
tag1 = JS_VALUE_GET_NORM_TAG(op1);
tag2 = JS_VALUE_GET_NORM_TAG(op2);
/* try to call an overloaded operator */
- if (((tag1 == JS_TAG_OBJECT &&
- (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
- (tag2 == JS_TAG_OBJECT &&
- (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) &&
- ctx->bignum_ext) {
- res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op);
+ if ((tag1 == JS_TAG_OBJECT &&
+ (tag2 != JS_TAG_NULL && tag2 != JS_TAG_UNDEFINED)) ||
+ (tag2 == JS_TAG_OBJECT &&
+ (tag1 != JS_TAG_NULL && tag1 != JS_TAG_UNDEFINED))) {
+ res = js_call_binary_op_fallback(ctx, &ret, op1, op2, op,
+ FALSE, HINT_NUMBER);
if (res != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -13165,7 +13335,7 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp,
} else {
if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) ||
(tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) &&
- !is_bigint_mode(ctx)) {
+ !is_math_mode(ctx)) {
if (tag1 == JS_TAG_STRING) {
op1 = JS_StringToBigInt(ctx, op1);
if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
@@ -13271,10 +13441,11 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
goto exception;
}
} else if (tag1 == tag2) {
- if (tag1 == JS_TAG_OBJECT && ctx->bignum_ext) {
+ if (tag1 == JS_TAG_OBJECT) {
/* try the fallback operator */
res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
- is_neq ? OP_neq : OP_eq);
+ is_neq ? OP_neq : OP_eq,
+ FALSE, HINT_NONE);
if (res != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -13294,7 +13465,7 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
(tag2 == JS_TAG_STRING && tag_is_number(tag1))) {
if ((tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) &&
- !is_bigint_mode(ctx)) {
+ !is_math_mode(ctx)) {
if (tag1 == JS_TAG_STRING) {
op1 = JS_StringToBigInt(ctx, op1);
if (JS_VALUE_GET_TAG(op1) != JS_TAG_BIG_INT)
@@ -13336,7 +13507,8 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp,
/* try the fallback operator */
res = js_call_binary_op_fallback(ctx, &ret, op1, op2,
- is_neq ? OP_neq : OP_eq);
+ is_neq ? OP_neq : OP_eq,
+ FALSE, HINT_NONE);
if (res != 0) {
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
@@ -13391,7 +13563,7 @@ static no_inline int js_shr_slow(JSContext *ctx, JSValue *sp)
goto exception;
}
/* XXX: could forbid >>> in bignum mode */
- if (!is_bigint_mode(ctx) &&
+ if (!is_math_mode(ctx) &&
(JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_INT ||
JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_INT)) {
JS_ThrowTypeError(ctx, "bigint operands are forbidden for >>>");
@@ -13433,34 +13605,38 @@ static JSValue js_mul_pow10_to_float64(JSContext *ctx, const bf_t *a,
static no_inline int js_mul_pow10(JSContext *ctx, JSValue *sp)
{
- bf_t a_s, *a, r_s, *r = &r_s;
- JSValue op1, op2;
- slimb_t e;
+ bf_t a_s, *a, *r;
+ JSValue op1, op2, res;
+ int64_t e;
int ret;
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res))
+ return -1;
+ r = JS_GetBigFloat(res);
op1 = sp[-2];
op2 = sp[-1];
a = JS_ToBigFloat(ctx, &a_s, op1);
if (!a)
return -1;
-#if LIMB_BITS == 32
- ret = JS_ToInt32(ctx, &e, op2);
-#else
- ret = JS_ToInt64(ctx, &e, op2);
-#endif
+ if (JS_IsBigInt(ctx, op2)) {
+ ret = JS_ToBigInt64(ctx, &e, op2);
+ } else {
+ ret = JS_ToInt64(ctx, &e, op2);
+ }
if (ret) {
if (a == &a_s)
bf_delete(a);
+ JS_FreeValue(ctx, res);
return -1;
}
- bf_init(ctx->bf_ctx, r);
bf_mul_pow_radix(r, a, 10, e, ctx->fp_env.prec, ctx->fp_env.flags);
if (a == &a_s)
bf_delete(a);
JS_FreeValue(ctx, op1);
JS_FreeValue(ctx, op2);
- sp[-2] = JS_NewBigFloat(ctx, r);
+ sp[-2] = res;
return 0;
}
@@ -13882,22 +14058,9 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
d2 = JS_VALUE_GET_INT(op2);
goto number_test;
} else if (tag2 == JS_TAG_FLOAT64) {
-#ifdef CONFIG_BIGNUM
- if (is_bigint_mode(ctx)) {
- res = FALSE;
- } else
-#endif
- {
- d2 = JS_VALUE_GET_FLOAT64(op2);
- goto number_test;
- }
- } else
-#ifdef CONFIG_BIGNUM
- if (tag2 == JS_TAG_BIG_INT && is_bigint_mode(ctx)) {
- goto bigint_test;
- } else
-#endif
- {
+ d2 = JS_VALUE_GET_FLOAT64(op2);
+ goto number_test;
+ } else {
res = FALSE;
}
break;
@@ -13905,11 +14068,7 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
d1 = JS_VALUE_GET_FLOAT64(op1);
if (tag2 == JS_TAG_FLOAT64) {
d2 = JS_VALUE_GET_FLOAT64(op2);
- } else if (tag2 == JS_TAG_INT
-#ifdef CONFIG_BIGNUM
- && !is_bigint_mode(ctx)
-#endif
- ) {
+ } else if (tag2 == JS_TAG_INT) {
d2 = JS_VALUE_GET_INT(op2);
} else {
res = FALSE;
@@ -13936,15 +14095,10 @@ static BOOL js_strict_eq2(JSContext *ctx, JSValue op1, JSValue op2,
case JS_TAG_BIG_INT:
{
bf_t a_s, *a, b_s, *b;
- if (tag1 == tag2) {
- /* OK */
- } else if (tag2 == JS_TAG_INT && is_bigint_mode(ctx)) {
- /* OK */
- } else {
+ if (tag1 != tag2) {
res = FALSE;
break;
}
- bigint_test:
a = JS_ToBigFloat(ctx, &a_s, op1);
b = JS_ToBigFloat(ctx, &b_s, op2);
res = bf_cmp_eq(a, b);
@@ -14100,30 +14254,20 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValue op1)
tag = JS_VALUE_GET_NORM_TAG(op1);
switch(tag) {
#ifdef CONFIG_BIGNUM
- case JS_TAG_INT:
- if (is_bigint_mode(ctx))
- atom = JS_ATOM_bigint;
- else
- atom = JS_ATOM_number;
- break;
case JS_TAG_BIG_INT:
atom = JS_ATOM_bigint;
break;
- case JS_TAG_FLOAT64:
- atom = JS_ATOM_number;
- break;
case JS_TAG_BIG_FLOAT:
atom = JS_ATOM_bigfloat;
break;
case JS_TAG_BIG_DECIMAL:
atom = JS_ATOM_bigdecimal;
break;
-#else
+#endif
case JS_TAG_INT:
case JS_TAG_FLOAT64:
atom = JS_ATOM_number;
break;
-#endif
case JS_TAG_UNDEFINED:
atom = JS_ATOM_undefined;
break;
@@ -15288,7 +15432,7 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
/* we only propagate the bignum mode as some runtime functions
test it */
if (prev_sf)
- sf->js_mode = prev_sf->js_mode & JS_MODE_BIGINT;
+ sf->js_mode = prev_sf->js_mode & JS_MODE_MATH;
else
sf->js_mode = 0;
#else
@@ -17315,11 +17459,12 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
v1 = JS_VALUE_GET_INT(op1);
v2 = JS_VALUE_GET_INT(op2);
r = (int64_t)v1 * v2;
-#ifdef CONFIG_BIGNUM
- if (unlikely((int)r != r) || (r == 0 && !is_bigint_mode(ctx)))
- goto binary_arith_slow;
-#else
if (unlikely((int)r != r)) {
+#ifdef CONFIG_BIGNUM
+ if (unlikely(sf->js_mode & JS_MODE_MATH) &&
+ (r < -MAX_SAFE_INTEGER || r > MAX_SAFE_INTEGER))
+ goto binary_arith_slow;
+#endif
d = (double)r;
goto mul_fp_res;
}
@@ -17328,14 +17473,15 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
d = -0.0;
goto mul_fp_res;
}
-#endif
sp[-2] = JS_NewInt32(ctx, r);
sp--;
} else if (JS_VALUE_IS_BOTH_FLOAT(op1, op2)) {
+#ifdef CONFIG_BIGNUM
+ if (unlikely(sf->js_mode & JS_MODE_MATH))
+ goto binary_arith_slow;
+#endif
d = JS_VALUE_GET_FLOAT64(op1) * JS_VALUE_GET_FLOAT64(op2);
-#ifndef CONFIG_BIGNUM
mul_fp_res:
-#endif
sp[-2] = __JS_NewFloat64(ctx, d);
sp--;
} else {
@@ -17343,11 +17489,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
}
}
BREAK;
-#ifdef CONFIG_BIGNUM
- CASE(OP_math_div):
- CASE(OP_div):
- goto binary_arith_slow;
-#else
CASE(OP_div):
{
JSValue op1, op2;
@@ -17355,6 +17496,8 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
op2 = sp[-1];
if (likely(JS_VALUE_IS_BOTH_INT(op1, op2))) {
int v1, v2;
+ if (unlikely(sf->js_mode & JS_MODE_MATH))
+ goto binary_arith_slow;
v1 = JS_VALUE_GET_INT(op1);
v2 = JS_VALUE_GET_INT(op2);
sp[-2] = JS_NewFloat64(ctx, (double)v1 / (double)v2);
@@ -17364,7 +17507,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
}
}
BREAK;
-#endif
CASE(OP_mod):
#ifdef CONFIG_BIGNUM
CASE(OP_math_mod):
@@ -17390,9 +17532,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
}
BREAK;
CASE(OP_pow):
-#ifdef CONFIG_BIGNUM
- CASE(OP_math_pow):
-#endif
binary_arith_slow:
if (js_binary_arith_slow(ctx, sp, opcode))
goto exception;
@@ -17422,11 +17561,6 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
tag = JS_VALUE_GET_TAG(op1);
if (tag == JS_TAG_INT) {
val = JS_VALUE_GET_INT(op1);
-#ifdef CONFIG_BIGNUM
- if (unlikely(val == INT32_MIN) ||
- (val == 0 && !is_bigint_mode(ctx)))
- goto slow_neg;
-#else
/* Note: -0 cannot be expressed as integer */
if (unlikely(val == 0)) {
d = -0.0;
@@ -17436,18 +17570,12 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
d = -(double)val;
goto neg_fp_res;
}
-#endif
sp[-1] = JS_NewInt32(ctx, -val);
} else if (JS_TAG_IS_FLOAT64(tag)) {
d = -JS_VALUE_GET_FLOAT64(op1);
-#ifndef CONFIG_BIGNUM
neg_fp_res:
-#endif
sp[-1] = __JS_NewFloat64(ctx, d);
} else {
-#ifdef CONFIG_BIGNUM
- slow_neg:
-#endif
if (js_unary_arith_slow(ctx, sp, opcode))
goto exception;
}
@@ -17560,7 +17688,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
#ifdef CONFIG_BIGNUM
{
int64_t r;
- if (is_bigint_mode(ctx)) {
+ if (unlikely(sf->js_mode & JS_MODE_MATH)) {
if (v2 > 0x1f)
goto shl_slow;
r = (int64_t)v1 << v2;
@@ -17616,7 +17744,7 @@ static JSValue JS_CallInternal(JSContext *ctx, JSValueConst func_obj,
v2 = JS_VALUE_GET_INT(op2);
#ifdef CONFIG_BIGNUM
if (unlikely(v2 > 0x1f)) {
- if (is_bigint_mode(ctx))
+ if (unlikely(sf->js_mode & JS_MODE_MATH))
goto sar_slow;
else
v2 &= 0x1f;
@@ -20182,7 +20310,7 @@ static __exception int next_token(JSParseState *s)
ATOD_ACCEPT_UNDERSCORES;
#ifdef CONFIG_BIGNUM
flags |= ATOD_ACCEPT_SUFFIX;
- if (s->cur_func->js_mode & JS_MODE_BIGINT) {
+ if (s->cur_func->js_mode & JS_MODE_MATH) {
flags |= ATOD_MODE_BIGINT;
if (s->cur_func->js_mode & JS_MODE_MATH)
flags |= ATOD_TYPE_BIG_FLOAT;
@@ -23312,7 +23440,6 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
} else
#ifdef CONFIG_BIGNUM
if (JS_VALUE_GET_TAG(val) == JS_TAG_BIG_FLOAT) {
- bf_t r_s, *r = &r_s;
slimb_t e;
int ret;
@@ -23326,9 +23453,9 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
emit_op(s, OP_push_i32);
emit_u32(s, e);
} else {
- bf_init(s->ctx->bf_ctx, r);
- bf_set_si(r, e);
- val = JS_NewBigInt(s->ctx, r);
+ val = JS_NewBigInt64_1(s->ctx, e);
+ if (JS_IsException(val))
+ return -1;
ret = emit_push_const(s, val, 0);
JS_FreeValue(s->ctx, val);
if (ret < 0)
@@ -24105,10 +24232,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
return -1;
if (js_parse_unary(s, 1))
return -1;
- if (s->cur_func->js_mode & JS_MODE_MATH)
- emit_op(s, OP_math_pow);
- else
- emit_op(s, OP_pow);
+ emit_op(s, OP_pow);
}
#else
if (s->token.val == TOK_POW) {
@@ -24151,12 +24275,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level,
opcode = OP_mul;
break;
case '/':
-#ifdef CONFIG_BIGNUM
- if (s->cur_func->js_mode & JS_MODE_MATH)
- opcode = OP_math_div;
- else
-#endif
- opcode = OP_div;
+ opcode = OP_div;
break;
case '%':
#ifdef CONFIG_BIGNUM
@@ -24549,12 +24668,8 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
op = assign_opcodes[op - TOK_MUL_ASSIGN];
#ifdef CONFIG_BIGNUM
if (s->cur_func->js_mode & JS_MODE_MATH) {
- if (op == OP_div)
- op = OP_math_div;
- else if (op == OP_mod)
+ if (op == OP_mod)
op = OP_math_mod;
- else if (op == OP_pow)
- op = OP_math_pow;
}
#endif
emit_op(s, op);
@@ -30149,20 +30264,6 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
len = opcode_info[op].size;
pos_next = pos + len;
switch(op) {
- case OP_close_var_object:
- {
- if (s->var_object_idx >= 0) {
- /* close the var object and create a new one */
- add_pc2line_info(s, bc_out.size, line_num);
- dbuf_putc(&bc_out, OP_close_loc);
- dbuf_put_u16(&bc_out, s->var_object_idx);
- dbuf_putc(&bc_out, OP_special_object);
- dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
- put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
- }
- }
- break;
-
case OP_line_num:
/* line number info (for debug). We put it in a separate
compressed table to reduce memory usage and get better
@@ -31508,11 +31609,8 @@ static __exception int js_parse_directives(JSParseState *s)
}
#endif
#ifdef CONFIG_BIGNUM
- else if (s->ctx->bignum_ext && !strcmp(str, "use bigint")) {
- s->cur_func->js_mode |= JS_MODE_BIGINT;
- }
else if (s->ctx->bignum_ext && !strcmp(str, "use math")) {
- s->cur_func->js_mode |= JS_MODE_BIGINT | JS_MODE_MATH;
+ s->cur_func->js_mode |= JS_MODE_MATH;
}
#endif
}
@@ -31804,13 +31902,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
if (js_parse_destructing_element(s, TOK_VAR, 1, TRUE, -1, TRUE))
goto fail;
- /* Close var object: necessary if direct eval call
- occurred in the assignment expression or if any
- variable was captured and a later direct eval call
- may instantiate it in the var object.
- The next pass will generate the capture if required.
- */
- emit_op(s, OP_close_var_object);
} else if (s->token.val == TOK_IDENT) {
if (s->token.u.ident.is_reserved) {
js_parse_error_reserved_identifier(s);
@@ -31889,8 +31980,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
set_object_name(s, name);
emit_op(s, OP_put_arg);
emit_u16(s, idx);
- /* Close var object: see above comment. */
- emit_op(s, OP_close_var_object);
emit_label(s, label);
}
} else if (!has_opt_arg) {
@@ -34399,30 +34488,20 @@ static JSValue JS_ToObject(JSContext *ctx, JSValueConst val)
case JS_TAG_EXCEPTION:
return JS_DupValue(ctx, val);
#ifdef CONFIG_BIGNUM
- case JS_TAG_INT:
- if (is_bigint_mode(ctx))
- obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
- else
- obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
- goto set_value;
case JS_TAG_BIG_INT:
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_INT);
goto set_value;
- case JS_TAG_FLOAT64:
- obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
- goto set_value;
case JS_TAG_BIG_FLOAT:
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_FLOAT);
goto set_value;
case JS_TAG_BIG_DECIMAL:
obj = JS_NewObjectClass(ctx, JS_CLASS_BIG_DECIMAL);
goto set_value;
-#else
+#endif
case JS_TAG_INT:
case JS_TAG_FLOAT64:
obj = JS_NewObjectClass(ctx, JS_CLASS_NUMBER);
goto set_value;
-#endif
case JS_TAG_STRING:
/* XXX: should call the string constructor */
{
@@ -34995,10 +35074,13 @@ static JSValue js_object_preventExtensions(JSContext *ctx, JSValueConst this_val
ret = JS_PreventExtensions(ctx, obj);
if (ret < 0)
return JS_EXCEPTION;
- if (reflect)
+ if (reflect) {
return JS_NewBool(ctx, ret);
- else
+ } else {
+ if (!ret)
+ return JS_ThrowTypeError(ctx, "proxy preventExtensions handler returned false");
return JS_DupValue(ctx, obj);
+ }
}
static JSValue js_object_hasOwnProperty(JSContext *ctx, JSValueConst this_val,
@@ -35166,7 +35248,7 @@ static JSValue js_object_seal(JSContext *ctx, JSValueConst this_val,
goto exception;
}
js_free_prop_enum(ctx, props, len);
- return JS_TRUE;
+ return JS_DupValue(ctx, obj);
exception:
js_free_prop_enum(ctx, props, len);
@@ -37690,17 +37772,14 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSValue val, obj;
-#ifdef CONFIG_BIGNUM
if (argc == 0) {
- if (is_bigint_mode(ctx))
- val = __JS_NewFloat64(ctx, 0);
- else
- val = JS_NewInt32(ctx, 0);
+ val = JS_NewInt32(ctx, 0);
} else {
val = JS_ToNumeric(ctx, argv[0]);
if (JS_IsException(val))
return val;
switch(JS_VALUE_GET_TAG(val)) {
+#ifdef CONFIG_BIGNUM
case JS_TAG_BIG_INT:
case JS_TAG_BIG_FLOAT:
{
@@ -37711,25 +37790,19 @@ static JSValue js_number_constructor(JSContext *ctx, JSValueConst new_target,
val = __JS_NewFloat64(ctx, d);
}
break;
- case JS_TAG_INT:
- if (is_bigint_mode(ctx)) {
- /* always return a number in bignum mode */
- val = __JS_NewFloat64(ctx, JS_VALUE_GET_INT(val));
- }
+ case JS_TAG_BIG_DECIMAL:
+ val = JS_ToStringFree(ctx, val);
+ if (JS_IsException(val))
+ return val;
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return val;
break;
+#endif
default:
break;
}
}
-#else
- if (argc == 0) {
- val = JS_NewInt32(ctx, 0);
- } else {
- val = JS_ToNumber(ctx, argv[0]);
- if (JS_IsException(val))
- return val;
- }
-#endif
if (!JS_IsUndefined(new_target)) {
obj = js_create_from_ctor(ctx, new_target, JS_CLASS_NUMBER);
if (!JS_IsException(obj))
@@ -37760,7 +37833,6 @@ static JSValue js_number___toLength(JSContext *ctx, JSValueConst this_val,
static JSValue js_number_isNaN(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- /* XXX: should just check for float and big_float */
if (!JS_IsNumber(argv[0]))
return JS_FALSE;
return js_global_isNaN(ctx, this_val, argc, argv);
@@ -37793,8 +37865,7 @@ static JSValue js_number_isSafeInteger(JSContext *ctx, JSValueConst this_val,
return JS_FALSE;
if (unlikely(JS_ToFloat64(ctx, &d, argv[0])))
return JS_EXCEPTION;
- return JS_NewBool(ctx, isfinite(d) && floor(d) == d &&
- fabs(d) <= (double)MAX_SAFE_INTEGER);
+ return JS_NewBool(ctx, is_safe_integer(d));
}
static const JSCFunctionListEntry js_number_funcs[] = {
@@ -37838,6 +37909,18 @@ static JSValue js_number_valueOf(JSContext *ctx, JSValueConst this_val,
return js_thisNumberValue(ctx, this_val);
}
+static int js_get_radix(JSContext *ctx, JSValueConst val)
+{
+ int radix;
+ if (JS_ToInt32Sat(ctx, &radix, val))
+ return -1;
+ if (radix < 2 || radix > 36) {
+ JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
+ return -1;
+ }
+ return radix;
+}
+
static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
@@ -37851,12 +37934,9 @@ static JSValue js_number_toString(JSContext *ctx, JSValueConst this_val,
if (magic || JS_IsUndefined(argv[0])) {
base = 10;
} else {
- if (JS_ToInt32Sat(ctx, &base, argv[0]))
- goto fail;
- if (base < 2 || base > 36) {
- JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
+ base = js_get_radix(ctx, argv[0]);
+ if (base < 0)
goto fail;
- }
}
if (JS_ToFloat64Free(ctx, &d, val))
return JS_EXCEPTION;
@@ -37972,10 +38052,6 @@ static JSValue js_parseInt(JSContext *ctx, JSValueConst this_val,
p = str;
p += skip_spaces(p);
flags = ATOD_INT_ONLY | ATOD_ACCEPT_PREFIX_AFTER_SIGN;
-#ifdef CONFIG_BIGNUM
- if (is_bigint_mode(ctx))
- flags |= ATOD_MODE_BIGINT;
-#endif
ret = js_atof(ctx, p, NULL, radix, flags);
}
JS_FreeCString(ctx, str);
@@ -39738,348 +39814,6 @@ static double js_fmax(double a, double b)
}
}
-#ifdef CONFIG_BIGNUM
-
-enum {
- MATH_OP_ABS,
- MATH_OP_FLOOR,
- MATH_OP_CEIL,
- MATH_OP_ROUND,
- MATH_OP_TRUNC,
- MATH_OP_SQRT,
- MATH_OP_FPROUND,
- MATH_OP_ACOS,
- MATH_OP_ASIN,
- MATH_OP_ATAN,
- MATH_OP_ATAN2,
- MATH_OP_COS,
- MATH_OP_EXP,
- MATH_OP_LOG,
- MATH_OP_POW,
- MATH_OP_SIN,
- MATH_OP_TAN,
- MATH_OP_FMOD,
- MATH_OP_REM,
- MATH_OP_SIGN,
-
- MATH_OP_ADD,
- MATH_OP_SUB,
- MATH_OP_MUL,
- MATH_OP_DIV,
-};
-
-static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
-{
- bf_t a_s, *a, r_s, *r = &r_s;
- JSFloatEnv *fe;
- int rnd_mode;
- JSValue op1;
-
- op1 = JS_ToNumber(ctx, argv[0]);
- if (JS_IsException(op1))
- return op1;
- a = JS_ToBigFloat(ctx, &a_s, op1);
- fe = &ctx->fp_env;
- if (argc > 1) {
- fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
- if (!fe) {
- if (a == &a_s)
- bf_delete(a);
- JS_FreeValue(ctx, op1);
- return JS_EXCEPTION;
- }
- }
-
- bf_init(ctx->bf_ctx, r);
- switch (magic) {
- case MATH_OP_ABS:
- bf_set(r, a);
- r->sign = 0;
- break;
- case MATH_OP_FLOOR:
- rnd_mode = BF_RNDD;
- goto rint;
- case MATH_OP_CEIL:
- rnd_mode = BF_RNDU;
- goto rint;
- case MATH_OP_ROUND:
- rnd_mode = BF_RNDNU;
- goto rint;
- case MATH_OP_TRUNC:
- rnd_mode = BF_RNDZ;
- rint:
- bf_set(r, a);
- fe->status |= bf_rint(r, rnd_mode);
- break;
- case MATH_OP_SQRT:
- fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_FPROUND:
- bf_set(r, a);
- fe->status |= bf_round(r, fe->prec, fe->flags);
- break;
- case MATH_OP_ACOS:
- fe->status |= bf_acos(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_ASIN:
- fe->status |= bf_asin(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_ATAN:
- fe->status |= bf_atan(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_COS:
- fe->status |= bf_cos(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_EXP:
- fe->status |= bf_exp(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_LOG:
- fe->status |= bf_log(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_SIN:
- fe->status |= bf_sin(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_TAN:
- fe->status |= bf_tan(r, a, fe->prec, fe->flags);
- break;
- case MATH_OP_SIGN:
- if (bf_is_nan(a) || bf_is_zero(a)) {
- bf_set(r, a);
- } else {
- bf_set_si(r, 1 - 2 * a->sign);
- }
- break;
- default:
- abort();
- }
- if (a == &a_s)
- bf_delete(a);
- JS_FreeValue(ctx, op1);
- return JS_NewBigFloat(ctx, r);
-}
-
-static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
-{
- bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
- JSFloatEnv *fe;
- JSValue op1, op2;
-
- op1 = JS_ToNumber(ctx, argv[0]);
- if (JS_IsException(op1))
- return op1;
- op2 = JS_ToNumber(ctx, argv[1]);
- if (JS_IsException(op2)) {
- JS_FreeValue(ctx, op1);
- return op2;
- }
- a = JS_ToBigFloat(ctx, &a_s, op1);
- b = JS_ToBigFloat(ctx, &b_s, op2);
- fe = &ctx->fp_env;
- if (argc > 2) {
- fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
- if (!fe) {
- if (a == &a_s)
- bf_delete(a);
- if (b == &b_s)
- bf_delete(b);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return JS_EXCEPTION;
- }
- }
-
- bf_init(ctx->bf_ctx, r);
- switch (magic) {
- case MATH_OP_ATAN2:
- fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
- break;
- case MATH_OP_POW:
- fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUICKS);
- break;
- case MATH_OP_FMOD:
- fe->status |= bf_fmod(r, a, b, fe->prec, fe->flags);
- break;
- case MATH_OP_REM:
- fe->status |= bf_remainder(r, a, b, fe->prec, fe->flags);
- break;
- case MATH_OP_ADD:
- fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
- break;
- case MATH_OP_SUB:
- fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
- break;
- case MATH_OP_MUL:
- fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
- break;
- case MATH_OP_DIV:
- fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
- break;
- default:
- abort();
- }
- if (a == &a_s)
- bf_delete(a);
- if (b == &b_s)
- bf_delete(b);
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return JS_NewBigFloat(ctx, r);
-}
-
-static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv, int magic)
-{
- BOOL is_max = magic;
- JSValue val, ret;
- int i;
- uint32_t tag;
-
- if (unlikely(argc == 0)) {
- return __JS_NewFloat64(ctx, is_max ? -1.0 / 0.0 : 1.0 / 0.0);
- }
-
- tag = JS_VALUE_GET_TAG(argv[0]);
- if (tag == JS_TAG_INT) {
- int a1, r1 = JS_VALUE_GET_INT(argv[0]);
- for(i = 1; i < argc; i++) {
- tag = JS_VALUE_GET_TAG(argv[i]);
- if (tag != JS_TAG_INT) {
- ret = JS_NewInt32(ctx, r1);
- goto generic_case;
- }
- a1 = JS_VALUE_GET_INT(argv[i]);
- if (is_max)
- r1 = max_int(r1, a1);
- else
- r1 = min_int(r1, a1);
- }
- ret = JS_NewInt32(ctx, r1);
- } else {
- ret = JS_ToNumber(ctx, argv[0]);
- if (JS_IsException(ret))
- return ret;
- i = 1;
- generic_case:
- for(; i < argc; i++) {
- val = JS_ToNumber(ctx, argv[i]);
- if (JS_IsException(val)) {
- JS_FreeValue(ctx, ret);
- return val;
- }
- if (JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(ret)) &&
- JS_TAG_IS_FLOAT64(JS_VALUE_GET_TAG(val))) {
- double r, a;
- r = JS_VALUE_GET_FLOAT64(ret);
- a = JS_VALUE_GET_FLOAT64(val);
- if (!isnan(r)) {
- if (isnan(a)) {
- r = a;
- } else {
- if (is_max)
- r = js_fmax(r, a);
- else
- r = js_fmin(r, a);
- }
- ret = __JS_NewFloat64(ctx, r);
- }
- } else {
- bf_t a_s, *a, r_s, *r;
- int res;
-
- r = JS_ToBigFloat(ctx, &r_s, ret);
- if (!bf_is_nan(r)) {
- a = JS_ToBigFloat(ctx, &a_s, val);
- res = bf_cmp_full(a, r);
- if (is_max)
- res = -res;
- if (bf_is_nan(a) || res < 0) {
- JS_FreeValue(ctx, ret);
- ret = JS_DupValue(ctx, val);
- }
- if (a == &a_s)
- bf_delete(a);
- }
- if (r == &r_s)
- bf_delete(r);
- JS_FreeValue(ctx, val);
- }
- }
- }
- return ret;
-}
-
-static JSValue js_math_abs(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- JSValue val;
- uint32_t tag;
-
- val = JS_ToNumeric(ctx, argv[0]);
- tag = JS_VALUE_GET_NORM_TAG(val);
- switch(tag) {
- case JS_TAG_INT:
- if (JS_VALUE_GET_INT(val) < 0)
- val = JS_NewInt64(ctx, -(int64_t)JS_VALUE_GET_INT(val));
- break;
- case JS_TAG_FLOAT64:
- val = __JS_NewFloat64(ctx, fabs(JS_VALUE_GET_FLOAT64(val)));
- break;
- case JS_TAG_BIG_FLOAT:
- case JS_TAG_BIG_INT:
- {
- JSBigFloat *p = JS_VALUE_GET_PTR(val);
- bf_t r_s, *r = &r_s;
- bf_init(ctx->bf_ctx, r);
- bf_set(r, &p->num);
- r->sign = 0;
- JS_FreeValue(ctx, val);
- if (tag == JS_TAG_BIG_FLOAT)
- val = JS_NewBigFloat(ctx, r);
- else
- val = JS_NewBigInt2(ctx, r, TRUE);
- }
- break;
- default:
- break;
- }
- return val;
-}
-
-#if 0
-/* XXX: should give exact rounding */
-/* XXX: correct NaN/Infinity handling */
-static JSValue js_math_hypot(JSContext *ctx, JSValueConst this_val,
- int argc, JSValueConst *argv)
-{
- bf_t a_s, *a, r_s, *r = &r_s, r2_s, *r2 = &r2_s;
- JSValue val;
- int i;
- BOOL is_float;
-
- bf_init(ctx->bf_ctx, r);
- bf_set_si(r, 0);
- for(i = 0; i < argc; i++) {
- val = JS_ToNumber(ctx, argv[i]);
- if (JS_IsException(val)) {
- bf_delete(r);
- return val;
- }
- a = JS_ToBigFloat(ctx, &is_float, &a_s, val);
- bf_add(r, r, a, ctx->fp_env.prec, ctx->fp_env.flags);
- if (a == &a_s)
- bf_delete(a);
- }
- bf_init(ctx->bf_ctx, r2);
- bf_sqrt(r2, r, ctx->fp_env.prec, ctx->fp_env.flags);
- bf_delete(r);
- return JS_NewBigFloat(ctx, r2);
-}
-#endif
-
-#else
-
static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
@@ -40133,8 +39867,6 @@ static JSValue js_math_min_max(JSContext *ctx, JSValueConst this_val,
}
}
-#endif /* !CONFIG_BIGNUM */
-
static double js_math_sign(double a)
{
if (isnan(a) || a == 0.0)
@@ -40267,11 +39999,7 @@ static JSValue js_math_random(JSContext *ctx, JSValueConst this_val,
static const JSCFunctionListEntry js_math_funcs[] = {
JS_CFUNC_MAGIC_DEF("min", 2, js_math_min_max, 0 ),
JS_CFUNC_MAGIC_DEF("max", 2, js_math_min_max, 1 ),
-#ifdef CONFIG_BIGNUM
- JS_CFUNC_DEF("abs", 1, js_math_abs ),
-#else
JS_CFUNC_SPECIAL_DEF("abs", 1, f_f, fabs ),
-#endif
JS_CFUNC_SPECIAL_DEF("floor", 1, f_f, floor ),
JS_CFUNC_SPECIAL_DEF("ceil", 1, f_f, ceil ),
JS_CFUNC_SPECIAL_DEF("round", 1, f_f, js_math_round ),
@@ -41959,46 +41687,12 @@ static JSValue json_parse_value(JSParseState *s)
}
is_neg = 1;
number:
-#ifdef CONFIG_BIGNUM
- val = JS_DupValue(ctx, s->token.u.num.val);
- if (is_neg) {
- switch(JS_VALUE_GET_NORM_TAG(val)) {
- case JS_TAG_BIG_INT:
- case JS_TAG_BIG_FLOAT:
- {
- JSBigFloat *p;
- p = JS_VALUE_GET_PTR(val);
- bf_neg(&p->num);
- }
- break;
- case JS_TAG_FLOAT64:
- {
- double d;
- d = JS_VALUE_GET_FLOAT64(val);
- val = __JS_NewFloat64(ctx, -d);
- }
- break;
- default:
- case JS_TAG_INT:
- {
- int v;
- v = JS_VALUE_GET_INT(val);
- if (v == 0 && !is_bigint_mode(s->ctx))
- val = __JS_NewFloat64(ctx, -0.0);
- else
- val = JS_NewInt64(ctx, -(int64_t)v);
- }
- break;
- }
- }
-#else
val = s->token.u.num.val;
if (is_neg) {
double d;
JS_ToFloat64(ctx, &d, val); /* no exception possible */
val = JS_NewFloat64(ctx, -d);
}
-#endif
if (next_token(s))
goto fail;
break;
@@ -42168,10 +41862,6 @@ static JSValue JS_ToQuotedStringFree(JSContext *ctx, JSValue val) {
return r;
}
-#ifdef CONFIG_BIGNUM
-static inline BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v);
-#endif
-
static JSValue js_json_check(JSContext *ctx, JSONStringifyContext *jsc,
JSValueConst holder, JSValue val, JSValueConst key)
{
@@ -46764,7 +46454,8 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
double d;
int p, i, c, sgn;
JSString *sp;
-
+ BOOL is_local;
+
rv = JS_NAN;
s = JS_ToString(ctx, argv[0]);
@@ -46780,11 +46471,15 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
if (string_get_signed_field(sp, &p, &fields[0]))
goto done;
+ is_local = TRUE;
for (i = 1; i < 6; i++) {
if (string_get_field(sp, &p, &fields[i]))
break;
}
- if (i == 6 && p < sp->len && string_get(sp, p) == '.') {
+ 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;
@@ -46802,14 +46497,20 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
/* parse the time zone offset if present: [+-]HH:mm */
tz = 0;
- if (p < sp->len && ((sgn = string_get(sp, p)) == '+' || sgn == '-')) {
- if (string_get_field(sp, &p, &hh))
- goto done;
- if (string_get_field(sp, &p, &mm))
- goto done;
- tz = hh * 60 + mm;
- if (sgn == '-')
- tz = -tz;
+ if (p < sp->len) {
+ sgn = string_get(sp, p);
+ if (sgn == '+' || sgn == '-') {
+ if (string_get_field(sp, &p, &hh))
+ goto done;
+ if (string_get_field(sp, &p, &mm))
+ goto done;
+ tz = hh * 60 + mm;
+ if (sgn == '-')
+ tz = -tz;
+ is_local = FALSE;
+ } else if (sgn == 'Z') {
+ is_local = FALSE;
+ }
}
} else {
/* toString or toUTCString format */
@@ -46844,6 +46545,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
// XXX: parse optional milliseconds?
/* parse the time zone offset if present: [+-]HHmm */
+ is_local = FALSE;
tz = 0;
for (tz = 0; p < sp->len; p++) {
sgn = string_get(sp, p);
@@ -46860,7 +46562,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
}
}
}
- d = set_date_fields(fields, 0) - tz * 60000;
+ d = set_date_fields(fields, is_local) - tz * 60000;
rv = __JS_NewFloat64(ctx, d);
done:
@@ -47080,61 +46782,364 @@ void JS_AddIntrinsicEval(JSContext *ctx)
#ifdef CONFIG_BIGNUM
+/* Operators */
+
+static void js_operator_set_finalizer(JSRuntime *rt, JSValue val)
+{
+ JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
+ int i, j;
+ JSBinaryOperatorDefEntry *ent;
+
+ if (opset) {
+ for(i = 0; i < JS_OVOP_COUNT; i++) {
+ if (opset->self_ops[i])
+ JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]));
+ }
+ for(j = 0; j < opset->left.count; j++) {
+ ent = &opset->left.tab[j];
+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+ if (ent->ops[i])
+ JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
+ }
+ }
+ js_free_rt(rt, opset->left.tab);
+ for(j = 0; j < opset->right.count; j++) {
+ ent = &opset->right.tab[j];
+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+ if (ent->ops[i])
+ JS_FreeValueRT(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]));
+ }
+ }
+ js_free_rt(rt, opset->right.tab);
+ js_free_rt(rt, opset);
+ }
+}
+
+static void js_operator_set_mark(JSRuntime *rt, JSValueConst val,
+ JS_MarkFunc *mark_func)
+{
+ JSOperatorSetData *opset = JS_GetOpaque(val, JS_CLASS_OPERATOR_SET);
+ int i, j;
+ JSBinaryOperatorDefEntry *ent;
+
+ if (opset) {
+ for(i = 0; i < JS_OVOP_COUNT; i++) {
+ if (opset->self_ops[i])
+ JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[i]),
+ mark_func);
+ }
+ for(j = 0; j < opset->left.count; j++) {
+ ent = &opset->left.tab[j];
+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+ if (ent->ops[i])
+ JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
+ mark_func);
+ }
+ }
+ for(j = 0; j < opset->right.count; j++) {
+ ent = &opset->right.tab[j];
+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+ if (ent->ops[i])
+ JS_MarkValue(rt, JS_MKPTR(JS_TAG_OBJECT, ent->ops[i]),
+ mark_func);
+ }
+ }
+ }
+}
+
+
+/* create an OperatorSet object */
+static JSValue js_operators_create_internal(JSContext *ctx,
+ int argc, JSValueConst *argv,
+ BOOL is_primitive)
+{
+ JSValue opset_obj, prop, obj;
+ JSOperatorSetData *opset, *opset1;
+ JSBinaryOperatorDef *def;
+ JSValueConst arg;
+ int i, j;
+ JSBinaryOperatorDefEntry *new_tab;
+ JSBinaryOperatorDefEntry *ent;
+ uint32_t op_count;
+
+ if (ctx->rt->operator_count == UINT32_MAX) {
+ return JS_ThrowTypeError(ctx, "too many operators");
+ }
+ opset_obj = JS_NewObjectProtoClass(ctx, JS_NULL, JS_CLASS_OPERATOR_SET);
+ if (JS_IsException(opset_obj))
+ goto fail;
+ opset = js_mallocz(ctx, sizeof(*opset));
+ if (!opset)
+ goto fail;
+ JS_SetOpaque(opset_obj, opset);
+ if (argc >= 1) {
+ arg = argv[0];
+ /* self operators */
+ for(i = 0; i < JS_OVOP_COUNT; i++) {
+ prop = JS_GetPropertyStr(ctx, arg, js_overloadable_operator_names[i]);
+ if (JS_IsException(prop))
+ goto fail;
+ if (!JS_IsUndefined(prop)) {
+ if (check_function(ctx, prop)) {
+ JS_FreeValue(ctx, prop);
+ goto fail;
+ }
+ opset->self_ops[i] = JS_VALUE_GET_OBJ(prop);
+ }
+ }
+ }
+ /* left & right operators */
+ for(j = 1; j < argc; j++) {
+ arg = argv[j];
+ prop = JS_GetPropertyStr(ctx, arg, "left");
+ if (JS_IsException(prop))
+ goto fail;
+ def = &opset->right;
+ if (JS_IsUndefined(prop)) {
+ prop = JS_GetPropertyStr(ctx, arg, "right");
+ if (JS_IsException(prop))
+ goto fail;
+ if (JS_IsUndefined(prop)) {
+ JS_ThrowTypeError(ctx, "left or right property must be present");
+ goto fail;
+ }
+ def = &opset->left;
+ }
+ /* get the operator set */
+ obj = JS_GetProperty(ctx, prop, JS_ATOM_prototype);
+ JS_FreeValue(ctx, prop);
+ if (JS_IsException(obj))
+ goto fail;
+ prop = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_operatorSet);
+ JS_FreeValue(ctx, obj);
+ if (JS_IsException(prop))
+ goto fail;
+ opset1 = JS_GetOpaque2(ctx, prop, JS_CLASS_OPERATOR_SET);
+ if (!opset1) {
+ JS_FreeValue(ctx, prop);
+ goto fail;
+ }
+ op_count = opset1->operator_counter;
+ JS_FreeValue(ctx, prop);
+
+ /* we assume there are few entries */
+ new_tab = js_realloc(ctx, def->tab,
+ (def->count + 1) * sizeof(def->tab[0]));
+ if (!new_tab)
+ goto fail;
+ def->tab = new_tab;
+ def->count++;
+ ent = def->tab + def->count - 1;
+ memset(ent, 0, sizeof(def->tab[0]));
+ ent->operator_index = op_count;
+
+ for(i = 0; i < JS_OVOP_BINARY_COUNT; i++) {
+ prop = JS_GetPropertyStr(ctx, arg,
+ js_overloadable_operator_names[i]);
+ if (JS_IsException(prop))
+ goto fail;
+ if (!JS_IsUndefined(prop)) {
+ if (check_function(ctx, prop)) {
+ JS_FreeValue(ctx, prop);
+ goto fail;
+ }
+ ent->ops[i] = JS_VALUE_GET_OBJ(prop);
+ }
+ }
+ }
+ opset->is_primitive = is_primitive;
+ opset->operator_counter = ctx->rt->operator_count++;
+ return opset_obj;
+ fail:
+ JS_FreeValue(ctx, opset_obj);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_operators_create(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ return js_operators_create_internal(ctx, argc, argv, FALSE);
+}
+
+static JSValue js_operators_updateBigIntOperators(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue opset_obj, prop;
+ JSOperatorSetData *opset;
+ const JSOverloadableOperatorEnum ops[2] = { JS_OVOP_DIV, JS_OVOP_POW };
+ JSOverloadableOperatorEnum op;
+ int i;
+
+ opset_obj = JS_GetProperty(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
+ JS_ATOM_Symbol_operatorSet);
+ if (JS_IsException(opset_obj))
+ goto fail;
+ opset = JS_GetOpaque2(ctx, opset_obj, JS_CLASS_OPERATOR_SET);
+ if (!opset)
+ goto fail;
+ for(i = 0; i < countof(ops); i++) {
+ op = ops[i];
+ prop = JS_GetPropertyStr(ctx, argv[0],
+ js_overloadable_operator_names[op]);
+ if (JS_IsException(prop))
+ goto fail;
+ if (!JS_IsUndefined(prop)) {
+ if (!JS_IsNull(prop) && check_function(ctx, prop)) {
+ JS_FreeValue(ctx, prop);
+ goto fail;
+ }
+ if (opset->self_ops[op])
+ JS_FreeValue(ctx, JS_MKPTR(JS_TAG_OBJECT, opset->self_ops[op]));
+ if (JS_IsNull(prop)) {
+ opset->self_ops[op] = NULL;
+ } else {
+ opset->self_ops[op] = JS_VALUE_GET_PTR(prop);
+ }
+ }
+ }
+ JS_FreeValue(ctx, opset_obj);
+ return JS_UNDEFINED;
+ fail:
+ JS_FreeValue(ctx, opset_obj);
+ return JS_EXCEPTION;
+}
+
+static int js_operators_set_default(JSContext *ctx, JSValueConst obj)
+{
+ JSValue opset_obj;
+
+ if (!JS_IsObject(obj)) /* in case the prototype is not defined */
+ return 0;
+ opset_obj = js_operators_create_internal(ctx, 0, NULL, TRUE);
+ if (JS_IsException(opset_obj))
+ return -1;
+ /* cannot be modified by the user */
+ JS_DefinePropertyValue(ctx, obj, JS_ATOM_Symbol_operatorSet,
+ opset_obj, 0);
+ return 0;
+}
+
+static JSValue js_dummy_operators_ctor(JSContext *ctx, JSValueConst new_target,
+ int argc, JSValueConst *argv)
+{
+ return js_create_from_ctor(ctx, new_target, JS_CLASS_OBJECT);
+}
+
+static JSValue js_global_operators(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue func_obj, proto, opset_obj;
+
+ func_obj = JS_UNDEFINED;
+ proto = JS_NewObject(ctx);
+ if (JS_IsException(proto))
+ return JS_EXCEPTION;
+ opset_obj = js_operators_create_internal(ctx, argc, argv, FALSE);
+ if (JS_IsException(opset_obj))
+ goto fail;
+ JS_DefinePropertyValue(ctx, proto, JS_ATOM_Symbol_operatorSet,
+ opset_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ func_obj = JS_NewCFunction2(ctx, js_dummy_operators_ctor, "Operators",
+ 0, JS_CFUNC_constructor, 0);
+ if (JS_IsException(func_obj))
+ goto fail;
+ JS_SetConstructor2(ctx, func_obj, proto,
+ 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ JS_FreeValue(ctx, proto);
+ return func_obj;
+ fail:
+ JS_FreeValue(ctx, proto);
+ JS_FreeValue(ctx, func_obj);
+ return JS_EXCEPTION;
+}
+
+static const JSCFunctionListEntry js_operators_funcs[] = {
+ JS_CFUNC_DEF("create", 1, js_operators_create ),
+ JS_CFUNC_DEF("updateBigIntOperators", 2, js_operators_updateBigIntOperators ),
+};
+
+/* must be called after all overloadable base types are initialized */
+void JS_AddIntrinsicOperators(JSContext *ctx)
+{
+ JSValue obj;
+
+ ctx->allow_operator_overloading = TRUE;
+ obj = JS_NewCFunction(ctx, js_global_operators, "Operators", 1);
+ JS_SetPropertyFunctionList(ctx, obj,
+ js_operators_funcs,
+ countof(js_operators_funcs));
+ JS_DefinePropertyValue(ctx, ctx->global_obj, JS_ATOM_Operators,
+ obj,
+ JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
+ /* add default operatorSets */
+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BOOLEAN]);
+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_NUMBER]);
+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_STRING]);
+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_INT]);
+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT]);
+ js_operators_set_default(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
+}
+
/* BigInt */
static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
{
uint32_t tag;
- BOOL is_legacy;
- int ret;
- is_legacy = is_bigint_mode(ctx) ^ 1;
redo:
tag = JS_VALUE_GET_NORM_TAG(val);
switch(tag) {
case JS_TAG_INT:
case JS_TAG_BOOL:
- if (is_legacy) {
- bf_t r_s, *r = &r_s;
- bf_init(ctx->bf_ctx, r);
- bf_set_si(r, JS_VALUE_GET_INT(val));
- val = JS_NewBigInt2(ctx, r, TRUE);
- } else {
- val = JS_NewInt32(ctx, JS_VALUE_GET_INT(val));
- }
+ val = JS_NewBigInt64(ctx, JS_VALUE_GET_INT(val));
break;
case JS_TAG_BIG_INT:
break;
case JS_TAG_FLOAT64:
case JS_TAG_BIG_FLOAT:
{
- bf_t *a, a_s, r_s, *r = &r_s;
+ bf_t *a, a_s;
+
a = JS_ToBigFloat(ctx, &a_s, val);
- bf_init(ctx->bf_ctx, r);
if (!bf_is_finite(a)) {
JS_FreeValue(ctx, val);
val = JS_ThrowRangeError(ctx, "cannot convert NaN or Infinity to bigint");
} else {
- bf_set(r, a);
- ret = bf_rint(r, BF_RNDZ);
+ JSValue val1 = JS_NewBigInt(ctx);
+ bf_t *r;
+ int ret;
+ if (JS_IsException(val1)) {
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+ }
+ r = JS_GetBigInt(val1);
+ ret = bf_set(r, a);
+ ret |= bf_rint(r, BF_RNDZ);
JS_FreeValue(ctx, val);
- if (is_legacy && (ret & BF_ST_INEXACT)) {
- bf_delete(r);
+ if (ret & BF_ST_MEM_ERROR) {
+ JS_FreeValue(ctx, val1);
+ val = JS_ThrowOutOfMemory(ctx);
+ } else if (ret & BF_ST_INEXACT) {
+ JS_FreeValue(ctx, val1);
val = JS_ThrowRangeError(ctx, "cannot convert to bigint: not an integer");
} else {
- val = JS_NewBigInt2(ctx, r, is_legacy);
+ val = JS_CompactBigInt(ctx, val1);
}
}
if (a == &a_s)
bf_delete(a);
}
break;
+ case JS_TAG_BIG_DECIMAL:
+ val = JS_ToStringFree(ctx, val);
+ if (JS_IsException(val))
+ break;
+ goto redo;
case JS_TAG_STRING:
val = JS_StringToBigIntErr(ctx, val);
break;
case JS_TAG_OBJECT:
- val = JS_ToPrimitiveFree(ctx, val,
- is_legacy ? HINT_NUMBER : HINT_INTEGER);
+ val = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
if (JS_IsException(val))
break;
goto redo;
@@ -47154,17 +47159,6 @@ static JSValue js_bigint_constructor(JSContext *ctx,
return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
}
-static inline BOOL JS_IsBigInt(JSContext *ctx, JSValueConst v)
-{
- int tag = JS_VALUE_GET_TAG(v);
- if (tag == JS_TAG_BIG_INT)
- return TRUE;
- if (is_bigint_mode(ctx))
- return tag == JS_TAG_INT;
- else
- return FALSE;
-}
-
static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
{
if (JS_IsBigInt(ctx, this_val))
@@ -47173,8 +47167,6 @@ static JSValue js_thisBigIntValue(JSContext *ctx, JSValueConst this_val)
if (JS_VALUE_GET_TAG(this_val) == JS_TAG_OBJECT) {
JSObject *p = JS_VALUE_GET_OBJ(this_val);
if (p->class_id == JS_CLASS_BIG_INT) {
- /* XXX: may relax the check in case the object comes from
- bignum mode */
if (JS_IsBigInt(ctx, p->u.object_data))
return JS_DupValue(ctx, p->u.object_data);
}
@@ -47195,12 +47187,9 @@ static JSValue js_bigint_toString(JSContext *ctx, JSValueConst this_val,
if (argc == 0 || JS_IsUndefined(argv[0])) {
base = 10;
} else {
- if (JS_ToInt32Sat(ctx, &base, argv[0]))
+ base = js_get_radix(ctx, argv[0]);
+ if (base < 0)
goto fail;
- if (base < 2 || base > 36) {
- JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
- goto fail;
- }
}
ret = js_bigint_to_string1(ctx, val, base);
JS_FreeValue(ctx, val);
@@ -47220,72 +47209,96 @@ static JSValue js_bigint_div(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
- bf_t a_s, b_s, *a, *b, r_s, *r = &r_s, q_s, *q = &q_s;
+ bf_t a_s, b_s, *a, *b, *r, *q;
int status;
-
+ JSValue q_val, r_val;
+
+ q_val = JS_NewBigInt(ctx);
+ if (JS_IsException(q_val))
+ return JS_EXCEPTION;
+ r_val = JS_NewBigInt(ctx);
+ if (JS_IsException(r_val))
+ goto fail;
b = NULL;
a = JS_ToBigInt(ctx, &a_s, argv[0]);
if (!a)
- return JS_EXCEPTION;
+ goto fail;
b = JS_ToBigInt(ctx, &b_s, argv[1]);
if (!b) {
JS_FreeBigInt(ctx, a, &a_s);
- return JS_EXCEPTION;
+ goto fail;
}
- bf_init(ctx->bf_ctx, q);
- bf_init(ctx->bf_ctx, r);
+ q = JS_GetBigInt(q_val);
+ r = JS_GetBigInt(r_val);
status = bf_divrem(q, r, a, b, BF_PREC_INF, BF_RNDZ, magic & 0xf);
JS_FreeBigInt(ctx, a, &a_s);
JS_FreeBigInt(ctx, b, &b_s);
if (unlikely(status)) {
- bf_delete(q);
- bf_delete(r);
throw_bf_exception(ctx, status);
- return JS_EXCEPTION;
+ goto fail;
}
+ q_val = JS_CompactBigInt(ctx, q_val);
if (magic & 0x10) {
JSValue ret;
- /* XXX: handle exceptions */
ret = JS_NewArray(ctx);
- JS_SetPropertyUint32(ctx, ret, 0, JS_NewBigInt(ctx, q));
- JS_SetPropertyUint32(ctx, ret, 1, JS_NewBigInt(ctx, r));
+ if (JS_IsException(ret))
+ goto fail;
+ JS_SetPropertyUint32(ctx, ret, 0, q_val);
+ JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, r_val));
return ret;
} else {
- bf_delete(r);
- return JS_NewBigInt(ctx, q);
+ JS_FreeValue(ctx, r_val);
+ return q_val;
}
+ fail:
+ JS_FreeValue(ctx, q_val);
+ JS_FreeValue(ctx, r_val);
+ return JS_EXCEPTION;
}
static JSValue js_bigint_sqrt(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
- bf_t a_s, *a, r_s, *r = &r_s, rem_s, *rem = &rem_s;
+ bf_t a_s, *a, *r, *rem;
int status;
+ JSValue r_val, rem_val;
+
+ r_val = JS_NewBigInt(ctx);
+ if (JS_IsException(r_val))
+ return JS_EXCEPTION;
+ rem_val = JS_NewBigInt(ctx);
+ if (JS_IsException(rem_val))
+ return JS_EXCEPTION;
+ r = JS_GetBigInt(r_val);
+ rem = JS_GetBigInt(rem_val);
a = JS_ToBigInt(ctx, &a_s, argv[0]);
if (!a)
- return JS_EXCEPTION;
- bf_init(ctx->bf_ctx, r);
- bf_init(ctx->bf_ctx, rem);
+ goto fail;
status = bf_sqrtrem(r, rem, a);
JS_FreeBigInt(ctx, a, &a_s);
if (unlikely(status & ~BF_ST_INEXACT)) {
- bf_delete(r);
- bf_delete(rem);
- return throw_bf_exception(ctx, status);
+ throw_bf_exception(ctx, status);
+ goto fail;
}
+ r_val = JS_CompactBigInt(ctx, r_val);
if (magic) {
JSValue ret;
- /* XXX: handle exceptions */
ret = JS_NewArray(ctx);
- JS_SetPropertyUint32(ctx, ret, 0, JS_NewBigInt(ctx, r));
- JS_SetPropertyUint32(ctx, ret, 1, JS_NewBigInt(ctx, rem));
+ if (JS_IsException(ret))
+ goto fail;
+ JS_SetPropertyUint32(ctx, ret, 0, r_val);
+ JS_SetPropertyUint32(ctx, ret, 1, JS_CompactBigInt(ctx, rem_val));
return ret;
} else {
- bf_delete(rem);
- return JS_NewBigInt(ctx, r);
+ JS_FreeValue(ctx, rem_val);
+ return r_val;
}
+ fail:
+ JS_FreeValue(ctx, r_val);
+ JS_FreeValue(ctx, rem_val);
+ return JS_EXCEPTION;
}
static JSValue js_bigint_op1(JSContext *ctx,
@@ -47326,15 +47339,22 @@ static JSValue js_bigint_asUintN(JSContext *ctx,
int argc, JSValueConst *argv, int asIntN)
{
uint64_t bits;
- bf_t a_s, *a = &a_s, r_s, *r = &r_s, mask_s, *mask = &mask_s;
-
+ bf_t a_s, *a = &a_s, *r, mask_s, *mask = &mask_s;
+ JSValue res;
+
if (JS_ToIndex(ctx, &bits, argv[0]))
return JS_EXCEPTION;
+ res = JS_NewBigInt(ctx);
+ if (JS_IsException(res))
+ return JS_EXCEPTION;
+ r = JS_GetBigInt(res);
a = JS_ToBigInt(ctx, &a_s, argv[1]);
- if (!a)
+ if (!a) {
+ JS_FreeValue(ctx, res);
return JS_EXCEPTION;
+ }
/* XXX: optimize */
- bf_init(ctx->bf_ctx, r);
+ r = JS_GetBigInt(res);
bf_init(ctx->bf_ctx, mask);
bf_set_ui(mask, 1);
bf_mul_2exp(mask, bits, BF_PREC_INF, BF_RNDZ);
@@ -47351,7 +47371,7 @@ static JSValue js_bigint_asUintN(JSContext *ctx,
}
bf_delete(mask);
JS_FreeBigInt(ctx, a, &a_s);
- return JS_NewBigInt(ctx, r);
+ return JS_CompactBigInt(ctx, res);
}
static const JSCFunctionListEntry js_bigint_funcs[] = {
@@ -47430,12 +47450,9 @@ static JSValue js_bigfloat_toString(JSContext *ctx, JSValueConst this_val,
if (argc == 0 || JS_IsUndefined(argv[0])) {
base = 10;
} else {
- if (JS_ToInt32Sat(ctx, &base, argv[0]))
+ base = js_get_radix(ctx, argv[0]);
+ if (base < 0)
goto fail;
- if (base < 2 || base > 36) {
- JS_ThrowRangeError(ctx, "radix must be between 2 and 36");
- goto fail;
- }
}
ret = js_ftoa(ctx, val, base, 0, BF_RNDN | BF_FTOA_FORMAT_FREE_MIN);
JS_FreeValue(ctx, val);
@@ -47451,7 +47468,7 @@ static JSValue js_bigfloat_valueOf(JSContext *ctx, JSValueConst this_val,
return js_thisBigFloatValue(ctx, this_val);
}
-static int get_rnd_mode(JSContext *ctx, JSValueConst val)
+static int bigfloat_get_rnd_mode(JSContext *ctx, JSValueConst val)
{
int rnd_mode;
if (JS_ToInt32Sat(ctx, &rnd_mode, val))
@@ -47468,8 +47485,7 @@ static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val,
{
JSValue val, ret;
int64_t f;
- int res, rnd_mode;
- bf_t a_s, *a, b;
+ int rnd_mode, radix;
val = js_thisBigFloatValue(ctx, this_val);
if (JS_IsException(val))
@@ -47481,26 +47497,19 @@ static JSValue js_bigfloat_toFixed(JSContext *ctx, JSValueConst this_val,
goto fail;
}
rnd_mode = BF_RNDNA;
+ radix = 10;
+ /* XXX: swap parameter order for rounding mode and radix */
if (argc > 1) {
- rnd_mode = get_rnd_mode(ctx, argv[1]);
+ rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
if (rnd_mode < 0)
goto fail;
}
-
- a = JS_ToBigFloat(ctx, &a_s, val);
- if (!a)
- goto fail;
- bf_init(ctx->bf_ctx, &b);
- bf_set_float64(&b, 1e21);
- res = bf_cmpu(a, &b);
- bf_delete(&b);
- if (a == &a_s)
- bf_delete(a);
- if (res >= 0) {
- ret = JS_ToString(ctx, val);
- } else {
- ret = js_ftoa(ctx, val, 10, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
+ if (argc > 2) {
+ radix = js_get_radix(ctx, argv[2]);
+ if (radix < 0)
+ goto fail;
}
+ ret = js_ftoa(ctx, val, radix, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
JS_FreeValue(ctx, val);
return ret;
fail:
@@ -47533,7 +47542,7 @@ static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val,
{
JSValue val, ret;
int64_t f;
- int rnd_mode;
+ int rnd_mode, radix;
val = js_thisBigFloatValue(ctx, this_val);
if (JS_IsException(val))
@@ -47551,12 +47560,18 @@ static JSValue js_bigfloat_toExponential(JSContext *ctx, JSValueConst this_val,
goto fail;
}
rnd_mode = BF_RNDNA;
+ radix = 10;
if (argc > 1) {
- rnd_mode = get_rnd_mode(ctx, argv[1]);
+ rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
if (rnd_mode < 0)
goto fail;
}
- ret = js_ftoa(ctx, val, 10, f + 1,
+ if (argc > 2) {
+ radix = js_get_radix(ctx, argv[2]);
+ if (radix < 0)
+ goto fail;
+ }
+ ret = js_ftoa(ctx, val, radix, f + 1,
rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
}
JS_FreeValue(ctx, val);
@@ -47571,7 +47586,7 @@ static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val,
{
JSValue val, ret;
int64_t p;
- int rnd_mode;
+ int rnd_mode, radix;
val = js_thisBigFloatValue(ctx, this_val);
if (JS_IsException(val))
@@ -47589,12 +47604,18 @@ static JSValue js_bigfloat_toPrecision(JSContext *ctx, JSValueConst this_val,
goto fail;
}
rnd_mode = BF_RNDNA;
+ radix = 10;
if (argc > 1) {
- rnd_mode = get_rnd_mode(ctx, argv[1]);
+ rnd_mode = bigfloat_get_rnd_mode(ctx, argv[1]);
if (rnd_mode < 0)
goto fail;
}
- ret = js_ftoa(ctx, val, 10, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
+ if (argc > 2) {
+ radix = js_get_radix(ctx, argv[2]);
+ if (radix < 0)
+ goto fail;
+ }
+ ret = js_ftoa(ctx, val, radix, p, rnd_mode | BF_FTOA_FORMAT_FIXED);
}
JS_FreeValue(ctx, val);
return ret;
@@ -47617,10 +47638,12 @@ static JSValue js_bigfloat_constructor(JSContext *ctx,
{
JSValue val;
if (argc == 0) {
- bf_t r_s, *r = &r_s;
- bf_init(ctx->bf_ctx, r);
+ bf_t *r;
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ return val;
+ r = JS_GetBigFloat(val);
bf_set_zero(r, 0);
- val = JS_NewBigFloat(ctx, r);
} else {
val = JS_DupValue(ctx, argv[0]);
redo:
@@ -47629,18 +47652,26 @@ static JSValue js_bigfloat_constructor(JSContext *ctx,
break;
case JS_TAG_FLOAT64:
{
- bf_t r_s, *r = &r_s;
- bf_init(ctx->bf_ctx, r);
- bf_set_float64(r, JS_VALUE_GET_FLOAT64(val));
- val = JS_NewBigFloat(ctx, r);
+ bf_t *r;
+ double d = JS_VALUE_GET_FLOAT64(val);
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ break;
+ r = JS_GetBigFloat(val);
+ if (bf_set_float64(r, d))
+ goto fail;
}
break;
case JS_TAG_INT:
{
- bf_t r_s, *r = &r_s;
- bf_init(ctx->bf_ctx, r);
- bf_set_si(r, JS_VALUE_GET_INT(val));
- val = JS_NewBigFloat(ctx, r);
+ bf_t *r;
+ int32_t v = JS_VALUE_GET_INT(val);
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ break;
+ r = JS_GetBigFloat(val);
+ if (bf_set_si(r, v))
+ goto fail;
}
break;
case JS_TAG_BIG_INT:
@@ -47650,6 +47681,11 @@ static JSValue js_bigfloat_constructor(JSContext *ctx,
val = JS_MKPTR(JS_TAG_BIG_FLOAT, p);
}
break;
+ case JS_TAG_BIG_DECIMAL:
+ val = JS_ToStringFree(ctx, val);
+ if (JS_IsException(val))
+ break;
+ goto redo;
case JS_TAG_STRING:
{
const char *str, *p;
@@ -47663,10 +47699,12 @@ static JSValue js_bigfloat_constructor(JSContext *ctx,
p = str;
p += skip_spaces(p);
if ((p - str) == len) {
- bf_t r_s, *r = &r_s;
- bf_init(ctx->bf_ctx, r);
- bf_set_si(r, 0);
- val = JS_NewBigFloat(ctx, r);
+ bf_t *r;
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ break;
+ r = JS_GetBigFloat(val);
+ bf_set_zero(r, 0);
err = 0;
} else {
val = js_atof(ctx, p, &p, 0, ATOD_ACCEPT_BIN_OCT |
@@ -47699,13 +47737,20 @@ static JSValue js_bigfloat_constructor(JSContext *ctx,
}
}
return val;
+ fail:
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
}
static JSValue js_bigfloat_get_const(JSContext *ctx,
- JSValueConst this_val, int magic)
+ JSValueConst this_val, int magic)
{
- bf_t r_s, *r = &r_s;
- bf_init(ctx->bf_ctx, r);
+ bf_t *r;
+ JSValue val;
+ val = JS_NewBigFloat(ctx);
+ if (JS_IsException(val))
+ return val;
+ r = JS_GetBigFloat(val);
switch(magic) {
case 0: /* PI */
bf_const_pi(r, ctx->fp_env.prec, ctx->fp_env.flags);
@@ -47741,13 +47786,13 @@ static JSValue js_bigfloat_get_const(JSContext *ctx,
default:
abort();
}
- return JS_NewBigFloat(ctx, r);
+ return val;
}
static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- bf_t a_s, *a = &a_s;
+ bf_t *a;
const char *str;
JSValue ret;
int radix;
@@ -47771,10 +47816,13 @@ static JSValue js_bigfloat_parseFloat(JSContext *ctx, JSValueConst this_val,
if (!fe)
goto fail;
}
- bf_init(ctx->bf_ctx, a);
+ ret = JS_NewBigFloat(ctx);
+ if (JS_IsException(ret))
+ goto done;
+ a = JS_GetBigFloat(ret);
/* XXX: use js_atof() */
bf_atof(a, str, NULL, radix, fe->prec, fe->flags);
- ret = JS_NewBigFloat(ctx, a);
+ done:
JS_FreeCString(ctx, str);
return ret;
}
@@ -47800,7 +47848,201 @@ static JSValue js_bigfloat_isNaN(JSContext *ctx, JSValueConst this_val,
if (JS_VALUE_GET_NORM_TAG(val) != JS_TAG_BIG_FLOAT)
return JS_FALSE;
p = JS_VALUE_GET_PTR(val);
- return JS_NewBool(ctx, bf_is_finite(&p->num));
+ return JS_NewBool(ctx, bf_is_nan(&p->num));
+}
+
+enum {
+ MATH_OP_ABS,
+ MATH_OP_FLOOR,
+ MATH_OP_CEIL,
+ MATH_OP_ROUND,
+ MATH_OP_TRUNC,
+ MATH_OP_SQRT,
+ MATH_OP_FPROUND,
+ MATH_OP_ACOS,
+ MATH_OP_ASIN,
+ MATH_OP_ATAN,
+ MATH_OP_ATAN2,
+ MATH_OP_COS,
+ MATH_OP_EXP,
+ MATH_OP_LOG,
+ MATH_OP_POW,
+ MATH_OP_SIN,
+ MATH_OP_TAN,
+ MATH_OP_FMOD,
+ MATH_OP_REM,
+ MATH_OP_SIGN,
+
+ MATH_OP_ADD,
+ MATH_OP_SUB,
+ MATH_OP_MUL,
+ MATH_OP_DIV,
+};
+
+static JSValue js_bigfloat_fop(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic)
+{
+ bf_t a_s, *a, *r;
+ JSFloatEnv *fe;
+ int rnd_mode;
+ JSValue op1, res;
+
+ op1 = JS_ToNumeric(ctx, argv[0]);
+ if (JS_IsException(op1))
+ return op1;
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ fe = &ctx->fp_env;
+ if (argc > 1) {
+ fe = JS_GetOpaque2(ctx, argv[1], JS_CLASS_FLOAT_ENV);
+ if (!fe)
+ goto fail;
+ }
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res)) {
+ fail:
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, op1);
+ return JS_EXCEPTION;
+ }
+ r = JS_GetBigFloat(res);
+ switch (magic) {
+ case MATH_OP_ABS:
+ bf_set(r, a);
+ r->sign = 0;
+ break;
+ case MATH_OP_FLOOR:
+ rnd_mode = BF_RNDD;
+ goto rint;
+ case MATH_OP_CEIL:
+ rnd_mode = BF_RNDU;
+ goto rint;
+ case MATH_OP_ROUND:
+ rnd_mode = BF_RNDNA;
+ goto rint;
+ case MATH_OP_TRUNC:
+ rnd_mode = BF_RNDZ;
+ rint:
+ bf_set(r, a);
+ fe->status |= bf_rint(r, rnd_mode);
+ break;
+ case MATH_OP_SQRT:
+ fe->status |= bf_sqrt(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_FPROUND:
+ bf_set(r, a);
+ fe->status |= bf_round(r, fe->prec, fe->flags);
+ break;
+ case MATH_OP_ACOS:
+ fe->status |= bf_acos(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_ASIN:
+ fe->status |= bf_asin(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_ATAN:
+ fe->status |= bf_atan(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_COS:
+ fe->status |= bf_cos(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_EXP:
+ fe->status |= bf_exp(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_LOG:
+ fe->status |= bf_log(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_SIN:
+ fe->status |= bf_sin(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_TAN:
+ fe->status |= bf_tan(r, a, fe->prec, fe->flags);
+ break;
+ case MATH_OP_SIGN:
+ if (bf_is_nan(a) || bf_is_zero(a)) {
+ bf_set(r, a);
+ } else {
+ bf_set_si(r, 1 - 2 * a->sign);
+ }
+ break;
+ default:
+ abort();
+ }
+ if (a == &a_s)
+ bf_delete(a);
+ JS_FreeValue(ctx, op1);
+ return res;
+}
+
+static JSValue js_bigfloat_fop2(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv, int magic)
+{
+ bf_t a_s, *a, b_s, *b, r_s, *r = &r_s;
+ JSFloatEnv *fe;
+ JSValue op1, op2, res;
+
+ op1 = JS_ToNumeric(ctx, argv[0]);
+ if (JS_IsException(op1))
+ return op1;
+ op2 = JS_ToNumeric(ctx, argv[1]);
+ if (JS_IsException(op2)) {
+ JS_FreeValue(ctx, op1);
+ return op2;
+ }
+ a = JS_ToBigFloat(ctx, &a_s, op1);
+ b = JS_ToBigFloat(ctx, &b_s, op2);
+ fe = &ctx->fp_env;
+ if (argc > 2) {
+ fe = JS_GetOpaque2(ctx, argv[2], JS_CLASS_FLOAT_ENV);
+ if (!fe)
+ goto fail;
+ }
+ res = JS_NewBigFloat(ctx);
+ if (JS_IsException(res)) {
+ fail:
+ if (a == &a_s)
+ bf_delete(a);
+ if (b == &b_s)
+ bf_delete(b);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return JS_EXCEPTION;
+ }
+ r = JS_GetBigFloat(res);
+ switch (magic) {
+ case MATH_OP_ATAN2:
+ fe->status |= bf_atan2(r, a, b, fe->prec, fe->flags);
+ break;
+ case MATH_OP_POW:
+ fe->status |= bf_pow(r, a, b, fe->prec, fe->flags | BF_POW_JS_QUIRKS);
+ break;
+ case MATH_OP_FMOD:
+ fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
+ break;
+ case MATH_OP_REM:
+ fe->status |= bf_rem(r, a, b, fe->prec, fe->flags, BF_RNDN);
+ break;
+ case MATH_OP_ADD:
+ fe->status |= bf_add(r, a, b, fe->prec, fe->flags);
+ break;
+ case MATH_OP_SUB:
+ fe->status |= bf_sub(r, a, b, fe->prec, fe->flags);
+ break;
+ case MATH_OP_MUL:
+ fe->status |= bf_mul(r, a, b, fe->prec, fe->flags);
+ break;
+ case MATH_OP_DIV:
+ fe->status |= bf_div(r, a, b, fe->prec, fe->flags);
+ break;
+ default:
+ abort();
+ }
+ if (a == &a_s)
+ bf_delete(a);
+ if (b == &b_s)
+ bf_delete(b);
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return res;
}
static const JSCFunctionListEntry js_bigfloat_funcs[] = {
@@ -47895,9 +48137,6 @@ static JSValue js_float_env_get_expBits(JSContext *ctx, JSValueConst this_val)
return JS_NewInt32(ctx, bf_get_exp_bits(ctx->fp_env.flags));
}
-/* temporary fix for string conversion overflows */
-#define BF_EXP_BITS_MAX1 (BF_EXP_BITS_MAX - 1)
-
static JSValue js_float_env_setPrec(JSContext *ctx,
JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -47913,18 +48152,16 @@ static JSValue js_float_env_setPrec(JSContext *ctx,
return JS_EXCEPTION;
if (prec < BF_PREC_MIN || prec > BF_PREC_MAX)
return JS_ThrowRangeError(ctx, "invalid precision");
- exp_bits = BF_EXP_BITS_MAX1;
+ exp_bits = BF_EXP_BITS_MAX;
if (argc > 2 && !JS_IsUndefined(argv[2])) {
if (JS_ToInt32Sat(ctx, &exp_bits, argv[2]))
return JS_EXCEPTION;
- if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX1)
+ if (exp_bits < BF_EXP_BITS_MIN || exp_bits > BF_EXP_BITS_MAX)
return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
}
- flags = BF_RNDN | bf_set_exp_bits(exp_bits);
- if (exp_bits != BF_EXP_BITS_MAX1)
- flags |= BF_FLAG_SUBNORMAL;
+ flags = BF_RNDN | BF_FLAG_SUBNORMAL | bf_set_exp_bits(exp_bits);
saved_prec = ctx->fp_env.prec;
saved_flags = ctx->fp_env.flags;
@@ -47984,24 +48221,20 @@ static JSValue js_float_env_proto_set_status(JSContext *ctx, JSValueConst this_v
case FE_EXP:
if (JS_ToInt32Sat(ctx, &b, val))
return JS_EXCEPTION;
- if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX1)
+ if (b < BF_EXP_BITS_MIN || b > BF_EXP_BITS_MAX)
return JS_ThrowRangeError(ctx, "invalid number of exponent bits");
- if (b == BF_EXP_BITS_MAX1)
- fe->flags &= ~BF_FLAG_SUBNORMAL;
fe->flags = (fe->flags & ~(BF_EXP_BITS_MASK << BF_EXP_BITS_SHIFT)) |
bf_set_exp_bits(b);
break;
case FE_RNDMODE:
- b = get_rnd_mode(ctx, val);
+ b = bigfloat_get_rnd_mode(ctx, val);
if (b < 0)
return JS_EXCEPTION;
fe->flags = (fe->flags & ~BF_RND_MASK) | b;
break;
case FE_SUBNORMAL:
b = JS_ToBool(ctx, val);
- if (bf_get_exp_bits(fe->flags) != BF_EXP_BITS_MAX1) {
- fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
- }
+ fe->flags = (fe->flags & ~BF_FLAG_SUBNORMAL) | (b ? BF_FLAG_SUBNORMAL: 0);
break;
default:
b = JS_ToBool(ctx, val);
@@ -48031,12 +48264,12 @@ static const JSCFunctionListEntry js_float_env_funcs[] = {
JS_PROP_INT32_DEF("RNDU", BF_RNDU, 0 ),
JS_PROP_INT32_DEF("RNDD", BF_RNDD, 0 ),
JS_PROP_INT32_DEF("RNDNA", BF_RNDNA, 0 ),
- JS_PROP_INT32_DEF("RNDNU", BF_RNDNU, 0 ),
+ JS_PROP_INT32_DEF("RNDA", BF_RNDA, 0 ),
JS_PROP_INT32_DEF("RNDF", BF_RNDF, 0 ),
JS_PROP_INT32_DEF("precMin", BF_PREC_MIN, 0 ),
JS_PROP_INT64_DEF("precMax", BF_PREC_MAX, 0 ),
JS_PROP_INT32_DEF("expBitsMin", BF_EXP_BITS_MIN, 0 ),
- JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX1, 0 ),
+ JS_PROP_INT32_DEF("expBitsMax", BF_EXP_BITS_MAX, 0 ),
};
static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
@@ -48112,10 +48345,18 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
case JS_TAG_BOOL:
case JS_TAG_INT:
{
- bfdec_t r_s, *r = &r_s;
- bfdec_init(ctx->bf_ctx, r);
- bfdec_set_si(r, JS_VALUE_GET_INT(val));
- val = JS_NewBigDecimal(ctx, r);
+ bfdec_t *r;
+ int32_t v = JS_VALUE_GET_INT(val);
+
+ val = JS_NewBigDecimal(ctx);
+ if (JS_IsException(val))
+ break;
+ r = JS_GetBigDecimal(val);
+ if (bfdec_set_si(r, v)) {
+ JS_FreeValue(ctx, val);
+ val = JS_EXCEPTION;
+ break;
+ }
}
break;
case JS_TAG_FLOAT64:
@@ -48138,10 +48379,12 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
p = str;
p += skip_spaces(p);
if ((p - str) == len) {
- bfdec_t r_s, *r = &r_s;
- bfdec_init(ctx->bf_ctx, r);
+ bfdec_t *r;
+ val = JS_NewBigDecimal(ctx);
+ if (JS_IsException(val))
+ break;
+ r = JS_GetBigDecimal(val);
bfdec_set_zero(r, 0);
- val = JS_NewBigDecimal(ctx, r);
err = 0;
} else {
val = js_atof(ctx, p, &p, 0, ATOD_TYPE_BIG_DECIMAL);
@@ -48166,12 +48409,14 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
goto redo;
case JS_TAG_UNDEFINED:
{
- bfdec_t r_s, *r = &r_s;
+ bfdec_t *r;
if (!allow_null_or_undefined)
goto fail;
- bfdec_init(ctx->bf_ctx, r);
+ val = JS_NewBigDecimal(ctx);
+ if (JS_IsException(val))
+ break;
+ r = JS_GetBigDecimal(val);
bfdec_set_nan(r);
- val = JS_NewBigDecimal(ctx, r);
}
break;
default:
@@ -48188,10 +48433,12 @@ static JSValue js_bigdecimal_constructor(JSContext *ctx,
{
JSValue val;
if (argc == 0) {
- bfdec_t r_s, *r = &r_s;
- bfdec_init(ctx->bf_ctx, r);
+ bfdec_t *r;
+ val = JS_NewBigDecimal(ctx);
+ if (JS_IsException(val))
+ return val;
+ r = JS_GetBigDecimal(val);
bfdec_set_zero(r, 0);
- val = JS_NewBigDecimal(ctx, r);
} else {
val = JS_ToBigDecimalFree(ctx, JS_DupValue(ctx, argv[0]), FALSE);
}
@@ -48230,6 +48477,39 @@ static JSValue js_bigdecimal_valueOf(JSContext *ctx, JSValueConst this_val,
return js_thisBigDecimalValue(ctx, this_val);
}
+static int js_bigdecimal_get_rnd_mode(JSContext *ctx, JSValueConst obj)
+{
+ const char *str;
+ size_t size;
+ int rnd_mode;
+
+ str = JS_ToCStringLen(ctx, &size, obj);
+ if (!str)
+ return -1;
+ if (strlen(str) != size)
+ goto invalid_rounding_mode;
+ if (!strcmp(str, "floor")) {
+ rnd_mode = BF_RNDD;
+ } else if (!strcmp(str, "ceiling")) {
+ rnd_mode = BF_RNDU;
+ } else if (!strcmp(str, "down")) {
+ rnd_mode = BF_RNDZ;
+ } else if (!strcmp(str, "up")) {
+ rnd_mode = BF_RNDA;
+ } else if (!strcmp(str, "half-even")) {
+ rnd_mode = BF_RNDN;
+ } else if (!strcmp(str, "half-up")) {
+ rnd_mode = BF_RNDNA;
+ } else {
+ invalid_rounding_mode:
+ JS_FreeCString(ctx, str);
+ JS_ThrowTypeError(ctx, "invalid rounding mode");
+ return -1;
+ }
+ JS_FreeCString(ctx, str);
+ return rnd_mode;
+}
+
typedef struct {
int64_t prec;
bf_flags_t flags;
@@ -48239,10 +48519,9 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
JSValueConst obj)
{
JSValue prop;
- const char *str;
- size_t size;
int64_t val;
BOOL has_prec;
+ int rnd_mode;
if (!JS_IsObject(obj)) {
JS_ThrowTypeErrorNotAnObject(ctx);
@@ -48251,29 +48530,11 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
prop = JS_GetProperty(ctx, obj, JS_ATOM_roundingMode);
if (JS_IsException(prop))
return -1;
- str = JS_ToCStringLen(ctx, &size, prop);
+ rnd_mode = js_bigdecimal_get_rnd_mode(ctx, prop);
JS_FreeValue(ctx, prop);
- if (!str)
+ if (rnd_mode < 0)
return -1;
- if (strlen(str) != size)
- goto invalid_rounding_mode;
- if (!strcmp(str, "floor")) {
- fe->flags = BF_RNDD;
- } else if (!strcmp(str, "ceiling")) {
- fe->flags = BF_RNDU;
- } else if (!strcmp(str, "down")) {
- fe->flags = BF_RNDZ;
- } else if (!strcmp(str, "half-even")) {
- fe->flags = BF_RNDN;
- } else if (!strcmp(str, "half-up")) {
- fe->flags = BF_RNDNA;
- } else {
- invalid_rounding_mode:
- JS_FreeCString(ctx, str);
- JS_ThrowTypeError(ctx, "invalid rounding mode");
- return -1;
- }
- JS_FreeCString(ctx, str);
+ fe->flags = rnd_mode;
prop = JS_GetProperty(ctx, obj, JS_ATOM_maximumSignificantDigits);
if (JS_IsException(prop))
@@ -48282,7 +48543,7 @@ static int js_bigdecimal_get_env(JSContext *ctx, BigDecimalEnv *fe,
if (!JS_IsUndefined(prop)) {
if (JS_ToInt64SatFree(ctx, &val, prop))
return -1;
- if (val < 0 || val > BF_PREC_MAX)
+ if (val < 1 || val > BF_PREC_MAX)
goto invalid_precision;
fe->prec = val;
has_prec = TRUE;
@@ -48320,7 +48581,7 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
bfdec_t *a, *b, r_s, *r = &r_s;
- JSValue op1, op2;
+ JSValue op1, op2, res;
BigDecimalEnv fe_s, *fe = &fe_s;
int op_count, ret;
@@ -48354,21 +48615,18 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
fe->flags = BF_RNDZ;
fe->prec = BF_PREC_INF;
if (op_count < argc) {
- if (js_bigdecimal_get_env(ctx, fe, argv[op_count])) {
- fail:
- JS_FreeValue(ctx, op1);
- JS_FreeValue(ctx, op2);
- return JS_EXCEPTION;
- }
- if ((fe->flags & BF_FLAG_RADPNT_PREC) &&
- magic != MATH_OP_DIV &&
- magic != MATH_OP_ROUND) {
- JS_ThrowTypeError(ctx, "maximumFractionDigits is not supported for this operation");
+ if (js_bigdecimal_get_env(ctx, fe, argv[op_count]))
goto fail;
- }
}
- bfdec_init(ctx->bf_ctx, r);
+ res = JS_NewBigDecimal(ctx);
+ if (JS_IsException(res)) {
+ fail:
+ JS_FreeValue(ctx, op1);
+ JS_FreeValue(ctx, op2);
+ return JS_EXCEPTION;
+ }
+ r = JS_GetBigDecimal(res);
switch (magic) {
case MATH_OP_ADD:
ret = bfdec_add(r, a, b, fe->prec, fe->flags);
@@ -48382,6 +48640,9 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
case MATH_OP_DIV:
ret = bfdec_div(r, a, b, fe->prec, fe->flags);
break;
+ case MATH_OP_FMOD:
+ ret = bfdec_rem(r, a, b, fe->prec, fe->flags, BF_RNDZ);
+ break;
case MATH_OP_SQRT:
ret = bfdec_sqrt(r, a, fe->prec, fe->flags);
break;
@@ -48398,16 +48659,119 @@ static JSValue js_bigdecimal_fop(JSContext *ctx, JSValueConst this_val,
ret &= BF_ST_MEM_ERROR | BF_ST_DIVIDE_ZERO | BF_ST_INVALID_OP |
BF_ST_OVERFLOW;
if (ret != 0) {
- bfdec_delete(r);
+ JS_FreeValue(ctx, res);
return throw_bf_exception(ctx, ret);
} else {
- return JS_NewBigDecimal(ctx, r);
+ return res;
}
}
+static JSValue js_bigdecimal_toFixed(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue val, ret;
+ int64_t f;
+ int rnd_mode;
+
+ val = js_thisBigDecimalValue(ctx, this_val);
+ if (JS_IsException(val))
+ return val;
+ if (JS_ToInt64Sat(ctx, &f, argv[0]))
+ goto fail;
+ if (f < 0 || f > BF_PREC_MAX) {
+ JS_ThrowRangeError(ctx, "invalid number of digits");
+ goto fail;
+ }
+ rnd_mode = BF_RNDNA;
+ if (argc > 1) {
+ rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
+ if (rnd_mode < 0)
+ goto fail;
+ }
+ ret = js_bigdecimal_to_string1(ctx, val, f, rnd_mode | BF_FTOA_FORMAT_FRAC);
+ JS_FreeValue(ctx, val);
+ return ret;
+ fail:
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_bigdecimal_toExponential(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue val, ret;
+ int64_t f;
+ int rnd_mode;
+
+ val = js_thisBigDecimalValue(ctx, this_val);
+ if (JS_IsException(val))
+ return val;
+ if (JS_ToInt64Sat(ctx, &f, argv[0]))
+ goto fail;
+ if (JS_IsUndefined(argv[0])) {
+ ret = js_bigdecimal_to_string1(ctx, val, 0,
+ BF_RNDN | BF_FTOA_FORMAT_FREE_MIN | BF_FTOA_FORCE_EXP);
+ } else {
+ if (f < 0 || f > BF_PREC_MAX) {
+ JS_ThrowRangeError(ctx, "invalid number of digits");
+ goto fail;
+ }
+ rnd_mode = BF_RNDNA;
+ if (argc > 1) {
+ rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
+ if (rnd_mode < 0)
+ goto fail;
+ }
+ ret = js_bigdecimal_to_string1(ctx, val, f + 1,
+ rnd_mode | BF_FTOA_FORMAT_FIXED | BF_FTOA_FORCE_EXP);
+ }
+ JS_FreeValue(ctx, val);
+ return ret;
+ fail:
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+}
+
+static JSValue js_bigdecimal_toPrecision(JSContext *ctx, JSValueConst this_val,
+ int argc, JSValueConst *argv)
+{
+ JSValue val, ret;
+ int64_t p;
+ int rnd_mode;
+
+ val = js_thisBigDecimalValue(ctx, this_val);
+ if (JS_IsException(val))
+ return val;
+ if (JS_IsUndefined(argv[0])) {
+ return JS_ToStringFree(ctx, val);
+ }
+ if (JS_ToInt64Sat(ctx, &p, argv[0]))
+ goto fail;
+ if (p < 1 || p > BF_PREC_MAX) {
+ JS_ThrowRangeError(ctx, "invalid number of digits");
+ goto fail;
+ }
+ rnd_mode = BF_RNDNA;
+ if (argc > 1) {
+ rnd_mode = js_bigdecimal_get_rnd_mode(ctx, argv[1]);
+ if (rnd_mode < 0)
+ goto fail;
+ }
+ ret = js_bigdecimal_to_string1(ctx, val, p,
+ rnd_mode | BF_FTOA_FORMAT_FIXED);
+ JS_FreeValue(ctx, val);
+ return ret;
+ fail:
+ JS_FreeValue(ctx, val);
+ return JS_EXCEPTION;
+}
+
static const JSCFunctionListEntry js_bigdecimal_proto_funcs[] = {
JS_CFUNC_DEF("toString", 0, js_bigdecimal_toString ),
JS_CFUNC_DEF("valueOf", 0, js_bigdecimal_valueOf ),
+ JS_CFUNC_DEF("toPrecision", 1, js_bigdecimal_toPrecision ),
+ JS_CFUNC_DEF("toFixed", 1, js_bigdecimal_toFixed ),
+ JS_CFUNC_DEF("toExponential", 1, js_bigdecimal_toExponential ),
};
static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
@@ -48415,6 +48779,7 @@ static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
JS_CFUNC_MAGIC_DEF("sub", 2, js_bigdecimal_fop, MATH_OP_SUB ),
JS_CFUNC_MAGIC_DEF("mul", 2, js_bigdecimal_fop, MATH_OP_MUL ),
JS_CFUNC_MAGIC_DEF("div", 2, js_bigdecimal_fop, MATH_OP_DIV ),
+ JS_CFUNC_MAGIC_DEF("mod", 2, js_bigdecimal_fop, MATH_OP_FMOD ),
JS_CFUNC_MAGIC_DEF("round", 1, js_bigdecimal_fop, MATH_OP_ROUND ),
JS_CFUNC_MAGIC_DEF("sqrt", 1, js_bigdecimal_fop, MATH_OP_SQRT ),
};
@@ -49512,6 +49877,8 @@ static JSValue js_typed_array_copyWithin(JSContext *ctx, JSValueConst this_val,
count = min_int(final - from, len - to);
if (count > 0) {
p = JS_VALUE_GET_OBJ(this_val);
+ if (typed_array_is_detached(ctx, p))
+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
shift = typed_array_size_log2(p->class_id);
memmove(p->u.array.u.uint8_ptr + (to << shift),
p->u.array.u.uint8_ptr + (from << shift),
@@ -49579,6 +49946,9 @@ static JSValue js_typed_array_fill(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+ if (typed_array_is_detached(ctx, p))
+ return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+
shift = typed_array_size_log2(p->class_id);
switch(shift) {
case 0: