Bug 771026 - Replace JSProperty with Shape (r=bhackett)
☠☠ backed out by 76fd67373e89 ☠ ☠
authorBill McCloskey <wmccloskey@mozilla.com>
Wed, 04 Jul 2012 19:34:06 -0700
changeset 98387 fe305819d2f26c9dbef649f0de0088152476209c
parent 98386 fbd96a0bcc002b25656174adc1a499ced1df7f70
child 98388 76fd67373e897d6407d73b4bb3bb1b18e27ed13b
push id11465
push usereakhgari@mozilla.com
push dateThu, 05 Jul 2012 15:14:00 +0000
treeherdermozilla-inbound@f4e2d7842325 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs771026
milestone16.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
Bug 771026 - Replace JSProperty with Shape (r=bhackett)
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsclass.h
js/src/jsclone.cpp
js/src/jsinterp.cpp
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsproxy.cpp
js/src/jsprvtd.h
js/src/jsscope.cpp
js/src/jsscope.h
js/src/jstypedarray.cpp
js/src/jstypedarray.h
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/ScopeObject.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3392,41 +3392,39 @@ JS_DeepFreezeObject(JSContext *cx, JSObj
             return false;
     }
 
     return true;
 }
 
 static JSBool
 LookupPropertyById(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                   MutableHandleObject objp, JSProperty **propp)
+                   MutableHandleObject objp, MutableHandleShape propp)
 {
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     JSAutoResolveFlags rf(cx, flags);
     return obj->lookupGeneric(cx, id, objp, propp);
 }
 
 #define AUTO_NAMELEN(s,n)   (((n) == (size_t)-1) ? js_strlen(s) : (n))
 
 static JSBool
 LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, jsid id,
-             JSProperty* prop, Value *vp)
-{
-    if (!prop) {
+             HandleShape shape, Value *vp)
+{
+    if (!shape) {
         /* XXX bad API: no way to tell "not defined" from "void value" */
         vp->setUndefined();
         return JS_TRUE;
     }
 
     if (obj2->isNative()) {
-        Shape *shape = (Shape *) prop;
-
         /* Peek at the native property's slot value, without doing a Get. */
         if (shape->hasSlot()) {
             *vp = obj2->nativeGetSlot(shape->slot());
             return true;
         }
     } else {
         if (obj2->isDenseArray())
             return js_GetDenseArrayElementValue(cx, obj2, id, vp);
@@ -3447,17 +3445,17 @@ LookupResult(JSContext *cx, HandleObject
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LookupPropertyById(JSContext *cx, JSObject *obj_, jsid id_, jsval *vp)
 {
     RootedId id(cx, id_);
     RootedObject obj(cx, obj_);
     RootedObject obj2(cx);
-    JSProperty* prop;
+    RootedShape prop(cx);
 
     return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
            LookupResult(cx, obj, obj2, id, prop, vp);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_LookupElement(JSContext *cx, JSObject *obj, uint32_t index, jsval *vp)
 {
@@ -3485,17 +3483,17 @@ JS_LookupUCProperty(JSContext *cx, JSObj
 
 JS_PUBLIC_API(JSBool)
 JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj_, jsid id_, unsigned flags,
                                JSObject **objp_, jsval *vp)
 {
     RootedObject obj(cx, obj_);
     RootedObject objp(cx, *objp_);
     RootedId id(cx, id_);
-    JSProperty* prop;
+    RootedShape prop(cx);
 
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     if (!(obj->isNative()
           ? LookupPropertyWithFlags(cx, obj, id, flags, &objp, &prop)
           : obj->lookupGeneric(cx, id, &objp, &prop)))
         return false;
@@ -3516,17 +3514,17 @@ JS_LookupPropertyWithFlags(JSContext *cx
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasPropertyById(JSContext *cx, JSObject *obj_, jsid id_, JSBool *foundp)
 {
     RootedObject obj(cx, obj_);
     RootedId id(cx, id_);
     RootedObject obj2(cx);
-    JSProperty* prop;
+    RootedShape prop(cx);
     JSBool ok = LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
                                    &obj2, &prop);
     *foundp = (prop != NULL);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasElement(JSContext *cx, JSObject *obj, uint32_t index, JSBool *foundp)
@@ -3561,17 +3559,17 @@ JS_AlreadyHasOwnPropertyById(JSContext *
     RootedObject obj(cx, obj_);
 
     AssertNoGC(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
 
     if (!obj->isNative()) {
         RootedObject obj2(cx);
-        JSProperty *prop;
+        RootedShape prop(cx);
 
         if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
                                 &obj2, &prop)) {
             return JS_FALSE;
         }
         *foundp = (obj == obj2);
         return JS_TRUE;
     }
@@ -3833,33 +3831,32 @@ JS_DefineProperties(JSContext *cx, JSObj
     return ok;
 }
 
 static JSBool
 GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                           JSBool own, PropertyDescriptor *desc)
 {
     RootedObject obj2(cx);
-    JSProperty *prop;
-
-    if (!LookupPropertyById(cx, obj, id, flags, &obj2, &prop))
+    RootedShape shape(cx);
+
+    if (!LookupPropertyById(cx, obj, id, flags, &obj2, &shape))
         return JS_FALSE;
 
-    if (!prop || (own && obj != obj2)) {
+    if (!shape || (own && obj != obj2)) {
         desc->obj = NULL;
         desc->attrs = 0;
         desc->getter = NULL;
         desc->setter = NULL;
         desc->value.setUndefined();
         return JS_TRUE;
     }
 
     desc->obj = obj2;
     if (obj2->isNative()) {
-        Shape *shape = (Shape *) prop;
         desc->attrs = shape->attributes();
         desc->getter = shape->getter();
         desc->setter = shape->setter();
         if (shape->hasSlot())
             desc->value = obj2->nativeGetSlot(shape->slot());
         else
             desc->value.setUndefined();
     } else {
@@ -3958,25 +3955,24 @@ JS_GetOwnPropertyDescriptor(JSContext *c
     Rooted<jsid> id(cx, id_);
     return GetOwnPropertyDescriptor(cx, obj, id, vp);
 }
 
 static JSBool
 SetPropertyAttributesById(JSContext *cx, HandleObject obj, HandleId id, unsigned attrs, JSBool *foundp)
 {
     RootedObject obj2(cx);
-    JSProperty *prop;
-
-    if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
+    RootedShape shape(cx);
+
+    if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &shape))
         return false;
-    if (!prop || obj != obj2) {
+    if (!shape || obj != obj2) {
         *foundp = false;
         return true;
     }
-    Shape *shape = (Shape *) prop;
     JSBool ok = obj->isNative()
                 ? obj->changePropertyAttributes(cx, shape, attrs)
                 : obj->setGenericAttributes(cx, id, &attrs);
     if (ok)
         *foundp = true;
     return ok;
 }
 
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -342,17 +342,17 @@ DoGetElement(JSContext *cx, JSObject *ob
     if (!IndexToId(cx, obj, index, hole, id.address()))
         return JS_FALSE;
     if (*hole) {
         vp->setUndefined();
         return JS_TRUE;
     }
 
     RootedObject obj2(cx);
-    JSProperty *prop;
+    RootedShape prop(cx);
     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         vp->setUndefined();
         *hole = JS_TRUE;
     } else {
         if (!obj->getGeneric(cx, id, vp))
             return JS_FALSE;
@@ -687,69 +687,69 @@ IsDenseArrayId(JSContext *cx, JSObject *
     JS_ASSERT(obj->isDenseArray());
 
     uint32_t i;
     return JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
            (js_IdIsIndex(id, &i) && IsDenseArrayIndex(obj, i));
 }
 
 static JSBool
-array_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
-                    JSProperty **propp)
+array_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                    MutableHandleObject objp, MutableHandleShape propp)
 {
     if (!obj->isDenseArray())
         return baseops::LookupProperty(cx, obj, id, objp, propp);
 
     if (IsDenseArrayId(cx, obj, id)) {
-        *propp = (JSProperty *) 1;  /* non-null to indicate found */
+        MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
         return JS_TRUE;
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
         objp.set(NULL);
-        *propp = NULL;
+        propp.set(NULL);
         return JS_TRUE;
     }
     return proto->lookupGeneric(cx, id, objp, propp);
 }
 
 static JSBool
 array_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                     MutableHandleObject objp, JSProperty **propp)
+                     MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return array_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-array_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
-                    JSProperty **propp)
+array_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+                    MutableHandleObject objp, MutableHandleShape propp)
 {
     if (!obj->isDenseArray())
         return baseops::LookupElement(cx, obj, index, objp, propp);
 
     if (IsDenseArrayIndex(obj, index)) {
-        *propp = (JSProperty *) 1;  /* non-null to indicate found */
+        MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
         return true;
     }
 
     if (JSObject *proto = obj->getProto())
         return proto->lookupElement(cx, index, objp, propp);
 
     objp.set(NULL);
-    *propp = NULL;
+    propp.set(NULL);
     return true;
 }
 
 static JSBool
-array_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid, MutableHandleObject objp,
-                    JSProperty **propp)
+array_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                    MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return array_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, Value *vp)
 {
--- a/js/src/jsclass.h
+++ b/js/src/jsclass.h
@@ -144,27 +144,27 @@ JSID_TO_SPECIALID(jsid id)
     return SpecialId::defaultXMLNamespace();
 }
 
 typedef JS::Handle<SpecialId> HandleSpecialId;
 
 /* js::Class operation signatures. */
 
 typedef JSBool
-(* LookupGenericOp)(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
-                    JSProperty **propp);
+(* LookupGenericOp)(JSContext *cx, HandleObject obj, HandleId id,
+                    MutableHandleObject objp, MutableHandleShape propp);
 typedef JSBool
-(* LookupPropOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleObject objp,
-                 JSProperty **propp);
+(* LookupPropOp)(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                 MutableHandleObject objp, MutableHandleShape propp);
 typedef JSBool
-(* LookupElementOp)(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
-                    JSProperty **propp);
+(* LookupElementOp)(JSContext *cx, HandleObject obj, uint32_t index,
+                    MutableHandleObject objp, MutableHandleShape propp);
 typedef JSBool
-(* LookupSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid, MutableHandleObject objp,
-                    JSProperty **propp);
+(* LookupSpecialOp)(JSContext *cx, HandleObject obj, HandleSpecialId sid,
+                    MutableHandleObject objp, MutableHandleShape propp);
 typedef JSBool
 (* DefineGenericOp)(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
 typedef JSBool
 (* DefinePropOp)(JSContext *cx, HandleObject obj, HandlePropertyName name, const Value *value,
                  PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
 typedef JSBool
 (* DefineElementOp)(JSContext *cx, HandleObject obj, uint32_t index, const Value *value,
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -554,17 +554,17 @@ JSStructuredCloneWriter::write(const Val
             checkStack();
             if (JSID_IS_STRING(id) || JSID_IS_INT(id)) {
                 /*
                  * If obj still has an own property named id, write it out.
                  * The cost of re-checking could be avoided by using
                  * NativeIterators.
                  */
                 RootedObject obj2(context());
-                JSProperty *prop;
+                RootedShape prop(context());
                 if (!js_HasOwnProperty(context(), obj->getOps()->lookupGeneric, obj, id,
                                        &obj2, &prop)) {
                     return false;
                 }
 
                 if (prop) {
                     Value val;
                     if (!writeId(id) ||
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -949,32 +949,30 @@ js::AssertValidPropertyCacheHit(JSContex
     uint64_t sample = cx->runtime->gcNumber;
     PropertyCacheEntry savedEntry = *entry;
 
     RootedPropertyName name(cx, GetNameFromBytecode(cx, script, pc, JSOp(*pc)));
     RootedObject start(cx, start_);
 
     RootedObject obj(cx);
     RootedObject pobj(cx);
-    JSProperty *prop;
+    RootedShape prop(cx);
     JSBool ok;
 
     if (JOF_OPMODE(*pc) == JOF_NAME)
         ok = FindProperty(cx, name, start, &obj, &pobj, &prop);
     else
         ok = baseops::LookupProperty(cx, start, name, &pobj, &prop);
     JS_ASSERT(ok);
 
     if (cx->runtime->gcNumber != sample)
         JS_PROPERTY_CACHE(cx).restore(&savedEntry);
     JS_ASSERT(prop);
     JS_ASSERT(pobj == found);
-
-    Shape *shape = (Shape *) prop;
-    JS_ASSERT(entry->prop == shape);
+    JS_ASSERT(entry->prop == prop);
 }
 #endif /* DEBUG && !JS_THREADSAFE */
 
 /*
  * Ensure that the intrepreter switch can close call-bytecode cases in the
  * same way as non-call bytecodes.
  */
 JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
@@ -1276,16 +1274,17 @@ js::Interpret(JSContext *cx, StackFrame 
      */
     RootedValue rootValue0(cx), rootValue1(cx);
     RootedString rootString0(cx), rootString1(cx);
     RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
     RootedFunction rootFunction0(cx);
     RootedTypeObject rootType0(cx);
     RootedPropertyName rootName0(cx);
     RootedId rootId0(cx);
+    RootedShape rootShape0(cx);
 
     if (rt->profilingScripts)
         ENABLE_INTERRUPTS();
 
     if (!entryFrame)
         entryFrame = regs.fp();
 
     /*
@@ -1741,17 +1740,17 @@ BEGIN_CASE(JSOP_IN)
         js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL);
         goto error;
     }
     RootedObject &obj = rootObject0;
     obj = &rref.toObject();
     RootedId &id = rootId0;
     FETCH_ELEMENT_ID(obj, -2, id);
     RootedObject &obj2 = rootObject1;
-    JSProperty *prop;
+    RootedShape &prop = rootShape0;
     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
         goto error;
     bool cond = prop != NULL;
     TRY_BRANCH_AFTER_COND(cond, 2);
     regs.sp--;
     regs.sp[-1].setBoolean(cond);
 }
 END_CASE(JSOP_IN)
@@ -2201,17 +2200,17 @@ BEGIN_CASE(JSOP_DELNAME)
     RootedPropertyName &name = rootName0;
     LOAD_NAME(0, name);
 
     RootedObject &scopeObj = rootObject0;
     scopeObj = cx->stack.currentScriptedScopeChain();
 
     RootedObject &obj = rootObject1;
     RootedObject &obj2 = rootObject2;
-    JSProperty *prop;
+    RootedShape &prop = rootShape0;
     if (!FindProperty(cx, name, scopeObj, &obj, &obj2, &prop))
         goto error;
 
     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
     JS_ASSERT(!script->strictModeCode);
 
     /* ECMA says to return true if name is undefined or inherited. */
     PUSH_BOOLEAN(true);
@@ -2548,17 +2547,17 @@ BEGIN_CASE(JSOP_IMPLICITTHIS)
     RootedPropertyName &name = rootName0;
     LOAD_NAME(0, name);
 
     RootedObject &scopeObj = rootObject0;
     scopeObj = cx->stack.currentScriptedScopeChain();
 
     RootedObject &obj = rootObject1;
     RootedObject &obj2 = rootObject2;
-    JSProperty *prop;
+    RootedShape &prop = rootShape0;
     if (!FindPropertyHelper(cx, name, false, scopeObj, &obj, &obj2, &prop))
         goto error;
 
     Value v;
     if (!ComputeImplicitThis(cx, obj, &v))
         goto error;
     PUSH_COPY(v);
 }
@@ -2915,38 +2914,37 @@ BEGIN_CASE(JSOP_DEFFUN)
      * and functions defined by eval inside let or with blocks.
      */
     RootedObject &parent = rootObject0;
     parent = &regs.fp()->varObj();
 
     /* ES5 10.5 (NB: with subsequent errata). */
     RootedPropertyName &name = rootName0;
     name = fun->atom->asPropertyName();
-    JSProperty *prop = NULL;
+    RootedShape &shape = rootShape0;
     RootedObject &pobj = rootObject1;
-    if (!parent->lookupProperty(cx, name, &pobj, &prop))
+    if (!parent->lookupProperty(cx, name, &pobj, &shape))
         goto error;
 
     RootedValue &rval = rootValue0;
     rval = ObjectValue(*fun);
 
     do {
         /* Steps 5d, 5f. */
-        if (!prop || pobj != parent) {
+        if (!shape || pobj != parent) {
             if (!parent->defineProperty(cx, name, rval,
                                         JS_PropertyStub, JS_StrictPropertyStub, attrs))
             {
                 goto error;
             }
             break;
         }
 
         /* Step 5e. */
         JS_ASSERT(parent->isNative());
-        Shape *shape = reinterpret_cast<Shape *>(prop);
         if (parent->isGlobal()) {
             if (shape->configurable()) {
                 if (!parent->defineProperty(cx, name, rval,
                                             JS_PropertyStub, JS_StrictPropertyStub, attrs))
                 {
                     goto error;
                 }
                 break;
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -380,56 +380,55 @@ NameOperation(JSContext *cx, JSScript *s
     JS_PROPERTY_CACHE(cx).test(cx, pc, obj.get(), obj2.get(), entry, name.get());
     if (!name) {
         AssertValidPropertyCacheHit(cx, obj, obj2, entry);
         if (!NativeGet(cx, obj, obj2, entry->prop, 0, vp))
             return false;
         return true;
     }
 
-    JSProperty *prop;
-    if (!FindPropertyHelper(cx, name, true, obj, &obj, &obj2, &prop))
+    RootedShape shape(cx);
+    if (!FindPropertyHelper(cx, name, true, obj, &obj, &obj2, &shape))
         return false;
-    if (!prop) {
+    if (!shape) {
         /* Kludge to allow (typeof foo == "undefined") tests. */
         JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
         if (op2 == JSOP_TYPEOF) {
             vp->setUndefined();
             return true;
         }
         JSAutoByteString printable;
         if (js_AtomToPrintableString(cx, name, &printable))
             js_ReportIsNotDefined(cx, printable.ptr());
         return false;
     }
 
-    /* Take the slow path if prop was not found in a native object. */
+    /* Take the slow path if shape was not found in a native object. */
     if (!obj->isNative() || !obj2->isNative()) {
         Rooted<jsid> id(cx, NameToId(name));
         if (!obj->getGeneric(cx, id, vp))
             return false;
     } else {
-        Shape *shape = (Shape *)prop;
         Rooted<JSObject*> normalized(cx, obj);
         if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
             normalized = &normalized->asWith().object();
         if (!NativeGet(cx, normalized, obj2, shape, 0, vp))
             return false;
     }
 
     return true;
 }
 
 inline bool
 DefVarOrConstOperation(JSContext *cx, HandleObject varobj, PropertyName *dn, unsigned attrs)
 {
     JS_ASSERT(varobj->isVarObj());
     JS_ASSERT(!varobj->getOps()->defineProperty || varobj->isDebugScope());
 
-    JSProperty *prop;
+    RootedShape prop(cx);
     RootedObject obj2(cx);
     if (!varobj->lookupProperty(cx, dn, &obj2, &prop))
         return false;
 
     /* Steps 8c, 8d. */
     if (!prop || (obj2 != varobj && varobj->isGlobal())) {
         if (!varobj->defineProperty(cx, dn, UndefinedValue(), JS_PropertyStub,
                                     JS_StrictPropertyStub, attrs)) {
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -988,26 +988,26 @@ SuppressDeletedPropertyHelper(JSContext 
                 if (predicate(*idp)) {
                     /*
                      * Check whether another property along the prototype chain
                      * became visible as a result of this deletion.
                      */
                     if (obj->getProto()) {
                         JSObject *proto = obj->getProto();
                         RootedObject obj2(cx);
-                        JSProperty *prop;
+                        RootedShape prop(cx);
                         RootedId id(cx);
                         if (!ValueToId(cx, StringValue(*idp), id.address()))
                             return false;
                         if (!proto->lookupGeneric(cx, id, &obj2, &prop))
                             return false;
                         if (prop) {
                             unsigned attrs;
                             if (obj2->isNative())
-                                attrs = ((Shape *) prop)->attributes();
+                                attrs = prop->attributes();
                             else if (!obj2->getGenericAttributes(cx, id, &attrs))
                                 return false;
 
                             if (attrs & JSPROP_ENUMERATE)
                                 continue;
                         }
                     }
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -174,17 +174,17 @@ MarkSharpObjects(JSContext *cx, HandleOb
         if (!ida)
             return false;
 
         bool ok = true;
         RootedId id(cx);
         for (int i = 0, length = ida->length; i < length; i++) {
             id = ida->vector[i];
             RootedObject obj2(cx);
-            JSProperty *prop;
+            RootedShape prop(cx);
             ok = obj->lookupGeneric(cx, id, &obj2, &prop);
             if (!ok)
                 break;
             if (!prop)
                 continue;
             bool hasGetter, hasSetter;
             RootedValue valueRoot(cx), setterRoot(cx);
             Value &value = valueRoot.get();
@@ -455,17 +455,17 @@ obj_toSource(JSContext *cx, unsigned arg
 
     RootedId id(cx);
     for (int i = 0; i < ida->length; i++) {
         /* Get strings for id and value and GC-root them via vp. */
         id = ida->vector[i];
         JSLinearString *idstr;
 
         RootedObject obj2(cx);
-        JSProperty *prop;
+        RootedShape prop(cx);
         if (!obj->lookupGeneric(cx, id, &obj2, &prop))
             return false;
 
         /*
          * Convert id to a value and then to a string.  Decide early whether we
          * prefer get/set or old getter/setter syntax.
          */
         JSString *s = ToString(cx, IdToValue(id));
@@ -802,58 +802,58 @@ js_HasOwnPropertyHelper(JSContext *cx, L
     RootedId id(cx);
     if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), id.address()))
         return JS_FALSE;
 
     RootedObject obj(cx, ToObject(cx, &vp[1]));
     if (!obj)
         return false;
     RootedObject obj2(cx);
-    JSProperty *prop;
+    RootedShape prop(cx);
     if (obj->isProxy()) {
         bool has;
         if (!Proxy::hasOwn(cx, obj, id, &has))
             return false;
         vp->setBoolean(has);
         return true;
     }
     if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
         return JS_FALSE;
     vp->setBoolean(!!prop);
     return JS_TRUE;
 }
 
 JSBool
 js_HasOwnProperty(JSContext *cx, LookupGenericOp lookup, HandleObject obj, HandleId id,
-                  MutableHandleObject objp, JSProperty **propp)
+                  MutableHandleObject objp, MutableHandleShape propp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
     if (lookup) {
         if (!lookup(cx, obj, id, objp, propp))
             return false;
     } else {
         if (!baseops::LookupProperty(cx, obj, id, objp, propp))
             return false;
     }
-    if (!*propp)
+    if (!propp)
         return true;
 
     if (objp == obj)
         return true;
 
     JSObject *outer = NULL;
     if (JSObjectOp op = objp->getClass()->ext.outerObject) {
         Rooted<JSObject*> inner(cx, objp);
         outer = op(cx, inner);
         if (!outer)
             return false;
     }
 
     if (outer != objp)
-        *propp = NULL;
+        propp.set(NULL);
     return true;
 }
 
 /* ES5 15.2.4.6. */
 static JSBool
 obj_isPrototypeOf(JSContext *cx, unsigned argc, Value *vp)
 {
     /* Step 1. */
@@ -889,17 +889,17 @@ obj_propertyIsEnumerable(JSContext *cx, 
     /* Steps 3-5. */
     return js_PropertyIsEnumerable(cx, obj, id, vp);
 }
 
 JSBool
 js_PropertyIsEnumerable(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
 {
     RootedObject pobj(cx);
-    JSProperty *prop;
+    RootedShape prop(cx);
     if (!obj->lookupGeneric(cx, id, &pobj, &prop))
         return false;
 
     if (!prop) {
         vp->setBoolean(false);
         return true;
     }
 
@@ -999,23 +999,22 @@ obj_lookupGetter(JSContext *cx, unsigned
         PropertyDescriptor desc;
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_GETTER) && desc.getter)
             *vp = CastAsObjectJsval(desc.getter);
         return JS_TRUE;
     }
     RootedObject pobj(cx);
-    JSProperty *prop;
-    if (!obj->lookupGeneric(cx, id, &pobj, &prop))
+    RootedShape shape(cx);
+    if (!obj->lookupGeneric(cx, id, &pobj, &shape))
         return JS_FALSE;
     vp->setUndefined();
-    if (prop) {
+    if (shape) {
         if (pobj->isNative()) {
-            Shape *shape = (Shape *) prop;
             if (shape->hasGetterValue())
                 *vp = shape->getterValue();
         }
     }
     return JS_TRUE;
 }
 
 static JSBool
@@ -1034,23 +1033,22 @@ obj_lookupSetter(JSContext *cx, unsigned
         PropertyDescriptor desc;
         if (!Proxy::getPropertyDescriptor(cx, obj, id, false, &desc))
             return JS_FALSE;
         if (desc.obj && (desc.attrs & JSPROP_SETTER) && desc.setter)
             *vp = CastAsObjectJsval(desc.setter);
         return JS_TRUE;
     }
     RootedObject pobj(cx);
-    JSProperty *prop;
-    if (!obj->lookupGeneric(cx, id, &pobj, &prop))
+    RootedShape shape(cx);
+    if (!obj->lookupGeneric(cx, id, &pobj, &shape))
         return JS_FALSE;
     vp->setUndefined();
-    if (prop) {
+    if (shape) {
         if (pobj->isNative()) {
-            Shape *shape = (Shape *) prop;
             if (shape->hasSetterValue())
                 *vp = shape->setterValue();
         }
     }
     return JS_TRUE;
 }
 #endif /* OLD_GETTER_SETTER_METHODS */
 
@@ -1166,27 +1164,26 @@ PropDesc::makeObject(JSContext *cx)
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, PropertyDescriptor *desc)
 {
     if (obj->isProxy())
         return Proxy::getOwnPropertyDescriptor(cx, obj, id, false, desc);
 
     RootedObject pobj(cx);
-    JSProperty *prop;
-    if (!js_HasOwnProperty(cx, obj->getOps()->lookupGeneric, obj, id, &pobj, &prop))
+    RootedShape shape(cx);
+    if (!js_HasOwnProperty(cx, obj->getOps()->lookupGeneric, obj, id, &pobj, &shape))
         return false;
-    if (!prop) {
+    if (!shape) {
         desc->obj = NULL;
         return true;
     }
 
     bool doGet = true;
     if (pobj->isNative()) {
-        Shape *shape = (Shape *) prop;
         desc->attrs = shape->attributes();
         if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
             doGet = false;
             if (desc->attrs & JSPROP_GETTER)
                 desc->getter = CastAsPropertyOp(shape->getterObject());
             if (desc->attrs & JSPROP_SETTER)
                 desc->setter = CastAsStrictPropertyOp(shape->setterObject());
         }
@@ -1504,26 +1501,26 @@ js::CheckDefineProperty(JSContext *cx, H
     return true;
 }
 
 static JSBool
 DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropDesc &desc,
                        bool throwError, bool *rval)
 {
     /* 8.12.9 step 1. */
-    JSProperty *current;
+    RootedShape shape(cx);
     RootedObject obj2(cx);
     JS_ASSERT(!obj->getOps()->lookupGeneric);
-    if (!js_HasOwnProperty(cx, NULL, obj, id, &obj2, &current))
+    if (!js_HasOwnProperty(cx, NULL, obj, id, &obj2, &shape))
         return JS_FALSE;
 
     JS_ASSERT(!obj->getOps()->defineProperty);
 
     /* 8.12.9 steps 2-4. */
-    if (!current) {
+    if (!shape) {
         if (!obj->isExtensible())
             return Reject(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE, throwError, rval);
 
         *rval = true;
 
         if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
             JS_ASSERT(!obj->getOps()->defineProperty);
             Value v = desc.hasValue() ? desc.value() : UndefinedValue();
@@ -1548,17 +1545,16 @@ DefinePropertyOnObject(JSContext *cx, Ha
                                       desc.getter(), desc.setter(), desc.attributes());
     }
 
     /* 8.12.9 steps 5-6 (note 5 is merely a special case of 6). */
     Value v = UndefinedValue();
 
     JS_ASSERT(obj == obj2);
 
-    Rooted<Shape *> shape(cx, reinterpret_cast<Shape *>(current));
     do {
         if (desc.isAccessorDescriptor()) {
             if (!shape->isAccessorDescriptor())
                 break;
 
             if (desc.hasGet()) {
                 bool same;
                 if (!SameValue(cx, desc.getterValue(), shape->getterOrUndefined(), &same))
@@ -3852,19 +3848,16 @@ js_GetClassObject(JSContext *cx, HandleO
     return true;
 }
 
 bool
 js_FindClassObject(JSContext *cx, HandleObject start, JSProtoKey protoKey,
                    MutableHandleValue vp, Class *clasp)
 {
     RootedId id(cx);
-    JSProperty *prop;
-    Shape *shape;
-
     RootedObject obj(cx);
 
     if (start) {
         obj = &start->global();
         obj = GetInnerObject(cx, obj);
     } else {
         obj = GetGlobalForScopeChain(cx);
     }
@@ -3886,21 +3879,21 @@ js_FindClassObject(JSContext *cx, Handle
         JSAtom *atom = js_Atomize(cx, clasp->name, strlen(clasp->name));
         if (!atom)
             return false;
         id = AtomToId(atom);
     }
 
     JS_ASSERT(obj->isNative());
     RootedObject pobj(cx);
-    if (!LookupPropertyWithFlags(cx, obj, id, 0, &pobj, &prop))
+    RootedShape shape(cx);
+    if (!LookupPropertyWithFlags(cx, obj, id, 0, &pobj, &shape))
         return false;
     RootedValue v(cx, UndefinedValue());
-    if (prop && pobj->isNative()) {
-        shape = (Shape *) prop;
+    if (shape && pobj->isNative()) {
         if (shape->hasSlot()) {
             v = pobj->nativeGetSlot(shape->slot());
             if (v.get().isPrimitive())
                 v.get().setUndefined();
         }
     }
     vp.set(v);
     return true;
@@ -4110,32 +4103,30 @@ DefineNativeProperty(JSContext *cx, Hand
 
     /*
      * If defining a getter or setter, we must check for its counterpart and
      * update the attributes and property ops.  A getter or setter is really
      * only half of a property.
      */
     RootedShape shape(cx);
     if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
-        JSProperty *prop;
-
         /* Type information for getter/setter properties is unknown. */
         AddTypePropertyId(cx, obj, id, types::Type::UnknownType());
         MarkTypePropertyConfigured(cx, obj, id);
 
         /*
          * If we are defining a getter whose setter was already defined, or
          * vice versa, finish the job via obj->changeProperty, and refresh the
          * property cache line for (obj, id) to map shape.
          */
         RootedObject pobj(cx);
-        if (!baseops::LookupProperty(cx, obj, id, &pobj, &prop))
+        RootedShape shape(cx);
+        if (!baseops::LookupProperty(cx, obj, id, &pobj, &shape))
             return NULL;
-        if (prop && pobj == obj) {
-            shape = (Shape *) prop;
+        if (shape && pobj == obj) {
             if (shape->isAccessorDescriptor()) {
                 shape = obj->changeProperty(cx, shape, attrs,
                                             JSPROP_GETTER | JSPROP_SETTER,
                                             (attrs & JSPROP_GETTER)
                                             ? getter
                                             : shape->getter(),
                                             (attrs & JSPROP_SETTER)
                                             ? setter
@@ -4213,17 +4204,17 @@ DefineNativeProperty(JSContext *cx, Hand
  *   - If the resolve hook finds or defines the sought property, set *objp and
  *     *propp appropriately, set *recursedp = false, and return true.
  *
  *   - Otherwise no property was resolved. Set *propp = NULL and *recursedp = false
  *     and return true.
  */
 static JSBool
 CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-              MutableHandleObject objp, JSProperty **propp, bool *recursedp)
+              MutableHandleObject objp, MutableHandleShape propp, bool *recursedp)
 {
     Class *clasp = obj->getClass();
     JSResolveOp resolve = clasp->resolve;
 
     /*
      * Avoid recursion on (obj, id) already being resolved on cx.
      *
      * Once we have successfully added an entry for (obj, key) to
@@ -4234,17 +4225,17 @@ CallResolveOp(JSContext *cx, HandleObjec
     AutoResolving resolving(cx, obj, id);
     if (resolving.alreadyStarted()) {
         /* Already resolving id in obj -- suppress recursion. */
         *recursedp = true;
         return true;
     }
     *recursedp = false;
 
-    *propp = NULL;
+    propp.set(NULL);
 
     if (clasp->flags & JSCLASS_NEW_RESOLVE) {
         JSNewResolveOp newresolve = reinterpret_cast<JSNewResolveOp>(resolve);
         if (flags == RESOLVE_INFER)
             flags = js_InferFlags(cx, 0);
 
         RootedObject obj2(cx, NULL);
         if (!newresolve(cx, obj, id, flags, &obj2))
@@ -4268,45 +4259,45 @@ CallResolveOp(JSContext *cx, HandleObjec
     } else {
         if (!resolve(cx, obj, id))
             return false;
     }
 
     if (!obj->nativeEmpty()) {
         if (Shape *shape = obj->nativeLookup(cx, id)) {
             objp.set(obj);
-            *propp = (JSProperty *) shape;
+            propp.set(shape);
         }
     }
 
     return true;
 }
 
 static JS_ALWAYS_INLINE bool
 LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                              MutableHandleObject objp, JSProperty **propp)
+                              MutableHandleObject objp, MutableHandleShape propp)
 {
     /* Search scopes starting with obj and following the prototype link. */
     RootedObject current(cx, obj);
     while (true) {
         Shape *shape = current->nativeLookup(cx, id);
         if (shape) {
             objp.set(current);
-            *propp = (JSProperty *) shape;
+            propp.set(shape);
             return true;
         }
 
         /* Try obj's class resolve hook if id was not found in obj's scope. */
         if (current->getClass()->resolve != JS_ResolveStub) {
             bool recursed;
             if (!CallResolveOp(cx, current, id, flags, objp, propp, &recursed))
                 return false;
             if (recursed)
                 break;
-            if (*propp) {
+            if (propp) {
                 /*
                  * For stats we do not recalculate protoIndex even if it was
                  * resolved on some other object.
                  */
                 return true;
             }
         }
 
@@ -4321,67 +4312,68 @@ LookupPropertyWithFlagsInline(JSContext 
              * Non-native objects must have either non-native lookup results,
              * or else native results from the non-native's prototype chain.
              *
              * See StackFrame::getValidCalleeObject, where we depend on this
              * fact to force a prototype-delegated joined method accessed via
              * arguments.callee through the delegating |this| object's method
              * read barrier.
              */
-            if (*propp && objp->isNative()) {
+            if (propp && objp->isNative()) {
                 while ((proto = proto->getProto()) != objp)
                     JS_ASSERT(proto);
             }
 #endif
             return true;
         }
 
         current = proto;
     }
 
     objp.set(NULL);
-    *propp = NULL;
+    propp.set(NULL);
     return true;
 }
 
 JS_FRIEND_API(JSBool)
 baseops::LookupProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
-                        JSProperty **propp)
+                        MutableHandleShape propp)
 {
     return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
 }
 
 JS_FRIEND_API(JSBool)
 baseops::LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                       MutableHandleObject objp, JSProperty **propp)
+                       MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
 
     return LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, objp, propp);
 }
 
 bool
 js::LookupPropertyWithFlags(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                            MutableHandleObject objp, JSProperty **propp)
+                            MutableHandleObject objp, MutableHandleShape propp)
 {
     return LookupPropertyWithFlagsInline(cx, obj, id, flags, objp, propp);
 }
 
 bool
 js::FindPropertyHelper(JSContext *cx,
                        HandlePropertyName name, bool cacheResult, HandleObject scopeChain,
-                       MutableHandleObject objp, MutableHandleObject pobjp, JSProperty **propp)
+                       MutableHandleObject objp, MutableHandleObject pobjp,
+                       MutableHandleShape propp)
 {
     RootedId id(cx, NameToId(name));
 
     RootedObject pobj(cx);
     int scopeIndex;
-    JSProperty *prop;
+    RootedShape prop(cx);
 
     /* Scan entries on the scope chain that we can cache across. */
     RootedObject obj(cx, scopeChain);
     RootedObject parent(cx, obj->enclosingScope());
     for (scopeIndex = 0;
          parent
          ? IsCacheableNonGlobalScope(obj)
          : !obj->getOps()->lookupProperty;
@@ -4411,18 +4403,17 @@ js::FindPropertyHelper(JSContext *cx,
             }
 #endif
 
             /*
              * We must check if pobj is native as a global object can have
              * non-native prototype.
              */
             if (cacheResult && pobj->isNative()) {
-                JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj,
-                                           (Shape *) prop);
+                JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, prop);
             }
 
             goto out;
         }
 
         if (!parent) {
             pobj = NULL;
             goto out;
@@ -4448,27 +4439,27 @@ js::FindPropertyHelper(JSContext *cx,
         }
         obj = parent;
     }
 
   out:
     JS_ASSERT(!!pobj == !!prop);
     objp.set(obj);
     pobjp.set(pobj);
-    *propp = prop;
+    propp.set(prop);
     return true;
 }
 
 /*
  * On return, if |*pobjp| is a native object, then |*propp| is a |Shape *|.
  * Otherwise, its type and meaning depends on the host object's implementation.
  */
 bool
 js::FindProperty(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
-                 MutableHandleObject objp, MutableHandleObject pobjp, JSProperty **propp)
+                 MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp)
 {
     return !!FindPropertyHelper(cx, name, false, scopeChain, objp, pobjp, propp);
 }
 
 JSObject *
 js::FindIdentifierBase(JSContext *cx, HandleObject scopeChain, HandlePropertyName name)
 {
     /*
@@ -4488,42 +4479,42 @@ js::FindIdentifierBase(JSContext *cx, Ha
      * The test order here matters because IsCacheableNonGlobalScope
      * must not be passed a global object (i.e. one with null parent).
      */
     for (int scopeIndex = 0;
          obj->isGlobal() || IsCacheableNonGlobalScope(obj);
          scopeIndex++)
     {
         RootedObject pobj(cx);
-        JSProperty *prop;
-        if (!LookupPropertyWithFlags(cx, obj, name, cx->resolveFlags, &pobj, &prop))
+        RootedShape shape(cx);
+        if (!LookupPropertyWithFlags(cx, obj, name, cx->resolveFlags, &pobj, &shape))
             return NULL;
-        if (prop) {
+        if (shape) {
             if (!pobj->isNative()) {
                 JS_ASSERT(obj->isGlobal());
                 return obj;
             }
             JS_ASSERT_IF(obj->isScope(), pobj->getClass() == obj->getClass());
-            JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, (Shape *) prop);
+            JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, pobj, shape);
             return obj;
         }
 
         JSObject *parent = obj->enclosingScope();
         if (!parent)
             return obj;
         obj = parent;
     }
 
     /* Loop until we find a property or reach the global object. */
     do {
         RootedObject pobj(cx);
-        JSProperty *prop;
-        if (!obj->lookupProperty(cx, name, &pobj, &prop))
+        RootedShape shape(cx);
+        if (!obj->lookupProperty(cx, name, &pobj, &shape))
             return NULL;
-        if (prop)
+        if (shape)
             break;
 
         /*
          * We conservatively assume that a resolve hook could mutate the scope
          * chain during JSObject::lookupGeneric. So we must check if parent is
          * not null here even if it wasn't before the lookup.
          */
         JSObject *parent = obj->enclosingScope();
@@ -4624,26 +4615,25 @@ js_NativeSet(JSContext *cx, Handle<JSObj
 
     return true;
 }
 
 static JS_ALWAYS_INLINE JSBool
 js_GetPropertyHelperInline(JSContext *cx, HandleObject obj, HandleObject receiver, jsid id_,
                            uint32_t getHow, Value *vp)
 {
-    JSProperty *prop;
-
     RootedId id(cx, id_);
 
     /* This call site is hot -- use the always-inlined variant of LookupPropertyWithFlags(). */
     RootedObject obj2(cx);
-    if (!LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, &obj2, &prop))
+    RootedShape shape(cx);
+    if (!LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, &obj2, &shape))
         return false;
 
-    if (!prop) {
+    if (!shape) {
         vp->setUndefined();
 
         if (!CallJSPropertyOp(cx, obj->getClass()->getProperty, obj, id, vp))
             return JS_FALSE;
 
         /* Record non-undefined values produced by the class getter hook. */
         if (!vp->isUndefined())
             AddTypePropertyId(cx, obj, id, *vp);
@@ -4701,18 +4691,16 @@ js_GetPropertyHelperInline(JSContext *cx
     }
 
     if (!obj2->isNative()) {
         return obj2->isProxy()
                ? Proxy::get(cx, obj2, receiver, id, vp)
                : obj2->getGeneric(cx, id, vp);
     }
 
-    Shape *shape = (Shape *) prop;
-
     if (getHow & JSGET_CACHE_RESULT)
         JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, obj2, shape);
 
     /* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
     if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp))
         return JS_FALSE;
 
     return JS_TRUE;
@@ -4740,17 +4728,17 @@ baseops::GetElement(JSContext *cx, Handl
 
     /* This call site is hot -- use the always-inlined variant of js_GetPropertyHelper(). */
     return js_GetPropertyHelperInline(cx, obj, receiver, id, 0, vp);
 }
 
 JSBool
 baseops::GetPropertyDefault(JSContext *cx, HandleObject obj, HandleId id, const Value &def, Value *vp)
 {
-    JSProperty *prop;
+    RootedShape prop(cx);
     RootedObject obj2(cx);
     if (!LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
         return false;
 
     if (!prop) {
         *vp = def;
         return true;
     }
@@ -4831,17 +4819,16 @@ JSObject::callMethod(JSContext *cx, Hand
     return GetMethod(cx, obj, id, 0, &fval) &&
            Invoke(cx, ObjectValue(*obj), fval, argc, argv, vp);
 }
 
 JSBool
 baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id,
                            unsigned defineHow, Value *vp, JSBool strict)
 {
-    JSProperty *prop;
     unsigned attrs, flags;
     int shortid;
     Class *clasp;
     PropertyOp getter;
     StrictPropertyOp setter;
     bool added;
 
     JS_ASSERT((defineHow & ~(DNP_CACHE_RESULT | DNP_UNQUALIFIED)) == 0);
@@ -4849,19 +4836,20 @@ baseops::SetPropertyHelper(JSContext *cx
     if (JS_UNLIKELY(obj->watched())) {
         /* Fire watchpoints, if any. */
         WatchpointMap *wpmap = cx->compartment->watchpointMap;
         if (wpmap && !wpmap->triggerWatchpoint(cx, obj, id, vp))
             return false;
     }
 
     RootedObject pobj(cx);
-    if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &prop))
+    RootedShape shape(cx);
+    if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &shape))
         return false;
-    if (prop) {
+    if (shape) {
         if (!pobj->isNative()) {
             if (pobj->isProxy()) {
                 AutoPropertyDescriptorRooter pd(cx);
                 if (!Proxy::getPropertyDescriptor(cx, pobj, id, true, &pd))
                     return false;
 
                 if ((pd.attrs & (JSPROP_SHARED | JSPROP_SHADOWABLE)) == JSPROP_SHARED) {
                     return !pd.setter ||
@@ -4873,31 +4861,29 @@ baseops::SetPropertyHelper(JSContext *cx
                     if (strict)
                         return JSObject::reportReadOnly(cx, id, JSREPORT_ERROR);
                     if (cx->hasStrictOption())
                         return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
                     return true;
                 }
             }
 
-            prop = NULL;
+            shape = NULL;
         }
     } else {
         /* We should never add properties to lexical blocks. */
         JS_ASSERT(!obj->isBlock());
 
         if (obj->isGlobal() &&
             (defineHow & DNP_UNQUALIFIED) &&
             !js::CheckUndeclaredVarAssignment(cx, JSID_TO_STRING(id))) {
             return JS_FALSE;
         }
     }
 
-    RootedShape shape(cx, (Shape *) prop);
-
     /*
      * Now either shape is null, meaning id was not found in obj or one of its
      * prototypes; or shape is non-null, meaning id was found directly in pobj.
      */
     attrs = JSPROP_ENUMERATE;
     flags = 0;
     shortid = 0;
     clasp = obj->getClass();
@@ -5027,98 +5013,93 @@ baseops::SetElementHelper(JSContext *cx,
         return false;
     return baseops::SetPropertyHelper(cx, obj, receiver, id, defineHow, vp, strict);
 }
 
 JSBool
 baseops::GetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject nobj(cx);
-    JSProperty *prop;
-    if (!baseops::LookupProperty(cx, obj, id, &nobj, &prop))
+    RootedShape shape(cx);
+    if (!baseops::LookupProperty(cx, obj, id, &nobj, &shape))
         return false;
-    if (!prop) {
+    if (!shape) {
         *attrsp = 0;
         return true;
     }
     if (!nobj->isNative())
         return nobj->getGenericAttributes(cx, id, attrsp);
 
-    Shape *shape = (Shape *)prop;
     *attrsp = shape->attributes();
     return true;
 }
 
 JSBool
 baseops::GetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
     RootedObject nobj(cx);
-    JSProperty *prop;
-    if (!baseops::LookupElement(cx, obj, index, &nobj, &prop))
+    RootedShape shape(cx);
+    if (!baseops::LookupElement(cx, obj, index, &nobj, &shape))
         return false;
-    if (!prop) {
+    if (!shape) {
         *attrsp = 0;
         return true;
     }
     if (!nobj->isNative())
         return nobj->getElementAttributes(cx, index, attrsp);
 
-    Shape *shape = (Shape *)prop;
     *attrsp = shape->attributes();
     return true;
 }
 
 JSBool
 baseops::SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject nobj(cx);
-    JSProperty *prop;
-    if (!baseops::LookupProperty(cx, obj, id, &nobj, &prop))
+    RootedShape shape(cx);
+    if (!baseops::LookupProperty(cx, obj, id, &nobj, &shape))
         return false;
-    if (!prop)
+    if (!shape)
         return true;
     return nobj->isNative()
-           ? nobj->changePropertyAttributes(cx, (Shape *) prop, *attrsp)
+           ? nobj->changePropertyAttributes(cx, shape, *attrsp)
            : nobj->setGenericAttributes(cx, id, attrsp);
 }
 
 JSBool
 baseops::SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp)
 {
     RootedObject nobj(cx);
-    JSProperty *prop;
-    if (!baseops::LookupElement(cx, obj, index, &nobj, &prop))
+    RootedShape shape(cx);
+    if (!baseops::LookupElement(cx, obj, index, &nobj, &shape))
         return false;
-    if (!prop)
+    if (!shape)
         return true;
     return nobj->isNative()
-           ? nobj->changePropertyAttributes(cx, (Shape *) prop, *attrsp)
+           ? nobj->changePropertyAttributes(cx, shape, *attrsp)
            : nobj->setElementAttributes(cx, index, attrsp);
 }
 
 JSBool
 baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, Value *rval, JSBool strict)
 {
-    JSProperty *prop;
-    Shape *shape;
-
     rval->setBoolean(true);
 
     RootedObject proto(cx);
-    if (!baseops::LookupProperty(cx, obj, id, &proto, &prop))
+    RootedShape shape(cx);
+    if (!baseops::LookupProperty(cx, obj, id, &proto, &shape))
         return false;
-    if (!prop || proto != obj) {
+    if (!shape || proto != obj) {
         /*
          * If no property, or the property comes from a prototype, call the
          * class's delProperty hook, passing rval as the result parameter.
          */
         return CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval);
     }
 
-    shape = (Shape *)prop;
     if (!shape->configurable()) {
         if (strict)
             return obj->reportNotConfigurable(cx, id);
         rval->setBoolean(false);
         return true;
     }
 
     if (shape->hasSlot()) {
@@ -5300,53 +5281,50 @@ JS_EnumerateState(JSContext *cx, JSHandl
 
 namespace js {
 
 JSBool
 CheckAccess(JSContext *cx, JSObject *obj_, HandleId id, JSAccessMode mode,
             Value *vp, unsigned *attrsp)
 {
     JSBool writing;
-    JSProperty *prop;
-    Shape *shape;
-
     RootedObject obj(cx, obj_), pobj(cx);
 
     while (JS_UNLIKELY(obj->isWith()))
         obj = obj->getProto();
 
     writing = (mode & JSACC_WRITE) != 0;
     switch (mode & JSACC_TYPEMASK) {
       case JSACC_PROTO:
         pobj = obj;
         if (!writing)
             vp->setObjectOrNull(obj->getProto());
         *attrsp = JSPROP_PERMANENT;
         break;
 
       default:
-        if (!obj->lookupGeneric(cx, id, &pobj, &prop))
+        RootedShape shape(cx);
+        if (!obj->lookupGeneric(cx, id, &pobj, &shape))
             return JS_FALSE;
-        if (!prop) {
+        if (!shape) {
             if (!writing)
                 vp->setUndefined();
             *attrsp = 0;
             pobj = obj;
             break;
         }
 
         if (!pobj->isNative()) {
             if (!writing) {
                     vp->setUndefined();
                 *attrsp = 0;
             }
             break;
         }
 
-        shape = (Shape *)prop;
         *attrsp = shape->attributes();
         if (!writing) {
             if (shape->hasSlot())
                 *vp = pobj->nativeGetSlot(shape->slot());
             else
                 vp->setUndefined();
         }
     }
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -94,29 +94,29 @@ namespace baseops {
 
 /*
  * On success, and if id was found, return true with *objp non-null and with a
  * property of *objp stored in *propp. If successful but id was not found,
  * return true with both *objp and *propp null.
  */
 extern JS_FRIEND_API(JSBool)
 LookupProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
-               JSProperty **propp);
+               MutableHandleShape propp);
 
 inline bool
 LookupProperty(JSContext *cx, HandleObject obj, PropertyName *name,
-               MutableHandleObject objp, JSProperty **propp)
+               MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return LookupProperty(cx, obj, id, objp, propp);
 }
 
 extern JS_FRIEND_API(JSBool)
 LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-              MutableHandleObject objp, JSProperty **propp);
+              MutableHandleObject objp, MutableHandleShape propp);
 
 extern JSBool
 DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, const js::Value *value,
                JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs);
 
 inline JSBool
 DefineProperty(JSContext *cx, HandleObject obj, PropertyName *name, const js::Value *value,
                JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs)
@@ -780,22 +780,24 @@ struct JSObject : public js::ObjectImpl
     inline bool changePropertyAttributes(JSContext *cx, js::Shape *shape, unsigned attrs);
 
     /* Remove the property named by id from this object. */
     bool removeProperty(JSContext *cx, jsid id);
 
     /* Clear the scope, making it empty. */
     void clear(JSContext *cx);
 
-    inline JSBool lookupGeneric(JSContext *cx, js::HandleId id, js::MutableHandleObject objp, JSProperty **propp);
-    inline JSBool lookupProperty(JSContext *cx, js::PropertyName *name, js::MutableHandleObject objp, JSProperty **propp);
+    inline JSBool lookupGeneric(JSContext *cx, js::HandleId id,
+                                js::MutableHandleObject objp, js::MutableHandleShape propp);
+    inline JSBool lookupProperty(JSContext *cx, js::PropertyName *name,
+                                 js::MutableHandleObject objp, js::MutableHandleShape propp);
     inline JSBool lookupElement(JSContext *cx, uint32_t index,
-                                js::MutableHandleObject objp, JSProperty **propp);
+                                js::MutableHandleObject objp, js::MutableHandleShape propp);
     inline JSBool lookupSpecial(JSContext *cx, js::SpecialId sid,
-                                js::MutableHandleObject objp, JSProperty **propp);
+                                js::MutableHandleObject objp, js::MutableHandleShape propp);
 
     inline JSBool defineGeneric(JSContext *cx, js::HandleId id, const js::Value &value,
                                 JSPropertyOp getter = JS_PropertyStub,
                                 JSStrictPropertyOp setter = JS_StrictPropertyStub,
                                 unsigned attrs = JSPROP_ENUMERATE);
     inline JSBool defineProperty(JSContext *cx, js::PropertyName *name, const js::Value &value,
                                  JSPropertyOp getter = JS_PropertyStub,
                                  JSStrictPropertyOp setter = JS_StrictPropertyStub,
@@ -1041,17 +1043,17 @@ extern void
 js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map);
 
 extern JSBool
 js_HasOwnPropertyHelper(JSContext *cx, js::LookupGenericOp lookup, unsigned argc,
                         js::Value *vp);
 
 extern JSBool
 js_HasOwnProperty(JSContext *cx, js::LookupGenericOp lookup, js::HandleObject obj, js::HandleId id,
-                  js::MutableHandleObject objp, JSProperty **propp);
+                  js::MutableHandleObject objp, js::MutableHandleShape propp);
 
 extern JSBool
 js_PropertyIsEnumerable(JSContext *cx, js::HandleObject obj, js::HandleId id, js::Value *vp);
 
 #if JS_HAS_OBJ_PROTO_PROP
 extern JSPropertySpec object_props[];
 #else
 #define object_props NULL
@@ -1160,21 +1162,21 @@ DefineNativeProperty(JSContext *cx, Hand
                                 shortid, defineHow);
 }
 
 /*
  * Specialized subroutine that allows caller to preset JSRESOLVE_* flags.
  */
 extern bool
 LookupPropertyWithFlags(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                        js::MutableHandleObject objp, JSProperty **propp);
+                        js::MutableHandleObject objp, js::MutableHandleShape propp);
 
 inline bool
 LookupPropertyWithFlags(JSContext *cx, HandleObject obj, PropertyName *name, unsigned flags,
-                        js::MutableHandleObject objp, JSProperty **propp)
+                        js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return LookupPropertyWithFlags(cx, obj, id, flags, objp, propp);
 }
 
 /*
  * Call the [[DefineOwnProperty]] internal method of obj.
  *
@@ -1203,25 +1205,25 @@ ReadPropertyDescriptors(JSContext *cx, J
 static const unsigned RESOLVE_INFER = 0xffff;
 
 /*
  * If cacheResult is false, return JS_NO_PROP_CACHE_FILL on success.
  */
 extern bool
 FindPropertyHelper(JSContext *cx, HandlePropertyName name,
                    bool cacheResult, HandleObject scopeChain,
-                   MutableHandleObject objp, MutableHandleObject pobjp, JSProperty **propp);
+                   MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp);
 
 /*
  * Search for name either on the current scope chain or on the scope chain's
  * global object, per the global parameter.
  */
 extern bool
 FindProperty(JSContext *cx, HandlePropertyName name, HandleObject scopeChain,
-             MutableHandleObject objp, MutableHandleObject pobjp, JSProperty **propp);
+             MutableHandleObject objp, MutableHandleObject pobjp, MutableHandleShape propp);
 
 extern JSObject *
 FindIdentifierBase(JSContext *cx, HandleObject scopeChain, HandlePropertyName name);
 
 }
 
 extern JSObject *
 js_FindVariableScope(JSContext *cx, JSFunction **funp);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -922,17 +922,17 @@ JSObject::finish(js::FreeOp *fop)
     if (hasDynamicElements())
         fop->free_(getElementsHeader());
 }
 
 inline bool
 JSObject::hasProperty(JSContext *cx, js::HandleId id, bool *foundp, unsigned flags)
 {
     js::RootedObject pobj(cx);
-    JSProperty *prop;
+    js::RootedShape prop(cx);
     JSAutoResolveFlags rf(cx, flags);
     if (!lookupGeneric(cx, id, &pobj, &prop))
         return false;
     *foundp = !!prop;
     return true;
 }
 
 inline bool
@@ -1029,28 +1029,30 @@ JSObject::sizeOfExcludingThis(JSMallocSi
     if (isArguments()) {
         *miscSize += asArguments().sizeOfMisc(mallocSizeOf);
     } else if (isRegExpStatics()) {
         *miscSize += js::SizeOfRegExpStaticsData(this, mallocSizeOf);
     }
 }
 
 inline JSBool
-JSObject::lookupGeneric(JSContext *cx, js::HandleId id, js::MutableHandleObject objp, JSProperty **propp)
+JSObject::lookupGeneric(JSContext *cx, js::HandleId id,
+                        js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
     js::RootedObject self(cx, this);
 
     js::LookupGenericOp op = getOps()->lookupGeneric;
     if (op)
         return op(cx, self, id, objp, propp);
     return js::baseops::LookupProperty(cx, self, id, objp, propp);
 }
 
 inline JSBool
-JSObject::lookupProperty(JSContext *cx, js::PropertyName *name, js::MutableHandleObject objp, JSProperty **propp)
+JSObject::lookupProperty(JSContext *cx, js::PropertyName *name,
+                         js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
     js::Rooted<jsid> id(cx, js::NameToId(name));
     return lookupGeneric(cx, id, objp, propp);
 }
 
 inline JSBool
 JSObject::defineGeneric(JSContext *cx, js::HandleId id, const js::Value &value,
                         JSPropertyOp getter /* = JS_PropertyStub */,
@@ -1092,26 +1094,28 @@ JSObject::defineSpecial(JSContext *cx, j
                         JSStrictPropertyOp setter /* = JS_StrictPropertyStub */,
                         unsigned attrs /* = JSPROP_ENUMERATE */)
 {
     js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return defineGeneric(cx, id, value, getter, setter, attrs);
 }
 
 inline JSBool
-JSObject::lookupElement(JSContext *cx, uint32_t index, js::MutableHandleObject objp, JSProperty **propp)
+JSObject::lookupElement(JSContext *cx, uint32_t index,
+                        js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
     js::RootedObject self(cx, this);
 
     js::LookupElementOp op = getOps()->lookupElement;
     return (op ? op : js::baseops::LookupElement)(cx, self, index, objp, propp);
 }
 
 inline JSBool
-JSObject::lookupSpecial(JSContext *cx, js::SpecialId sid, js::MutableHandleObject objp, JSProperty **propp)
+JSObject::lookupSpecial(JSContext *cx, js::SpecialId sid,
+                        js::MutableHandleObject objp, js::MutableHandleShape propp)
 {
     js::Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return lookupGeneric(cx, id, objp, propp);
 }
 
 inline JSBool
 JSObject::getElement(JSContext *cx, js::HandleObject receiver, uint32_t index, js::Value *vp)
 {
@@ -1149,17 +1153,17 @@ JSObject::getElementIfPresent(JSContext 
      * lookupGeneric/getGeneric.  Once lookupElement and getElement stop both
      * doing index-to-id conversions, we can use those here.
      */
     js::RootedId id(cx);
     if (!js::IndexToId(cx, index, id.address()))
         return false;
 
     js::RootedObject obj2(cx);
-    JSProperty *prop;
+    js::RootedShape prop(cx);
     if (!self->lookupGeneric(cx, id, &obj2, &prop))
         return false;
 
     if (!prop) {
         *present = false;
         js::Debug_SetValueRangeToCrashOnTouch(vp, 1);
         return true;
     }
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1216,54 +1216,54 @@ Proxy::iteratorNext(JSContext *cx, JSObj
 
 static JSObject *
 proxy_innerObject(JSContext *cx, HandleObject obj)
 {
     return GetProxyPrivate(obj).toObjectOrNull();
 }
 
 static JSBool
-proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
-                    JSProperty **propp)
+proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                    MutableHandleObject objp, MutableHandleShape propp)
 {
     bool found;
     if (!Proxy::has(cx, obj, id, &found))
         return false;
 
     if (found) {
-        *propp = (JSProperty *)0x1;
+        MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
     } else {
         objp.set(NULL);
-        *propp = NULL;
+        propp.set(NULL);
     }
     return true;
 }
 
 static JSBool
 proxy_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                     MutableHandleObject objp, JSProperty **propp)
+                     MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
-                    JSProperty **propp)
+proxy_LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+                    MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 proxy_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                    MutableHandleObject objp, JSProperty **propp)
+                    MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -46,17 +46,16 @@ typedef uint8_t     jsbytecode;
 typedef uint8_t     jssrcnote;
 typedef uintptr_t   jsatomid;
 
 /* Struct typedefs. */
 typedef struct JSArgumentFormatMap  JSArgumentFormatMap;
 typedef struct JSGCThing            JSGCThing;
 typedef struct JSGenerator          JSGenerator;
 typedef struct JSNativeEnumerator   JSNativeEnumerator;
-typedef struct JSProperty           JSProperty;
 typedef struct JSSharpObjectMap     JSSharpObjectMap;
 typedef struct JSTryNote            JSTryNote;
 
 /* Friend "Advanced API" typedefs. */
 typedef struct JSAtomState          JSAtomState;
 typedef struct JSCodeSpec           JSCodeSpec;
 typedef struct JSPrinter            JSPrinter;
 typedef struct JSStackHeader        JSStackHeader;
@@ -220,16 +219,18 @@ struct TypeCompartment;
 } /* namespace types */
 
 typedef JS::Handle<Shape*>             HandleShape;
 typedef JS::Handle<BaseShape*>         HandleBaseShape;
 typedef JS::Handle<types::TypeObject*> HandleTypeObject;
 typedef JS::Handle<JSAtom*>            HandleAtom;
 typedef JS::Handle<PropertyName*>      HandlePropertyName;
 
+typedef JS::MutableHandle<Shape*>      MutableHandleShape;
+
 typedef JS::Rooted<Shape*>             RootedShape;
 typedef JS::Rooted<BaseShape*>         RootedBaseShape;
 typedef JS::Rooted<types::TypeObject*> RootedTypeObject;
 typedef JS::Rooted<JSAtom*>            RootedAtom;
 typedef JS::Rooted<PropertyName*>      RootedPropertyName;
 
 enum XDRMode {
     XDR_ENCODE,
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -1388,8 +1388,21 @@ JSCompartment::sweepInitialShapeTable()
                 JS_ASSERT(parent == shape->getObjectParent());
 #endif
                 InitialShapeEntry newKey(shape, proto);
                 e.rekeyFront(newKey.getLookup(), newKey);
             }
         }
     }
 }
+
+/*
+ * Property lookup hooks on non-native objects are required to return a non-NULL
+ * shape to signify that the property has been found. The actual shape returned
+ * is arbitrary, and it should never be read from. We use the non-native
+ * object's shape_ field, since it is readily available.
+ */
+void
+js::MarkNonNativePropertyFound(HandleObject obj, MutableHandleShape propp)
+{
+    propp.set(obj->lastProperty());
+}
+
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -1157,16 +1157,19 @@ Shape::searchNoAllocation(JSContext *cx,
         if (shape->propidRef() == id)
             return shape;
     }
 
     return NULL;
 }
 #endif /* DEBUG */
 
+void
+MarkNonNativePropertyFound(HandleObject obj, MutableHandleShape propp);
+
 } // namespace js
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
 #endif
 
 namespace JS {
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -290,24 +290,22 @@ ArrayBufferObject::obj_trace(JSTracer *t
      */
     JSObject *delegate = static_cast<JSObject*>(obj->getPrivate());
     if (delegate) {
         MarkObjectUnbarriered(trc, &delegate, "arraybuffer.delegate");
         obj->setPrivateUnbarriered(delegate);
     }
 }
 
-static JSProperty * const PROPERTY_FOUND = reinterpret_cast<JSProperty *>(1);
-
 JSBool
 ArrayBufferObject::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                                     MutableHandleObject objp, JSProperty **propp)
+                                     MutableHandleObject objp, MutableHandleShape propp)
 {
     if (JSID_IS_ATOM(id, cx->runtime->atomState.byteLengthAtom)) {
-        *propp = PROPERTY_FOUND;
+        MarkNonNativePropertyFound(obj, propp);
         objp.set(getArrayBuffer(obj));
         return true;
     }
 
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
 
@@ -316,74 +314,74 @@ ArrayBufferObject::obj_lookupGeneric(JSC
     /* If false, there was an error, so propagate it.
      * Otherwise, if propp is non-null, the property
      * was found. Otherwise it was not
      * found so look in the prototype chain.
      */
     if (!delegateResult)
         return false;
 
-    if (*propp != NULL) {
+    if (propp) {
         if (objp == delegate)
             objp.set(obj);
         return true;
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
         objp.set(NULL);
-        *propp = NULL;
+        propp.set(NULL);
         return true;
     }
 
     return proto->lookupGeneric(cx, id, objp, propp);
 }
 
 JSBool
 ArrayBufferObject::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                      MutableHandleObject objp, JSProperty **propp)
+                                      MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 ArrayBufferObject::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                     MutableHandleObject objp, JSProperty **propp)
+                                     MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedObject delegate(cx, ArrayBufferDelegate(cx, obj));
     if (!delegate)
         return false;
 
     /*
      * If false, there was an error, so propagate it.
      * Otherwise, if propp is non-null, the property
      * was found. Otherwise it was not
      * found so look in the prototype chain.
      */
     if (!delegate->lookupElement(cx, index, objp, propp))
         return false;
 
-    if (*propp != NULL) {
+    if (propp) {
         if (objp == delegate)
             objp.set(obj);
         return true;
     }
 
     if (JSObject *proto = obj->getProto())
         return proto->lookupElement(cx, index, objp, propp);
 
     objp.set(NULL);
-    *propp = NULL;
+    propp.set(NULL);
     return true;
 }
 
 JSBool
 ArrayBufferObject::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                     MutableHandleObject objp, JSProperty **propp)
+                                     MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 ArrayBufferObject::obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *v,
                                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
@@ -769,69 +767,69 @@ bool
 js::IsDataView(JSObject* obj)
 {
     JS_ASSERT(obj);
     return obj->isDataView();
 }
 
 JSBool
 TypedArray::obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                              MutableHandleObject objp, JSProperty **propp)
+                              MutableHandleObject objp, MutableHandleShape propp)
 {
     JSObject *tarray = getTypedArray(obj);
     JS_ASSERT(tarray);
 
     if (isArrayIndex(cx, tarray, id)) {
-        *propp = PROPERTY_FOUND;
+        MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
         return true;
     }
 
     JSObject *proto = obj->getProto();
     if (!proto) {
         objp.set(NULL);
-        *propp = NULL;
+        propp.set(NULL);
         return true;
     }
 
     return proto->lookupGeneric(cx, id, objp, propp);
 }
 
 JSBool
 TypedArray::obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                               MutableHandleObject objp, JSProperty **propp)
+                               MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 TypedArray::obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                              MutableHandleObject objp, JSProperty **propp)
+                              MutableHandleObject objp, MutableHandleShape propp)
 {
     JSObject *tarray = getTypedArray(obj);
     JS_ASSERT(tarray);
 
     if (index < length(tarray)) {
-        *propp = PROPERTY_FOUND;
+        MarkNonNativePropertyFound(obj, propp);
         objp.set(obj);
         return true;
     }
 
     if (JSObject *proto = obj->getProto())
         return proto->lookupElement(cx, index, objp, propp);
 
     objp.set(NULL);
-    *propp = NULL;
+    propp.set(NULL);
     return true;
 }
 
 JSBool
 TypedArray::obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                              MutableHandleObject objp, JSProperty **propp)
+                              MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return obj_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 JSBool
 TypedArray::obj_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
--- a/js/src/jstypedarray.h
+++ b/js/src/jstypedarray.h
@@ -42,26 +42,26 @@ class ArrayBufferObject : public JSObjec
     static JSObject *createSlice(JSContext *cx, ArrayBufferObject &arrayBuffer,
                                  uint32_t begin, uint32_t end);
 
     static void
     obj_trace(JSTracer *trc, JSObject *obj);
 
     static JSBool
     obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                      MutableHandleObject objp, JSProperty **propp);
+                      MutableHandleObject objp, MutableHandleShape propp);
     static JSBool
     obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                       MutableHandleObject objp, JSProperty **propp);
+                       MutableHandleObject objp, MutableHandleShape propp);
     static JSBool
     obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                      MutableHandleObject objp, JSProperty **propp);
+                      MutableHandleObject objp, MutableHandleShape propp);
     static JSBool
     obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                      MutableHandleObject objp, JSProperty **propp);
+                      MutableHandleObject objp, MutableHandleShape propp);
 
     static JSBool
     obj_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *v,
                       PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
     static JSBool
     obj_defineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, const Value *v,
                        PropertyOp getter, StrictPropertyOp setter, unsigned attrs);
     static JSBool
@@ -184,23 +184,23 @@ struct TypedArray {
     // and MUST NOT be used to construct new objects.
     static Class classes[TYPE_MAX];
 
     // These are the proto/original classes, used
     // fo constructing new objects
     static Class protoClasses[TYPE_MAX];
 
     static JSBool obj_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                                    MutableHandleObject objp, JSProperty **propp);
+                                    MutableHandleObject objp, MutableHandleShape propp);
     static JSBool obj_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                                     MutableHandleObject objp, JSProperty **propp);
+                                     MutableHandleObject objp, MutableHandleShape propp);
     static JSBool obj_lookupElement(JSContext *cx, HandleObject obj, uint32_t index,
-                                    MutableHandleObject objp, JSProperty **propp);
+                                    MutableHandleObject objp, MutableHandleShape propp);
     static JSBool obj_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                                    MutableHandleObject objp, JSProperty **propp);
+                                    MutableHandleObject objp, MutableHandleShape propp);
 
     static JSBool obj_getGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
     static JSBool obj_getPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp);
     static JSBool obj_getElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, unsigned *attrsp);
     static JSBool obj_getSpecialAttributes(JSContext *cx, HandleObject obj, HandleSpecialId sid, unsigned *attrsp);
 
     static JSBool obj_setGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
     static JSBool obj_setPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp);
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -4627,25 +4627,25 @@ HasIndexedProperty(JSXML *xml, uint32_t 
 }
 
 static JSBool
 HasSimpleContent(JSXML *xml);
 
 static JSBool
 HasFunctionProperty(JSContext *cx, JSObject *obj_, jsid funid_, JSBool *found)
 {
-    JSProperty *prop;
     JSXML *xml;
 
     JS_ASSERT(obj_->getClass() == &XMLClass);
 
     RootedId funid(cx, funid_);
 
     Rooted<JSObject*> obj(cx, obj_);
     RootedObject pobj(cx);
+    RootedShape prop(cx);
     if (!baseops::LookupProperty(cx, obj, funid, &pobj, &prop))
         return false;
     if (!prop) {
         xml = (JSXML *) obj->getPrivate();
         if (HasSimpleContent(xml)) {
             /*
              * Search in String.prototype to set found whenever
              * GetXMLFunction returns existing function.
@@ -4738,18 +4738,18 @@ HasProperty(JSContext *cx, JSObject *obj
  * We partially workaround the problem in GetXMLFunction. There we take
  * advantage of the fact that typically function:: is used to access the
  * functions from XML.prototype. So when js_GetProperty returns a non-function
  * property, we assume that it represents the result of GetProperty setter
  * hiding the function and use an extra prototype chain lookup to recover it.
  * For a proper solution see bug 355257.
 */
 static JSBool
-xml_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHandleObject objp,
-                  JSProperty **propp)
+xml_lookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
+                  MutableHandleObject objp, MutableHandleShape propp)
 {
     JSBool found;
     JSXML *xml;
     uint32_t i;
     JSObject *qn;
 
     RootedId funid(cx);
 
@@ -4761,68 +4761,68 @@ xml_lookupGeneric(JSContext *cx, HandleO
         if (!qn)
             return JS_FALSE;
         if (!JSID_IS_VOID(funid))
             return baseops::LookupProperty(cx, obj, funid, objp, propp);
         found = HasNamedProperty(xml, qn);
     }
     if (!found) {
         objp.set(NULL);
-        *propp = NULL;
+        propp.set(NULL);
     } else {
         Shape *shape =
             js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty,
                                  SHAPE_INVALID_SLOT, JSPROP_ENUMERATE,
                                  0, 0);
         if (!shape)
             return JS_FALSE;
 
         objp.set(obj);
-        *propp = (JSProperty *) shape;
+        propp.set(shape);
     }
     return JS_TRUE;
 }
 
 static JSBool
 xml_lookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                   MutableHandleObject objp, JSProperty **propp)
+                   MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return xml_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 xml_lookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
-                  JSProperty **propp)
+                  MutableHandleShape propp)
 {
     JSXML *xml = reinterpret_cast<JSXML *>(obj->getPrivate());
     if (!HasIndexedProperty(xml, index)) {
         objp.set(NULL);
-        *propp = NULL;
+        propp.set(NULL);
         return true;
     }
 
     jsid id;
     if (!IndexToId(cx, index, &id))
         return false;
 
     Shape *shape =
         js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, SHAPE_INVALID_SLOT,
                              JSPROP_ENUMERATE, 0, 0);
     if (!shape)
         return false;
 
     objp.set(obj);
-    *propp = (JSProperty *) shape;
+    propp.set(shape);
     return true;
 }
 
 static JSBool
 xml_lookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                  MutableHandleObject objp, JSProperty **propp)
+                  MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return xml_lookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 xml_defineGeneric(JSContext *cx, HandleObject obj, HandleId id, const Value *v,
                   PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
@@ -7740,17 +7740,16 @@ js_FindXMLProperty(JSContext *cx, const 
 {
     JSObject *nameobj;
     jsval v;
     JSObject *qn;
     RootedId funid(cx);
     JSObject *obj, *target, *proto;
     JSXML *xml;
     JSBool found;
-    JSProperty *prop;
 
     JS_ASSERT(nameval.isObject());
     nameobj = &nameval.toObject();
     if (nameobj->getClass() == &AnyNameClass) {
         v = STRING_TO_JSVAL(cx->runtime->atomState.starAtom);
         nameobj = ConstructObjectWithArguments(cx, &QNameClass, 1, &v);
         if (!nameobj)
             return JS_FALSE;
@@ -7787,16 +7786,17 @@ js_FindXMLProperty(JSContext *cx, const 
             }
             if (found) {
                 *idp = OBJECT_TO_JSID(nameobj);
                 objp.set(target);
                 return JS_TRUE;
             }
         } else if (!JSID_IS_VOID(funid)) {
             RootedObject pobj(cx);
+            RootedShape prop(cx);
             if (!target->lookupGeneric(cx, funid, &pobj, &prop))
                 return JS_FALSE;
             if (prop) {
                 *idp = funid;
                 objp.set(target);
                 return JS_TRUE;
             }
         }
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -5066,23 +5066,22 @@ mjit::Compiler::testSingletonProperty(Ha
         if (!nobj->isNative())
             return false;
         if (nobj->getClass()->ops.lookupGeneric)
             return false;
         nobj = nobj->getProto();
     }
 
     RootedObject holder(cx);
-    JSProperty *prop = NULL;
-    if (!obj->lookupGeneric(cx, id, &holder, &prop))
+    RootedShape shape(cx);
+    if (!obj->lookupGeneric(cx, id, &holder, &shape))
         return false;
-    if (!prop)
+    if (!shape)
         return false;
 
-    Shape *shape = (Shape *) prop;
     if (shape->hasDefaultGetter()) {
         if (!shape->hasSlot())
             return false;
         if (holder->getSlot(shape->slot()).isUndefined())
             return false;
     } else {
         return false;
     }
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -2681,28 +2681,27 @@ mjit::Compiler::jsop_initprop()
     if (!baseobj || monitored(PC)) {
         prepareStubCall(Uses(2));
         masm.move(ImmPtr(name), Registers::ArgReg1);
         INLINE_STUBCALL(stubs::InitProp, REJOIN_FALLTHROUGH);
         return;
     }
 
     RootedObject holder(cx);
-    JSProperty *prop = NULL;
+    RootedShape shape(cx);
     Rooted<jsid> id(cx, NameToId(name));
 #ifdef DEBUG
     bool res =
 #endif
-    LookupPropertyWithFlags(cx, baseobj, id, JSRESOLVE_QUALIFIED, &holder, &prop);
-    JS_ASSERT(res && prop && holder == baseobj);
+    LookupPropertyWithFlags(cx, baseobj, id, JSRESOLVE_QUALIFIED, &holder, &shape);
+    JS_ASSERT(res && shape && holder == baseobj);
 
     RegisterID objReg = frame.copyDataIntoReg(obj);
 
     /* Perform the store. */
-    Shape *shape = (Shape *) prop;
     Address address = masm.objPropAddress(baseobj, objReg, shape->slot());
     frame.storeTo(fe, address);
     frame.freeReg(objReg);
 }
 
 void
 mjit::Compiler::jsop_initelem()
 {
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -449,45 +449,43 @@ class SetPropCompiler : public PICStubCo
         if (clasp->setProperty != JS_StrictPropertyStub)
             return disable("set property hook");
         if (clasp->ops.lookupProperty)
             return disable("ops lookup property hook");
         if (clasp->ops.setProperty)
             return disable("ops set property hook");
 
         RootedObject holder(cx);
-        JSProperty *prop = NULL;
+        RootedShape shape(cx);
 
         /* lookupProperty can trigger recompilations. */
         RecompilationMonitor monitor(cx);
-        if (!obj->lookupProperty(cx, name, &holder, &prop))
+        if (!obj->lookupProperty(cx, name, &holder, &shape))
             return error();
         if (monitor.recompiled())
             return Lookup_Uncacheable;
 
         /* If the property exists but is on a prototype, treat as addprop. */
-        if (prop && holder != obj) {
-            Shape *shape = (Shape *) prop;
-
+        if (shape && holder != obj) {
             if (!holder->isNative())
                 return disable("non-native holder");
 
             if (!shape->writable())
                 return disable("readonly");
             if (!shape->hasDefaultSetter() || !shape->hasDefaultGetter())
                 return disable("getter/setter in prototype");
             if (shape->hasShortID())
                 return disable("short ID in prototype");
             if (!shape->hasSlot())
                 return disable("missing slot");
 
-            prop = NULL;
+            shape = NULL;
         }
 
-        if (!prop) {
+        if (!shape) {
             /* Adding a property to the object. */
             if (obj->isDelegate())
                 return disable("delegate");
             if (!obj->isExtensible())
                 return disable("not extensible");
 
             if (clasp->addProperty != JS_PropertyStub)
                 return disable("add property hook");
@@ -518,17 +516,17 @@ class SetPropCompiler : public PICStubCo
             unsigned flags = 0;
             PropertyOp getter = clasp->getProperty;
 
             /*
              * Define the property but do not set it yet. For setmethod,
              * populate the slot to satisfy the method invariant (in case we
              * hit an early return below).
              */
-            Shape *shape =
+            shape =
                 obj->putProperty(cx, name, getter, clasp->setProperty,
                                  SHAPE_INVALID_SLOT, JSPROP_ENUMERATE, flags, 0);
             if (!shape)
                 return error();
 
             if (monitor.recompiled())
                 return Lookup_Uncacheable;
 
@@ -570,17 +568,16 @@ class SetPropCompiler : public PICStubCo
 #endif
 
             if (pic.typeMonitored && !updateMonitoredTypes())
                 return Lookup_Uncacheable;
 
             return generateStub(initialShape, shape, true);
         }
 
-        Shape *shape = (Shape *) prop;
         if (!shape->writable())
             return disable("readonly");
         if (shape->hasDefaultSetter()) {
             if (!shape->hasSlot())
                 return disable("invalid slot");
             if (pic.typeMonitored && !updateMonitoredTypes())
                 return Lookup_Uncacheable;
         } else {
@@ -656,24 +653,24 @@ struct GetPropHelper {
     RootedObject       obj;
     RootedPropertyName name;
     IC                 &ic;
     VMFrame            &f;
 
     // These fields are set by |bind| and |lookup|. After a call to either
     // function, these are set exactly as they are in JSOP_GETPROP or JSOP_NAME.
     RootedObject       holder;
-    JSProperty         *prop;
+    RootedShape        prop;
 
     // This field is set by |bind| and |lookup| only if they returned
     // Lookup_Cacheable, otherwise it is NULL.
-    Shape *shape;
+    RootedShape        shape;
 
     GetPropHelper(JSContext *cx, JSObject *obj, PropertyName *name, IC &ic, VMFrame &f)
-      : cx(cx), obj(cx, obj), name(cx, name), ic(ic), f(f), holder(cx), prop(NULL), shape(NULL)
+      : cx(cx), obj(cx, obj), name(cx, name), ic(ic), f(f), holder(cx), prop(cx), shape(cx)
     { }
 
   public:
     LookupStatus bind() {
         RecompilationMonitor monitor(cx);
         RootedObject scopeChain(cx, cx->stack.currentScriptedScopeChain());
         if (js_CodeSpec[*f.pc()].format & JOF_GNAME)
             scopeChain = &scopeChain->global();
@@ -682,17 +679,17 @@ struct GetPropHelper {
         if (monitor.recompiled())
             return Lookup_Uncacheable;
         if (!prop)
             return ic.disable(cx, "lookup failed");
         if (!obj->isNative())
             return ic.disable(cx, "non-native");
         if (!IsCacheableProtoChain(obj, holder))
             return ic.disable(cx, "non-native holder");
-        shape = (Shape *)prop;
+        shape = prop;
         return Lookup_Cacheable;
     }
 
     LookupStatus lookup() {
         JSObject *aobj = obj;
         if (obj->isDenseArray())
             aobj = obj->getProto();
         if (!aobj->isNative())
@@ -703,17 +700,17 @@ struct GetPropHelper {
             return ic.error(cx);
         if (monitor.recompiled())
             return Lookup_Uncacheable;
 
         if (!prop)
             return ic.disable(f, "lookup failed");
         if (!IsCacheableProtoChain(obj, holder))
             return ic.disable(f, "non-native holder");
-        shape = (Shape *)prop;
+        shape = prop;
         return Lookup_Cacheable;
     }
 
     LookupStatus testForGet() {
         if (!shape->hasDefaultGetter()) {
             if (shape->hasGetterValue()) {
                 JSObject *getterObj = shape->getterObject();
                 if (!getterObj->isFunction() || !getterObj->toFunction()->isNative())
@@ -1670,17 +1667,17 @@ class ScopeNameCompiler : public PICStub
 
         return disable("scope object not handled yet");
     }
 
     bool retrieve(Value *vp, PICInfo::Kind kind)
     {
         JSObject *obj = getprop.obj;
         Rooted<JSObject*> holder(cx, getprop.holder);
-        const JSProperty *prop = getprop.prop;
+        RootedShape prop(cx, getprop.prop);
 
         if (!prop) {
             /* Kludge to allow (typeof foo == "undefined") tests. */
             if (kind == ic::PICInfo::NAME) {
                 JSOp op2 = JSOp(f.pc()[JSOP_NAME_LENGTH]);
                 if (op2 == JSOP_TYPEOF) {
                     vp->setUndefined();
                     return true;
@@ -1693,17 +1690,17 @@ class ScopeNameCompiler : public PICStub
         // If the property was found, but we decided not to cache it, then
         // take a slow path and do a full property fetch.
         if (!getprop.shape) {
             if (!obj->getProperty(cx, name, vp))
                 return false;
             return true;
         }
 
-        Shape *shape = getprop.shape;
+        RootedShape shape(cx, getprop.shape);
         Rooted<JSObject*> normalized(cx, obj);
         if (obj->isWith() && !shape->hasDefaultGetter())
             normalized = &obj->asWith().object();
         NATIVE_GET(cx, normalized, holder, shape, 0, vp, return false);
         return true;
     }
 };
 
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -188,17 +188,17 @@ stubs::ToId(VMFrame &f)
 
 void JS_FASTCALL
 stubs::ImplicitThis(VMFrame &f, PropertyName *name_)
 {
     RootedObject scopeObj(f.cx, f.cx->stack.currentScriptedScopeChain());
     RootedPropertyName name(f.cx, name_);
 
     RootedObject obj(f.cx), obj2(f.cx);
-    JSProperty *prop;
+    RootedShape prop(f.cx);
     if (!FindPropertyHelper(f.cx, name, false, scopeObj, &obj, &obj2, &prop))
         THROW();
 
     if (!ComputeImplicitThis(f.cx, obj, &f.regs.sp[0]))
         THROW();
 }
 
 void JS_FASTCALL
@@ -333,37 +333,36 @@ stubs::DefFun(VMFrame &f, JSFunction *fu
      * We define the function as a property of the variable object and not the
      * current scope chain even for the case of function expression statements
      * and functions defined by eval inside let or with blocks.
      */
     Rooted<JSObject*> parent(cx, &fp->varObj());
 
     /* ES5 10.5 (NB: with subsequent errata). */
     PropertyName *name = fun->atom->asPropertyName();
-    JSProperty *prop = NULL;
+    RootedShape shape(cx);
     RootedObject pobj(cx);
-    if (!parent->lookupProperty(cx, name, &pobj, &prop))
+    if (!parent->lookupProperty(cx, name, &pobj, &shape))
         THROW();
 
     Value rval = ObjectValue(*fun);
 
     do {
         /* Steps 5d, 5f. */
-        if (!prop || pobj != parent) {
+        if (!shape || pobj != parent) {
             if (!parent->defineProperty(cx, name, rval,
                                         JS_PropertyStub, JS_StrictPropertyStub, attrs))
             {
                 THROW();
             }
             break;
         }
 
         /* Step 5e. */
         JS_ASSERT(parent->isNative());
-        Shape *shape = reinterpret_cast<Shape *>(prop);
         if (parent->isGlobal()) {
             if (shape->configurable()) {
                 if (!parent->defineProperty(cx, name, rval,
                                             JS_PropertyStub, JS_StrictPropertyStub, attrs))
                 {
                     THROW();
                 }
                 break;
@@ -1334,17 +1333,17 @@ stubs::Pos(VMFrame &f)
 
 void JS_FASTCALL
 stubs::DelName(VMFrame &f, PropertyName *name_)
 {
     RootedObject scopeObj(f.cx, f.cx->stack.currentScriptedScopeChain());
     RootedPropertyName name(f.cx, name_);
 
     RootedObject obj(f.cx), obj2(f.cx);
-    JSProperty *prop;
+    RootedShape prop(f.cx);
     if (!FindProperty(f.cx, name, scopeObj, &obj, &obj2, &prop))
         THROW();
 
     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
     JS_ASSERT(!f.script()->strictModeCode);
 
     /* ECMA says to return true if name is undefined or inherited. */
     f.regs.sp++;
@@ -1434,17 +1433,17 @@ stubs::In(VMFrame &f)
     }
 
     JSObject *obj = &rref.toObject();
     RootedId id(cx);
     if (!FetchElementId(f.cx, obj, f.regs.sp[-2], id.address(), &f.regs.sp[-2]))
         THROWV(JS_FALSE);
 
     RootedObject obj2(cx);
-    JSProperty *prop;
+    RootedShape prop(cx);
     if (!obj->lookupGeneric(cx, id, &obj2, &prop))
         THROWV(JS_FALSE);
 
     return !!prop;
 }
 
 template void JS_FASTCALL stubs::DelElem<true>(VMFrame &f);
 template void JS_FASTCALL stubs::DelElem<false>(VMFrame &f);
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2684,29 +2684,28 @@ ShapeOf(JSContext *cx, unsigned argc, JS
  * If referent has an own property named id, copy that property to obj[id].
  * Since obj is native, this isn't totally transparent; properties of a
  * non-native referent may be simplified to data properties.
  */
 static JSBool
 CopyProperty(JSContext *cx, HandleObject obj, HandleObject referent, HandleId id,
              unsigned lookupFlags, MutableHandleObject objp)
 {
-    JSProperty *prop;
+    RootedShape shape(cx);
     PropertyDescriptor desc;
     unsigned propFlags = 0;
     RootedObject obj2(cx);
 
     objp.set(NULL);
     if (referent->isNative()) {
-        if (!LookupPropertyWithFlags(cx, referent, id, lookupFlags, &obj2, &prop))
+        if (!LookupPropertyWithFlags(cx, referent, id, lookupFlags, &obj2, &shape))
             return false;
         if (obj2 != referent)
             return true;
 
-        const Shape *shape = (Shape *) prop;
         if (shape->hasSlot()) {
             desc.value = referent->nativeGetSlot(shape->slot());
         } else {
             desc.value.setUndefined();
         }
 
         desc.attrs = shape->attributes();
         desc.getter = shape->getter();
@@ -2719,17 +2718,17 @@ CopyProperty(JSContext *cx, HandleObject
         propFlags = shape->getFlags();
    } else if (IsProxy(referent)) {
         PropertyDescriptor desc;
         if (!Proxy::getOwnPropertyDescriptor(cx, referent, id, false, &desc))
             return false;
         if (!desc.obj)
             return true;
     } else {
-        if (!referent->lookupGeneric(cx, id, objp, &prop))
+        if (!referent->lookupGeneric(cx, id, objp, &shape))
             return false;
         if (objp != referent)
             return true;
         if (!referent->getGeneric(cx, id, &desc.value) ||
             !referent->getGenericAttributes(cx, id, &desc.attrs)) {
             return false;
         }
         desc.attrs &= JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -254,17 +254,17 @@ args_enumerate(JSContext *cx, HandleObje
     for (int i = -2; i != argc; i++) {
         id = (i == -2)
              ? NameToId(cx->runtime->atomState.lengthAtom)
              : (i == -1)
              ? NameToId(cx->runtime->atomState.calleeAtom)
              : INT_TO_JSID(i);
 
         RootedObject pobj(cx);
-        JSProperty *prop;
+        RootedShape prop(cx);
         if (!baseops::LookupProperty(cx, argsobj, id, &pobj, &prop))
             return false;
     }
     return true;
 }
 
 static JSBool
 StrictArgGetter(JSContext *cx, HandleObject obj, HandleId id, Value *vp)
@@ -364,17 +364,17 @@ strictargs_enumerate(JSContext *cx, Hand
 {
     Rooted<StrictArgumentsObject*> argsobj(cx, &obj->asStrictArguments());
 
     /*
      * Trigger reflection in strictargs_resolve using a series of
      * js_LookupProperty calls.
      */
     RootedObject pobj(cx);
-    JSProperty *prop;
+    RootedShape prop(cx);
     RootedId id(cx);
 
     // length
     id = NameToId(cx->runtime->atomState.lengthAtom);
     if (!baseops::LookupProperty(cx, argsobj, id, &pobj, &prop))
         return false;
 
     // callee
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4408,17 +4408,17 @@ DebuggerEnv_find(JSContext *cx, unsigned
 
     {
         AutoCompartment ac(cx, env);
         if (!ac.enter() || !cx->compartment->wrapId(cx, id.address()))
             return false;
 
         /* This can trigger resolve hooks. */
         ErrorCopier ec(ac, dbg->toJSObject());
-        JSProperty *prop = NULL;
+        RootedShape prop(cx);
         RootedObject pobj(cx);
         for (; env && !prop; env = env->enclosingScope()) {
             if (!env->lookupGeneric(cx, id, &pobj, &prop))
                 return false;
             if (prop)
                 break;
         }
     }
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -346,42 +346,42 @@ WithObject::create(JSContext *cx, Handle
 
     obj->setFixedSlot(THIS_SLOT, ObjectValue(*thisp));
 
     return &obj->asWith();
 }
 
 static JSBool
 with_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
-                   MutableHandleObject objp, JSProperty **propp)
+                   MutableHandleObject objp, MutableHandleShape propp)
 {
     return obj->asWith().object().lookupGeneric(cx, id, objp, propp);
 }
 
 static JSBool
 with_LookupProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
-                    MutableHandleObject objp, JSProperty **propp)
+                    MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return with_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
-with_LookupElement(JSContext *cx, HandleObject obj, uint32_t index, MutableHandleObject objp,
-                   JSProperty **propp)
+with_LookupElement(JSContext *cx, HandleObject obj, uint32_t index,
+                   MutableHandleObject objp, MutableHandleShape propp)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, id.address()))
         return false;
     return with_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 with_LookupSpecial(JSContext *cx, HandleObject obj, HandleSpecialId sid,
-                   MutableHandleObject objp, JSProperty **propp)
+                   MutableHandleObject objp, MutableHandleShape propp)
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return with_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static JSBool
 with_GetGeneric(JSContext *cx, HandleObject obj, HandleObject receiver, HandleId id, Value *vp)
 {