diff --git a/src/duk_js_compiler.c b/src/duk_js_compiler.c index 1c9b10e4..d298c076 100644 --- a/src/duk_js_compiler.c +++ b/src/duk_js_compiler.c @@ -1570,16 +1570,19 @@ static void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_iv /* FIXME: to util */ static int duk__is_whole_get_i32(double x, duk_int32_t *ival) { + duk_small_int_t c; duk_int32_t t; - if (DUK_FPCLASSIFY(x) != DUK_FP_NORMAL) { - return 0; - } - - t = (duk_int32_t) x; - if ((double) t == x) { - *ival = t; - return 1; + c = DUK_FPCLASSIFY(x); + if (c == DUK_FP_NORMAL || (c == DUK_FP_ZERO && !DUK_SIGNBIT(x))) { + /* Don't allow negative zero as it will cause trouble with + * LDINT+LDINTX. But positive zero is OK. + */ + t = (duk_int32_t) x; + if ((double) t == x) { + *ival = t; + return 1; + } } return 0; @@ -3178,11 +3181,10 @@ static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { duk_is_number(ctx, res->x1.valstack_idx)) { /* unary plus of a number is identity */ ; - } else { - args = (DUK_EXTRAOP_UNP << 8) + 0; - goto unary_extraop; + return; } - return; + args = (DUK_EXTRAOP_UNP << 8) + 0; + goto unary_extraop; } case DUK_TOK_SUB: { /* unary minus */ @@ -3201,11 +3203,10 @@ static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { du.d = -du.d; DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); DUK_TVAL_SET_NUMBER(tv_num, du.d); - } else { - args = (DUK_EXTRAOP_UNM << 8) + 0; - goto unary_extraop; + return; } - return; + args = (DUK_EXTRAOP_UNM << 8) + 0; + goto unary_extraop; } case DUK_TOK_BNOT: { duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ @@ -3214,11 +3215,40 @@ static void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) { } case DUK_TOK_LNOT: { duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */ + if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) { + /* Very minimal inlining to handle common idioms '!0' and '!1', + * and also boolean arguments like '!false' and '!true'. + */ + duk_tval *tv_val = duk_get_tval(ctx, res->x1.valstack_idx); + + DUK_ASSERT(tv_val != NULL); + if (DUK_TVAL_IS_NUMBER(tv_val)) { + duk_double_t d; + d = DUK_TVAL_GET_NUMBER(tv_val); + if (d == 0.0) { + /* Matches both +0 and -0 on purpose. */ + DUK_D(DUK_DPRINT("inlined lnot: !0 -> true")); + DUK_TVAL_SET_BOOLEAN_TRUE(tv_val); + return; + } else if (d == 1.0) { + DUK_D(DUK_DPRINT("inlined lnot: !1 -> false")); + DUK_TVAL_SET_BOOLEAN_FALSE(tv_val); + return; + } + } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) { + duk_small_int_t v; + v = DUK_TVAL_GET_BOOLEAN(tv_val); + DUK_D(DUK_DPRINT("inlined lnot boolean: %d", (int) v)); + DUK_ASSERT(v == 0 || v == 1); + DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01); + return; + } + } args = (DUK_OP_LNOT << 8) + 0; goto unary; } - } + } /* end switch */ DUK_ERROR(thr, DUK_ERR_SYNTAX_ERROR, "unexpected token to duk__expr_nud(): %d", tok); return;