Coerce strings to numbers for appropriate ops.
authorshaver@mozilla.org
Thu, 31 Jul 2008 07:41:58 -0700
changeset 17910 edd0d8812b7b0679251b54fb8b32f46bc56a0727
parent 17909 cce4240c2e2ae46800baced30a2b83c30ce96909
child 17911 8421b003fb5f154bb6b8243b991a5d0ab855761d
push id1452
push usershaver@mozilla.com
push dateFri, 22 Aug 2008 00:08:22 +0000
treeherderautoland@d13bb0868596 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.1a1pre
Coerce strings to numbers for appropriate ops. (Wants a specialized StringToInt32 and a filter to put it in place.)
js/src/builtins.tbl
js/src/jsbuiltins.cpp
js/src/jstracer.cpp
js/src/trace-test.js
--- a/js/src/builtins.tbl
+++ b/js/src/builtins.tbl
@@ -51,8 +51,9 @@ BUILTIN4(Array_dense_setelem,   LO, LO, 
 BUILTIN4(String_p_substring,    LO, LO, LO, LO, LO, JSString*, JSContext*, JSString*, jsint, jsint, 1, 1)
 BUILTIN3(String_p_substring_1,  LO, LO, LO, LO, JSString*, JSContext*, JSString*, jsint, 1, 1)
 BUILTIN3(ConcatStrings,         LO, LO, LO, LO, JSString*, JSContext*, JSString*, JSString*, 1, 1)
 BUILTIN3(String_getelem,        LO, LO, LO, LO, JSString*, JSContext*, JSString*, jsint, 1, 1)
 BUILTIN2(String_fromCharCode,   LO, LO, LO,     JSString*, JSContext*, jsint, 1, 1)
 BUILTIN2(String_p_charCodeAt,   LO,     LO, LO, jsint,     JSString*, jsint, 1, 1)
 BUILTIN1(Math_random,           LO,     F,      jsdouble,  JSRuntime*, 1, 1)
 BUILTIN2(EqualStrings,          LO,     LO, LO, bool,      JSString*, JSString*, 1, 1)
+BUILTIN2(StringToNumber,        LO,     LO, F,  jsdouble,  JSContext*, JSString*, 1, 1)
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -233,16 +233,34 @@ builtin_Math_random(JSRuntime* rt)
 }
 
 bool FASTCALL
 builtin_EqualStrings(JSString* str1, JSString* str2)
 {
     return js_EqualStrings(str1, str2);
 }
 
+jsdouble FASTCALL
+builtin_StringToNumber(JSContext* cx, JSString *str)
+{
+    const jschar* bp;
+    const jschar* end;
+    const jschar* ep;
+    jsdouble d;
+
+    JSSTRING_CHARS_AND_END(str, bp, end);
+    if ((!js_strtod(cx, bp, end, &ep, &d) ||
+         js_SkipWhiteSpace(ep, end) != end) &&
+        (!js_strtointeger(cx, bp, end, &ep, 0, &d) ||
+         js_SkipWhiteSpace(ep, end) != end)) {
+        return *cx->runtime->jsNaN;
+    }
+    return d;
+}
+
 #define LO ARGSIZE_LO
 #define F  ARGSIZE_F
 #define Q  ARGSIZE_Q
 
 #ifdef DEBUG
 #define NAME(op) ,#op
 #else
 #define NAME(op)
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -1687,19 +1687,35 @@ TraceRecorder::unary(LOpcode op)
 }
 
 bool
 TraceRecorder::binary(LOpcode op)
 {
     jsval& r = stackval(-1);
     jsval& l = stackval(-2);
     bool intop = !(op & LIR64);
-    if (isNumber(l) && isNumber(r)) {
-        LIns* a = get(&l);
-        LIns* b = get(&r);
+    LIns* a = get(&l);
+    LIns* b = get(&r);
+    bool leftNumber = isNumber(l), rightNumber = isNumber(r);
+    if ((op >= LIR_sub && op <= LIR_ush) ||  // sub, mul, (callh), or, xor, (not,) lsh, rsh, ush
+        (op >= LIR_fsub && op <= LIR_fdiv)) { // fsub, fmul, fdiv
+        LIns* args[] = { NULL, cx_ins };
+        JS_ASSERT(op != LIR_callh);
+        if (JSVAL_IS_STRING(l)) {
+            args[0] = a;
+            a = lir->insCall(F_StringToNumber, args);
+            leftNumber = true;
+        }
+        if (JSVAL_IS_STRING(r)) {
+            args[0] = b;
+            b = lir->insCall(F_StringToNumber, args);
+            rightNumber = true;
+        }
+    }
+    if (leftNumber && rightNumber) {
         if (intop) {
             a = lir->insCall(op == LIR_ush ? F_doubleToUint32 : F_doubleToInt32, &a);
             b = f2i(b);
         }
         a = lir->ins2(op, a, b);
         if (intop)
             a = lir->ins1(op == LIR_ush ? LIR_u2f : LIR_i2f, a);
         set(&l, a);
--- a/js/src/trace-test.js
+++ b/js/src/trace-test.js
@@ -317,11 +317,30 @@ function strings()
     if (s[i] != 'b')
       d++;
     b = s.length;
   }
   return a.toString() + b + c + d;
 }
 test("strings", strings(), "aaa,bbb,ccc,ddd,eee,fff,ggg,hhh,iii,jjj1019");
 
+function stringConvert()
+{
+  var a = [];
+  var s1 = "F", s2 = "1.3", s3 = "5";
+  for (var i = 0; i < 10; i++) {
+    a[0] = 1 >> s1;
+    a[1] = 10 - s2;
+    a[2] = 15 * s3;
+    a[3] = s3 | 32;
+    // a[4] = s2 + 60;
+    // a[5] = 9 + s3;
+    // a[6] = -s3;
+    a[7] = s3 & "7";
+    // a[8] = ~s3;
+  }
+  return a.toString();
+}
+test("stringConvert", stringConvert(), "1,8.7,75,37,,,,5");
+
 /* Keep these at the end so that we can see the summary after the trace-debug spew. */
 print("pass:", passes.length ? passes.join(",") : "<none>");
 print("FAIL:", fails.length ? fails.join(",") : "<none>");