Remove JSObject::title. Bug 606029, r=igor.
authorJason Orendorff <jorendorff@mozilla.com>
Fri, 22 Oct 2010 19:04:22 -0500
changeset 56567 60bdafdffdb929a45b6d30c99b5349cbf57c892a
parent 56561 8b6a5c70647f9500a32647d1e74b647ce0e43106
child 56568 8901fae3833adaf2442e6628540d5e9412824c0d
push id16602
push userrsayre@mozilla.com
push dateWed, 27 Oct 2010 01:10:03 +0000
treeherdermozilla-central@7b83033bb6f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersigor
bugs606029
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Remove JSObject::title. Bug 606029, r=igor.
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsbuiltins.cpp
js/src/jsclone.cpp
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsinterp.cpp
js/src/jsiter.cpp
js/src/jslock.cpp
js/src/jslock.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsparse.cpp
js/src/jspropertycache.cpp
js/src/jspropertycacheinlines.h
js/src/jsprvtd.h
js/src/jsregexp.cpp
js/src/jsscope.cpp
js/src/jsscope.h
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jsxml.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/StubCalls-inl.h
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1711,49 +1711,40 @@ JS_ResolveStandardClass(JSContext *cx, J
 
         if (!stdnm->init(cx, obj))
             return JS_FALSE;
         *resolved = JS_TRUE;
     }
     return JS_TRUE;
 }
 
-static JSBool
-AlreadyHasOwnProperty(JSContext *cx, JSObject *obj, JSAtom *atom)
-{
-    JS_LOCK_OBJ(cx, obj);
-    bool found = obj->nativeContains(ATOM_TO_JSID(atom));
-    JS_UNLOCK_OBJ(cx, obj);
-    return found;
-}
-
 JS_PUBLIC_API(JSBool)
 JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj)
 {
     JSRuntime *rt;
     JSAtom *atom;
     uintN i;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     rt = cx->runtime;
 
     /* Check whether we need to bind 'undefined' and define it if so. */
     atom = rt->atomState.typeAtoms[JSTYPE_VOID];
-    if (!AlreadyHasOwnProperty(cx, obj, atom) &&
+    if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
         !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(),
                              PropertyStub, PropertyStub,
                              JSPROP_PERMANENT | JSPROP_READONLY)) {
         return JS_FALSE;
     }
 
     /* Initialize any classes that have not been resolved yet. */
     for (i = 0; standard_class_atoms[i].init; i++) {
         atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
-        if (!AlreadyHasOwnProperty(cx, obj, atom) &&
+        if (!obj->nativeContains(ATOM_TO_JSID(atom)) &&
             !standard_class_atoms[i].init(cx, obj)) {
             return JS_FALSE;
         }
     }
 
     return JS_TRUE;
 }
 
@@ -1809,17 +1800,17 @@ AddAtomToArray(JSContext *cx, JSAtom *at
     *ip = i + 1;
     return ida;
 }
 
 static JSIdArray *
 EnumerateIfResolved(JSContext *cx, JSObject *obj, JSAtom *atom, JSIdArray *ida,
                     jsint *ip, JSBool *foundp)
 {
-    *foundp = AlreadyHasOwnProperty(cx, obj, atom);
+    *foundp = obj->nativeContains(ATOM_TO_JSID(atom));
     if (*foundp)
         ida = AddAtomToArray(cx, atom, ida, ip);
     return ida;
 }
 
 JS_PUBLIC_API(JSIdArray *)
 JS_EnumerateResolvedStandardClasses(JSContext *cx, JSObject *obj, JSIdArray *ida)
 {
@@ -3173,27 +3164,25 @@ LookupResult(JSContext *cx, JSObject *ob
         return JS_TRUE;
     }
 
     if (obj2->isNative()) {
         Shape *shape = (Shape *) prop;
 
         if (shape->isMethod()) {
             AutoShapeRooter root(cx, shape);
-            JS_UNLOCK_OBJ(cx, obj2);
             vp->setObject(shape->methodObject());
             return obj2->methodReadBarrier(cx, *shape, vp);
         }
 
         /* Peek at the native property's slot value, without doing a Get. */
         if (obj2->containsSlot(shape->slot))
-            *vp = obj2->lockedGetSlot(shape->slot);
+            *vp = obj2->nativeGetSlot(shape->slot);
         else
             vp->setBoolean(true);
-        JS_UNLOCK_OBJ(cx, obj2);
     } else if (obj2->isDenseArray()) {
         return js_GetDenseArrayElementValue(cx, obj2, id, vp);
     } else {
         /* XXX bad API: no way to return "defined but value unknown" */
         vp->setBoolean(true);
     }
     return true;
 }
@@ -3245,33 +3234,25 @@ JS_LookupPropertyWithFlagsById(JSContext
 JS_PUBLIC_API(JSBool)
 JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name, uintN flags, jsval *vp)
 {
     JSObject *obj2;
     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     return atom && JS_LookupPropertyWithFlagsById(cx, obj, ATOM_TO_JSID(atom), flags, &obj2, vp);
 }
 
-static JSBool
-HasPropertyResult(JSContext *cx, JSObject *obj2, JSProperty *prop, JSBool *foundp)
-{
-    *foundp = (prop != NULL);
-    if (prop)
-        obj2->dropProperty(cx, prop);
-    return true;
-}
-
 JS_PUBLIC_API(JSBool)
 JS_HasPropertyById(JSContext *cx, JSObject *obj, jsid id, JSBool *foundp)
 {
     JSObject *obj2;
     JSProperty *prop;
-    return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
-                              &obj2, &prop) &&
-           HasPropertyResult(cx, obj2, prop, foundp);
+    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, jsint index, JSBool *foundp)
 {
     return JS_HasPropertyById(cx, obj, INT_TO_JSID(index), foundp);
 }
 
@@ -3299,24 +3280,20 @@ JS_AlreadyHasOwnPropertyById(JSContext *
         JSObject *obj2;
         JSProperty *prop;
 
         if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING,
                                 &obj2, &prop)) {
             return JS_FALSE;
         }
         *foundp = (obj == obj2);
-        if (prop)
-            obj2->dropProperty(cx, prop);
         return JS_TRUE;
     }
 
-    JS_LOCK_OBJ(cx, obj);
     *foundp = obj->nativeContains(id);
-    JS_UNLOCK_OBJ(cx, obj);
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AlreadyHasOwnElement(JSContext *cx, JSObject *obj, jsint index, JSBool *foundp)
 {
     return JS_AlreadyHasOwnPropertyById(cx, obj, INT_TO_JSID(index), foundp);
 }
@@ -3517,72 +3494,66 @@ JS_AliasProperty(JSContext *cx, JSObject
         return JS_FALSE;
     if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         js_ReportIsNotDefined(cx, name);
         return JS_FALSE;
     }
     if (obj2 != obj || !obj->isNative()) {
-        obj2->dropProperty(cx, prop);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
                              alias, name, obj2->getClass()->name);
         return JS_FALSE;
     }
     atom = js_Atomize(cx, alias, strlen(alias), 0);
     if (!atom) {
         ok = JS_FALSE;
     } else {
         shape = (Shape *)prop;
         ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(atom),
                                    shape->getter(), shape->setter(), shape->slot,
                                    shape->attributes(), shape->getFlags() | Shape::ALIAS,
                                    shape->shortid)
               != NULL);
     }
-    JS_UNLOCK_OBJ(cx, obj);
     return ok;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
 {
     JSObject *obj2;
     JSProperty *prop;
     Shape *shape;
-    JSBool ok;
 
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     JSAtom *atom = js_Atomize(cx, name, strlen(name), 0);
     if (!atom)
         return JS_FALSE;
     if (!LookupPropertyById(cx, obj, ATOM_TO_JSID(atom), JSRESOLVE_QUALIFIED, &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         js_ReportIsNotDefined(cx, name);
         return JS_FALSE;
     }
     if (obj2 != obj || !obj->isNative()) {
         char numBuf[12];
-        obj2->dropProperty(cx, prop);
         JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)alias);
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_ALIAS,
                              numBuf, name, obj2->getClass()->name);
         return JS_FALSE;
     }
     shape = (Shape *)prop;
-    ok = (js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
-                               shape->getter(), shape->setter(), shape->slot,
-                               shape->attributes(), shape->getFlags() | Shape::ALIAS,
-                               shape->shortid)
-          != NULL);
-    JS_UNLOCK_OBJ(cx, obj);
-    return ok;
+    return js_AddNativeProperty(cx, obj, INT_TO_JSID(alias),
+                                shape->getter(), shape->setter(), shape->slot,
+                                shape->attributes(), shape->getFlags() | Shape::ALIAS,
+                                shape->shortid)
+           != NULL;
 }
 
 static JSBool
 GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                           JSBool own, PropertyDescriptor *desc)
 {
     JSObject *obj2;
     JSProperty *prop;
@@ -3591,38 +3562,35 @@ GetPropertyDescriptorById(JSContext *cx,
         return JS_FALSE;
 
     if (!prop || (own && obj != obj2)) {
         desc->obj = NULL;
         desc->attrs = 0;
         desc->getter = NULL;
         desc->setter = NULL;
         desc->value.setUndefined();
-        if (prop)
-            obj2->dropProperty(cx, prop);
         return JS_TRUE;
     }
 
     desc->obj = obj2;
     if (obj2->isNative()) {
         Shape *shape = (Shape *) prop;
         desc->attrs = shape->attributes();
 
         if (shape->isMethod()) {
             desc->getter = desc->setter = PropertyStub;
             desc->value.setObject(shape->methodObject());
         } else {
             desc->getter = shape->getter();
             desc->setter = shape->setter();
             if (obj2->containsSlot(shape->slot))
-                desc->value = obj2->lockedGetSlot(shape->slot);
+                desc->value = obj2->nativeGetSlot(shape->slot);
             else
                 desc->value.setUndefined();
         }
-        JS_UNLOCK_OBJ(cx, obj2);
     } else {
         if (obj2->isProxy()) {
             JSAutoResolveFlags rf(cx, flags);
             return own
                    ? JSProxy::getOwnPropertyDescriptor(cx, obj2, id, false, desc)
                    : JSProxy::getPropertyDescriptor(cx, obj2, id, false, desc);
         }
         if (!obj2->getAttributes(cx, id, &desc->attrs))
@@ -3710,18 +3678,16 @@ SetPropertyAttributesById(JSContext *cx,
 {
     JSObject *obj2;
     JSProperty *prop;
 
     if (!LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop))
         return false;
     if (!prop || obj != obj2) {
         *foundp = false;
-        if (prop)
-            obj2->dropProperty(cx, prop);
         return true;
     }
     JSBool ok = obj->isNative()
                 ? js_SetNativeAttributes(cx, obj, (Shape *) prop, attrs)
                 : obj->setAttributes(cx, id, &attrs);
     if (ok)
         *foundp = true;
     return ok;
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -379,17 +379,16 @@ GetArrayElement(JSContext *cx, JSObject 
     JSObject *obj2;
     JSProperty *prop;
     if (!obj->lookupProperty(cx, idr.id(), &obj2, &prop))
         return JS_FALSE;
     if (!prop) {
         *hole = JS_TRUE;
         vp->setUndefined();
     } else {
-        obj2->dropProperty(cx, prop);
         if (!obj->getProperty(cx, idr.id(), vp))
             return JS_FALSE;
         *hole = JS_FALSE;
     }
     return JS_TRUE;
 }
 
 /*
@@ -721,17 +720,16 @@ array_getProperty(JSContext *cx, JSObjec
         if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags,
                                        &obj2, &prop) < 0)
             return JS_FALSE;
 
         if (prop && obj2->isNative()) {
             shape = (const Shape *) prop;
             if (!js_NativeGet(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, vp))
                 return JS_FALSE;
-            JS_UNLOCK_OBJ(cx, obj2);
         }
         return JS_TRUE;
     }
 
     *vp = obj->getDenseArrayElement(i);
     return JS_TRUE;
 }
 
--- a/js/src/jsbuiltins.cpp
+++ b/js/src/jsbuiltins.cpp
@@ -180,46 +180,37 @@ js_StringToInt32(JSContext* cx, JSString
     return StringToNumberType<int32>(cx, str);
 }
 JS_DEFINE_CALLINFO_2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, ACCSET_NONE)
 
 /* Nb: it's always safe to set isDefinitelyAtom to false if you're unsure or don't know. */
 static inline JSBool
 AddPropertyHelper(JSContext* cx, JSObject* obj, Shape* shape, bool isDefinitelyAtom)
 {
-    JS_LOCK_OBJ(cx, obj);
     JS_ASSERT(shape->previous() == obj->lastProperty());
 
     if (obj->nativeEmpty()) {
         if (!obj->ensureClassReservedSlotsForEmptyObject(cx))
-            goto exit_trace;
+            return false;
     }
 
     uint32 slot;
     slot = shape->slot;
     JS_ASSERT(slot == obj->slotSpan());
 
     if (slot < obj->numSlots()) {
         JS_ASSERT(obj->getSlot(slot).isUndefined());
     } else {
         if (!obj->allocSlot(cx, &slot))
-            goto exit_trace;
+            return false;
         JS_ASSERT(slot == shape->slot);
     }
 
     obj->extend(cx, shape, isDefinitelyAtom);
-    if (js_IsPropertyCacheDisabled(cx))
-        goto exit_trace;
-
-    JS_UNLOCK_OBJ(cx, obj);
-    return true;
-
-  exit_trace:
-    JS_UNLOCK_OBJ(cx, obj);
-    return false;
+    return !js_IsPropertyCacheDisabled(cx);
 }
 
 JSBool FASTCALL
 js_AddProperty(JSContext* cx, JSObject* obj, Shape* shape)
 {
     return AddPropertyHelper(cx, obj, shape, /* isDefinitelyAtom = */false);
 }
 JS_DEFINE_CALLINFO_3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SHAPE, 0, ACCSET_STORE_ANY)
@@ -242,18 +233,16 @@ HasProperty(JSContext* cx, JSObject* obj
         if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass)
             return JS_NEITHER;
     }
 
     JSObject* obj2;
     JSProperty* prop;
     if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
         return JS_NEITHER;
-    if (prop)
-        obj2->dropProperty(cx, prop);
     return prop != NULL;
 }
 
 JSBool FASTCALL
 js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr)
 {
     JSAtom *atom = js_AtomizeString(cx, idstr, 0);
     if (!atom)
--- a/js/src/jsclone.cpp
+++ b/js/src/jsclone.cpp
@@ -554,18 +554,16 @@ JSStructuredCloneWriter::write(const Val
                 JSObject *obj2;
                 JSProperty *prop;
                 if (!js_HasOwnProperty(context(), obj->getOps()->lookupProperty, obj, id,
                                        &obj2, &prop)) {
                     return false;
                 }
 
                 if (prop) {
-                    obj2->dropProperty(context(), prop);
-
                     Value val;
                     if (!writeId(id) || !obj->getProperty(context(), id, &val) || !startWrite(val))
                         return false;
                 }
             }
         } else {
             out.writePair(SCTAG_NULL, 0);
             memory.remove(obj);
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -554,33 +554,30 @@ DropWatchPointAndUnlock(JSContext *cx, J
         if (wp2->shape == shape) {
             setter = wp->setter;
             break;
         }
     }
     DBG_UNLOCK(rt);
 
     if (!setter) {
-        JS_LOCK_OBJ(cx, wp->object);
-
         /*
          * If the property wasn't found on wp->object, or it isn't still being
          * watched, then someone else must have deleted or unwatched it, and we
          * don't need to change the property attributes.
          */
         const Shape *wprop = wp->object->nativeLookup(shape->id);
         if (wprop &&
             wprop->hasSetterValue() == shape->hasSetterValue() &&
             IsWatchedProperty(cx, *wprop)) {
             shape = wp->object->changeProperty(cx, wprop, 0, wprop->attributes(),
                                                wprop->getter(), wp->setter);
             if (!shape)
                 ok = false;
         }
-        JS_UNLOCK_OBJ(cx, wp->object);
     }
 
     cx->free(wp);
     return ok;
 }
 
 /*
  * NB: js_TraceWatchPoints does not acquire cx->runtime->debuggerLock, since
@@ -674,25 +671,23 @@ js_watch_set(JSContext *cx, JSObject *ob
          &wp->links != &rt->watchPointList;
          wp = (JSWatchPoint *)wp->links.next) {
         const Shape *shape = wp->shape;
         if (wp->object == obj && SHAPE_USERID(shape) == id &&
             !(wp->flags & JSWP_HELD)) {
             wp->flags |= JSWP_HELD;
             DBG_UNLOCK(rt);
 
-            JS_LOCK_OBJ(cx, obj);
             jsid propid = shape->id;
             jsid userid = SHAPE_USERID(shape);
-            JS_UNLOCK_OBJ(cx, obj);
 
             /* NB: wp is held, so we can safely dereference it still. */
             if (!wp->handler(cx, obj, propid,
                              obj->containsSlot(shape->slot)
-                             ? Jsvalify(obj->getSlotMT(cx, shape->slot))
+                             ? Jsvalify(obj->nativeGetSlot(shape->slot))
                              : JSVAL_VOID,
                              Jsvalify(vp), wp->closure)) {
                 DBG_LOCK(rt);
                 DropWatchPointAndUnlock(cx, wp, JSWP_HELD);
                 return JS_FALSE;
             }
 
             /*
@@ -776,17 +771,16 @@ JS_SetWatchPoint(JSContext *cx, JSObject
     JSObject *origobj;
     Value v;
     uintN attrs;
     jsid propid;
     JSObject *pobj;
     JSProperty *prop;
     const Shape *shape;
     JSRuntime *rt;
-    JSBool ok;
     JSWatchPoint *wp;
     PropertyOp watcher;
 
     origobj = obj;
     obj = obj->wrappedObject(cx);
     OBJ_TO_INNER_OBJECT(cx, obj);
     if (!obj)
         return JS_FALSE;
@@ -833,24 +827,23 @@ JS_SetWatchPoint(JSContext *cx, JSObject
         /* Clone the prototype property so we can watch the right object. */
         AutoValueRooter valroot(cx);
         PropertyOp getter, setter;
         uintN attrs, flags;
         intN shortid;
 
         if (pobj->isNative()) {
             valroot.set(pobj->containsSlot(shape->slot)
-                        ? pobj->lockedGetSlot(shape->slot)
+                        ? pobj->nativeGetSlot(shape->slot)
                         : UndefinedValue());
             getter = shape->getter();
             setter = shape->setter();
             attrs = shape->attributes();
             flags = shape->getFlags();
             shortid = shape->shortid;
-            JS_UNLOCK_OBJ(cx, pobj);
         } else {
             if (!pobj->getProperty(cx, propid, valroot.addr()) ||
                 !pobj->getAttributes(cx, propid, &attrs)) {
                 return JS_FALSE;
             }
             getter = setter = NULL;
             flags = 0;
             shortid = 0;
@@ -864,68 +857,59 @@ JS_SetWatchPoint(JSContext *cx, JSObject
         }
         shape = (Shape *) prop;
     }
 
     /*
      * At this point, prop/shape exists in obj, obj is locked, and we must
      * unlock the object before returning.
      */
-    ok = JS_TRUE;
     DBG_LOCK(rt);
     wp = FindWatchPoint(rt, obj, propid);
     if (!wp) {
         DBG_UNLOCK(rt);
         watcher = js_WrapWatchedSetter(cx, propid, shape->attributes(), shape->setter());
-        if (!watcher) {
-            ok = JS_FALSE;
-            goto out;
-        }
+        if (!watcher)
+            return JS_FALSE;
 
         wp = (JSWatchPoint *) cx->malloc(sizeof *wp);
-        if (!wp) {
-            ok = JS_FALSE;
-            goto out;
-        }
+        if (!wp)
+            return JS_FALSE;
         wp->handler = NULL;
         wp->closure = NULL;
         wp->object = obj;
         wp->setter = shape->setter();
         wp->flags = JSWP_LIVE;
 
         /* XXXbe nest in obj lock here */
         shape = js_ChangeNativePropertyAttrs(cx, obj, shape, 0, shape->attributes(),
                                              shape->getter(), watcher);
         if (!shape) {
             /* Self-link so DropWatchPointAndUnlock can JS_REMOVE_LINK it. */
             JS_INIT_CLIST(&wp->links);
             DBG_LOCK(rt);
             DropWatchPointAndUnlock(cx, wp, JSWP_LIVE);
-            ok = JS_FALSE;
-            goto out;
+            return JS_FALSE;
         }
         wp->shape = shape;
 
         /*
          * Now that wp is fully initialized, append it to rt's wp list.
          * Because obj is locked we know that no other thread could have added
          * a watchpoint for (obj, propid).
          */
         DBG_LOCK(rt);
         JS_ASSERT(!FindWatchPoint(rt, obj, propid));
         JS_APPEND_LINK(&wp->links, &rt->watchPointList);
         ++rt->debuggerMutations;
     }
     wp->handler = handler;
     wp->closure = reinterpret_cast<JSObject*>(closure);
     DBG_UNLOCK(rt);
-
-out:
-    JS_UNLOCK_OBJ(cx, obj);
-    return ok;
+    return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id,
                    JSWatchPointHandler *handlerp, JSObject **closurep)
 {
     JSRuntime *rt;
     JSWatchPoint *wp;
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -1708,31 +1708,29 @@ LookupCompileTimeConstant(JSContext *cx,
              */
             if (cg->inFunction()) {
                 if (cg->fun->lookupLocal(cx, atom, NULL) != JSLOCAL_NONE)
                     break;
             } else {
                 JS_ASSERT(cg->compileAndGo());
                 obj = cg->scopeChain;
 
-                JS_LOCK_OBJ(cx, obj);
                 const Shape *shape = obj->nativeLookup(ATOM_TO_JSID(atom));
                 if (shape) {
                     /*
                      * We're compiling code that will be executed immediately,
                      * not re-executed against a different scope chain and/or
                      * variable object.  Therefore we can get constant values
                      * from our variable object here.
                      */
                     if (!shape->writable() && !shape->configurable() &&
                         shape->hasDefaultGetter() && obj->containsSlot(shape->slot)) {
-                        *constp = obj->lockedGetSlot(shape->slot);
+                        *constp = obj->getSlot(shape->slot);
                     }
                 }
-                JS_UNLOCK_OBJ(cx, obj);
 
                 if (shape)
                     break;
             }
         }
     } while ((cg = (JSCodeGenerator *) cg->parent) != NULL);
     return JS_TRUE;
 }
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -458,18 +458,16 @@ exn_enumerate(JSContext *cx, JSObject *o
         (uint16)offsetof(JSAtomState, stackAtom),
     };
 
     atomState = &cx->runtime->atomState;
     for (i = 0; i != JS_ARRAY_LENGTH(offsets); ++i) {
         atom = *(JSAtom **)((uint8 *)atomState + offsets[i]);
         if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
             return JS_FALSE;
-        if (prop)
-            pobj->dropProperty(cx, prop);
     }
     return JS_TRUE;
 }
 
 static JSBool
 exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
             JSObject **objp)
 {
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -642,20 +642,16 @@ args_enumerate(JSContext *cx, JSObject *
                   : (i == -1)
                   ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom)
                   : INT_TO_JSID(i);
 
         JSObject *pobj;
         JSProperty *prop;
         if (!js_LookupProperty(cx, obj, id, &pobj, &prop))
             return false;
-
-        /* prop is null when the property was deleted. */
-        if (prop)
-            pobj->dropProperty(cx, prop);
     }
     return true;
 }
 
 namespace {
 
 JSBool
 StrictArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp)
@@ -763,44 +759,36 @@ strictargs_resolve(JSContext *cx, JSObje
 
 JSBool
 strictargs_enumerate(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isStrictArguments());
 
     /*
      * Trigger reflection in strictargs_resolve using a series of
-     * js_LookupProperty calls.  Beware deleted properties!
+     * js_LookupProperty calls.
      */
     JSObject *pobj;
     JSProperty *prop;
 
     // length
     if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), &pobj, &prop))
         return false;
-    if (prop)
-        pobj->dropProperty(cx, prop);
 
     // callee
     if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.calleeAtom), &pobj, &prop))
         return false;
-    if (prop)
-        pobj->dropProperty(cx, prop);
 
     // caller
     if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.callerAtom), &pobj, &prop))
         return false;
-    if (prop)
-        pobj->dropProperty(cx, prop);
 
     for (uint32 i = 0, argc = obj->getArgsInitialLength(); i < argc; i++) {
         if (!js_LookupProperty(cx, obj, INT_TO_JSID(i), &pobj, &prop))
             return false;
-        if (prop)
-            pobj->dropProperty(cx, prop);
     }
 
     return true;
 }
 
 } // namespace
 
 static void
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1020,20 +1020,16 @@ CheckRedeclaration(JSContext *cx, JSObje
     JS_ASSERT_IF(attrs == JSPROP_INITIALIZER, !propp);
 
     if (!obj->lookupProperty(cx, id, &obj2, &prop))
         return false;
     if (!prop)
         return true;
     if (obj2->isNative()) {
         oldAttrs = ((Shape *) prop)->attributes();
-
-        /* If our caller doesn't want prop, unlock obj2. */
-        if (!propp)
-            JS_UNLOCK_OBJ(cx, obj2);
     } else {
         if (!obj2->getAttributes(cx, id, &oldAttrs))
             return false;
     }
 
     if (!propp) {
         prop = NULL;
     } else {
@@ -1073,18 +1069,16 @@ CheckRedeclaration(JSContext *cx, JSObje
 
             /*
              * Allow redeclaration of an impermanent property (in which case
              * anyone could delete it and redefine it, willy-nilly).
              */
             if (!(oldAttrs & JSPROP_PERMANENT))
                 return JS_TRUE;
         }
-        if (prop)
-            obj2->dropProperty(cx, prop);
 
         report = JSREPORT_ERROR;
         isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0;
         if (!isFunction) {
             Value value;
             if (!obj->getProperty(cx, id, &value))
                 return JS_FALSE;
             isFunction = IsFunctionObject(value);
@@ -2015,48 +2009,45 @@ AssertValidPropertyCacheHit(JSContext *c
     if (JOF_OPMODE(*regs.pc) == JOF_NAME) {
         ok = js_FindProperty(cx, ATOM_TO_JSID(atom), &obj, &pobj, &prop);
     } else {
         obj = start;
         ok = js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop);
     }
     if (!ok)
         return false;
-    if (cx->runtime->gcNumber != sample || entry->vshape() != pobj->shape()) {
-        pobj->dropProperty(cx, prop);
+    if (cx->runtime->gcNumber != sample || entry->vshape() != pobj->shape())
         return true;
-    }
     JS_ASSERT(prop);
     JS_ASSERT(pobj == found);
 
     const Shape *shape = (Shape *) prop;
     if (entry->vword.isSlot()) {
         JS_ASSERT(entry->vword.toSlot() == shape->slot);
         JS_ASSERT(!shape->isMethod());
     } else if (entry->vword.isShape()) {
         JS_ASSERT(entry->vword.toShape() == shape);
         JS_ASSERT_IF(shape->isMethod(),
-                     &shape->methodObject() == &pobj->lockedGetSlot(shape->slot).toObject());
+                     &shape->methodObject() == &pobj->nativeGetSlot(shape->slot).toObject());
     } else {
         Value v;
         JS_ASSERT(entry->vword.isFunObj());
         JS_ASSERT(!entry->vword.isNull());
         JS_ASSERT(pobj->brandedOrHasMethodBarrier());
         JS_ASSERT(shape->hasDefaultGetterOrIsMethod());
         JS_ASSERT(pobj->containsSlot(shape->slot));
-        v = pobj->lockedGetSlot(shape->slot);
+        v = pobj->nativeGetSlot(shape->slot);
         JS_ASSERT(&entry->vword.toFunObj() == &v.toObject());
 
         if (shape->isMethod()) {
             JS_ASSERT(js_CodeSpec[*regs.pc].format & JOF_CALLOP);
             JS_ASSERT(&shape->methodObject() == &v.toObject());
         }
     }
 
-    pobj->dropProperty(cx, prop);
     return true;
 }
 
 #else
 # define ASSERT_VALID_PROPERTY_CACHE_HIT(pcoff,obj,pobj,entry) ((void) 0)
 #endif
 
 /*
@@ -2997,18 +2988,16 @@ BEGIN_CASE(JSOP_IN)
     JSObject *obj = &rref.toObject();
     jsid id;
     FETCH_ELEMENT_ID(obj, -2, id);
     JSObject *obj2;
     JSProperty *prop;
     if (!obj->lookupProperty(cx, id, &obj2, &prop))
         goto error;
     bool cond = prop != NULL;
-    if (prop)
-        obj2->dropProperty(cx, prop);
     TRY_BRANCH_AFTER_COND(cond, 2);
     regs.sp--;
     regs.sp[-1].setBoolean(cond);
 }
 END_CASE(JSOP_IN)
 
 BEGIN_CASE(JSOP_ITER)
 {
@@ -3073,18 +3062,17 @@ BEGIN_CASE(JSOP_FORNAME)
     JS_ASSERT(regs.sp - 1 >= regs.fp->base());
     JSAtom *atom;
     LOAD_ATOM(0, atom);
     jsid id = ATOM_TO_JSID(atom);
     JSObject *obj, *obj2;
     JSProperty *prop;
     if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
         goto error;
-    if (prop)
-        obj2->dropProperty(cx, prop);
+
     {
         AutoValueRooter tvr(cx);
         JS_ASSERT(regs.sp[-1].isObject());
         if (!IteratorNext(cx, &regs.sp[-1].toObject(), tvr.addr()))
             goto error;
         if (!obj->setProperty(cx, id, tvr.addr(), script->strictModeCode))
             goto error;
     }
@@ -3164,33 +3152,33 @@ END_CASE(JSOP_PICK)
 
 #define NATIVE_GET(cx,obj,pobj,shape,getHow,vp)                               \
     JS_BEGIN_MACRO                                                            \
         if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {         \
             /* Fast path for Object instance properties. */                   \
             JS_ASSERT((shape)->slot != SHAPE_INVALID_SLOT ||                  \
                       !shape->hasDefaultSetter());                            \
             if (((shape)->slot != SHAPE_INVALID_SLOT))                        \
-                *(vp) = (pobj)->lockedGetSlot((shape)->slot);                 \
+                *(vp) = (pobj)->nativeGetSlot((shape)->slot);                 \
             else                                                              \
                 (vp)->setUndefined();                                         \
         } else {                                                              \
             if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp))              \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
 #define NATIVE_SET(cx,obj,shape,entry,vp)                                     \
     JS_BEGIN_MACRO                                                            \
         TRACE_2(SetPropHit, entry, shape);                                    \
         if (shape->hasDefaultSetter() &&                                      \
             (shape)->slot != SHAPE_INVALID_SLOT &&                            \
             !(obj)->brandedOrHasMethodBarrier()) {                            \
             /* Fast path for, e.g., plain Object instance properties. */      \
-            (obj)->lockedSetSlot((shape)->slot, *vp);                         \
+            (obj)->nativeSetSlot((shape)->slot, *vp);                         \
         } else {                                                              \
             if (!js_NativeSet(cx, obj, shape, false, vp))                     \
                 goto error;                                                   \
         }                                                                     \
     JS_END_MACRO
 
 /*
  * Skip the JSOP_POP typically found after a JSOP_SET* opcode, where oplen is
@@ -3753,17 +3741,16 @@ BEGIN_CASE(JSOP_DELNAME)
         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);
     if (prop) {
-        obj2->dropProperty(cx, prop);
         if (!obj->deleteProperty(cx, id, &regs.sp[-1], false))
             goto error;
     }
 }
 END_CASE(JSOP_DELNAME)
 
 BEGIN_CASE(JSOP_DELPROP)
 {
@@ -3862,18 +3849,17 @@ BEGIN_CASE(JSOP_GNAMEDEC)
 
     JSObject *obj2;
     PropertyCacheEntry *entry;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom);
     if (!atom) {
         ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
         if (obj == obj2 && entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
-            JS_ASSERT(obj->containsSlot(slot));
-            Value &rref = obj->getSlotRef(slot);
+            Value &rref = obj->nativeGetSlotRef(slot);
             int32_t tmp;
             if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) {
                 int32_t inc = tmp + ((js_CodeSpec[op].format & JOF_INC) ? 1 : -1);
                 if (!(js_CodeSpec[op].format & JOF_POST))
                     tmp = inc;
                 rref.getInt32Ref() = inc;
                 PUSH_INT32(tmp);
                 len = JSOP_INCNAME_LENGTH;
@@ -3886,17 +3872,16 @@ BEGIN_CASE(JSOP_GNAMEDEC)
     id = ATOM_TO_JSID(atom);
     JSProperty *prop;
     if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
         goto error;
     if (!prop) {
         atomNotDefined = atom;
         goto atom_not_defined;
     }
-    obj2->dropProperty(cx, prop);
 }
 
 do_incop:
 {
     /*
      * We need a root to store the value to leave on the stack until
      * we have done with obj->setProperty.
      */
@@ -4102,18 +4087,17 @@ BEGIN_CASE(JSOP_GETXPROP)
             JSAtom *atom;
             JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
             if (!atom) {
                 ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry);
                 if (entry->vword.isFunObj()) {
                     rval.setObject(entry->vword.toFunObj());
                 } else if (entry->vword.isSlot()) {
                     uint32 slot = entry->vword.toSlot();
-                    JS_ASSERT(obj2->containsSlot(slot));
-                    rval = obj2->lockedGetSlot(slot);
+                    rval = obj2->nativeGetSlot(slot);
                 } else {
                     JS_ASSERT(entry->vword.isShape());
                     const Shape *shape = entry->vword.toShape();
                     NATIVE_GET(cx, obj, obj2, shape,
                                regs.fp->hasImacropc() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
                                &rval);
                 }
                 break;
@@ -4198,18 +4182,17 @@ BEGIN_CASE(JSOP_CALLPROP)
     JSAtom *atom;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
     if (!atom) {
         ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry);
         if (entry->vword.isFunObj()) {
             rval.setObject(entry->vword.toFunObj());
         } else if (entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
-            JS_ASSERT(obj2->containsSlot(slot));
-            rval = obj2->lockedGetSlot(slot);
+            rval = obj2->nativeGetSlot(slot);
         } else {
             JS_ASSERT(entry->vword.isShape());
             const Shape *shape = entry->vword.toShape();
             NATIVE_GET(cx, &objv.toObject(), obj2, shape, JSGET_NO_METHOD_BARRIER, &rval);
         }
         regs.sp[-1] = rval;
         assertSameCompartment(cx, regs.sp[-1]);
         PUSH_COPY(lval);
@@ -4339,25 +4322,17 @@ BEGIN_CASE(JSOP_SETMETHOD)
                     PCMETER(cache->setpchits++);
                     NATIVE_SET(cx, obj, shape, entry, &rval);
                     break;
                 }
             } else {
                 JS_ASSERT(obj->isExtensible());
 
                 if (obj->nativeEmpty()) {
-                    /*
-                     * We check that cx owns obj here and will continue to own
-                     * it after ensureClassReservedSlotsForEmptyObject returns
-                     * so we can continue to skip JS_UNLOCK_OBJ calls.
-                     */
-                    JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj));
-                    bool ok = obj->ensureClassReservedSlotsForEmptyObject(cx);
-                    JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj));
-                    if (!ok)
+                    if (!obj->ensureClassReservedSlotsForEmptyObject(cx))
                         goto error;
                 }
 
                 uint32 slot;
                 if (shape->previous() == obj->lastProperty() &&
                     entry->vshape() == rt->protoHazardShape &&
                     shape->hasDefaultSetter()) {
                     slot = shape->slot;
@@ -4384,17 +4359,17 @@ BEGIN_CASE(JSOP_SETMETHOD)
                     obj->extend(cx, shape);
 
                     /*
                      * No method change check here because here we are adding a
                      * new property, not updating an existing slot's value that
                      * might contain a method of a branded shape.
                      */
                     TRACE_2(SetPropHit, entry, shape);
-                    obj->lockedSetSlot(slot, rval);
+                    obj->nativeSetSlot(slot, rval);
 
                     /*
                      * Purge the property cache of the id we may have just
                      * shadowed in obj's scope and proto chains.
                      */
                     js_PurgeScopeChain(cx, obj, shape->id);
                     break;
                 }
@@ -4803,18 +4778,17 @@ BEGIN_CASE(JSOP_CALLNAME)
     JSAtom *atom;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom);
     if (!atom) {
         ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry);
         if (entry->vword.isFunObj()) {
             PUSH_OBJECT(entry->vword.toFunObj());
         } else if (entry->vword.isSlot()) {
             uintN slot = entry->vword.toSlot();
-            JS_ASSERT(obj2->containsSlot(slot));
-            PUSH_COPY(obj2->lockedGetSlot(slot));
+            PUSH_COPY(obj2->nativeGetSlot(slot));
         } else {
             JS_ASSERT(entry->vword.isShape());
             shape = entry->vword.toShape();
             NATIVE_GET(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, &rval);
             PUSH_COPY(rval);
         }
 
         /*
@@ -4849,26 +4823,24 @@ BEGIN_CASE(JSOP_CALLNAME)
             DO_NEXT_OP(len);
         }
         atomNotDefined = atom;
         goto atom_not_defined;
     }
 
     /* Take the slow path if prop was not found in a native object. */
     if (!obj->isNative() || !obj2->isNative()) {
-        obj2->dropProperty(cx, prop);
         if (!obj->getProperty(cx, id, &rval))
             goto error;
     } else {
         shape = (Shape *)prop;
         JSObject *normalized = obj;
         if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter())
             normalized = js_UnwrapWithObject(cx, normalized);
         NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval);
-        JS_UNLOCK_OBJ(cx, obj2);
     }
 
     PUSH_COPY(rval);
 
     /* obj must be on the scope chain, thus not a function. */
     if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
         SLOW_PUSH_THISV(cx, obj);
 }
@@ -5271,17 +5243,16 @@ BEGIN_CASE(JSOP_CALLUPVAR_DBG)
     }
 
     if (!prop) {
         atomNotDefined = atom;
         goto atom_not_defined;
     }
 
     /* Minimize footprint with generic code instead of NATIVE_GET. */
-    obj2->dropProperty(cx, prop);
     Value *vp = regs.sp;
     PUSH_NULL();
     if (!obj->getProperty(cx, id, vp))
         goto error;
 
     if (op == JSOP_CALLUPVAR_DBG)
         PUSH_UNDEFINED();
 }
@@ -5315,48 +5286,32 @@ BEGIN_CASE(JSOP_CALLGLOBAL)
 END_CASE(JSOP_GETGLOBAL)
 
 BEGIN_CASE(JSOP_FORGLOBAL)
 {
     Value rval;
     if (!IteratorNext(cx, &regs.sp[-1].toObject(), &rval))
         goto error;
     PUSH_COPY(rval);
-    uint32 slot = GET_SLOTNO(regs.pc);
-    slot = script->getGlobalSlot(slot);
+    uint32 slot = script->getGlobalSlot(GET_SLOTNO(regs.pc));
     JSObject *obj = regs.fp->scopeChain().getGlobal();
-    JS_ASSERT(obj->containsSlot(slot));
-    JS_LOCK_OBJ(cx, obj);
-    {
-        if (!obj->methodWriteBarrier(cx, slot, rval)) {
-            JS_UNLOCK_OBJ(cx, obj);
-            goto error;
-        }
-        obj->lockedSetSlot(slot, rval);
-        JS_UNLOCK_OBJ(cx, obj);
-    }
+    if (!obj->methodWriteBarrier(cx, slot, rval))
+        goto error;
+    obj->nativeSetSlot(slot, rval);
     regs.sp--;
 }
 END_CASE(JSOP_FORGLOBAL)
 
 BEGIN_CASE(JSOP_SETGLOBAL)
 {
-    uint32 slot = GET_SLOTNO(regs.pc);
-    slot = script->getGlobalSlot(slot);
+    uint32 slot = script->getGlobalSlot(GET_SLOTNO(regs.pc));
     JSObject *obj = regs.fp->scopeChain().getGlobal();
-    JS_ASSERT(obj->containsSlot(slot));
-    {
-        JS_LOCK_OBJ(cx, obj);
-        if (!obj->methodWriteBarrier(cx, slot, regs.sp[-1])) {
-            JS_UNLOCK_OBJ(cx, obj);
-            goto error;
-        }
-        obj->lockedSetSlot(slot, regs.sp[-1]);
-        JS_UNLOCK_OBJ(cx, obj);
-    }
+    if (!obj->methodWriteBarrier(cx, slot, regs.sp[-1]))
+        goto error;
+    obj->nativeSetSlot(slot, regs.sp[-1]);
 }
 END_SET_CASE(JSOP_SETGLOBAL)
 
 BEGIN_CASE(JSOP_DEFCONST)
 BEGIN_CASE(JSOP_DEFVAR)
 {
     uint32 index = GET_INDEX(regs.pc);
     JSAtom *atom = atoms[index];
@@ -5389,18 +5344,16 @@ BEGIN_CASE(JSOP_DEFVAR)
     if (!prop) {
         if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), PropertyStub, PropertyStub,
                                      attrs, 0, 0, &prop)) {
             goto error;
         }
         JS_ASSERT(prop);
         obj2 = obj;
     }
-
-    obj2->dropProperty(cx, prop);
 }
 END_CASE(JSOP_DEFVAR)
 
 BEGIN_CASE(JSOP_DEFFUN)
 {
     /*
      * A top-level function defined in Global or Eval code (see ECMA-262
      * Ed. 3), or else a SpiderMonkey extension: a named function statement in
@@ -5501,17 +5454,16 @@ BEGIN_CASE(JSOP_DEFFUN)
              * JSPROP_PERMANENT (not [[Configurable]] in ES5 terms) attribute
              * is not changing (note that JSPROP_ENUMERATE is set for all Call
              * object properties).
              */
             JS_ASSERT(oldAttrs & attrs & JSPROP_ENUMERATE);
             if (oldAttrs & JSPROP_PERMANENT)
                 doSet = true;
         }
-        pobj->dropProperty(cx, prop);
     }
 
     Value rval = ObjectValue(*obj);
     ok = doSet
          ? parent->setProperty(cx, id, &rval, script->strictModeCode)
          : parent->defineProperty(cx, id, rval, PropertyStub, PropertyStub, attrs);
     if (!ok)
         goto error;
@@ -5962,18 +5914,17 @@ BEGIN_CASE(JSOP_INITMETHOD)
      * So check first.
      *
      * On a hit, if the cached shape has a non-default setter, it must be
      * __proto__. If shape->previous() != obj->lastProperty(), there must be a
      * repeated property name. The fast path does not handle these two cases.
      */
     PropertyCacheEntry *entry;
     const Shape *shape;
-    if (CX_OWNS_OBJECT_TITLE(cx, obj) &&
-        JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, &shape, &entry) &&
+    if (JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, &shape, &entry) &&
         shape->hasDefaultSetter() &&
         shape->previous() == obj->lastProperty())
     {
         /* Fast path. Property cache hit. */
         uint32 slot = shape->slot;
 
         JS_ASSERT(slot == obj->slotSpan());
         JS_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
@@ -5991,17 +5942,17 @@ BEGIN_CASE(JSOP_INITMETHOD)
         obj->extend(cx, shape);
 
         /*
          * No method change check here because here we are adding a new
          * property, not updating an existing slot's value that might
          * contain a method of a branded shape.
          */
         TRACE_2(SetPropHit, entry, shape);
-        obj->lockedSetSlot(slot, rval);
+        obj->nativeSetSlot(slot, rval);
     } else {
         PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++);
 
         /* Get the immediate property name into id. */
         JSAtom *atom;
         LOAD_ATOM(0, atom);
         jsid id = ATOM_TO_JSID(atom);
 
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -249,36 +249,32 @@ Enumerate(JSContext *cx, JSObject *obj, 
     return true;
 }
 
 template <class EnumPolicy>
 static bool
 EnumerateNativeProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags, IdSet &ht,
                           typename EnumPolicy::ResultVector *props)
 {
-    JS_LOCK_OBJ(cx, pobj);
-
     size_t initialLength = props->length();
 
     /* Collect all unique properties from this object's scope. */
     for (Shape::Range r = pobj->lastProperty()->all(); !r.empty(); r.popFront()) {
         const Shape &shape = r.front();
 
         if (!JSID_IS_DEFAULT_XML_NAMESPACE(shape.id) &&
             !shape.isAlias() &&
             !Enumerate<EnumPolicy>(cx, obj, pobj, shape.id, shape.enumerable(),
                                    shape.isSharedPermanent(), flags, ht, props))
         {
             return false;
         }
     }
 
     Reverse(props->begin() + initialLength, props->end());
-
-    JS_UNLOCK_OBJ(cx, pobj);
     return true;
 }
 
 template <class EnumPolicy>
 static bool
 EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags,
                               IdSet &ht, typename EnumPolicy::ResultVector *props)
 {
@@ -917,22 +913,21 @@ SuppressDeletedPropertyHelper(JSContext 
                     if (obj->getProto()) {
                         AutoObjectRooter proto(cx, obj->getProto());
                         AutoObjectRooter obj2(cx);
                         JSProperty *prop;
                         if (!proto.object()->lookupProperty(cx, *idp, obj2.addr(), &prop))
                             return false;
                         if (prop) {
                             uintN attrs;
-                            if (obj2.object()->isNative()) {
+                            if (obj2.object()->isNative())
                                 attrs = ((Shape *) prop)->attributes();
-                                JS_UNLOCK_OBJ(cx, obj2.object());
-                            } else if (!obj2.object()->getAttributes(cx, *idp, &attrs)) {
+                            else if (!obj2.object()->getAttributes(cx, *idp, &attrs))
                                 return false;
-                            }
+
                             if (attrs & JSPROP_ENUMERATE)
                                 continue;
                         }
                     }
 
                     /*
                      * If lookupProperty or getAttributes above removed a property from
                      * ni, start over.
--- a/js/src/jslock.cpp
+++ b/js/src/jslock.cpp
@@ -545,18 +545,18 @@ ClaimTitle(JSTitle *title, JSContext *cx
 
     /* Reload in case ownercx went away while we blocked on the lock. */
     while (JSContext *ownercx = title->ownercx) {
         /*
          * Avoid selflock if ownercx is dead, or is not running a request, or
          * has the same thread as cx, or cx->thread runs the GC (in which case
          * all other requests must be suspended), or ownercx->thread runs a GC
          * and the GC waits for all requests to finish. Set title->ownercx to
-         * cx so that the matching JS_UNLOCK_OBJ macro call will take the fast
-         * path around the corresponding js_UnlockObj function call.
+         * cx to enable the fast path around the matching js_UnlockTitle
+         * function call.
          *
          * If title->u.link is non-null, title has already been inserted on
          * the rt->titleSharingTodo list, because another thread's context
          * already wanted to lock title while ownercx was running a request.
          * That context must still be in request and cannot be dead. Moreover,
          * the GC can not run at this moment as it must wait until all the
          * titles are shared and the threads that want to lock them finish
          * their requests. Thus we can claim the title if its thread matches
@@ -650,157 +650,16 @@ js_ShareWaitingTitles(JSContext *cx)
 
         FinishSharingTitle(cx, title);  /* set ownercx = NULL */
         shared = true;
     }
     if (shared)
         JS_NOTIFY_ALL_CONDVAR(cx->runtime->titleSharingDone);
 }
 
-/* Exported to js.c, which calls it via OBJ_GET_* and JSVAL_IS_* macros. */
-JS_FRIEND_API(jsval)
-js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
-{
-    jsval v;
-#ifndef NSPR_LOCK
-    JSThinLock *tl;
-    jsword me;
-#endif
-
-    OBJ_CHECK_SLOT(obj, slot);
-
-    /*
-     * Native object locking is inlined here to optimize the single-threaded
-     * and contention-free multi-threaded cases.
-     */
-    JS_ASSERT(obj->title.ownercx != cx);
-    JS_ASSERT(obj->containsSlot(slot));
-
-    /*
-     * Avoid locking if called from the GC.  Also avoid locking a non-extensible
-     * object.  If neither of those special cases applies, try to claim obj's
-     * flyweight lock from whatever context may have had it in an earlier
-     * request.
-     */
-    if (CX_THREAD_IS_RUNNING_GC(cx) ||
-        !obj->isExtensible() ||
-        (obj->title.ownercx && ClaimTitle(&obj->title, cx))) {
-        return Jsvalify(obj->getSlot(slot));
-    }
-
-#ifndef NSPR_LOCK
-    tl = &obj->title.lock;
-    me = CX_THINLOCK_ID(cx);
-    JS_ASSERT(CURRENT_THREAD_IS_ME(me));
-    if (NativeCompareAndSwap(&tl->owner, 0, me)) {
-        /*
-         * Got the lock with one compare-and-swap. Even so, someone else may
-         * have mutated obj so it now has its own title lock, which would
-         * require either a restart from the top of this routine, or a thin
-         * lock release followed by fat lock acquisition.
-         */
-        v = Jsvalify(obj->getSlot(slot));
-        if (!NativeCompareAndSwap(&tl->owner, me, 0)) {
-            /* Assert that title locks never revert to flyweight. */
-            JS_ASSERT(obj->title.ownercx != cx);
-            LOGIT(obj->title, '1');
-            obj->title.u.count = 1;
-            js_UnlockObj(cx, obj);
-        }
-        return v;
-    }
-    if (Thin_RemoveWait(ReadWord(tl->owner)) == me)
-        return Jsvalify(obj->getSlot(slot));
-#endif
-
-    js_LockObj(cx, obj);
-    v = Jsvalify(obj->getSlot(slot));
-
-    /*
-     * Test whether cx took ownership of obj's scope during js_LockObj.
-     *
-     * This does not mean that a given scope reverted to flyweight from "thin"
-     * or "fat" -- it does mean that obj's map pointer changed due to another
-     * thread setting a property, requiring obj to cease sharing a prototype
-     * object's scope (whose lock was not flyweight, else we wouldn't be here
-     * in the first place!).
-     */
-    if (obj->title.ownercx != cx)
-        js_UnlockTitle(cx, &obj->title);
-    return v;
-}
-
-void
-js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
-{
-#ifndef NSPR_LOCK
-    JSThinLock *tl;
-    jsword me;
-#endif
-
-    OBJ_CHECK_SLOT(obj, slot);
-
-    /* Any string stored in a thread-safe object must be immutable. */
-    if (JSVAL_IS_STRING(v) &&
-        !js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) {
-        /* FIXME bug 363059: See comments in js_FinishSharingScope. */
-        v = JSVAL_NULL;
-    }
-
-    /*
-     * Native object locking is inlined here to optimize the single-threaded
-     * and contention-free multi-threaded cases.
-     */
-    JS_ASSERT(obj->title.ownercx != cx);
-    JS_ASSERT(obj->containsSlot(slot));
-
-    /*
-     * Avoid locking if called from the GC.  Also avoid locking a non-extensible
-     * object.  If neither of those special cases applies, try to claim obj's
-     * flyweight lock from whatever context may have had it in an earlier
-     * request.
-     */
-    if (CX_THREAD_IS_RUNNING_GC(cx) ||
-        !obj->isExtensible() ||
-        (obj->title.ownercx && ClaimTitle(&obj->title, cx))) {
-        obj->lockedSetSlot(slot, Valueify(v));
-        return;
-    }
-
-#ifndef NSPR_LOCK
-    tl = &obj->title.lock;
-    me = CX_THINLOCK_ID(cx);
-    JS_ASSERT(CURRENT_THREAD_IS_ME(me));
-    if (NativeCompareAndSwap(&tl->owner, 0, me)) {
-        obj->lockedSetSlot(slot, Valueify(v));
-        if (!NativeCompareAndSwap(&tl->owner, me, 0)) {
-            /* Assert that scope locks never revert to flyweight. */
-            JS_ASSERT(obj->title.ownercx != cx);
-            LOGIT(obj->title, '1');
-            obj->title.u.count = 1;
-            js_UnlockObj(cx, obj);
-        }
-        return;
-    }
-    if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
-        obj->lockedSetSlot(slot, Valueify(v));
-        return;
-    }
-#endif
-
-    js_LockObj(cx, obj);
-    obj->lockedSetSlot(slot, Valueify(v));
-
-    /*
-     * Same drill as above, in js_GetSlotThreadSafe.
-     */
-    if (obj->title.ownercx != cx)
-        js_UnlockTitle(cx, &obj->title);
-}
-
 #ifndef NSPR_LOCK
 
 static JSFatLock *
 NewFatlock()
 {
     JSFatLock *fl = (JSFatLock *)js_malloc(sizeof(JSFatLock)); /* for now */
     if (!fl) return NULL;
     fl->susp = 0;
@@ -1227,44 +1086,16 @@ js_UnlockTitle(JSContext *cx, JSTitle *t
         return;
     }
     LOGIT(title, '-');
     if (--title->u.count == 0)
         ThinUnlock(&title->lock, me);
 }
 
 void
-js_LockObj(JSContext *cx, JSObject *obj)
-{
-    JS_ASSERT(obj->isNative());
-
-    /*
-     * We must test whether the GC is calling and return without mutating any
-     * state, especially lockedSealedScope. Note asymmetry with respect to
-     * js_UnlockObj, which is a thin-layer on top of js_UnlockTitle.
-     */
-    if (CX_THREAD_IS_RUNNING_GC(cx))
-        return;
-
-    if (!obj->isExtensible() && !cx->thread->lockedSealedTitle) {
-        cx->thread->lockedSealedTitle = &obj->title;
-        return;
-    }
-
-    js_LockTitle(cx, &obj->title);
-}
-
-void
-js_UnlockObj(JSContext *cx, JSObject *obj)
-{
-    JS_ASSERT(obj->isNative());
-    js_UnlockTitle(cx, &obj->title);
-}
-
-void
 js_InitTitle(JSContext *cx, JSTitle *title)
 {
 #ifdef JS_THREADSAFE
     title->ownercx = cx;
     js_InitLock(&title->lock);
 
     /*
      * Set u.link = NULL, not u.count = 0, in case the target architecture's
@@ -1293,29 +1124,23 @@ js_FinishTitle(JSContext *cx, JSTitle *t
 
 JSBool
 js_IsRuntimeLocked(JSRuntime *rt)
 {
     return js_CurrentThreadId() == rt->rtLockOwner;
 }
 
 JSBool
-js_IsObjLocked(JSContext *cx, JSObject *obj)
-{
-    return js_IsTitleLocked(cx, &obj->title);
-}
-
-JSBool
 js_IsTitleLocked(JSContext *cx, JSTitle *title)
 {
     /* Special case: the GC locking any object's title, see js_LockTitle. */
     if (CX_THREAD_IS_RUNNING_GC(cx))
         return JS_TRUE;
 
-    /* Special case: locked object is not extensible -- see js_LockObj. */
+    /* Special case: locked object is not extensible. */
     if (cx->thread->lockedSealedTitle == title)
         return JS_TRUE;
 
     /*
      * General case: the title is either exclusively owned by some context, or
      * it has a thin or fat lock to cope with shared (concurrent) ownership.
      *
      * js_LockTitle(cx, title) must set ownercx to cx when claiming the title
--- a/js/src/jslock.h
+++ b/js/src/jslock.h
@@ -96,19 +96,19 @@ struct JSTitle {
     union {                             /* union lockful and lock-free state: */
         jsrefcount  count;              /* lock entry count for reentrancy */
         JSTitle     *link;              /* next link in rt->titleSharingTodo */
     } u;
 };
 
 /*
  * Title structure is always allocated as a field of JSObject.
+ * Since objects don't have titles anymore, this is always NULL for now.
  */
-#define TITLE_TO_OBJECT(title)                                                 \
-    ((JSObject *)((uint8 *) (title) - offsetof(JSObject, title)))
+#define TITLE_TO_OBJECT(title)      (NULL)
 
 /*
  * Atomic increment and decrement for a reference counter, given jsrefcount *p.
  * NB: jsrefcount is int32, aka PRInt32, so that pratom.h functions work.
  */
 #define JS_ATOMIC_INCREMENT(p)      PR_AtomicIncrement((PRInt32 *)(p))
 #define JS_ATOMIC_DECREMENT(p)      PR_AtomicDecrement((PRInt32 *)(p))
 #define JS_ATOMIC_ADD(p,v)          PR_AtomicAdd((PRInt32 *)(p), (PRInt32)(v))
@@ -128,85 +128,46 @@ struct JSTitle {
 #define JS_NOTIFY_ALL_CONDVAR(cv)   PR_NotifyAllCondVar(cv)
 
 #define JS_LOCK(cx, tl)             js_Lock(cx, tl)
 #define JS_UNLOCK(cx, tl)           js_Unlock(cx, tl)
 
 #define JS_LOCK_RUNTIME(rt)         js_LockRuntime(rt)
 #define JS_UNLOCK_RUNTIME(rt)       js_UnlockRuntime(rt)
 
-/*
- * NB: The JS_LOCK_OBJ and JS_UNLOCK_OBJ macros work *only* on native objects
- * (objects for which obj->isNative() returns true).  All uses of these macros in
- * the engine are predicated on obj->isNative or equivalent checks.
- */
-#define CX_OWNS_OBJECT_TITLE(cx,obj) ((obj)->title.ownercx == (cx))
-
-#define JS_LOCK_OBJ(cx,obj)                                                   \
-    JS_BEGIN_MACRO                                                            \
-        JSObject *obj_ = (obj);                                               \
-        if (!CX_OWNS_OBJECT_TITLE(cx, obj_)) {                                \
-            js_LockObj(cx, obj_);                                             \
-            JS_SET_OBJ_INFO(obj_, __FILE__, __LINE__);                        \
-        }                                                                     \
-    JS_END_MACRO
-
-#define JS_UNLOCK_OBJ(cx,obj)                                                 \
-    JS_BEGIN_MACRO                                                            \
-        JSObject *obj_ = (obj);                                               \
-        if (!CX_OWNS_OBJECT_TITLE(cx, obj_))                                  \
-            js_UnlockObj(cx, obj_);                                           \
-    JS_END_MACRO
-
-#define JS_LOCK_TITLE(cx,title)                                               \
-    ((title)->ownercx == (cx) ? (void)0                                       \
-     : (js_LockTitle(cx, (title)),                                            \
-        JS_SET_TITLE_INFO(title,__FILE__,__LINE__)))
-
-#define JS_UNLOCK_TITLE(cx,title) ((title)->ownercx == (cx) ? (void)0         \
-                                   : js_UnlockTitle(cx, title))
-
 extern void js_Lock(JSContext *cx, JSThinLock *tl);
 extern void js_Unlock(JSContext *cx, JSThinLock *tl);
 extern void js_LockRuntime(JSRuntime *rt);
 extern void js_UnlockRuntime(JSRuntime *rt);
-extern void js_LockObj(JSContext *cx, JSObject *obj);
-extern void js_UnlockObj(JSContext *cx, JSObject *obj);
 extern void js_InitTitle(JSContext *cx, JSTitle *title);
 extern void js_FinishTitle(JSContext *cx, JSTitle *title);
 extern void js_LockTitle(JSContext *cx, JSTitle *title);
 extern void js_UnlockTitle(JSContext *cx, JSTitle *title);
 extern int js_SetupLocks(int,int);
 extern void js_CleanupLocks();
-extern JS_FRIEND_API(jsval)
-js_GetSlotThreadSafe(JSContext *, JSObject *, uint32);
-extern void js_SetSlotThreadSafe(JSContext *, JSObject *, uint32, jsval);
 extern void js_InitLock(JSThinLock *);
 extern void js_FinishLock(JSThinLock *);
 
 /*
  * This function must be called with the GC lock held.
  */
 extern void
 js_ShareWaitingTitles(JSContext *cx);
 
 #ifdef DEBUG
 
 #define JS_IS_RUNTIME_LOCKED(rt)        js_IsRuntimeLocked(rt)
-#define JS_IS_OBJ_LOCKED(cx,obj)        js_IsObjLocked(cx,obj)
 #define JS_IS_TITLE_LOCKED(cx,title)    js_IsTitleLocked(cx,title)
 
 extern JSBool js_IsRuntimeLocked(JSRuntime *rt);
-extern JSBool js_IsObjLocked(JSContext *cx, JSObject *obj);
 extern JSBool js_IsTitleLocked(JSContext *cx, JSTitle *title);
 
 #else
 
 #define JS_IS_RUNTIME_LOCKED(rt)        0
-#define JS_IS_OBJ_LOCKED(cx,obj)        1
 #define JS_IS_TITLE_LOCKED(cx,title)    1
 
 #endif /* DEBUG */
 
 #else  /* !JS_THREADSAFE */
 
 #define JS_ATOMIC_INCREMENT(p)      (++*(p))
 #define JS_ATOMIC_DECREMENT(p)      (--*(p))
@@ -224,22 +185,18 @@ extern JSBool js_IsTitleLocked(JSContext
 #define JS_NEW_CONDVAR(l)           NULL
 #define JS_DESTROY_CONDVAR(cv)      ((void)0)
 #define JS_WAIT_CONDVAR(cv,to)      ((void)0)
 #define JS_NOTIFY_CONDVAR(cv)       ((void)0)
 #define JS_NOTIFY_ALL_CONDVAR(cv)   ((void)0)
 
 #define JS_LOCK_RUNTIME(rt)         ((void)0)
 #define JS_UNLOCK_RUNTIME(rt)       ((void)0)
-#define JS_LOCK_OBJ(cx,obj)         ((void)0)
-#define JS_UNLOCK_OBJ(cx,obj)       ((void)0)
 
-#define CX_OWNS_OBJECT_TITLE(cx,obj)    1
 #define JS_IS_RUNTIME_LOCKED(rt)        1
-#define JS_IS_OBJ_LOCKED(cx,obj)        1
 #define JS_IS_TITLE_LOCKED(cx,title)    1
 
 #endif /* !JS_THREADSAFE */
 
 #define JS_LOCK_RUNTIME_VOID(rt,e)                                            \
     JS_BEGIN_MACRO                                                            \
         JS_LOCK_RUNTIME(rt);                                                  \
         e;                                                                    \
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -241,17 +241,16 @@ MarkSharpObjects(JSContext *cx, JSObject
             if (obj2->isNative()) {
                 const Shape *shape = (Shape *) prop;
                 hasGetter = shape->hasGetterValue();
                 hasSetter = shape->hasSetterValue();
                 if (hasGetter)
                     v.set(shape->getterValue());
                 if (hasSetter)
                     setter.set(shape->setterValue());
-                JS_UNLOCK_OBJ(cx, obj2);
             } else {
                 hasGetter = hasSetter = false;
             }
             if (hasSetter) {
                 /* Mark the getter, then set val to setter. */
                 if (hasGetter && v.value().isObject()) {
                     ok = !!MarkSharpObjects(cx, &v.value().toObject(), NULL);
                     if (!ok)
@@ -568,17 +567,16 @@ obj_toSource(JSContext *cx, uintN argc, 
 
         /*
          * Convert id to a value and then to a string.  Decide early whether we
          * prefer get/set or old getter/setter syntax.
          */
         idstr = js_ValueToString(cx, IdToValue(id));
         if (!idstr) {
             ok = JS_FALSE;
-            obj2->dropProperty(cx, prop);
             goto error;
         }
         vp->setString(idstr);                           /* local root */
 
         jsint valcnt = 0;
         if (prop) {
             bool doGet = true;
             if (obj2->isNative()) {
@@ -591,17 +589,16 @@ obj_toSource(JSContext *cx, uintN argc, 
                     valcnt++;
                 }
                 if (attrs & JSPROP_SETTER) {
                     doGet = false;
                     val[valcnt] = shape->setterValue();
                     gsop[valcnt] = ATOM_TO_STRING(cx->runtime->atomState.setAtom);
                     valcnt++;
                 }
-                JS_UNLOCK_OBJ(cx, obj2);
             }
             if (doGet) {
                 valcnt = 1;
                 gsop[0] = NULL;
                 ok = obj->getProperty(cx, id, &val[0]);
                 if (!ok)
                     goto error;
             }
@@ -1400,22 +1397,17 @@ js_HasOwnPropertyHelper(JSContext *cx, L
         bool has;
         if (!JSProxy::hasOwn(cx, obj, id, &has))
             return false;
         vp->setBoolean(has);
         return true;
     }
     if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop))
         return JS_FALSE;
-    if (prop) {
-        vp->setBoolean(true);
-        obj2->dropProperty(cx, prop);
-    } else {
-        vp->setBoolean(false);
-    }
+    vp->setBoolean(prop != NULL);
     return JS_TRUE;
 }
 
 JSBool
 js_HasOwnProperty(JSContext *cx, LookupPropOp lookup, JSObject *obj, jsid id,
                   JSObject **objp, JSProperty **propp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DETECTING);
@@ -1452,17 +1444,16 @@ js_HasOwnProperty(JSContext *cx, LookupP
              * the property, there is no way to tell whether it is directly
              * owned, or indirectly delegated.
              */
             Shape *shape = reinterpret_cast<Shape *>(*propp);
             if (shape->isSharedPermanent())
                 return true;
         }
 
-        (*objp)->dropProperty(cx, *propp);
         *propp = NULL;
     }
     return true;
 }
 
 /* Proposed ECMA 15.2.4.6. */
 static JSBool
 obj_isPrototypeOf(JSContext *cx, uintN argc, Value *vp)
@@ -1512,17 +1503,16 @@ js_PropertyIsEnumerable(JSContext *cx, J
      * to distinguish a shared permanent proto-property from a local one.
      */
     bool shared;
     uintN attrs;
     if (pobj->isNative()) {
         Shape *shape = (Shape *) prop;
         shared = shape->isSharedPermanent();
         attrs = shape->attributes();
-        JS_UNLOCK_OBJ(cx, pobj);
     } else {
         shared = false;
         if (!pobj->getAttributes(cx, id, &attrs))
             return false;
     }
     if (pobj != obj && !shared) {
         vp->setBoolean(false);
         return true;
@@ -1610,17 +1600,16 @@ obj_lookupGetter(JSContext *cx, uintN ar
     if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop))
         return JS_FALSE;
     vp->setUndefined();
     if (prop) {
         if (pobj->isNative()) {
             Shape *shape = (Shape *) prop;
             if (shape->hasGetterValue())
                 *vp = shape->getterValue();
-            JS_UNLOCK_OBJ(cx, pobj);
         }
     }
     return JS_TRUE;
 }
 
 static JSBool
 obj_lookupSetter(JSContext *cx, uintN argc, Value *vp)
 {
@@ -1633,17 +1622,16 @@ obj_lookupSetter(JSContext *cx, uintN ar
     if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop))
         return JS_FALSE;
     vp->setUndefined();
     if (prop) {
         if (pobj->isNative()) {
             Shape *shape = (Shape *) prop;
             if (shape->hasSetterValue())
                 *vp = shape->setterValue();
-            JS_UNLOCK_OBJ(cx, pobj);
         }
     }
     return JS_TRUE;
 }
 #endif /* OLD_GETTER_SETTER_METHODS */
 
 JSBool
 obj_getPrototypeOf(JSContext *cx, uintN argc, Value *vp)
@@ -1732,17 +1720,16 @@ js_GetOwnPropertyDescriptor(JSContext *c
         attrs = shape->attributes();
         if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
             doGet = false;
             if (attrs & JSPROP_GETTER)
                 roots[0] = shape->getterValue();
             if (attrs & JSPROP_SETTER)
                 roots[1] = shape->setterValue();
         }
-        JS_UNLOCK_OBJ(cx, pobj);
     } else {
         if (!pobj->getAttributes(cx, id, &attrs))
             return false;
     }
 
     if (doGet && !obj->getProperty(cx, id, &roots[2]))
         return false;
 
@@ -1984,24 +1971,16 @@ Reject(JSContext *cx, JSObject *obj, uin
         return JS_FALSE;
     }
 
     *rval = false;
     return JS_TRUE;
 }
 
 static JSBool
-Reject(JSContext *cx, JSObject *obj, JSProperty *prop, uintN errorNumber, bool throwError,
-       jsid id, bool *rval)
-{
-    obj->dropProperty(cx, prop);
-    return Reject(cx, errorNumber, throwError, id, rval);
-}
-
-static JSBool
 DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc,
                        bool throwError, bool *rval)
 {
     /* 8.12.9 step 1. */
     JSProperty *current;
     JSObject *obj2;
     JS_ASSERT(!obj->getOps()->lookupProperty);
     if (!js_HasOwnProperty(cx, NULL, obj, desc.id, &obj2, &current))
@@ -2095,18 +2074,17 @@ DefinePropertyOnObject(JSContext *cx, JS
                  * &c.).  Longer-term perhaps we should convert such properties
                  * to use data descriptors (at which point representing a
                  * descriptor with native getter/setter as an accessor
                  * descriptor would be fine) and take a small memory hit, but
                  * for now we'll simply forbid their redefinition.
                  */
                 if (!shape->configurable() &&
                     (!shape->hasDefaultGetter() || !shape->hasDefaultSetter())) {
-                    return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError,
-                                  desc.id, rval);
+                    return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
                 }
 
                 if (!js_NativeGet(cx, obj, obj2, shape, JSGET_NO_METHOD_BARRIER, &v)) {
                     /* current was dropped when the failure occurred. */
                     return JS_FALSE;
                 }
             }
 
@@ -2125,67 +2103,64 @@ DefinePropertyOnObject(JSContext *cx, JS
         }
 
         if (desc.hasConfigurable && desc.configurable() != shape->configurable())
             break;
         if (desc.hasEnumerable && desc.enumerable() != shape->enumerable())
             break;
 
         /* The conditions imposed by step 5 or step 6 apply. */
-        obj2->dropProperty(cx, current);
         *rval = true;
         return JS_TRUE;
     } while (0);
 
     /* 8.12.9 step 7. */
     if (!shape->configurable()) {
         /*
          * Since [[Configurable]] defaults to false, we don't need to check
          * whether it was specified.  We can't do likewise for [[Enumerable]]
          * because its putative value is used in a comparison -- a comparison
          * whose result must always be false per spec if the [[Enumerable]]
          * field is not present.  Perfectly pellucid logic, eh?
          */
         JS_ASSERT_IF(!desc.hasConfigurable, !desc.configurable());
         if (desc.configurable() ||
             (desc.hasEnumerable && desc.enumerable() != shape->enumerable())) {
-            return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
+            return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
         }
     }
 
     bool callDelProperty = false;
 
     if (desc.isGenericDescriptor()) {
         /* 8.12.9 step 8, no validation required */
     } else if (desc.isDataDescriptor() != shape->isDataDescriptor()) {
         /* 8.12.9 step 9. */
         if (!shape->configurable())
-            return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
+            return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
     } else if (desc.isDataDescriptor()) {
         /* 8.12.9 step 10. */
         JS_ASSERT(shape->isDataDescriptor());
         if (!shape->configurable() && !shape->writable()) {
             if ((desc.hasWritable && desc.writable()) ||
                 (desc.hasValue && !SameValue(desc.value, v, cx))) {
-                return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id,
-                              rval);
+                return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
             }
         }
 
         callDelProperty = !shape->hasDefaultGetter() || !shape->hasDefaultSetter();
     } else {
         /* 8.12.9 step 11. */
         JS_ASSERT(desc.isAccessorDescriptor() && shape->isAccessorDescriptor());
         if (!shape->configurable()) {
             if ((desc.hasSet &&
                  !SameValue(desc.setterValue(), shape->setterOrUndefined(), cx)) ||
                 (desc.hasGet &&
                  !SameValue(desc.getterValue(), shape->getterOrUndefined(), cx))) {
-                return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id,
-                              rval);
+                return Reject(cx, JSMSG_CANT_REDEFINE_PROP, throwError, desc.id, rval);
             }
         }
     }
 
     /* 8.12.9 step 12. */
     uintN attrs;
     PropertyOp getter, setter;
     if (desc.isGenericDescriptor()) {
@@ -2219,20 +2194,18 @@ DefinePropertyOnObject(JSContext *cx, JS
     } else {
         JS_ASSERT(desc.isAccessorDescriptor());
 
         /*
          * Getters and setters are just like watchpoints from an access
          * control point of view.
          */
         Value dummy;
-        if (!CheckAccess(cx, obj2, desc.id, JSACC_WATCH, &dummy, &attrs)) {
-             obj2->dropProperty(cx, current);
+        if (!CheckAccess(cx, obj2, desc.id, JSACC_WATCH, &dummy, &attrs))
              return JS_FALSE;
-        }
 
         JS_ASSERT_IF(shape->isMethod(), !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
 
         /* 8.12.9 step 12. */
         uintN changed = 0;
         if (desc.hasConfigurable)
             changed |= JSPROP_PERMANENT;
         if (desc.hasEnumerable)
@@ -2255,17 +2228,16 @@ DefinePropertyOnObject(JSContext *cx, JS
         } else {
             setter = (shape->hasDefaultSetter() && !shape->hasSetterValue())
                      ? PropertyStub
                      : shape->setter();
         }
     }
 
     *rval = true;
-    obj2->dropProperty(cx, current);
 
     /*
      * Since "data" properties implemented using native C functions may rely on
      * side effects during setting, we must make them aware that they have been
      * "assigned"; deleting the property before redefining it does the trick.
      * See bug 539766, where we ran into problems when we redefined
      * arguments.length without making the property aware that its value had
      * been changed (which would have happened if we had deleted it before
@@ -2872,20 +2844,16 @@ js_String_tn(JSContext* cx, JSObject* pr
 JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0,
                      nanojit::ACCSET_STORE_ANY)
 
 JSObject* FASTCALL
 js_CreateThisFromTrace(JSContext *cx, Class *clasp, JSObject *ctor)
 {
     JS_ASSERT(JS_ON_TRACE(cx));
     JS_ASSERT(ctor->isFunction());
-#ifdef JS_THREADSAFE
-    if (ctor->title.ownercx != cx)
-        return NULL;
-#endif
 
     if (!ctor->ensureClassReservedSlots(cx))
         return NULL;
 
     jsid classPrototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
     const Shape *shape = ctor->nativeLookup(classPrototypeId);
     Value pval = shape ? ctor->getSlot(shape->slot) : MagicValue(JS_GENERIC_MAGIC);
 
@@ -3535,40 +3503,30 @@ DefineStandardSlot(JSContext *cx, JSObje
         /*
          * Initializing an actual standard class on a global object. If the
          * property is not yet present, force it into a new one bound to a
          * reserved slot. Otherwise, go through the normal property path.
          */
         JS_ASSERT(obj->getClass()->flags & JSCLASS_IS_GLOBAL);
         JS_ASSERT(obj->isNative());
 
-        JS_LOCK_OBJ(cx, obj);
-        if (!obj->ensureClassReservedSlots(cx)) {
-            JS_UNLOCK_OBJ(cx, obj);
+        if (!obj->ensureClassReservedSlots(cx))
             return false;
-        }
 
         const Shape *shape = obj->nativeLookup(id);
         if (!shape) {
             uint32 slot = 2 * JSProto_LIMIT + key;
-            if (!js_SetReservedSlot(cx, obj, slot, v)) {
-                JS_UNLOCK_OBJ(cx, obj);
+            if (!js_SetReservedSlot(cx, obj, slot, v))
                 return false;
-            }
-
-            shape = obj->addProperty(cx, id, PropertyStub, PropertyStub, slot, attrs, 0, 0);
-
-            JS_UNLOCK_OBJ(cx, obj);
-            if (!shape)
+            if (!obj->addProperty(cx, id, PropertyStub, PropertyStub, slot, attrs, 0, 0))
                 return false;
 
             named = true;
             return true;
         }
-        JS_UNLOCK_OBJ(cx, obj);
     }
 
     named = obj->defineProperty(cx, id, v, PropertyStub, PropertyStub, attrs);
     return named;
 }
 
 JSObject *
 js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
@@ -3868,35 +3826,29 @@ namespace js {
 
 bool
 SetProto(JSContext *cx, JSObject *obj, JSObject *proto, bool checkForCycles)
 {
     JS_ASSERT_IF(!checkForCycles, obj != proto);
     JS_ASSERT(obj->isExtensible());
 
     if (obj->isNative()) {
-        JS_LOCK_OBJ(cx, obj);
-        bool ok = obj->ensureClassReservedSlots(cx);
-        JS_UNLOCK_OBJ(cx, obj);
-        if (!ok)
+        if (!obj->ensureClassReservedSlots(cx))
             return false;
     }
 
     /*
      * Regenerate property cache shape ids for all of the scopes along the
      * old prototype chain to invalidate their property cache entries, in
      * case any entries were filled by looking up through obj.
      */
     JSObject *oldproto = obj;
     while (oldproto && oldproto->isNative()) {
-        JS_LOCK_OBJ(cx, oldproto);
         oldproto->protoShapeChange(cx);
-        JSObject *tmp = oldproto->getProto();
-        JS_UNLOCK_OBJ(cx, oldproto);
-        oldproto = tmp;
+        oldproto = oldproto->getProto();
     }
 
     if (!proto || !checkForCycles) {
         obj->setProto(proto);
     } else if (!SetProtoCheckingForCycles(cx, obj, proto)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CYCLIC_VALUE, js_proto_str);
         return false;
     }
@@ -4027,21 +3979,20 @@ js_FindClassObject(JSContext *cx, JSObje
     if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_CLASSNAME,
                                    &pobj, &prop) < 0) {
         return JS_FALSE;
     }
     Value v = UndefinedValue();
     if (prop && pobj->isNative()) {
         shape = (Shape *) prop;
         if (pobj->containsSlot(shape->slot)) {
-            v = pobj->lockedGetSlot(shape->slot);
+            v = pobj->nativeGetSlot(shape->slot);
             if (v.isPrimitive())
                 v.setUndefined();
         }
-        JS_UNLOCK_OBJ(cx, pobj);
     }
     *vp = v;
     return JS_TRUE;
 }
 
 JSObject *
 js_ConstructObject(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent,
                    uintN argc, Value *argv)
@@ -4250,38 +4201,32 @@ PurgeProtoChain(JSContext *cx, JSObject 
 {
     const Shape *shape;
 
     while (obj) {
         if (!obj->isNative()) {
             obj = obj->getProto();
             continue;
         }
-        JS_LOCK_OBJ(cx, obj);
         shape = obj->nativeLookup(id);
         if (shape) {
             PCMETER(JS_PROPERTY_CACHE(cx).pcpurges++);
             obj->shadowingShapeChange(cx, *shape);
-            JS_UNLOCK_OBJ(cx, obj);
 
             if (!obj->getParent()) {
                 /*
                  * All scope chains end in a global object, so this will change
                  * the global shape. jstracer.cpp assumes that the global shape
                  * never changes on trace, so we must deep-bail here.
                  */
                 LeaveTrace(cx);
             }
             return JS_TRUE;
         }
-#ifdef JS_THREADSAFE
-        JSObject *pobj = obj;
-#endif
         obj = obj->getProto();
-        JS_UNLOCK_OBJ(cx, pobj);
     }
     return JS_FALSE;
 }
 
 void
 js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id)
 {
     JS_ASSERT(obj->isDelegate());
@@ -4301,50 +4246,41 @@ js_PurgeScopeChainHelper(JSContext *cx, 
     }
 }
 
 const Shape *
 js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id,
                      PropertyOp getter, PropertyOp setter, uint32 slot,
                      uintN attrs, uintN flags, intN shortid)
 {
-    const Shape *shape;
-
     JS_ASSERT(!(flags & Shape::METHOD));
 
     /*
      * Purge the property cache of now-shadowed id in obj's scope chain. Do
      * this optimistically (assuming no failure below) before locking obj, so
      * we can lock the shadowed scope.
      */
     js_PurgeScopeChain(cx, obj, id);
 
-    JS_LOCK_OBJ(cx, obj);
-    if (!obj->ensureClassReservedSlots(cx)) {
-        shape = NULL;
-    } else {
-        /* Convert string indices to integers if appropriate. */
-        id = js_CheckForStringIndex(id);
-        shape = obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid);
-    }
-    JS_UNLOCK_OBJ(cx, obj);
-    return shape;
+    if (!obj->ensureClassReservedSlots(cx))
+        return NULL;
+
+    /* Convert string indices to integers if appropriate. */
+    id = js_CheckForStringIndex(id);
+    return obj->putProperty(cx, id, getter, setter, slot, attrs, flags, shortid);
 }
 
 const Shape *
 js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj,
                              const Shape *shape, uintN attrs, uintN mask,
                              PropertyOp getter, PropertyOp setter)
 {
-    JS_LOCK_OBJ(cx, obj);
-    shape = obj->ensureClassReservedSlots(cx)
-            ? obj->changeProperty(cx, shape, attrs, mask, getter, setter)
-            : NULL;
-    JS_UNLOCK_OBJ(cx, obj);
-    return shape;
+    if (!obj->ensureClassReservedSlots(cx))
+        return NULL;
+    return obj->changeProperty(cx, shape, attrs, mask, getter, setter);
 }
 
 JSBool
 js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value,
                   PropertyOp getter, PropertyOp setter, uintN attrs)
 {
     return js_DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs,
                                    0, 0, NULL);
@@ -4361,17 +4297,17 @@ CallAddPropertyHook(JSContext *cx, Class
 {
     if (clasp->addProperty != PropertyStub) {
         Value nominal = *vp;
 
         if (!CallJSPropertyOp(cx, clasp->addProperty, obj, SHAPE_USERID(shape), vp))
             return false;
         if (*vp != nominal) {
             if (obj->containsSlot(shape->slot))
-                obj->lockedSetSlot(shape->slot, *vp);
+                obj->nativeSetSlot(shape->slot, *vp);
         }
     }
     return true;
 }
 
 JSBool
 js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value,
                         PropertyOp getter, PropertyOp setter, uintN attrs,
@@ -4415,21 +4351,19 @@ js_DefineNativeProperty(JSContext *cx, J
                                         JSPROP_GETTER | JSPROP_SETTER,
                                         (attrs & JSPROP_GETTER)
                                         ? getter
                                         : shape->getter(),
                                         (attrs & JSPROP_SETTER)
                                         ? setter
                                         : shape->setter());
 
-            /* NB: obj == pobj, so we can share unlock code at the bottom. */
             if (!shape)
-                goto error;
+                return false;
         } else if (prop) {
-            pobj->dropProperty(cx, prop);
             prop = NULL;
             shape = NULL;
         }
     }
 
     /*
      * Purge the property cache of any properties named by id that are about
      * to be shadowed in obj's scope chain unless it is known a priori that it
@@ -4441,31 +4375,28 @@ js_DefineNativeProperty(JSContext *cx, J
     /*
      * Check whether a readonly property or setter is being defined on a known
      * prototype object. See the comment in jscntxt.h before protoHazardShape's
      * member declaration.
      */
     if (obj->isDelegate() && (attrs & (JSPROP_READONLY | JSPROP_SETTER)))
         cx->runtime->protoHazardShape = js_GenerateShape(cx, false);
 
-    /* Lock if object locking is required by this implementation. */
-    JS_LOCK_OBJ(cx, obj);
-
     /* Use the object's class getter and setter by default. */
     clasp = obj->getClass();
     if (!(defineHow & JSDNP_SET_METHOD)) {
         if (!getter && !(attrs & JSPROP_GETTER))
             getter = clasp->getProperty;
         if (!setter && !(attrs & JSPROP_SETTER))
             setter = clasp->setProperty;
     }
 
     /* Get obj's own scope if it has one, or create a new one for obj. */
     if (!obj->ensureClassReservedSlots(cx))
-        goto error;
+        return false;
 
     added = false;
     if (!shape) {
         /* Add a new property, or replace an existing one of the same id. */
         if (defineHow & JSDNP_SET_METHOD) {
             JS_ASSERT(clasp == &js_ObjectClass);
             JS_ASSERT(IsFunctionObject(value));
             JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
@@ -4478,56 +4409,53 @@ js_DefineNativeProperty(JSContext *cx, J
             }
         }
 
         added = !obj->nativeContains(id);
         uint32 oldShape = obj->shape();
         shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
                                  attrs, flags, shortid);
         if (!shape)
-            goto error;
+            return false;
 
         /*
          * If shape is a method, the above call to putProperty suffices to
          * update the shape if necessary. But if scope->branded(), the shape
          * may not have changed and we may be overwriting a function-valued
          * property. See bug 560998.
          */
         if (obj->shape() == oldShape && obj->branded() && shape->slot != SHAPE_INVALID_SLOT)
             obj->methodWriteBarrier(cx, shape->slot, value);
     }
 
     /* Store value before calling addProperty, in case the latter GC's. */
     if (obj->containsSlot(shape->slot))
-        obj->lockedSetSlot(shape->slot, value);
+        obj->nativeSetSlot(shape->slot, value);
 
     /* XXXbe called with lock held */
     valueCopy = value;
     if (!CallAddPropertyHook(cx, clasp, obj, shape, &valueCopy)) {
         obj->removeProperty(cx, id);
-        goto error;
+        return false;
     }
 
     if (defineHow & JSDNP_CACHE_RESULT) {
 #ifdef JS_TRACER
         JS_ASSERT_NOT_ON_TRACE(cx);
         PropertyCacheEntry *entry =
 #endif
             JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, shape, added);
         TRACE_2(SetPropHit, entry, shape);
     }
     if (propp)
         *propp = (JSProperty *) shape;
-    else
-        JS_UNLOCK_OBJ(cx, obj);
-    return JS_TRUE;
-
-error: // TRACE_2 jumps here on error, as well.
-    JS_UNLOCK_OBJ(cx, obj);
-    return JS_FALSE;
+    return true;
+
+error: // TRACE_2 jumps here on error.
+    return false;
 }
 
 JS_FRIEND_API(JSBool)
 js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
                   JSProperty **propp)
 {
     return js_LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags,
                                       objp, propp) >= 0;
@@ -4570,93 +4498,76 @@ CallResolveOp(JSContext *cx, JSObject *s
      *
      * Once we have successfully added an entry for (obj, key) to
      * cx->resolvingTable, control must go through cleanup: before
      * returning.  But note that JS_DHASH_ADD may find an existing
      * entry, in which case we bail to suppress runaway recursion.
      */
     JSResolvingKey key = {obj, id};
     JSResolvingEntry *entry;
-    if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry)) {
-        JS_UNLOCK_OBJ(cx, obj);
+    if (!js_StartResolving(cx, &key, JSRESFLAG_LOOKUP, &entry))
         return false;
-    }
     if (!entry) {
         /* Already resolving id in obj -- suppress recursion. */
-        JS_UNLOCK_OBJ(cx, obj);
         *recursedp = true;
         return true;
     }
     uint32 generation = cx->resolvingTable->generation;
     *recursedp = false;
 
     *propp = NULL;
 
     JSBool ok;
     const Shape *shape = NULL;
     if (clasp->flags & JSCLASS_NEW_RESOLVE) {
         JSNewResolveOp newresolve = (JSNewResolveOp)resolve;
         if (flags == JSRESOLVE_INFER)
             flags = js_InferFlags(cx, 0);
         JSObject *obj2 = (clasp->flags & JSCLASS_NEW_RESOLVE_GETS_START) ? start : NULL;
-        JS_UNLOCK_OBJ(cx, obj);
 
         {
             /* Protect id and all atoms from a GC nested in resolve. */
             AutoKeepAtoms keep(cx->runtime);
             ok = newresolve(cx, obj, id, flags, &obj2);
         }
         if (!ok)
             goto cleanup;
 
-        JS_LOCK_OBJ(cx, obj);
         if (obj2) {
-            /* Resolved: juggle locks and lookup id again. */
-            if (obj2 != obj) {
-                JS_UNLOCK_OBJ(cx, obj);
-                if (obj2->isNative())
-                    JS_LOCK_OBJ(cx, obj2);
-            }
+            /* Resolved: lookup id again for backward compatibility. */
             if (!obj2->isNative()) {
                 /* Whoops, newresolve handed back a foreign obj2. */
                 JS_ASSERT(obj2 != obj);
                 ok = obj2->lookupProperty(cx, id, objp, propp);
                 if (!ok || *propp)
                     goto cleanup;
-                JS_LOCK_OBJ(cx, obj2);
             } else {
                 /*
                  * Require that obj2 not be empty now, as we do for old-style
                  * resolve.  If it doesn't, then id was not truly resolved, and
                  * we'll find it in the proto chain, or miss it if obj2's proto
                  * is not on obj's proto chain.  That last case is a "too bad!"
                  * case.
                  */
                 if (!obj2->nativeEmpty())
                     shape = obj2->nativeLookup(id);
             }
             if (shape) {
                 JS_ASSERT(!obj2->nativeEmpty());
                 obj = obj2;
-            } else if (obj2 != obj) {
-                if (obj2->isNative())
-                    JS_UNLOCK_OBJ(cx, obj2);
-                JS_LOCK_OBJ(cx, obj);
             }
         }
     } else {
         /*
          * Old resolve always requires id re-lookup if obj is not empty after
          * resolve returns.
          */
-        JS_UNLOCK_OBJ(cx, obj);
         ok = resolve(cx, obj, id);
         if (!ok)
             goto cleanup;
-        JS_LOCK_OBJ(cx, obj);
         JS_ASSERT(obj->isNative());
         if (!obj->nativeEmpty())
             shape = obj->nativeLookup(id);
     }
 
 cleanup:
     if (ok && shape) {
         *objp = obj;
@@ -4672,17 +4583,16 @@ js_LookupPropertyWithFlagsInline(JSConte
 {
     /* Convert string indices to integers if appropriate. */
     id = js_CheckForStringIndex(id);
 
     /* Search scopes starting with obj and following the prototype link. */
     JSObject *start = obj;
     int protoIndex;
     for (protoIndex = 0; ; protoIndex++) {
-        JS_LOCK_OBJ(cx, obj);
         const Shape *shape = obj->nativeLookup(id);
         if (shape) {
             SCOPE_DEPTH_ACCUM(&cx->runtime->protoLookupDepthStats, protoIndex);
             *objp = obj;
             *propp = (JSProperty *) shape;
             return protoIndex;
         }
 
@@ -4699,17 +4609,16 @@ js_LookupPropertyWithFlagsInline(JSConte
                 for (JSObject *proto = start; proto && proto != *objp; proto = proto->getProto())
                     protoIndex++;
                 SCOPE_DEPTH_ACCUM(&cx->runtime->protoLookupDepthStats, protoIndex);
                 return protoIndex;
             }
         }
 
         JSObject *proto = obj->getProto();
-        JS_UNLOCK_OBJ(cx, obj);
         if (!proto)
             break;
         if (!proto->isNative()) {
             if (!proto->lookupProperty(cx, id, objp, propp))
                 return -1;
             return protoIndex + 1;
         }
 
@@ -4872,36 +4781,33 @@ js_FindIdentifierBase(JSContext *cx, JSO
             }
             JS_ASSERT_IF(obj->getParent(), pobj->getClass() == obj->getClass());
 #ifdef DEBUG
             PropertyCacheEntry *entry =
 #endif
                 JS_PROPERTY_CACHE(cx).fill(cx, scopeChain, scopeIndex, protoIndex, pobj,
                                            (Shape *) prop);
             JS_ASSERT(entry);
-            JS_UNLOCK_OBJ(cx, pobj);
             return obj;
         }
 
         JSObject *parent = obj->getParent();
         if (!parent)
             return obj;
         obj = parent;
     }
 
     /* Loop until we find a property or reach the global object. */
     do {
         JSObject *pobj;
         JSProperty *prop;
         if (!obj->lookupProperty(cx, id, &pobj, &prop))
             return NULL;
-        if (prop) {
-            pobj->dropProperty(cx, prop);
+        if (prop)
             break;
-        }
 
         /*
          * We conservatively assume that a resolve hook could mutate the scope
          * chain during JSObject::lookupProperty. So we must check if parent is
          * not null here even if it wasn't before the lookup.
          */
         JSObject *parent = obj->getParent();
         if (!parent)
@@ -4916,51 +4822,46 @@ js_NativeGetInline(JSContext *cx, JSObje
                    Value *vp)
 {
     LeaveTraceIfGlobalObject(cx, pobj);
 
     uint32 slot;
     int32 sample;
 
     JS_ASSERT(pobj->isNative());
-    JS_ASSERT(JS_IS_OBJ_LOCKED(cx, pobj));
 
     slot = shape->slot;
     if (slot != SHAPE_INVALID_SLOT) {
-        *vp = pobj->lockedGetSlot(slot);
+        *vp = pobj->nativeGetSlot(slot);
         JS_ASSERT(!vp->isMagic());
     } else {
         vp->setUndefined();
     }
     if (shape->hasDefaultGetter())
         return true;
 
     if (JS_UNLIKELY(shape->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER)) {
         JS_ASSERT(&shape->methodObject() == &vp->toObject());
         return true;
     }
 
     sample = cx->runtime->propertyRemovals;
-    JS_UNLOCK_OBJ(cx, pobj);
     {
         AutoShapeRooter tvr(cx, shape);
         AutoObjectRooter tvr2(cx, pobj);
         if (!shape->get(cx, obj, pobj, vp))
             return false;
     }
-    JS_LOCK_OBJ(cx, pobj);
 
     if (pobj->containsSlot(slot) &&
         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
          pobj->nativeContains(*shape))) {
-        if (!pobj->methodWriteBarrier(cx, *shape, *vp)) {
-            JS_UNLOCK_OBJ(cx, pobj);
+        if (!pobj->methodWriteBarrier(cx, *shape, *vp))
             return false;
-        }
-        pobj->lockedSetSlot(slot, *vp);
+        pobj->nativeSetSlot(slot, *vp);
     }
 
     return true;
 }
 
 JSBool
 js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, uintN getHow,
              Value *vp)
@@ -4972,59 +4873,52 @@ JSBool
 js_NativeSet(JSContext *cx, JSObject *obj, const Shape *shape, bool added, Value *vp)
 {
     LeaveTraceIfGlobalObject(cx, obj);
 
     uint32 slot;
     int32 sample;
 
     JS_ASSERT(obj->isNative());
-    JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));
 
     slot = shape->slot;
     if (slot != SHAPE_INVALID_SLOT) {
-        OBJ_CHECK_SLOT(obj, slot);
+        JS_ASSERT(obj->containsSlot(slot));
 
         /* If shape has a stub setter, keep obj locked and just store *vp. */
         if (shape->hasDefaultSetter()) {
-            if (!added && !obj->methodWriteBarrier(cx, *shape, *vp)) {
-                JS_UNLOCK_OBJ(cx, obj);
+            if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
                 return false;
-            }
-            obj->lockedSetSlot(slot, *vp);
+            obj->nativeSetSlot(slot, *vp);
             return true;
         }
     } else {
         /*
          * Allow API consumers to create shared properties with stub setters.
          * Such properties effectively function as data descriptors which are
          * not writable, so attempting to set such a property should do nothing
          * or throw if we're in strict mode.
          */
         if (!shape->hasGetterValue() && shape->hasDefaultSetter())
             return js_ReportGetterOnlyAssignment(cx);
     }
 
     sample = cx->runtime->propertyRemovals;
-    JS_UNLOCK_OBJ(cx, obj);
     {
         AutoShapeRooter tvr(cx, shape);
         if (!shape->set(cx, obj, vp))
             return false;
     }
 
-    JS_LOCK_OBJ(cx, obj);
     if (obj->containsSlot(slot) &&
         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
          obj->nativeContains(*shape))) {
-        if (!added && !obj->methodWriteBarrier(cx, *shape, *vp)) {
-            JS_UNLOCK_OBJ(cx, obj);
+        if (!added && !obj->methodWriteBarrier(cx, *shape, *vp))
             return false;
-        }
-        obj->lockedSetSlot(slot, *vp);
+        obj->setSlot(slot, *vp);
     }
 
     return true;
 }
 
 static JS_ALWAYS_INLINE bool
 js_GetPropertyHelperWithShapeInline(JSContext *cx, JSObject *obj, jsid id,
                                     uintN getHow, Value *vp,
@@ -5122,17 +5016,16 @@ js_GetPropertyHelperWithShapeInline(JSCo
         JS_ASSERT_NOT_ON_TRACE(cx);
         JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2, shape);
     }
 
     /* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
     if (!js_NativeGetInline(cx, obj, obj2, shape, getHow, vp))
         return JS_FALSE;
 
-    JS_UNLOCK_OBJ(cx, obj2);
     return JS_TRUE;
 }
 
 extern bool
 js_GetPropertyHelperWithShape(JSContext *cx, JSObject *obj, jsid id,
                               uint32 getHow, Value *vp,
                               const Shape **shapeOut, JSObject **holderOut)
 {
@@ -5168,17 +5061,16 @@ js::GetPropertyDefault(JSContext *cx, JS
     if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0)
         return false;
 
     if (!prop) {
         *vp = def;
         return true;
     }
 
-    obj2->dropProperty(cx, prop);
     return js_GetProperty(cx, obj2, id, vp);
 }
 
 JSBool
 js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, Value *vp)
 {
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
 
@@ -5287,43 +5179,36 @@ js_SetPropertyHelper(JSContext *cx, JSOb
             return JS_FALSE;
         }
     }
     shape = (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.
-     * If JS_THREADSAFE and shape is non-null, then pobj is locked, and shape
-     * is held: we must JSObject::dropProperty or else JS_UNLOCK_OBJ before we
-     * return (the two are equivalent for native objects; we use JS_UNLOCK_OBJ
-     * because it is cheaper).
      */
     attrs = JSPROP_ENUMERATE;
     flags = 0;
     shortid = 0;
     clasp = obj->getClass();
     getter = clasp->getProperty;
     setter = clasp->setProperty;
 
     if (shape) {
         /* ES5 8.12.4 [[Put]] step 2. */
         if (shape->isAccessorDescriptor()) {
             if (shape->hasDefaultSetter()) {
-                JS_UNLOCK_OBJ(cx, pobj);
                 if (defineHow & JSDNP_CACHE_RESULT)
                     TRACE_2(SetPropHit, JS_NO_PROP_CACHE_FILL, shape);
                 return js_ReportGetterOnlyAssignment(cx);
             }
         } else {
             JS_ASSERT(shape->isDataDescriptor());
 
             if (!shape->writable()) {
-                JS_UNLOCK_OBJ(cx, pobj);
-
                 PCMETER((defineHow & JSDNP_CACHE_RESULT) && JS_PROPERTY_CACHE(cx).rofills++);
                 if (defineHow & JSDNP_CACHE_RESULT) {
                     JS_ASSERT_NOT_ON_TRACE(cx);
                     TRACE_2(SetPropHit, JS_NO_PROP_CACHE_FILL, shape);
                 }
 
                 /* Error in strict mode code, warn with strict option, otherwise do nothing. */
                 if (strict)
@@ -5339,23 +5224,18 @@ js_SetPropertyHelper(JSContext *cx, JSOb
             }
         }
 
         attrs = shape->attributes();
         if (pobj != obj) {
             /*
              * We found id in a prototype object: prepare to share or shadow.
              *
-             * NB: Thanks to the immutable, garbage-collected property tree
-             * maintained by jsscope.c in cx->runtime, we needn't worry about
-             * shape going away behind our back after we've unlocked pobj.
+             * Don't clone a prototype property that doesn't have a slot.
              */
-            JS_UNLOCK_OBJ(cx, pobj);
-
-            /* Don't clone a prototype property that doesn't have a slot. */
             if (!shape->hasSlot()) {
                 if (defineHow & JSDNP_CACHE_RESULT) {
 #ifdef JS_TRACER
                     JS_ASSERT_NOT_ON_TRACE(cx);
                     PropertyCacheEntry *entry =
 #endif
                         JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, protoIndex, pobj, shape);
                     TRACE_2(SetPropHit, entry, shape);
@@ -5428,21 +5308,18 @@ js_SetPropertyHelper(JSContext *cx, JSOb
 
         /*
          * Purge the property cache of now-shadowed id in obj's scope chain.
          * Do this early, before locking obj to avoid nesting locks.
          */
         js_PurgeScopeChain(cx, obj, id);
 
         /* Find or make a property descriptor with the right heritage. */
-        JS_LOCK_OBJ(cx, obj);
-        if (!obj->ensureClassReservedSlots(cx)) {
-            JS_UNLOCK_OBJ(cx, obj);
+        if (!obj->ensureClassReservedSlots(cx))
             return JS_FALSE;
-        }
 
         /*
          * Check for Object class here to avoid defining a method on a class
          * with magic resolve, addProperty, getProperty, etc. hooks.
          */
         if ((defineHow & JSDNP_SET_METHOD) && obj->canHaveMethodBarrier()) {
             JS_ASSERT(IsFunctionObject(*vp));
             JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
@@ -5452,52 +5329,45 @@ js_SetPropertyHelper(JSContext *cx, JSOb
             if (fun == funobj) {
                 flags |= Shape::METHOD;
                 getter = CastAsPropertyOp(funobj);
             }
         }
 
         shape = obj->putProperty(cx, id, getter, setter, SHAPE_INVALID_SLOT,
                                  attrs, flags, shortid);
-        if (!shape) {
-            JS_UNLOCK_OBJ(cx, obj);
+        if (!shape)
             return JS_FALSE;
-        }
 
         /*
          * Initialize the new property value (passed to setter) to undefined.
          * Note that we store before calling addProperty, to match the order
          * in js_DefineNativeProperty.
          */
         if (obj->containsSlot(shape->slot))
-            obj->lockedSetSlot(shape->slot, UndefinedValue());
+            obj->nativeSetSlot(shape->slot, UndefinedValue());
 
         /* XXXbe called with obj locked */
         if (!CallAddPropertyHook(cx, clasp, obj, shape, vp)) {
             obj->removeProperty(cx, id);
-            JS_UNLOCK_OBJ(cx, obj);
             return JS_FALSE;
         }
         added = true;
     }
 
     if (defineHow & JSDNP_CACHE_RESULT) {
 #ifdef JS_TRACER
         JS_ASSERT_NOT_ON_TRACE(cx);
         PropertyCacheEntry *entry =
 #endif
             JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, shape, added);
         TRACE_2(SetPropHit, entry, shape);
     }
 
-    if (!js_NativeSet(cx, obj, shape, added, vp))
-        return NULL;
-
-    JS_UNLOCK_OBJ(cx, obj);
-    return JS_TRUE;
+    return js_NativeSet(cx, obj, shape, added, vp);
 }
 
 JSBool
 js_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSBool strict)
 {
     return js_SetPropertyHelper(cx, obj, id, 0, vp, strict);
 }
 
@@ -5511,28 +5381,25 @@ js_GetAttributes(JSContext *cx, JSObject
         *attrsp = 0;
         return true;
     }
     if (!obj->isNative())
         return obj->getAttributes(cx, id, attrsp);
 
     const Shape *shape = (Shape *)prop;
     *attrsp = shape->attributes();
-    JS_UNLOCK_OBJ(cx, obj);
     return true;
 }
 
 JSBool
 js_SetNativeAttributes(JSContext *cx, JSObject *obj, Shape *shape, uintN attrs)
 {
     JS_ASSERT(obj->isNative());
-    bool ok = !!js_ChangeNativePropertyAttrs(cx, obj, shape, attrs, 0,
-                                             shape->getter(), shape->setter());
-    JS_UNLOCK_OBJ(cx, obj);
-    return ok;
+    return !!js_ChangeNativePropertyAttrs(cx, obj, shape, attrs, 0,
+                                          shape->getter(), shape->setter());
 }
 
 JSBool
 js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp)
 {
     JSProperty *prop;
     if (!js_LookupProperty(cx, obj, id, &obj, &prop))
         return false;
@@ -5544,17 +5411,16 @@ js_SetAttributes(JSContext *cx, JSObject
 }
 
 JSBool
 js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool strict)
 {
     JSObject *proto;
     JSProperty *prop;
     const Shape *shape;
-    JSBool ok;
 
     rval->setBoolean(true);
 
     /* Convert string indices to integers if appropriate. */
     id = js_CheckForStringIndex(id);
 
     if (!js_LookupProperty(cx, obj, id, &proto, &prop))
         return false;
@@ -5563,50 +5429,44 @@ js_DeleteProperty(JSContext *cx, JSObjec
          * If the property was found in a native prototype, check whether it's
          * shared and permanent.  Such a property stands for direct properties
          * in all delegating objects, matching ECMA semantics without bloating
          * each delegating object.
          */
         if (prop && proto->isNative()) {
             shape = (Shape *)prop;
             if (shape->isSharedPermanent()) {
-                JS_UNLOCK_OBJ(cx, proto);
                 if (strict)
                     return obj->reportNotConfigurable(cx, id);
                 rval->setBoolean(false);
                 return true;
             }
-            JS_UNLOCK_OBJ(cx, proto);
         }
 
         /*
          * If no property, or the property comes unshared or impermanent 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()) {
-        JS_UNLOCK_OBJ(cx, obj);
         if (strict)
             return obj->reportNotConfigurable(cx, id);
         rval->setBoolean(false);
         return true;
     }
 
-    /* XXXbe called with obj locked */
-    if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, SHAPE_USERID(shape), rval)) {
-        JS_UNLOCK_OBJ(cx, obj);
+    if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, SHAPE_USERID(shape), rval))
         return false;
-    }
 
     if (obj->containsSlot(shape->slot)) {
-        const Value &v = obj->lockedGetSlot(shape->slot);
+        const Value &v = obj->nativeGetSlot(shape->slot);
         GC_POKE(cx, v);
 
         /*
          * Delete is rare enough that we can take the hit of checking for an
          * active cloned method function object that must be homed to a callee
          * slot on the active stack frame before this delete completes, in case
          * someone saved the clone and checks it against foo.caller for a foo
          * called from the active method.
@@ -5630,20 +5490,17 @@ js_DeleteProperty(JSContext *cx, JSObjec
                             fp->calleeValue().setObject(*funobj);
                         }
                     }
                 }
             }
         }
     }
 
-    ok = obj->removeProperty(cx, id);
-    JS_UNLOCK_OBJ(cx, obj);
-
-    return ok && js_SuppressDeletedProperty(cx, obj, id);
+    return obj->removeProperty(cx, id) && js_SuppressDeletedProperty(cx, obj, id);
 }
 
 namespace js {
 
 /*
  * When we have an object of a builtin class, we don't quite know what its
  * valueOf/toString methods are, since these methods may have been overwritten
  * or shadowed. However, we can still do better than js_TryMethod by
@@ -5652,45 +5509,36 @@ namespace js {
  * TODO: a per-thread shape-based cache would be faster and simpler.
  */
 static JS_ALWAYS_INLINE bool
 ClassMethodIsNative(JSContext *cx, JSObject *obj, Class *classp, jsid methodid,
                     Native native)
 {
     JS_ASSERT(obj->getClass() == classp);
 
-    JS_LOCK_OBJ(cx, obj);
-    JSObject *lockedobj = obj;
     const Shape *shape = obj->nativeLookup(methodid);
     JSObject *pobj = obj;
 
     if (!shape) {
         pobj = obj->getProto();
 
-        if (pobj && pobj->getClass() == classp) {
-            JS_UNLOCK_OBJ(cx, obj);
-            JS_LOCK_OBJ(cx, pobj);
-            lockedobj = pobj;
+        if (pobj && pobj->getClass() == classp)
             shape = pobj->nativeLookup(methodid);
-        }
     }
 
     if (shape && shape->hasDefaultGetter() && pobj->containsSlot(shape->slot)) {
-        const Value &fval = pobj->lockedGetSlot(shape->slot);
+        const Value &fval = pobj->nativeGetSlot(shape->slot);
 
         JSObject *funobj;
         if (IsFunctionObject(fval, &funobj)) {
             JSFunction *fun = funobj->getFunctionPrivate();
-            if (fun->maybeNative() == native) {
-                JS_UNLOCK_OBJ(cx, lockedobj);
+            if (fun->maybeNative() == native)
                 return true;
-            }
         }
     }
-    JS_UNLOCK_OBJ(cx, lockedobj);
     return false;
 }
 
 JSBool
 DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp)
 {
     JS_ASSERT(hint != JSTYPE_OBJECT && hint != JSTYPE_FUNCTION);
 
@@ -5830,21 +5678,20 @@ CheckAccess(JSContext *cx, JSObject *obj
             }
             break;
         }
 
         shape = (Shape *)prop;
         *attrsp = shape->attributes();
         if (!writing) {
             if (pobj->containsSlot(shape->slot))
-                *vp = pobj->lockedGetSlot(shape->slot);
+                *vp = pobj->nativeGetSlot(shape->slot);
             else
                 vp->setUndefined();
         }
-        JS_UNLOCK_OBJ(cx, pobj);
     }
 
     /*
      * If obj's class has a stub (null) checkAccess hook, use the per-runtime
      * checkObjectAccess callback, if configured.
      *
      * We don't want to require all classes to supply a checkAccess hook; we
      * need that hook only for certain classes used when precompiling scripts
@@ -5884,24 +5731,16 @@ js_TypeOf(JSContext *cx, JSObject *obj)
         return (obj->getClass() != &js_RegExpClass)
                ? JSTYPE_FUNCTION
                : JSTYPE_OBJECT;
     }
 
     return JSTYPE_OBJECT;
 }
 
-#ifdef JS_THREADSAFE
-void
-js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop)
-{
-    JS_UNLOCK_OBJ(cx, obj);
-}
-#endif
-
 bool
 js_IsDelegate(JSContext *cx, JSObject *obj, const Value &v)
 {
     if (v.isPrimitive())
         return false;
     JSObject *obj2 = v.toObject().wrappedObject(cx);
     while ((obj2 = obj2->getProto()) != NULL) {
         if (obj2 == obj)
@@ -6337,68 +6176,60 @@ js_TraceObject(JSTracer *trc, JSObject *
 
 void
 js_ClearNative(JSContext *cx, JSObject *obj)
 {
     /*
      * Clear obj of all obj's properties. FIXME: we do not clear reserved slots
      * lying below JSSLOT_FREE(clasp). JS_ClearScope does that.
      */
-    JS_LOCK_OBJ(cx, obj);
     if (!obj->nativeEmpty()) {
         /* Now that we're done using real properties, clear obj. */
         obj->clear(cx);
 
         /* Clear slot values since obj->clear reset our shape to empty. */
         uint32 freeslot = JSSLOT_FREE(obj->getClass());
         uint32 n = obj->numSlots();
         for (uint32 i = freeslot; i < n; ++i)
             obj->setSlot(i, UndefinedValue());
     }
-    JS_UNLOCK_OBJ(cx, obj);
 }
 
 bool
 js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, Value *vp)
 {
     if (!obj->isNative()) {
         vp->setUndefined();
         return true;
     }
 
-    JS_LOCK_OBJ(cx, obj);
     if (slot < obj->numSlots())
         *vp = obj->getSlot(slot);
     else
         vp->setUndefined();
-    JS_UNLOCK_OBJ(cx, obj);
     return true;
 }
 
 bool
 js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 slot, const Value &v)
 {
     if (!obj->isNative())
         return true;
 
     Class *clasp = obj->getClass();
 
-    JS_LOCK_OBJ(cx, obj);
     if (slot >= obj->numSlots()) {
         uint32 nslots = JSSLOT_FREE(clasp);
         JS_ASSERT(slot < nslots);
-        if (!obj->allocSlots(cx, nslots)) {
-            JS_UNLOCK_OBJ(cx, obj);
+        if (!obj->allocSlots(cx, nslots))
             return false;
-        }
     }
 
     obj->setSlot(slot, v);
     GC_POKE(cx, JS_NULL);
-    JS_UNLOCK_OBJ(cx, obj);
     return true;
 }
 
 JSObject *
 JSObject::wrappedObject(JSContext *cx) const
 {
     if (JSObjectOp op = getClass()->ext.wrappedObject) {
         if (JSObject *obj = op(cx, const_cast<JSObject *>(this)))
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -191,20 +191,19 @@ struct JSObjectMap {
   private:
     /* No copy or assignment semantics. */
     JSObjectMap(JSObjectMap &);
     void operator=(JSObjectMap &);
 };
 
 /*
  * Unlike js_DefineNativeProperty, propp must be non-null. On success, and if
- * id was found, return true with *objp non-null and locked, and with a held
- * property stored in *propp. If successful but id was not found, return true
- * with both *objp and *propp null. Therefore all callers who receive a
- * non-null *propp must later call (*objp)->dropProperty(cx, *propp).
+ * 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)
 js_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
                   JSProperty **propp);
 
 extern JSBool
 js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value,
                   js::PropertyOp getter, js::PropertyOp setter, uintN attrs);
@@ -351,20 +350,16 @@ struct JSObject : js::gc::Cell {
     enum {
         NSLOTS_BITS     = 29,
         NSLOTS_LIMIT    = JS_BIT(NSLOTS_BITS)
     };
 
     uint32      flags;                      /* flags */
     uint32      objShape;                   /* copy of lastProp->shape, or override if different */
 
-#ifdef JS_THREADSAFE
-    JSTitle     title;
-#endif
-
     /* If prototype, lazily filled array of empty shapes for each object size. */
     js::EmptyShape **emptyShapes;
 
     JSObject    *proto;                     /* object's prototype */
     JSObject    *parent;                    /* object's parent */
     void        *privateData;               /* private data */
     jsuword     capacity;                   /* capacity of slots */
     js::Value   *slots;                     /* dynamically allocated slots,
@@ -607,36 +602,43 @@ struct JSObject : js::gc::Cell {
 
     bool containsSlot(uint32 slot) const { return slot < slotSpan(); }
 
     js::Value& getSlotRef(uintN slot) {
         JS_ASSERT(slot < capacity);
         return slots[slot];
     }
 
+    js::Value &nativeGetSlotRef(uintN slot) {
+        JS_ASSERT(isNative());
+        JS_ASSERT(containsSlot(slot));
+        return getSlotRef(slot);
+    }
+
     const js::Value &getSlot(uintN slot) const {
         JS_ASSERT(slot < capacity);
         return slots[slot];
     }
 
+    const js::Value &nativeGetSlot(uintN slot) const {
+        JS_ASSERT(isNative());
+        JS_ASSERT(containsSlot(slot));
+        return getSlot(slot);
+    }
+
     void setSlot(uintN slot, const js::Value &value) {
         JS_ASSERT(slot < capacity);
         slots[slot] = value;
     }
 
-    inline const js::Value &lockedGetSlot(uintN slot) const;
-    inline void lockedSetSlot(uintN slot, const js::Value &value);
-
-    /*
-     * These ones are for multi-threaded ("MT") objects.  Use getSlot(),
-     * getSlotRef(), setSlot() to directly manipulate slots in obj when only
-     * one thread can access obj.
-     */
-    inline js::Value getSlotMT(JSContext *cx, uintN slot);
-    inline void setSlotMT(JSContext *cx, uintN slot, const js::Value &value);
+    void nativeSetSlot(uintN slot, const js::Value &value) {
+        JS_ASSERT(isNative());
+        JS_ASSERT(containsSlot(slot));
+        return setSlot(slot, value);
+    }
 
     inline js::Value getReservedSlot(uintN index) const;
 
     /* Defined in jsscopeinlines.h to avoid including implementation dependencies here. */
     inline void updateShape(JSContext *cx);
     inline void updateFlags(const js::Shape *shape, bool isDefinitelyAtom = false);
 
     /* Extend this object to have shape as its last-added property. */
@@ -1102,18 +1104,16 @@ struct JSObject : js::gc::Cell {
     /* These four are time-optimized to avoid stub calls. */
     JSObject *thisObject(JSContext *cx) {
         JSObjectOp op = getOps()->thisObject;
         return op ? op(cx, this) : this;
     }
 
     static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
 
-    inline void dropProperty(JSContext *cx, JSProperty *prop);
-
     inline JSCompartment *getCompartment() const;
 
     inline JSObject *getThrowTypeError() const;
 
     bool swap(JSContext *cx, JSObject *obj);
 
     const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
 
@@ -1172,18 +1172,16 @@ JSObject::getFixedSlotOffset(size_t slot
 struct JSObject_Slots2 : JSObject { js::Value fslots[2]; };
 struct JSObject_Slots4 : JSObject { js::Value fslots[4]; };
 struct JSObject_Slots8 : JSObject { js::Value fslots[8]; };
 struct JSObject_Slots12 : JSObject { js::Value fslots[12]; };
 struct JSObject_Slots16 : JSObject { js::Value fslots[16]; };
 
 #define JSSLOT_FREE(clasp)  JSCLASS_RESERVED_SLOTS(clasp)
 
-#define OBJ_CHECK_SLOT(obj,slot) JS_ASSERT((obj)->containsSlot(slot))
-
 #ifdef JS_THREADSAFE
 
 /*
  * The GC runs only when all threads except the one on which the GC is active
  * are suspended at GC-safe points, so calling obj->getSlot() from the GC's
  * thread is safe when rt->gcRunning is set. See jsgc.cpp for details.
  */
 #define THREAD_IS_RUNNING_GC(rt, thread)                                      \
@@ -1473,19 +1471,17 @@ const uintN JSDNP_SET_METHOD   = 4; /* j
                                        flag on to JSObject::{add,put}Property */
 const uintN JSDNP_UNQUALIFIED  = 8; /* Unqualified property set.  Only used in
                                        the defineHow argument of
                                        js_SetPropertyHelper. */
 
 /*
  * On error, return false.  On success, if propp is non-null, return true with
  * obj locked and with a held property in *propp; if propp is null, return true
- * but release obj's lock first.  Therefore all callers who pass non-null propp
- * result parameters must later call obj->dropProperty(cx, *propp) both to drop
- * the held property, and to release the lock on obj.
+ * but release obj's lock first.
  */
 extern JSBool
 js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value &value,
                         js::PropertyOp getter, js::PropertyOp setter, uintN attrs,
                         uintN flags, intN shortid, JSProperty **propp,
                         uintN defineHow = 0);
 
 /*
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -58,24 +58,16 @@
 #include "jscntxt.h"
 #include "jsnum.h"
 #include "jsscopeinlines.h"
 #include "jsstr.h"
 
 #include "jsgcinlines.h"
 #include "jsprobes.h"
 
-inline void
-JSObject::dropProperty(JSContext *cx, JSProperty *prop)
-{
-    JS_ASSERT(prop);
-    if (isNative())
-        JS_UNLOCK_OBJ(cx, this);
-}
-
 inline bool
 JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props)
 {
     JS_ASSERT(isExtensible());
 
     if (js::FixOp fix = getOps()->fix) {
         bool success;
         if (!fix(cx, this, &success, props))
@@ -189,83 +181,47 @@ ChangesMethodValue(const js::Value &prev
     return prev.isObject() && (prevObj = &prev.toObject())->isFunction() &&
            (!v.isObject() || &v.toObject() != prevObj);
 }
 
 inline bool
 JSObject::methodWriteBarrier(JSContext *cx, const js::Shape &shape, const js::Value &v)
 {
     if (flags & (BRANDED | METHOD_BARRIER)) {
-        const js::Value &prev = lockedGetSlot(shape.slot);
+        const js::Value &prev = nativeGetSlot(shape.slot);
 
         if (ChangesMethodValue(prev, v)) {
             JS_FUNCTION_METER(cx, mwritebarrier);
             return methodShapeChange(cx, shape);
         }
     }
     return true;
 }
 
 inline bool
 JSObject::methodWriteBarrier(JSContext *cx, uint32 slot, const js::Value &v)
 {
     if (flags & (BRANDED | METHOD_BARRIER)) {
-        const js::Value &prev = lockedGetSlot(slot);
+        const js::Value &prev = nativeGetSlot(slot);
 
         if (ChangesMethodValue(prev, v)) {
             JS_FUNCTION_METER(cx, mwslotbarrier);
             return methodShapeChange(cx, slot);
         }
     }
     return true;
 }
 
 inline bool
 JSObject::ensureClassReservedSlots(JSContext *cx)
 {
     return !nativeEmpty() || ensureClassReservedSlotsForEmptyObject(cx);
 }
 
 inline js::Value
-JSObject::getSlotMT(JSContext *cx, uintN slot)
-{
-#ifdef JS_THREADSAFE
-    /*
-     * If thread-safe, define a getSlotMT() that bypasses, for a native object,
-     * the lock-free "fast path" test of (obj->title.ownercx == cx), to avoid
-     * needlessly switching from lock-free to lock-full scope when doing GC on
-     * a different context from the last one to own the scope. The caller in
-     * this case is probably a JSClass.mark function, e.g., fun_mark, or maybe
-     * a finalizer.
-     */
-    OBJ_CHECK_SLOT(this, slot);
-    return (title.ownercx == cx)
-           ? this->lockedGetSlot(slot)
-           : js::Valueify(js_GetSlotThreadSafe(cx, this, slot));
-#else
-    return this->lockedGetSlot(slot);
-#endif
-}
-
-inline void
-JSObject::setSlotMT(JSContext *cx, uintN slot, const js::Value &value)
-{
-#ifdef JS_THREADSAFE
-    /* Thread-safe way to set a slot. */
-    OBJ_CHECK_SLOT(this, slot);
-    if (title.ownercx == cx)
-        this->lockedSetSlot(slot, value);
-    else
-        js_SetSlotThreadSafe(cx, this, slot, js::Jsvalify(value));
-#else
-    this->lockedSetSlot(slot, value);
-#endif
-}
-
-inline js::Value
 JSObject::getReservedSlot(uintN index) const
 {
     return (index < numSlots()) ? getSlot(index) : js::UndefinedValue();
 }
 
 inline bool
 JSObject::canHaveMethodBarrier() const
 {
@@ -654,37 +610,30 @@ JSObject::init(JSContext *cx, js::Class 
 
     /*
      * Fill the fixed slots with undefined or array holes.  This object must
      * already have its capacity filled in, as by js_NewGCObject.
      */
     JS_ASSERT(capacity == numFixedSlots());
     ClearValueRange(slots, capacity, useHoles);
 
-#ifdef JS_THREADSAFE
-    js_InitTitle(cx, &title);
-#endif
-
     emptyShapes = NULL;
 }
 
 inline void
 JSObject::finish(JSContext *cx)
 {
 #ifdef DEBUG
     if (isNative())
         JS_LOCK_RUNTIME_VOID(cx->runtime, cx->runtime->liveObjectProps -= propertyCount());
 #endif
     if (hasSlotsArray())
         freeSlotsArray(cx);
     if (emptyShapes)
         cx->free(emptyShapes);
-#ifdef JS_THREADSAFE
-    js_FinishTitle(cx, &title);
-#endif
 }
 
 inline bool
 JSObject::initSharingEmptyShape(JSContext *cx,
                                 js::Class *aclasp,
                                 JSObject *proto,
                                 JSObject *parent,
                                 void *privateValue,
@@ -725,18 +674,16 @@ inline bool
 JSObject::hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags)
 {
     JSObject *pobj;
     JSProperty *prop;
     JSAutoResolveFlags rf(cx, flags);
     if (!lookupProperty(cx, id, &pobj, &prop))
         return false;
     *foundp = !!prop;
-    if (prop)
-        pobj->dropProperty(cx, prop);
     return true;
 }
 
 inline bool
 JSObject::isCallable()
 {
     return isFunction() || getClass()->call;
 }
@@ -802,24 +749,20 @@ InitScopeForObject(JSContext* cx, JSObje
 {
     JS_ASSERT(clasp->isNative());
     JS_ASSERT(proto == obj->getProto());
 
     /* Share proto's emptyShape only if obj is similar to proto. */
     js::EmptyShape *empty = NULL;
 
     if (proto) {
-        JS_LOCK_OBJ(cx, proto);
         if (proto->canProvideEmptyShape(clasp)) {
             empty = proto->getEmptyShape(cx, clasp, kind);
-            JS_UNLOCK_OBJ(cx, proto);
             if (!empty)
                 goto bad;
-        } else {
-            JS_UNLOCK_OBJ(cx, proto);
         }
     }
 
     if (!empty) {
         empty = js::EmptyShape::create(cx, clasp);
         if (!empty)
             goto bad;
         uint32 freeslot = JSSLOT_FREE(clasp);
@@ -859,20 +802,18 @@ NewNativeClassInstance(JSContext *cx, Cl
     if (obj) {
         /*
          * Default parent to the parent of the prototype, which was set from
          * the parent of the prototype's constructor.
          */
         bool useHoles = (clasp == &js_ArrayClass);
         obj->init(cx, clasp, proto, parent, NULL, useHoles);
 
-        JS_LOCK_OBJ(cx, proto);
         JS_ASSERT(proto->canProvideEmptyShape(clasp));
         js::EmptyShape *empty = proto->getEmptyShape(cx, clasp, kind);
-        JS_UNLOCK_OBJ(cx, proto);
 
         if (empty)
             obj->setMap(empty);
         else
             obj = NULL;
     }
 
     return obj;
@@ -1101,25 +1042,11 @@ NewObjectGCKind(JSContext *cx, js::Class
 {
     if (clasp == &js_ArrayClass || clasp == &js_SlowArrayClass)
         return gc::FINALIZE_OBJECT8;
     if (clasp == &js_FunctionClass)
         return gc::FINALIZE_OBJECT2;
     return gc::FINALIZE_OBJECT4;
 }
 
-class AutoPropertyDropper {
-    JSContext *cx;
-    JSObject *holder;
-    JSProperty *prop;
-
-  public:
-    AutoPropertyDropper(JSContext *cx, JSObject *obj, JSProperty *prop)
-      : cx(cx), holder(obj), prop(prop)
-    { JS_ASSERT(prop); }
-
-    ~AutoPropertyDropper()
-    { holder->dropProperty(cx, prop); }
-};
-
 } /* namespace js */
 
 #endif /* jsobjinlines_h___ */
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -1049,18 +1049,16 @@ Compiler::defineGlobals(JSContext *cx, G
                                      PropertyStub, JSPROP_ENUMERATE | JSPROP_PERMANENT,
                                      0, 0, &prop)) {
             return false;
         }
 
         JS_ASSERT(prop);
         const Shape *shape = (const Shape *)prop;
         def.knownSlot = shape->slot;
-
-        globalObj->dropProperty(cx, prop);
     }
 
     js::Vector<JSScript *, 16, ContextAllocPolicy> worklist(cx);
     if (!worklist.append(script))
         return false;
 
     /*
      * Recursively walk through all scripts we just compiled. For each script,
@@ -3476,29 +3474,26 @@ DefineGlobal(JSParseNode *pn, JSCodeGene
     JSObject *globalObj = globalScope->globalObj;
 
     if (!cg->compileAndGo() || !globalObj || cg->compilingForEval())
         return true;
 
     JSAtomListElement *ale = globalScope->names.lookup(atom);
     if (!ale) {
         JSContext *cx = cg->parser->context;
-        AutoObjectLocker locker(cx, globalObj);
 
         JSObject *holder;
         JSProperty *prop;
         if (!globalObj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
             return false;
 
         JSFunctionBox *funbox = (pn->pn_type == TOK_FUNCTION) ? pn->pn_funbox : NULL;
 
         GlobalScope::GlobalDef def;
         if (prop) {
-            AutoPropertyDropper dropper(cx, globalObj, prop);
-
             /*
              * A few cases where we don't bother aggressively caching:
              *   1) Function value changes.
              *   2) Configurable properties.
              *   3) Properties without slots, or with getters/setters.
              */
             const Shape *shape = (const Shape *)prop;
             if (funbox ||
--- a/js/src/jspropertycache.cpp
+++ b/js/src/jspropertycache.cpp
@@ -149,25 +149,23 @@ PropertyCache::fill(JSContext *cx, JSObj
         if (cs->format & JOF_CALLOP) {
             if (shape->isMethod()) {
                 /*
                  * A compiler-created function object, AKA a method, already
                  * memoized in the property tree.
                  */
                 JS_ASSERT(pobj->hasMethodBarrier());
                 JSObject &funobj = shape->methodObject();
-                JS_ASSERT(&funobj == &pobj->lockedGetSlot(shape->slot).toObject());
+                JS_ASSERT(&funobj == &pobj->nativeGetSlot(shape->slot).toObject());
                 vword.setFunObj(funobj);
                 break;
             }
 
-            if (!pobj->generic() &&
-                shape->hasDefaultGetter() &&
-                pobj->containsSlot(shape->slot)) {
-                const Value &v = pobj->lockedGetSlot(shape->slot);
+            if (!pobj->generic() && shape->hasDefaultGetter() && pobj->containsSlot(shape->slot)) {
+                const Value &v = pobj->nativeGetSlot(shape->slot);
                 JSObject *funobj;
 
                 if (IsFunctionObject(v, &funobj)) {
                     /*
                      * Great, we have a function-valued prototype property
                      * where the getter is JS_PropertyStub. The type id in
                      * pobj does not evolve with changes to property values,
                      * however.
--- a/js/src/jspropertycacheinlines.h
+++ b/js/src/jspropertycacheinlines.h
@@ -46,17 +46,17 @@
 #include "jspropertycache.h"
 #include "jsscope.h"
 
 using namespace js;
 
 /* static */ inline bool
 PropertyCache::matchShape(JSContext *cx, JSObject *obj, uint32 shape)
 {
-    return CX_OWNS_OBJECT_TITLE(cx, obj) && obj->shape() == shape;
+    return obj->shape() == shape;
 }
 
 /*
  * This method is designed to inline the fast path in js_Interpret, so it makes
  * "just-so" restrictions on parameters, e.g. pobj and obj should not be the
  * same variable, since for JOF_PROP-mode opcodes, obj must not be changed
  * because of a cache miss.
  *
@@ -107,17 +107,17 @@ PropertyCache::testForSet(JSContext *cx,
 {
     uint32 shape = obj->shape();
     PropertyCacheEntry *entry = &table[hash(pc, shape)];
     *entryp = entry;
     PCMETER(pctestentry = entry);
     PCMETER(tests++);
     PCMETER(settests++);
     JS_ASSERT(entry->kshape < SHAPE_OVERFLOW_BIT);
-    if (entry->kpc == pc && entry->kshape == shape && CX_OWNS_OBJECT_TITLE(cx, obj))
+    if (entry->kpc == pc && entry->kshape == shape)
         return true;
 
 #ifdef DEBUG
     JSObject *orig = obj;
 #endif
     JSAtom *atom = fullTest(cx, pc, &obj, obj2p, entry);
     if (atom) {
         PCMETER(misses++);
--- a/js/src/jsprvtd.h
+++ b/js/src/jsprvtd.h
@@ -288,18 +288,17 @@ typedef struct JSDebugHooks {
  * Look for id in obj and its prototype chain, returning false on error or
  * exception, true on success.  On success, return null in *propp if id was
  * not found.  If id was found, return the first object searching from obj
  * along its prototype chain in which id names a direct property in *objp, and
  * return a non-null, opaque property pointer in *propp.
  *
  * If JSLookupPropOp succeeds and returns with *propp non-null, that pointer
  * may be passed as the prop parameter to a JSAttributesOp, as a short-cut
- * that bypasses id re-lookup.  In any case, a non-null *propp result after a
- * successful lookup must be dropped via JSObject::dropProperty.
+ * that bypasses id re-lookup.
  *
  * NB: successful return with non-null *propp means the implementation may
  * have locked *objp and added a reference count associated with *propp, so
  * callers should not risk deadlock by nesting or interleaving other lookups
  * or any obj-bearing ops before dropping *propp.
  */
 typedef JSBool
 (* JSLookupPropOp)(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -112,23 +112,19 @@ Class js::regexp_statics_class = {
 
 /*
  * Lock obj and replace its regexp internals with |newRegExp|.
  * Decref the replaced regexp internals.
  */
 static void
 SwapObjectRegExp(JSContext *cx, JSObject *obj, RegExp &newRegExp)
 {
-    RegExp *oldRegExp;
-    {
-        AutoObjectLocker lock(cx, obj);
-        oldRegExp = RegExp::extractFrom(obj);
-        obj->setPrivate(&newRegExp);
-        obj->zeroRegExpLastIndex();
-    }
+    RegExp *oldRegExp = RegExp::extractFrom(obj);
+    obj->setPrivate(&newRegExp);
+    obj->zeroRegExpLastIndex();
     if (oldRegExp)
         oldRegExp->decref(cx);
 }
 
 JSObject * JS_FASTCALL
 js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto)
 {
     JS_ASSERT(obj->getClass() == &js_RegExpClass);
@@ -297,17 +293,16 @@ RegExp::createFlagged(JSContext *cx, JSS
     static JSBool                                                              \
     name(JSContext *cx, JSObject *obj, jsid id, Value *vp)                     \
     {                                                                          \
         while (obj->getClass() != &js_RegExpClass) {                           \
             obj = obj->getProto();                                             \
             if (!obj)                                                          \
                 return true;                                                   \
         }                                                                      \
-        AutoObjectLocker(cx, obj);                                             \
         RegExp *re = RegExp::extractFrom(obj);                                 \
         code;                                                                  \
         return true;                                                           \
     }
 
 /* lastIndex is stored in the object, re = re silences the compiler warning. */
 DEFINE_GETTER(lastIndex_getter,  re = re; *vp = obj->getRegExpLastIndex())
 DEFINE_GETTER(source_getter,     *vp = StringValue(re->getSource()))
@@ -572,53 +567,49 @@ js::Class js_RegExpClass = {
  */
 
 JSBool
 js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
 {
     static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0};
     if (!InstanceOf(cx, obj, &js_RegExpClass, vp + 2))
         return false;
-    JS_LOCK_OBJ(cx, obj);
     RegExp *re = RegExp::extractFrom(obj);
     if (!re) {
-        JS_UNLOCK_OBJ(cx, obj);
         *vp = StringValue(cx->runtime->emptyString);
         return true;
     }
 
     const jschar *source;
     size_t length;
     re->getSource()->getCharsAndLength(source, length);
     if (length == 0) {
         source = empty_regexp_ucstr;
         length = JS_ARRAY_LENGTH(empty_regexp_ucstr) - 1;
     }
     length += 2;
     uint32 nflags = re->flagCount();
     jschar *chars = (jschar*) cx->malloc((length + nflags + 1) * sizeof(jschar));
     if (!chars) {
-        JS_UNLOCK_OBJ(cx, obj);
         return false;
     }
 
     chars[0] = '/';
     js_strncpy(&chars[1], source, length - 2);
     chars[length - 1] = '/';
     if (nflags) {
         if (re->global())
             chars[length++] = 'g';
         if (re->ignoreCase())
             chars[length++] = 'i';
         if (re->multiline())
             chars[length++] = 'm';
         if (re->sticky())
             chars[length++] = 'y';
     }
-    JS_UNLOCK_OBJ(cx, obj);
     chars[length] = 0;
 
     JSString *str = js_NewString(cx, chars, length);
     if (!str) {
         cx->free(chars);
         return false;
     }
     *vp = StringValue(str);
@@ -704,17 +695,16 @@ regexp_compile_sub(JSContext *cx, JSObje
          */
         JSObject &sourceObj = sourceValue.toObject();
         if (argc >= 2 && !argv[1].isUndefined()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED);
             return false;
         }
         RegExp *clone;
         {
-            AutoObjectLocker lock(cx, &sourceObj);
             RegExp *re = RegExp::extractFrom(&sourceObj);
             if (!re)
                 return false;
             clone = RegExp::clone(cx, *re);
         }
         if (!clone)
             return false;
         SwapObjectRegExp(cx, obj, *clone);
@@ -753,22 +743,20 @@ regexp_compile(JSContext *cx, uintN argc
 }
 
 static JSBool
 regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, JSBool test, Value *rval)
 {
     bool ok = InstanceOf(cx, obj, &js_RegExpClass, argv);
     if (!ok)
         return JS_FALSE;
-    JS_LOCK_OBJ(cx, obj);
+
     RegExp *re = RegExp::extractFrom(obj);
-    if (!re) {
-        JS_UNLOCK_OBJ(cx, obj);
+    if (!re)
         return JS_TRUE;
-    }
 
     /* NB: we must reach out: after this paragraph, in order to drop re. */
     re->incref(cx);
     jsdouble lastIndex;
     if (re->global() || re->sticky()) {
         const Value v = obj->getRegExpLastIndex();
         if (v.isInt32()) {
             lastIndex = v.toInt32();
@@ -777,17 +765,16 @@ regexp_exec_sub(JSContext *cx, JSObject 
                 lastIndex = v.toDouble();
             else if (!ValueToNumber(cx, v, &lastIndex))
                 return JS_FALSE;
             lastIndex = js_DoubleToInteger(lastIndex);
         }
     } else {
         lastIndex = 0;
     }
-    JS_UNLOCK_OBJ(cx, obj);
 
     /* Now that obj is unlocked, it's safe to (potentially) grab the GC lock. */
     RegExpStatics *res = cx->regExpStatics();
     JSString *str;
     if (argc) {
         str = js_ValueToString(cx, argv[0]);
         if (!str) {
             ok = JS_FALSE;
--- a/js/src/jsscope.cpp
+++ b/js/src/jsscope.cpp
@@ -1265,17 +1265,17 @@ JSObject::deletingShapeChange(JSContext 
 }
 
 bool
 JSObject::methodShapeChange(JSContext *cx, const Shape &shape)
 {
     JS_ASSERT(!JSID_IS_VOID(shape.id));
     if (shape.isMethod()) {
 #ifdef DEBUG
-        const Value &prev = lockedGetSlot(shape.slot);
+        const Value &prev = nativeGetSlot(shape.slot);
         JS_ASSERT(&shape.methodObject() == &prev.toObject());
         JS_ASSERT(canHaveMethodBarrier());
         JS_ASSERT(hasMethodBarrier());
         JS_ASSERT(!shape.rawSetter || shape.rawSetter == js_watch_set);
 #endif
 
         /*
          * Pass null to make a stub getter, but pass along shape.rawSetter to
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -255,30 +255,16 @@ struct PropertyTable {
     bool            change(JSContext *cx, int change);
     js::Shape       **search(jsid id, bool adding);
 };
 
 } /* namespace js */
 
 struct JSObject;
 
-inline const js::Value &
-JSObject::lockedGetSlot(uintN slot) const
-{
-    OBJ_CHECK_SLOT(this, slot);
-    return this->getSlot(slot);
-}
-
-inline void
-JSObject::lockedSetSlot(uintN slot, const js::Value &value)
-{
-    OBJ_CHECK_SLOT(this, slot);
-    this->setSlot(slot, value);
-}
-
 namespace js {
 
 class PropertyTree;
 
 static inline PropertyOp
 CastAsPropertyOp(js::Class *clasp)
 {
     return JS_DATA_TO_FUNC_PTR(PropertyOp, clasp);
@@ -856,28 +842,16 @@ Shape::search(js::Shape **startp, jsid i
 #undef METER
 
 inline bool
 Shape::isSharedPermanent() const
 {
     return (~attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0;
 }
 
-class AutoObjectLocker {
-    JSContext   * const cx;
-    JSObject    * const obj;
-  public:
-    AutoObjectLocker(JSContext *cx, JSObject *obj)
-      : cx(cx), obj(obj) {
-        JS_LOCK_OBJ(cx, obj);
-    }
-
-    ~AutoObjectLocker() { JS_UNLOCK_OBJ(cx, obj); }
-};
-
 }
 
 #ifdef _MSC_VER
 #pragma warning(pop)
 #pragma warning(pop)
 #endif
 
 #endif /* jsscope_h___ */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -5679,28 +5679,21 @@ CheckGlobalObjectShape(JSContext* cx, Tr
     }
 
     /*
      * The global object must have a unique shape. That way, if an operand
      * isn't the global at record time, a shape guard suffices to ensure
      * that it isn't the global at run time.
      */
     if (!globalObj->hasOwnShape()) {
-        JS_LOCK_OBJ(cx, globalObj);
-        bool ok = globalObj->globalObjectOwnShapeChange(cx);
-        JS_UNLOCK_OBJ(cx, globalObj);
-        if (!ok) {
+        if (!globalObj->globalObjectOwnShapeChange(cx)) {
             debug_only_print0(LC_TMTracer,
                               "Can't record: failed to give globalObj a unique shape.\n");
             return false;
         }
-    } else {
-        /* Claim the title so we don't abort at the top of recordLoopEdge. */
-        JS_LOCK_OBJ(cx, globalObj);
-        JS_UNLOCK_OBJ(cx, globalObj);
     }
 
     uint32 globalShape = globalObj->shape();
 
     if (tm->recorder) {
         TreeFragment* root = tm->recorder->getFragment()->root;
 
         /* Check the global shape matches the recorder's treeinfo's shape. */
@@ -6163,24 +6156,16 @@ RecordingIfTrue(bool b)
 
 /*
  * A postcondition of recordLoopEdge is that if recordLoopEdge does not return
  * MONITOR_RECORDING, the recording has been aborted.
  */
 JS_REQUIRES_STACK MonitorResult
 TraceRecorder::recordLoopEdge(JSContext* cx, TraceRecorder* r, uintN& inlineCallCount)
 {
-#ifdef JS_THREADSAFE
-    /* If changing this, see "Claim the title" in CheckGlobalObjectShape. */
-    if (cx->fp()->scopeChain().getGlobal()->title.ownercx != cx) {
-        AbortRecording(cx, "Global object not owned by this context");
-        return MONITOR_NOT_RECORDING; /* we stay away from shared global objects */
-    }
-#endif
-
     TraceMonitor* tm = &JS_TRACE_MONITOR(cx);
 
     /* Process needFlush and deep abort requests. */
     if (tm->needFlush) {
         ResetJIT(cx, FR_DEEP_BAIL);
         return MONITOR_NOT_RECORDING;
     }
 
@@ -8230,45 +8215,36 @@ TraceRecorder::scopeChainProp(JSObject* 
             chainHead = cx->fp()->callee().getParent();
             head_ins = stobj_get_parent(get(&cx->fp()->calleeValue()));
         } else {
             head_ins = scopeChain();
         }
         LIns *obj_ins;
         CHECK_STATUS_A(traverseScopeChain(chainHead, head_ins, obj, obj_ins));
 
-        if (obj2 != obj) {
-            obj2->dropProperty(cx, prop);
+        if (obj2 != obj)
             RETURN_STOP_A("prototype property");
-        }
 
         Shape* shape = (Shape*) prop;
-        if (!isValidSlot(obj, shape)) {
-            JS_UNLOCK_OBJ(cx, obj2);
+        if (!isValidSlot(obj, shape))
             return ARECORD_STOP;
-        }
-        if (!lazilyImportGlobalSlot(shape->slot)) {
-            JS_UNLOCK_OBJ(cx, obj2);
+        if (!lazilyImportGlobalSlot(shape->slot))
             RETURN_STOP_A("lazy import of global slot failed");
-        }
         vp = &obj->getSlotRef(shape->slot);
         ins = get(vp);
-        JS_UNLOCK_OBJ(cx, obj2);
         nr.tracked = true;
         return ARECORD_CONTINUE;
     }
 
     if (obj == obj2 && obj->isCall()) {
         AbortableRecordingStatus status =
             InjectStatus(callProp(obj, prop, ATOM_TO_JSID(atom), vp, ins, nr));
-        JS_UNLOCK_OBJ(cx, obj);
         return status;
     }
 
-    obj2->dropProperty(cx, prop);
     RETURN_STOP_A("fp->scopeChain is not global or active call object");
 }
 
 /*
  * Generate LIR to access a property of a Call object.
  */
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, Value*& vp,
@@ -9652,30 +9628,26 @@ TraceRecorder::test_property_cache(JSObj
             /* js_FindPropertyHelper can reenter the interpreter and kill |this|. */
             if (!localtm.recorder)
                 return ARECORD_ABORTED;
 
             if (entry == JS_NO_PROP_CACHE_FILL)
                 RETURN_STOP_A("cannot cache name");
         } else {
             TraceMonitor &localtm = *traceMonitor;
-            JSContext *localcx = cx;
             int protoIndex = js_LookupPropertyWithFlags(cx, aobj, id,
                                                         cx->resolveFlags,
                                                         &obj2, &prop);
 
             if (protoIndex < 0)
                 RETURN_ERROR_A("error in js_LookupPropertyWithFlags");
 
             /* js_LookupPropertyWithFlags can reenter the interpreter and kill |this|. */
-            if (!localtm.recorder) {
-                if (prop)
-                    obj2->dropProperty(localcx, prop);
+            if (!localtm.recorder)
                 return ARECORD_ABORTED;
-            }
 
             if (prop) {
                 if (!obj2->isNative())
                     RETURN_STOP_A("property found on non-native object");
                 entry = JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, protoIndex, obj2,
                                                    (Shape*) prop);
                 JS_ASSERT(entry);
                 if (entry == JS_NO_PROP_CACHE_FILL)
@@ -9690,17 +9662,16 @@ TraceRecorder::test_property_cache(JSObj
             // the global it's assigning does not yet exist, create it.
             obj2 = obj;
 
             // Use a null pcval to return "no such property" to our caller.
             pcval.setNull();
             return ARECORD_CONTINUE;
         }
 
-        obj2->dropProperty(cx, prop);
         if (!entry)
             RETURN_STOP_A("failed to fill property cache");
     }
 
 #ifdef JS_THREADSAFE
     // There's a potential race in any JS_THREADSAFE embedding that's nuts
     // enough to share mutable objects on the scope or proto chain, but we
     // don't care about such insane embeddings. Anyway, the (scope, proto)
@@ -12676,17 +12647,16 @@ GetPropertyWithNativeGetter(JSContext* c
 {
     LeaveTraceIfGlobalObject(cx, obj);
 
 #ifdef DEBUG
     JSProperty* prop;
     JSObject* pobj;
     JS_ASSERT(obj->lookupProperty(cx, shape->id, &pobj, &prop));
     JS_ASSERT(prop == (JSProperty*) shape);
-    pobj->dropProperty(cx, prop);
 #endif
 
     // Shape::get contains a special case for With objects. We can elide it
     // here because With objects are, we claim, never on the operand stack
     // while recording.
     JS_ASSERT(obj->getClass() != &js_WithClass);
 
     vp->setUndefined();
@@ -15193,35 +15163,29 @@ TraceRecorder::record_JSOP_IN()
     } else {
         RETURN_STOP_A("string or integer expected");
     }
 
     guard(false, lir->ins2ImmI(LIR_eqi, x, JS_NEITHER), OOM_EXIT);
     x = lir->ins2ImmI(LIR_eqi, x, 1);
 
     TraceMonitor &localtm = *traceMonitor;
-    JSContext *localcx = cx;
 
     JSObject* obj2;
     JSProperty* prop;
     JSBool ok = obj->lookupProperty(cx, id, &obj2, &prop);
 
     if (!ok)
         RETURN_ERROR_A("obj->lookupProperty failed in JSOP_IN");
 
     /* lookupProperty can reenter the interpreter and kill |this|. */
-    if (!localtm.recorder) {
-        if (prop)
-            obj2->dropProperty(localcx, prop);
+    if (!localtm.recorder)
         return ARECORD_ABORTED;
-    }
 
     bool cond = prop != NULL;
-    if (prop)
-        obj2->dropProperty(cx, prop);
 
     /*
      * The interpreter fuses comparisons and the following branch, so we have
      * to do that here as well.
      */
     fuseIf(cx->regs->pc + 1, cond, x);
 
     /*
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -522,17 +522,16 @@ class TypedArrayTemplate
             if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, &obj2, &prop) < 0)
                 return false;
 
             if (prop) {
                 if (obj2->isNative()) {
                     shape = (Shape *) prop;
                     if (!js_NativeGet(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, vp))
                         return false;
-                    JS_UNLOCK_OBJ(cx, obj2);
                 }
             }
         }
 
         return true;
     }
 
     static JSBool
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -4589,35 +4589,31 @@ HasFunctionProperty(JSContext *cx, JSObj
     JSObject *pobj;
     JSProperty *prop;
     JSXML *xml;
 
     JS_ASSERT(obj->getClass() == &js_XMLClass);
 
     if (!js_LookupProperty(cx, obj, funid, &pobj, &prop))
         return false;
-    if (prop) {
-        pobj->dropProperty(cx, prop);
-    } else {
+    if (!prop) {
         xml = (JSXML *) obj->getPrivate();
         if (HasSimpleContent(xml)) {
             AutoObjectRooter tvr(cx);
 
             /*
              * Search in String.prototype to set found whenever
              * GetXMLFunction returns existing function.
              */
             if (!js_GetClassPrototype(cx, NULL, JSProto_String, tvr.addr()))
                 return false;
 
             JS_ASSERT(tvr.object());
             if (!js_LookupProperty(cx, tvr.object(), funid, &pobj, &prop))
                 return false;
-            if (prop)
-                pobj->dropProperty(cx, prop);
         }
     }
     *found = (prop != NULL);
     return true;
 }
 
 /* ECMA-357 9.1.1.6 XML [[HasProperty]] and 9.2.1.5 XMLList [[HasProperty]]. */
 static JSBool
@@ -4721,17 +4717,16 @@ xml_lookupProperty(JSContext *cx, JSObje
         const Shape *shape =
             js_AddNativeProperty(cx, obj, id,
                                  Valueify(GetProperty), Valueify(PutProperty),
                                  SHAPE_INVALID_SLOT, JSPROP_ENUMERATE,
                                  0, 0);
         if (!shape)
             return JS_FALSE;
 
-        JS_LOCK_OBJ(cx, obj);
         *objp = obj;
         *propp = (JSProperty *) shape;
     }
     return JS_TRUE;
 }
 
 static JSBool
 xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v,
@@ -7123,19 +7118,17 @@ js_InitXMLClass(JSContext *cx, JSObject 
      */
     if (!js_LookupProperty(cx, proto,
                            ATOM_TO_JSID(cx->runtime->atomState.constructorAtom),
                            &pobj, &prop)) {
         return NULL;
     }
     JS_ASSERT(prop);
     shape = (Shape *) prop;
-    JS_ASSERT(pobj->containsSlot(shape->slot));
-    cval = Jsvalify(pobj->getSlotMT(cx, shape->slot));
-    JS_UNLOCK_OBJ(cx, pobj);
+    cval = Jsvalify(pobj->nativeGetSlot(shape->slot));
     JS_ASSERT(VALUE_IS_FUNCTION(cx, cval));
 
     /* Set default settings. */
     vp[0] = JSVAL_NULL;
     vp[1] = cval;
     vp[2] = JSVAL_VOID;
     if (!xml_setSettings(cx, 1, vp))
         return NULL;
@@ -7424,17 +7417,16 @@ js_FindXMLProperty(JSContext *cx, const 
                 *idp = OBJECT_TO_JSID(nameobj);
                 *objp = target;
                 return JS_TRUE;
             }
         } else if (!JSID_IS_VOID(funid)) {
             if (!target->lookupProperty(cx, funid, &pobj, &prop))
                 return JS_FALSE;
             if (prop) {
-                pobj->dropProperty(cx, prop);
                 *idp = funid;
                 *objp = target;
                 return JS_TRUE;
             }
         }
     } while ((obj = obj->getParent()) != NULL);
 
     printable = js_ValueToPrintableString(cx, ObjectValue(*nameobj));
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -81,30 +81,27 @@ void JS_FASTCALL
 ic::GetGlobalName(VMFrame &f, ic::MICInfo *ic)
 {
     JSObject *obj = f.fp()->scopeChain().getGlobal();
     JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
     jsid id = ATOM_TO_JSID(atom);
 
     JS_ASSERT(ic->kind == ic::MICInfo::GET);
 
-    JS_LOCK_OBJ(f.cx, obj);
     const Shape *shape = obj->nativeLookup(id);
     if (!shape ||
         !shape->hasDefaultGetterOrIsMethod() ||
         !shape->hasSlot())
     {
-        JS_UNLOCK_OBJ(f.cx, obj);
         if (shape)
             PatchGetFallback(f, ic);
         stubs::GetGlobalName(f);
         return;
     }
     uint32 slot = shape->slot;
-    JS_UNLOCK_OBJ(f.cx, obj);
 
     ic->u.name.touched = true;
 
     /* Patch shape guard. */
     JSC::RepatchBuffer repatch(ic->entry.executableAddress(), 50);
     repatch.repatch(ic->shape, obj->shape());
 
     /* Patch loads. */
@@ -159,31 +156,28 @@ void JS_FASTCALL
 ic::SetGlobalName(VMFrame &f, ic::MICInfo *ic)
 {
     JSObject *obj = f.fp()->scopeChain().getGlobal();
     JSAtom *atom = f.fp()->script()->getAtom(GET_INDEX(f.regs.pc));
     jsid id = ATOM_TO_JSID(atom);
 
     JS_ASSERT(ic->kind == ic::MICInfo::SET);
 
-    JS_LOCK_OBJ(f.cx, obj);
     const Shape *shape = obj->nativeLookup(id);
     if (!shape ||
         !shape->hasDefaultGetterOrIsMethod() ||
         !shape->writable() ||
         !shape->hasSlot())
     {
-        JS_UNLOCK_OBJ(f.cx, obj);
         if (shape)
             PatchSetFallback(f, ic);
         GetStubForSetGlobalName(f)(f, atom);
         return;
     }
     uint32 slot = shape->slot;
-    JS_UNLOCK_OBJ(f.cx, obj);
 
     ic->u.name.touched = true;
 
     /* Patch shape guard. */
     JSC::RepatchBuffer repatch(ic->entry.executableAddress(), 50);
     repatch.repatch(ic->shape, obj->shape());
 
     /* Patch loads. */
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -339,26 +339,16 @@ class SetPropCompiler : public PICStubCo
         JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->getClass() == &js_CallClass);
 
         MaybeJump skipOver;
 
         if (adding) {
             JS_ASSERT(shape->hasSlot());
             pic.shapeRegHasBaseShape = false;
 
-#ifdef JS_THREADSAFE
-            /* Check that the object isn't shared, so no locking needed. */
-            masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), pic.shapeReg);
-            Jump sharedObject = masm.branchPtr(Assembler::NotEqual,
-                                               Address(pic.objReg, offsetof(JSObject, title.ownercx)),
-                                               pic.shapeReg);
-            if (!slowExits.append(sharedObject))
-                return false;
-#endif
-
             /* Emit shape guards for the object's prototype chain. */
             JSObject *proto = obj->getProto();
             RegisterID lastReg = pic.objReg;
             while (proto) {
                 masm.loadPtr(Address(lastReg, offsetof(JSObject, proto)), pic.shapeReg);
                 Jump protoGuard = masm.guardShape(pic.shapeReg, proto->shape());
                 if (!otherGuards.append(protoGuard))
                     return false;
@@ -544,31 +534,25 @@ class SetPropCompiler : public PICStubCo
 
         if (clasp->setProperty != PropertyStub)
             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");
 
-#ifdef JS_THREADSAFE
-        if (!CX_OWNS_OBJECT_TITLE(cx, obj))
-            return disable("shared object");
-#endif
-
         jsid id = ATOM_TO_JSID(atom);
 
         JSObject *holder;
         JSProperty *prop = NULL;
         if (!obj->lookupProperty(cx, id, &holder, &prop))
             return false;
 
         /* If the property exists but is on a prototype, treat as addprop. */
         if (prop && holder != obj) {
-            AutoPropertyDropper dropper(cx, holder, prop);
             const Shape *shape = (const Shape *) prop;
 
             if (!holder->isNative())
                 return disable("non-native holder");
 
             if (!shape->writable())
                 return disable("readonly");
             if (!shape->hasDefaultSetter() || !shape->hasDefaultGetter())
@@ -651,18 +635,16 @@ class SetPropCompiler : public PICStubCo
              * don't realloc.
              */
             if (obj->numSlots() != slots)
                 return disable("insufficient slot capacity");
 
             return generateStub(initialShape, shape, true, !obj->hasSlotsArray());
         }
 
-        AutoPropertyDropper dropper(cx, holder, prop);
-
         const Shape *shape = (const Shape *) prop;
         if (pic.kind == ic::PICInfo::SETMETHOD && !shape->isMethod())
             return disable("set method on non-method shape");
         if (!shape->writable())
             return disable("readonly");
 
         if (shape->hasDefaultSetter()) {
             if (!shape->hasSlot())
@@ -858,17 +840,16 @@ class GetPropCompiler : public PICStubCo
 
         JSObject *holder;
         JSProperty *prop;
         if (!obj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
             return false;
         if (!prop)
             return disable("property not found");
 
-        AutoPropertyDropper dropper(cx, holder, prop);
         const Shape *shape = (const Shape *)prop;
         if (holder != obj)
             return disable("proto walk on String.prototype");
         if (!shape->hasDefaultGetterOrIsMethod())
             return disable("getter");
         if (shape->isMethod() && !isCallOp())
             return disable("method valued shape");
         if (!shape->hasSlot())
@@ -1177,18 +1158,16 @@ class GetPropCompiler : public PICStubCo
         JSObject *holder;
         JSProperty *prop;
         if (!aobj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
             return false;
 
         if (!prop)
             return disable("lookup failed");
 
-        AutoPropertyDropper dropper(cx, holder, prop);
-
         if (!holder->isNative())
             return disable("non-native holder");
 
         const Shape *shape = (const Shape *)prop;
         if (!shape->hasDefaultGetterOrIsMethod())
             return disable("getter");
         if (shape->isMethod() && !isCallOp())
             return disable("method valued shape");
@@ -1516,18 +1495,16 @@ class GetElemCompiler : public PICStubCo
         JSObject *holder;
         JSProperty *prop;
         if (!obj->lookupProperty(cx, ATOM_TO_JSID(atom), &holder, &prop))
             return false;
 
         if (!prop)
             return disable("lookup failed");
 
-        AutoPropertyDropper dropper(cx, holder, prop);
-
         if (!obj->isNative())
             return disable("non-native obj");
         if (!holder->isNative())
             return disable("non-native holder");
 
         const Shape *shape = (const Shape *)prop;
         if (!shape->hasDefaultGetterOrIsMethod())
             return disable("getter");
@@ -1845,17 +1822,16 @@ class ScopeNameCompiler : public PICStub
             return generateGlobalStub();
 
         return disable("scope object not handled yet");
     }
 
     bool retrieve(Value *vp)
     {
         if (prop && (!obj->isNative() || !holder->isNative())) {
-            holder->dropProperty(cx, prop);
             if (!obj->getProperty(cx, ATOM_TO_JSID(atom), vp))
                 return false;
         } else {
             if (!prop) {
                 /* Kludge to allow (typeof foo == "undefined") tests. */
                 disable("property not found");
                 if (pic.kind == ic::PICInfo::NAME) {
                     JSOp op2 = js_GetOpcode(cx, script, cx->regs->pc + JSOP_NAME_LENGTH);
@@ -1868,17 +1844,16 @@ class ScopeNameCompiler : public PICStub
                 return false;
             }
             const Shape *shape = (const Shape *)prop;
             JSObject *normalized = obj;
             if (obj->getClass() == &js_WithClass && !shape->hasDefaultGetter())
                 normalized = js_UnwrapWithObject(cx, obj);
             NATIVE_GET(cx, normalized, holder, shape, JSGET_METHOD_BARRIER, vp,
                        return false);
-            JS_UNLOCK_OBJ(cx, holder);
         }
 
         return true;
     }
 };
 
 class BindNameCompiler : public PICStubCompiler
 {
@@ -2209,18 +2184,17 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pi
     JSObject *obj2;
     JSAtom *atom;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
     if (!atom) {
         if (entry->vword.isFunObj()) {
             rval.setObject(entry->vword.toFunObj());
         } else if (entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
-            JS_ASSERT(obj2->containsSlot(slot));
-            rval = obj2->lockedGetSlot(slot);
+            rval = obj2->nativeGetSlot(slot);
         } else {
             JS_ASSERT(entry->vword.isShape());
             const Shape *shape = entry->vword.toShape();
             NATIVE_GET(cx, &objv.toObject(), obj2, shape, JSGET_NO_METHOD_BARRIER, &rval,
                        THROW());
         }
         regs.sp++;
         regs.sp[-2] = rval;
--- a/js/src/methodjit/StubCalls-inl.h
+++ b/js/src/methodjit/StubCalls-inl.h
@@ -71,31 +71,31 @@ ReportAtomNotDefined(JSContext *cx, JSAt
 }
 
 #define NATIVE_SET(cx,obj,shape,entry,vp)                                     \
     JS_BEGIN_MACRO                                                            \
         if (shape->hasDefaultSetter() &&                                      \
             (shape)->slot != SHAPE_INVALID_SLOT &&                            \
             !(obj)->brandedOrHasMethodBarrier()) {                            \
             /* Fast path for, e.g., plain Object instance properties. */      \
-            (obj)->lockedSetSlot((shape)->slot, *vp);                         \
+            (obj)->nativeSetSlot((shape)->slot, *vp);                         \
         } else {                                                              \
             if (!js_NativeSet(cx, obj, shape, false, vp))                     \
                 THROW();                                                      \
         }                                                                     \
     JS_END_MACRO
 
 #define NATIVE_GET(cx,obj,pobj,shape,getHow,vp,onerr)                         \
     JS_BEGIN_MACRO                                                            \
         if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {         \
             /* Fast path for Object instance properties. */                   \
             JS_ASSERT((shape)->slot != SHAPE_INVALID_SLOT ||                  \
                       !shape->hasDefaultSetter());                            \
             if (((shape)->slot != SHAPE_INVALID_SLOT))                        \
-                *(vp) = (pobj)->lockedGetSlot((shape)->slot);                 \
+                *(vp) = (pobj)->nativeGetSlot((shape)->slot);                 \
             else                                                              \
                 (vp)->setUndefined();                                         \
         } else {                                                              \
             if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp))              \
                 onerr;                                                        \
         }                                                                     \
     JS_END_MACRO
 
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -189,25 +189,17 @@ stubs::SetName(VMFrame &f, JSAtom *origA
                     PCMETER(cache->setpchits++);
                     NATIVE_SET(cx, obj, shape, entry, &rval);
                     break;
                 }
             } else {
                 JS_ASSERT(obj->isExtensible());
 
                 if (obj->nativeEmpty()) {
-                    /*
-                     * We check that cx owns obj here and will continue to own
-                     * it after ensureClassReservedSlotsForEmptyObject returns
-                     * so we can continue to skip JS_UNLOCK_OBJ calls.
-                     */
-                    JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj));
-                    bool ok = obj->ensureClassReservedSlotsForEmptyObject(cx);
-                    JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj));
-                    if (!ok)
+                    if (!obj->ensureClassReservedSlotsForEmptyObject(cx))
                         THROW();
                 }
 
                 uint32 slot;
                 if (shape->previous() == obj->lastProperty() &&
                     entry->vshape() == cx->runtime->protoHazardShape &&
                     shape->hasDefaultSetter()) {
                     slot = shape->slot;
@@ -233,17 +225,17 @@ stubs::SetName(VMFrame &f, JSAtom *origA
                     /* Simply extend obj's property tree path with shape! */
                     obj->extend(cx, shape);
 
                     /*
                      * No method change check here because here we are adding a
                      * new property, not updating an existing slot's value that
                      * might contain a method of a branded shape.
                      */
-                    obj->lockedSetSlot(slot, rval);
+                    obj->setSlot(slot, rval);
 
                     /*
                      * Purge the property cache of the id we may have just
                      * shadowed in obj's scope and proto chains.
                      */
                     js_PurgeScopeChain(cx, obj, shape->id);
                     break;
                 }
@@ -352,19 +344,18 @@ NameOp(VMFrame &f, JSObject *obj, bool c
     JSAtom *atom;
     JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
     if (!atom) {
         if (entry->vword.isFunObj()) {
             f.regs.sp++;
             f.regs.sp[-1].setObject(entry->vword.toFunObj());
         } else if (entry->vword.isSlot()) {
             uintN slot = entry->vword.toSlot();
-            JS_ASSERT(obj2->containsSlot(slot));
             f.regs.sp++;
-            f.regs.sp[-1] = obj2->lockedGetSlot(slot);
+            f.regs.sp[-1] = obj2->nativeGetSlot(slot);
         } else {
             JS_ASSERT(entry->vword.isShape());
             shape = entry->vword.toShape();
             NATIVE_GET(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, &rval, return NULL);
             f.regs.sp++;
             f.regs.sp[-1] = rval;
         }
 
@@ -401,26 +392,24 @@ NameOp(VMFrame &f, JSObject *obj, bool c
             return obj;
         }
         ReportAtomNotDefined(cx, atom);
         return NULL;
     }
 
     /* Take the slow path if prop was not found in a native object. */
     if (!obj->isNative() || !obj2->isNative()) {
-        obj2->dropProperty(cx, prop);
         if (!obj->getProperty(cx, id, &rval))
             return NULL;
     } else {
         shape = (Shape *)prop;
         JSObject *normalized = obj;
         if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter())
             normalized = js_UnwrapWithObject(cx, normalized);
         NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval, return NULL);
-        JS_UNLOCK_OBJ(cx, obj2);
     }
 
     f.regs.sp++;
     f.regs.sp[-1] = rval;
     if (callname) {
         Class *clasp;
         JSObject *thisp = obj;
         if (!thisp->getParent() ||
@@ -486,18 +475,16 @@ stubs::ForName(VMFrame &f, JSAtom *atom)
     JSFrameRegs &regs = f.regs;
 
     JS_ASSERT(regs.sp - 1 >= f.fp()->base());
     jsid id = ATOM_TO_JSID(atom);
     JSObject *obj, *obj2;
     JSProperty *prop;
     if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
         THROW();
-    if (prop)
-        obj2->dropProperty(cx, prop);
     {
         AutoValueRooter tvr(cx);
         JS_ASSERT(regs.sp[-1].isObject());
         if (!IteratorNext(cx, &regs.sp[-1].toObject(), tvr.addr()))
             THROW();
         if (!obj->setProperty(cx, id, tvr.addr(), strict))
             THROW();
     }
@@ -970,17 +957,16 @@ stubs::DefFun(VMFrame &f, JSFunction *fu
              * JSPROP_PERMANENT (not [[Configurable]] in ES5 terms) attribute
              * is not changing (note that JSPROP_ENUMERATE is set for all Call
              * object properties).
              */
             JS_ASSERT(oldAttrs & attrs & JSPROP_ENUMERATE);
             if (oldAttrs & JSPROP_PERMANENT)
                 doSet = true;
         }
-        pobj->dropProperty(cx, prop);
     }
 
     Value rval = ObjectValue(*obj);
     ok = doSet
          ? parent->setProperty(cx, id, &rval, strict)
          : parent->defineProperty(cx, id, rval, PropertyStub, PropertyStub, attrs);
     if (!ok)
         THROW();
@@ -1754,18 +1740,17 @@ NameIncDec(VMFrame &f, JSObject *obj, JS
     JSAtom *atom;
     JSObject *obj2;
     JSProperty *prop;
     PropertyCacheEntry *entry;
     JS_PROPERTY_CACHE(cx).test(cx, f.regs.pc, obj, obj2, entry, atom);
     if (!atom) {
         if (obj == obj2 && entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
-            JS_ASSERT(obj->containsSlot(slot));
-            Value &rref = obj->getSlotRef(slot);
+            Value &rref = obj->nativeGetSlotRef(slot);
             int32_t tmp;
             if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) {
                 int32_t inc = tmp + N;
                 if (!POST)
                     tmp = inc;
                 rref.getInt32Ref() = inc;
                 f.regs.sp[0].setInt32(tmp);
                 return true;
@@ -1776,17 +1761,16 @@ NameIncDec(VMFrame &f, JSObject *obj, JS
 
     jsid id = ATOM_TO_JSID(atom);
     if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
         return false;
     if (!prop) {
         ReportAtomNotDefined(cx, atom);
         return false;
     }
-    obj2->dropProperty(cx, prop);
     return ObjIncOp<N, POST, strict>(f, obj, id);
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::PropInc(VMFrame &f, JSAtom *atom)
 {
     JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);
@@ -2037,18 +2021,17 @@ InlineGetProp(VMFrame &f)
         JSObject *obj2;
         JSAtom *atom;
         JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
         if (!atom) {
             if (entry->vword.isFunObj()) {
                 rval.setObject(entry->vword.toFunObj());
             } else if (entry->vword.isSlot()) {
                 uint32 slot = entry->vword.toSlot();
-                JS_ASSERT(obj2->containsSlot(slot));
-                rval = obj2->lockedGetSlot(slot);
+                rval = obj2->nativeGetSlot(slot);
             } else {
                 JS_ASSERT(entry->vword.isShape());
                 const Shape *shape = entry->vword.toShape();
                 NATIVE_GET(cx, obj, obj2, shape,
                         f.fp()->hasImacropc() ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER,
                         &rval, return false);
             }
             break;
@@ -2129,18 +2112,17 @@ stubs::CallProp(VMFrame &f, JSAtom *orig
     JSObject *obj2;
     JSAtom *atom;
     JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom);
     if (!atom) {
         if (entry->vword.isFunObj()) {
             rval.setObject(entry->vword.toFunObj());
         } else if (entry->vword.isSlot()) {
             uint32 slot = entry->vword.toSlot();
-            JS_ASSERT(obj2->containsSlot(slot));
-            rval = obj2->lockedGetSlot(slot);
+            rval = obj2->nativeGetSlot(slot);
         } else {
             JS_ASSERT(entry->vword.isShape());
             const Shape *shape = entry->vword.toShape();
             NATIVE_GET(cx, &objv.toObject(), obj2, shape, JSGET_NO_METHOD_BARRIER, &rval,
                        THROW());
         }
         regs.sp++;
         regs.sp[-2] = rval;
@@ -2244,18 +2226,17 @@ InitPropOrMethod(VMFrame &f, JSAtom *ato
      * So check first.
      *
      * On a hit, if the cached shape has a non-default setter, it must be
      * __proto__. If shape->previous() != obj->lastProperty(), there must be a
      * repeated property name. The fast path does not handle these two cases.
      */
     PropertyCacheEntry *entry;
     const Shape *shape;
-    if (CX_OWNS_OBJECT_TITLE(cx, obj) &&
-        JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, &shape, &entry) &&
+    if (JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, &shape, &entry) &&
         shape->hasDefaultSetter() &&
         shape->previous() == obj->lastProperty())
     {
         /* Fast path. Property cache hit. */
         uint32 slot = shape->slot;
 
         JS_ASSERT(slot == obj->slotSpan());
         JS_ASSERT(slot >= JSSLOT_FREE(obj->getClass()));
@@ -2272,17 +2253,17 @@ InitPropOrMethod(VMFrame &f, JSAtom *ato
                   obj->shape() == obj->lastProperty()->shape);
         obj->extend(cx, shape);
 
         /*
          * No method change check here because here we are adding a new
          * property, not updating an existing slot's value that might
          * contain a method of a branded shape.
          */
-        obj->lockedSetSlot(slot, rval);
+        obj->nativeSetSlot(slot, rval);
     } else {
         PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++);
 
         /* Get the immediate property name into id. */
         jsid id = ATOM_TO_JSID(atom);
 
         /* No need to check for duplicate property; the compiler already did. */
 
@@ -2679,17 +2660,16 @@ stubs::DelName(VMFrame &f, JSAtom *atom)
 
     /* Strict mode code should never contain JSOP_DELNAME opcodes. */
     JS_ASSERT(!f.fp()->script()->strictModeCode);
 
     /* ECMA says to return true if name is undefined or inherited. */
     f.regs.sp++;
     f.regs.sp[-1] = BooleanValue(true);
     if (prop) {
-        obj2->dropProperty(f.cx, prop);
         if (!obj->deleteProperty(f.cx, id, &f.regs.sp[-1], false))
             THROW();
     }
 }
 
 template<JSBool strict>
 void JS_FASTCALL
 stubs::DelProp(VMFrame &f, JSAtom *atom)
@@ -2756,18 +2736,16 @@ stubs::DefVar(VMFrame &f, JSAtom *atom)
     if (!prop) {
         if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), PropertyStub, PropertyStub,
                                      attrs, 0, 0, &prop)) {
             THROW();
         }
         JS_ASSERT(prop);
         obj2 = obj;
     }
-
-    obj2->dropProperty(cx, prop);
 }
 
 JSBool JS_FASTCALL
 stubs::In(VMFrame &f)
 {
     JSContext *cx = f.cx;
 
     const Value &rref = f.regs.sp[-1];
@@ -2781,18 +2759,14 @@ stubs::In(VMFrame &f)
     if (!FetchElementId(f, obj, f.regs.sp[-2], id, &f.regs.sp[-2]))
         THROWV(JS_FALSE);
 
     JSObject *obj2;
     JSProperty *prop;
     if (!obj->lookupProperty(cx, id, &obj2, &prop))
         THROWV(JS_FALSE);
 
-    JSBool cond = !!prop;
-    if (prop)
-        obj2->dropProperty(cx, prop);
-
-    return cond;
+    return prop != NULL;
 }
 
 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
@@ -2315,17 +2315,16 @@ DumpStats(JSContext *cx, uintN argc, jsv
             DumpScope(cx, cx->globalObject, stdout);
         } else {
             if (!JS_ValueToId(cx, STRING_TO_JSVAL(str), &id))
                 return JS_FALSE;
             JSObject *obj;
             if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
                 return JS_FALSE;
             if (prop) {
-                obj2->dropProperty(cx, prop);
                 if (!obj->getProperty(cx, id, &value))
                     return JS_FALSE;
             }
             if (!prop || !value.isObjectOrNull()) {
                 fprintf(gErrFile, "js: invalid stats argument %s\n",
                         bytes);
                 continue;
             }
@@ -2969,23 +2968,17 @@ split_resolve(JSContext *cx, JSObject *o
                                  JSPROP_SHARED);
     }
 
     cpx = split_get_private(cx, obj);
     if (!cpx)
         return JS_TRUE;
     if (!cpx->isInner && cpx->inner) {
         JSProperty *prop;
-
-        if (!cpx->inner->lookupProperty(cx, id, objp, &prop))
-            return JS_FALSE;
-        if (prop)
-            cpx->inner->dropProperty(cx, prop);
-
-        return JS_TRUE;
+        return cpx->inner->lookupProperty(cx, id, objp, &prop);
     }
 
 #ifdef LAZY_STANDARD_CLASSES
     if (!(flags & JSRESOLVE_ASSIGNING)) {
         JSBool resolved;
 
         if (!ResolveClass(cx, obj, id, &resolved))
             return JS_FALSE;