Change type testing interface (bug 689831, r=sstangl).
authorDavid Anderson <danderson@mozilla.com>
Wed, 05 Oct 2011 23:22:25 -0700
changeset 78609 eafe88c524da54994cf2ac50f368db1916ef776c
parent 78608 8cfeba5239a9e4f20c462d6fb20421b4e4e7c735
child 78610 4d1446eeacb9811685298c4f4f36f83e0e70006a
push id217
push userdanderson@mozilla.com
push dateThu, 06 Oct 2011 06:26:59 +0000
reviewerssstangl
bugs689831
milestone10.0a1
Change type testing interface (bug 689831, r=sstangl).
js/src/ion/CodeGenerator.cpp
js/src/ion/x64/MacroAssembler-x64.h
js/src/ion/x86/MacroAssembler-x86.h
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -54,64 +54,55 @@ CodeGenerator::CodeGenerator(MIRGenerato
 }
 
 bool
 CodeGenerator::visitValueToInt32(LValueToInt32 *lir)
 {
     ValueOperand operand = ToValue(lir, LValueToInt32::Input);
     Register output = ToRegister(lir->output());
 
-    Assembler::Condition cond;
     Label done, simple, isInt32, isBool, notDouble;
 
     // Type-check switch.
-    cond = masm.testInt32(Assembler::Equal, operand);
-    masm.j(cond, &isInt32);
-    cond = masm.testBoolean(Assembler::Equal, operand);
-    masm.j(cond, &isBool);
-    cond = masm.testDouble(Assembler::NotEqual, operand);
-    masm.j(cond, &notDouble);
+    masm.branchTestInt32(Assembler::Equal, operand, &isInt32);
+    masm.branchTestBoolean(Assembler::Equal, operand, &isBool);
+    masm.branchTestDouble(Assembler::NotEqual, operand, &notDouble);
 
     // If the value is a double, see if it fits in a 32-bit int. We need to ask
     // the platform-specific codegenerator to do this.
     FloatRegister temp = ToFloatRegister(lir->tempFloat());
     masm.unboxDouble(operand, temp);
 
     Label fails;
     switch (lir->mode()) {
       case LValueToInt32::TRUNCATE:
         emitTruncateDouble(temp, output, &fails);
         break;
       default:
         JS_ASSERT(lir->mode() == LValueToInt32::NORMAL);
         emitDoubleToInt32(temp, output, &fails);
         break;
     }
-    if (!bailoutFrom(&fails, lir->snapshot()))
-        return false;
     masm.jump(&done);
 
     masm.bind(&notDouble);
 
     if (lir->mode() == LValueToInt32::NORMAL) {
         // If the value is not null, it's a string, object, or undefined,
         // which we can't handle here.
-        cond = masm.testNull(Assembler::NotEqual, operand);
-        if (!bailoutIf(cond, lir->snapshot()))
-            return false;
+        masm.branchTestNull(Assembler::NotEqual, operand, &fails);
     } else {
         // Test for string or object - then fallthrough to null, which will
         // also handle undefined.
-        cond = masm.testObject(Assembler::Equal, operand);
-        if (!bailoutIf(cond, lir->snapshot()))
-            return false;
-        cond = masm.testString(Assembler::Equal, operand);
-        if (!bailoutIf(cond, lir->snapshot()))
-            return false;
+        masm.branchTestObject(Assembler::Equal, operand, &fails);
+        masm.branchTestString(Assembler::Equal, operand, &fails);
     }
+
+    if (fails.used() && !bailoutFrom(&fails, lir->snapshot()))
+        return false;
     
     // The value is null - just emit 0.
     masm.mov(Imm32(0), output);
     masm.jump(&done);
 
     // Just unbox a bool, the result is 0 or 1.
     masm.bind(&isBool);
     masm.unboxBoolean(operand, output);
@@ -129,30 +120,25 @@ CodeGenerator::visitValueToInt32(LValueT
 static const double DoubleZero = 0.0;
 
 bool
 CodeGenerator::visitValueToDouble(LValueToDouble *lir)
 {
     ValueOperand operand = ToValue(lir, LValueToDouble::Input);
     FloatRegister output = ToFloatRegister(lir->output());
 
-    Assembler::Condition cond;
     Label isDouble, isInt32, isBool, isNull, done;
 
     // Type-check switch.
-    cond = masm.testDouble(Assembler::Equal, operand);
-    masm.j(cond, &isDouble);
-    cond = masm.testInt32(Assembler::Equal, operand);
-    masm.j(cond, &isInt32);
-    cond = masm.testBoolean(Assembler::Equal, operand);
-    masm.j(cond, &isBool);
-    cond = masm.testNull(Assembler::Equal, operand);
-    masm.j(cond, &isNull);
+    masm.branchTestDouble(Assembler::Equal, operand, &isDouble);
+    masm.branchTestInt32(Assembler::Equal, operand, &isInt32);
+    masm.branchTestBoolean(Assembler::Equal, operand, &isBool);
+    masm.branchTestNull(Assembler::Equal, operand, &isNull);
 
-    cond = masm.testUndefined(Assembler::NotEqual, operand);
+    Assembler::Condition cond = masm.testUndefined(Assembler::NotEqual, operand);
     if (!bailoutIf(cond, lir->snapshot()))
         return false;
     masm.loadStaticDouble(&js_NaN, output);
     masm.jump(&done);
 
     masm.bind(&isNull);
     masm.loadStaticDouble(&DoubleZero, output);
     masm.jump(&done);
@@ -187,45 +173,37 @@ CodeGenerator::visitTestVAndBranch(LTest
     Register tag = splitTagForTest(value);
 
     Assembler::Condition cond;
 
     // Eventually we will want some sort of type filter here. For now, just
     // emit all easy cases. For speed we use the cached tag for all comparison,
     // except for doubles, which we test last (as the operation can clobber the
     // tag, which may be in ScratchReg).
-    cond = masm.testUndefined(Assembler::Equal, tag);
-    masm.j(cond, lir->ifFalse());
+    masm.branchTestUndefined(Assembler::Equal, tag, lir->ifFalse());
 
-    cond = masm.testNull(Assembler::Equal, tag);
-    masm.j(cond, lir->ifFalse());
-
-    cond = masm.testObject(Assembler::Equal, tag);
-    masm.j(cond, lir->ifTrue());
+    masm.branchTestNull(Assembler::Equal, tag, lir->ifFalse());
+    masm.branchTestObject(Assembler::Equal, tag, lir->ifTrue());
 
     Label notBoolean;
-    cond = masm.testBoolean(Assembler::NotEqual, tag);
-    masm.j(cond, &notBoolean);
-    cond = masm.testBooleanTruthy(false, value);
-    masm.j(cond, lir->ifFalse());
+    masm.branchTestBoolean(Assembler::NotEqual, tag, &notBoolean);
+    masm.branchTestBooleanTruthy(false, value, lir->ifFalse());
     masm.jump(lir->ifTrue());
     masm.bind(&notBoolean);
 
     Label notInt32;
-    cond = masm.testInt32(Assembler::NotEqual, tag);
-    masm.j(cond, &notInt32);
+    masm.branchTestInt32(Assembler::NotEqual, tag, &notInt32);
     cond = masm.testInt32Truthy(false, value);
     masm.j(cond, lir->ifFalse());
     masm.jump(lir->ifTrue());
     masm.bind(&notInt32);
 
     // Test if a string is non-empty.
     Label notString;
-    cond = masm.testString(Assembler::NotEqual, tag);
-    masm.j(cond, &notString);
+    masm.branchTestString(Assembler::NotEqual, tag, &notString);
     cond = testStringTruthy(false, value);
     masm.j(cond, lir->ifFalse());
     masm.jump(lir->ifTrue());
     masm.bind(&notString);
 
     // If we reach here the value is a double.
     masm.unboxDouble(value, ToFloatRegister(lir->tempFloat()));
     cond = masm.testDoubleTruthy(false, ToFloatRegister(lir->tempFloat()));
--- a/js/src/ion/x64/MacroAssembler-x64.h
+++ b/js/src/ion/x64/MacroAssembler-x64.h
@@ -102,16 +102,77 @@ class MacroAssemblerX64 : public MacroAs
     }
     void movePtr(Operand op, const Register &dest) {
         movq(op, dest);
     }
     void moveValue(const Value &val, const Register &dest) {
         movq(ImmWord((void *)val.asRawBits()), dest);
     }
 
+    Condition testUndefined(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED));
+        return cond;
+    }
+    Condition testInt32(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_INT32));
+        return cond;
+    }
+    Condition testBoolean(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN));
+        return cond;
+    }
+    Condition testNull(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_NULL));
+        return cond;
+    }
+    Condition testString(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_STRING));
+        return cond;
+    }
+    Condition testObject(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_OBJECT));
+        return cond;
+    }
+    Condition testUndefined(Condition cond, const ValueOperand &src) {
+        splitTag(src, ScratchReg);
+        return testUndefined(cond, ScratchReg);
+    }
+    Condition testInt32(Condition cond, const ValueOperand &src) {
+        splitTag(src, ScratchReg);
+        return testInt32(cond, ScratchReg);
+    }
+    Condition testBoolean(Condition cond, const ValueOperand &src) {
+        splitTag(src, ScratchReg);
+        return testBoolean(cond, ScratchReg);
+    }
+    Condition testDouble(Condition cond, const ValueOperand &src) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        movq(ImmShiftedTag(JSVAL_SHIFTED_TAG_MAX_DOUBLE), ScratchReg);
+        cmpq(src.value(), ScratchReg);
+        return (cond == NotEqual) ? Above : BelowOrEqual;
+    }
+    Condition testNull(Condition cond, const ValueOperand &src) {
+        splitTag(src, ScratchReg);
+        return testNull(cond, ScratchReg);
+    }
+    Condition testString(Condition cond, const ValueOperand &src) {
+        splitTag(src, ScratchReg);
+        return testString(cond, ScratchReg);
+    }
+    Condition testObject(Condition cond, const ValueOperand &src) {
+        splitTag(src, ScratchReg);
+        return testObject(cond, ScratchReg);
+    }
+
     /////////////////////////////////////////////////////////////////
     // Common interface.
     /////////////////////////////////////////////////////////////////
     void reserveStack(uint32 amount) {
         if (amount)
             subq(Imm32(amount), StackPointer);
         framePushed_ += amount;
     }
@@ -159,78 +220,69 @@ class MacroAssemblerX64 : public MacroAs
         movq(operand.value(), ScratchReg);
         shrq(Imm32(JSVAL_TAG_SHIFT), ScratchReg);
     }
     void cmpTag(const ValueOperand &operand, ImmTag tag) {
         splitTag(operand, ScratchReg);
         cmpl(Operand(ScratchReg), tag);
     }
 
-    Condition testInt32(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_INT32));
-        return cond;
+    void branchTestUndefined(Condition cond, const Register &tag, Label *label) {
+        cond = testUndefined(cond, tag);
+        j(cond, label);
     }
-    Condition testBoolean(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN));
-        return cond;
+    void branchTestInt32(Condition cond, const Register &tag, Label *label) {
+        cond = testInt32(cond, tag);
+        j(cond, label);
     }
-    Condition testNull(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_NULL));
-        return cond;
+    void branchTestBoolean(Condition cond, const Register &tag, Label *label) {
+        cond = testBoolean(cond, tag);
+        j(cond, label);
     }
-    Condition testUndefined(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED));
-        return cond;
+    void branchTestNull(Condition cond, const Register &tag, Label *label) {
+        cond = testNull(cond, tag);
+        j(cond, label);
     }
-    Condition testString(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_STRING));
-        return cond;
+    void branchTestString(Condition cond, const Register &tag, Label *label) {
+        cond = testString(cond, tag);
+        j(cond, label);
     }
-    Condition testObject(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_OBJECT));
-        return cond;
+    void branchTestObject(Condition cond, const Register &tag, Label *label) {
+        cond = testObject(cond, tag);
+        j(cond, label);
     }
 
     // Type-testing instructions on x64 will clobber ScratchReg.
-    Condition testInt32(Condition cond, const ValueOperand &src) {
-        splitTag(src, ScratchReg);
-        return testInt32(cond, ScratchReg);
+    void branchTestUndefined(Condition cond, const ValueOperand &src, Label *label) {
+        cond = testUndefined(cond, src);
+        j(cond, label);
     }
-    Condition testBoolean(Condition cond, const ValueOperand &src) {
+    void branchTestInt32(Condition cond, const ValueOperand &src, Label *label) {
         splitTag(src, ScratchReg);
-        return testBoolean(cond, ScratchReg);
+        branchTestInt32(cond, ScratchReg, label);
     }
-    Condition testDouble(Condition cond, const ValueOperand &src) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        movq(ImmShiftedTag(JSVAL_SHIFTED_TAG_MAX_DOUBLE), ScratchReg);
-        cmpq(src.value(), ScratchReg);
-        return (cond == NotEqual) ? Above : BelowOrEqual;
+    void branchTestBoolean(Condition cond, const ValueOperand &src, Label *label) {
+        splitTag(src, ScratchReg);
+        branchTestBoolean(cond, ScratchReg, label);
     }
-    Condition testObject(Condition cond, const ValueOperand &src) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpTag(src, ImmTag(JSVAL_TAG_OBJECT));
-        return cond;
+    void branchTestDouble(Condition cond, const ValueOperand &src, Label *label) {
+        cond = testDouble(cond, src);
+        j(cond, label);
+    }
+    void branchTestNull(Condition cond, const ValueOperand &src, Label *label) {
+        cond = testNull(cond, src);
+        j(cond, label);
     }
-    Condition testNull(Condition cond, const ValueOperand &src) {
-        splitTag(src, ScratchReg);
-        return testNull(cond, ScratchReg);
+    void branchTestString(Condition cond, const ValueOperand &src, Label *label) {
+        cond = testString(cond, src);
+        j(cond, label);
     }
-    Condition testUndefined(Condition cond, const ValueOperand &src) {
-        splitTag(src, ScratchReg);
-        return testUndefined(cond, ScratchReg);
-    }
-    Condition testString(Condition cond, const ValueOperand &src) {
-        splitTag(src, ScratchReg);
-        return testString(cond, ScratchReg);
+    void branchTestObject(Condition cond, const ValueOperand &src, Label *label) {
+        cond = testObject(cond, src);
+        j(cond, label);
     }
 
     // Note that the |dest| register here may be ScratchReg, so we shouldn't
     // use it.
     void unboxInt32(const ValueOperand &src, const Register &dest) {
         movl(src.value(), dest);
     }
     void unboxBoolean(const ValueOperand &src, const Register &dest) {
@@ -271,19 +323,19 @@ class MacroAssemblerX64 : public MacroAs
     void loadStaticDouble(const double *dp, const FloatRegister &dest) {
         loadDouble(*dp, dest);
     }
 
     Condition testInt32Truthy(bool truthy, const ValueOperand &operand) {
         testl(operand.valueReg(), operand.valueReg());
         return truthy ? NonZero : Zero;
     }
-    Condition testBooleanTruthy(bool truthy, const ValueOperand &operand) {
+    void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) {
         testl(operand.valueReg(), operand.valueReg());
-        return truthy ? NonZero : Zero;
+        j(truthy ? NonZero : Zero, label);
     }
 };
 
 typedef MacroAssemblerX64 MacroAssemblerSpecific;
 
 } // namespace ion
 } // namespace js
 
--- a/js/src/ion/x86/MacroAssembler-x86.h
+++ b/js/src/ion/x86/MacroAssembler-x86.h
@@ -96,16 +96,74 @@ class MacroAssemblerX86 : public MacroAs
     void storeValue(ValueOperand val, Operand dest) {
         movl(val.payloadReg(), ToPayload(dest));
         movl(val.typeReg(), ToType(dest));
     }
     void movePtr(Operand op, const Register &dest) {
         movl(op, dest);
     }
 
+    Condition testUndefined(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED));
+        return cond;
+    }
+    Condition testBoolean(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN));
+        return cond;
+    }
+    Condition testInt32(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_INT32));
+        return cond;
+    }
+    Condition testDouble(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+        Condition actual = (cond == Equal) ? Below : AboveOrEqual;
+        cmpl(tag, ImmTag(JSVAL_TAG_CLEAR));
+        return actual;
+    }
+    Condition testNull(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_NULL));
+        return cond;
+    }
+    Condition testString(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_STRING));
+        return cond;
+    }
+    Condition testObject(Condition cond, const Register &tag) {
+        JS_ASSERT(cond == Equal || cond == NotEqual);
+        cmpl(tag, ImmTag(JSVAL_TAG_OBJECT));
+        return cond;
+    }
+    Condition testUndefined(Condition cond, const ValueOperand &value) {
+        return testUndefined(cond, value.typeReg());
+    }
+    Condition testBoolean(Condition cond, const ValueOperand &value) {
+        return testBoolean(cond, value.typeReg());
+    }
+    Condition testInt32(Condition cond, const ValueOperand &value) {
+        return testInt32(cond, value.typeReg());
+    }
+    Condition testDouble(Condition cond, const ValueOperand &value) {
+        return testDouble(cond, value.typeReg());
+    }
+    Condition testNull(Condition cond, const ValueOperand &value) {
+        return testNull(cond, value.typeReg());
+    }
+    Condition testString(Condition cond, const ValueOperand &value) {
+        return testString(cond, value.typeReg());
+    }
+    Condition testObject(Condition cond, const ValueOperand &value) {
+        return testObject(cond, value.typeReg());
+    }
+
     /////////////////////////////////////////////////////////////////
     // Common interface.
     /////////////////////////////////////////////////////////////////
     void reserveStack(uint32 amount) {
         if (amount)
             subl(Imm32(amount), StackPointer);
         framePushed_ += amount;
     }
@@ -145,73 +203,52 @@ class MacroAssemblerX86 : public MacroAs
         movl(esp, eax);
         testl(Imm32(StackAlignment - 1), eax);
         j(Equal, &good);
         breakpoint();
         bind(&good);
 #endif
     }
 
-    Condition testInt32(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_INT32));
-        return cond;
-    }
-    Condition testBoolean(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_BOOLEAN));
-        return cond;
+    // Type testing instructions can take a tag in a register or a
+    // ValueOperand.
+    template <typename T>
+    void branchTestUndefined(Condition cond, const T &t, Label *label) {
+        cond = testUndefined(cond, t);
+        j(cond, label);
     }
-    Condition testDouble(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
-        Condition actual = (cond == Equal) ? Below : AboveOrEqual;
-        cmpl(tag, ImmTag(JSVAL_TAG_CLEAR));
-        return actual;
+    template <typename T>
+    void branchTestInt32(Condition cond, const T &t, Label *label) {
+        cond = testInt32(cond, t);
+        j(cond, label);
     }
-    Condition testNull(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_NULL));
-        return cond;
-    }
-    Condition testUndefined(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_UNDEFINED));
-        return cond;
+    template <typename T>
+    void branchTestBoolean(Condition cond, const T &t, Label *label) {
+        cond = testBoolean(cond, t);
+        j(cond, label);
     }
-    Condition testString(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_STRING));
-        return cond;
+    template <typename T>
+    void branchTestDouble(Condition cond, const T &t, Label *label) {
+        cond = testDouble(cond, t);
+        j(cond, label);
     }
-    Condition testObject(Condition cond, const Register &tag) {
-        JS_ASSERT(cond == Equal || cond == NotEqual);
-        cmpl(tag, ImmTag(JSVAL_TAG_OBJECT));
-        return cond;
-    }
-
-    Condition testInt32(Condition cond, const ValueOperand &value) {
-        return testInt32(cond, value.typeReg());
+    template <typename T>
+    void branchTestNull(Condition cond, const T &t, Label *label) {
+        cond = testNull(cond, t);
+        j(cond, label);
     }
-    Condition testBoolean(Condition cond, const ValueOperand &value) {
-        return testBoolean(cond, value.typeReg());
-    }
-    Condition testDouble(Condition cond, const ValueOperand &value) {
-        return testDouble(cond, value.typeReg());
-    }
-    Condition testNull(Condition cond, const ValueOperand &value) {
-        return testNull(cond, value.typeReg());
+    template <typename T>
+    void branchTestString(Condition cond, const T &t, Label *label) {
+        cond = testString(cond, t);
+        j(cond, label);
     }
-    Condition testUndefined(Condition cond, const ValueOperand &value) {
-        return testUndefined(cond, value.typeReg());
-    }
-    Condition testString(Condition cond, const ValueOperand &value) {
-        return testString(cond, value.typeReg());
-    }
-    Condition testObject(Condition cond, const ValueOperand &value) {
-        return testObject(cond, value.typeReg());
+    template <typename T>
+    void branchTestObject(Condition cond, const T &t, Label *label) {
+        cond = testObject(cond, t);
+        j(cond, label);
     }
 
     void unboxInt32(const ValueOperand &operand, const Register &dest) {
         movl(operand.payloadReg(), dest);
     }
     void unboxBoolean(const ValueOperand &operand, const Register &dest) {
         movl(operand.payloadReg(), dest);
     }
@@ -237,19 +274,19 @@ class MacroAssemblerX86 : public MacroAs
     void loadStaticDouble(const double *dp, const FloatRegister &dest) {
         movsd(dp, dest);
     }
 
     Condition testInt32Truthy(bool truthy, const ValueOperand &operand) {
         testl(operand.payloadReg(), operand.payloadReg());
         return truthy ? NonZero : Zero;
     }
-    Condition testBooleanTruthy(bool truthy, const ValueOperand &operand) {
+    void branchTestBooleanTruthy(bool truthy, const ValueOperand &operand, Label *label) {
         testl(operand.payloadReg(), operand.payloadReg());
-        return truthy ? NonZero : Zero;
+        j(truthy ? NonZero : Zero, label);
     }
 };
 
 typedef MacroAssemblerX86 MacroAssemblerSpecific;
 
 } // namespace ion
 } // namespace js