Compile JSOP_ITER (bug 701965, r=jandem)
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 08 Feb 2012 11:05:32 +0100
changeset 112663 e4fb2cc5006a3993277027ff55d9b9708eab6e92
parent 112662 41382184b0f5f23cb359fab4ef67d5bcec6875dc
child 112664 0eca72ae5ad25ee0dd5012640752b19120f6deb4
push id239
push userakeybl@mozilla.com
push dateThu, 03 Jan 2013 21:54:43 +0000
treeherdermozilla-release@3a7b66445659 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs701965
milestone13.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
Compile JSOP_ITER (bug 701965, r=jandem)
js/src/ion/CodeGenerator.cpp
js/src/ion/CodeGenerator.h
js/src/ion/IonBuilder.cpp
js/src/ion/IonBuilder.h
js/src/ion/LIR-Common.h
js/src/ion/LOpcodes.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MIRGraph.cpp
js/src/ion/MOpcodes.h
js/src/jsiter.cpp
js/src/jsiter.h
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1223,16 +1223,72 @@ CodeGenerator::visitOutOfLineStoreElemen
         return false;
 
     restoreLive(ins);
     masm.jump(ool->rejoin());
     return true;
 }
 
 bool
+CodeGenerator::visitCallIteratorStart(LCallIteratorStart *lir)
+{
+    typedef JSObject *(*pf)(JSContext *, JSObject *, uint32_t);
+    static const VMFunction Info = FunctionInfo<pf>(GetIteratorObject);
+
+    const Register objReg = ToRegister(lir->getOperand(0));
+
+    pushArg(Imm32(lir->mir()->flags()));
+    pushArg(objReg);
+    return callVM(Info, lir);
+}
+
+bool
+CodeGenerator::visitCallIteratorNext(LCallIteratorNext *lir)
+{
+    typedef bool (*pf)(JSContext *, JSObject *, Value *);
+    static const VMFunction Info = FunctionInfo<pf>(js_IteratorNext);
+
+    const Register objReg = ToRegister(lir->getOperand(0));
+
+    pushArg(objReg);
+    return callVM(Info, lir);
+}
+
+bool
+CodeGenerator::visitCallIteratorMore(LCallIteratorMore *lir)
+{
+    typedef bool (*pf)(JSContext *, JSObject *, Value *);
+    static const VMFunction Info = FunctionInfo<pf>(js_IteratorMore);
+
+    const Register objReg = ToRegister(lir->getOperand(0));
+
+    pushArg(objReg);
+    if (!callVM(Info, lir))
+        return false;
+
+    // Unbox the boolean value produced by IteratorMore to the output register.
+    Register output = ToRegister(lir->getDef(0));
+    masm.unboxValue(JSReturnOperand, AnyRegister(output));
+
+    return true;
+}
+
+bool
+CodeGenerator::visitCallIteratorEnd(LCallIteratorEnd *lir)
+{
+    typedef bool (*pf)(JSContext *, JSObject *);
+    static const VMFunction Info = FunctionInfo<pf>(js_CloseIterator);
+
+    const Register objReg = ToRegister(lir->getOperand(0));
+
+    pushArg(objReg);
+    return callVM(Info, lir);
+}
+
+bool
 CodeGenerator::generate()
 {
     JSContext *cx = gen->cx;
 
     if (!safepoints_.init(graph.localSlotCount()))
         return false;
 
     // Before generating any code, we generate type checks for all parameters.
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -122,16 +122,20 @@ class CodeGenerator : public CodeGenerat
     bool visitCallSetElement(LCallSetElement *lir);
     bool visitThrow(LThrow *lir);
     bool visitLoadElementV(LLoadElementV *load);
     bool visitLoadElementHole(LLoadElementHole *lir);
     bool visitStoreElementT(LStoreElementT *lir);
     bool visitStoreElementV(LStoreElementV *lir);
     bool visitStoreElementHoleT(LStoreElementHoleT *lir);
     bool visitStoreElementHoleV(LStoreElementHoleV *lir);
+    bool visitCallIteratorStart(LCallIteratorStart *lir);
+    bool visitCallIteratorNext(LCallIteratorNext *lir);
+    bool visitCallIteratorMore(LCallIteratorMore *lir);
+    bool visitCallIteratorEnd(LCallIteratorEnd *lir);
 
     bool visitCheckOverRecursed(LCheckOverRecursed *lir);
     bool visitCheckOverRecursedFailure(CheckOverRecursedFailure *ool);
 
     bool visitUnboxDouble(LUnboxDouble *lir);
     bool visitOutOfLineUnboxDouble(OutOfLineUnboxDouble *ool);
     bool visitOutOfLineCacheGetProperty(OutOfLineCache *ool);
     bool visitOutOfLineCacheSetProperty(OutOfLineCache *ool);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -557,26 +557,19 @@ IonBuilder::snoopControlFlow(JSOp op)
           case SRC_CONTINUE:
           case SRC_CONT2LABEL:
             return processContinue(op, sn);
 
           case SRC_SWITCHBREAK:
             return processSwitchBreak(op, sn);
 
           case SRC_WHILE:
+          case SRC_FOR_IN:
             // while (cond) { }
-            if (!whileLoop(op, sn))
-              return ControlStatus_Error;
-            return ControlStatus_Jumped;
-
-          case SRC_FOR_IN:
-            // for (x in y) { }
-            if (!forInLoop(op, sn))
-              return ControlStatus_Error;
-            return ControlStatus_Jumped;
+            return whileOrForInLoop(op, sn);
 
           default:
             // Hard assert for now - make an error later.
             JS_NOT_REACHED("unknown goto case");
             break;
         }
         break;
       }
@@ -794,16 +787,28 @@ IonBuilder::inspectOpcode(JSOp op)
         return jsop_setprop(info().getAtom(pc));
 
       case JSOP_REGEXP:
         return jsop_regexp(info().getRegExp(pc));
 
       case JSOP_OBJECT:
         return jsop_object(info().getObject(pc));
 
+      case JSOP_ITER:
+        return jsop_iter(GET_INT8(pc));
+
+      case JSOP_ITERNEXT:
+        return jsop_iternext(GET_INT8(pc));
+
+      case JSOP_MOREITER:
+        return jsop_itermore();
+
+      case JSOP_ENDITER:
+        return jsop_iterend();
+
       default:
 #ifdef DEBUG
         return abort("Unsupported opcode: %s (line %d)", js_CodeName[op], info().lineno(cx, pc));
 #else
         return abort("Unsupported opcode: %d (line %d)", op, info().lineno(cx, pc));
 #endif
     }
 }
@@ -1568,27 +1573,29 @@ IonBuilder::doWhileLoop(JSOp op, jssrcno
     if (!jsop_loophead(GetNextPc(pc)))
         return ControlStatus_Error;
 
     pc = bodyStart;
     return ControlStatus_Jumped;
 }
 
 IonBuilder::ControlStatus
-IonBuilder::whileLoop(JSOp op, jssrcnote *sn)
+IonBuilder::whileOrForInLoop(JSOp op, jssrcnote *sn)
 {
     // while (cond) { } loops have the following structure:
     //    GOTO cond   ; SRC_WHILE (offset to IFNE)
     //    LOOPHEAD
     //    ...
     //  cond:
     //    LOOPENTRY
     //    ...
     //    IFNE        ; goes to LOOPHEAD
-    int ifneOffset = js_GetSrcNoteOffset(sn, 0);
+    // for (x in y) { } loops are similar; the cond will be a MOREITER.
+    size_t which = (SN_TYPE(sn) == SRC_FOR_IN) ? 1 : 0;
+    int ifneOffset = js_GetSrcNoteOffset(sn, which);
     jsbytecode *ifne = pc + ifneOffset;
     JS_ASSERT(ifne > pc);
 
     // Verify that the IFNE goes back to a loophead op.
     jsbytecode *loopHead = GetNextPc(pc);
     JS_ASSERT(JSOp(*loopHead) == JSOP_LOOPHEAD);
     JS_ASSERT(loopHead == ifne + GetJumpOffset(ifne));
 
@@ -3513,8 +3520,54 @@ IonBuilder::jsop_this()
         // can introduce a phi, but this phi will be specialized.
         current->pushSlot(info().thisSlot());
         return true;
     }
 
     return abort("JSOP_THIS hard case not yet handled");
 }
 
+bool
+IonBuilder::jsop_iter(uint8 flags)
+{
+    MDefinition *obj = current->pop();
+    MInstruction *ins = MIteratorStart::New(obj, flags);
+
+    current->add(ins);
+    current->push(ins);
+
+    return resumeAfter(ins);
+}
+
+bool
+IonBuilder::jsop_iternext(uint8 depth)
+{
+    MDefinition *iter = current->peek(-depth);
+    MInstruction *ins = MIteratorNext::New(iter);
+
+    current->add(ins);
+    current->push(ins);
+
+    return resumeAfter(ins);
+}
+
+bool
+IonBuilder::jsop_itermore()
+{
+    MDefinition *iter = current->peek(-1);
+    MInstruction *ins = MIteratorMore::New(iter);
+
+    current->add(ins);
+    current->push(ins);
+
+    return resumeAfter(ins);
+}
+
+bool
+IonBuilder::jsop_iterend()
+{
+    MDefinition *iter = current->pop();
+    MInstruction *ins = MIteratorEnd::New(iter);
+
+    current->add(ins);
+
+    return resumeAfter(ins);
+}
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -255,21 +255,18 @@ class IonBuilder : public MIRGenerator
     ControlStatus processBrokenLoop(CFGState &state);
 
     // Computes loop phis, places them in all successors of a loop, then
     // handles any pending breaks.
     ControlStatus finishLoop(CFGState &state, MBasicBlock *successor);
 
     void assertValidLoopHeadOp(jsbytecode *pc);
 
-    bool forInLoop(JSOp op, jssrcnote *sn) {
-        return false;
-    }
     ControlStatus forLoop(JSOp op, jssrcnote *sn);
-    ControlStatus whileLoop(JSOp op, jssrcnote *sn);
+    ControlStatus whileOrForInLoop(JSOp op, jssrcnote *sn);
     ControlStatus doWhileLoop(JSOp op, jssrcnote *sn);
     ControlStatus tableSwitch(JSOp op, jssrcnote *sn);
 
     // Please see the Big Honkin' Comment about how resume points work in
     // IonBuilder.cpp, near the definition for this function.
     bool resumeAt(MInstruction *ins, jsbytecode *pc);
     bool resumeAfter(MInstruction *ins);
 
@@ -306,19 +303,23 @@ class IonBuilder : public MIRGenerator
     bool jsop_length();
     bool jsop_length_fastPath();
     bool jsop_getprop(JSAtom *atom);
     bool jsop_setprop(JSAtom *atom);
     bool jsop_newarray(uint32 count);
     bool jsop_regexp(RegExpObject *reobj);
     bool jsop_object(JSObject *obj);
     bool jsop_this();
+    bool jsop_iter(uint8 flags);
+    bool jsop_iternext(uint8 depth);
+    bool jsop_itermore();
+    bool jsop_iterend();
 
     // Replace generic calls to native function by instructions which can be
-    // specialized and which can enable GVN & LICM on these native calls.
+    // specialized and which can enable GVN & LICM on these native calls.
     void discardCallArgs(uint32 argc, MDefinition **argv);
     bool optimizeNativeCall(uint32 argc);
 
     /* Inlining. */
 
     enum InliningStatus
     {
         InliningStatus_Error,
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -1713,16 +1713,69 @@ class LCacheSetPropertyT : public LInstr
     const MGenericSetProperty *mir() const {
         return mir_->toGenericSetProperty();
     }
     MIRType valueType() {
         return valueType_;
     }
 };
 
+class LCallIteratorStart : public LCallInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(CallIteratorStart);
+
+    LCallIteratorStart(const LAllocation &object) {
+        setOperand(0, object);
+    }
+    MIteratorStart *mir() const {
+        return mir_->toIteratorStart();
+    }
+};
+
+class LCallIteratorNext : public LCallInstructionHelper<BOX_PIECES, 1, 0>
+{
+  public:
+    LIR_HEADER(CallIteratorNext);
+    BOX_OUTPUT_ACCESSORS();
+
+    LCallIteratorNext(const LAllocation &iterator) {
+        setOperand(0, iterator);
+    }
+    MIteratorNext *mir() const {
+        return mir_->toIteratorNext();
+    }
+};
+
+class LCallIteratorMore : public LCallInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(CallIteratorMore);
+
+    LCallIteratorMore(const LAllocation &iterator) {
+        setOperand(0, iterator);
+    }
+    MIteratorMore *mir() const {
+        return mir_->toIteratorMore();
+    }
+};
+
+class LCallIteratorEnd : public LCallInstructionHelper<0, 1, 0>
+{
+  public:
+    LIR_HEADER(CallIteratorEnd);
+
+    LCallIteratorEnd(const LAllocation &iterator) {
+        setOperand(0, iterator);
+    }
+    MIteratorEnd *mir() const {
+        return mir_->toIteratorEnd();
+    }
+};
+
 // Mark a Value if it is a GCThing.
 class LWriteBarrierV : public LInstructionHelper<0, BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(WriteBarrierV);
 
     LWriteBarrierV()
     { }
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -128,16 +128,20 @@
     _(CallGetName)                  \
     _(CallGetNameTypeOf)            \
     _(CallGetElement)               \
     _(CallSetElement)               \
     _(CallSetPropertyV)             \
     _(CallSetPropertyT)             \
     _(CacheSetPropertyV)            \
     _(CacheSetPropertyT)            \
+    _(CallIteratorStart)            \
+    _(CallIteratorNext)             \
+    _(CallIteratorMore)             \
+    _(CallIteratorEnd)              \
     _(ArrayLength)                  \
     _(StringLength)                 \
     _(Round)
 
 #if defined(JS_CPU_X86)
 # include "x86/LOpcodes-x86.h"
 #elif defined(JS_CPU_X64)
 # include "x64/LOpcodes-x64.h"
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -1169,16 +1169,44 @@ LIRGenerator::visitCallSetElement(MCallS
     if (!useBox(lir, LCallSetElement::Index, ins->index()))
         return false;
     if (!useBox(lir, LCallSetElement::Value, ins->value()))
         return false;
     return add(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
+LIRGenerator::visitIteratorStart(MIteratorStart *ins)
+{
+    LCallIteratorStart *lir = new LCallIteratorStart(useRegister(ins->object()));
+    return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
+LIRGenerator::visitIteratorNext(MIteratorNext *ins)
+{
+    LCallIteratorNext *lir = new LCallIteratorNext(useRegister(ins->iterator()));
+    return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
+LIRGenerator::visitIteratorMore(MIteratorMore *ins)
+{
+    LCallIteratorMore *lir = new LCallIteratorMore(useRegister(ins->iterator()));
+    return defineVMReturn(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
+LIRGenerator::visitIteratorEnd(MIteratorEnd *ins)
+{
+    LCallIteratorEnd *lir = new LCallIteratorEnd(useRegister(ins->iterator()));
+    return add(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
 LIRGenerator::visitStringLength(MStringLength *ins)
 {
     JS_ASSERT(ins->string()->type() == MIRType_String);
     return define(new LStringLength(useRegister(ins->string())), ins);
 }
 
 bool
 LIRGenerator::visitThrow(MThrow *ins)
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -166,16 +166,20 @@ class LIRGenerator : public LIRGenerator
     bool visitGetPropertyCache(MGetPropertyCache *ins);
     bool visitGuardClass(MGuardClass *ins);
     bool visitCallGetProperty(MCallGetProperty *ins);
     bool visitCallGetName(MCallGetName *ins);
     bool visitCallGetNameTypeOf(MCallGetNameTypeOf *ins);
     bool visitCallGetElement(MCallGetElement *ins);
     bool visitCallSetElement(MCallSetElement *ins);
     bool visitGenericSetProperty(MGenericSetProperty *ins);
+    bool visitIteratorStart(MIteratorStart *ins);
+    bool visitIteratorNext(MIteratorNext *ins);
+    bool visitIteratorMore(MIteratorMore *ins);
+    bool visitIteratorEnd(MIteratorEnd *ins);
     bool visitStringLength(MStringLength *ins);
     bool visitThrow(MThrow *ins);
 
     bool visitGuardObject(MGuardObject *ins) {
         // The type policy associated with this instruction does all the work.
         return true;
     }
 };
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -3123,16 +3123,119 @@ class MRound
         return mode_;
     }
 
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
+class MIteratorStart
+  : public MUnaryInstruction,
+    public ObjectPolicy
+{
+    uint8 flags_;
+
+    MIteratorStart(MDefinition *obj, uint8 flags)
+      : MUnaryInstruction(obj), flags_(flags)
+    {
+        setResultType(MIRType_Object);
+    }
+
+  public:
+    INSTRUCTION_HEADER(IteratorStart);
+
+    static MIteratorStart *New(MDefinition *obj, uint8 flags) {
+        return new MIteratorStart(obj, flags);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+    MDefinition *object() const {
+        return getOperand(0);
+    }
+    uint8 flags() const {
+        return flags_;
+    }
+};
+
+class MIteratorNext
+  : public MUnaryInstruction,
+    public ObjectPolicy
+{
+    MIteratorNext(MDefinition *iter)
+      : MUnaryInstruction(iter)
+    {
+        setResultType(MIRType_Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(IteratorNext);
+
+    static MIteratorNext *New(MDefinition *iter) {
+        return new MIteratorNext(iter);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+    MDefinition *iterator() const {
+        return getOperand(0);
+    }
+};
+
+class MIteratorMore
+  : public MUnaryInstruction,
+    public ObjectPolicy
+{
+    MIteratorMore(MDefinition *iter)
+      : MUnaryInstruction(iter)
+    {
+        setResultType(MIRType_Boolean);
+    }
+
+  public:
+    INSTRUCTION_HEADER(IteratorMore);
+
+    static MIteratorMore *New(MDefinition *iter) {
+        return new MIteratorMore(iter);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+    MDefinition *iterator() const {
+        return getOperand(0);
+    }
+};
+
+class MIteratorEnd
+  : public MUnaryInstruction,
+    public ObjectPolicy
+{
+    MIteratorEnd(MDefinition *iter)
+      : MUnaryInstruction(iter)
+    {}
+
+  public:
+    INSTRUCTION_HEADER(IteratorEnd);
+
+    static MIteratorEnd *New(MDefinition *iter) {
+        return new MIteratorEnd(iter);
+    }
+
+    TypePolicy *typePolicy() {
+        return this;
+    }
+    MDefinition *iterator() const {
+        return getOperand(0);
+    }
+};
+
 // Given a value, guard that the value is in a particular TypeSet, then returns
 // that value.
 class MTypeBarrier : public MUnaryInstruction
 {
     BailoutKind bailoutKind_;
     types::TypeSet *typeSet_;
 
     MTypeBarrier(MDefinition *def, types::TypeSet *types)
--- a/js/src/ion/MIRGraph.cpp
+++ b/js/src/ion/MIRGraph.cpp
@@ -150,27 +150,32 @@ MBasicBlock::init()
     if (!slots_)
         return false;
     return true;
 }
 
 void
 MBasicBlock::copySlots(MBasicBlock *from)
 {
-    stackPosition_ = from->stackPosition_;
+    JS_ASSERT(stackPosition_ == from->stackPosition_);
 
     for (uint32 i = 0; i < stackPosition_; i++)
         slots_[i] = from->slots_[i];
 }
 
 bool
 MBasicBlock::inherit(MBasicBlock *pred)
 {
-    if (pred)
+    if (pred) {
+        stackPosition_ = pred->stackPosition_;
         copySlots(pred);
+    } else {
+        uint32_t stackDepth = info().script()->analysis()->getCode(pc()).stackDepth;
+        stackPosition_ = info().firstStackSlot() + stackDepth;
+    }
 
     // Propagate the caller resume point from the inherited block.
     MResumePoint *callerResumePoint = pred ? pred->callerResumePoint() : NULL;
 
     // Create a resume point using our initial stack state.
     entryResumePoint_ = new MResumePoint(this, pc(), callerResumePoint);
     if (!entryResumePoint_->init(this))
         return false;
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -111,16 +111,20 @@ namespace ion {
     _(LoadFixedSlot)                                                        \
     _(StoreFixedSlot)                                                       \
     _(CallGetProperty)                                                      \
     _(CallGetName)                                                          \
     _(CallGetNameTypeOf)                                                    \
     _(CallGetElement)                                                       \
     _(CallSetElement)                                                       \
     _(GenericSetProperty)                                                   \
+    _(IteratorStart)                                                        \
+    _(IteratorNext)                                                         \
+    _(IteratorMore)                                                         \
+    _(IteratorEnd)                                                          \
     _(StringLength)                                                         \
     _(Round)
 
 // Forward declarations of MIR types.
 #define FORWARD_DECLARE(op) class M##op;
  MIR_OPCODE_LIST(FORWARD_DECLARE)
 #undef FORWARD_DECLARE
 
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -765,18 +765,27 @@ GetIterator(JSContext *cx, JSObject *obj
     if (shapes.length())
         cx->compartment->nativeIterCache.set(key, iterobj);
 
     if (shapes.length() == 2)
         cx->compartment->nativeIterCache.last = iterobj;
     return true;
 }
 
+JSObject *
+GetIteratorObject(JSContext *cx, JSObject *obj, uint32_t flags)
+{
+    Value value;
+    if (!GetIterator(cx, obj, flags, &value))
+        return NULL;
+    return &value.toObject();
 }
 
+} /* namespace js */
+
 static JSObject *
 iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly)
 {
     return obj;
 }
 
 static JSBool
 Iterator(JSContext *cx, uintN argc, Value *vp)
@@ -870,17 +879,17 @@ js_ValueToIterator(JSContext *cx, uintN 
     return GetIterator(cx, obj, flags, vp);
 }
 
 #if JS_HAS_GENERATORS
 static JSBool
 CloseGenerator(JSContext *cx, JSObject *genobj);
 #endif
 
-JS_FRIEND_API(JSBool)
+JS_FRIEND_API(bool)
 js_CloseIterator(JSContext *cx, JSObject *obj)
 {
     cx->iterValue.setMagic(JS_NO_ITER_VALUE);
 
     if (obj->isIterator()) {
         /* Remove enumerators from the active list, which is a stack. */
         NativeIterator *ni = obj->getNativeIterator();
 
@@ -1039,17 +1048,17 @@ class IndexRangePredicate {
 };
 
 bool
 js_SuppressDeletedElements(JSContext *cx, JSObject *obj, uint32_t begin, uint32_t end)
 {
     return SuppressDeletedPropertyHelper(cx, obj, IndexRangePredicate(begin, end));
 }
 
-JSBool
+bool
 js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval)
 {
     /* Fast path for native iterators */
     NativeIterator *ni = NULL;
     if (iterobj->isIterator()) {
         /* Key iterators are handled by fast-paths. */
         ni = iterobj->getNativeIterator();
         bool more = ni->props_cursor < ni->props_end;
@@ -1098,17 +1107,17 @@ js_IteratorMore(JSContext *cx, JSObject 
 
     /* Cache the value returned by iterobj.next() so js_IteratorNext() can find it. */
     JS_ASSERT(!rval->isMagic(JS_NO_ITER_VALUE));
     cx->iterValue = *rval;
     rval->setBoolean(true);
     return true;
 }
 
-JSBool
+bool
 js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
 {
     /* Fast path for native iterators */
     if (iterobj->isIterator()) {
         /*
          * Implement next directly as all the methods of the native iterator are
          * read-only and permanent.
          */
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -102,16 +102,19 @@ struct NativeIterator {
 };
 
 bool
 VectorToIdArray(JSContext *cx, js::AutoIdVector &props, JSIdArray **idap);
 
 bool
 GetIterator(JSContext *cx, JSObject *obj, uintN flags, js::Value *vp);
 
+JSObject *
+GetIteratorObject(JSContext *cx, JSObject *obj, uint32_t flags);
+
 bool
 VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
 
 bool
 VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp);
 
 /*
  * Creates either a key or value iterator, depending on flags. For a value
@@ -126,37 +129,37 @@ EnumeratedIdVectorToIterator(JSContext *
  * Convert the value stored in *vp to its iteration object. The flags should
  * contain JSITER_ENUMERATE if js_ValueToIterator is called when enumerating
  * for-in semantics are required, and when the caller can guarantee that the
  * iterator will never be exposed to scripts.
  */
 extern JS_FRIEND_API(JSBool)
 js_ValueToIterator(JSContext *cx, uintN flags, js::Value *vp);
 
-extern JS_FRIEND_API(JSBool)
+extern JS_FRIEND_API(bool)
 js_CloseIterator(JSContext *cx, JSObject *iterObj);
 
 extern bool
 js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id);
 
 extern bool
 js_SuppressDeletedElement(JSContext *cx, JSObject *obj, uint32_t index);
 
 extern bool
 js_SuppressDeletedElements(JSContext *cx, JSObject *obj, uint32_t begin, uint32_t end);
 
 /*
  * IteratorMore() indicates whether another value is available. It might
  * internally call iterobj.next() and then cache the value until its
  * picked up by IteratorNext(). The value is cached in the current context.
  */
-extern JSBool
+extern bool
 js_IteratorMore(JSContext *cx, JSObject *iterobj, js::Value *rval);
 
-extern JSBool
+extern bool
 js_IteratorNext(JSContext *cx, JSObject *iterobj, js::Value *rval);
 
 extern JSBool
 js_ThrowStopIteration(JSContext *cx);
 
 #if JS_HAS_GENERATORS
 
 /*