Compile JSOP_GETFCSLOT and JSOP_CALLFCSLOT (bug 725970, r=dvander)
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 11 Feb 2012 13:20:46 +0100
changeset 112690 dc65aacb0f4d455469ef6ddf7fa4d550b54d9cdd
parent 112689 caa3dbc75fa73f1ec96b9b7aeb02ec1332391c5a
child 112691 73866db4e189cb5ca4c232262be99214e087e448
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)
reviewersdvander
bugs725970
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_GETFCSLOT and JSOP_CALLFCSLOT (bug 725970, r=dvander)
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/LIR.h
js/src/ion/LOpcodes.h
js/src/ion/LinearScan.cpp
js/src/ion/LinearScan.h
js/src/ion/Lowering.cpp
js/src/ion/Lowering.h
js/src/ion/MIR.h
js/src/ion/MOpcodes.h
js/src/ion/TypeOracle.h
js/src/ion/TypePolicy.cpp
js/src/ion/arm/MacroAssembler-arm.cpp
js/src/ion/arm/MacroAssembler-arm.h
js/src/ion/x64/MacroAssembler-x64.h
js/src/ion/x86/MacroAssembler-x86.h
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -419,16 +419,27 @@ bool
 CodeGenerator::visitElements(LElements *lir)
 {
     Address elements(ToRegister(lir->object()), JSObject::offsetOfElements());
     masm.loadPtr(elements, ToRegister(lir->output()));
     return true;
 }
 
 bool
+CodeGenerator::visitFlatClosureUpvars(LFlatClosureUpvars *lir)
+{
+    Register callee = ToRegister(lir->callee());
+    Register output = ToRegister(lir->output());
+
+    Address upvars(callee, JSFunction::getFlatClosureUpvarsOffset());
+    masm.loadPrivate(upvars, output);
+    return true;
+}
+
+bool
 CodeGenerator::visitFunctionEnvironment(LFunctionEnvironment *lir)
 {
     Address environment(ToRegister(lir->function()), JSFunction::offsetOfEnvironment());
     masm.loadPtr(environment, ToRegister(lir->output()));
     return true;
 }
 
 bool
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -91,16 +91,17 @@ class CodeGenerator : public CodeGenerat
     bool visitTruncateDToInt32(LTruncateDToInt32 *lir);
     bool visitIntToString(LIntToString *lir);
     bool visitInteger(LInteger *lir);
     bool visitRegExp(LRegExp *lir);
     bool visitPointer(LPointer *lir);
     bool visitSlots(LSlots *lir);
     bool visitStoreSlotV(LStoreSlotV *store);
     bool visitElements(LElements *lir);
+    bool visitFlatClosureUpvars(LFlatClosureUpvars *lir);
     bool visitTypeBarrier(LTypeBarrier *lir);
     bool visitCallNative(LCallNative *lir);
     bool visitCallGeneric(LCallGeneric *lir);
     bool visitDoubleToInt32(LDoubleToInt32 *lir);
     bool visitNewArray(LNewArray *builder);
     bool visitArrayLength(LArrayLength *lir);
     bool visitStringLength(LStringLength *lir);
     bool visitInitializedLength(LInitializedLength *lir);
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -728,16 +728,20 @@ IonBuilder::inspectOpcode(JSOp op)
         return pushConstant(ObjectValue(*script->global()));
 
       case JSOP_SETGNAME:
         return jsop_setgname(info().getAtom(pc));
 
       case JSOP_NAME:
         return jsop_getname(info().getAtom(pc));
 
+      case JSOP_GETFCSLOT:
+      case JSOP_CALLFCSLOT:
+        return jsop_getfcslot(GET_UINT16(pc));
+
       case JSOP_DUP:
         current->pushSlot(current->stackDepth() - 1);
         return true;
 
       case JSOP_DUP2:
         return jsop_dup2();
 
       case JSOP_SWAP:
@@ -3132,16 +3136,34 @@ IonBuilder::jsop_getname(JSAtom *atom)
         return false;
 
     types::TypeSet *barrier = oracle->propertyReadBarrier(script, pc);
     types::TypeSet *types = oracle->propertyRead(script, pc);
     return pushTypeBarrier(ins, types, barrier);
 }
 
 bool
+IonBuilder::jsop_getfcslot(uint16 index)
+{
+    MCallee *callee = MCallee::New();
+    current->add(callee);
+
+    MFlatClosureUpvars *upvars = MFlatClosureUpvars::New(callee);
+    current->add(upvars);
+
+    MLoadSlot *upvar = MLoadSlot::New(upvars, index);
+    current->add(upvar);
+    current->push(upvar);
+
+    types::TypeSet *barrier = oracle->propertyReadBarrier(script, pc);
+    types::TypeSet *types = oracle->propertyRead(script, pc);
+    return pushTypeBarrier(upvar, types, barrier);
+}
+
+bool
 IonBuilder::jsop_getelem()
 {
     if (oracle->elementReadIsDense(script, pc))
         return jsop_getelem_dense();
 
     MDefinition *rhs = current->pop();
     MDefinition *lhs = current->pop();
 
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -292,16 +292,17 @@ class IonBuilder : public MIRGenerator
     bool jsop_loophead(jsbytecode *pc);
     bool jsop_incslot(JSOp op, uint32 slot);
     bool jsop_localinc(JSOp op);
     bool jsop_arginc(JSOp op);
     bool jsop_compare(JSOp op);
     bool jsop_getgname(JSAtom *atom);
     bool jsop_setgname(JSAtom *atom);
     bool jsop_getname(JSAtom *atom);
+    bool jsop_getfcslot(uint16 index);
     bool jsop_getelem();
     bool jsop_getelem_dense();
     bool jsop_setelem();
     bool jsop_setelem_dense();
     bool jsop_length();
     bool jsop_length_fastPath();
     bool jsop_getprop(JSAtom *atom);
     bool jsop_setprop(JSAtom *atom);
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -1090,16 +1090,33 @@ class LElements : public LInstructionHel
     const LAllocation *object() {
         return getOperand(0);
     }
     const LDefinition *output() {
         return getDef(0);
     }
 };
 
+class LFlatClosureUpvars : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(FlatClosureUpvars);
+
+    LFlatClosureUpvars(const LAllocation &callee) {
+        setOperand(0, callee);
+    }
+
+    const LAllocation *callee() {
+        return getOperand(0);
+    }
+    const LDefinition *output() {
+        return getDef(0);
+    }
+};
+
 // Load a dense array's initialized length from an elements vector.
 class LInitializedLength : public LInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(InitializedLength);
 
     LInitializedLength(const LAllocation &elements) {
         setOperand(0, elements);
--- a/js/src/ion/LIR.h
+++ b/js/src/ion/LIR.h
@@ -554,16 +554,17 @@ class LDefinition
           case MIRType_Double:
             return LDefinition::DOUBLE;
 #if defined(JS_PUNBOX64)
           case MIRType_Value:
             return LDefinition::BOX;
 #endif
           case MIRType_Slots:
           case MIRType_Elements:
+          case MIRType_UpvarSlots:
             // When we begin allocating slots vectors from the GC, this will
             // need to change to ::OBJECT.
             return LDefinition::GENERAL;
           case MIRType_StackFrame:
             return LDefinition::GENERAL;
           default:
             JS_NOT_REACHED("unexpected type");
             return LDefinition::GENERAL;
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -93,16 +93,17 @@
     _(Start)                        \
     _(OsrEntry)                     \
     _(OsrValue)                     \
     _(OsrScopeChain)                \
     _(RegExp)                       \
     _(ImplicitThis)                 \
     _(Slots)                        \
     _(Elements)                     \
+    _(FlatClosureUpvars)            \
     _(LoadSlotV)                    \
     _(LoadSlotT)                    \
     _(StoreSlotV)                   \
     _(StoreSlotT)                   \
     _(GuardShape)                   \
     _(GuardClass)                   \
     _(WriteBarrierV)                \
     _(WriteBarrierT)                \
--- a/js/src/ion/LinearScan.cpp
+++ b/js/src/ion/LinearScan.cpp
@@ -1523,21 +1523,21 @@ LinearScanAllocator::freeAllocation(Live
     VirtualRegister *other = otherHalfOfNunbox(mine);
     if (other->finished()) {
         if (!mine->canonicalSpill() && !other->canonicalSpill())
             return;
 
         JS_ASSERT_IF(mine->canonicalSpill() && other->canonicalSpill(),
                      mine->canonicalSpill()->isStackSlot() == other->canonicalSpill()->isStackSlot());
 
-        VirtualRegister *candidate = alloc ? mine : other;
+        VirtualRegister *candidate = mine->canonicalSpill() ? mine : other;
         if (!candidate->canonicalSpill()->isStackSlot())
             return;
 
-        finishedDoubleSlots_.append(interval);
+        finishedDoubleSlots_.append(candidate->lastInterval());
     }
 #endif
 }
 
 void
 LinearScanAllocator::finishInterval(LiveInterval *interval)
 {
     LAllocation *alloc = interval->getAllocation();
--- a/js/src/ion/LinearScan.h
+++ b/js/src/ion/LinearScan.h
@@ -420,22 +420,26 @@ class VirtualRegister
         return def_;
     }
     LDefinition::Type type() const {
         return def()->type();
     }
     bool isTemp() const {
         return isTemp_;
     }
-    size_t numIntervals() {
+    size_t numIntervals() const {
         return intervals_.length();
     }
-    LiveInterval *getInterval(size_t i) {
+    LiveInterval *getInterval(size_t i) const {
         return intervals_[i];
     }
+    LiveInterval *lastInterval() const {
+        JS_ASSERT(numIntervals() > 0);
+        return getInterval(numIntervals() - 1);
+    }
     bool addInterval(LiveInterval *interval) {
         JS_ASSERT(interval->numRanges());
 
         // Preserve ascending order for faster lookups.
         LiveInterval **found = NULL;
         LiveInterval **i;
         for (i = intervals_.begin(); i != intervals_.end(); i++) {
             if (!found && interval->start() < (*i)->start())
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -801,16 +801,22 @@ LIRGenerator::visitSlots(MSlots *ins)
 
 bool
 LIRGenerator::visitElements(MElements *ins)
 {
     return define(new LElements(useRegister(ins->object())), ins);
 }
 
 bool
+LIRGenerator::visitFlatClosureUpvars(MFlatClosureUpvars *ins)
+{
+    return define(new LFlatClosureUpvars(useRegister(ins->callee())), ins);
+}
+
+bool
 LIRGenerator::visitLoadSlot(MLoadSlot *ins)
 {
     switch (ins->type()) {
       case MIRType_Value:
         return defineBox(new LLoadSlotV(useRegister(ins->slots())), ins);
 
       case MIRType_Undefined:
       case MIRType_Null:
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -145,16 +145,17 @@ class LIRGenerator : public LIRGenerator
     bool visitToInt32(MToInt32 *convert);
     bool visitTruncateToInt32(MTruncateToInt32 *truncate);
     bool visitToString(MToString *convert);
     bool visitCopy(MCopy *ins);
     bool visitRegExp(MRegExp *ins);
     bool visitImplicitThis(MImplicitThis *ins);
     bool visitSlots(MSlots *ins);
     bool visitElements(MElements *ins);
+    bool visitFlatClosureUpvars(MFlatClosureUpvars *ins);
     bool visitLoadSlot(MLoadSlot *ins);
     bool visitFunctionEnvironment(MFunctionEnvironment *ins);
     bool visitStoreSlot(MStoreSlot *ins);
     bool visitTypeBarrier(MTypeBarrier *ins);
     bool visitArrayLength(MArrayLength *ins);
     bool visitInitializedLength(MInitializedLength *ins);
     bool visitBoundsCheck(MBoundsCheck *ins);
     bool visitBoundsCheckLower(MBoundsCheckLower *ins);
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -676,19 +676,27 @@ class MCallee : public MNullaryInstructi
   public:
     MCallee()
     {
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(Callee);
+
+    bool congruentTo(MDefinition * const &ins) const {
+        return congruentIfOperandsEqual(ins);
+    }
+
     static MCallee *New() {
         return new MCallee();
     }
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
 };
 
 class MControlInstruction : public MInstruction
 {
   public:
     MControlInstruction()
     { }
 
@@ -2241,16 +2249,45 @@ class MElements
     bool congruentTo(MDefinition *const &ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
+class MFlatClosureUpvars
+  : public MUnaryInstruction
+{
+    MFlatClosureUpvars(MDefinition *callee)
+      : MUnaryInstruction(callee)
+    {
+        JS_ASSERT(callee->type() == MIRType_Object);
+        setResultType(MIRType_UpvarSlots);
+        setMovable();
+    }
+
+  public:
+    INSTRUCTION_HEADER(FlatClosureUpvars);
+
+    static MFlatClosureUpvars *New(MDefinition *callee) {
+        return new MFlatClosureUpvars(callee);
+    }
+
+    MDefinition *callee() const {
+        return getOperand(0);
+    }
+    bool congruentTo(MDefinition * const &ins) const {
+        return congruentIfOperandsEqual(ins);
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::Load(AliasSet::ObjectFields);
+    }
+};
+
 // Load a dense array's initialized length from an elements vector.
 class MInitializedLength
   : public MUnaryInstruction
 {
     MInitializedLength(MDefinition *elements)
       : MUnaryInstruction(elements)
     {
         setResultType(MIRType_Int32);
@@ -2805,17 +2842,17 @@ class MLoadSlot
     uint32 slot_;
 
     MLoadSlot(MDefinition *slots, uint32 slot)
       : MUnaryInstruction(slots),
         slot_(slot)
     {
         setResultType(MIRType_Value);
         setMovable();
-        JS_ASSERT(slots->type() == MIRType_Slots);
+        JS_ASSERT(slots->type() == MIRType_Slots || slots->type() == MIRType_UpvarSlots);
     }
 
   public:
     INSTRUCTION_HEADER(LoadSlot);
 
     static MLoadSlot *New(MDefinition *slots, uint32 slot) {
         return new MLoadSlot(slots, slot);
     }
@@ -2832,17 +2869,21 @@ class MLoadSlot
     bool congruentTo(MDefinition * const &ins) const {
         if (!ins->isLoadSlot())
             return false;
         if (slot() != ins->toLoadSlot()->slot())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
-        return AliasSet::Load(AliasSet::Slot);
+        if (slots()->type() == MIRType_Slots)
+            return AliasSet::Load(AliasSet::Slot);
+
+        JS_ASSERT(slots()->type() == MIRType_UpvarSlots);
+        return AliasSet::None();
     }
 };
 
 // Inline call to access a function's environment (scope chain).
 class MFunctionEnvironment
   : public MUnaryInstruction,
     public ObjectPolicy
 {
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -112,16 +112,17 @@ namespace ion {
     _(LoadFixedSlot)                                                        \
     _(StoreFixedSlot)                                                       \
     _(CallGetProperty)                                                      \
     _(CallGetName)                                                          \
     _(CallGetNameTypeOf)                                                    \
     _(CallGetElement)                                                       \
     _(CallSetElement)                                                       \
     _(CallSetProperty)                                                      \
+    _(FlatClosureUpvars)                                                    \
     _(SetPropertyCache)                                                     \
     _(IteratorStart)                                                        \
     _(IteratorNext)                                                         \
     _(IteratorMore)                                                         \
     _(IteratorEnd)                                                          \
     _(StringLength)                                                         \
     _(Round)
 
--- a/js/src/ion/TypeOracle.h
+++ b/js/src/ion/TypeOracle.h
@@ -61,16 +61,17 @@ enum MIRType
     MIRType_String,
     MIRType_Object,
     MIRType_Magic,
     MIRType_Value,
     MIRType_Any,        // Any type.
     MIRType_None,       // Invalid, used as a placeholder.
     MIRType_Slots,      // A slots vector
     MIRType_Elements,   // An elements vector
+    MIRType_UpvarSlots, // Flat closure upvar slots
     MIRType_StackFrame  // StackFrame pointer for OSR.
 };
 
 class TypeOracle
 {
   public:
     struct UnaryTypes {
         types::TypeSet *inTypes;
@@ -319,16 +320,18 @@ StringFromMIRType(MIRType type)
     case MIRType_Any:
       return "Any";
     case MIRType_None:
       return "None";
     case MIRType_Slots:
       return "Slots";
     case MIRType_Elements:
       return "Elements";
+    case MIRType_UpvarSlots:
+      return "UpvarSlots";
     case MIRType_StackFrame:
       return "StackFrame";
     default:
       JS_NOT_REACHED("Unknown MIRType.");
       return "";
   }
 }
 
--- a/js/src/ion/TypePolicy.cpp
+++ b/js/src/ion/TypePolicy.cpp
@@ -201,17 +201,17 @@ TableSwitchPolicy::adjustInputs(MInstruc
     return true;
 }
 
 bool
 ObjectPolicy::adjustInputs(MInstruction *def)
 {
     MDefinition *in = def->getOperand(0);
     if (in->type() == MIRType_Object || in->type() == MIRType_Slots ||
-        in->type() == MIRType_Elements)
+        in->type() == MIRType_Elements || in->type() == MIRType_UpvarSlots)
     {
         return true;
     }
 
     // Once we have C++ calls, we can change this to insert a PrimitiveToObject
     // call.
     if (in->type() != MIRType_Value)
         in = boxAt(def, in);
--- a/js/src/ion/arm/MacroAssembler-arm.cpp
+++ b/js/src/ion/arm/MacroAssembler-arm.cpp
@@ -1175,16 +1175,29 @@ MacroAssemblerARMCompat::loadPtr(const A
 }
 void
 MacroAssemblerARMCompat::loadPtr(const ImmWord &imm, const Register &dest)
 {
     movePtr(imm, ScratchRegister);
     loadPtr(Address(ScratchRegister, 0x0), dest);
 }
 
+Operand payloadOf(const Address &address) {
+    return Operand(address.base, address.offset);
+}
+Operand tagOf(const Address &address) {
+    return Operand(address.base, address.offset + 4);
+}
+
+void
+MacroAssemblerARMCompat::loadPrivate(const Address &address, const Register &dest)
+{
+    ma_ldr(payloadOf(address), dest);
+}
+
 void
 MacroAssemblerARMCompat::store32(Register src, const ImmWord &imm)
 {
     storePtr(src, imm);
 }
 
 void
 MacroAssemblerARMCompat::store32(Register src, const Address &address)
@@ -1280,23 +1293,16 @@ Operand ToPayload(Operand base) {
     return Operand(Register::FromCode(base.base()),
                    base.disp());
 }
 Operand ToType(Operand base) {
     return Operand(Register::FromCode(base.base()),
                    base.disp() + sizeof(void *));
 }
 
-Operand payloadOf(const Address &address) {
-    return Operand(address.base, address.offset);
-}
-Operand tagOf(const Address &address) {
-    return Operand(address.base, address.offset + 4);
-}
-
 Assembler::Condition
 MacroAssemblerARMCompat::testInt32(Assembler::Condition cond, const ValueOperand &value)
 {
     JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
     ma_cmp(value.typeReg(), ImmType(JSVAL_TYPE_INT32));
     return cond;
 }
 
--- a/js/src/ion/arm/MacroAssembler-arm.h
+++ b/js/src/ion/arm/MacroAssembler-arm.h
@@ -731,16 +731,17 @@ class MacroAssemblerARMCompat : public M
     void movePtr(const ImmGCPtr &imm, const Register &dest);
     void movePtr(const Address &src, const Register &dest);
 
     void load16(const Address &address, const Register &dest);
     void load32(const Address &address, const Register &dest);
     void load32(const ImmWord &imm, const Register &dest);
     void loadPtr(const Address &address, const Register &dest);
     void loadPtr(const ImmWord &imm, const Register &dest);
+    void loadPrivate(const Address &address, const Register &dest);
 
     void store32(Register src, const ImmWord &imm);
     void store32(Register src, const Address &address);
     void store32(Imm32 src, const Address &address);
     void storePtr(Register src, const Address &address);
     void storePtr(Register src, const ImmWord &imm);
 
     void cmp32(const Register &lhs, const Imm32 &rhs);
--- a/js/src/ion/x64/MacroAssembler-x64.h
+++ b/js/src/ion/x64/MacroAssembler-x64.h
@@ -340,16 +340,20 @@ class MacroAssemblerX64 : public MacroAs
     }
     void loadPtr(ImmWord imm, Register dest) {
         movq(imm, ScratchReg);
         movq(Operand(ScratchReg, 0x0), dest);
     }
     void loadPtr(const Address &address, Register dest) {
         movq(Operand(address), dest);
     }
+    void loadPrivate(const Address &src, Register dest) {
+        loadPtr(src, dest);
+        shlq(Imm32(1), dest);
+    }
     void storePtr(Register src, const Address &address) {
         movq(src, Operand(address));
     }
     void rshiftPtr(Imm32 imm, const Register &dest) {
         shrq(imm, dest);
     }
 
     void setStackArg(const Register &reg, uint32 arg) {
--- a/js/src/ion/x86/MacroAssembler-x86.h
+++ b/js/src/ion/x86/MacroAssembler-x86.h
@@ -371,16 +371,19 @@ class MacroAssemblerX86 : public MacroAs
         movl(imm, dest);
     }
     void loadPtr(const Address &address, Register dest) {
         movl(Operand(address), dest);
     }
     void loadPtr(ImmWord imm, Register dest) {
         movl(Operand(imm.asPointer()), dest);
     }
+    void loadPrivate(const Address &src, Register dest) {
+        movl(payloadOf(src), dest);
+    }
     void storePtr(Register src, const Address &address) {
         movl(src, Operand(address));
     }
 
     void setStackArg(const Register &reg, uint32 arg) {
         movl(reg, Operand(esp, arg * STACK_SLOT_SIZE));
     }