Remove direct class pointer from JSObject, bug 690133.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 29 Sep 2011 08:20:06 -0700
changeset 81235 55a63871f966714c7ef78fca2f945538d7ed8f59
parent 81234 ff51ddfdf5d1c04f37c272b745454af2d58be08d
child 81236 c9be55115ad8d40540394421223b94142a7dd51b
push id21565
push userbhackett@mozilla.com
push dateSat, 03 Dec 2011 20:25:52 +0000
treeherdermozilla-central@13afcd4c097c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs690133
milestone9.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
Remove direct class pointer from JSObject, bug 690133.
js/src/jsarray.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfun.cpp
js/src/jsinfer.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsscope.h
js/src/jsscopeinlines.h
js/src/jstypedarray.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastOps.cpp
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PolyIC.h
js/src/tracejit/Writer.cpp
js/src/tracejit/Writer.h
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1291,48 +1291,45 @@ JSBool
 JSObject::makeDenseArraySlow(JSContext *cx)
 {
     JS_ASSERT(isDenseArray());
 
     MarkTypeObjectFlags(cx, this,
                         OBJECT_FLAG_NON_PACKED_ARRAY |
                         OBJECT_FLAG_NON_DENSE_ARRAY);
     markDenseArrayNotPacked(cx);
+    backfillDenseArrayHoles(cx);
+
+    uint32 arrayCapacity = getDenseArrayCapacity();
+    uint32 arrayInitialized = getDenseArrayInitializedLength();
+
+    /*
+     * Adjust the slots to account for the different layout between dense
+     * arrays and other objects. The slots must be dynamic, and the fixed slots
+     * are now available for newly added properties.
+     */
+    if (denseArrayHasInlineSlots()) {
+        if (!allocSlots(cx, numSlots()))
+            return false;
+        JS_ASSERT(!denseArrayHasInlineSlots());
+    }
 
     /*
      * Save old map now, before calling InitScopeForObject. We'll have to undo
      * on error. This is gross, but a better way is not obvious. Note: the
      * exact contents of the array are not preserved on error.
      */
     js::Shape *oldMap = lastProp;
 
     /* Create a native scope. */
     gc::AllocKind kind = getAllocKind();
     if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind))
         return false;
 
-    backfillDenseArrayHoles(cx);
-
-    uint32 arrayCapacity = getDenseArrayCapacity();
-    uint32 arrayInitialized = getDenseArrayInitializedLength();
-
-    /*
-     * Adjust the slots to account for the different layout between dense
-     * arrays and other objects. The slots must be dynamic, and the fixed slots
-     * are now available for newly added properties.
-     */
-    if (denseArrayHasInlineSlots()) {
-        if (!allocSlots(cx, numSlots())) {
-            setMap(oldMap);
-            return false;
-        }
-        JS_ASSERT(!denseArrayHasInlineSlots());
-    }
     capacity = numFixedSlots() + arrayCapacity;
-    clasp = &SlowArrayClass;
 
     /*
      * Root all values in the array during conversion, as SlowArrayClass only
      * protects up to its slot span.
      */
     AutoValueArray autoArray(cx, slots, arrayInitialized);
 
     /* The initialized length is used iff this is a dense array. */
@@ -1342,17 +1339,16 @@ JSObject::makeDenseArraySlow(JSContext *
     /*
      * Begin with the length property to share more of the property tree.
      * The getter/setter here will directly access the object's private value.
      */
     if (!AddLengthProperty(cx, this)) {
         setMap(oldMap);
         capacity = arrayCapacity;
         initializedLength = arrayInitialized;
-        clasp = &ArrayClass;
         return false;
     }
 
     /*
      * Create new properties pointing to existing elements. Pack the array to
      * remove holes, so that shapes use successive slots (as for other objects).
      */
     uint32 next = 0;
@@ -1365,17 +1361,16 @@ JSObject::makeDenseArraySlow(JSContext *
             continue;
 
         setSlot(next, slots[i]);
 
         if (!addDataProperty(cx, id, next, JSPROP_ENUMERATE)) {
             setMap(oldMap);
             capacity = arrayCapacity;
             initializedLength = arrayInitialized;
-            clasp = &ArrayClass;
             return false;
         }
 
         next++;
     }
 
     clearSlotRange(next, capacity - next);
 
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -82,17 +82,18 @@ JSCompartment::JSCompartment(JSRuntime *
     hasDebugModeCodeToDrop(false),
 #ifdef JS_METHODJIT
     jaegerCompartment_(NULL),
 #endif
 #if ENABLE_YARR_JIT
     regExpAllocator(NULL),
 #endif
     propertyTree(thisForCtor()),
-    emptyArgumentsShape(NULL),
+    emptyStrictArgumentsShape(NULL),
+    emptyNormalArgumentsShape(NULL),
     emptyBlockShape(NULL),
     emptyCallShape(NULL),
     emptyDeclEnvShape(NULL),
     emptyEnumeratorShape(NULL),
     emptyWithShape(NULL),
     initialRegExpShape(NULL),
     initialStringShape(NULL),
     debugModeBits(rt->debugMode ? DebugFromC : 0),
@@ -496,48 +497,49 @@ JSCompartment::markTypes(JSTracer *trc)
                 MarkObject(trc, *object, "mark_types_singleton");
         }
     }
 
     for (CellIterUnderGC i(this, FINALIZE_TYPE_OBJECT); !i.done(); i.next())
         MarkTypeObject(trc, i.get<types::TypeObject>(), "mark_types_scan");
 }
 
+template <class T>
+void
+CheckWeakShape(JSContext *cx, T *&shape)
+{
+    if (shape && IsAboutToBeFinalized(cx, shape))
+        shape = NULL;
+}
+
 void
 JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
 {
     /* Remove dead wrappers from the table. */
     for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) {
         JS_ASSERT_IF(IsAboutToBeFinalized(cx, e.front().key.toGCThing()) &&
                      !IsAboutToBeFinalized(cx, e.front().value.toGCThing()),
                      e.front().key.isString());
         if (IsAboutToBeFinalized(cx, e.front().key.toGCThing()) ||
             IsAboutToBeFinalized(cx, e.front().value.toGCThing())) {
             e.removeFront();
         }
     }
 
     /* Remove dead empty shapes. */
-    if (emptyArgumentsShape && IsAboutToBeFinalized(cx, emptyArgumentsShape))
-        emptyArgumentsShape = NULL;
-    if (emptyBlockShape && IsAboutToBeFinalized(cx, emptyBlockShape))
-        emptyBlockShape = NULL;
-    if (emptyCallShape && IsAboutToBeFinalized(cx, emptyCallShape))
-        emptyCallShape = NULL;
-    if (emptyDeclEnvShape && IsAboutToBeFinalized(cx, emptyDeclEnvShape))
-        emptyDeclEnvShape = NULL;
-    if (emptyEnumeratorShape && IsAboutToBeFinalized(cx, emptyEnumeratorShape))
-        emptyEnumeratorShape = NULL;
-    if (emptyWithShape && IsAboutToBeFinalized(cx, emptyWithShape))
-        emptyWithShape = NULL;
+    CheckWeakShape(cx, emptyStrictArgumentsShape);
+    CheckWeakShape(cx, emptyNormalArgumentsShape);
+    CheckWeakShape(cx, emptyBlockShape);
+    CheckWeakShape(cx, emptyCallShape);
+    CheckWeakShape(cx, emptyDeclEnvShape);
+    CheckWeakShape(cx, emptyEnumeratorShape);
+    CheckWeakShape(cx, emptyWithShape);
 
-    if (initialRegExpShape && IsAboutToBeFinalized(cx, initialRegExpShape))
-        initialRegExpShape = NULL;
-    if (initialStringShape && IsAboutToBeFinalized(cx, initialStringShape))
-        initialStringShape = NULL;
+    CheckWeakShape(cx, initialRegExpShape);
+    CheckWeakShape(cx, initialStringShape);
 
     /* Remove dead base shapes */
     sweepBaseShapeTable(cx);
 
     sweepBreakpoints(cx);
 
 #ifdef JS_TRACER
     if (hasTraceMonitor())
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -471,17 +471,18 @@ struct JS_FRIEND_API(JSCompartment) {
     jsrefcount                   propTreeKidsChunks;
     jsrefcount                   liveDictModeNodes;
 #endif
 
     /*
      * Runtime-shared empty scopes for well-known built-in objects that lack
      * class prototypes (the usual locus of an emptyShape). Mnemonic: ABCDEW
      */
-    js::EmptyShape               *emptyArgumentsShape;
+    js::EmptyShape               *emptyStrictArgumentsShape;
+    js::EmptyShape               *emptyNormalArgumentsShape;
     js::EmptyShape               *emptyBlockShape;
     js::EmptyShape               *emptyCallShape;
     js::EmptyShape               *emptyDeclEnvShape;
     js::EmptyShape               *emptyEnumeratorShape;
     js::EmptyShape               *emptyWithShape;
 
     /*
      * Set of all unowned base shapes in the compartment, with optional empty
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -198,31 +198,29 @@ ArgumentsObject::create(JSContext *cx, u
         return NULL;
 
     JS_STATIC_ASSERT(NormalArgumentsObject::RESERVED_SLOTS == 2);
     JS_STATIC_ASSERT(StrictArgumentsObject::RESERVED_SLOTS == 2);
     JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!obj)
         return NULL;
 
-    EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx);
+    bool strict = callee.getFunctionPrivate()->inStrictMode();
+    EmptyShape *emptyArgumentsShape = EmptyShape::getEmptyArgumentsShape(cx, strict);
     if (!emptyArgumentsShape)
         return NULL;
 
     ArgumentsData *data = (ArgumentsData *)
         cx->malloc_(offsetof(ArgumentsData, slots) + argc * sizeof(Value));
     if (!data)
         return NULL;
     SetValueRangeToUndefined(data->slots, argc);
 
     /* Can't fail from here on, so initialize everything in argsobj. */
-    obj->init(cx, callee.getFunctionPrivate()->inStrictMode()
-              ? &StrictArgumentsObjectClass
-              : &NormalArgumentsObjectClass,
-              type, proto->getParent(), NULL, false);
+    obj->init(cx, type, proto->getParent(), NULL, false);
     obj->setMap(emptyArgumentsShape);
 
     ArgumentsObject *argsobj = obj->asArguments();
 
     JS_ASSERT(UINT32_MAX > (uint64(argc) << PACKED_BITS_COUNT));
     argsobj->setInitialLength(argc);
 
     argsobj->setCalleeAndData(callee, data);
@@ -761,17 +759,17 @@ NewDeclEnvObject(JSContext *cx, StackFra
 {
     JSObject *envobj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!envobj)
         return NULL;
 
     EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx);
     if (!emptyDeclEnvShape)
         return NULL;
-    envobj->init(cx, &DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false);
+    envobj->init(cx, &emptyTypeObject, &fp->scopeChain(), fp, false);
     envobj->setMap(emptyDeclEnvShape);
 
     return envobj;
 }
 
 namespace js {
 
 CallObject *
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -5604,17 +5604,17 @@ JSObject::makeLazyType(JSContext *cx)
     /*
      * XML objects do not have equality hooks but are treated special by EQ/NE
      * ops. Just mark the type as totally unknown.
      */
     if (isXML() && !type->unknownProperties())
         type->markUnknown(cx);
 #endif
 
-    if (clasp->ext.equality)
+    if (getClass()->ext.equality)
         type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
 
     if (type->unknownProperties()) {
         type_ = type;
         flags &= ~LAZY_TYPE;
         return;
     }
 
@@ -5657,17 +5657,17 @@ JSObject::makeNewType(JSContext *cx, JSF
         CheckNewScriptProperties(cx, type, fun);
 
 #if JS_HAS_XML_SUPPORT
     /* Special case for XML object equality, see makeLazyType(). */
     if (isXML() && !type->unknownProperties())
         type->flags |= OBJECT_FLAG_UNKNOWN_MASK;
 #endif
 
-    if (clasp->ext.equality)
+    if (getClass()->ext.equality)
         type->flags |= OBJECT_FLAG_SPECIAL_EQUALITY;
 
     /*
      * The new type is not present in any type sets, so mark the object as
      * unknown in all type sets it appears in. This allows the prototype of
      * such objects to mutate freely without triggering an expensive walk of
      * the compartment's type sets. (While scripts normally don't mutate
      * __proto__, the browser will for proxies and such, and we need to
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -413,17 +413,17 @@ NewIteratorObject(JSContext *cx, uintN f
          */
         JSObject *obj = js_NewGCObject(cx, FINALIZE_OBJECT0);
         if (!obj)
             return NULL;
 
         EmptyShape *emptyEnumeratorShape = EmptyShape::getEmptyEnumeratorShape(cx);
         if (!emptyEnumeratorShape)
             return NULL;
-        obj->init(cx, &IteratorClass, &types::emptyTypeObject, NULL, NULL, false);
+        obj->init(cx, &types::emptyTypeObject, NULL, NULL, false);
         obj->setMap(emptyEnumeratorShape);
         return obj;
     }
 
     return NewBuiltinClassInstance(cx, &IteratorClass);
 }
 
 NativeIterator *
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3474,17 +3474,17 @@ js_NewWithObject(JSContext *cx, JSObject
         return NULL;
 
     obj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!obj)
         return NULL;
 
     StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp());
 
-    obj->init(cx, &WithClass, type, parent, priv, false);
+    obj->init(cx, type, parent, priv, false);
 
     EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx);
     if (!emptyWithShape)
         return NULL;
 
     obj->setMap(emptyWithShape);
     OBJ_SET_BLOCK_DEPTH(cx, obj, depth);
 
@@ -3508,17 +3508,17 @@ js_NewBlockObject(JSContext *cx)
      */
     JSObject *blockObj = js_NewGCObject(cx, FINALIZE_OBJECT2);
     if (!blockObj)
         return NULL;
 
     EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx);
     if (!emptyBlockShape)
         return NULL;
-    blockObj->init(cx, &BlockClass, &emptyTypeObject, NULL, NULL, false);
+    blockObj->init(cx, &emptyTypeObject, NULL, NULL, false);
     blockObj->setMap(emptyBlockShape);
 
     return blockObj;
 }
 
 JSObject *
 js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
 {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -440,28 +440,23 @@ struct JSObject : js::gc::Cell {
      * TraceRecorder must be a friend because it generates code that
      * manipulates JSObjects, which requires peeking under any encapsulation.
      * ValidateWriter must be a friend because it works in tandem with
      * TraceRecorder.
      */
     friend class js::TraceRecorder;
     friend class nanojit::ValidateWriter;
 
-#if JS_BITS_PER_WORD == 32
-    void *padding;
-#endif
-
     /*
      * Private pointer to the last added property and methods to manipulate the
      * list it links among properties in this scope.
      */
     js::Shape           *lastProp;
 
   private:
-    js::Class           *clasp;
 
     inline void setLastProperty(const js::Shape *shape);
     inline void removeLastProperty();
 
     /* For setLastProperty() only. */
     friend class js::StringObject;
 
 #ifdef DEBUG
@@ -539,27 +534,21 @@ struct JSObject : js::gc::Cell {
     /* Make the type object to use for LAZY_TYPE objects. */
     void makeLazyType(JSContext *cx);
 
   public:
 
     inline bool isNative() const;
     inline bool isNewborn() const;
 
-    void setClass(js::Class *c) { clasp = c; }
-    js::Class *getClass() const { return clasp; }
-    JSClass *getJSClass() const { return Jsvalify(clasp); }
-
-    bool hasClass(const js::Class *c) const {
-        return c == clasp;
-    }
-
-    const js::ObjectOps *getOps() const {
-        return &getClass()->ops;
-    }
+    /* Inline functions defined in jsobjinlines.h */
+    js::Class *getClass() const;
+    JSClass *getJSClass() const;
+    bool hasClass(const js::Class *c) const;
+    const js::ObjectOps *getOps() const;
 
     inline void trace(JSTracer *trc);
     inline void scanSlots(js::GCMarker *gcmarker);
 
     bool isDelegate() const     { return !!(flags & DELEGATE); }
     void setDelegate()          { flags |= DELEGATE; }
     void clearDelegate()        { flags &= ~DELEGATE; }
 
@@ -573,17 +562,17 @@ struct JSObject : js::gc::Cell {
     bool isSystem() const       { return !!(flags & SYSTEM); }
     void setSystem()            { flags |= SYSTEM; }
 
     bool generic()              { return !!(flags & GENERIC); }
     void setGeneric()           { flags |= GENERIC; }
 
     bool hasSpecialEquality() const { return !!(flags & HAS_EQUALITY); }
     void assertSpecialEqualitySynced() const {
-        JS_ASSERT(!!clasp->ext.equality == hasSpecialEquality());
+        JS_ASSERT(!!getClass()->ext.equality == hasSpecialEquality());
     }
 
     /* Sets an object's HAS_EQUALITY flag based on its clasp. */
     inline void syncSpecialEquality();
 
     bool watched() const { return !!(flags & WATCHED); }
 
     bool setWatched(JSContext *cx) {
@@ -1208,17 +1197,17 @@ struct JSObject : js::gc::Cell {
     void earlyInit(jsuword capacity) {
         this->capacity = capacity;
 
         /* Stops obj from being scanned until initializated. */
         lastProp = NULL;
     }
 
     /* The map field is not initialized here and should be set separately. */
-    void init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type,
+    void init(JSContext *cx, js::types::TypeObject *type,
               JSObject *parent, void *priv, bool denseArray);
 
     inline void finish(JSContext *cx);
     JS_ALWAYS_INLINE void finalize(JSContext *cx);
 
     /*
      * Like init, but also initializes map.  proto must have an empty shape
      * created for it via proto->getEmptyShape.
@@ -1414,66 +1403,62 @@ struct JSObject : js::gc::Cell {
 
     JS_FRIEND_API(JSObject *) clone(JSContext *cx, JSObject *proto, JSObject *parent);
     JS_FRIEND_API(bool) copyPropertiesFrom(JSContext *cx, JSObject *obj);
     bool swap(JSContext *cx, JSObject *other);
 
     const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
 
     inline bool isArguments() const { return isNormalArguments() || isStrictArguments(); }
-    inline bool isArrayBuffer() const { return clasp == &js::ArrayBufferClass; }
-    inline bool isNormalArguments() const { return clasp == &js::NormalArgumentsObjectClass; }
-    inline bool isStrictArguments() const { return clasp == &js::StrictArgumentsObjectClass; }
+    inline bool isArrayBuffer() const { return hasClass(&js::ArrayBufferClass); }
+    inline bool isNormalArguments() const { return hasClass(&js::NormalArgumentsObjectClass); }
+    inline bool isStrictArguments() const { return hasClass(&js::StrictArgumentsObjectClass); }
     inline bool isArray() const { return isSlowArray() || isDenseArray(); }
-    inline bool isDenseArray() const { return clasp == &js::ArrayClass; }
-    inline bool isSlowArray() const { return clasp == &js::SlowArrayClass; }
-    inline bool isNumber() const { return clasp == &js::NumberClass; }
-    inline bool isBoolean() const { return clasp == &js::BooleanClass; }
-    inline bool isString() const { return clasp == &js::StringClass; }
+    inline bool isDenseArray() const { return hasClass(&js::ArrayClass); }
+    inline bool isSlowArray() const { return hasClass(&js::SlowArrayClass); }
+    inline bool isNumber() const { return hasClass(&js::NumberClass); }
+    inline bool isBoolean() const { return hasClass(&js::BooleanClass); }
+    inline bool isString() const { return hasClass(&js::StringClass); }
     inline bool isPrimitive() const { return isNumber() || isString() || isBoolean(); }
-    inline bool isDate() const { return clasp == &js::DateClass; }
-    inline bool isFunction() const { return clasp == &js::FunctionClass; }
-    inline bool isObject() const { return clasp == &js::ObjectClass; }
-    inline bool isWith() const { return clasp == &js::WithClass; }
-    inline bool isBlock() const { return clasp == &js::BlockClass; }
+    inline bool isDate() const { return hasClass(&js::DateClass); }
+    inline bool isFunction() const { return hasClass(&js::FunctionClass); }
+    inline bool isObject() const { return hasClass(&js::ObjectClass); }
+    inline bool isWith() const { return hasClass(&js::WithClass); }
+    inline bool isBlock() const { return hasClass(&js::BlockClass); }
     inline bool isStaticBlock() const { return isBlock() && !getProto(); }
     inline bool isClonedBlock() const { return isBlock() && !!getProto(); }
-    inline bool isCall() const { return clasp == &js::CallClass; }
-    inline bool isDeclEnv() const { return clasp == &js::DeclEnvClass; }
-    inline bool isRegExp() const { return clasp == &js::RegExpClass; }
-    inline bool isScript() const { return clasp == &js::ScriptClass; }
-    inline bool isGenerator() const { return clasp == &js::GeneratorClass; }
-    inline bool isIterator() const { return clasp == &js::IteratorClass; }
-    inline bool isStopIteration() const { return clasp == &js::StopIterationClass; }
-    inline bool isError() const { return clasp == &js::ErrorClass; }
-    inline bool isXML() const { return clasp == &js::XMLClass; }
-    inline bool isNamespace() const { return clasp == &js::NamespaceClass; }
-    inline bool isWeakMap() const { return clasp == &js::WeakMapClass; }
-    inline bool isFunctionProxy() const { return clasp == &js::FunctionProxyClass; }
+    inline bool isCall() const { return hasClass(&js::CallClass); }
+    inline bool isDeclEnv() const { return hasClass(&js::DeclEnvClass); }
+    inline bool isRegExp() const { return hasClass(&js::RegExpClass); }
+    inline bool isScript() const { return hasClass(&js::ScriptClass); }
+    inline bool isGenerator() const { return hasClass(&js::GeneratorClass); }
+    inline bool isIterator() const { return hasClass(&js::IteratorClass); }
+    inline bool isStopIteration() const { return hasClass(&js::StopIterationClass); }
+    inline bool isError() const { return hasClass(&js::ErrorClass); }
+    inline bool isXML() const { return hasClass(&js::XMLClass); }
+    inline bool isNamespace() const { return hasClass(&js::NamespaceClass); }
+    inline bool isWeakMap() const { return hasClass(&js::WeakMapClass); }
+    inline bool isFunctionProxy() const { return hasClass(&js::FunctionProxyClass); }
     inline bool isProxy() const { return isObjectProxy() || isFunctionProxy(); }
 
     inline bool isXMLId() const {
-        return clasp == &js::QNameClass || clasp == &js::AttributeNameClass || clasp == &js::AnyNameClass;
-    }
+    return hasClass(&js::QNameClass) || hasClass(&js::AttributeNameClass) || hasClass(&js::AnyNameClass);
+}
     inline bool isQName() const {
-        return clasp == &js::QNameClass || clasp == &js::AttributeNameClass || clasp == &js::AnyNameClass;
-    }
+    return hasClass(&js::QNameClass) || hasClass(&js::AttributeNameClass) || hasClass(&js::AnyNameClass);
+}
     inline bool isObjectProxy() const {
-        return clasp == &js::ObjectProxyClass || clasp == &js::OuterWindowProxyClass;
-    }
+    return hasClass(&js::ObjectProxyClass) || hasClass(&js::OuterWindowProxyClass);
+}
 
     JS_FRIEND_API(bool) isWrapper() const;
     bool isCrossCompartmentWrapper() const;
     JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL);
 
     inline void initArrayClass();
-
-    /*** For jit compiler: ***/
-
-    static size_t offsetOfClassPointer() { return offsetof(JSObject, clasp); }
 };
 
 /* Check alignment for any fixed slots allocated after the object. */
 JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(js::Value) == 0);
 
 /*
  * The only sensible way to compare JSObject with == is by identity. We use
  * const& instead of * as a syntactic way to assert non-null. This leads to an
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -176,41 +176,45 @@ JSObject::finalize(JSContext *cx)
 
 /* 
  * Initializer for Call objects for functions and eval frames. Set class,
  * parent, map, and shape, and allocate slots.
  */
 inline bool
 JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent)
 {
-    init(cx, &js::CallClass, &js::types::emptyTypeObject, parent, NULL, false);
+    init(cx, &js::types::emptyTypeObject, parent, NULL, false);
     setMap(bindings.lastShape());
 
+    JS_ASSERT(isCall());
+    JS_ASSERT(!inDictionaryMode());
+
     /*
      * If |bindings| is for a function that has extensible parents, that means
      * its Call should have its own shape; see js::BaseShape::extensibleParents.
      */
     if (lastProp->extensibleParents())
         return generateOwnShape(cx);
     return true;
 }
 
 /*
  * Initializer for cloned block objects. Set class, prototype, frame, map, and
  * shape.
  */
 inline bool
 JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame)
 {
-    init(cx, &js::BlockClass, type, NULL, frame, false);
+    init(cx, type, NULL, frame, false);
 
-    /* Cloned blocks copy their prototype's map; it had better be shareable. */
-    JS_ASSERT(!getProto()->inDictionaryMode());
     setMap(getProto()->lastProp);
 
+    JS_ASSERT(!inDictionaryMode());
+    JS_ASSERT(isClonedBlock());
+
     if (lastProp->extensibleParents())
         return generateOwnShape(cx);
     return true;
 }
 
 /*
  * Property read barrier for deferred cloning of compiler-created function
  * objects optimized as typically non-escaping, ad-hoc methods in obj.
@@ -762,24 +766,21 @@ JSObject::setType(js::types::TypeObject 
         JS_ASSERT(obj != this);
 #endif
     JS_ASSERT_IF(hasSpecialEquality(), newType->hasAnyFlags(js::types::OBJECT_FLAG_SPECIAL_EQUALITY));
     JS_ASSERT(!hasSingletonType());
     type_ = newType;
 }
 
 inline void
-JSObject::init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type,
+JSObject::init(JSContext *cx, js::types::TypeObject *type,
                JSObject *parent, void *priv, bool denseArray)
 {
-    clasp = aclasp;
     flags = capacity << FIXED_SLOTS_SHIFT;
 
-    JS_ASSERT(denseArray == (aclasp == &js::ArrayClass));
-
     privateData = priv;
 
     /*
      * Fill the fixed slots with undefined if needed.  This object must
      * already have its capacity filled in, as by js_NewGCObject. If inference
      * is disabled, NewArray will backfill holes up to the array's capacity
      * and unset the PACKED_ARRAY flag.
      */
@@ -808,25 +809,25 @@ JSObject::finish(JSContext *cx)
 inline bool
 JSObject::initSharingEmptyShape(JSContext *cx,
                                 js::Class *aclasp,
                                 js::types::TypeObject *type,
                                 JSObject *parent,
                                 void *privateValue,
                                 js::gc::AllocKind kind)
 {
-    init(cx, aclasp, type, parent, privateValue, false);
-
-    JS_ASSERT(!isDenseArray());
+    init(cx, type, parent, privateValue, false);
 
     js::EmptyShape *empty = type->getEmptyShape(cx, aclasp, kind);
     if (!empty)
         return false;
 
     setMap(empty);
+
+    JS_ASSERT(!isDenseArray());
     return true;
 }
 
 inline bool
 JSObject::hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags)
 {
     JSObject *pobj;
     JSProperty *prop;
@@ -1119,34 +1120,35 @@ static inline bool
 InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::TypeObject *type,
                    gc::AllocKind kind)
 {
     JS_ASSERT(clasp->isNative());
 
     /* Share proto's emptyShape only if obj is similar to proto. */
     js::EmptyShape *empty = NULL;
 
-    uint32 freeslot = JSSLOT_FREE(clasp);
-    if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot))
-        goto bad;
-
     if (type->canProvideEmptyShape(clasp))
         empty = type->getEmptyShape(cx, clasp, kind);
     else
         empty = js::EmptyShape::create(cx, clasp);
-    if (!empty)
-        goto bad;
+    if (!empty) {
+        JS_ASSERT(obj->isNewborn());
+        return false;
+    }
 
     obj->setMap(empty);
-    return true;
 
-  bad:
-    /* The GC nulls map initially. It should still be null on error. */
-    JS_ASSERT(obj->isNewborn());
-    return false;
+    uint32 freeslot = JSSLOT_FREE(clasp);
+    if (freeslot > obj->numSlots() && !obj->allocSlots(cx, freeslot)) {
+        obj->setMap(NULL);
+        JS_ASSERT(obj->isNewborn());
+        return false;
+    }
+
+    return true;
 }
 
 static inline bool
 InitNonNativeObject(JSContext *cx, JSObject *obj, js::Class *clasp)
 {
     JS_ASSERT(!clasp->isNative());
 
     js::EmptyShape *empty = js::BaseShape::lookupEmpty(cx, clasp);
@@ -1207,17 +1209,17 @@ NewNativeClassInstance(JSContext *cx, Cl
     if (!obj)
         return NULL;
 
     /*
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */
     bool denseArray = (clasp == &ArrayClass);
-    obj->init(cx, clasp, type, parent, NULL, denseArray);
+    obj->init(cx, type, parent, NULL, denseArray);
 
     JS_ASSERT(type->canProvideEmptyShape(clasp));
     js::EmptyShape *empty = type->getEmptyShape(cx, clasp, kind);
     if (!empty)
         return NULL;
 
     obj->setMap(empty);
 
@@ -1370,17 +1372,17 @@ NewObject(JSContext *cx, js::Class *clas
 
     /* This needs to match up with the size of JSFunction::data_padding. */
     JS_ASSERT_IF(isFunction, kind == gc::FINALIZE_OBJECT2);
 
     /*
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */
-    obj->init(cx, clasp, type,
+    obj->init(cx, type,
               (!parent && proto) ? proto->getParent() : parent,
               NULL, clasp == &ArrayClass);
 
     if (clasp->isNative()
         ? !InitScopeForObject(cx, obj, clasp, type, kind)
         : !InitNonNativeObject(cx, obj, clasp)) {
         obj = NULL;
     }
@@ -1457,17 +1459,17 @@ NewObjectWithType(JSContext *cx, types::
     JSObject* obj = js_NewGCObject(cx, kind);
     if (!obj)
         goto out;
 
     /*
      * Default parent to the parent of the prototype, which was set from
      * the parent of the prototype's constructor.
      */
-    obj->init(cx, &ObjectClass, type,
+    obj->init(cx, type,
               (!parent && type->proto) ? type->proto->getParent() : parent,
               NULL, false);
 
     if (!InitScopeForObject(cx, obj, &ObjectClass, type, kind)) {
         obj = NULL;
         goto out;
     }
 
@@ -1604,9 +1606,29 @@ PropDesc::checkSetter(JSContext *cx)
 } /* namespace js */
 
 inline JSObject *
 js_GetProtoIfDenseArray(JSObject *obj)
 {
     return obj->isDenseArray() ? obj->getProto() : obj;
 }
 
+inline js::Class *
+JSObject::getClass() const {
+    return lastProp->getClass();
+}
+
+inline JSClass *
+JSObject::getJSClass() const {
+    return Jsvalify(getClass());
+}
+
+inline bool
+JSObject::hasClass(const js::Class *c) const {
+    return getClass() == c;
+}
+
+inline const js::ObjectOps *
+JSObject::getOps() const {
+    return &getClass()->ops;
+}
+
 #endif /* jsobjinlines_h___ */
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -759,16 +759,19 @@ struct Shape : public js::gc::Cell
 #ifdef DEBUG
     void dump(JSContext *cx, FILE *fp) const;
     void dumpSubtree(JSContext *cx, int level, FILE *fp) const;
 #endif
 
     void finalize(JSContext *cx);
     void removeChild(js::Shape *child);
     void removeChildSlowly(js::Shape *child);
+
+    /* For JIT usage */
+    static inline size_t offsetOfBase() { return offsetof(Shape, base_); }
 };
 
 struct EmptyShape : public js::Shape
 {
     EmptyShape(BaseShape *base);
 
     static EmptyShape *create(JSContext *cx, js::Class *clasp) {
         BaseShape lookup(clasp);
@@ -787,18 +790,17 @@ struct EmptyShape : public js::Shape
         if (!shape) {
             if (!(shape = create(cx, clasp)))
                 return NULL;
             return *shapep = shape;
         }
         return shape;
     }
 
-    static inline EmptyShape *getEmptyArgumentsShape(JSContext *cx);
-
+    static inline EmptyShape *getEmptyArgumentsShape(JSContext *cx, bool strict);
     static inline EmptyShape *getEmptyBlockShape(JSContext *cx);
     static inline EmptyShape *getEmptyCallShape(JSContext *cx);
     static inline EmptyShape *getEmptyDeclEnvShape(JSContext *cx);
     static inline EmptyShape *getEmptyEnumeratorShape(JSContext *cx);
     static inline EmptyShape *getEmptyWithShape(JSContext *cx);
 };
 
 } /* namespace js */
--- a/js/src/jsscopeinlines.h
+++ b/js/src/jsscopeinlines.h
@@ -319,19 +319,21 @@ EmptyShape::EmptyShape(BaseShape *base)
   : js::Shape(base)
 {
     /* Only empty shapes can be NON_NATIVE. */
     if (!getClass()->isNative())
         flags |= NON_NATIVE;
 }
 
 /* static */ inline EmptyShape *
-EmptyShape::getEmptyArgumentsShape(JSContext *cx)
+EmptyShape::getEmptyArgumentsShape(JSContext *cx, bool strict)
 {
-    return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyArgumentsShape);
+    if (strict)
+        return ensure(cx, &StrictArgumentsObjectClass, &cx->compartment->emptyStrictArgumentsShape);
+    return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyNormalArgumentsShape);
 }
 
 /* static */ inline EmptyShape *
 EmptyShape::getEmptyBlockShape(JSContext *cx)
 {
     return ensure(cx, &BlockClass, &cx->compartment->emptyBlockShape);
 }
 
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -210,17 +210,16 @@ ArrayBuffer::create(JSContext *cx, int32
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH);
         return NULL;
     }
 
     JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass);
 
     if (!InitNonNativeObject(cx, obj, &ArrayBufferClass))
         return NULL;
-    obj->setClass(&ArrayBufferClass);
 
     /*
      * The first 8 bytes hold the length.
      * The rest of it is a flat data store for the array buffer.
      */
     if (!obj->allocateArrayBufferSlots(cx, nbytes))
         return NULL;
 
@@ -1285,17 +1284,16 @@ class TypedArrayTemplate
         JS_ASSERT(getByteOffset(obj) <= bufferByteLength);
         JS_ASSERT(getBuffer(obj)->arrayBufferDataOffset() <= getDataOffset(obj));
         JS_ASSERT(getDataOffset(obj) <= offsetData(obj, bufferByteLength));
 
         JS_ASSERT(obj->getClass() == slowClass());
 
         if (!InitNonNativeObject(cx, obj, fastClass()))
             return NULL;
-        obj->setClass(fastClass());
 
         // FIXME Bug 599008: make it ok to call preventExtensions here.
         obj->flags |= JSObject::NOT_EXTENSIBLE;
 
         return obj;
     }
 
     /*
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -189,21 +189,16 @@ static const JSC::MacroAssembler::Regist
         loadPtr(Address(obj, offsetof(JSObject, lastProp)), shape);
     }
 
     Jump guardShape(RegisterID objReg, JSObject *obj) {
         return branchPtr(NotEqual, Address(objReg, offsetof(JSObject, lastProp)),
                          ImmPtr(obj->lastProperty()));
     }
 
-    Jump testFunction(Condition cond, RegisterID fun) {
-        return branchPtr(cond, Address(fun, JSObject::offsetOfClassPointer()),
-                         ImmPtr(&FunctionClass));
-    }
-
     /*
      * Finds and returns the address of a known object and slot.
      */
     Address objSlotRef(JSObject *obj, RegisterID reg, uint32 slot) {
         move(ImmPtr(obj), reg);
         if (obj->isFixedSlot(slot)) {
             return Address(reg, JSObject::getFixedSlotOffset(slot));
         } else {
@@ -813,26 +808,34 @@ static const JSC::MacroAssembler::Regist
                                          Imm32(StackFrame::OVERFLOW_ARGS));
         move(Imm32(fun->nargs), reg);
         overflowArgs.linkTo(label(), this);
         lshiftPtr(Imm32(3), reg);
         negPtr(reg);
         addPtr(JSFrameReg, reg);
     }
 
-    void loadObjClass(RegisterID objReg, RegisterID destReg) {
-        loadPtr(Address(objReg, JSObject::offsetOfClassPointer()), destReg);
+    void loadObjClass(RegisterID obj, RegisterID dest) {
+        loadPtr(Address(obj, offsetof(JSObject, lastProp)), dest);
+        loadPtr(Address(dest, Shape::offsetOfBase()), dest);
+        loadPtr(Address(dest, offsetof(BaseShape, clasp)), dest);
     }
 
     Jump testClass(Condition cond, RegisterID claspReg, js::Class *clasp) {
         return branchPtr(cond, claspReg, ImmPtr(clasp));
     }
 
-    Jump testObjClass(Condition cond, RegisterID objReg, js::Class *clasp) {
-        return branchPtr(cond, Address(objReg, JSObject::offsetOfClassPointer()), ImmPtr(clasp));
+    Jump testObjClass(Condition cond, RegisterID obj, RegisterID temp, js::Class *clasp) {
+        loadPtr(Address(obj, offsetof(JSObject, lastProp)), temp);
+        loadPtr(Address(temp, Shape::offsetOfBase()), temp);
+        return branchPtr(cond, Address(temp, offsetof(BaseShape, clasp)), ImmPtr(clasp));
+    }
+
+    Jump testFunction(Condition cond, RegisterID fun, RegisterID temp) {
+        return testObjClass(cond, fun, temp, &js::FunctionClass);
     }
 
     void branchValue(Condition cond, RegisterID reg, int32 value, RegisterID result)
     {
         if (Registers::maskReg(result) & Registers::SingleByteRegs) {
             set32(cond, reg, Imm32(value), result);
         } else {
             Jump j = branch32(cond, reg, Imm32(value));
@@ -1289,17 +1292,16 @@ static const JSC::MacroAssembler::Regist
             addPtr(Imm32(-(int)sizeof(JSObject)), result);
         } else {
             JS_ASSERT(!templateObject->newType);
             addPtr(Imm32(-thingSize), result);
             storePtr(ImmPtr(NULL), Address(result, JSObject::offsetOfSlots()));
         }
 
         storePtr(ImmPtr(templateObject->lastProp), Address(result, offsetof(JSObject, lastProp)));
-        storePtr(ImmPtr(templateObject->getClass()), Address(result, JSObject::offsetOfClassPointer()));
         store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags)));
         storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType)));
         storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent)));
         storePtr(ImmPtr(templateObject->privateData), Address(result, offsetof(JSObject, privateData)));
         storePtr(ImmPtr((void *) templateObject->capacity), Address(result, offsetof(JSObject, capacity)));
         storePtr(ImmPtr(templateObject->type()), Address(result, JSObject::offsetOfType()));
 
         /* Fixed slots of non-array objects are required to be initialized. */
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -118,16 +118,17 @@ mjit::Compiler::Compiler(JSContext *cx, 
     callSites(CompilerAllocPolicy(cx, *thisFromCtor())),
     doubleList(CompilerAllocPolicy(cx, *thisFromCtor())),
     fixedIntToDoubleEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
     fixedDoubleToAnyEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
     jumpTables(CompilerAllocPolicy(cx, *thisFromCtor())),
     jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())),
     loopEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
     rootedObjects(CompilerAllocPolicy(cx, *thisFromCtor())),
+    denseArrayShape(NULL),
     stubcc(cx, *thisFromCtor(), frame),
     debugMode_(cx->compartment->debugMode()),
 #if defined JS_TRACER
     addTraceHints(cx->traceJitEnabled),
 #else
     addTraceHints(false),
 #endif
     inlining_(false),
@@ -991,16 +992,17 @@ mjit::Compiler::finishThisUp(JITScript *
     jit->invokeEntry = result;
     jit->singleStepMode = script->stepModeEnabled();
     if (script->hasFunction) {
         jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
         jit->argsCheckEntry = stubCode.locationOf(argsCheckLabel).executableAddress();
         jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
     }
     jit->pcLengths = pcLengths;
+    jit->denseArrayShape = denseArrayShape;
 
     /*
      * WARNING: mics(), callICs() et al depend on the ordering of these
      * variable-length sections.  See JITScript's declaration for details.
      */
 
     /* ICs can only refer to bytecodes in the outermost script, not inlined calls. */
     Label *jumpMap = a->jumpMap;
@@ -1308,20 +1310,20 @@ mjit::Compiler::finishThisUp(JITScript *
         to.idRemat = from.id;
 
         if (from.typeGuard.isSet()) {
             int inlineTypeGuard = fullCode.locationOf(from.typeGuard.get()) -
                                   fullCode.locationOf(from.fastPathStart);
             to.inlineTypeGuard = inlineTypeGuard;
             JS_ASSERT(to.inlineTypeGuard == inlineTypeGuard);
         }
-        int inlineClaspGuard = fullCode.locationOf(from.claspGuard) -
+        int inlineShapeGuard = fullCode.locationOf(from.shapeGuard) -
                                fullCode.locationOf(from.fastPathStart);
-        to.inlineClaspGuard = inlineClaspGuard;
-        JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard);
+        to.inlineShapeGuard = inlineShapeGuard;
+        JS_ASSERT(to.inlineShapeGuard == inlineShapeGuard);
 
         stubCode.patch(from.paramAddr, &to);
     }
 
     ic::SetElementIC *jitSetElems = (ic::SetElementIC *)cursor;
     jit->nSetElems = setElemICs.length();
     cursor += sizeof(ic::SetElementIC) * jit->nSetElems;
     for (size_t i = 0; i < jit->nSetElems; i++) {
@@ -1338,20 +1340,20 @@ mjit::Compiler::finishThisUp(JITScript *
         JS_ASSERT(to.objRemat == from.objRemat.toInt32());
 
         to.hasConstantKey = from.key.isConstant();
         if (from.key.isConstant())
             to.keyValue = from.key.index();
         else
             to.keyReg = from.key.reg();
 
-        int inlineClaspGuard = fullCode.locationOf(from.claspGuard) -
+        int inlineShapeGuard = fullCode.locationOf(from.shapeGuard) -
                                fullCode.locationOf(from.fastPathStart);
-        to.inlineClaspGuard = inlineClaspGuard;
-        JS_ASSERT(to.inlineClaspGuard == inlineClaspGuard);
+        to.inlineShapeGuard = inlineShapeGuard;
+        JS_ASSERT(to.inlineShapeGuard == inlineShapeGuard);
 
         int inlineHoleGuard = fullCode.locationOf(from.holeGuard) -
                                fullCode.locationOf(from.fastPathStart);
         to.inlineHoleGuard = inlineHoleGuard;
         JS_ASSERT(to.inlineHoleGuard == inlineHoleGuard);
 
         CheckIsStubCall(to.slowPathCall.labelAtOffset(0));
 
@@ -3315,25 +3317,35 @@ void
 mjit::Compiler::checkCallApplySpeculation(uint32 callImmArgc, uint32 speculatedArgc,
                                           FrameEntry *origCallee, FrameEntry *origThis,
                                           MaybeRegisterID origCalleeType, RegisterID origCalleeData,
                                           MaybeRegisterID origThisType, RegisterID origThisData,
                                           Jump *uncachedCallSlowRejoin, CallPatchInfo *uncachedCallPatch)
 {
     JS_ASSERT(IsLowerableFunCallOrApply(PC));
 
+    RegisterID temp;
+    Registers tempRegs(Registers::AvailRegs);
+    if (origCalleeType.isSet())
+        tempRegs.takeReg(origCalleeType.reg());
+    tempRegs.takeReg(origCalleeData);
+    if (origThisType.isSet())
+        tempRegs.takeReg(origThisType.reg());
+    tempRegs.takeReg(origThisData);
+    temp = tempRegs.takeAnyReg().reg();
+
     /*
      * if (origCallee.isObject() &&
      *     origCallee.toObject().isFunction &&
      *     origCallee.toObject().getFunctionPrivate() == js_fun_{call,apply})
      */
     MaybeJump isObj;
     if (origCalleeType.isSet())
         isObj = masm.testObject(Assembler::NotEqual, origCalleeType.reg());
-    Jump isFun = masm.testFunction(Assembler::NotEqual, origCalleeData);
+    Jump isFun = masm.testFunction(Assembler::NotEqual, origCalleeData, temp);
     masm.loadObjPrivate(origCalleeData, origCalleeData);
     Native native = *PC == JSOP_FUNCALL ? js_fun_call : js_fun_apply;
     Jump isNative = masm.branchPtr(Assembler::NotEqual,
                                    Address(origCalleeData, JSFunction::offsetOfNativeOrScript()),
                                    ImmPtr(JS_FUNC_TO_DATA_PTR(void *, native)));
 
     /*
      * If speculation fails, we can't use the ic, since it is compiled on the
@@ -3596,24 +3608,25 @@ mjit::Compiler::inlineCallHelper(uint32 
     RESERVE_OOL_SPACE(stubcc.masm);
 
     Jump rejoin1, rejoin2;
     {
         RESERVE_OOL_SPACE(stubcc.masm);
         stubcc.linkExitDirect(j, stubcc.masm.label());
         callIC.slowPathStart = stubcc.masm.label();
 
+        RegisterID tmp = tempRegs.takeAnyReg().reg();
+
         /*
          * Test if the callee is even a function. If this doesn't match, we
          * take a _really_ slow path later.
          */
-        Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, icCalleeData);
+        Jump notFunction = stubcc.masm.testFunction(Assembler::NotEqual, icCalleeData, tmp);
 
         /* Test if the function is scripted. */
-        RegisterID tmp = tempRegs.takeAnyReg().reg();
         stubcc.masm.loadObjPrivate(icCalleeData, funPtrReg);
         stubcc.masm.load16(Address(funPtrReg, offsetof(JSFunction, flags)), tmp);
         stubcc.masm.and32(Imm32(JSFUN_KINDMASK), tmp);
         Jump isNative = stubcc.masm.branch32(Assembler::Below, tmp, Imm32(JSFUN_INTERPRETED));
         tempRegs.putReg(tmp);
 
         /*
          * N.B. After this call, the frame will have a dynamic frame size.
@@ -5735,17 +5748,17 @@ mjit::Compiler::iterNext(ptrdiff_t offse
     RegisterID reg = frame.tempRegForData(fe);
 
     /* Is it worth trying to pin this longer? Prolly not. */
     frame.pinReg(reg);
     RegisterID T1 = frame.allocReg();
     frame.unpinReg(reg);
 
     /* Test clasp */
-    Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass);
+    Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, T1, &IteratorClass);
     stubcc.linkExit(notFast, Uses(1));
 
     /* Get private from iter obj. */
     masm.loadObjPrivate(reg, T1);
 
     RegisterID T3 = frame.allocReg();
     RegisterID T4 = frame.allocReg();
 
@@ -5790,17 +5803,17 @@ mjit::Compiler::iterMore(jsbytecode *tar
     if (!frame.syncForBranch(target, Uses(1)))
         return false;
 
     FrameEntry *fe = frame.peek(-1);
     RegisterID reg = frame.tempRegForData(fe);
     RegisterID tempreg = frame.allocReg();
 
     /* Test clasp */
-    Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass);
+    Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, tempreg, &IteratorClass);
     stubcc.linkExitForBranch(notFast);
 
     /* Get private from iter obj. */
     masm.loadObjPrivate(reg, reg);
 
     /* Test that the iterator supports fast iteration. */
     notFast = masm.branchTest32(Assembler::NonZero, Address(reg, offsetof(NativeIterator, flags)),
                                 Imm32(JSITER_FOREACH));
@@ -5829,17 +5842,17 @@ mjit::Compiler::iterEnd()
     FrameEntry *fe= frame.peek(-1);
     RegisterID reg = frame.tempRegForData(fe);
 
     frame.pinReg(reg);
     RegisterID T1 = frame.allocReg();
     frame.unpinReg(reg);
 
     /* Test clasp */
-    Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass);
+    Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, T1, &IteratorClass);
     stubcc.linkExit(notIterator, Uses(1));
 
     /* Get private from iter obj. */
     masm.loadObjPrivate(reg, T1);
 
     RegisterID T2 = frame.allocReg();
 
     /* Load flags. */
@@ -6089,37 +6102,39 @@ mjit::Compiler::jsop_callgname_epilogue(
      *         equal to the global of the current script, and
      *      2. bake in the global of the current script, which is why
      *         this optimized path requires compile-and-go.
      */
 
     /* If the callee is not an object, jump to the inline fast path. */
     MaybeRegisterID typeReg = frame.maybePinType(fval);
     RegisterID objReg = frame.copyDataIntoReg(fval);
+    RegisterID tempReg = frame.allocReg();
 
     MaybeJump isNotObj;
     if (!fval->isType(JSVAL_TYPE_OBJECT)) {
         isNotObj = frame.testObject(Assembler::NotEqual, fval);
         frame.maybeUnpinReg(typeReg);
     }
 
     /*
      * If the callee is not a function, jump to OOL slow path.
      */
-    Jump notFunction = masm.testFunction(Assembler::NotEqual, objReg);
+    Jump notFunction = masm.testFunction(Assembler::NotEqual, objReg, tempReg);
     stubcc.linkExit(notFunction, Uses(1));
 
     /*
      * If the callee's parent is not equal to the global, jump to
      * OOL slow path.
      */
     masm.loadPtr(Address(objReg, offsetof(JSObject, parent)), objReg);
     Jump globalMismatch = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(globalObj));
     stubcc.linkExit(globalMismatch, Uses(1));
     frame.freeReg(objReg);
+    frame.freeReg(tempReg);
 
     /* OOL stub call path. */
     stubcc.leave();
     OOL_STUBCALL(stubs::PushImplicitThisForGlobal, REJOIN_NONE);
 
     /* Fast path. */
     if (isNotObj.isSet())
         isNotObj.getJump().linkTo(masm.label(), &masm);
@@ -6287,20 +6302,24 @@ mjit::Compiler::jsop_instanceof()
     if (!rhs->isTypeKnown()) {
         Jump j = frame.testObject(Assembler::NotEqual, rhs);
         stubcc.linkExit(j, Uses(2));
     }
 
     frame.forgetMismatchedObject(lhs);
     frame.forgetMismatchedObject(rhs);
 
+    RegisterID tmp = frame.allocReg();
     RegisterID obj = frame.tempRegForData(rhs);
-    Jump notFunction = masm.testFunction(Assembler::NotEqual, obj);
+
+    Jump notFunction = masm.testFunction(Assembler::NotEqual, obj, tmp);
     stubcc.linkExit(notFunction, Uses(2));
 
+    frame.freeReg(tmp);
+
     /* Test for bound functions. */
     Jump isBound = masm.branchTest32(Assembler::NonZero, Address(obj, offsetof(JSObject, flags)),
                                      Imm32(JSObject::BOUND_FUNCTION));
     {
         stubcc.linkExit(isBound, Uses(2));
         stubcc.leave();
         OOL_STUBCALL(stubs::InstanceOf, REJOIN_FALLTHROUGH);
         firstSlow = stubcc.masm.jump();
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -209,27 +209,27 @@ class Compiler : public BaseCompiler
 
     struct GetElementICInfo : public BaseICInfo {
         GetElementICInfo(JSOp op) : BaseICInfo(op)
         { }
         RegisterID  typeReg;
         RegisterID  objReg;
         ValueRemat  id;
         MaybeJump   typeGuard;
-        Jump        claspGuard;
+        Jump        shapeGuard;
     };
 
     struct SetElementICInfo : public BaseICInfo {
         SetElementICInfo(JSOp op) : BaseICInfo(op)
         { }
         RegisterID  objReg;
         StateRemat  objRemat;
         ValueRemat  vr;
         Jump        capacityGuard;
-        Jump        claspGuard;
+        Jump        shapeGuard;
         Jump        holeGuard;
         Int32Key    key;
         uint32      volatileMask;
     };
 
     struct PICGenInfo : public BaseICInfo {
         PICGenInfo(ic::PICInfo::Kind kind, JSOp op, bool usePropCache)
           : BaseICInfo(op), kind(kind), usePropCache(usePropCache), typeMonitored(false)
@@ -431,16 +431,17 @@ class Compiler : public BaseCompiler
     js::Vector<InternalCallSite, 64, CompilerAllocPolicy> callSites;
     js::Vector<DoublePatch, 16, CompilerAllocPolicy> doubleList;
     js::Vector<uint32> fixedIntToDoubleEntries;
     js::Vector<uint32> fixedDoubleToAnyEntries;
     js::Vector<JumpTable, 16> jumpTables;
     js::Vector<uint32, 16> jumpTableOffsets;
     js::Vector<LoopEntry, 16> loopEntries;
     js::Vector<JSObject *, 0, CompilerAllocPolicy> rootedObjects;
+    Shape *denseArrayShape;
     StubCompiler stubcc;
     Label invokeLabel;
     Label arityLabel;
     Label argsCheckLabel;
 #ifdef JS_MONOIC
     Label argsCheckStub;
     Label argsCheckFallthrough;
     Jump argsCheckJump;
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -1550,19 +1550,27 @@ mjit::Compiler::jsop_setelem(bool popGua
     RESERVE_IC_SPACE(masm);
     ic.fastPathStart = masm.label();
 
     // Create the common out-of-line sync block, taking care to link previous
     // guards here after.
     RESERVE_OOL_SPACE(stubcc.masm);
     ic.slowPathStart = stubcc.syncExit(Uses(3));
 
+    if (!denseArrayShape) {
+        denseArrayShape = BaseShape::lookupEmpty(cx, &ArrayClass);
+        if (!denseArrayShape)
+            return false;
+    }
+
     // Guard obj is a dense array.
-    ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass);
-    stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
+    ic.shapeGuard = masm.branchPtr(Assembler::NotEqual,
+                                   Address(ic.objReg, offsetof(JSObject, lastProp)),
+                                   ImmPtr(denseArrayShape));
+    stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
 
     // Guard in range of initialized length.
     Jump initlenGuard = masm.guardArrayExtent(offsetof(JSObject, initializedLength),
                                               ic.objReg, ic.key, Assembler::BelowOrEqual);
     stubcc.linkExitDirect(initlenGuard, ic.slowPathStart);
 
     // Load the dynamic slots vector.
     masm.loadPtr(Address(ic.objReg, offsetof(JSObject, slots)), ic.objReg);
@@ -2103,19 +2111,27 @@ mjit::Compiler::jsop_getelem(bool isCall
 
     if (id->mightBeType(JSVAL_TYPE_INT32)) {
         // Always test the type first (see comment in PolyIC.h).
         if (!id->isTypeKnown()) {
             ic.typeGuard = masm.testInt32(Assembler::NotEqual, ic.typeReg);
             stubcc.linkExitDirect(ic.typeGuard.get(), ic.slowPathStart);
         }
 
-        // Guard on the clasp.
-        ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass);
-        stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
+        if (!denseArrayShape) {
+            denseArrayShape = BaseShape::lookupEmpty(cx, &ArrayClass);
+            if (!denseArrayShape)
+                return false;
+        }
+
+        // Guard obj is a dense array.
+        ic.shapeGuard = masm.branchPtr(Assembler::NotEqual,
+                                       Address(ic.objReg, offsetof(JSObject, lastProp)),
+                                       ImmPtr(denseArrayShape));
+        stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
 
         Int32Key key = id->isConstant()
                        ? Int32Key::FromConstant(id->getValue().toInt32())
                        : Int32Key::FromRegister(ic.id.dataReg());
 
         Assembler::FastArrayLoadFails fails =
             masm.fastArrayLoad(ic.objReg, key, ic.typeReg, ic.objReg);
 
@@ -2127,18 +2143,18 @@ mjit::Compiler::jsop_getelem(bool isCall
             frame.freeReg(thisReg.reg());
         }
 
         stubcc.linkExitDirect(fails.rangeCheck, ic.slowPathStart);
         stubcc.linkExitDirect(fails.holeCheck, ic.slowPathStart);
     } else {
         // The type is known to not be dense-friendly ahead of time, so always
         // fall back to a slow path.
-        ic.claspGuard = masm.jump();
-        stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart);
+        ic.shapeGuard = masm.jump();
+        stubcc.linkExitDirect(ic.shapeGuard, ic.slowPathStart);
     }
 
     stubcc.leave();
     if (objTypeGuard.isSet())
         objTypeGuard.get().linkTo(stubcc.masm.label(), &stubcc.masm);
 #ifdef JS_POLYIC
     passICAddress(&ic);
     if (isCall)
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -1320,11 +1320,14 @@ JITScript::trace(JSTracer *trc)
      * to maintain references to any scripts whose code was inlined into this.
      */
     InlineFrame *inlineFrames_ = inlineFrames();
     for (unsigned i = 0; i < nInlineFrames; i++)
         MarkObject(trc, *inlineFrames_[i].fun, "jitscript_fun");
 
     for (uint32 i = 0; i < nRootedObjects; ++i)
         MarkObject(trc, *rootedObjects()[i], "mjit rooted object");
+
+    if (denseArrayShape)
+        MarkShape(trc, denseArrayShape, "mjit rooted shape");
 }
 
 /* static */ const double mjit::Assembler::oneDouble = 1.0;
--- a/js/src/methodjit/MethodJIT.h
+++ b/js/src/methodjit/MethodJIT.h
@@ -635,16 +635,19 @@ struct JITScript {
     // Additional ExecutablePools that IC stubs were generated into.
     typedef Vector<JSC::ExecutablePool *, 0, SystemAllocPolicy> ExecPoolVector;
     ExecPoolVector execPools;
 #endif
 
     // Additional ExecutablePools for native call and getter stubs.
     Vector<NativeCallStub, 0, SystemAllocPolicy> nativeCallStubs;
 
+    // Rooted shape for dense arrays. :XXX: bug 685358 remove
+    Shape *denseArrayShape;
+
     NativeMapEntry *nmap() const;
     js::mjit::InlineFrame *inlineFrames() const;
     js::mjit::CallSite *callSites() const;
     JSObject **rootedObjects() const;
 #ifdef JS_MONOIC
     ic::GetGlobalNameIC *getGlobalNames() const;
     ic::SetGlobalNameIC *setGlobalNames() const;
     ic::CallICInfo *callICs() const;
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -738,17 +738,17 @@ class CallCompiler : public BaseCompiler
         Assembler masm;
 
         Registers tempRegs(Registers::AvailRegs);
         tempRegs.takeReg(ic.funObjReg);
 
         RegisterID t0 = tempRegs.takeAnyReg().reg();
 
         /* Guard that it's actually a function object. */
-        Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &FunctionClass);
+        Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, t0, &FunctionClass);
 
         /* Guard that it's the same function. */
         JSFunction *fun = obj->getFunctionPrivate();
         masm.loadObjPrivate(ic.funObjReg, t0);
         Jump funGuard = masm.branchPtr(Assembler::NotEqual, t0, ImmPtr(fun));
         Jump done = masm.jump();
 
         LinkerHelper linker(masm, JSC::METHOD_CODE);
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -810,17 +810,17 @@ class GetPropCompiler : public PICStubCo
         FunctionPtr target(JS_FUNC_TO_DATA_PTR(void *, stub));
         repatcher.relink(pic.slowPathCall, target);
     }
 
     LookupStatus generateArgsLengthStub()
     {
         Assembler masm;
 
-        Jump notArgs = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
+        Jump notArgs = masm.guardShape(pic.objReg, obj);
 
         masm.load32(Address(pic.objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), pic.objReg);
         masm.move(pic.objReg, pic.shapeReg);
         Jump overridden = masm.branchTest32(Assembler::NonZero, pic.shapeReg,
                                             Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
         masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), pic.objReg);
 
         masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
@@ -891,17 +891,17 @@ class GetPropCompiler : public PICStubCo
 
         return Lookup_Cacheable;
     }
 
     LookupStatus generateStringObjLengthStub()
     {
         Assembler masm;
 
-        Jump notStringObj = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
+        Jump notStringObj = masm.guardShape(pic.objReg, obj);
 
         masm.loadPayload(Address(pic.objReg, JSObject::getPrimitiveThisOffset()), pic.objReg);
         masm.loadPtr(Address(pic.objReg, JSString::offsetOfLengthAndFlags()), pic.objReg);
         masm.urshift32(Imm32(JSString::LENGTH_SHIFT), pic.objReg);
         masm.move(ImmType(JSVAL_TYPE_INT32), pic.shapeReg);
         Jump done = masm.jump();
 
         pic.updatePCCounters(cx, masm);
@@ -1180,17 +1180,19 @@ class GetPropCompiler : public PICStubCo
 
         Label start;
         Jump shapeGuardJump;
         Jump argsLenGuard;
 
         bool setStubShapeOffset = true;
         if (obj->isDenseArray()) {
             start = masm.label();
-            shapeGuardJump = masm.testObjClass(Assembler::NotEqual, pic.objReg, obj->getClass());
+            shapeGuardJump = masm.branchPtr(Assembler::NotEqual,
+                                            Address(pic.objReg, offsetof(JSObject, lastProp)),
+                                            ImmPtr(obj->lastProperty()));
 
             /*
              * No need to assert validity of GETPROP_STUB_SHAPE_JUMP in this case:
              * the IC is disabled after a dense array hit, so no patching can occur.
              */
 #ifndef JS_HAS_IC_LABELS
             setStubShapeOffset = false;
 #endif
@@ -2326,18 +2328,18 @@ GetElementIC::error(JSContext *cx)
 }
 
 void
 GetElementIC::purge(Repatcher &repatcher)
 {
     // Repatch the inline jumps.
     if (inlineTypeGuardPatched)
         repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), slowPathStart);
-    if (inlineClaspGuardPatched)
-        repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart);
+    if (inlineShapeGuardPatched)
+        repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), slowPathStart);
 
     if (slowCallPatched) {
         if (op == JSOP_GETELEM) {
             repatcher.relink(slowPathCall,
                              FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::GetElement)));
         } else if (op == JSOP_CALLELEM) {
             repatcher.relink(slowPathCall,
                              FunctionPtr(JS_FUNC_TO_DATA_PTR(void *, ic::CallElement)));
@@ -2387,23 +2389,18 @@ GetElementIC::attachGetProp(VMFrame &f, 
         masm.loadShape(objReg, typeReg);
         typeRegHasBaseShape = true;
     }
 
     MaybeJump atomIdGuard;
     if (!idRemat.isConstant())
         atomIdGuard = masm.branchPtr(Assembler::NotEqual, idRemat.dataReg(), ImmPtr(v.toString()));
 
-    // Guard on the base shape (or in the dense array case, the clasp).
-    Jump shapeGuard;
-    if (obj->isDenseArray()) {
-        shapeGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass());
-    } else {
-        shapeGuard = masm.branchPtr(Assembler::NotEqual, typeReg, ImmPtr(obj->lastProperty()));
-    }
+    // Guard on the base shape.
+    Jump shapeGuard = masm.branchPtr(Assembler::NotEqual, typeReg, ImmPtr(obj->lastProperty()));
 
     // Guard on the prototype, if applicable.
     MaybeJump protoGuard;
     JSObject *holder = getprop.holder;
     RegisterID holderReg = objReg;
     if (obj != holder) {
         // Bake in the holder identity. Careful not to clobber |objReg|, since we can't remat it.
         holderReg = typeReg;
@@ -2450,38 +2447,38 @@ GetElementIC::attachGetProp(VMFrame &f, 
     char *chars = DeflateString(cx, v.toString()->getChars(cx), v.toString()->length());
     JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom %p (\"%s\") shape %p (%s: %d)\n",
                js_CodeName[op], cs.executableAddress(), (void*)JSID_TO_ATOM(id), chars,
                holder->lastProperty(), cx->fp()->script()->filename, CurrentLine(cx));
     cx->free_(chars);
 #endif
 
     // Update the inline guards, if needed.
-    if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalClaspGuard()) {
+    if (shouldPatchInlineTypeGuard() || shouldPatchUnconditionalShapeGuard()) {
         Repatcher repatcher(cx->fp()->jit());
 
         if (shouldPatchInlineTypeGuard()) {
             // A type guard is present in the inline path, and this is the
             // first string stub, so patch it now.
             JS_ASSERT(!inlineTypeGuardPatched);
             JS_ASSERT(atomTypeGuard.isSet());
 
             repatcher.relink(fastPathStart.jumpAtOffset(inlineTypeGuard), cs);
             inlineTypeGuardPatched = true;
         }
 
-        if (shouldPatchUnconditionalClaspGuard()) {
-            // The clasp guard is unconditional, meaning there is no type
+        if (shouldPatchUnconditionalShapeGuard()) {
+            // The shape guard is unconditional, meaning there is no type
             // check. This is the first stub, so it has to be patched. Note
-            // that it is wrong to patch the inline clasp guard otherwise,
+            // that it is wrong to patch the inline shape guard otherwise,
             // because it follows an integer-id guard.
             JS_ASSERT(!hasInlineTypeGuard());
 
-            repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs);
-            inlineClaspGuardPatched = true;
+            repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
+            inlineShapeGuardPatched = true;
         }
     }
 
     // If there were previous stub guards, patch them now.
     if (hasLastStringStub) {
         Repatcher repatcher(lastStringStub);
         CodeLocationLabel stub(lastStringStub.start());
         if (atomGuard)
@@ -2531,17 +2528,17 @@ GetElementIC::attachArguments(JSContext 
 
     if (op == JSOP_CALLELEM)
         return disable(cx, "arguments object with call");
 
     JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32);
 
     Assembler masm;
 
-    Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass());
+    Jump shapeGuard = masm.guardShape(objReg, obj);
 
     masm.move(objReg, typeReg);
     masm.load32(Address(objReg, JSObject::getFixedSlotOffset(ArgumentsObject::INITIAL_LENGTH_SLOT)), 
                 objReg);
     Jump overridden = masm.branchTest32(Assembler::NonZero, objReg,
                                         Imm32(ArgumentsObject::LENGTH_OVERRIDDEN_BIT));
     masm.rshift32(Imm32(ArgumentsObject::PACKED_BITS_COUNT), objReg);
 
@@ -2637,34 +2634,34 @@ GetElementIC::attachArguments(JSContext 
     PICLinker buffer(masm, *this);
 
     if (!buffer.init(cx))
         return error(cx);
 
     if (!buffer.verifyRange(cx->fp()->jit()))
         return disable(cx, "code memory is out of range");
 
-    buffer.link(claspGuard, slowPathStart);
+    buffer.link(shapeGuard, slowPathStart);
     buffer.link(overridden, slowPathStart);
     buffer.link(outOfBounds, slowPathStart);
     buffer.link(holeCheck, slowPathStart);
     buffer.link(done, fastPathRejoin);    
     buffer.link(done2, fastPathRejoin);
     
     CodeLocationLabel cs = buffer.finalizeCodeAddendum();
 
     JaegerSpew(JSpew_PICs, "generated getelem arguments stub at %p\n", cs.executableAddress());
 
     Repatcher repatcher(cx->fp()->jit());
-    repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs);
-
-    JS_ASSERT(!shouldPatchUnconditionalClaspGuard());
-    JS_ASSERT(!inlineClaspGuardPatched);
-
-    inlineClaspGuardPatched = true;
+    repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
+
+    JS_ASSERT(!shouldPatchUnconditionalShapeGuard());
+    JS_ASSERT(!inlineShapeGuardPatched);
+
+    inlineShapeGuardPatched = true;
     stubsGenerated++;
 
     if (stubsGenerated == MAX_GETELEM_IC_STUBS)
         disable(cx, "max stubs reached");
 
     disable(cx, "generated arguments stub");
 
     if (!obj->getGeneric(cx, id, vp))
@@ -2678,24 +2675,24 @@ LookupStatus
 GetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp)
 {
     if (!v.isInt32())
         return disable(cx, "typed array with string key");
 
     if (op == JSOP_CALLELEM)
         return disable(cx, "typed array with call");
 
-    // The fast-path guarantees that after the dense clasp guard, the type is
+    // The fast-path guarantees that after the dense shape guard, the type is
     // known to be int32, either via type inference or the inline type check.
     JS_ASSERT(hasInlineTypeGuard() || idRemat.knownType() == JSVAL_TYPE_INT32);
 
     Assembler masm;
 
-    // Guard on this typed array's clasp.
-    Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass());
+    // Guard on this typed array's shape/class.
+    Jump shapeGuard = masm.guardShape(objReg, obj);
 
     // Bounds check.
     Jump outOfBounds;
     Address typedArrayLength(objReg, TypedArray::lengthOffset());
     if (idRemat.isConstant()) {
         JS_ASSERT(idRemat.value().toInt32() == v.toInt32());
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(v.toInt32()));
     } else {
@@ -2719,31 +2716,31 @@ GetElementIC::attachTypedArray(JSContext
 
     PICLinker buffer(masm, *this);
     if (!buffer.init(cx))
         return error(cx);
 
     if (!buffer.verifyRange(cx->fp()->jit()))
         return disable(cx, "code memory is out of range");
 
-    buffer.link(claspGuard, slowPathStart);
+    buffer.link(shapeGuard, slowPathStart);
     buffer.link(outOfBounds, slowPathStart);
     buffer.link(done, fastPathRejoin);
 
     CodeLocationLabel cs = buffer.finalizeCodeAddendum();
     JaegerSpew(JSpew_PICs, "generated getelem typed array stub at %p\n", cs.executableAddress());
 
-    // If we can generate a typed array stub, the clasp guard is conditional.
+    // If we can generate a typed array stub, the shape guard is conditional.
     // Also, we only support one typed array.
-    JS_ASSERT(!shouldPatchUnconditionalClaspGuard());
-    JS_ASSERT(!inlineClaspGuardPatched);
+    JS_ASSERT(!shouldPatchUnconditionalShapeGuard());
+    JS_ASSERT(!inlineShapeGuardPatched);
 
     Repatcher repatcher(cx->fp()->jit());
-    repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs);
-    inlineClaspGuardPatched = true;
+    repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
+    inlineShapeGuardPatched = true;
 
     stubsGenerated++;
 
     // In the future, it might make sense to attach multiple typed array stubs.
     // For simplicitly, they are currently monomorphic.
     if (stubsGenerated == MAX_GETELEM_IC_STUBS)
         disable(cx, "max stubs reached");
 
@@ -2909,18 +2906,18 @@ SetElementIC::error(JSContext *cx)
     disable(cx, "error");
     return Lookup_Error;
 }
 
 void
 SetElementIC::purge(Repatcher &repatcher)
 {
     // Repatch the inline jumps.
-    if (inlineClaspGuardPatched)
-        repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), slowPathStart);
+    if (inlineShapeGuardPatched)
+        repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), slowPathStart);
     if (inlineHoleGuardPatched)
         repatcher.relink(fastPathStart.jumpAtOffset(inlineHoleGuard), slowPathStart);
 
     if (slowCallPatched) {
         void *stub = JS_FUNC_TO_DATA_PTR(void *, APPLY_STRICTNESS(ic::SetElement, strictMode));
         repatcher.relink(slowPathCall, FunctionPtr(stub));
     }
 
@@ -3023,23 +3020,23 @@ SetElementIC::attachHoleStub(JSContext *
 
     return Lookup_Cacheable;
 }
 
 #if defined JS_METHODJIT_TYPED_ARRAY
 LookupStatus
 SetElementIC::attachTypedArray(JSContext *cx, JSObject *obj, int32 key)
 {
-    // Right now, only one clasp guard extension is supported.
-    JS_ASSERT(!inlineClaspGuardPatched);
+    // Right now, only one shape guard extension is supported.
+    JS_ASSERT(!inlineShapeGuardPatched);
 
     Assembler masm;
 
-    // Guard on this typed array's clasp.
-    Jump claspGuard = masm.testObjClass(Assembler::NotEqual, objReg, obj->getClass());
+    // Guard on this typed array's shape.
+    Jump shapeGuard = masm.guardShape(objReg, obj);
 
     // Bounds check.
     Jump outOfBounds;
     Address typedArrayLength(objReg, TypedArray::lengthOffset());
     if (hasConstantKey)
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, Imm32(keyValue));
     else
         outOfBounds = masm.branch32(Assembler::BelowOrEqual, typedArrayLength, keyReg);
@@ -3084,27 +3081,27 @@ SetElementIC::attachTypedArray(JSContext
     execPool = buffer.init(cx);
     if (!execPool)
         return error(cx);
 
     if (!buffer.verifyRange(cx->fp()->jit()))
         return disable(cx, "code memory is out of range");
 
     // Note that the out-of-bounds path simply does nothing.
-    buffer.link(claspGuard, slowPathStart);
+    buffer.link(shapeGuard, slowPathStart);
     buffer.link(outOfBounds, fastPathRejoin);
     buffer.link(done, fastPathRejoin);
     masm.finalize(buffer);
 
     CodeLocationLabel cs = buffer.finalizeCodeAddendum();
     JaegerSpew(JSpew_PICs, "generated setelem typed array stub at %p\n", cs.executableAddress());
 
     Repatcher repatcher(cx->fp()->jit());
-    repatcher.relink(fastPathStart.jumpAtOffset(inlineClaspGuard), cs);
-    inlineClaspGuardPatched = true;
+    repatcher.relink(fastPathStart.jumpAtOffset(inlineShapeGuard), cs);
+    inlineShapeGuardPatched = true;
 
     stubsGenerated++;
 
     // In the future, it might make sense to attach multiple typed array stubs.
     // For simplicitly, they are currently monomorphic.
     if (stubsGenerated == MAX_GETELEM_IC_STUBS)
         disable(cx, "max stubs reached");
 
--- a/js/src/methodjit/PolyIC.h
+++ b/js/src/methodjit/PolyIC.h
@@ -231,32 +231,32 @@ struct GetElementIC : public BasePolyIC 
     // On stub entry, objReg contains the object pointer for the |obj| parameter.
     // On stub exit, objReg must contain the payload of the result value.
     RegisterID objReg    : 5;
 
     // Offset from the fast path to the inline type check.
     // This is only set if hasInlineTypeCheck() is true.
     unsigned inlineTypeGuard  : 8;
 
-    // Offset from the fast path to the inline clasp guard. This is always
+    // Offset from the fast path to the inline shape guard. This is always
     // set; if |id| is known to not be int32, then it's an unconditional
     // jump to the slow path.
-    unsigned inlineClaspGuard : 8;
+    unsigned inlineShapeGuard : 8;
 
     // This is usable if hasInlineTypeGuard() returns true, which implies
     // that a dense array fast path exists. The inline type guard serves as
     // the head of the chain of all string-based element stubs.
     bool inlineTypeGuardPatched : 1;
 
-    // This is always usable, and specifies whether the inline clasp guard
+    // This is always usable, and specifies whether the inline shape guard
     // has been patched. If hasInlineTypeGuard() is true, it guards against
     // a dense array, and guarantees the inline type guard has passed.
-    // Otherwise, there is no inline type guard, and the clasp guard is just
+    // Otherwise, there is no inline type guard, and the shape guard is just
     // an unconditional jump.
-    bool inlineClaspGuardPatched : 1;
+    bool inlineShapeGuardPatched : 1;
 
     ////////////////////////////////////////////
     // State for string-based property stubs. //
     ////////////////////////////////////////////
 
     // True if typeReg is guaranteed to have the shape of objReg.
     bool typeRegHasBaseShape : 1;
 
@@ -280,28 +280,28 @@ struct GetElementIC : public BasePolyIC 
     ValueRemat idRemat;
 
     bool hasInlineTypeGuard() const {
         return !idRemat.isTypeKnown();
     }
     bool shouldPatchInlineTypeGuard() {
         return hasInlineTypeGuard() && !inlineTypeGuardPatched;
     }
-    bool shouldPatchUnconditionalClaspGuard() {
-        // The clasp guard is only unconditional if the type is known to not
+    bool shouldPatchUnconditionalShapeGuard() {
+        // The shape guard is only unconditional if the type is known to not
         // be an int32.
         if (idRemat.isTypeKnown() && idRemat.knownType() != JSVAL_TYPE_INT32)
-            return !inlineClaspGuardPatched;
+            return !inlineShapeGuardPatched;
         return false;
     }
 
     void reset() {
         BasePolyIC::reset();
         inlineTypeGuardPatched = false;
-        inlineClaspGuardPatched = false;
+        inlineShapeGuardPatched = false;
         typeRegHasBaseShape = false;
         hasLastStringStub = false;
     }
     void purge(Repatcher &repatcher);
     LookupStatus update(VMFrame &f, JSContext *cx, JSObject *obj, const Value &v, jsid id, Value *vp);
     LookupStatus attachGetProp(VMFrame &f, JSContext *cx, JSObject *obj, const Value &v, jsid id,
                                Value *vp);
     LookupStatus attachArguments(JSContext *cx, JSObject *obj, const Value &v, jsid id,
@@ -324,21 +324,21 @@ struct SetElementIC : public BaseIC {
     //   objReg contains the payload of the |obj| parameter.
     // On stub exit:
     //   objReg may be clobbered.
     RegisterID objReg    : 5;
 
     // Information on how to rematerialize |objReg|.
     int32 objRemat       : MIN_STATE_REMAT_BITS;
 
-    // Offset from the start of the fast path to the inline clasp guard.
-    unsigned inlineClaspGuard : 6;
+    // Offset from the start of the fast path to the inline shape guard.
+    unsigned inlineShapeGuard : 6;
 
-    // True if the clasp guard has been patched; false otherwise.
-    bool inlineClaspGuardPatched : 1;
+    // True if the shape guard has been patched; false otherwise.
+    bool inlineShapeGuardPatched : 1;
 
     // Offset from the start of the fast path to the inline hole guard.
     unsigned inlineHoleGuard : 8;
 
     // True if the capacity guard has been patched; false otherwise.
     bool inlineHoleGuardPatched : 1;
 
     // True if this is from a strict-mode script.
@@ -362,17 +362,17 @@ struct SetElementIC : public BaseIC {
     // Optional executable pool for the out-of-line hole stub.
     JSC::ExecutablePool *execPool;
 
     void reset() {
         BaseIC::reset();
         if (execPool != NULL)
             execPool->release();
         execPool = NULL;
-        inlineClaspGuardPatched = false;
+        inlineShapeGuardPatched = false;
         inlineHoleGuardPatched = false;
     }
     void purge(Repatcher &repatcher);
     LookupStatus attachTypedArray(JSContext *cx, JSObject *obj, int32 key);
     LookupStatus attachHoleStub(JSContext *cx, JSObject *obj, int32 key);
     LookupStatus update(JSContext *cx, const Value &objval, const Value &idval);
     LookupStatus disable(JSContext *cx, const char *reason);
     LookupStatus error(JSContext *cx);
--- a/js/src/tracejit/Writer.cpp
+++ b/js/src/tracejit/Writer.cpp
@@ -405,17 +405,18 @@ void ValidateWriter::checkAccSet(LOpcode
       // base = <JSObject>
       // ins  = ldp.obj<field> base[offsetof(JSObject, <field>)]
       #define OK_OBJ_FIELD(ldop, field) \
             ((op == (ldop)) && \
             (disp == offsetof(JSObject, field)) && \
             couldBeObjectOrString(base))
 
       case ACCSET_OBJ_CLASP:
-        ok = OK_OBJ_FIELD(LIR_ldp, clasp);
+        ok = false;
+        //ok = OK_OBJ_FIELD(LIR_ldp, clasp);
         break;
 
       case ACCSET_OBJ_FLAGS:
         ok = OK_OBJ_FIELD(LIR_ldi, flags);
         break;
 
       case ACCSET_OBJ_SHAPE:
         ok = true; // OK_OBJ_FIELD(LIR_ldi, objShape);
--- a/js/src/tracejit/Writer.h
+++ b/js/src/tracejit/Writer.h
@@ -475,17 +475,18 @@ class Writer
     nj::LIns *ldiRuntimeProtoHazardShape(nj::LIns *runtime) const {
         JS_NOT_REACHED("FIXME");
         return name(lir->insLoad(nj::LIR_ldi, runtime, 0,
                                  ACCSET_RUNTIME),
                     "protoHazardShape");
     }
 
     nj::LIns *ldpObjClasp(nj::LIns *obj, nj::LoadQual loadQual) const {
-        return name(lir->insLoad(nj::LIR_ldp, obj, JSObject::offsetOfClassPointer(), ACCSET_OBJ_CLASP,
+        JS_NOT_REACHED("FIXME");
+        return name(lir->insLoad(nj::LIR_ldp, obj, 0, ACCSET_OBJ_CLASP,
                                  loadQual),
                     "clasp");
     }
 
     nj::LIns *ldiObjFlags(nj::LIns *obj) const {
         return name(lir->insLoad(nj::LIR_ldi, obj, offsetof(JSObject, flags), ACCSET_OBJ_FLAGS),
                     "flags");
     }