Specialize math functions to integer arithmetic where appropriate (511307, r=dvander).
authorAndreas Gal <gal@mozilla.com>
Wed, 19 Aug 2009 15:31:10 -0700
changeset 31900 ccf91ba2d62a84a708c61f539797c7c1057e5d8e
parent 31899 85832269fb645d617b094fc98a26e1c0fca05c98
child 31901 15166116171f252bb017f2554700980ce8766212
push idunknown
push userunknown
push dateunknown
reviewersdvander
bugs511307
milestone1.9.3a1pre
Specialize math functions to integer arithmetic where appropriate (511307, r=dvander).
js/src/jsmath.cpp
js/src/jsmath.h
js/src/jstracer.cpp
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -232,18 +232,18 @@ math_ceil_kernel(jsdouble x)
 {
 #ifdef __APPLE__
     if (x < 0 && x > -1.0)
         return js_copysign(0, -1);
 #endif
     return ceil(x);
 }
 
-static JSBool
-math_ceil(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_ceil(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     x = js_ValueToNumber(cx, &vp[2]);
@@ -292,18 +292,18 @@ math_exp(JSContext *cx, uintN argc, jsva
             return JS_TRUE;
         }
     }
 #endif
     z = exp(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
-static JSBool
-math_floor(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_floor(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     x = js_ValueToNumber(cx, &vp[2]);
@@ -330,18 +330,18 @@ math_log(JSContext *cx, uintN argc, jsva
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
 #endif
     z = log(x);
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
-static JSBool
-math_max(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_max(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z = *cx->runtime->jsNegativeInfinity;
     jsval *argv;
     uintN i;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
         return JS_TRUE;
@@ -360,18 +360,18 @@ math_max(JSContext *cx, uintN argc, jsva
                 z = x;
         } else {
             z = (x > z) ? x : z;
         }
     }
     return js_NewNumberInRootedValue(cx, z, vp);
 }
 
-static JSBool
-math_min(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_min(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z = *cx->runtime->jsPositiveInfinity;
     jsval *argv;
     uintN i;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
         return JS_TRUE;
@@ -481,18 +481,18 @@ js_copysign(double x, double y)
     xu.d = x;
     yu.d = y;
     xu.s.hi &= ~JSDOUBLE_HI32_SIGNBIT;
     xu.s.hi |= yu.s.hi & JSDOUBLE_HI32_SIGNBIT;
     return xu.d;
 }
 #endif
 
-static JSBool
-math_round(JSContext *cx, uintN argc, jsval *vp)
+JSBool
+js_math_round(JSContext *cx, uintN argc, jsval *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
         return JS_TRUE;
     }
     x = js_ValueToNumber(cx, &vp[2]);
@@ -567,17 +567,16 @@ math_toSource(JSContext *cx, uintN argc,
     JS_DEFINE_TRCINFO_1(math_##name,                                          \
         (1, (static, DOUBLE, math_##name##_tn, DOUBLE, 1, 1)))
 
 MATH_BUILTIN_CFUN_1(abs, fabs)
 MATH_BUILTIN_1(atan)
 MATH_BUILTIN_1(sin)
 MATH_BUILTIN_1(cos)
 MATH_BUILTIN_1(sqrt)
-MATH_BUILTIN_1(floor)
 MATH_BUILTIN_1(tan)
 
 static jsdouble FASTCALL
 math_acos_tn(jsdouble d)
 {
 #if defined(SOLARIS) && defined(__GNUC__)
     if (d < -1 || 1 < d) {
         return js_NaN;
@@ -685,58 +684,66 @@ math_round_tn(jsdouble x)
 }
 
 static jsdouble FASTCALL
 math_ceil_tn(jsdouble x)
 {
     return math_ceil_kernel(x);
 }
 
+static jsdouble FASTCALL
+math_floor_tn(jsdouble x)
+{
+    return floor(x);
+}
+
 JS_DEFINE_TRCINFO_1(math_acos,
     (1, (static, DOUBLE, math_acos_tn, DOUBLE,          1, 1)))
 JS_DEFINE_TRCINFO_1(math_asin,
     (1, (static, DOUBLE, math_asin_tn, DOUBLE,          1, 1)))
 JS_DEFINE_TRCINFO_1(math_atan2,
     (2, (static, DOUBLE, math_atan2_kernel, DOUBLE, DOUBLE, 1, 1)))
+JS_DEFINE_TRCINFO_1(js_math_floor,
+    (1, (static, DOUBLE, math_floor_tn, DOUBLE,         1, 1)))
 JS_DEFINE_TRCINFO_1(math_log,
     (1, (static, DOUBLE, math_log_tn, DOUBLE,           1, 1)))
-JS_DEFINE_TRCINFO_1(math_max,
+JS_DEFINE_TRCINFO_1(js_math_max,
     (2, (static, DOUBLE, math_max_tn, DOUBLE, DOUBLE,   1, 1)))
-JS_DEFINE_TRCINFO_1(math_min,
+JS_DEFINE_TRCINFO_1(js_math_min,
     (2, (static, DOUBLE, math_min_tn, DOUBLE, DOUBLE,   1, 1)))
 JS_DEFINE_TRCINFO_1(math_pow,
     (2, (static, DOUBLE, math_pow_tn, DOUBLE, DOUBLE,   1, 1)))
 JS_DEFINE_TRCINFO_1(math_random,
     (1, (static, DOUBLE, math_random_tn, CONTEXT,       0, 0)))
-JS_DEFINE_TRCINFO_1(math_round,
+JS_DEFINE_TRCINFO_1(js_math_round,
     (1, (static, DOUBLE, math_round_tn, DOUBLE,         1, 1)))
-JS_DEFINE_TRCINFO_1(math_ceil,
+JS_DEFINE_TRCINFO_1(js_math_ceil,
     (1, (static, DOUBLE, math_ceil_tn, DOUBLE,          1, 1)))
 
 #endif /* JS_TRACER */
 
 static JSFunctionSpec math_static_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,  math_toSource,        0, 0),
 #endif
     JS_TN("abs",            math_abs,             1, 0, math_abs_trcinfo),
     JS_TN("acos",           math_acos,            1, 0, math_acos_trcinfo),
     JS_TN("asin",           math_asin,            1, 0, math_asin_trcinfo),
     JS_TN("atan",           math_atan,            1, 0, math_atan_trcinfo),
     JS_TN("atan2",          math_atan2,           2, 0, math_atan2_trcinfo),
-    JS_TN("ceil",           math_ceil,            1, 0, math_ceil_trcinfo),
+    JS_TN("ceil",           math_ceil,            1, 0, js_math_ceil_trcinfo),
     JS_TN("cos",            math_cos,             1, 0, math_cos_trcinfo),
     JS_TN("exp",            math_exp,             1, 0, math_exp_trcinfo),
-    JS_TN("floor",          math_floor,           1, 0, math_floor_trcinfo),
+    JS_TN("floor",          math_floor,           1, 0, js_math_floor_trcinfo),
     JS_TN("log",            math_log,             1, 0, math_log_trcinfo),
-    JS_TN("max",            math_max,             2, 0, math_max_trcinfo),
-    JS_TN("min",            math_min,             2, 0, math_min_trcinfo),
+    JS_TN("max",            math_max,             2, 0, js_math_max_trcinfo),
+    JS_TN("min",            math_min,             2, 0, js_math_min_trcinfo),
     JS_TN("pow",            math_pow,             2, 0, math_pow_trcinfo),
     JS_TN("random",         math_random,          0, 0, math_random_trcinfo),
-    JS_TN("round",          math_round,           1, 0, math_round_trcinfo),
+    JS_TN("round",          math_round,           1, 0, js_math_round_trcinfo),
     JS_TN("sin",            math_sin,             1, 0, math_sin_trcinfo),
     JS_TN("sqrt",           math_sqrt,            1, 0, math_sqrt_trcinfo),
     JS_TN("tan",            math_tan,             1, 0, math_tan_trcinfo),
     JS_FS_END
 };
 
 JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj)
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -48,11 +48,26 @@ JS_BEGIN_EXTERN_C
 extern JSClass js_MathClass;
 
 extern JSObject *
 js_InitMathClass(JSContext *cx, JSObject *obj);
 
 extern void
 js_InitRandom(JSThreadData *data);
 
+extern JSBool
+js_math_ceil(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSBool
+js_math_floor(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSBool
+js_math_max(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSBool
+js_math_min(JSContext *cx, uintN argc, jsval *vp);
+
+extern JSBool
+js_math_round(JSContext *cx, uintN argc, jsval *vp);
+
 JS_END_EXTERN_C
 
 #endif /* jsmath_h___ */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -60,16 +60,17 @@
 #include "jsarray.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jsemit.h"
 #include "jsfun.h"
 #include "jsinterp.h"
 #include "jsiter.h"
+#include "jsmath.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsregexp.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsdate.h"
 #include "jsstaticcheck.h"
 #include "jstracer.h"
@@ -9327,24 +9328,55 @@ TraceRecorder::callNative(uintN argc, JS
 {
     LIns* args[5];
 
     JS_ASSERT(mode == JSOP_CALL || mode == JSOP_NEW || mode == JSOP_APPLY);
 
     jsval* vp = &stackval(0 - (2 + argc));
     JSObject* funobj = JSVAL_TO_OBJECT(vp[0]);
     JSFunction* fun = GET_FUNCTION_PRIVATE(cx, funobj);
+    JSFastNative native = (JSFastNative)fun->u.n.native;
+
+    switch (argc) {
+      case 1:
+        if (native == js_math_ceil || native == js_math_floor || native == js_math_round) {
+            LIns* a = get(&vp[2]);
+            if (isPromote(a)) {
+                set(&vp[0], a);
+                pendingTraceableNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
+                return JSRS_CONTINUE;
+            }
+        }
+        break;
+      case 2:
+        if (native == js_math_min || native == js_math_max) {
+            LIns* a = get(&vp[2]);
+            LIns* b = get(&vp[3]);
+            if (isPromote(a) && isPromote(b)) {
+                a = ::demote(lir, a);
+                b = ::demote(lir, b);
+                set(&vp[0],
+                    lir->ins1(LIR_i2f,
+                              lir->ins_choose(lir->ins2((native == js_math_min)
+                                                        ? LIR_lt
+                                                        : LIR_gt, a, b),
+                                              a, b)));
+                pendingTraceableNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
+                return JSRS_CONTINUE;
+            }
+        }
+        break;
+    }
 
     if (fun->flags & JSFUN_TRACEABLE) {
         JSRecordingStatus status;
         if ((status = callTraceableNative(fun, argc, mode == JSOP_NEW)) != JSRS_STOP)
             return status;
     }
 
-    JSFastNative native = (JSFastNative)fun->u.n.native;
     if (native == js_fun_apply || native == js_fun_call)
         ABORT_TRACE("trying to call native apply or call");
 
     // Allocate the vp vector and emit code to root it.
     uintN vplen = 2 + JS_MAX(argc, FUN_MINARGS(fun)) + fun->u.n.extra;
     if (!(fun->flags & JSFUN_FAST_NATIVE))
         vplen++; // slow native return value slot
     lir->insStorei(INS_CONST(vplen), cx_ins, offsetof(JSContext, nativeVpLen));