]> git.kaiwu.me - njs.git/commitdiff
Math.imul() method.
authorValentin Bartenev <vbart@nginx.com>
Sat, 19 Nov 2016 19:20:06 +0000 (22:20 +0300)
committerValentin Bartenev <vbart@nginx.com>
Sat, 19 Nov 2016 19:20:06 +0000 (22:20 +0300)
njs/njs_math.c
njs/njs_number.c
njs/njs_number.h
njs/njs_vm.c
njs/test/njs_unit_test.c

index f20f5fee79c2c0bdbd1c0d98f9e8bd58c7aa4811..0a7d7d24b1699c38af520976dc157819079b2e85 100644 (file)
@@ -377,6 +377,29 @@ njs_object_math_hypot(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
 }
 
 
+static njs_ret_t
+njs_object_math_imul(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+{
+    double    num;
+    uint32_t  a, b;
+
+    if (nargs > 2) {
+        a = njs_number_to_integer(args[1].data.u.number);
+        b = njs_number_to_integer(args[2].data.u.number);
+
+        num = (int32_t) (a * b);
+
+    } else {
+        num = 0;
+    }
+
+    njs_number_set(&vm->retval, num);
+
+    return NXT_OK;
+}
+
+
 static njs_ret_t
 njs_object_math_log(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
@@ -898,6 +921,14 @@ static const njs_object_prop_t  njs_math_object_properties[] =
         .value = njs_native_function(njs_object_math_hypot, 0, 0),
     },
 
+    /* ES6. */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("imul"),
+        .value = njs_native_function(njs_object_math_imul, 0,
+                     NJS_SKIP_ARG, NJS_NUMBER_ARG, NJS_NUMBER_ARG),
+    },
+
     {
         .type = NJS_METHOD,
         .name = njs_string("log"),
index 2b9e1501f16dd098b1ff79b03aa7f6a6e4d27504..1e01a84513b126744d6e3621fb18b226a8a9ee1f 100644 (file)
@@ -741,3 +741,28 @@ njs_number_parse_float(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
 
     return NXT_OK;
 }
+
+
+nxt_noinline uint32_t
+njs_number_to_integer(double num)
+{
+    int64_t  i64;
+
+    /*
+     * ECMAScript 5.1: integer must be modulo 2^32.
+     * 2^53 is the largest integer number which can be stored in the IEEE-754
+     * format and numbers less than 2^53 can be just converted to int64_t
+     * eliding more expensive fmod() operation.  Then the int64 integer is
+     * truncated to uint32_t.  The NaN can be converted to 0x8000000000000000
+     * and becomes 0 after truncation.  fmod() of the infinity returns NaN.
+     */
+
+    if (num < 0 || num > 9007199254740992.0) {
+        i64 = fmod(num, 4294967296.0);
+
+    } else {
+        i64 = num;
+    }
+
+    return (uint32_t) i64;
+}
index 724dfbbede15d300e7e160a79449c14d825e264e..4365065d92db357f20f728f778b8751f8ba7746f 100644 (file)
@@ -27,6 +27,7 @@ njs_ret_t njs_number_parse_int(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, njs_index_t unused);
 njs_ret_t njs_number_parse_float(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, njs_index_t unused);
+nxt_noinline uint32_t njs_number_to_integer(double num);
 
 
 extern const njs_object_init_t  njs_number_constructor_init;
index ee86bf4daa64afd499f19c2e8f1098579984d88e..e1a0557d6404e852415a85d2e0f43cde41204031 100644 (file)
@@ -78,7 +78,6 @@ static njs_ret_t njs_object_property_query(njs_vm_t *vm,
     njs_property_query_t *pq, njs_value_t *value, njs_object_t *object);
 static njs_ret_t njs_method_private_copy(njs_vm_t *vm,
     njs_property_query_t *pq);
-static nxt_noinline uint32_t njs_integer_value(double num);
 static nxt_noinline njs_ret_t njs_values_equal(const njs_value_t *val1,
     const njs_value_t *val2);
 static nxt_noinline njs_ret_t njs_values_compare(const njs_value_t *val1,
@@ -1639,8 +1638,8 @@ njs_vmcode_left_shift(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
 
     if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
 
-        num1 = njs_integer_value(val1->data.u.number);
-        num2 = njs_integer_value(val2->data.u.number);
+        num1 = njs_number_to_integer(val1->data.u.number);
+        num2 = njs_number_to_integer(val2->data.u.number);
         njs_number_set(&vm->retval, num1 << (num2 & 0x1f));
 
         return sizeof(njs_vmcode_3addr_t);
@@ -1658,8 +1657,8 @@ njs_vmcode_right_shift(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
 
     if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
 
-        num1 = njs_integer_value(val1->data.u.number);
-        num2 = njs_integer_value(val2->data.u.number);
+        num1 = njs_number_to_integer(val1->data.u.number);
+        num2 = njs_number_to_integer(val2->data.u.number);
         njs_number_set(&vm->retval, num1 >> (num2 & 0x1f));
 
         return sizeof(njs_vmcode_3addr_t);
@@ -1678,8 +1677,8 @@ njs_vmcode_unsigned_right_shift(njs_vm_t *vm, njs_value_t *val1,
 
     if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
 
-        num1 = njs_integer_value(val1->data.u.number);
-        num2 = njs_integer_value(val2->data.u.number);
+        num1 = njs_number_to_integer(val1->data.u.number);
+        num2 = njs_number_to_integer(val2->data.u.number);
         njs_number_set(&vm->retval, num1 >> (num2 & 0x1f));
 
         return sizeof(njs_vmcode_3addr_t);
@@ -1745,7 +1744,7 @@ njs_vmcode_bitwise_not(njs_vm_t *vm, njs_value_t *value, njs_value_t *invld)
     int32_t  num;
 
     if (nxt_fast_path(njs_is_numeric(value))) {
-        num = njs_integer_value(value->data.u.number);
+        num = njs_number_to_integer(value->data.u.number);
         njs_number_set(&vm->retval, ~num);
 
         return sizeof(njs_vmcode_2addr_t);
@@ -1762,8 +1761,8 @@ njs_vmcode_bitwise_and(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
 
     if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
 
-        num1 = njs_integer_value(val1->data.u.number);
-        num2 = njs_integer_value(val2->data.u.number);
+        num1 = njs_number_to_integer(val1->data.u.number);
+        num2 = njs_number_to_integer(val2->data.u.number);
         njs_number_set(&vm->retval, num1 & num2);
 
         return sizeof(njs_vmcode_3addr_t);
@@ -1780,8 +1779,8 @@ njs_vmcode_bitwise_xor(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
 
     if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
 
-        num1 = njs_integer_value(val1->data.u.number);
-        num2 = njs_integer_value(val2->data.u.number);
+        num1 = njs_number_to_integer(val1->data.u.number);
+        num2 = njs_number_to_integer(val2->data.u.number);
         njs_number_set(&vm->retval, num1 ^ num2);
 
         return sizeof(njs_vmcode_3addr_t);
@@ -1798,8 +1797,8 @@ njs_vmcode_bitwise_or(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
 
     if (nxt_fast_path(njs_is_numeric(val1) && njs_is_numeric(val2))) {
 
-        num1 = njs_integer_value(val1->data.u.number);
-        num2 = njs_integer_value(val2->data.u.number);
+        num1 = njs_number_to_integer(val1->data.u.number);
+        num2 = njs_number_to_integer(val2->data.u.number);
         njs_number_set(&vm->retval, num1 | num2);
 
         return sizeof(njs_vmcode_3addr_t);
@@ -1809,31 +1808,6 @@ njs_vmcode_bitwise_or(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
 }
 
 
-static nxt_noinline uint32_t
-njs_integer_value(double num)
-{
-    int64_t  i64;
-
-    /*
-     * ECMAScript 5.1: integer must be modulo 2^32.
-     * 2^53 is the largest integer number which can be stored in the IEEE-754
-     * format and numbers less than 2^53 can be just converted to int64_t
-     * eliding more expensive fmod() operation.  Then the int64 integer is
-     * truncated to uint32_t.  The NaN can be converted to 0x8000000000000000
-     * and becomes 0 after truncation.  fmod() of the infinity returns NaN.
-     */
-
-    if (num < 0 || num > 9007199254740992.0) {
-        i64 = fmod(num, 4294967296.0);
-
-    } else {
-        i64 = num;
-    }
-
-    return (uint32_t) i64;
-}
-
-
 njs_ret_t
 njs_vmcode_equal(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2)
 {
index d8c14013e13c17a8795a2701f1b504d80b0f1fed..2a5866e2db66aaf4cd3ac90009e1769bdf5a2cb0 100644 (file)
@@ -5968,6 +5968,63 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Math.hypot(3, -4, 12.0, '84', 132)"),
       nxt_string("157") },
 
+    { nxt_string("Math.imul()"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul(1)"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul('a', 1)"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul(1, NaN)"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul(2, '3')"),
+      nxt_string("6") },
+
+    { nxt_string("Math.imul('3.9', -2.1)"),
+      nxt_string("-6") },
+
+    { nxt_string("Math.imul(2, 2147483647)"),
+      nxt_string("-2") },
+
+    { nxt_string("Math.imul(Number.MAX_SAFE_INTEGER, 2)"),
+      nxt_string("-2") },
+
+    { nxt_string("Math.imul(1, Number.MAX_SAFE_INTEGER + 1)"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul(2, Number.MIN_SAFE_INTEGER)"),
+      nxt_string("2") },
+
+    { nxt_string("Math.imul(Number.MIN_SAFE_INTEGER - 1, 1)"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul(2, 4294967297)"),
+      nxt_string("2") },
+
+    { nxt_string("Math.imul(-4294967297, 4294967297)"),
+      nxt_string("-1") },
+
+    { nxt_string("Math.imul(4294967297, -4294967298)"),
+      nxt_string("-2") },
+
+    { nxt_string("Math.imul(-4294967290, 4294967290)"),
+      nxt_string("-36") },
+
+    { nxt_string("Math.imul(-Infinity, 1)"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul(1, Infinity)"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul(Number.MAX_VALUE, 1)"),
+      nxt_string("0") },
+
+    { nxt_string("Math.imul(1, -Number.MAX_VALUE)"),
+      nxt_string("0") },
+
     { nxt_string("Math.log()"),
       nxt_string("NaN") },