Bug 588021: Port NAME PIC for ARM. (r=cdleary)
authorJacob Bramley <Jacob.Bramley@arm.com>
Thu, 13 Jan 2011 22:41:16 -0800
changeset 60594 cbdee93fd16348e9f5c0b35689555ca57c003bbd
parent 60593 02a47304563085c5160440e7e04e88c674aa3525
child 60595 151a8a6ce36bb7793b70729f32cc001cb92d5a43
push id18037
push usercleary@mozilla.com
push dateFri, 14 Jan 2011 17:42:55 +0000
treeherdermozilla-central@4e0501a0c5e5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscdleary
bugs588021
milestone2.0b10pre
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 588021: Port NAME PIC for ARM. (r=cdleary)
js/src/configure.in
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/ICLabels.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PolyIC.h
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2910,38 +2910,41 @@ case "$target" in
 i?86-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=i386
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
     ENABLE_POLYIC=1
     ENABLE_POLYIC_GETPROP=1
     ENABLE_POLYIC_BIND=1
+    ENABLE_POLYIC_NAME=1
     AC_DEFINE(JS_CPU_X86)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 x86_64*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=X64
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
     ENABLE_POLYIC=1
     ENABLE_POLYIC_GETPROP=1
     ENABLE_POLYIC_BIND=1
+    ENABLE_POLYIC_NAME=1
     AC_DEFINE(JS_CPU_X64)
     AC_DEFINE(JS_PUNBOX64)
     ;;
 arm*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=ARM
     ENABLE_METHODJIT=1
     ENABLE_MONOIC=1
     ENABLE_POLYIC=1
     ENABLE_POLYIC_GETPROP=1
     ENABLE_POLYIC_BIND=1
+    ENABLE_POLYIC_NAME=1
     AC_DEFINE(JS_CPU_ARM)
     AC_DEFINE(JS_NUNBOX32)
     ;;
 sparc*-*)
     ENABLE_TRACEJIT=1
     NANOJIT_ARCH=Sparc
     AC_DEFINE(JS_CPU_SPARC)
     ;;
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -3493,38 +3493,44 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
 #endif
 
 #ifdef JS_POLYIC_NAME
 void
 mjit::Compiler::jsop_name(JSAtom *atom)
 {
     PICGenInfo pic(ic::PICInfo::NAME, JSOp(*PC), true);
 
+    RESERVE_IC_SPACE(masm);
+
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
     pic.typeReg = Registers::ReturnReg;
     pic.atom = atom;
     pic.hasTypeCheck = false;
     pic.fastPathStart = masm.label();
 
+    /* There is no inline implementation, so we always jump to the slow path or to a stub. */
     pic.shapeGuard = masm.label();
-    Jump j = masm.jump();
-    DBGLABEL(dbgJumpOffset);
+    Jump inlineJump = masm.jump();
     {
-        pic.slowPathStart = stubcc.linkExit(j, Uses(0));
+        RESERVE_OOL_SPACE(stubcc.masm);
+        pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(0));
         stubcc.leave();
         passICAddress(&pic);
         pic.slowPathCall = OOL_STUBCALL(ic::Name);
+        CHECK_OOL_SPACE();
     }
-
     pic.fastPathRejoin = masm.label();
+
+    /* Initialize op labels. */
+    ScopeNameLabels &labels = pic.scopeNameLabels();
+    labels.setInlineJump(masm, pic.fastPathStart, inlineJump);
+
     frame.pushRegs(pic.shapeReg, pic.objReg);
 
-    JS_ASSERT(masm.differenceBetween(pic.fastPathStart, dbgJumpOffset) == SCOPENAME_JUMP_OFFSET);
-
     stubcc.rejoin(Changes(1));
 
     pics.append(pic);
 }
 
 bool
 mjit::Compiler::jsop_xname(JSAtom *atom)
 {
@@ -3535,39 +3541,48 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
         return jsop_getprop(atom);
     }
 
     if (!fe->isTypeKnown()) {
         Jump notObject = frame.testObject(Assembler::NotEqual, fe);
         stubcc.linkExit(notObject, Uses(1));
     }
 
+    RESERVE_IC_SPACE(masm);
+
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.copyDataIntoReg(fe);
     pic.typeReg = Registers::ReturnReg;
     pic.atom = atom;
     pic.hasTypeCheck = false;
     pic.fastPathStart = masm.label();
 
+    /* There is no inline implementation, so we always jump to the slow path or to a stub. */
     pic.shapeGuard = masm.label();
-    Jump j = masm.jump();
-    DBGLABEL(dbgJumpOffset);
+    Jump inlineJump = masm.jump();
     {
-        pic.slowPathStart = stubcc.linkExit(j, Uses(1));
+        RESERVE_OOL_SPACE(stubcc.masm);
+        pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(1));
         stubcc.leave();
         passICAddress(&pic);
         pic.slowPathCall = OOL_STUBCALL(ic::XName);
+        CHECK_OOL_SPACE();
     }
 
     pic.fastPathRejoin = masm.label();
+
+    RETURN_IF_OOM(false);
+
+    /* Initialize op labels. */
+    ScopeNameLabels &label = pic.scopeNameLabels();
+    labels.setInlineJumpOffset(masm.differenceBetween(pic.fastPathStart, inlineJump));
+
     frame.pop();
     frame.pushRegs(pic.shapeReg, pic.objReg);
 
-    JS_ASSERT(masm.differenceBetween(pic.fastPathStart, dbgJumpOffset) == SCOPENAME_JUMP_OFFSET);
-
     stubcc.rejoin(Changes(1));
 
     pics.append(pic);
     return true;
 }
 
 #endif /* JSOP_POLYIC_NAME */
 
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -221,43 +221,52 @@ class Compiler : public BaseCompiler
         JSAtom *atom;
         bool hasTypeCheck;
         ValueRemat vr;
 #ifdef JS_HAS_IC_LABELS
         union {
             ic::GetPropLabels getPropLabels_;
             ic::SetPropLabels setPropLabels_;
             ic::BindNameLabels bindNameLabels_;
+            ic::ScopeNameLabels scopeNameLabels_;
         };
 
         ic::GetPropLabels &getPropLabels() {
             JS_ASSERT(kind == ic::PICInfo::GET || kind == ic::PICInfo::CALL);
             return getPropLabels_;
         }
         ic::SetPropLabels &setPropLabels() {
             JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD);
             return setPropLabels_;
         }
         ic::BindNameLabels &bindNameLabels() {
             JS_ASSERT(kind == ic::PICInfo::BIND);
             return bindNameLabels_;
         }
+        ic::ScopeNameLabels &scopeNameLabels() {
+            JS_ASSERT(kind == ic::PICInfo::NAME || kind == ic::PICInfo::XNAME);
+            return scopeNameLabels_;
+        }
 #else
         ic::GetPropLabels &getPropLabels() {
             JS_ASSERT(kind == ic::PICInfo::GET || kind == ic::PICInfo::CALL);
             return ic::PICInfo::getPropLabels_;
         }
         ic::SetPropLabels &setPropLabels() {
             JS_ASSERT(kind == ic::PICInfo::SET || kind == ic::PICInfo::SETMETHOD);
             return ic::PICInfo::setPropLabels_;
         }
         ic::BindNameLabels &bindNameLabels() {
             JS_ASSERT(kind == ic::PICInfo::BIND);
             return ic::PICInfo::bindNameLabels_;
         }
+        ic::ScopeNameLabels &scopeNameLabels() {
+            JS_ASSERT(kind == ic::PICInfo::NAME || kind == ic::PICInfo::XNAME);
+            return ic::PICInfo::scopeNameLabels_;
+        }
 #endif
 
         void copySimpleMembersTo(ic::PICInfo &ic) {
             ic.kind = kind;
             ic.shapeReg = shapeReg;
             ic.objReg = objReg;
             ic.atom = atom;
             ic.usePropCache = usePropCache;
@@ -269,16 +278,18 @@ class Compiler : public BaseCompiler
             }
 #ifdef JS_HAS_IC_LABELS
             if (ic.isGet())
                 ic.setLabels(getPropLabels());
             else if (ic.isSet())
                 ic.setLabels(setPropLabels());
             else if (ic.isBind())
                 ic.setLabels(bindNameLabels());
+            else if (ic.isScopeName())
+                ic.setLabels(scopeNameLabels());
 #endif
         }
 
     };
 
     struct Defs {
         Defs(uint32 ndefs)
           : ndefs(ndefs)
--- a/js/src/methodjit/ICLabels.h
+++ b/js/src/methodjit/ICLabels.h
@@ -72,18 +72,16 @@ namespace ic {
  * using the extended register set. It is done on ARM for ease of
  * implementation.
  */
 
 #if defined JS_CPU_X64 || defined JS_CPU_ARM
 # define JS_HAS_IC_LABELS
 #endif
 
-# define JS_POLYIC_OFFSET_BITS 8
-
 /* GetPropCompiler */
 struct GetPropLabels : MacroAssemblerTypedefs {
     friend class ::ICOffsetInitializer;
 
     void setValueLoad(MacroAssembler &masm, Label fastPathRejoin, Label fastValueLoad) {
         int offset = masm.differenceBetween(fastPathRejoin, fastValueLoad);
 #ifdef JS_HAS_IC_LABELS
         inlineValueLoadOffset = offset;
@@ -351,14 +349,66 @@ struct BindNameLabels : MacroAssemblerTy
   private:
     /* Offset from shapeGuard to end of shape jump. */
     int32 inlineJumpOffset : 8;
 
     /* Offset from lastStubStart to end of the shape jump. */
     int32 stubJumpOffset : 8;
 };
 
+/* ScopeNameCompiler */
+struct ScopeNameLabels : MacroAssemblerTypedefs {
+    friend class ::ICOffsetInitializer;
+
+    void setInlineJumpOffset(int offset) {
+#ifdef JS_HAS_IC_LABELS
+        inlineJumpOffset = offset;
+#endif
+        JS_ASSERT(offset == inlineJumpOffset);
+    }
+
+    void setInlineJump(MacroAssembler &masm, Label fastPathStart, Jump inlineJump) {
+        int offset = masm.differenceBetween(fastPathStart, inlineJump);
+        setInlineJumpOffset(offset);
+    }
+
+    CodeLocationJump getInlineJump(CodeLocationLabel fastPathStart) {
+        return fastPathStart.jumpAtOffset(getInlineJumpOffset());
+    }
+
+    int getInlineJumpOffset() {
+        return inlineJumpOffset;
+    }
+
+    void setStubJumpOffset(int offset) {
+#ifdef JS_HAS_IC_LABELS
+        stubJumpOffset = offset;
+#endif
+        JS_ASSERT(offset == stubJumpOffset);
+    }
+
+    void setStubJump(MacroAssembler &masm, Label stubStart, Jump stubJump) {
+        int offset = masm.differenceBetween(stubStart, stubJump);
+        setStubJumpOffset(offset);
+    }
+
+    CodeLocationJump getStubJump(CodeLocationLabel lastStubStart) {
+        return lastStubStart.jumpAtOffset(getStubJumpOffset());
+    }
+
+    int getStubJumpOffset() {
+        return stubJumpOffset;
+    }
+
+  private:
+    /* Offset from fastPathStart to end of shape jump. */
+    int32 inlineJumpOffset : 8;
+
+    /* Offset from lastStubStart to end of the shape jump. */
+    int32 stubJumpOffset : 8;
+};
+
 } /* namespace ic */
 } /* namespace mjit */
 } /* namespace js */
 
 #endif /* jsjaeger_ic_labels_h__ */
 
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -88,22 +88,30 @@ ICOffsetInitializer::ICOffsetInitializer
     }
     {
         BindNameLabels &labels = PICInfo::bindNameLabels_;
 #if defined JS_CPU_X86
         labels.inlineJumpOffset = 10;
         labels.stubJumpOffset = 5;
 #endif
     }
+    {
+        ScopeNameLabels &labels = PICInfo::scopeNameLabels_;
+#if defined JS_CPU_X86
+        labels.inlineJumpOffset = 5;
+        labels.stubJumpOffset = 5;
+#endif
+    }
 }
 
 ICOffsetInitializer s_ICOffsetInitializer;
 GetPropLabels PICInfo::getPropLabels_;
 SetPropLabels PICInfo::setPropLabels_;
 BindNameLabels PICInfo::bindNameLabels_;
+ScopeNameLabels PICInfo::scopeNameLabels_;
 #endif
 
 // Helper class to simplify LinkBuffer usage in PIC stub generators.
 // This guarantees correct OOM and refcount handling for buffers while they
 // are instantiated and rooted.
 class PICLinker : public LinkerHelper
 {
     ic::BasePolyIC &ic;
@@ -1203,42 +1211,39 @@ class GetPropCompiler : public PICStubCo
         return generateStub(getprop.holder, getprop.shape);
     }
 };
 #endif
 
 #if defined JS_POLYIC_NAME
 class ScopeNameCompiler : public PICStubCompiler
 {
+  private:
+    typedef Vector<Jump, 8, ContextAllocPolicy> JumpList;
+
     JSObject *scopeChain;
     JSAtom *atom;
-
     GetPropertyHelper<ScopeNameCompiler> getprop;
-
     ScopeNameCompiler *thisFromCtor() { return this; }
-  public:
-    ScopeNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
-                      JSAtom *atom, VoidStubPIC stub)
-      : PICStubCompiler("name", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
-        scopeChain(scopeChain), atom(atom),
-        getprop(f.cx, NULL, atom, *thisFromCtor())
-    { }
-
-    static void reset(Repatcher &repatcher, ic::PICInfo &pic)
+
+    void patchPreviousToHere(CodeLocationLabel cs)
     {
-        repatcher.relink(pic.fastPathStart.jumpAtOffset(SCOPENAME_JUMP_OFFSET),
-                         pic.slowPathStart);
-
-        VoidStubPIC stub = (pic.kind == ic::PICInfo::NAME) ? ic::Name : ic::XName;
-        FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, stub));
-        repatcher.relink(pic.slowPathCall, target);
+        ScopeNameLabels &       labels = pic.scopeNameLabels();
+        Repatcher               repatcher(pic.lastCodeBlock(f.jit()));
+        CodeLocationLabel       start = pic.lastPathStart();
+        JSC::CodeLocationJump   jump;
+        
+        // Patch either the inline fast path or a generated stub.
+        if (pic.stubsGenerated)
+            jump = labels.getStubJump(start);
+        else
+            jump = labels.getInlineJump(start);
+        repatcher.relink(jump, cs);
     }
 
-    typedef Vector<Jump, 8, ContextAllocPolicy> JumpList;
-
     LookupStatus walkScopeChain(Assembler &masm, JumpList &fails)
     {
         /* Walk the scope chain. */
         JSObject *tobj = scopeChain;
 
         /* For GETXPROP, we'll never enter this loop. */
         JS_ASSERT_IF(pic.kind == ic::PICInfo::XNAME, tobj && tobj == getprop.holder);
         JS_ASSERT_IF(pic.kind == ic::PICInfo::XNAME, getprop.obj == tobj);
@@ -1269,20 +1274,42 @@ class ScopeNameCompiler : public PICStub
         }
 
         if (tobj != getprop.holder)
             return disable("scope chain walk terminated early");
 
         return Lookup_Cacheable;
     }
 
+  public:
+    ScopeNameCompiler(VMFrame &f, JSScript *script, JSObject *scopeChain, ic::PICInfo &pic,
+                      JSAtom *atom, VoidStubPIC stub)
+      : PICStubCompiler("name", f, script, pic, JS_FUNC_TO_DATA_PTR(void *, stub)),
+        scopeChain(scopeChain), atom(atom),
+        getprop(f.cx, NULL, atom, *thisFromCtor())
+    { }
+
+    static void reset(Repatcher &repatcher, ic::PICInfo &pic)
+    {
+        ScopeNameLabels &labels = pic.scopeNameLabels();
+
+        /* Link the inline path back to the slow path. */
+        JSC::CodeLocationJump inlineJump = labels.getInlineJump(pic.fastPathStart);
+        repatcher.relink(inlineJump, pic.slowPathStart);
+
+        VoidStubPIC stub = (pic.kind == ic::PICInfo::NAME) ? ic::Name : ic::XName;
+        FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, stub));
+        repatcher.relink(pic.slowPathCall, target);
+    }
+
     LookupStatus generateGlobalStub(JSObject *obj)
     {
         Assembler masm;
         JumpList fails(cx);
+        ScopeNameLabels &labels = pic.scopeNameLabels();
 
         /* For GETXPROP, the object is already in objReg. */
         if (pic.kind == ic::PICInfo::NAME)
             masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
 
         JS_ASSERT(obj == getprop.holder);
         JS_ASSERT(getprop.holder == scopeChain->getGlobal());
 
@@ -1295,65 +1322,62 @@ class ScopeNameCompiler : public PICStub
         if (pic.kind == ic::PICInfo::NAME)
             finalNull = masm.branchTestPtr(Assembler::Zero, pic.objReg, pic.objReg);
         masm.loadShape(pic.objReg, pic.shapeReg);
         Jump finalShape = masm.branch32(Assembler::NotEqual, pic.shapeReg, Imm32(getprop.holder->shape()));
 
         masm.loadObjProp(obj, pic.objReg, getprop.shape, pic.shapeReg, pic.objReg);
         Jump done = masm.jump();
 
-        // All failures flow to here, so there is a common point to patch.
+        /* All failures flow to here, so there is a common point to patch. */
         for (Jump *pj = fails.begin(); pj != fails.end(); ++pj)
             pj->linkTo(masm.label(), &masm);
         if (finalNull.isSet())
             finalNull.get().linkTo(masm.label(), &masm);
         finalShape.linkTo(masm.label(), &masm);
         Label failLabel = masm.label();
         Jump failJump = masm.jump();
-        DBGLABEL(dbgJumpOffset);
-
-        JS_ASSERT(masm.differenceBetween(failLabel, dbgJumpOffset) == SCOPENAME_JUMP_OFFSET);
 
         PICLinker buffer(masm, pic);
         if (!buffer.init(cx))
             return error();
 
         if (!buffer.verifyRange(pic.lastCodeBlock(f.jit())) ||
             !buffer.verifyRange(f.jit())) {
             return disable("code memory is out of range");
         }
 
         buffer.link(failJump, pic.slowPathStart);
         buffer.link(done, pic.fastPathRejoin);
         CodeLocationLabel cs = buffer.finalize();
         JaegerSpew(JSpew_PICs, "generated %s global stub at %p\n", type, cs.executableAddress());
         spew("NAME stub", "global");
 
-        Repatcher repatcher(pic.lastCodeBlock(f.jit()));
-        CodeLocationLabel label = pic.lastPathStart();
-        repatcher.relink(label.jumpAtOffset(SCOPENAME_JUMP_OFFSET), cs);
+        patchPreviousToHere(cs);
 
         pic.stubsGenerated++;
         pic.updateLastPath(buffer, failLabel);
+        labels.setStubJump(masm, failLabel, failJump);
 
         if (pic.stubsGenerated == MAX_PIC_STUBS)
             disable("max stubs reached");
 
         return Lookup_Cacheable;
     }
 
     enum CallObjPropKind {
         ARG,
         VAR
     };
 
     LookupStatus generateCallStub(JSObject *obj)
     {
         Assembler masm;
         Vector<Jump, 8, ContextAllocPolicy> fails(cx);
+        ScopeNameLabels &labels = pic.scopeNameLabels();
 
         /* For GETXPROP, the object is already in objReg. */
         if (pic.kind == ic::PICInfo::NAME)
             masm.loadPtr(Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()), pic.objReg);
 
         JS_ASSERT(obj == getprop.holder);
         JS_ASSERT(getprop.holder != scopeChain->getGlobal());
 
@@ -1430,22 +1454,21 @@ class ScopeNameCompiler : public PICStub
             return disable("code memory is out of range");
         }
 
         buffer.link(failJump, pic.slowPathStart);
         buffer.link(done, pic.fastPathRejoin);
         CodeLocationLabel cs = buffer.finalize();
         JaegerSpew(JSpew_PICs, "generated %s call stub at %p\n", type, cs.executableAddress());
 
-        Repatcher repatcher(pic.lastCodeBlock(f.jit()));
-        CodeLocationLabel label = pic.lastPathStart();
-        repatcher.relink(label.jumpAtOffset(SCOPENAME_JUMP_OFFSET), cs);
+        patchPreviousToHere(cs);
 
         pic.stubsGenerated++;
         pic.updateLastPath(buffer, failLabel);
+        labels.setStubJump(masm, failLabel, failJump);
 
         if (pic.stubsGenerated == MAX_PIC_STUBS)
             disable("max stubs reached");
 
         return Lookup_Cacheable;
     }
 
     LookupStatus updateForName()
--- a/js/src/methodjit/PolyIC.h
+++ b/js/src/methodjit/PolyIC.h
@@ -73,23 +73,16 @@ static const int32 SETPROP_INLINE_STORE_
 static const int32 SETPROP_INLINE_STORE_KTYPE_DATA =   0; //asserted
 static const int32 SETPROP_INLINE_STORE_CONST_TYPE = -14; //asserted
 static const int32 SETPROP_INLINE_STORE_CONST_DATA =  -4; //asserted
 #elif defined JS_CPU_X64
 static const int32 SETPROP_INLINE_STORE_VALUE      =   0; //asserted
 static const int32 SETPROP_INLINE_SHAPE_JUMP       =   6; //asserted
 #endif
 
-/* ScopeNameCompiler */
-#if defined JS_CPU_X86
-static const int32 SCOPENAME_JUMP_OFFSET = 5; //asserted
-#elif defined JS_CPU_X64
-static const int32 SCOPENAME_JUMP_OFFSET = 5; //asserted
-#endif
-
 void PurgePICs(JSContext *cx);
 
 enum LookupStatus {
     Lookup_Error = 0,
     Lookup_Uncacheable,
     Lookup_Cacheable
 };
 
@@ -478,16 +471,19 @@ struct PICInfo : public BasePolyIC {
         return kind == SET || kind == SETMETHOD;
     }
     inline bool isGet() const {
         return kind == GET || kind == CALL;
     }
     inline bool isBind() const {
         return kind == BIND;
     }
+    inline bool isScopeName() const {
+        return kind == NAME || kind == XNAME;
+    }
     inline RegisterID typeReg() {
         JS_ASSERT(isGet());
         return u.get.typeReg;
     }
     inline bool hasTypeCheck() {
         JS_ASSERT(isGet());
         return u.get.hasTypeCheck;
     }
@@ -498,48 +494,58 @@ struct PICInfo : public BasePolyIC {
         JS_ASSERT(kind == CALL);
         return !hasTypeCheck();
     }
 
 #if !defined JS_HAS_IC_LABELS
     static GetPropLabels getPropLabels_;
     static SetPropLabels setPropLabels_;
     static BindNameLabels bindNameLabels_;
+    static ScopeNameLabels scopeNameLabels_;
 #else
     union {
         GetPropLabels getPropLabels_;
         SetPropLabels setPropLabels_;
         BindNameLabels bindNameLabels_;
+        ScopeNameLabels scopeNameLabels_;
     };
     void setLabels(const ic::GetPropLabels &labels) {
         JS_ASSERT(isGet());
         getPropLabels_ = labels;
     }
     void setLabels(const ic::SetPropLabels &labels) {
         JS_ASSERT(isSet());
         setPropLabels_ = labels;
     }
     void setLabels(const ic::BindNameLabels &labels) {
         JS_ASSERT(kind == BIND);
         bindNameLabels_ = labels;
     }
+    void setLabels(const ic::ScopeNameLabels &labels) {
+        JS_ASSERT(kind == NAME || kind == XNAME);
+        scopeNameLabels_ = labels;
+    }
 #endif
 
     GetPropLabels &getPropLabels() {
         JS_ASSERT(isGet());
         return getPropLabels_;
     }
     SetPropLabels &setPropLabels() {
         JS_ASSERT(isSet());
         return setPropLabels_;
     }
     BindNameLabels &bindNameLabels() {
         JS_ASSERT(kind == BIND);
         return bindNameLabels_;
     }
+    ScopeNameLabels &scopeNameLabels() {
+        JS_ASSERT(kind == NAME || kind == XNAME);
+        return scopeNameLabels_;
+    }
 
     // Where in the script did we generate this PIC?
     jsbytecode *pc;
     
     // Index into the script's atom table.
     JSAtom *atom;
 
     // Reset the data members to the state of a fresh PIC before any patching