[INFER] Use type sets instead of known pushed types when looking for static overflows, bug 643376.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 22 Mar 2011 13:41:56 -0700
changeset 74835 87930727668318924e31591c9c57d8f53457ac43
parent 74834 bda26823bd877f5ca404bf6fc01d14200d1da570
child 74836 0e7d59dc92b63ed9b5731f143bdb150f9e29f1f8
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs643376
milestone2.0b13pre
[INFER] Use type sets instead of known pushed types when looking for static overflows, bug 643376.
js/src/jit-test/tests/jaeger/recompile/bug643376.js
js/src/jsinfer.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastArithmetic.cpp
js/src/methodjit/FastOps.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/recompile/bug643376.js
@@ -0,0 +1,8 @@
+SECTION = 0;
+function TestCase() {}
+function outer_func(x)
+{
+    var y = "inner";
+    new TestCase( SECTION, { SECTION: ++y });
+}
+outer_func(1111);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1828,20 +1828,16 @@ TypeCompartment::dynamicPush(JSContext *
     const JSCodeSpec *cs = &js_CodeSpec[op];
     if (cs->format & (JOF_INC | JOF_DEC)) {
 
         switch (op) {
           case JSOP_INCGNAME:
           case JSOP_DECGNAME:
           case JSOP_GNAMEINC:
           case JSOP_GNAMEDEC: {
-            /*
-             * This is only hit in the method JIT, which does not run into the issues
-             * posed by bug 605200.
-             */
             jsid id = GetAtomId(cx, script, pc, 0);
             TypeObject *global = script->getGlobalType();
             if (!global->unknownProperties) {
                 TypeSet *types = global->getProperty(cx, id, true);
                 if (!types)
                     break;
                 types->addType(cx, type);
             }
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -1431,41 +1431,33 @@ mjit::Compiler::generateMethod()
             jsop_rsh();
           END_CASE(JSOP_RSH)
 
           BEGIN_CASE(JSOP_URSH)
             jsop_bitop(op);
           END_CASE(JSOP_URSH)
 
           BEGIN_CASE(JSOP_ADD)
-            if (!jsop_binary(op, stubs::Add, knownPushedType(0))) {
-                markPushedOverflow();
+            if (!jsop_binary(op, stubs::Add, knownPushedType(0), pushedTypeSet(0)))
                 return Compile_Overflow;
-            }
           END_CASE(JSOP_ADD)
 
           BEGIN_CASE(JSOP_SUB)
-            if (!jsop_binary(op, stubs::Sub, knownPushedType(0))) {
-                markPushedOverflow();
+            if (!jsop_binary(op, stubs::Sub, knownPushedType(0), pushedTypeSet(0)))
                 return Compile_Overflow;
-            }
           END_CASE(JSOP_SUB)
 
           BEGIN_CASE(JSOP_MUL)
-            if (!jsop_binary(op, stubs::Mul, knownPushedType(0))) {
-                markPushedOverflow();
+            if (!jsop_binary(op, stubs::Mul, knownPushedType(0), pushedTypeSet(0)))
                 return Compile_Overflow;
-            }
           END_CASE(JSOP_MUL)
 
           BEGIN_CASE(JSOP_DIV)
-            if (!jsop_binary(op, stubs::Div, knownPushedType(0))) {
-                markPushedOverflow();
+            if (!jsop_binary(op, stubs::Div, knownPushedType(0), pushedTypeSet(0)))
                 return Compile_Overflow;
-            }
           END_CASE(JSOP_DIV)
 
           BEGIN_CASE(JSOP_MOD)
             if (!jsop_mod())
                 return Compile_Overflow;
           END_CASE(JSOP_MOD)
 
           BEGIN_CASE(JSOP_NOT)
@@ -1492,19 +1484,19 @@ mjit::Compiler::generateMethod()
             FrameEntry *top = frame.peek(-1);
             if (top->isConstant() && top->getValue().isPrimitive()) {
                 double d;
                 ValueToNumber(cx, top->getValue(), &d);
                 d = -d;
                 Value v = NumberValue(d);
 
                 /* Watch for overflow in constant propagation. */
-                if (!v.isInt32() && knownPushedType(0) == JSVAL_TYPE_INT32) {
-                    JaegerSpew(JSpew_Abort, "overflow in negation (%u)\n", PC - script->code);
-                    markPushedOverflow();
+                types::TypeSet *pushed = pushedTypeSet(0);
+                if (!v.isInt32() && pushed && !pushed->hasType(types::TYPE_DOUBLE)) {
+                    script->typeMonitorResult(cx, PC, types::TYPE_DOUBLE);
                     return Compile_Overflow;
                 }
 
                 frame.pop();
                 frame.push(v);
             } else {
                 jsop_neg();
             }
@@ -4355,17 +4347,17 @@ mjit::Compiler::jsop_gnameinc(JSOp op, V
 
         jsop_getgname(index, JSVAL_TYPE_UNKNOWN);
         // V
 
         frame.push(Int32Value(amt));
         // V 1
 
         /* Use sub since it calls ValueToNumber instead of string concat. */
-        jsop_binary(JSOP_SUB, stubs::Sub, JSVAL_TYPE_UNKNOWN);
+        jsop_binary(JSOP_SUB, stubs::Sub, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0));
         // N+1
 
         jsop_bindgname();
         // V+1 OBJ
 
         frame.dup2();
         // V+1 OBJ V+1 OBJ
 
@@ -4390,17 +4382,17 @@ mjit::Compiler::jsop_gnameinc(JSOp op, V
         // N
 
         frame.dup();
         // N N
 
         frame.push(Int32Value(-amt));
         // N N 1
 
-        jsop_binary(JSOP_ADD, stubs::Add, JSVAL_TYPE_UNKNOWN);
+        jsop_binary(JSOP_ADD, stubs::Add, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0));
         // N N+1
 
         jsop_bindgname();
         // N N+1 OBJ
 
         frame.dup2();
         // N N+1 OBJ N+1 OBJ
 
@@ -4447,17 +4439,17 @@ mjit::Compiler::jsop_nameinc(JSOp op, Vo
         jsop_name(atom, JSVAL_TYPE_UNKNOWN);
         // OBJ V
 
         frame.push(Int32Value(amt));
         // OBJ V 1
 
         /* Use sub since it calls ValueToNumber instead of string concat. */
         frame.syncAt(-3);
-        jsop_binary(JSOP_SUB, stubs::Sub, JSVAL_TYPE_UNKNOWN);
+        jsop_binary(JSOP_SUB, stubs::Sub, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0));
         // OBJ N+1
 
         if (!jsop_setprop(atom, false))
             return false;
         // N+1
 
         if (pop)
             frame.pop();
@@ -4475,17 +4467,17 @@ mjit::Compiler::jsop_nameinc(JSOp op, Vo
 
         frame.dupAt(-2);
         // N OBJ N
 
         frame.push(Int32Value(-amt));
         // N OBJ N 1
 
         frame.syncAt(-3);
-        jsop_binary(JSOP_ADD, stubs::Add, JSVAL_TYPE_UNKNOWN);
+        jsop_binary(JSOP_ADD, stubs::Add, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0));
         // N OBJ N+1
 
         if (!jsop_setprop(atom, false))
             return false;
         // N N+1
 
         frame.pop();
         // N
@@ -4533,17 +4525,17 @@ mjit::Compiler::jsop_propinc(JSOp op, Vo
                 return false;
             // OBJ * V
 
             frame.push(Int32Value(amt));
             // OBJ * V 1
 
             /* Use sub since it calls ValueToNumber instead of string concat. */
             frame.syncAt(-4);
-            jsop_binary(JSOP_SUB, stubs::Sub, JSVAL_TYPE_UNKNOWN);
+            jsop_binary(JSOP_SUB, stubs::Sub, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0));
             // OBJ * V+1
 
             frame.shimmy(1);
             // OBJ V+1
 
             if (!jsop_setprop(atom, false))
                 return false;
             // V+1
@@ -4565,17 +4557,17 @@ mjit::Compiler::jsop_propinc(JSOp op, Vo
 
             frame.dup();
             // OBJ N N
 
             frame.push(Int32Value(-amt));
             // OBJ N N 1
 
             frame.syncAt(-4);
-            jsop_binary(JSOP_ADD, stubs::Add, JSVAL_TYPE_UNKNOWN);
+            jsop_binary(JSOP_ADD, stubs::Add, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0));
             // OBJ N N+1
 
             frame.dupAt(-3);
             // OBJ N N+1 OBJ
 
             frame.dupAt(-2);
             // OBJ N N+1 OBJ N+1
 
@@ -5907,36 +5899,24 @@ JSValueType
 mjit::Compiler::knownArgumentType(uint32 arg)
 {
     if (!cx->typeInferenceEnabled())
         return JSVAL_TYPE_UNKNOWN;
     JS_ASSERT(fun && arg < fun->nargs);
     return argumentTypes[arg];
 }
 
-void
-mjit::Compiler::markArgumentOverflow(uint32 arg)
-{
-    script->typeSetArgument(cx, arg, DoubleValue(0.0));
-}
-
 JSValueType
 mjit::Compiler::knownLocalType(uint32 local)
 {
     if (!cx->typeInferenceEnabled() || local >= script->nfixed)
         return JSVAL_TYPE_UNKNOWN;
     return localTypes[local];
 }
 
-void
-mjit::Compiler::markLocalOverflow(uint32 local)
-{
-    script->typeSetLocal(cx, local, DoubleValue(0.0));
-}
-
 JSValueType
 mjit::Compiler::knownPushedType(uint32 pushed)
 {
     if (!cx->typeInferenceEnabled())
         return JSVAL_TYPE_UNKNOWN;
     types::TypeSet *types = script->types->pushed(PC - script->code, pushed);
     return types->getKnownTypeTag(cx, script);
 }
@@ -5965,35 +5945,36 @@ mjit::Compiler::argTypeSet(uint32 arg)
 types::TypeSet *
 mjit::Compiler::localTypeSet(uint32 local)
 {
     if (!cx->typeInferenceEnabled() || local >= script->nfixed)
         return NULL;
     return script->localTypes(local);
 }
 
+types::TypeSet *
+mjit::Compiler::pushedTypeSet(uint32 pushed)
+{
+    if (!cx->typeInferenceEnabled())
+        return NULL;
+    return script->types->pushed(PC - script->code, pushed);
+}
+
 bool
 mjit::Compiler::monitored(jsbytecode *pc)
 {
     return cx->typeInferenceEnabled() && script->types->monitored(pc - script->code);
 }
 
 void
 mjit::Compiler::pushSyncedEntry(uint32 pushed)
 {
     frame.pushSynced(knownPushedType(pushed));
 }
 
-void
-mjit::Compiler::markPushedOverflow()
-{
-    /* OK to ignore failure here, we aren't performing the operation itself. */
-    script->typeMonitorResult(cx, PC, types::TYPE_DOUBLE);
-}
-
 JSObject *
 mjit::Compiler::pushedSingleton(unsigned pushed)
 {
     if (!cx->typeInferenceEnabled())
         return NULL;
 
     types::TypeSet *types = script->types->pushed(PC - script->code, pushed);
     return types->getSingleton(cx, script);
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -438,20 +438,18 @@ class Compiler : public BaseCompiler
     JSValueType knownThisType();
     JSValueType knownArgumentType(uint32 arg);
     JSValueType knownLocalType(uint32 local);
     JSValueType knownPushedType(uint32 pushed);
     bool arrayPrototypeHasIndexedProperty();
     bool mayPushUndefined(uint32 pushed);
     types::TypeSet *argTypeSet(uint32 arg);
     types::TypeSet *localTypeSet(uint32 local);
+    types::TypeSet *pushedTypeSet(uint32 which);
     bool monitored(jsbytecode *pc);
-    void markPushedOverflow();
-    void markLocalOverflow(uint32 local);
-    void markArgumentOverflow(uint32 arg);
     bool testSingletonProperty(JSObject *obj, jsid id);
     bool testSingletonPropertyTypes(types::TypeSet *types, jsid id);
 
     /* Non-emitting helpers. */
     void pushSyncedEntry(uint32 pushed);
     uint32 fullAtomIndex(jsbytecode *pc);
     bool jumpInScript(Jump j, jsbytecode *pc);
     bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
@@ -539,17 +537,17 @@ class Compiler : public BaseCompiler
     void emitEval(uint32 argc);
     void jsop_arguments();
     bool jsop_tableswitch(jsbytecode *pc);
     void jsop_forprop(JSAtom *atom);
     void jsop_forname(JSAtom *atom);
     void jsop_forgname(JSAtom *atom);
 
     /* Fast arithmetic. */
-    bool jsop_binary(JSOp op, VoidStub stub, JSValueType type);
+    bool jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet);
     void jsop_binary_full(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
                           JSValueType type);
     void jsop_binary_full_simple(FrameEntry *fe, JSOp op, VoidStub stub,
                                  JSValueType type);
     void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
                             JSValueType type);
     void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
                                 FPRegisterID fpreg);
--- a/js/src/methodjit/FastArithmetic.cpp
+++ b/js/src/methodjit/FastArithmetic.cpp
@@ -192,26 +192,30 @@ mjit::Compiler::maybeJumpIfNotDouble(Ass
         else
             mj.setJump(masm.testDouble(Assembler::NotEqual, frame.addressOf(fe)));
     } else if (fe->getKnownType() != JSVAL_TYPE_DOUBLE) {
         mj.setJump(masm.jump());
     }
 }
 
 bool
-mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type)
+mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     Value v;
     if (tryBinaryConstantFold(cx, frame, op, lhs, rhs, &v)) {
-        if (type == JSVAL_TYPE_INT32 && !v.isInt32()) {
-            /* Caller must mark the right type set as having overflowed. */
-            JaegerSpew(JSpew_Abort, "overflow in binary (%u)\n", PC - script->code);
+        if (!v.isInt32() && typeSet && !typeSet->hasType(types::TYPE_DOUBLE)) {
+            /*
+             * OK to ignore failure here, we aren't performing the operation
+             * itself. Note that typeMonitorResult will propagate the type
+             * as necessary if a *INC operation overflowed.
+             */
+            script->typeMonitorResult(cx, PC, types::TYPE_DOUBLE);
             return false;
         }
         frame.popn(2);
         frame.push(v);
         return true;
     }
 
     /*
@@ -901,19 +905,19 @@ mjit::Compiler::jsop_mod()
 #if defined(JS_CPU_X86)
     JSValueType type = knownPushedType(0);
 
     FrameEntry *lhs = frame.peek(-2);
     FrameEntry *rhs = frame.peek(-1);
 
     Value v;
     if (tryBinaryConstantFold(cx, frame, JSOP_MOD, lhs, rhs, &v)) {
-        if (type == JSVAL_TYPE_INT32 && !v.isInt32()) {
-            JaegerSpew(JSpew_Abort, "overflow in mod (%u)\n", PC - script->code);
-            markPushedOverflow();
+        types::TypeSet *pushed = pushedTypeSet(0);
+        if (!v.isInt32() && pushed && !pushed->hasType(types::TYPE_DOUBLE)) {
+            script->typeMonitorResult(cx, PC, types::TYPE_DOUBLE);
             return false;
         }
         frame.popn(2);
         frame.push(v);
         return true;
     }
 
     if ((lhs->isConstant() && rhs->isConstant()) ||
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1008,20 +1008,18 @@ mjit::Compiler::jsop_localinc(JSOp op, u
 
         // Before: V
         // After:  V 1
         frame.push(Int32Value(amt));
 
         // Note, SUB will perform integer conversion for us.
         // Before: V 1
         // After:  N+1
-        if (!jsop_binary(JSOP_SUB, stubs::Sub, type)) {
-            markLocalOverflow(slot);
+        if (!jsop_binary(JSOP_SUB, stubs::Sub, type, localTypeSet(slot)))
             return false;
-        }
 
         // Before: N+1
         // After:  N+1
         frame.storeLocal(slot, type, popped, true);
 
         if (popped)
             frame.pop();
     } else {
@@ -1040,20 +1038,18 @@ mjit::Compiler::jsop_localinc(JSOp op, u
         frame.dup();
 
         // Before: N N
         // After:  N N 1
         frame.push(Int32Value(amt));
 
         // Before: N N 1
         // After:  N N+1
-        if (!jsop_binary(JSOP_ADD, stubs::Add, type)) {
-            markLocalOverflow(slot);
+        if (!jsop_binary(JSOP_ADD, stubs::Add, type, localTypeSet(slot)))
             return false;
-        }
 
         // Before: N N+1
         // After:  N N+1
         frame.storeLocal(slot, type, true, true);
 
         // Before: N N+1
         // After:  N
         frame.pop();
@@ -1076,20 +1072,18 @@ mjit::Compiler::jsop_arginc(JSOp op, uin
 
         // Before: V
         // After:  V 1
         frame.push(Int32Value(amt));
 
         // Note, SUB will perform integer conversion for us.
         // Before: V 1
         // After:  N+1
-        if (!jsop_binary(JSOP_SUB, stubs::Sub, type)) {
-            markArgumentOverflow(slot);
+        if (!jsop_binary(JSOP_SUB, stubs::Sub, type, argTypeSet(slot)))
             return false;
-        }
 
         // Before: N+1
         // After:  N+1
         frame.storeArg(slot, type, popped);
 
         if (popped)
             frame.pop();
     } else {
@@ -1108,20 +1102,18 @@ mjit::Compiler::jsop_arginc(JSOp op, uin
         frame.dup();
 
         // Before: N N
         // After:  N N 1
         frame.push(Int32Value(amt));
 
         // Before: N N 1
         // After:  N N+1
-        if (!jsop_binary(JSOP_ADD, stubs::Add, type)) {
-            markArgumentOverflow(slot);
+        if (!jsop_binary(JSOP_ADD, stubs::Add, type, argTypeSet(slot)))
             return false;
-        }
 
         // Before: N N+1
         // After:  N N+1
         frame.storeArg(slot, type, true);
 
         // Before: N N+1
         // After:  N
         frame.pop();