Coerce strings to numbers for appropriate ops.
Coerce strings to numbers for appropriate ops.
(Wants a specialized StringToInt32 and a filter to put it in place.)
--- 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>");