Bug 882736 - Ion-compile scripts that use ES5 getter/setter syntax. r=bhackett
authorJan de Mooij <jdemooij@mozilla.com>
Tue, 30 Jul 2013 12:52:09 +0200
changeset 140514 25e81fe30063a5973a1e7700d1f3e4df09a68c17
parent 140513 c53ae775f151306db0aff3e838d0323d7d958eda
child 140515 c22896a275640374218862768e95df771a709956
push id1970
push userryanvm@gmail.com
push dateTue, 30 Jul 2013 17:12:32 +0000
treeherderfx-team@72240998c094 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs882736
milestone25.0a1
Bug 882736 - Ion-compile scripts that use ES5 getter/setter syntax. r=bhackett
js/src/ion/BaselineCompiler.cpp
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/MOpcodes.h
js/src/ion/ParallelSafetyAnalysis.cpp
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
--- a/js/src/ion/BaselineCompiler.cpp
+++ b/js/src/ion/BaselineCompiler.cpp
@@ -1986,36 +1986,37 @@ BaselineCompiler::emit_JSOP_DEFFUN()
     pushArg(ImmGCPtr(fun));
     pushArg(R0.scratchReg());
     pushArg(ImmGCPtr(script));
 
     return callVM(DefFunOperationInfo);
 }
 
 typedef bool (*InitPropGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandlePropertyName,
-                                       HandleValue);
+                                       HandleObject);
 static const VMFunction InitPropGetterSetterInfo =
     FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation);
 
 bool
 BaselineCompiler::emitInitPropGetterSetter()
 {
     JS_ASSERT(JSOp(*pc) == JSOP_INITPROP_GETTER ||
               JSOp(*pc) == JSOP_INITPROP_SETTER);
 
-    // Load value in R0 but keep it on the stack for the decompiler.
+    // Keep values on the stack for the decompiler.
     frame.syncStack(0);
-    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
 
     prepareVMCall();
 
-    pushArg(R0);
+    masm.extractObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
+    masm.extractObject(frame.addressOfStackValue(frame.peek(-2)), R1.scratchReg());
+
+    pushArg(R0.scratchReg());
     pushArg(ImmGCPtr(script->getName(pc)));
-    masm.extractObject(frame.addressOfStackValue(frame.peek(-2)), R0.scratchReg());
-    pushArg(R0.scratchReg());
+    pushArg(R1.scratchReg());
     pushArg(ImmWord(pc));
 
     if (!callVM(InitPropGetterSetterInfo))
         return false;
 
     frame.pop();
     return true;
 }
@@ -2028,35 +2029,35 @@ BaselineCompiler::emit_JSOP_INITPROP_GET
 
 bool
 BaselineCompiler::emit_JSOP_INITPROP_SETTER()
 {
     return emitInitPropGetterSetter();
 }
 
 typedef bool (*InitElemGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandleValue,
-                                       HandleValue);
+                                       HandleObject);
 static const VMFunction InitElemGetterSetterInfo =
     FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation);
 
 bool
 BaselineCompiler::emitInitElemGetterSetter()
 {
     JS_ASSERT(JSOp(*pc) == JSOP_INITELEM_GETTER ||
               JSOp(*pc) == JSOP_INITELEM_SETTER);
 
     // Load index and value in R0 and R1, but keep values on the stack for the
     // decompiler.
     frame.syncStack(0);
     masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
-    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
+    masm.extractObject(frame.addressOfStackValue(frame.peek(-1)), R1.scratchReg());
 
     prepareVMCall();
 
-    pushArg(R1);
+    pushArg(R1.scratchReg());
     pushArg(R0);
     masm.extractObject(frame.addressOfStackValue(frame.peek(-3)), R0.scratchReg());
     pushArg(R0.scratchReg());
     pushArg(ImmWord(pc));
 
     if (!callVM(InitElemGetterSetterInfo))
         return false;
 
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -3167,16 +3167,35 @@ CodeGenerator::visitInitElem(LInitElem *
 
     pushArg(ToValue(lir, LInitElem::ValueIndex));
     pushArg(ToValue(lir, LInitElem::IdIndex));
     pushArg(objReg);
 
     return callVM(InitElemInfo, lir);
 }
 
+typedef bool (*InitElemGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandleValue,
+                                       HandleObject);
+static const VMFunction InitElemGetterSetterInfo =
+    FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation);
+
+bool
+CodeGenerator::visitInitElemGetterSetter(LInitElemGetterSetter *lir)
+{
+    Register obj = ToRegister(lir->object());
+    Register value = ToRegister(lir->value());
+
+    pushArg(value);
+    pushArg(ToValue(lir, LInitElemGetterSetter::IdIndex));
+    pushArg(obj);
+    pushArg(ImmWord(lir->mir()->resumePoint()->pc()));
+
+    return callVM(InitElemGetterSetterInfo, lir);
+}
+
 typedef bool(*InitPropFn)(JSContext *cx, HandleObject obj,
                           HandlePropertyName name, HandleValue value);
 static const VMFunction InitPropInfo =
     FunctionInfo<InitPropFn>(InitProp);
 
 bool
 CodeGenerator::visitInitProp(LInitProp *lir)
 {
@@ -3184,16 +3203,35 @@ CodeGenerator::visitInitProp(LInitProp *
 
     pushArg(ToValue(lir, LInitProp::ValueIndex));
     pushArg(ImmGCPtr(lir->mir()->propertyName()));
     pushArg(objReg);
 
     return callVM(InitPropInfo, lir);
 }
 
+typedef bool(*InitPropGetterSetterFn)(JSContext *, jsbytecode *, HandleObject, HandlePropertyName,
+                                      HandleObject);
+static const VMFunction InitPropGetterSetterInfo =
+    FunctionInfo<InitPropGetterSetterFn>(InitGetterSetterOperation);
+
+bool
+CodeGenerator::visitInitPropGetterSetter(LInitPropGetterSetter *lir)
+{
+    Register obj = ToRegister(lir->object());
+    Register value = ToRegister(lir->value());
+
+    pushArg(value);
+    pushArg(ImmGCPtr(lir->mir()->name()));
+    pushArg(obj);
+    pushArg(ImmWord(lir->mir()->resumePoint()->pc()));
+
+    return callVM(InitPropGetterSetterInfo, lir);
+}
+
 typedef bool (*CreateThisFn)(JSContext *cx, HandleObject callee, MutableHandleValue rval);
 static const VMFunction CreateThisInfo = FunctionInfo<CreateThisFn>(CreateThis);
 
 bool
 CodeGenerator::visitCreateThis(LCreateThis *lir)
 {
     const LAllocation *callee = lir->getCallee();
 
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -122,17 +122,19 @@ class CodeGenerator : public CodeGenerat
     bool visitNewDeclEnvObject(LNewDeclEnvObject *lir);
     bool visitNewCallObject(LNewCallObject *lir);
     bool visitNewCallObjectPar(LNewCallObjectPar *lir);
     bool visitNewStringObject(LNewStringObject *lir);
     bool visitNewPar(LNewPar *lir);
     bool visitNewDenseArrayPar(LNewDenseArrayPar *lir);
     bool visitAbortPar(LAbortPar *lir);
     bool visitInitElem(LInitElem *lir);
+    bool visitInitElemGetterSetter(LInitElemGetterSetter *lir);
     bool visitInitProp(LInitProp *lir);
+    bool visitInitPropGetterSetter(LInitPropGetterSetter *lir);
     bool visitCreateThis(LCreateThis *lir);
     bool visitCreateThisWithProto(LCreateThisWithProto *lir);
     bool visitCreateThisWithTemplate(LCreateThisWithTemplate *lir);
     bool visitCreateArgumentsObject(LCreateArgumentsObject *lir);
     bool visitGetArgumentsObjectArg(LGetArgumentsObjectArg *lir);
     bool visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir);
     bool visitReturnFromCtor(LReturnFromCtor *lir);
     bool visitArrayLength(LArrayLength *lir);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -1334,16 +1334,26 @@ IonBuilder::inspectOpcode(JSOp op)
         return jsop_initelem_array();
 
       case JSOP_INITPROP:
       {
         RootedPropertyName name(cx, info().getAtom(pc)->asPropertyName());
         return jsop_initprop(name);
       }
 
+      case JSOP_INITPROP_GETTER:
+      case JSOP_INITPROP_SETTER: {
+        PropertyName *name = info().getAtom(pc)->asPropertyName();
+        return jsop_initprop_getter_setter(name);
+      }
+
+      case JSOP_INITELEM_GETTER:
+      case JSOP_INITELEM_SETTER:
+        return jsop_initelem_getter_setter();
+
       case JSOP_ENDINIT:
         return true;
 
       case JSOP_FUNCALL:
         return jsop_funcall(GET_ARGC(pc));
 
       case JSOP_FUNAPPLY:
         return jsop_funapply(GET_ARGC(pc));
@@ -5439,16 +5449,39 @@ IonBuilder::jsop_initprop(HandleProperty
     MStoreSlot *store = MStoreSlot::New(slots, slot, value);
     if (needsBarrier)
         store->setNeedsBarrier();
 
     current->add(store);
     return resumeAfter(store);
 }
 
+bool
+IonBuilder::jsop_initprop_getter_setter(PropertyName *name)
+{
+    MDefinition *value = current->pop();
+    MDefinition *obj = current->peek(-1);
+
+    MInitPropGetterSetter *init = MInitPropGetterSetter::New(obj, name, value);
+    current->add(init);
+    return resumeAfter(init);
+}
+
+bool
+IonBuilder::jsop_initelem_getter_setter()
+{
+    MDefinition *value = current->pop();
+    MDefinition *id = current->pop();
+    MDefinition *obj = current->peek(-1);
+
+    MInitElemGetterSetter *init = MInitElemGetterSetter::New(obj, id, value);
+    current->add(init);
+    return resumeAfter(init);
+}
+
 MBasicBlock *
 IonBuilder::addBlock(MBasicBlock *block, uint32_t loopDepth)
 {
     if (!block)
         return NULL;
     graph().addBlock(block);
     block->setLoopDepth(loopDepth);
     return block;
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -417,17 +417,19 @@ class IonBuilder : public MIRGenerator
     bool jsop_not();
     bool jsop_getprop(HandlePropertyName name);
     bool jsop_setprop(HandlePropertyName name);
     bool jsop_delprop(HandlePropertyName name);
     bool jsop_newarray(uint32_t count);
     bool jsop_newobject(HandleObject baseObj);
     bool jsop_initelem();
     bool jsop_initelem_array();
+    bool jsop_initelem_getter_setter();
     bool jsop_initprop(HandlePropertyName name);
+    bool jsop_initprop_getter_setter(PropertyName *name);
     bool jsop_regexp(RegExpObject *reobj);
     bool jsop_object(JSObject *obj);
     bool jsop_lambda(JSFunction *fun);
     bool jsop_this();
     bool jsop_typeof();
     bool jsop_toid();
     bool jsop_iter(uint8_t flags);
     bool jsop_iternext();
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -525,16 +525,39 @@ class LInitElem : public LCallInstructio
     const LAllocation *getObject() {
         return getOperand(0);
     }
     MInitElem *mir() const {
         return mir_->toInitElem();
     }
 };
 
+class LInitElemGetterSetter : public LCallInstructionHelper<0, 2 + BOX_PIECES, 0>
+{
+  public:
+    LIR_HEADER(InitElemGetterSetter)
+
+    LInitElemGetterSetter(const LAllocation &object, const LAllocation &value) {
+        setOperand(0, object);
+        setOperand(1, value);
+    }
+
+    static const size_t IdIndex = 2;
+
+    const LAllocation *object() {
+        return getOperand(0);
+    }
+    const LAllocation *value() {
+        return getOperand(1);
+    }
+    MInitElemGetterSetter *mir() const {
+        return mir_->toInitElemGetterSetter();
+    }
+};
+
 // Takes in an Object and a Value.
 class LInitProp : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
 {
   public:
     LIR_HEADER(InitProp)
 
     LInitProp(const LAllocation &object) {
         setOperand(0, object);
@@ -549,16 +572,38 @@ class LInitProp : public LCallInstructio
         return getOperand(1);
     }
 
     MInitProp *mir() const {
         return mir_->toInitProp();
     }
 };
 
+class LInitPropGetterSetter : public LCallInstructionHelper<0, 2, 0>
+{
+  public:
+    LIR_HEADER(InitPropGetterSetter)
+
+    LInitPropGetterSetter(const LAllocation &object, const LAllocation &value) {
+        setOperand(0, object);
+        setOperand(1, value);
+    }
+
+    const LAllocation *object() {
+        return getOperand(0);
+    }
+    const LAllocation *value() {
+        return getOperand(1);
+    }
+
+    MInitPropGetterSetter *mir() const {
+        return mir_->toInitPropGetterSetter();
+    }
+};
+
 class LCheckOverRecursed : public LInstructionHelper<0, 0, 0>
 {
   public:
     LIR_HEADER(CheckOverRecursed)
 
     LCheckOverRecursed()
     { }
 };
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -28,17 +28,19 @@
     _(NewDeclEnvObject)             \
     _(NewCallObject)                \
     _(NewStringObject)              \
     _(NewPar)                       \
     _(NewDenseArrayPar)             \
     _(NewCallObjectPar)             \
     _(AbortPar)                     \
     _(InitElem)                     \
+    _(InitElemGetterSetter)         \
     _(InitProp)                     \
+    _(InitPropGetterSetter)         \
     _(CheckOverRecursed)            \
     _(CheckOverRecursedPar)         \
     _(DefVar)                       \
     _(DefFun)                       \
     _(CallKnown)                    \
     _(CallGeneric)                  \
     _(CallNative)                   \
     _(ApplyArgsGeneric)             \
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -248,26 +248,45 @@ LIRGenerator::visitInitElem(MInitElem *i
         return false;
     if (!useBoxAtStart(lir, LInitElem::ValueIndex, ins->getValue()))
         return false;
 
     return add(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
+LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter *ins)
+{
+    LInitElemGetterSetter *lir = new LInitElemGetterSetter(useRegisterAtStart(ins->object()),
+                                                           useRegisterAtStart(ins->value()));
+    if (!useBoxAtStart(lir, LInitElemGetterSetter::IdIndex, ins->idValue()))
+        return false;
+
+    return add(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
 LIRGenerator::visitInitProp(MInitProp *ins)
 {
     LInitProp *lir = new LInitProp(useRegisterAtStart(ins->getObject()));
     if (!useBoxAtStart(lir, LInitProp::ValueIndex, ins->getValue()))
         return false;
 
     return add(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
+LIRGenerator::visitInitPropGetterSetter(MInitPropGetterSetter *ins)
+{
+    LInitPropGetterSetter *lir = new LInitPropGetterSetter(useRegisterAtStart(ins->object()),
+                                                           useRegisterAtStart(ins->value()));
+    return add(lir, ins) && assignSafepoint(lir, ins);
+}
+
+bool
 LIRGenerator::visitPrepareCall(MPrepareCall *ins)
 {
     allocateArguments(ins->argc());
 
 #ifdef DEBUG
     if (!prepareCallStack_.append(ins))
         return false;
 #endif
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -89,17 +89,19 @@ class LIRGenerator : public LIRGenerator
     bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
     bool visitNewStringObject(MNewStringObject *ins);
     bool visitNewPar(MNewPar *ins);
     bool visitNewCallObjectPar(MNewCallObjectPar *ins);
     bool visitNewDenseArrayPar(MNewDenseArrayPar *ins);
     bool visitAbortPar(MAbortPar *ins);
     bool visitInitElem(MInitElem *ins);
+    bool visitInitElemGetterSetter(MInitElemGetterSetter *ins);
     bool visitInitProp(MInitProp *ins);
+    bool visitInitPropGetterSetter(MInitPropGetterSetter *ins);
     bool visitCheckOverRecursed(MCheckOverRecursed *ins);
     bool visitCheckOverRecursedPar(MCheckOverRecursedPar *ins);
     bool visitDefVar(MDefVar *ins);
     bool visitDefFun(MDefFun *ins);
     bool visitPrepareCall(MPrepareCall *ins);
     bool visitPassArg(MPassArg *arg);
     bool visitCreateThisWithTemplate(MCreateThisWithTemplate *ins);
     bool visitCreateThisWithProto(MCreateThisWithProto *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -676,16 +676,184 @@ class MUnaryInstruction : public MAryIns
     }
 
   public:
     MDefinition *input() const {
         return getOperand(0);
     }
 };
 
+class MBinaryInstruction : public MAryInstruction<2>
+{
+  protected:
+    MBinaryInstruction(MDefinition *left, MDefinition *right)
+    {
+        setOperand(0, left);
+        setOperand(1, right);
+    }
+
+  public:
+    MDefinition *lhs() const {
+        return getOperand(0);
+    }
+    MDefinition *rhs() const {
+        return getOperand(1);
+    }
+
+  protected:
+    HashNumber valueHash() const
+    {
+        MDefinition *lhs = getOperand(0);
+        MDefinition *rhs = getOperand(1);
+
+        return op() ^ lhs->valueNumber() ^ rhs->valueNumber();
+    }
+    void swapOperands() {
+        MDefinition *temp = getOperand(0);
+        replaceOperand(0, getOperand(1));
+        replaceOperand(1, temp);
+    }
+
+    bool congruentTo(MDefinition *const &ins) const
+    {
+        if (op() != ins->op())
+            return false;
+
+        if (type() != ins->type())
+            return false;
+
+        if (isEffectful() || ins->isEffectful())
+            return false;
+
+        MDefinition *left = getOperand(0);
+        MDefinition *right = getOperand(1);
+        MDefinition *tmp;
+
+        if (isCommutative() && left->valueNumber() > right->valueNumber()) {
+            tmp = right;
+            right = left;
+            left = tmp;
+        }
+
+        MBinaryInstruction *bi = static_cast<MBinaryInstruction *>(ins);
+        MDefinition *insLeft = bi->getOperand(0);
+        MDefinition *insRight = bi->getOperand(1);
+        if (isCommutative() && insLeft->valueNumber() > insRight->valueNumber()) {
+            tmp = insRight;
+            insRight = insLeft;
+            insLeft = tmp;
+        }
+
+        return (left->valueNumber() == insLeft->valueNumber()) &&
+               (right->valueNumber() == insRight->valueNumber());
+    }
+
+    // Return true if the operands to this instruction are both unsigned,
+    // in which case any wrapping operands were replaced with the underlying
+    // int32 operands.
+    bool tryUseUnsignedOperands();
+};
+
+class MTernaryInstruction : public MAryInstruction<3>
+{
+  protected:
+    MTernaryInstruction(MDefinition *first, MDefinition *second, MDefinition *third)
+    {
+        setOperand(0, first);
+        setOperand(1, second);
+        setOperand(2, third);
+    }
+
+  protected:
+    HashNumber valueHash() const
+    {
+        MDefinition *first = getOperand(0);
+        MDefinition *second = getOperand(1);
+        MDefinition *third = getOperand(2);
+
+        return op() ^ first->valueNumber() ^ second->valueNumber() ^ third->valueNumber();
+    }
+
+    bool congruentTo(MDefinition *const &ins) const
+    {
+        if (op() != ins->op())
+            return false;
+
+        if (type() != ins->type())
+            return false;
+
+        if (isEffectful() || ins->isEffectful())
+            return false;
+
+        MTernaryInstruction *ter = static_cast<MTernaryInstruction *>(ins);
+        MDefinition *first = getOperand(0);
+        MDefinition *second = getOperand(1);
+        MDefinition *third = getOperand(2);
+        MDefinition *insFirst = ter->getOperand(0);
+        MDefinition *insSecond = ter->getOperand(1);
+        MDefinition *insThird = ter->getOperand(2);
+
+        return first->valueNumber() == insFirst->valueNumber() &&
+               second->valueNumber() == insSecond->valueNumber() &&
+               third->valueNumber() == insThird->valueNumber();
+    }
+};
+
+class MQuaternaryInstruction : public MAryInstruction<4>
+{
+  protected:
+    MQuaternaryInstruction(MDefinition *first, MDefinition *second,
+                           MDefinition *third, MDefinition *fourth)
+    {
+        setOperand(0, first);
+        setOperand(1, second);
+        setOperand(2, third);
+        setOperand(3, fourth);
+    }
+
+  protected:
+    HashNumber valueHash() const
+    {
+        MDefinition *first = getOperand(0);
+        MDefinition *second = getOperand(1);
+        MDefinition *third = getOperand(2);
+        MDefinition *fourth = getOperand(3);
+
+        return op() ^ first->valueNumber() ^ second->valueNumber() ^
+                      third->valueNumber() ^ fourth->valueNumber();
+    }
+
+    bool congruentTo(MDefinition *const &ins) const
+    {
+        if (op() != ins->op())
+            return false;
+
+        if (type() != ins->type())
+            return false;
+
+        if (isEffectful() || ins->isEffectful())
+            return false;
+
+        MQuaternaryInstruction *qua = static_cast<MQuaternaryInstruction *>(ins);
+        MDefinition *first = getOperand(0);
+        MDefinition *second = getOperand(1);
+        MDefinition *third = getOperand(2);
+        MDefinition *fourth = getOperand(3);
+        MDefinition *insFirst = qua->getOperand(0);
+        MDefinition *insSecond = qua->getOperand(1);
+        MDefinition *insThird = qua->getOperand(2);
+        MDefinition *insFourth = qua->getOperand(3);
+
+        return first->valueNumber() == insFirst->valueNumber() &&
+               second->valueNumber() == insSecond->valueNumber() &&
+               third->valueNumber() == insThird->valueNumber() &&
+               fourth->valueNumber() == insFourth->valueNumber();
+    }
+};
+
 // Generates an LSnapshot without further effect.
 class MStart : public MNullaryInstruction
 {
   public:
     enum StartType {
         StartType_Default,
         StartType_Osr
     };
@@ -1322,16 +1490,48 @@ class MInitProp
     TypePolicy *typePolicy() {
         return this;
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
+class MInitPropGetterSetter
+  : public MBinaryInstruction,
+    public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
+{
+    CompilerRootPropertyName name_;
+
+    MInitPropGetterSetter(MDefinition *obj, PropertyName *name, MDefinition *value)
+      : MBinaryInstruction(obj, value),
+        name_(name)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(InitPropGetterSetter)
+
+    static MInitPropGetterSetter *New(MDefinition *obj, PropertyName *name, MDefinition *value) {
+        return new MInitPropGetterSetter(obj, name, value);
+    }
+
+    MDefinition *object() const {
+        return getOperand(0);
+    }
+    MDefinition *value() const {
+        return getOperand(1);
+    }
+    PropertyName *name() const {
+        return name_;
+    }
+    TypePolicy *typePolicy() {
+        return this;
+    }
+};
+
 class MInitElem
   : public MAryInstruction<3>,
     public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, BoxPolicy<2> >
 {
     MInitElem(MDefinition *obj, MDefinition *id, MDefinition *value)
     {
         setOperand(0, obj);
         setOperand(1, id);
@@ -1358,16 +1558,45 @@ class MInitElem
     TypePolicy *typePolicy() {
         return this;
     }
     bool possiblyCalls() const {
         return true;
     }
 };
 
+class MInitElemGetterSetter
+  : public MTernaryInstruction,
+    public Mix3Policy<ObjectPolicy<0>, BoxPolicy<1>, ObjectPolicy<2> >
+{
+    MInitElemGetterSetter(MDefinition *obj, MDefinition *id, MDefinition *value)
+      : MTernaryInstruction(obj, id, value)
+    { }
+
+  public:
+    INSTRUCTION_HEADER(InitElemGetterSetter)
+
+    static MInitElemGetterSetter *New(MDefinition *obj, MDefinition *id, MDefinition *value) {
+        return new MInitElemGetterSetter(obj, id, value);
+    }
+
+    MDefinition *object() const {
+        return getOperand(0);
+    }
+    MDefinition *idValue() const {
+        return getOperand(1);
+    }
+    MDefinition *value() const {
+        return getOperand(2);
+    }
+    TypePolicy *typePolicy() {
+        return this;
+    }
+};
+
 // Designates the start of call frame construction.
 // Generates code to adjust the stack pointer for the argument vector.
 // Argc is inferred by checking the use chain during lowering.
 class MPrepareCall : public MNullaryInstruction
 {
   public:
     INSTRUCTION_HEADER(PrepareCall)
 
@@ -1680,184 +1909,16 @@ class MCallDirectEval
     bool possiblyCalls() const {
         return true;
     }
 
   private:
     jsbytecode *pc_;
 };
 
-class MBinaryInstruction : public MAryInstruction<2>
-{
-  protected:
-    MBinaryInstruction(MDefinition *left, MDefinition *right)
-    {
-        setOperand(0, left);
-        setOperand(1, right);
-    }
-
-  public:
-    MDefinition *lhs() const {
-        return getOperand(0);
-    }
-    MDefinition *rhs() const {
-        return getOperand(1);
-    }
-
-  protected:
-    HashNumber valueHash() const
-    {
-        MDefinition *lhs = getOperand(0);
-        MDefinition *rhs = getOperand(1);
-
-        return op() ^ lhs->valueNumber() ^ rhs->valueNumber();
-    }
-    void swapOperands() {
-        MDefinition *temp = getOperand(0);
-        replaceOperand(0, getOperand(1));
-        replaceOperand(1, temp);
-    }
-
-    bool congruentTo(MDefinition *const &ins) const
-    {
-        if (op() != ins->op())
-            return false;
-
-        if (type() != ins->type())
-            return false;
-
-        if (isEffectful() || ins->isEffectful())
-            return false;
-
-        MDefinition *left = getOperand(0);
-        MDefinition *right = getOperand(1);
-        MDefinition *tmp;
-
-        if (isCommutative() && left->valueNumber() > right->valueNumber()) {
-            tmp = right;
-            right = left;
-            left = tmp;
-        }
-
-        MBinaryInstruction *bi = static_cast<MBinaryInstruction *>(ins);
-        MDefinition *insLeft = bi->getOperand(0);
-        MDefinition *insRight = bi->getOperand(1);
-        if (isCommutative() && insLeft->valueNumber() > insRight->valueNumber()) {
-            tmp = insRight;
-            insRight = insLeft;
-            insLeft = tmp;
-        }
-
-        return (left->valueNumber() == insLeft->valueNumber()) &&
-               (right->valueNumber() == insRight->valueNumber());
-    }
-
-    // Return true if the operands to this instruction are both unsigned,
-    // in which case any wrapping operands were replaced with the underlying
-    // int32 operands.
-    bool tryUseUnsignedOperands();
-};
-
-class MTernaryInstruction : public MAryInstruction<3>
-{
-  protected:
-    MTernaryInstruction(MDefinition *first, MDefinition *second, MDefinition *third)
-    {
-        setOperand(0, first);
-        setOperand(1, second);
-        setOperand(2, third);
-    }
-
-  protected:
-    HashNumber valueHash() const
-    {
-        MDefinition *first = getOperand(0);
-        MDefinition *second = getOperand(1);
-        MDefinition *third = getOperand(2);
-
-        return op() ^ first->valueNumber() ^ second->valueNumber() ^ third->valueNumber();
-    }
-
-    bool congruentTo(MDefinition *const &ins) const
-    {
-        if (op() != ins->op())
-            return false;
-
-        if (type() != ins->type())
-            return false;
-
-        if (isEffectful() || ins->isEffectful())
-            return false;
-
-        MTernaryInstruction *ter = static_cast<MTernaryInstruction *>(ins);
-        MDefinition *first = getOperand(0);
-        MDefinition *second = getOperand(1);
-        MDefinition *third = getOperand(2);
-        MDefinition *insFirst = ter->getOperand(0);
-        MDefinition *insSecond = ter->getOperand(1);
-        MDefinition *insThird = ter->getOperand(2);
-
-        return first->valueNumber() == insFirst->valueNumber() &&
-               second->valueNumber() == insSecond->valueNumber() &&
-               third->valueNumber() == insThird->valueNumber();
-    }
-};
-
-class MQuaternaryInstruction : public MAryInstruction<4>
-{
-  protected:
-    MQuaternaryInstruction(MDefinition *first, MDefinition *second,
-                           MDefinition *third, MDefinition *fourth)
-    {
-        setOperand(0, first);
-        setOperand(1, second);
-        setOperand(2, third);
-        setOperand(3, fourth);
-    }
-
-  protected:
-    HashNumber valueHash() const
-    {
-        MDefinition *first = getOperand(0);
-        MDefinition *second = getOperand(1);
-        MDefinition *third = getOperand(2);
-        MDefinition *fourth = getOperand(3);
-
-        return op() ^ first->valueNumber() ^ second->valueNumber() ^
-                      third->valueNumber() ^ fourth->valueNumber();
-    }
-
-    bool congruentTo(MDefinition *const &ins) const
-    {
-        if (op() != ins->op())
-            return false;
-
-        if (type() != ins->type())
-            return false;
-
-        if (isEffectful() || ins->isEffectful())
-            return false;
-
-        MQuaternaryInstruction *qua = static_cast<MQuaternaryInstruction *>(ins);
-        MDefinition *first = getOperand(0);
-        MDefinition *second = getOperand(1);
-        MDefinition *third = getOperand(2);
-        MDefinition *fourth = getOperand(3);
-        MDefinition *insFirst = qua->getOperand(0);
-        MDefinition *insSecond = qua->getOperand(1);
-        MDefinition *insThird = qua->getOperand(2);
-        MDefinition *insFourth = qua->getOperand(3);
-
-        return first->valueNumber() == insFirst->valueNumber() &&
-               second->valueNumber() == insSecond->valueNumber() &&
-               third->valueNumber() == insThird->valueNumber() &&
-               fourth->valueNumber() == insFourth->valueNumber();
-    }
-};
-
 class MCompare
   : public MBinaryInstruction,
     public ComparePolicy
 {
   public:
     enum CompareType {
 
         // Anything compared to Undefined
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -81,17 +81,19 @@ namespace ion {
     _(NewSlots)                                                             \
     _(NewParallelArray)                                                     \
     _(NewArray)                                                             \
     _(NewObject)                                                            \
     _(NewDeclEnvObject)                                                     \
     _(NewCallObject)                                                        \
     _(NewStringObject)                                                      \
     _(InitElem)                                                             \
+    _(InitElemGetterSetter)                                                 \
     _(InitProp)                                                             \
+    _(InitPropGetterSetter)                                                 \
     _(Start)                                                                \
     _(OsrEntry)                                                             \
     _(Nop)                                                                  \
     _(RegExp)                                                               \
     _(RegExpTest)                                                           \
     _(Lambda)                                                               \
     _(ImplicitThis)                                                         \
     _(Slots)                                                                \
--- a/js/src/ion/ParallelSafetyAnalysis.cpp
+++ b/js/src/ion/ParallelSafetyAnalysis.cpp
@@ -170,17 +170,19 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(MaybeToDoubleElement)
     CUSTOM_OP(ToString)
     SAFE_OP(NewSlots)
     CUSTOM_OP(NewArray)
     CUSTOM_OP(NewObject)
     CUSTOM_OP(NewCallObject)
     CUSTOM_OP(NewParallelArray)
     UNSAFE_OP(InitElem)
+    UNSAFE_OP(InitElemGetterSetter)
     UNSAFE_OP(InitProp)
+    UNSAFE_OP(InitPropGetterSetter)
     SAFE_OP(Start)
     UNSAFE_OP(OsrEntry)
     SAFE_OP(Nop)
     UNSAFE_OP(RegExp)
     CUSTOM_OP(Lambda)
     UNSAFE_OP(ImplicitThis)
     SAFE_OP(Slots)
     SAFE_OP(Elements)
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -2910,41 +2910,41 @@ BEGIN_CASE(JSOP_CALLEE)
     PUSH_COPY(regs.fp()->calleev());
 END_CASE(JSOP_CALLEE)
 
 BEGIN_CASE(JSOP_INITPROP_GETTER)
 BEGIN_CASE(JSOP_INITPROP_SETTER)
 {
     RootedObject &obj = rootObject0;
     RootedPropertyName &name = rootName0;
-    RootedValue &val = rootValue0;
+    RootedObject &val = rootObject1;
 
     JS_ASSERT(regs.stackDepth() >= 2);
     obj = &regs.sp[-2].toObject();
     name = script->getName(regs.pc);
-    val = regs.sp[-1];
+    val = &regs.sp[-1].toObject();
 
     if (!InitGetterSetterOperation(cx, regs.pc, obj, name, val))
         goto error;
 
     regs.sp--;
 }
 END_CASE(JSOP_INITPROP_GETTER)
 
 BEGIN_CASE(JSOP_INITELEM_GETTER)
 BEGIN_CASE(JSOP_INITELEM_SETTER)
 {
     RootedObject &obj = rootObject0;
     RootedValue &idval = rootValue0;
-    RootedValue &val = rootValue1;
+    RootedObject &val = rootObject1;
 
     JS_ASSERT(regs.stackDepth() >= 3);
     obj = &regs.sp[-3].toObject();
     idval = regs.sp[-2];
-    val = regs.sp[-1];
+    val = &regs.sp[-1].toObject();
 
     if (!InitGetterSetterOperation(cx, regs.pc, obj, idval, val))
         goto error;
 
     regs.sp -= 2;
 }
 END_CASE(JSOP_INITELEM_GETTER)
 
@@ -3855,19 +3855,19 @@ js::RunOnceScriptPrologue(JSContext *cx,
         return false;
 
     types::MarkTypeObjectFlags(cx, script->function(), types::OBJECT_FLAG_RUNONCE_INVALIDATED);
     return true;
 }
 
 bool
 js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleId id,
-                              HandleValue val)
+                              HandleObject val)
 {
-    JS_ASSERT(js_IsCallable(val));
+    JS_ASSERT(val->isCallable());
 
     /*
      * Getters and setters are just like watchpoints from an access control
      * point of view.
      */
     RootedValue scratch(cx, UndefinedValue());
     unsigned attrs = 0;
     if (!CheckAccess(cx, obj, id, JSACC_WATCH, &scratch, &attrs))
@@ -3875,40 +3875,40 @@ js::InitGetterSetterOperation(JSContext 
 
     PropertyOp getter;
     StrictPropertyOp setter;
     attrs = JSPROP_ENUMERATE | JSPROP_SHARED;
 
     JSOp op = JSOp(*pc);
 
     if (op == JSOP_INITPROP_GETTER || op == JSOP_INITELEM_GETTER) {
-        getter = CastAsPropertyOp(&val.toObject());
+        getter = CastAsPropertyOp(val);
         setter = JS_StrictPropertyStub;
         attrs |= JSPROP_GETTER;
     } else {
         JS_ASSERT(op == JSOP_INITPROP_SETTER || op == JSOP_INITELEM_SETTER);
         getter = JS_PropertyStub;
-        setter = CastAsStrictPropertyOp(&val.toObject());
+        setter = CastAsStrictPropertyOp(val);
         attrs |= JSPROP_SETTER;
     }
 
     scratch.setUndefined();
     return JSObject::defineGeneric(cx, obj, id, scratch, getter, setter, attrs);
 }
 
 bool
 js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj,
-                              HandlePropertyName name, HandleValue val)
+                              HandlePropertyName name, HandleObject val)
 {
     RootedId id(cx, NameToId(name));
     return InitGetterSetterOperation(cx, pc, obj, id, val);
 }
 
 bool
 js::InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
-                              HandleValue val)
+                              HandleObject val)
 {
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, idval, &id))
         return false;
 
     return InitGetterSetterOperation(cx, pc, obj, id, val);
 }
--- a/js/src/vm/Interpreter.h
+++ b/js/src/vm/Interpreter.h
@@ -494,25 +494,25 @@ IteratorMore(JSContext *cx, JSObject *it
 bool
 IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval);
 
 bool
 RunOnceScriptPrologue(JSContext *cx, HandleScript script);
 
 bool
 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleId id,
-                          HandleValue val);
+                          HandleObject val);
 
 bool
 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandlePropertyName name,
-                          HandleValue val);
+                          HandleObject val);
 
 bool
 InitGetterSetterOperation(JSContext *cx, jsbytecode *pc, HandleObject obj, HandleValue idval,
-                          HandleValue val);
+                          HandleObject val);
 
 inline bool
 SetConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName name, HandleValue rval)
 {
     return JSObject::defineProperty(cx, varobj, name, rval,
                                     JS_PropertyStub, JS_StrictPropertyStub,
                                     JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
 }