Bug 808148 -Implement experimental Math.imul. r=Waldo
authorTom Schuster <evilpies@gmail.com>
Fri, 14 Dec 2012 19:28:14 +0100
changeset 125197 1237d9a6ce46f17bc4f0778b7e3935eea22aa994
parent 125196 972ff78e9907c15649b3b94145b5669e9a888350
child 125198 e3998db26591d23ef26075c9594599d4c106a7d7
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs808148
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 808148 -Implement experimental Math.imul. r=Waldo
js/src/jit-test/tests/basic/mathImul.js
js/src/jsmath.cpp
js/src/jsmath.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/mathImul.js
@@ -0,0 +1,71 @@
+
+var table = [
+    [NaN, 0, 0],
+    [Infinity, Infinity, 0],
+    [NaN, 1000, 0],
+
+    [-1, -2, 2],
+    [1, 2, 2],
+    [-1, 2, -2],
+    [1, -2, -2],
+    [-0, 0, 0],
+    [0, -0, 0],
+    [-1, -0, 0],
+    [1, -0, 0],
+
+    [0xffffffff, 1, -1],
+
+    [0xffffffff, 0xffffffff, 1],
+    [0xffffffff, -0xffffffff, -1],
+    [0xffffffff, 0xfffffffe, 2],
+    [0xffffffff, -0xfffffffe, -2],
+    [0x10000, 0x10000, 0],
+
+    [{}, {}, 0],
+    [[], [], 0],
+    [{}, [], 0],
+    [[], {}, 0],
+
+    [{valueOf: function() { return -1; }}, 0x100000, -1048576],
+    ["3", "-4", -12],
+    [3.4, 6, 18]
+];
+
+try {
+    Math.imul({ valueOf: function() { throw "ha ha ha"; } });
+    assertEq(true, false, "no error thrown");
+} catch (e) {
+    assertEq(e, "ha ha ha");
+}
+
+var order = [];
+assertEq(Math.imul({ valueOf: function() { order.push("first"); return 0; } },
+                   { valueOf: function() { order.push("second"); return 0; } }),
+         0);
+assertEq(order[0], "first");
+assertEq(order[1], "second");
+
+var seen = [];
+try
+{
+    Math.imul({ valueOf: function() { seen.push("one"); return 17; } },
+              { valueOf: function() { throw "abort!"; } });
+    assertEq(true, false, "no error thrown");
+}
+catch (e)
+{
+  assertEq(e, "abort!", "should have thrown partway through, instead threw " + e);
+}
+assertEq(seen.length, 1);
+assertEq(seen[0], "one");
+
+assertEq(Math.imul(), 0);
+assertEq(Math.imul(100), 0);
+assertEq(Math.imul(NaN, 100), 0);
+assertEq(Math.imul(NaN, NaN), 0);
+assertEq(Math.imul(5, Infinity), 0);
+
+for (var i = 0; i < table.length; i++) {
+    assertEq(Math.imul(table[i][0], table[i][1]), table[i][2]);
+    assertEq(Math.imul(table[i][1], table[i][0]), table[i][2]);
+}
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -323,16 +323,34 @@ js_math_floor(JSContext *cx, unsigned ar
     }
     if (!ToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = js_math_floor_impl(x);
     vp->setNumber(z);
     return JS_TRUE;
 }
 
+JSBool
+js::math_imul(JSContext *cx, unsigned argc, Value *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    uint32_t a = 0, b = 0;
+    if (args.hasDefined(0) && !ToUint32(cx, args[0], &a))
+        return false;
+    if (args.hasDefined(1) && !ToUint32(cx, args[1], &b))
+        return false;
+
+    uint32_t product = a * b;
+    args.rval().setInt32(product > INT32_MAX
+                         ? int32_t(INT32_MIN + (product - INT32_MAX - 1))
+                         : int32_t(product));
+    return true;
+}
+
 double
 js::math_log_impl(MathCache *cache, double x)
 {
 #if defined(SOLARIS) && defined(__GNUC__)
     if (x < 0)
         return js_NaN;
 #endif
     return cache->lookup(log, x);
@@ -697,16 +715,17 @@ static JSFunctionSpec math_static_method
     JS_FN("acos",           math_acos,            1, 0),
     JS_FN("asin",           math_asin,            1, 0),
     JS_FN("atan",           math_atan,            1, 0),
     JS_FN("atan2",          math_atan2,           2, 0),
     JS_FN("ceil",           js_math_ceil,         1, 0),
     JS_FN("cos",            math_cos,             1, 0),
     JS_FN("exp",            math_exp,             1, 0),
     JS_FN("floor",          js_math_floor,        1, 0),
+    JS_FN("imul",           math_imul,            2, 0),
     JS_FN("log",            math_log,             1, 0),
     JS_FN("max",            js_math_max,          2, 0),
     JS_FN("min",            js_math_min,          2, 0),
     JS_FN("pow",            js_math_pow,          2, 0),
     JS_FN("random",         js_math_random,       0, 0),
     JS_FN("round",          js_math_round,        1, 0),
     JS_FN("sin",            math_sin,             1, 0),
     JS_FN("sqrt",           js_math_sqrt,         1, 0),
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -91,16 +91,19 @@ extern double
 js_math_ceil_impl(double x);
 
 extern double
 js_math_floor_impl(double x);
 
 namespace js {
 
 extern JSBool
+math_imul(JSContext *cx, unsigned argc, js::Value *vp);
+
+extern JSBool
 math_log(JSContext *cx, unsigned argc, js::Value *vp);
 
 extern double
 math_log_impl(MathCache *cache, double x);
 
 extern JSBool
 math_sin(JSContext *cx, unsigned argc, js::Value *vp);