Bug 899017 - Fix VM functions called by the JITs to use bool instead of JSBool. r=sstangl
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 30 Jul 2013 11:53:22 +0200
changeset 152779 91837985ae91d394ea96289bb43878161067bd69
parent 152778 80e1116e4599d8e1b8677e44f6066765500746fc
child 152780 313445f455f38bd21ad7a31cd4e301dac8e61c3e
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssstangl
bugs899017
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 899017 - Fix VM functions called by the JITs to use bool instead of JSBool. r=sstangl
js/src/builtin/RegExp.cpp
js/src/builtin/RegExp.h
js/src/ion/AsmJS.cpp
js/src/ion/BaselineCompiler.cpp
js/src/ion/BaselineIC.cpp
js/src/ion/CodeGenerator.cpp
js/src/ion/IonCode.h
js/src/ion/IonMacroAssembler.h
js/src/ion/ParallelFunctions.cpp
js/src/ion/ParallelFunctions.h
js/src/ion/VMFunctions.cpp
js/src/ion/VMFunctions.h
js/src/ion/arm/MacroAssembler-arm.cpp
js/src/ion/arm/MacroAssembler-arm.h
js/src/ion/arm/Trampoline-arm.cpp
js/src/ion/shared/MacroAssembler-x86-shared.h
js/src/ion/x64/Trampoline-x64.cpp
js/src/ion/x86/Trampoline-x86.cpp
js/src/jsapi.cpp
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -673,17 +673,17 @@ regexp_test_impl(JSContext *cx, CallArgs
     MatchConduit conduit(&match);
     RegExpRunStatus status = ExecuteRegExp(cx, args, conduit);
     args.rval().setBoolean(status == RegExpRunStatus_Success);
     return (status != RegExpRunStatus_Error);
 }
 
 /* Separate interface for use by IonMonkey. */
 bool
-js::regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, JSBool *result)
+js::regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, bool *result)
 {
     MatchPair match;
     MatchConduit conduit(&match);
     RegExpRunStatus status = ExecuteRegExp(cx, regexp, input, conduit, UpdateRegExpStatics);
     *result = (status == RegExpRunStatus_Success);
     return (status != RegExpRunStatus_Error);
 }
 
--- a/js/src/builtin/RegExp.h
+++ b/js/src/builtin/RegExp.h
@@ -50,17 +50,17 @@ CreateRegExpMatchResult(JSContext *cx, H
 bool
 CreateRegExpMatchResult(JSContext *cx, HandleString input, const jschar *chars, size_t length,
                         MatchPairs &matches, MutableHandleValue rval);
 
 extern JSBool
 regexp_exec(JSContext *cx, unsigned argc, Value *vp);
 
 bool
-regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, JSBool *result);
+regexp_test_raw(JSContext *cx, HandleObject regexp, HandleString input, bool *result);
 
 extern JSBool
 regexp_test(JSContext *cx, unsigned argc, Value *vp);
 
 /*
  * The following functions are for use by self-hosted code.
  */
 
--- a/js/src/ion/AsmJS.cpp
+++ b/js/src/ion/AsmJS.cpp
@@ -6148,19 +6148,19 @@ GenerateOperationCallbackExit(ModuleComp
     // argument 0: cx
 #if defined(JS_CPU_X86)
     LoadJSContextFromActivation(masm, activation, scratch);
     masm.storePtr(scratch, Address(StackPointer, 0));
 #elif defined(JS_CPU_X64)
     LoadJSContextFromActivation(masm, activation, IntArgReg0);
 #endif
 
-    JSBool (*pf)(JSContext*) = js_HandleExecutionInterrupt;
+    bool (*pf)(JSContext*) = js_HandleExecutionInterrupt;
     masm.call(ImmWord(JS_FUNC_TO_DATA_PTR(void*, pf)));
-    masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
+    masm.branchIfFalseBool(ReturnReg, throwLabel);
 
     // Restore the StackPointer to it's position before the call.
     masm.mov(ABIArgGenerator::NonVolatileReg, StackPointer);
 
     // Restore the machine state to before the interrupt.
     masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
     masm.popFlags();              // after this, nothing that sets conditions
     masm.ret();                   // pop resumePC into PC
@@ -6180,19 +6180,19 @@ GenerateOperationCallbackExit(ModuleComp
     LoadAsmJSActivationIntoRegister(masm, IntArgReg0);
     masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfResumePC()), IntArgReg1);
     masm.storePtr(IntArgReg1, Address(r6, 14 * sizeof(uint32_t*)));
 
     // argument 0: cx
     masm.loadPtr(Address(IntArgReg0, AsmJSActivation::offsetOfContext()), IntArgReg0);
 
     masm.PushRegsInMask(RegisterSet(GeneralRegisterSet(0), FloatRegisterSet(FloatRegisters::AllMask)));   // save all FP registers
-    JSBool (*pf)(JSContext*) = js_HandleExecutionInterrupt;
+    bool (*pf)(JSContext*) = js_HandleExecutionInterrupt;
     masm.call(ImmWord(JS_FUNC_TO_DATA_PTR(void*, pf)));
-    masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
+    masm.branchIfFalseBool(ReturnReg, throwLabel);
 
     // Restore the machine state to before the interrupt. this will set the pc!
     masm.PopRegsInMask(RegisterSet(GeneralRegisterSet(0), FloatRegisterSet(FloatRegisters::AllMask)));   // restore all FP registers
     masm.mov(r6,sp);
     masm.as_vmsr(r5);
     masm.as_msr(r4);
     // Restore all GP registers
     masm.startDataTransferM(IsLoad, sp, IA, WriteBack);
--- a/js/src/ion/BaselineCompiler.cpp
+++ b/js/src/ion/BaselineCompiler.cpp
@@ -322,17 +322,17 @@ BaselineCompiler::emitIC(ICStub *stub, b
     EmitCallIC(&patchOffset, masm);
     entry->setReturnOffset(masm.currentOffset());
     if (!addICLoadLabel(patchOffset))
         return false;
 
     return true;
 }
 
-typedef bool (*DebugPrologueFn)(JSContext *, BaselineFrame *, JSBool *);
+typedef bool (*DebugPrologueFn)(JSContext *, BaselineFrame *, bool *);
 static const VMFunction DebugPrologueInfo = FunctionInfo<DebugPrologueFn>(ion::DebugPrologue);
 
 bool
 BaselineCompiler::emitDebugPrologue()
 {
     if (!debugMode_)
         return true;
 
@@ -776,19 +776,19 @@ bool
 BaselineCompiler::emitTest(bool branchIfTrue)
 {
     bool knownBoolean = frame.peek(-1)->isKnownBoolean();
 
     // Keep top stack value in R0.
     frame.popRegsAndSync(1);
 
     if (!knownBoolean && !emitToBoolean())
-            return false;
-
-    // IC will leave a JSBool value (guaranteed) in R0, just need to branch on it.
+        return false;
+
+    // IC will leave a BooleanValue in R0, just need to branch on it.
     masm.branchTestBooleanTruthy(branchIfTrue, R0, labelOf(pc + GET_JUMP_OFFSET(pc)));
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_IFEQ()
 {
     return emitTest(false);
@@ -1549,17 +1549,17 @@ BaselineCompiler::emit_JSOP_ENUMELEM()
     ICSetElem_Fallback::Compiler stubCompiler(cx);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     frame.pop();
     return true;
 }
 
-typedef bool (*DeleteElementFn)(JSContext *, HandleValue, HandleValue, JSBool *);
+typedef bool (*DeleteElementFn)(JSContext *, HandleValue, HandleValue, bool *);
 static const VMFunction DeleteElementStrictInfo = FunctionInfo<DeleteElementFn>(DeleteElement<true>);
 static const VMFunction DeleteElementNonStrictInfo = FunctionInfo<DeleteElementFn>(DeleteElement<false>);
 
 bool
 BaselineCompiler::emit_JSOP_DELELEM()
 {
     // Keep values on the stack for the decompiler.
     frame.syncStack(0);
@@ -1695,17 +1695,17 @@ BaselineCompiler::emit_JSOP_LENGTH()
 }
 
 bool
 BaselineCompiler::emit_JSOP_GETXPROP()
 {
     return emit_JSOP_GETPROP();
 }
 
-typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, JSBool *);
+typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, bool *);
 static const VMFunction DeletePropertyStrictInfo = FunctionInfo<DeletePropertyFn>(DeleteProperty<true>);
 static const VMFunction DeletePropertyNonStrictInfo = FunctionInfo<DeletePropertyFn>(DeleteProperty<false>);
 
 bool
 BaselineCompiler::emit_JSOP_DELPROP()
 {
     // Keep value on the stack for the decompiler.
     frame.syncStack(0);
@@ -2467,17 +2467,17 @@ BaselineCompiler::emit_JSOP_EXCEPTION()
 
     if (!callVM(GetAndClearExceptionInfo))
         return false;
 
     frame.push(R0);
     return true;
 }
 
-typedef bool (*OnDebuggerStatementFn)(JSContext *, BaselineFrame *, jsbytecode *pc, JSBool *);
+typedef bool (*OnDebuggerStatementFn)(JSContext *, BaselineFrame *, jsbytecode *pc, bool *);
 static const VMFunction OnDebuggerStatementInfo =
     FunctionInfo<OnDebuggerStatementFn>(ion::OnDebuggerStatement);
 
 bool
 BaselineCompiler::emit_JSOP_DEBUGGER()
 {
     prepareVMCall();
     pushArg(ImmWord(pc));
@@ -2494,17 +2494,17 @@ BaselineCompiler::emit_JSOP_DEBUGGER()
     {
         masm.loadValue(frame.addressOfReturnValue(), JSReturnOperand);
         masm.jump(&return_);
     }
     masm.bind(&done);
     return true;
 }
 
-typedef bool (*DebugEpilogueFn)(JSContext *, BaselineFrame *, JSBool);
+typedef bool (*DebugEpilogueFn)(JSContext *, BaselineFrame *, bool);
 static const VMFunction DebugEpilogueInfo = FunctionInfo<DebugEpilogueFn>(ion::DebugEpilogue);
 
 bool
 BaselineCompiler::emitReturn()
 {
     if (debugMode_) {
         // Move return value into the frame's rval slot.
         masm.storeValue(JSReturnOperand, frame.addressOfReturnValue());
--- a/js/src/ion/BaselineIC.cpp
+++ b/js/src/ion/BaselineIC.cpp
@@ -9,16 +9,18 @@
 #include "builtin/Eval.h"
 #include "ion/BaselineCompiler.h"
 #include "ion/BaselineHelpers.h"
 #include "ion/BaselineJIT.h"
 #include "ion/IonLinker.h"
 #include "ion/IonSpewer.h"
 #include "ion/VMFunctions.h"
 
+#include "jsboolinlines.h"
+
 #include "vm/Interpreter-inl.h"
 
 namespace js {
 namespace ion {
 
 #ifdef DEBUG
 void
 FallbackICSpew(JSContext *cx, ICFallbackStub *stub, const char *fmt, ...)
@@ -1657,17 +1659,17 @@ DoCompareFallback(JSContext *cx, Baselin
         op = JSOP_STRICTEQ;
 
     // Don't pass lhs/rhs directly, we need the original values when
     // generating stubs.
     RootedValue lhsCopy(cx, lhs);
     RootedValue rhsCopy(cx, rhs);
 
     // Perform the compare operation.
-    JSBool out;
+    bool out;
     switch(op) {
       case JSOP_LT:
         if (!LessThan(cx, &lhsCopy, &rhsCopy, &out))
             return false;
         break;
       case JSOP_LE:
         if (!LessThanOrEqual(cx, &lhsCopy, &rhsCopy, &out))
             return false;
@@ -2323,17 +2325,18 @@ ICToBool_Object::Compiler::generateStubC
 
     masm.bind(&ifFalse);
     masm.moveValue(BooleanValue(false), R0);
     EmitReturnFromIC(masm);
 
     masm.bind(&slowPath);
     masm.setupUnalignedABICall(1, scratch);
     masm.passABIArg(objReg);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ObjectEmulatesUndefined));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::EmulatesUndefined));
+    masm.convertBoolToInt32(ReturnReg, ReturnReg);
     masm.xor32(Imm32(1), ReturnReg);
     masm.tagValue(JSVAL_TYPE_BOOLEAN, ReturnReg, R0);
     EmitReturnFromIC(masm);
 
     // Failure case - jump to next stub
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
@@ -4738,17 +4741,17 @@ DoInFallback(JSContext *cx, ICIn_Fallbac
 
     if (!objValue.isObject()) {
         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, objValue, NullPtr());
         return false;
     }
 
     RootedObject obj(cx, &objValue.toObject());
 
-    JSBool cond = false;
+    bool cond = false;
     if (!OperatorIn(cx, key, obj, &cond))
         return false;
 
     res.setBoolean(cond);
     return true;
 }
 
 typedef bool (*DoInFallbackFn)(JSContext *, ICIn_Fallback *, HandleValue, HandleValue,
@@ -7722,17 +7725,17 @@ ICCall_ScriptedApplyArguments::Compiler:
     // Enter type monitor IC to type-check result.
     EmitEnterTypeMonitorIC(masm);
 
     masm.bind(&failure);
     EmitStubGuardFailure(masm);
     return true;
 }
 
-static JSBool
+static bool
 DoubleValueToInt32ForSwitch(Value *v)
 {
     double d = v->toDouble();
     int32_t truncated = int32_t(d);
     if (d != double(truncated))
         return false;
 
     v->setInt32(truncated);
@@ -7778,17 +7781,17 @@ ICTableSwitch::Compiler::generateStubCod
         masm.setupUnalignedABICall(1, scratch);
         masm.passABIArg(R0.scratchReg());
         masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, DoubleValueToInt32ForSwitch));
 
         // If the function returns |true|, the value has been converted to
         // int32.
         masm.mov(ReturnReg, scratch);
         masm.popValue(R0);
-        masm.branchTest32(Assembler::Zero, scratch, scratch, &outOfRange);
+        masm.branchIfFalseBool(scratch, &outOfRange);
         masm.unboxInt32(R0, key);
     }
     masm.jump(&isInt32);
 
     masm.bind(&outOfRange);
 
     masm.loadPtr(Address(BaselineStubReg, offsetof(ICTableSwitch, defaultTarget_)), scratch);
 
@@ -8080,17 +8083,17 @@ DoInstanceOfFallback(JSContext *cx, ICIn
 
     if (!rhs.isObject()) {
         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rhs, NullPtr());
         return false;
     }
 
     RootedObject obj(cx, &rhs.toObject());
 
-    JSBool cond = false;
+    bool cond = false;
     if (!HasInstance(cx, obj, lhs, &cond))
         return false;
 
     res.setBoolean(cond);
     return true;
 }
 
 typedef bool (*DoInstanceOfFallbackFn)(JSContext *, ICInstanceOf_Fallback *, HandleValue, HandleValue,
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -21,16 +21,18 @@
 #include "ion/IonSpewer.h"
 #include "ion/MIRGenerator.h"
 #include "ion/MoveEmitter.h"
 #include "ion/ParallelFunctions.h"
 #include "ion/ParallelSafetyAnalysis.h"
 #include "ion/PerfSpewer.h"
 #include "vm/ForkJoin.h"
 
+#include "jsboolinlines.h"
+
 #include "ion/shared/CodeGenerator-shared-inl.h"
 #include "vm/Interpreter-inl.h"
 
 using namespace js;
 using namespace js::ion;
 
 using mozilla::DebugOnly;
 using mozilla::Maybe;
@@ -288,21 +290,21 @@ CodeGenerator::visitDoubleToInt32(LDoubl
 }
 
 void
 CodeGenerator::emitOOLTestObject(Register objreg, Label *ifTruthy, Label *ifFalsy, Register scratch)
 {
     saveVolatile(scratch);
     masm.setupUnalignedABICall(1, scratch);
     masm.passABIArg(objreg);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ObjectEmulatesUndefined));
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js::EmulatesUndefined));
     masm.storeCallResult(scratch);
     restoreVolatile(scratch);
 
-    masm.branchTest32(Assembler::NonZero, scratch, scratch, ifFalsy);
+    masm.branchIfTrueBool(scratch, ifFalsy);
     masm.jump(ifTruthy);
 }
 
 // Base out-of-line code generator for all tests of the truthiness of an
 // object, where the object might not be truthy.  (Recall that per spec all
 // objects are truthy, but we implement the JSCLASS_EMULATES_UNDEFINED class
 // flag to permit objects to look like |undefined| in certain contexts,
 // including in object truthiness testing.)  We check truthiness inline except
@@ -638,17 +640,17 @@ CodeGenerator::visitRegExp(LRegExp *lir)
     JSObject *proto = lir->mir()->getRegExpPrototype();
 
     pushArg(ImmGCPtr(proto));
     pushArg(ImmGCPtr(lir->mir()->source()));
     return callVM(CloneRegExpObjectInfo, lir);
 }
 
 typedef bool (*RegExpTestRawFn)(JSContext *cx, HandleObject regexp,
-                                HandleString input, JSBool *result);
+                                HandleString input, bool *result);
 static const VMFunction RegExpTestRawInfo = FunctionInfo<RegExpTestRawFn>(regexp_test_raw);
 
 bool
 CodeGenerator::visitRegExpTest(LRegExpTest *lir)
 {
     pushArg(ToRegister(lir->string()));
     pushArg(ToRegister(lir->regexp()));
     return callVM(RegExpTestRawInfo, lir);
@@ -2121,17 +2123,17 @@ CodeGenerator::visitFilterArguments(LFil
     masm.loadJSContext(temp2);
 
     masm.setupUnalignedABICall(2, temp1);
     masm.passABIArg(temp2);
     masm.passABIArg(string);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, FilterArguments));
 
     Label bail;
-    masm.branch32(Assembler::Equal, ReturnReg, Imm32(0), &bail);
+    masm.branchIfFalseBool(ReturnReg, &bail);
     return bailoutFrom(&bail, lir->snapshot());
 }
 
 typedef bool (*DirectEvalFn)(JSContext *, HandleObject, HandleScript, HandleValue, HandleString,
                              jsbytecode *, MutableHandleValue);
 static const VMFunction DirectEvalInfo = FunctionInfo<DirectEvalFn>(DirectEvalFromIon);
 
 bool
@@ -3622,19 +3624,18 @@ CodeGenerator::visitBinaryV(LBinaryV *li
       case JSOP_URSH:
         return callVM(UrshInfo, lir);
 
       default:
         MOZ_ASSUME_UNREACHABLE("Unexpected binary op");
     }
 }
 
-typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, JSBool *);
-typedef ParallelResult (*StringCompareParFn)(ForkJoinSlice *, HandleString, HandleString,
-                                             JSBool *);
+typedef bool (*StringCompareFn)(JSContext *, HandleString, HandleString, bool *);
+typedef ParallelResult (*StringCompareParFn)(ForkJoinSlice *, HandleString, HandleString, bool *);
 static const VMFunctionsModal StringsEqualInfo = VMFunctionsModal(
     FunctionInfo<StringCompareFn>(ion::StringsEqual<true>),
     FunctionInfo<StringCompareParFn>(ion::StringsEqualPar));
 static const VMFunctionsModal StringsNotEqualInfo = VMFunctionsModal(
     FunctionInfo<StringCompareFn>(ion::StringsEqual<false>),
     FunctionInfo<StringCompareParFn>(ion::StringsUnequalPar));
 
 bool
@@ -3695,19 +3696,19 @@ CodeGenerator::visitCompareS(LCompareS *
     Register left = ToRegister(lir->left());
     Register right = ToRegister(lir->right());
     Register output = ToRegister(lir->output());
     Register temp = ToRegister(lir->temp());
 
     return emitCompareS(lir, op, left, right, output, temp);
 }
 
-typedef bool (*CompareFn)(JSContext *, MutableHandleValue, MutableHandleValue, JSBool *);
+typedef bool (*CompareFn)(JSContext *, MutableHandleValue, MutableHandleValue, bool *);
 typedef ParallelResult (*CompareParFn)(ForkJoinSlice *, MutableHandleValue, MutableHandleValue,
-                                       JSBool *);
+                                       bool *);
 static const VMFunctionsModal EqInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(ion::LooselyEqual<true>),
     FunctionInfo<CompareParFn>(ion::LooselyEqualPar));
 static const VMFunctionsModal NeInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(ion::LooselyEqual<false>),
     FunctionInfo<CompareParFn>(ion::LooselyUnequalPar));
 static const VMFunctionsModal StrictEqInfo = VMFunctionsModal(
     FunctionInfo<CompareFn>(ion::StrictlyEqual<true>),
@@ -4554,20 +4555,19 @@ CodeGenerator::visitStoreElementHoleV(LS
         masm.storeValue(value, Address(elements, ToInt32(lir->index()) * sizeof(js::Value)));
     else
         masm.storeValue(value, BaseIndex(elements, ToRegister(lir->index()), TimesEight));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*SetObjectElementFn)(JSContext *, HandleObject,
-                                   HandleValue, HandleValue, JSBool strict);
-static const VMFunction SetObjectElementInfo =
-    FunctionInfo<SetObjectElementFn>(SetObjectElement);
+typedef bool (*SetObjectElementFn)(JSContext *, HandleObject, HandleValue, HandleValue,
+                                   bool strict);
+static const VMFunction SetObjectElementInfo = FunctionInfo<SetObjectElementFn>(SetObjectElement);
 
 bool
 CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole *ool)
 {
     Register object, elements;
     LInstruction *ins = ool->ins();
     const LAllocation *index;
     MIRType valueType;
@@ -5078,17 +5078,17 @@ CodeGenerator::visitIteratorNext(LIterat
 
     // Increase the cursor.
     masm.addPtr(Imm32(sizeof(JSString *)), Address(temp, offsetof(NativeIterator, props_cursor)));
 
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*IteratorMoreFn)(JSContext *, HandleObject, JSBool *);
+typedef bool (*IteratorMoreFn)(JSContext *, HandleObject, bool *);
 static const VMFunction IteratorMoreInfo = FunctionInfo<IteratorMoreFn>(ion::IteratorMore);
 
 bool
 CodeGenerator::visitIteratorMore(LIteratorMore *lir)
 {
     const Register obj = ToRegister(lir->object());
     const Register output = ToRegister(lir->output());
     const Register temp = ToRegister(lir->temp());
@@ -5993,32 +5993,32 @@ CodeGenerator::visitCallSetProperty(LCal
 
     pushArg(value);
     pushArg(ImmGCPtr(ins->mir()->name()));
     pushArg(objReg);
 
     return callVM(SetPropertyInfo, ins);
 }
 
-typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, JSBool *);
+typedef bool (*DeletePropertyFn)(JSContext *, HandleValue, HandlePropertyName, bool *);
 static const VMFunction DeletePropertyStrictInfo =
     FunctionInfo<DeletePropertyFn>(DeleteProperty<true>);
 static const VMFunction DeletePropertyNonStrictInfo =
     FunctionInfo<DeletePropertyFn>(DeleteProperty<false>);
 
 bool
 CodeGenerator::visitCallDeleteProperty(LCallDeleteProperty *lir)
 {
     pushArg(ImmGCPtr(lir->mir()->name()));
     pushArg(ToValue(lir, LCallDeleteProperty::Value));
 
     if (lir->mir()->block()->info().script()->strict)
         return callVM(DeletePropertyStrictInfo, lir);
-    else
-        return callVM(DeletePropertyNonStrictInfo, lir);
+
+    return callVM(DeletePropertyNonStrictInfo, lir);
 }
 
 bool
 CodeGenerator::visitSetPropertyCacheV(LSetPropertyCacheV *ins)
 {
     RegisterSet liveRegs = ins->safepoint()->liveRegs();
     Register objReg = ToRegister(ins->getOperand(0));
     ConstantOrRegister value = TypedOrValueRegister(ToValue(ins, LSetPropertyCacheV::Value));
@@ -6494,29 +6494,29 @@ CodeGenerator::visitClampVToUint8(LClamp
 
     masm.bind(&isZero);
     masm.move32(Imm32(0), output);
 
     masm.bind(&done);
     return true;
 }
 
-typedef bool (*OperatorInFn)(JSContext *, HandleValue, HandleObject, JSBool *);
+typedef bool (*OperatorInFn)(JSContext *, HandleValue, HandleObject, bool *);
 static const VMFunction OperatorInInfo = FunctionInfo<OperatorInFn>(OperatorIn);
 
 bool
 CodeGenerator::visitIn(LIn *ins)
 {
     pushArg(ToRegister(ins->rhs()));
     pushArg(ToValue(ins, LIn::LHS));
 
     return callVM(OperatorInInfo, ins);
 }
 
-typedef bool (*OperatorInIFn)(JSContext *, uint32_t, HandleObject, JSBool *);
+typedef bool (*OperatorInIFn)(JSContext *, uint32_t, HandleObject, bool *);
 static const VMFunction OperatorInIInfo = FunctionInfo<OperatorInIFn>(OperatorInI);
 
 bool
 CodeGenerator::visitInArray(LInArray *lir)
 {
     const MInArray *mir = lir->mir();
     Register elements = ToRegister(lir->elements());
     Register initLength = ToRegister(lir->initLength());
@@ -6592,26 +6592,22 @@ CodeGenerator::visitInstanceOfO(LInstanc
 bool
 CodeGenerator::visitInstanceOfV(LInstanceOfV *ins)
 {
     return emitInstanceOf(ins, ins->mir()->prototypeObject());
 }
 
 // Wrap IsDelegate, which takes a Value for the lhs of an instanceof.
 static bool
-IsDelegateObject(JSContext *cx, HandleObject protoObj, HandleObject obj, JSBool *res)
-{
-    bool nres;
-    if (!IsDelegate(cx, protoObj, ObjectValue(*obj), &nres))
-        return false;
-    *res = nres;
-    return true;
-}
-
-typedef bool (*IsDelegateObjectFn)(JSContext *, HandleObject, HandleObject, JSBool *);
+IsDelegateObject(JSContext *cx, HandleObject protoObj, HandleObject obj, bool *res)
+{
+    return IsDelegate(cx, protoObj, ObjectValue(*obj), res);
+}
+
+typedef bool (*IsDelegateObjectFn)(JSContext *, HandleObject, HandleObject, bool *);
 static const VMFunction IsDelegateObjectInfo = FunctionInfo<IsDelegateObjectFn>(IsDelegateObject);
 
 bool
 CodeGenerator::emitInstanceOf(LInstruction *ins, JSObject *prototypeObject)
 {
     // This path implements fun_hasInstance when the function's prototype is
     // known to be prototypeObject.
 
@@ -6694,17 +6690,17 @@ CodeGenerator::emitInstanceOf(LInstructi
     masm.bind(&testLazy);
     masm.branchPtr(Assembler::Equal, output, ImmWord(1), lazyEntry);
 
     masm.bind(&done);
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef bool (*HasInstanceFn)(JSContext *, HandleObject, HandleValue, JSBool *);
+typedef bool (*HasInstanceFn)(JSContext *, HandleObject, HandleValue, bool *);
 static const VMFunction HasInstanceInfo = FunctionInfo<HasInstanceFn>(js::HasInstance);
 
 bool
 CodeGenerator::visitCallInstanceOf(LCallInstanceOf *ins)
 {
     ValueOperand lhs = ToValue(ins, LCallInstanceOf::LHS);
     Register rhs = ToRegister(ins->rhs());
     JS_ASSERT(ToRegister(ins->output()) == ReturnReg);
--- a/js/src/ion/IonCode.h
+++ b/js/src/ion/IonCode.h
@@ -42,17 +42,17 @@ class IonCode : public gc::Cell
     uint8_t *code_;
     JSC::ExecutablePool *pool_;
     uint32_t bufferSize_;             // Total buffer size.
     uint32_t insnSize_;               // Instruction stream size.
     uint32_t dataSize_;               // Size of the read-only data area.
     uint32_t jumpRelocTableBytes_;    // Size of the jump relocation table.
     uint32_t dataRelocTableBytes_;    // Size of the data relocation table.
     uint32_t preBarrierTableBytes_;   // Size of the prebarrier table.
-    JSBool invalidated_;              // Whether the code object has been invalidated.
+    bool invalidated_;                // Whether the code object has been invalidated.
                                       // This is necessary to prevent GC tracing.
 
 #if JS_BITS_PER_WORD == 32
     // Ensure IonCode is gc::Cell aligned.
     uint32_t padding_;
 #endif
 
     IonCode()
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -214,16 +214,22 @@ class MacroAssembler : public MacroAssem
     }
 
     // Branches to |label| if |reg| is false. |reg| should be a C++ bool.
     void branchIfFalseBool(const Register &reg, Label *label) {
         // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
         branchTest32(Assembler::Zero, reg, Imm32(0xFF), label);
     }
 
+    // Branches to |label| if |reg| is true. |reg| should be a C++ bool.
+    void branchIfTrueBool(const Register &reg, Label *label) {
+        // Note that C++ bool is only 1 byte, so ignore the higher-order bits.
+        branchTest32(Assembler::NonZero, reg, Imm32(0xFF), label);
+    }
+
     void loadObjPrivate(Register obj, uint32_t nfixed, Register dest) {
         loadPtr(Address(obj, JSObject::getPrivateDataOffset(nfixed)), dest);
     }
 
     void loadObjProto(Register obj, Register dest) {
         loadPtr(Address(obj, JSObject::offsetOfType()), dest);
         loadPtr(Address(dest, offsetof(types::TypeObject, proto)), dest);
     }
--- a/js/src/ion/ParallelFunctions.cpp
+++ b/js/src/ion/ParallelFunctions.cpp
@@ -271,36 +271,36 @@ CompareMaybeStringsPar(ForkJoinSlice *sl
         return TP_RETRY_SEQUENTIALLY;
     if (!v2.isString())
         return TP_RETRY_SEQUENTIALLY;
     return CompareStringsPar(slice, v1.toString(), v2.toString(), res);
 }
 
 template<bool Equal>
 ParallelResult
-LooselyEqualImplPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+LooselyEqualImplPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(==, Equal);
 }
 
 ParallelResult
-js::ion::LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+js::ion::LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return LooselyEqualImplPar<true>(slice, lhs, rhs, res);
 }
 
 ParallelResult
-js::ion::LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+js::ion::LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return LooselyEqualImplPar<false>(slice, lhs, rhs, res);
 }
 
 template<bool Equal>
 ParallelResult
-StrictlyEqualImplPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+StrictlyEqualImplPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     if (lhs.isNumber()) {
         if (rhs.isNumber()) {
             *res = (lhs.toNumber() == rhs.toNumber()) == Equal;
             return TP_SUCCESS;
         }
     } else if (lhs.isBoolean()) {
         if (rhs.isBoolean()) {
@@ -327,71 +327,71 @@ StrictlyEqualImplPar(ForkJoinSlice *slic
             return LooselyEqualImplPar<Equal>(slice, lhs, rhs, res);
     }
 
     *res = false;
     return TP_SUCCESS;
 }
 
 ParallelResult
-js::ion::StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+js::ion::StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return StrictlyEqualImplPar<true>(slice, lhs, rhs, res);
 }
 
 ParallelResult
-js::ion::StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+js::ion::StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     return StrictlyEqualImplPar<false>(slice, lhs, rhs, res);
 }
 
 ParallelResult
-js::ion::LessThanPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+js::ion::LessThanPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(<, true);
 }
 
 ParallelResult
-js::ion::LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+js::ion::LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(<=, true);
 }
 
 ParallelResult
-js::ion::GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+js::ion::GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(>, true);
 }
 
 ParallelResult
-js::ion::GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+js::ion::GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
     PAR_RELATIONAL_OP(>=, true);
 }
 
 template<bool Equal>
 ParallelResult
-StringsEqualImplPar(ForkJoinSlice *slice, HandleString lhs, HandleString rhs, JSBool *res)
+StringsEqualImplPar(ForkJoinSlice *slice, HandleString lhs, HandleString rhs, bool *res)
 {
     int32_t vsZero;
     ParallelResult ret = CompareStringsPar(slice, lhs, rhs, &vsZero);
     if (ret != TP_SUCCESS)
         return ret;
     *res = (vsZero == 0) == Equal;
     return TP_SUCCESS;
 }
 
 ParallelResult
-js::ion::StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, JSBool *res)
+js::ion::StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *res)
 {
     return StringsEqualImplPar<true>(slice, v1, v2, res);
 }
 
 ParallelResult
-js::ion::StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, JSBool *res)
+js::ion::StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *res)
 {
     return StringsEqualImplPar<false>(slice, v1, v2, res);
 }
 
 void
 ion::AbortPar(ParallelBailoutCause cause, JSScript *outermostScript, JSScript *currentScript,
               jsbytecode *bytecode)
 {
--- a/js/src/ion/ParallelFunctions.h
+++ b/js/src/ion/ParallelFunctions.h
@@ -42,27 +42,27 @@ JSObject *ExtendArrayPar(ForkJoinSlice *
 // that take a ThreadSafeContext.
 ParallelResult ConcatStringsPar(ForkJoinSlice *slice, HandleString left, HandleString right,
                                 MutableHandleString out);
 ParallelResult IntToStringPar(ForkJoinSlice *slice, int i, MutableHandleString out);
 ParallelResult DoubleToStringPar(ForkJoinSlice *slice, double d, MutableHandleString out);
 
 // These parallel operations fail if they would be required to convert
 // to a string etc etc.
-ParallelResult StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, JSBool *);
-ParallelResult StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, JSBool *);
-ParallelResult LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, JSBool *);
-ParallelResult LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, JSBool *);
-ParallelResult LessThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, JSBool *);
-ParallelResult LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, JSBool *);
-ParallelResult GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, JSBool *);
-ParallelResult GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, JSBool *);
+ParallelResult StrictlyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+ParallelResult StrictlyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+ParallelResult LooselyEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+ParallelResult LooselyUnequalPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+ParallelResult LessThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+ParallelResult LessThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+ParallelResult GreaterThanPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
+ParallelResult GreaterThanOrEqualPar(ForkJoinSlice *slice, MutableHandleValue v1, MutableHandleValue v2, bool *);
 
-ParallelResult StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, JSBool *);
-ParallelResult StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, JSBool *);
+ParallelResult StringsEqualPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
+ParallelResult StringsUnequalPar(ForkJoinSlice *slice, HandleString v1, HandleString v2, bool *);
 
 ParallelResult InitRestParameterPar(ForkJoinSlice *slice, uint32_t length, Value *rest,
                                     HandleObject templateObj, HandleObject res,
                                     MutableHandleObject out);
 
 void AbortPar(ParallelBailoutCause cause, JSScript *outermostScript, JSScript *currentScript,
               jsbytecode *bytecode);
 void PropagateAbortPar(JSScript *outermostScript, JSScript *currentScript);
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -11,18 +11,16 @@
 #include "ion/BaselineIC.h"
 #include "ion/Ion.h"
 #include "ion/IonCompartment.h"
 #include "ion/IonFrames.h"
 #include "vm/ArrayObject.h"
 #include "vm/Debugger.h"
 #include "vm/Interpreter.h"
 
-#include "jsboolinlines.h"
-
 #include "ion/BaselineFrame-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/StringObject-inl.h"
 
 using namespace js;
 using namespace js::ion;
 
 namespace js {
@@ -141,104 +139,82 @@ InitProp(JSContext *cx, HandleObject obj
 
     if (name == cx->names().proto)
         return baseops::SetPropertyHelper(cx, obj, obj, id, 0, &rval, false);
     return DefineNativeProperty(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, 0, 0, 0);
 }
 
 template<bool Equal>
 bool
-LooselyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+LooselyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
-    bool equal;
-    if (!js::LooselyEqual(cx, lhs, rhs, &equal))
+    if (!js::LooselyEqual(cx, lhs, rhs, res))
         return false;
-    *res = (equal == Equal);
+    if (!Equal)
+        *res = !*res;
     return true;
 }
 
-template bool LooselyEqual<true>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
-template bool LooselyEqual<false>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
+template bool LooselyEqual<true>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
+template bool LooselyEqual<false>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
 
 template<bool Equal>
 bool
-StrictlyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+StrictlyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
-    bool equal;
-    if (!js::StrictlyEqual(cx, lhs, rhs, &equal))
+    if (!js::StrictlyEqual(cx, lhs, rhs, res))
         return false;
-    *res = (equal == Equal);
+    if (!Equal)
+        *res = !*res;
     return true;
 }
 
-template bool StrictlyEqual<true>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
-template bool StrictlyEqual<false>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
+template bool StrictlyEqual<true>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
+template bool StrictlyEqual<false>(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
 
 bool
-LessThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+LessThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
-    bool cond;
-    if (!LessThanOperation(cx, lhs, rhs, &cond))
-        return false;
-    *res = cond;
-    return true;
+    return LessThanOperation(cx, lhs, rhs, res);
 }
 
 bool
-LessThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+LessThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
-    bool cond;
-    if (!LessThanOrEqualOperation(cx, lhs, rhs, &cond))
-        return false;
-    *res = cond;
-    return true;
+    return LessThanOrEqualOperation(cx, lhs, rhs, res);
 }
 
 bool
-GreaterThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+GreaterThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
-    bool cond;
-    if (!GreaterThanOperation(cx, lhs, rhs, &cond))
-        return false;
-    *res = cond;
-    return true;
+    return GreaterThanOperation(cx, lhs, rhs, res);
 }
 
 bool
-GreaterThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res)
+GreaterThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res)
 {
-    bool cond;
-    if (!GreaterThanOrEqualOperation(cx, lhs, rhs, &cond))
-        return false;
-    *res = cond;
-    return true;
+    return GreaterThanOrEqualOperation(cx, lhs, rhs, res);
 }
 
 template<bool Equal>
 bool
-StringsEqual(JSContext *cx, HandleString lhs, HandleString rhs, JSBool *res)
+StringsEqual(JSContext *cx, HandleString lhs, HandleString rhs, bool *res)
 {
-    bool equal;
-    if (!js::EqualStrings(cx, lhs, rhs, &equal))
+    if (!js::EqualStrings(cx, lhs, rhs, res))
         return false;
-    *res = (equal == Equal);
+    if (!Equal)
+        *res = !*res;
     return true;
 }
 
-template bool StringsEqual<true>(JSContext *cx, HandleString lhs, HandleString rhs, JSBool *res);
-template bool StringsEqual<false>(JSContext *cx, HandleString lhs, HandleString rhs, JSBool *res);
-
-JSBool
-ObjectEmulatesUndefined(JSObject *obj)
-{
-    return EmulatesUndefined(obj);
-}
+template bool StringsEqual<true>(JSContext *cx, HandleString lhs, HandleString rhs, bool *res);
+template bool StringsEqual<false>(JSContext *cx, HandleString lhs, HandleString rhs, bool *res);
 
 bool
-IteratorMore(JSContext *cx, HandleObject obj, JSBool *res)
+IteratorMore(JSContext *cx, HandleObject obj, bool *res)
 {
     RootedValue tmp(cx);
     if (!js_IteratorMore(cx, obj, &tmp))
         return false;
 
     *res = tmp.toBoolean();
     return true;
 }
@@ -474,33 +450,33 @@ SPSEnter(JSContext *cx, HandleScript scr
 bool
 SPSExit(JSContext *cx, HandleScript script)
 {
     cx->runtime()->spsProfiler.exit(cx, script, script->function());
     return true;
 }
 
 bool
-OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, JSBool *out)
+OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out)
 {
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, key, &id))
         return false;
 
     RootedObject obj2(cx);
     RootedShape prop(cx);
     if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
         return false;
 
     *out = !!prop;
     return true;
 }
 
 bool
-OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, JSBool *out)
+OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out)
 {
     RootedValue key(cx, Int32Value(index));
     return OperatorIn(cx, key, obj, out);
 }
 
 bool
 GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval)
 {
@@ -566,17 +542,17 @@ GetDynamicName(JSContext *cx, JSObject *
     if (LookupNameNoGC(cx, atom->asPropertyName(), scopeChain, &scope, &pobj, &shape)) {
         if (FetchNameNoGC(pobj, shape, MutableHandleValue::fromMarkedLocation(vp)))
             return;
     }
 
     vp->setUndefined();
 }
 
-JSBool
+bool
 FilterArguments(JSContext *cx, JSString *str)
 {
     // getChars() is fallible, but cannot GC: it can only allocate a character
     // for the flattened string. If this call fails then the calling Ion code
     // will bailout, resume in the interpreter and likely fail again when
     // trying to flatten the string and unwind the stack.
     const jschar *chars = str->getChars(cx);
     if (!chars)
@@ -609,17 +585,17 @@ GetIndexFromString(JSString *str)
     JSAtom *atom = &str->asAtom();
     if (!atom->isIndex(&index))
         return UINT32_MAX;
 
     return index;
 }
 
 bool
-DebugPrologue(JSContext *cx, BaselineFrame *frame, JSBool *mustReturn)
+DebugPrologue(JSContext *cx, BaselineFrame *frame, bool *mustReturn)
 {
     *mustReturn = false;
 
     JSTrapStatus status = ScriptDebugPrologue(cx, frame);
     switch (status) {
       case JSTRAP_CONTINUE:
         return true;
 
@@ -635,17 +611,17 @@ DebugPrologue(JSContext *cx, BaselineFra
         return false;
 
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid trap status");
     }
 }
 
 bool
-DebugEpilogue(JSContext *cx, BaselineFrame *frame, JSBool ok)
+DebugEpilogue(JSContext *cx, BaselineFrame *frame, bool ok)
 {
     // Unwind scope chain to stack depth 0.
     UnwindScope(cx, frame, 0);
 
     // If ScriptDebugEpilogue returns |true| we have to return the frame's
     // return value. If it returns |false|, the debugger threw an exception.
     // In both cases we have to pop debug scopes.
     ok = ScriptDebugEpilogue(cx, frame, ok);
@@ -723,17 +699,17 @@ InitRestParameter(JSContext *cx, uint32_
         }
         return arrRes;
     }
 
     return NewDenseCopiedArray(cx, length, rest, NULL);
 }
 
 bool
-HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, JSBool *mustReturn)
+HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn)
 {
     *mustReturn = false;
 
     RootedScript script(cx, frame->script());
     jsbytecode *pc = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script);
 
     JS_ASSERT(cx->compartment()->debugMode());
     JS_ASSERT(script->stepModeEnabled() || script->hasBreakpointsAt(pc));
@@ -771,17 +747,17 @@ HandleDebugTrap(JSContext *cx, BaselineF
       default:
         MOZ_ASSUME_UNREACHABLE("Invalid trap status");
     }
 
     return true;
 }
 
 bool
-OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, JSBool *mustReturn)
+OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn)
 {
     *mustReturn = false;
 
     RootedScript script(cx, frame->script());
     JSTrapStatus status = JSTRAP_CONTINUE;
     RootedValue rval(cx);
 
     if (JSDebuggerHandler handler = cx->runtime()->debugHooks.debuggerHandler)
--- a/js/src/ion/VMFunctions.h
+++ b/js/src/ion/VMFunctions.h
@@ -358,16 +358,17 @@ template <> struct TypeToRootType<Handle
     static const uint32_t result = VMFunction::RootCell;
 };
 
 template <class> struct OutParamToDataType { static const DataType result = Type_Void; };
 template <> struct OutParamToDataType<Value *> { static const DataType result = Type_Value; };
 template <> struct OutParamToDataType<int *> { static const DataType result = Type_Int32; };
 template <> struct OutParamToDataType<uint32_t *> { static const DataType result = Type_Int32; };
 template <> struct OutParamToDataType<uint8_t **> { static const DataType result = Type_Pointer; };
+template <> struct OutParamToDataType<bool *> { static const DataType result = Type_Bool; };
 template <> struct OutParamToDataType<MutableHandleValue> { static const DataType result = Type_Handle; };
 template <> struct OutParamToDataType<MutableHandleObject> { static const DataType result = Type_Handle; };
 template <> struct OutParamToDataType<MutableHandleString> { static const DataType result = Type_Handle; };
 
 template <class> struct OutParamToRootType {
     static const VMFunction::RootType result = VMFunction::RootNone;
 };
 template <> struct OutParamToRootType<MutableHandleValue> {
@@ -573,32 +574,30 @@ JSObject *NewGCThing(JSContext *cx, gc::
 
 bool CheckOverRecursed(JSContext *cx);
 
 bool DefVarOrConst(JSContext *cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain);
 bool SetConst(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval);
 bool InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value);
 
 template<bool Equal>
-bool LooselyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
+bool LooselyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
 
 template<bool Equal>
-bool StrictlyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
+bool StrictlyEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
 
-bool LessThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
-bool LessThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
-bool GreaterThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
-bool GreaterThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, JSBool *res);
+bool LessThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
+bool LessThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
+bool GreaterThan(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
+bool GreaterThanOrEqual(JSContext *cx, MutableHandleValue lhs, MutableHandleValue rhs, bool *res);
 
 template<bool Equal>
-bool StringsEqual(JSContext *cx, HandleString left, HandleString right, JSBool *res);
+bool StringsEqual(JSContext *cx, HandleString left, HandleString right, bool *res);
 
-JSBool ObjectEmulatesUndefined(JSObject *obj);
-
-bool IteratorMore(JSContext *cx, HandleObject obj, JSBool *res);
+bool IteratorMore(JSContext *cx, HandleObject obj, bool *res);
 
 // Allocation functions for JSOP_NEWARRAY and JSOP_NEWOBJECT and parallel array inlining
 JSObject *NewInitParallelArray(JSContext *cx, HandleObject templateObj);
 JSObject *NewInitArray(JSContext *cx, uint32_t count, types::TypeObject *type);
 JSObject *NewInitObject(JSContext *cx, HandleObject templateObject);
 JSObject *NewInitObjectWithClassPrototype(JSContext *cx, HandleObject templateObject);
 
 bool ArrayPopDense(JSContext *cx, HandleObject obj, MutableHandleValue rval);
@@ -617,46 +616,46 @@ bool InterruptCheck(JSContext *cx);
 HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots);
 JSObject *NewCallObject(JSContext *cx, HandleScript script,
                         HandleShape shape, HandleTypeObject type, HeapSlot *slots);
 JSObject *NewStringObject(JSContext *cx, HandleString str);
 
 bool SPSEnter(JSContext *cx, HandleScript script);
 bool SPSExit(JSContext *cx, HandleScript script);
 
-bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, JSBool *out);
-bool OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, JSBool *out);
+bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out);
+bool OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out);
 
 bool GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval);
 
 bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval);
 
 void GetDynamicName(JSContext *cx, JSObject *scopeChain, JSString *str, Value *vp);
 
-JSBool FilterArguments(JSContext *cx, JSString *str);
+bool FilterArguments(JSContext *cx, JSString *str);
 
 #ifdef JSGC_GENERATIONAL
 void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
 #endif
 
 uint32_t GetIndexFromString(JSString *str);
 
-bool DebugPrologue(JSContext *cx, BaselineFrame *frame, JSBool *mustReturn);
-bool DebugEpilogue(JSContext *cx, BaselineFrame *frame, JSBool ok);
+bool DebugPrologue(JSContext *cx, BaselineFrame *frame, bool *mustReturn);
+bool DebugEpilogue(JSContext *cx, BaselineFrame *frame, bool ok);
 
 bool StrictEvalPrologue(JSContext *cx, BaselineFrame *frame);
 bool HeavyweightFunPrologue(JSContext *cx, BaselineFrame *frame);
 
 bool NewArgumentsObject(JSContext *cx, BaselineFrame *frame, MutableHandleValue res);
 
 JSObject *InitRestParameter(JSContext *cx, uint32_t length, Value *rest, HandleObject templateObj,
                             HandleObject res);
 
-bool HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, JSBool *mustReturn);
-bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, JSBool *mustReturn);
+bool HandleDebugTrap(JSContext *cx, BaselineFrame *frame, uint8_t *retAddr, bool *mustReturn);
+bool OnDebuggerStatement(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool *mustReturn);
 
 bool EnterBlock(JSContext *cx, BaselineFrame *frame, Handle<StaticBlockObject *> block);
 bool LeaveBlock(JSContext *cx, BaselineFrame *frame);
 
 bool InitBaselineFrameForOsr(BaselineFrame *frame, StackFrame *interpFrame,
                              uint32_t numStackValues);
 
 } // namespace ion
--- a/js/src/ion/arm/MacroAssembler-arm.cpp
+++ b/js/src/ion/arm/MacroAssembler-arm.cpp
@@ -26,16 +26,24 @@ isValueDTRDCandidate(ValueOperand &val)
     if ((val.typeReg().code() != (val.payloadReg().code() + 1)))
         return false;
     if ((val.payloadReg().code() & 1) != 0)
         return false;
     return true;
 }
 
 void
+MacroAssemblerARM::convertBoolToInt32(Register source, Register dest)
+{
+    // Note that C++ bool is only 1 byte, so zero extend it to clear the
+    // higher-order bits.
+    ma_and(Imm32(0xff), source, dest);
+}
+
+void
 MacroAssemblerARM::convertInt32ToDouble(const Register &src, const FloatRegister &dest_)
 {
     // direct conversions aren't possible.
     VFPRegister dest = VFPRegister(dest_);
     as_vxfer(src, InvalidReg, dest.sintOverlay(),
              CoreToFloat);
     as_vcvt(dest, dest.sintOverlay());
 }
--- a/js/src/ion/arm/MacroAssembler-arm.h
+++ b/js/src/ion/arm/MacroAssembler-arm.h
@@ -40,16 +40,17 @@ class MacroAssemblerARM : public Assembl
       : secondScratchReg_(lr)
     { }
 
     void setSecondScratchReg(Register reg) {
         JS_ASSERT(reg != ScratchRegister);
         secondScratchReg_ = reg;
     }
 
+    void convertBoolToInt32(Register source, Register dest);
     void convertInt32ToDouble(const Register &src, const FloatRegister &dest);
     void convertInt32ToDouble(const Address &src, FloatRegister dest);
     void convertUInt32ToDouble(const Register &src, const FloatRegister &dest);
     void convertDoubleToFloat(const FloatRegister &src, const FloatRegister &dest);
     void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail);
     void convertDoubleToInt32(const FloatRegister &src, const Register &dest, Label *fail,
                               bool negativeZeroCheck = true);
 
--- a/js/src/ion/arm/Trampoline-arm.cpp
+++ b/js/src/ion/arm/Trampoline-arm.cpp
@@ -253,17 +253,17 @@ IonRuntime::generateEnterJIT(JSContext *
         masm.pop(jitcode);
         masm.pop(framePtr);
 
         JS_ASSERT(jitcode != ReturnReg);
 
         Label error;
         masm.addPtr(Imm32(IonExitFrameLayout::SizeWithFooter()), sp);
         masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
-        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &error);
+        masm.branchIfFalseBool(ReturnReg, &error);
 
         masm.jump(jitcode);
 
         // OOM: load error value, discard return address and previous frame
         // pointer and return.
         masm.bind(&error);
         masm.mov(framePtr, sp);
         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), sp);
@@ -648,16 +648,17 @@ IonRuntime::generateVMWrapper(JSContext 
         outReg = r4;
         regs.take(outReg);
         masm.PushEmptyRooted(f.outParamRootType);
         masm.ma_mov(sp, outReg);
         break;
 
       case Type_Int32:
       case Type_Pointer:
+      case Type_Bool:
         outReg = r4;
         regs.take(outReg);
         masm.reserveStack(sizeof(int32_t));
         masm.ma_mov(sp, outReg);
         break;
 
       default:
         JS_ASSERT(f.outParam == Type_Void);
@@ -728,16 +729,21 @@ IonRuntime::generateVMWrapper(JSContext 
         break;
 
       case Type_Int32:
       case Type_Pointer:
         masm.load32(Address(sp, 0), ReturnReg);
         masm.freeStack(sizeof(int32_t));
         break;
 
+      case Type_Bool:
+        masm.load8ZeroExtend(Address(sp, 0), ReturnReg);
+        masm.freeStack(sizeof(int32_t));
+        break;
+
       default:
         JS_ASSERT(f.outParam == Type_Void);
         break;
     }
     masm.leaveExitFrame();
     masm.retn(Imm32(sizeof(IonExitFrameLayout) +
                     f.explicitStackSlots() * sizeof(void *) +
                     f.extraValuesToPop * sizeof(Value)));
@@ -788,17 +794,17 @@ IonRuntime::generatePreBarrier(JSContext
 
     masm.PopRegsInMask(save);
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx, JSC::OTHER_CODE);
 }
 
-typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, JSBool *);
+typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, bool *);
 static const VMFunction HandleDebugTrapInfo = FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap);
 
 IonCode *
 IonRuntime::generateDebugTrapHandler(JSContext *cx)
 {
     MacroAssembler masm;
 
     Register scratch1 = r0;
--- a/js/src/ion/shared/MacroAssembler-x86-shared.h
+++ b/js/src/ion/shared/MacroAssembler-x86-shared.h
@@ -402,16 +402,22 @@ class MacroAssemblerX86Shared : public A
         // "2. Optimizing subroutines in assembly language" by Agner Fog, and as
         // previously implemented here. However, with x86 and x64 both using
         // constant pool loads for double constants, this is probably only
         // worthwhile in cases where a load is likely to be delayed.
 
         return false;
     }
 
+    void convertBoolToInt32(Register source, Register dest) {
+        // Note that C++ bool is only 1 byte, so zero extend it to clear the
+        // higher-order bits.
+        movzxbl(source, dest);
+    }
+
     void emitSet(Assembler::Condition cond, const Register &dest,
                  Assembler::NaNCond ifNaN = Assembler::NaN_HandledByCond) {
         if (GeneralRegisterSet(Registers::SingleByteRegs).has(dest)) {
             // If the register we're defining is a single byte register,
             // take advantage of the setCC instruction
             setCC(cond, dest);
             movzxbl(dest, dest);
 
--- a/js/src/ion/x64/Trampoline-x64.cpp
+++ b/js/src/ion/x64/Trampoline-x64.cpp
@@ -201,17 +201,17 @@ IonRuntime::generateEnterJIT(JSContext *
         masm.pop(reg_code);
         masm.pop(framePtr);
 
         JS_ASSERT(reg_code != ReturnReg);
 
         Label error;
         masm.addPtr(Imm32(IonExitFrameLayout::SizeWithFooter()), rsp);
         masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
-        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &error);
+        masm.branchIfFalseBool(ReturnReg, &error);
 
         masm.jump(reg_code);
 
         // OOM: load error value, discard return address and previous frame
         // pointer and return.
         masm.bind(&error);
         masm.mov(framePtr, rsp);
         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), rsp);
@@ -520,16 +520,17 @@ IonRuntime::generateVMWrapper(JSContext 
 
       case Type_Handle:
         outReg = regs.takeAny();
         masm.PushEmptyRooted(f.outParamRootType);
         masm.movq(esp, outReg);
         break;
 
       case Type_Int32:
+      case Type_Bool:
         outReg = regs.takeAny();
         masm.reserveStack(sizeof(int32_t));
         masm.movq(esp, outReg);
         break;
 
       case Type_Pointer:
         outReg = regs.takeAny();
         masm.reserveStack(sizeof(uintptr_t));
@@ -603,16 +604,21 @@ IonRuntime::generateVMWrapper(JSContext 
         masm.freeStack(sizeof(Value));
         break;
 
       case Type_Int32:
         masm.load32(Address(esp, 0), ReturnReg);
         masm.freeStack(sizeof(int32_t));
         break;
 
+      case Type_Bool:
+        masm.load8ZeroExtend(Address(esp, 0), ReturnReg);
+        masm.freeStack(sizeof(int32_t));
+        break;
+
       case Type_Pointer:
         masm.loadPtr(Address(esp, 0), ReturnReg);
         masm.freeStack(sizeof(uintptr_t));
         break;
 
       default:
         JS_ASSERT(f.outParam == Type_Void);
         break;
@@ -662,17 +668,17 @@ IonRuntime::generatePreBarrier(JSContext
 
     masm.PopRegsInMask(regs);
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx, JSC::OTHER_CODE);
 }
 
-typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, JSBool *);
+typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, bool *);
 static const VMFunction HandleDebugTrapInfo = FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap);
 
 IonCode *
 IonRuntime::generateDebugTrapHandler(JSContext *cx)
 {
     MacroAssembler masm;
 
     Register scratch1 = rax;
--- a/js/src/ion/x86/Trampoline-x86.cpp
+++ b/js/src/ion/x86/Trampoline-x86.cpp
@@ -186,17 +186,17 @@ IonRuntime::generateEnterJIT(JSContext *
         masm.pop(jitcode);
         masm.pop(framePtr);
 
         JS_ASSERT(jitcode != ReturnReg);
 
         Label error;
         masm.addPtr(Imm32(IonExitFrameLayout::SizeWithFooter()), esp);
         masm.addPtr(Imm32(BaselineFrame::Size()), framePtr);
-        masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, &error);
+        masm.branchIfFalseBool(ReturnReg, &error);
 
         masm.jump(jitcode);
 
         // OOM: load error value, discard return address and previous frame
         // pointer and return.
         masm.bind(&error);
         masm.mov(framePtr, esp);
         masm.addPtr(Imm32(2 * sizeof(uintptr_t)), esp);
@@ -545,16 +545,17 @@ IonRuntime::generateVMWrapper(JSContext 
       case Type_Handle:
         outReg = regs.takeAny();
         masm.PushEmptyRooted(f.outParamRootType);
         masm.movl(esp, outReg);
         break;
 
       case Type_Int32:
       case Type_Pointer:
+      case Type_Bool:
         outReg = regs.takeAny();
         masm.reserveStack(sizeof(int32_t));
         masm.movl(esp, outReg);
         break;
 
       default:
         JS_ASSERT(f.outParam == Type_Void);
         break;
@@ -627,16 +628,21 @@ IonRuntime::generateVMWrapper(JSContext 
         masm.Pop(JSReturnOperand);
         break;
 
       case Type_Int32:
       case Type_Pointer:
         masm.Pop(ReturnReg);
         break;
 
+      case Type_Bool:
+        masm.Pop(ReturnReg);
+        masm.movzxbl(ReturnReg, ReturnReg);
+        break;
+
       default:
         JS_ASSERT(f.outParam == Type_Void);
         break;
     }
     masm.leaveExitFrame();
     masm.retn(Imm32(sizeof(IonExitFrameLayout) +
                     f.explicitStackSlots() * sizeof(void *) +
                     f.extraValuesToPop * sizeof(Value)));
@@ -688,17 +694,17 @@ IonRuntime::generatePreBarrier(JSContext
 
     masm.PopRegsInMask(save);
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx, JSC::OTHER_CODE);
 }
 
-typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, JSBool *);
+typedef bool (*HandleDebugTrapFn)(JSContext *, BaselineFrame *, uint8_t *, bool *);
 static const VMFunction HandleDebugTrapInfo = FunctionInfo<HandleDebugTrapFn>(HandleDebugTrap);
 
 IonCode *
 IonRuntime::generateDebugTrapHandler(JSContext *cx)
 {
     MacroAssembler masm;
 
     Register scratch1 = eax;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2780,17 +2780,22 @@ JS_InstanceOf(JSContext *cx, JSObject *o
 
 JS_PUBLIC_API(JSBool)
 JS_HasInstance(JSContext *cx, JSObject *objArg, jsval valueArg, JSBool *bp)
 {
     RootedObject obj(cx, objArg);
     RootedValue value(cx, valueArg);
     AssertHeapIsIdle(cx);
     assertSameCompartment(cx, obj, value);
-    return HasInstance(cx, obj, value, bp);
+
+    bool b;
+    if (!HasInstance(cx, obj, value, &b))
+        return false;
+    *bp = b;
+    return true;
 }
 
 JS_PUBLIC_API(void *)
 JS_GetPrivate(JSObject *obj)
 {
     /* This function can be called by a finalizer. */
     return obj->getPrivate();
 }
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -1027,23 +1027,22 @@ js_InvokeOperationCallback(JSContext *cx
      * Important: Additional callbacks can occur inside the callback handler
      * if it re-enters the JS engine. The embedding must ensure that the
      * callback is disconnected before attempting such re-entry.
      */
     JSOperationCallback cb = cx->operationCallback;
     return !cb || cb(cx);
 }
 
-JSBool
+bool
 js_HandleExecutionInterrupt(JSContext *cx)
 {
-    JSBool result = JS_TRUE;
     if (cx->runtime()->interrupt)
-        result = js_InvokeOperationCallback(cx) && result;
-    return result;
+        return js_InvokeOperationCallback(cx);
+    return true;
 }
 
 js::ThreadSafeContext::ThreadSafeContext(JSRuntime *rt, PerThreadData *pt, ContextKind kind)
   : ContextFriendFields(rt),
     contextKind_(kind),
     perThreadData(pt),
     allocator_(NULL)
 { }
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -820,17 +820,17 @@ extern const JSErrorFormatString js_Erro
 
 /*
  * Invoke the operation callback and return false if the current execution
  * is to be terminated.
  */
 extern JSBool
 js_InvokeOperationCallback(JSContext *cx);
 
-extern JSBool
+extern bool
 js_HandleExecutionInterrupt(JSContext *cx);
 
 /*
  * If the operation callback flag was set, call the operation callback.
  * This macro can run the full GC. Return true if it is OK to continue and
  * false otherwise.
  */
 static MOZ_ALWAYS_INLINE bool
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -660,27 +660,32 @@ js::Execute(JSContext *cx, HandleScript 
         return false;
     Value thisv = ObjectValue(*thisObj);
 
     return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
                          NullFramePtr() /* evalInFrame */, rval);
 }
 
 bool
-js::HasInstance(JSContext *cx, HandleObject obj, HandleValue v, JSBool *bp)
+js::HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp)
 {
     Class *clasp = obj->getClass();
     RootedValue local(cx, v);
-    if (clasp->hasInstance)
-        return clasp->hasInstance(cx, obj, &local, bp);
+    if (clasp->hasInstance) {
+        JSBool b;
+        if (!clasp->hasInstance(cx, obj, &local, &b))
+            return false;
+        *bp = b;
+        return true;
+    }
 
     RootedValue val(cx, ObjectValue(*obj));
     js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
                         JSDVG_SEARCH_STACK, val, NullPtr());
-    return JS_FALSE;
+    return false;
 }
 
 bool
 js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result)
 {
     if (SameType(lval, rval)) {
         if (lval.isString()) {
             JSString *l = lval.toString();
@@ -3182,17 +3187,17 @@ BEGIN_CASE(JSOP_INSTANCEOF)
     RootedValue &rref = rootValue0;
     rref = regs.sp[-1];
     if (rref.isPrimitive()) {
         js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, NullPtr());
         goto error;
     }
     RootedObject &obj = rootObject0;
     obj = &rref.toObject();
-    JSBool cond = JS_FALSE;
+    bool cond = false;
     if (!HasInstance(cx, obj, regs.stackHandleAt(-2), &cond))
         goto error;
     regs.sp--;
     regs.sp[-1].setBoolean(cond);
 }
 END_CASE(JSOP_INSTANCEOF)
 
 BEGIN_CASE(JSOP_DEBUGGER)
@@ -3660,86 +3665,90 @@ js::SetProperty(JSContext *cx, HandleObj
     return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
 }
 
 template bool js::SetProperty<true> (JSContext *cx, HandleObject obj, HandleId id, const Value &value);
 template bool js::SetProperty<false>(JSContext *cx, HandleObject obj, HandleId id, const Value &value);
 
 template <bool strict>
 bool
-js::DeleteProperty(JSContext *cx, HandleValue v, HandlePropertyName name, JSBool *bp)
+js::DeleteProperty(JSContext *cx, HandleValue v, HandlePropertyName name, bool *bp)
 {
-    // convert value to JSObject pointer
     RootedObject obj(cx, ToObjectFromStack(cx, v));
     if (!obj)
         return false;
 
-    if (!JSObject::deleteProperty(cx, obj, name, bp))
+    JSBool b;
+    if (!JSObject::deleteProperty(cx, obj, name, &b))
         return false;
+    *bp = b;
+
     if (strict && !*bp) {
         obj->reportNotConfigurable(cx, NameToId(name));
         return false;
     }
     return true;
 }
 
-template bool js::DeleteProperty<true> (JSContext *cx, HandleValue val, HandlePropertyName name, JSBool *bp);
-template bool js::DeleteProperty<false>(JSContext *cx, HandleValue val, HandlePropertyName name, JSBool *bp);
+template bool js::DeleteProperty<true> (JSContext *cx, HandleValue val, HandlePropertyName name, bool *bp);
+template bool js::DeleteProperty<false>(JSContext *cx, HandleValue val, HandlePropertyName name, bool *bp);
 
 template <bool strict>
 bool
-js::DeleteElement(JSContext *cx, HandleValue val, HandleValue index, JSBool *bp)
+js::DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bp)
 {
     RootedObject obj(cx, ToObjectFromStack(cx, val));
     if (!obj)
         return false;
 
-    if (!JSObject::deleteByValue(cx, obj, index, bp))
+    JSBool b;
+    if (!JSObject::deleteByValue(cx, obj, index, &b))
         return false;
+    *bp = b;
     if (strict && !*bp) {
         // XXX This observably calls ToString(propval).  We should convert to
         //     PropertyKey and use that to delete, and to report an error if
         //     necessary!
         RootedId id(cx);
         if (!ValueToId<CanGC>(cx, index, &id))
             return false;
         obj->reportNotConfigurable(cx, id);
         return false;
     }
     return true;
 }
 
-template bool js::DeleteElement<true> (JSContext *, HandleValue, HandleValue, JSBool *succeeded);
-template bool js::DeleteElement<false>(JSContext *, HandleValue, HandleValue, JSBool *succeeded);
+template bool js::DeleteElement<true> (JSContext *, HandleValue, HandleValue, bool *succeeded);
+template bool js::DeleteElement<false>(JSContext *, HandleValue, HandleValue, bool *succeeded);
 
 bool
 js::GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue vp)
 {
     return GetElementOperation(cx, JSOP_GETELEM, lref, rref, vp);
 }
 
 bool
 js::CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res)
 {
     return GetElementOperation(cx, JSOP_CALLELEM, lref, rref, res);
 }
 
 bool
 js::SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
-                     JSBool strict)
+                     bool strict)
 {
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, index, &id))
         return false;
     return SetObjectElementOperation(cx, obj, id, value, strict);
 }
 
 bool
 js::SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
-                     JSBool strict, HandleScript script, jsbytecode *pc)
+                     bool strict, HandleScript script, jsbytecode *pc)
 {
     JS_ASSERT(pc);
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, index, &id))
         return false;
     return SetObjectElementOperation(cx, obj, id, value, strict, script, pc);
 }
 
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -309,17 +309,17 @@ LooselyEqual(JSContext *cx, const Value 
 /* === except that NaN is the same as NaN and -0 is not the same as +0. */
 extern bool
 SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same);
 
 extern JSType
 TypeOfValue(JSContext *cx, const Value &v);
 
 extern bool
-HasInstance(JSContext *cx, HandleObject obj, HandleValue v, JSBool *bp);
+HasInstance(JSContext *cx, HandleObject obj, HandleValue v, bool *bp);
 
 /*
  * A linked list of the |FrameRegs regs;| variables belonging to all
  * js::Interpret C++ frames on this thread's stack.
  *
  * Note that this is *not* a list of all JS frames running under the
  * interpreter; that would include inlined frames, whose FrameRegs are
  * saved in various pieces in various places. Rather, this lists each
@@ -415,20 +415,20 @@ Lambda(JSContext *cx, HandleFunction fun
 bool
 GetElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
 
 bool
 CallElement(JSContext *cx, MutableHandleValue lref, HandleValue rref, MutableHandleValue res);
 
 bool
 SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
-                 JSBool strict);
+                 bool strict);
 bool
 SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
-                 JSBool strict, HandleScript script, jsbytecode *pc);
+                 bool strict, HandleScript script, jsbytecode *pc);
 
 bool
 InitElementArray(JSContext *cx, jsbytecode *pc,
                  HandleObject obj, uint32_t index, HandleValue value);
 
 bool
 AddValues(JSContext *cx, HandleScript script, jsbytecode *pc,
           MutableHandleValue lhs, MutableHandleValue rhs,
@@ -460,21 +460,21 @@ UrshValues(JSContext *cx, HandleScript s
            Value *res);
 
 template <bool strict>
 bool
 SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value);
 
 template <bool strict>
 bool
-DeleteProperty(JSContext *ctx, HandleValue val, HandlePropertyName name, JSBool *bv);
+DeleteProperty(JSContext *ctx, HandleValue val, HandlePropertyName name, bool *bv);
 
 template <bool strict>
 bool
-DeleteElement(JSContext *cx, HandleValue val, HandleValue index, JSBool *bv);
+DeleteElement(JSContext *cx, HandleValue val, HandleValue index, bool *bv);
 
 bool
 DefFunOperation(JSContext *cx, HandleScript script, HandleObject scopeChain, HandleFunction funArg);
 
 bool
 SetCallOperation(JSContext *cx);
 
 bool