Backout due to bustage
authorBlake Kaplan <mrbkap@gmail.com>
Thu, 02 Dec 2010 17:13:20 -0800
changeset 58712 102b282b6f4fca5c5521ffc2bba60fa686062c77
parent 58706 017a0aaab2450baaab7401b71dbd33f74e4201f3
child 58713 9ef0b28ced32aba45036dafed4d1aab292588190
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
milestone2.0b8pre
Backout due to bustage
content/base/src/nsNodeUtils.cpp
content/base/test/test_bug601803.html
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
js/src/js.msg
js/src/jsapi-tests/testBug604087.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpccomponents.cpp
js/src/xpconnect/src/xpcpublic.h
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/tests/chrome/Makefile.in
js/src/xpconnect/tests/chrome/test_bug601803.xul
js/src/xpconnect/wrappers/WrapperFactory.cpp
js/src/xpconnect/wrappers/WrapperFactory.h
--- a/content/base/src/nsNodeUtils.cpp
+++ b/content/base/src/nsNodeUtils.cpp
@@ -1,10 +1,9 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=2 sw=2 et tw=99: */
 /* ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
  *
@@ -60,17 +59,16 @@
 #include "nsBindingManager.h"
 #include "nsGenericHTMLElement.h"
 #ifdef MOZ_MEDIA
 #include "nsHTMLMediaElement.h"
 #endif // MOZ_MEDIA
 #include "nsImageLoadingContent.h"
 #include "jsobj.h"
 #include "jsgc.h"
-#include "xpcpublic.h"
 
 using namespace mozilla::dom;
 
 // This macro expects the ownerDocument of content_ to be in scope as
 // |nsIDocument* doc|
 // NOTE: AttributeChildRemoved doesn't use this macro but has a very similar use.
 // If you change how this macro behave please update AttributeChildRemoved.
 #define IMPL_MUTATION_NOTIFICATION(func_, content_, params_)      \
@@ -458,21 +456,16 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
 
   *aResult = nsnull;
 
   // First deal with aNode and walk its attributes (and their children). Then,
   // if aDeep is PR_TRUE, deal with aNode's children (and recurse into their
   // attributes and children).
 
   nsresult rv;
-  if (aCx) {
-      rv = xpc_MorphSlimWrapper(aCx, aNode);
-      NS_ENSURE_SUCCESS(rv, rv);
-  }
-
   nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager;
 
   // aNode.
   nsINodeInfo *nodeInfo = aNode->mNodeInfo;
   nsCOMPtr<nsINodeInfo> newNodeInfo;
   if (nodeInfoManager) {
 
     // Don't allow importing/adopting nodes from non-privileged "scriptable"
@@ -518,16 +511,21 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
       isDeepDocumentClone = PR_TRUE;
       // After cloning the document itself, we want to clone the children into
       // the cloned document (somewhat like cloning and importing them into the
       // cloned document).
       nodeInfoManager = clone->mNodeInfo->NodeInfoManager();
     }
   }
   else if (nodeInfoManager) {
+    // FIXME Bug 601803 Need to support adopting a node cross-compartment
+    if (aCx && aOldScope->compartment() != aNewScope->compartment()) {
+      return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+    }
+
     nsIDocument* oldDoc = aNode->GetOwnerDoc();
     PRBool wasRegistered = PR_FALSE;
     if (oldDoc && aNode->IsElement()) {
       Element* element = aNode->AsElement();
       oldDoc->ClearBoxObjectFor(element);
       wasRegistered = oldDoc->UnregisterFreezableElement(element);
     }
 
@@ -580,38 +578,19 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNod
 
     if (elem) {
       elem->RecompileScriptEventListeners();
     }
 
     if (aCx) {
       nsIXPConnect *xpc = nsContentUtils::XPConnect();
       if (xpc) {
-        nsWrapperCache *cache;
-        CallQueryInterface(aNode, &cache);
-        JSObject *preservedWrapper = nsnull;
-
-        // If reparenting moves us to a new compartment, preserving causes
-        // problems. In that case, we release ourselves and re-preserve after
-        // reparenting so we're sure to have the right JS object preserved.
-        // We use a JSObject stack copy of the wrapper to protect it from GC
-        // under ReparentWrappedNativeIfFound.
-        if (cache && cache->PreservingWrapper()) {
-          preservedWrapper = cache->GetWrapper();
-          nsContentUtils::ReleaseWrapper(aNode, cache);
-        }
-
         nsCOMPtr<nsIXPConnectJSObjectHolder> oldWrapper;
         rv = xpc->ReparentWrappedNativeIfFound(aCx, aOldScope, aNewScope, aNode,
                                                getter_AddRefs(oldWrapper));
-
-        if (preservedWrapper) {
-          nsContentUtils::PreserveWrapper(aNode, cache);
-        }
-
         if (NS_FAILED(rv)) {
           aNode->mNodeInfo.swap(nodeInfo);
 
           return rv;
         }
       }
     }
   }
--- a/content/base/test/test_bug601803.html
+++ b/content/base/test/test_bug601803.html
@@ -17,17 +17,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 601803 **/
 SimpleTest.waitForExplicitFinish();
 
 window.onmessage = function (event) {
-    is(event.data, "false", "Shouldn't throw when adopting a node cross-compartment");
+    todo(event.data == "false", "Shouldn't throw when adopting a node cross-compartment");
     SimpleTest.finish();
 }
 
 document.getElementById("frame").src = "http://example.org/tests/content/base/test/file_bug601803a.html";
 
 
 
 </script>
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -4696,33 +4696,24 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
   // document.body.foopy() needs to ensure that looking up foopy on
   // document.body's prototype will find the right function.
   JSObject *global = ::JS_GetGlobalForObject(cx, proto);
 
   // Only do this if the global object is a window.
   // XXX Is there a better way to check this?
   nsISupports *globalNative = XPConnect()->GetNativeOfWrapper(cx, global);
   nsCOMPtr<nsPIDOMWindow> piwin = do_QueryInterface(globalNative);
-  if (!piwin) {
+  if(!piwin) {
     return NS_OK;
   }
 
   nsGlobalWindow *win = nsGlobalWindow::FromSupports(globalNative);
   if (win->IsClosedOrClosing()) {
     return NS_OK;
   }
-
-  // If the window is in a different compartment than the global object, then
-  // it's likely that global is a sandbox object whose prototype is a window.
-  // Don't do anything in this case.
-  if (win->FastGetGlobalJSObject() &&
-      global->compartment() != win->FastGetGlobalJSObject()->compartment()) {
-    return NS_OK;
-  }
-
   if (win->IsOuterWindow()) {
     // XXXjst: Do security checks here when we remove the security
     // checks on the inner window.
 
     win = win->GetCurrentInnerWindowInternal();
 
     if (!win || !(global = win->GetGlobalJSObject()) ||
         win->IsClosedOrClosing()) {
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2045,17 +2045,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
     } else {
       JSObject *outerObject =
         NS_NewOuterWindowProxy(cx, newInnerWindow->mJSObject);
       if (!outerObject) {
         NS_ERROR("out of memory");
         return NS_ERROR_FAILURE;
       }
 
-      outerObject = JS_TransplantObject(cx, mJSObject, outerObject);
+      outerObject = JS_TransplantWrapper(cx, mJSObject, outerObject);
       if (!outerObject) {
         NS_ERROR("unable to transplant wrappers, probably OOM");
         return NS_ERROR_FAILURE;
       }
 
       mJSObject = outerObject;
       SetWrapper(mJSObject);
 
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -339,9 +339,8 @@ MSG_DEF(JSMSG_CALLER_IS_STRICT,       25
 MSG_DEF(JSMSG_NEED_DEBUG_MODE,        257, 0, JSEXN_ERR, "function can be called only in debug mode")
 MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 258, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
 MSG_DEF(JSMSG_CANT_CHANGE_EXTENSIBILITY, 259, 0, JSEXN_TYPEERR, "can't change object's extensibility")
 MSG_DEF(JSMSG_SC_BAD_SERIALIZED_DATA, 260, 1, JSEXN_INTERNALERR, "bad serialized structured data ({0})")
 MSG_DEF(JSMSG_SC_UNSUPPORTED_TYPE,    261, 0, JSEXN_TYPEERR, "unsupported type for structured data")
 MSG_DEF(JSMSG_SC_RECURSION,           262, 0, JSEXN_INTERNALERR, "recursive object")
 MSG_DEF(JSMSG_CANT_WRAP_XML_OBJECT,   263, 0, JSEXN_TYPEERR, "can't wrap XML objects")
 MSG_DEF(JSMSG_BAD_CLONE_VERSION,      264, 0, JSEXN_ERR, "unsupported structured clone version")
-MSG_DEF(JSMSG_CANT_CLONE_OBJECT,      265, 0, JSEXN_TYPEERR, "can't clone object")
--- a/js/src/jsapi-tests/testBug604087.cpp
+++ b/js/src/jsapi-tests/testBug604087.cpp
@@ -1,12 +1,12 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * vim: set ts=8 sw=4 et tw=99:
  *
- * Tests JS_TransplantObject
+ * Tests JS_TransplantWrappers
  */
 
 #include "tests.h"
 #include "jswrapper.h"
 
 struct OuterWrapper : JSWrapper
 {
     OuterWrapper() : JSWrapper(0) {}
@@ -73,12 +73,12 @@ BEGIN_TEST(testBug604087)
         JSAutoEnterCompartment ac;
         CHECK(ac.enter(cx, compartment2));
         next = JSWrapper::New(cx, compartment2, compartment2->getProto(), compartment2,
                               &OuterWrapper::singleton);
         CHECK(next);
     }
 
     JS_SetWrapObjectCallbacks(JS_GetRuntime(cx), Wrap, PreWrap);
-    CHECK(JS_TransplantObject(cx, outerObj, next));
+    CHECK(JS_TransplantWrapper(cx, outerObj, next));
     return true;
 }
 END_TEST(testBug604087)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1212,39 +1212,41 @@ JS_WrapObject(JSContext *cx, JSObject **
 JS_PUBLIC_API(JSBool)
 JS_WrapValue(JSContext *cx, jsval *vp)
 {
     CHECK_REQUEST(cx);
     return cx->compartment->wrap(cx, Valueify(vp));
 }
 
 JS_PUBLIC_API(JSObject *)
-JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target)
-{
-     // This function is called when an object moves between two different
-     // compartments. In that case, we need to "move" the window from origobj's
-     // compartment to target's compartment.
+JS_TransplantWrapper(JSContext *cx, JSObject *wrapper, JSObject *target)
+{
+    JS_ASSERT(wrapper->isWrapper());
+
+    /*
+     * This function is called when a window is navigating. In that case, we
+     * need to "move" the window from wrapper's compartment to target's
+     * compartment.
+     */
     JSCompartment *destination = target->getCompartment();
-    if (origobj->getCompartment() == destination) {
-        // If the original object is in the same compartment as the
-        // destination, then we know that we won't find wrapper in the
-        // destination's cross compartment map and that the same object
-        // will continue to work.
-        if (!origobj->swap(cx, target))
+    if (wrapper->getCompartment() == destination) {
+        // If the wrapper is in the same compartment as the destination, then
+        // we know that we won't find wrapper in the destination's cross
+        // compartment map and that the same object will continue to work.
+        if (!wrapper->swap(cx, target))
             return NULL;
-        return origobj;
+        return wrapper;
     }
 
     JSObject *obj;
     WrapperMap &map = destination->crossCompartmentWrappers;
-    Value origv = ObjectValue(*origobj);
-
-    // There might already be a wrapper for the original object in the new
-    // compartment.
-    if (WrapperMap::Ptr p = map.lookup(origv)) {
+    Value wrapperv = ObjectValue(*wrapper);
+
+    // There might already be a wrapper for the window in the new compartment.
+    if (WrapperMap::Ptr p = map.lookup(wrapperv)) {
         // If there is, make it the primary outer window proxy around the
         // inner (accomplished by swapping target's innards with the old,
         // possibly security wrapper, innards).
         obj = &p->value.toObject();
         map.remove(p);
         if (!obj->swap(cx, target))
             return NULL;
     } else {
@@ -1259,28 +1261,28 @@ JS_TransplantObject(JSContext *cx, JSObj
     // based on whether the new compartment is same origin with them.
     Value targetv = ObjectValue(*obj);
     WrapperVector &vector = cx->runtime->compartments;
     AutoValueVector toTransplant(cx);
     toTransplant.reserve(vector.length());
 
     for (JSCompartment **p = vector.begin(), **end = vector.end(); p != end; ++p) {
         WrapperMap &pmap = (*p)->crossCompartmentWrappers;
-        if (WrapperMap::Ptr wp = pmap.lookup(origv)) {
+        if (WrapperMap::Ptr wp = pmap.lookup(wrapperv)) {
             // We found a wrapper. Remember and root it.
             toTransplant.append(wp->value);
         }
     }
 
     for (Value *begin = toTransplant.begin(), *end = toTransplant.end(); begin != end; ++begin) {
         JSObject *wobj = &begin->toObject();
         JSCompartment *wcompartment = wobj->compartment();
         WrapperMap &pmap = wcompartment->crossCompartmentWrappers;
-        JS_ASSERT(pmap.lookup(origv));
-        pmap.remove(origv);
+        JS_ASSERT(pmap.lookup(wrapperv));
+        pmap.remove(wrapperv);
 
         // First, we wrap it in the new compartment. This will return a
         // new wrapper.
         AutoCompartment ac(cx, wobj);
         JSObject *tobj = obj;
         if (!ac.enter() || !wcompartment->wrap(cx, &tobj))
             return NULL;
 
@@ -1289,25 +1291,25 @@ JS_TransplantObject(JSContext *cx, JSObj
         // entry in the compartment's wrapper map to point to the old
         // wrapper.
         JS_ASSERT(tobj != wobj);
         if (!wobj->swap(cx, tobj))
             return NULL;
         pmap.put(targetv, ObjectValue(*wobj));
     }
 
-    // Lastly, update the original object to point to the new one.
+    // Lastly, update the old outer window proxy to point to the new one.
     {
-        AutoCompartment ac(cx, origobj);
+        AutoCompartment ac(cx, wrapper);
         JSObject *tobj = obj;
         if (!ac.enter() || !JS_WrapObject(cx, &tobj))
             return NULL;
-        if (!origobj->swap(cx, tobj))
+        if (!wrapper->swap(cx, tobj))
             return NULL;
-        origobj->getCompartment()->crossCompartmentWrappers.put(targetv, origv);
+        wrapper->getCompartment()->crossCompartmentWrappers.put(targetv, wrapperv);
     }
 
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_GetGlobalObject(JSContext *cx)
 {
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -960,17 +960,17 @@ JS_GetCompartmentPrivate(JSContext *cx, 
 
 extern JS_PUBLIC_API(JSBool)
 JS_WrapObject(JSContext *cx, JSObject **objp);
 
 extern JS_PUBLIC_API(JSBool)
 JS_WrapValue(JSContext *cx, jsval *vp);
 
 extern JS_PUBLIC_API(JSObject *)
-JS_TransplantObject(JSContext *cx, JSObject *origobj, JSObject *target);
+JS_TransplantWrapper(JSContext *cx, JSObject *wrapper, JSObject *target);
 
 #ifdef __cplusplus
 JS_END_EXTERN_C
 
 class JS_PUBLIC_API(JSAutoEnterCompartment)
 {
     JSCrossCompartmentCall *call;
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -72,17 +72,16 @@
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstaticcheck.h"
 #include "jsstdint.h"
 #include "jsstr.h"
 #include "jstracer.h"
 #include "jsdbgapi.h"
 #include "json.h"
-#include "jswrapper.h"
 
 #include "jsinterpinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsobjinlines.h"
 
 #if JS_HAS_GENERATORS
 #include "jsiter.h"
@@ -3292,214 +3291,64 @@ JSObject::defineBlockVariable(JSContext 
 static size_t
 GetObjectSize(JSObject *obj)
 {
     return (obj->isFunction() && !obj->getPrivate())
            ? sizeof(JSFunction)
            : sizeof(JSObject) + sizeof(js::Value) * obj->numFixedSlots();
 }
 
-bool
-JSObject::copyPropertiesFrom(JSContext *cx, JSObject *obj)
-{
-    // If we're not native, then we cannot copy properties.
-    JS_ASSERT(isNative() == obj->isNative());
-    if (!isNative())
-        return true;
-
-    Vector<const Shape *> shapes(cx);
-    for (Shape::Range r(obj->lastProperty()); !r.empty(); r.popFront()) {
-        if (!shapes.append(&r.front()))
-            return false;
-    }
-
-    size_t n = shapes.length();
-    while (n > 0) {
-        const Shape *shape = shapes[--n];
-        uintN attrs = shape->attributes();
-        PropertyOp getter = shape->getter();
-        if ((attrs & JSPROP_GETTER) && !cx->compartment->wrap(cx, &getter))
-            return false;
-        PropertyOp setter = shape->setter();
-        if ((attrs & JSPROP_SETTER) && !cx->compartment->wrap(cx, &setter))
-            return false;
-        Value v = shape->hasSlot() ? obj->getSlot(shape->slot) : UndefinedValue();
-        if (!cx->compartment->wrap(cx, &v))
-            return false;
-        if (!defineProperty(cx, shape->id, v, getter, setter, attrs))
-            return false;
-    }
-    return true;
-}
-
-static bool
-CopySlots(JSContext *cx, JSObject *from, JSObject *to)
-{
-    JS_ASSERT(!from->isNative() && !to->isNative());
-    size_t nslots = from->numSlots();
-    if (to->ensureSlots(cx, nslots))
-        return false;
-
-    size_t n = 0;
-    if (to->isWrapper() &&
-        (JSWrapper::wrapperHandler(to)->flags() & JSWrapper::CROSS_COMPARTMENT)) {
-        to->slots[0] = from->slots[0];
-        to->slots[1] = from->slots[1];
-        n = 2;
-    }
-
-    for (; n < nslots; ++n) {
-        Value v = from->slots[n];
-        if (!cx->compartment->wrap(cx, &v))
-            return false;
-        to->slots[n] = v;
-    }
-    return true;
-}
-
-JSObject *
-JSObject::clone(JSContext *cx, JSObject *proto, JSObject *parent)
-{
-    /*
-     * We can only clone native objects and proxies. Dense arrays are slowified if
-     * we try to clone them.
-     */
-    if (!isNative()) {
-        if (isDenseArray()) {
-            if (!makeDenseArraySlow(cx))
-                return NULL;
-        } else if (!isProxy()) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_CANT_CLONE_OBJECT);
-            return NULL;
-        }
-    }
-    JSObject *clone = NewObject<WithProto::Given>(cx, getClass(),
-                                                  proto, parent,
-                                                  gc::FinalizeKind(finalizeKind()));
-    if (!clone)
-        return NULL;
-    if (isNative()) {
-        if (clone->isFunction() && (compartment() != clone->compartment())) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
-                                 JSMSG_CANT_CLONE_OBJECT);
-            return NULL;
-        }
-
-        if (getClass()->flags & JSCLASS_HAS_PRIVATE)
-            clone->setPrivate(getPrivate());
-    } else {
-        JS_ASSERT(isProxy());
-        if (!CopySlots(cx, this, clone))
-            return NULL;
-    }
-    return clone;
-}
-
-static void
-TradeGuts(JSObject *a, JSObject *b)
-{
-    JS_ASSERT(a->compartment() == b->compartment());
-    JS_ASSERT(a->isFunction() == b->isFunction());
-
-    bool aInline = !a->hasSlotsArray();
-    bool bInline = !b->hasSlotsArray();
-
-    /* Trade the guts of the objects. */
-    const size_t size = GetObjectSize(a);
-    if (size == GetObjectSize(b)) {
-        /*
-         * If the objects are the same size, then we make no assumptions about
-         * whether they have dynamically allocated slots and instead just copy
-         * them over wholesale.
-         */
-        char tmp[tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::result];
-        JS_ASSERT(size <= sizeof(tmp));
-
-        memcpy(tmp, a, size);
-        memcpy(a, b, size);
-        memcpy(b, tmp, size);
-
-        /* Fixup pointers for inline slots on the objects. */
-        if (aInline)
-            b->slots = b->fixedSlots();
-        if (bInline)
-            a->slots = a->fixedSlots();
-    } else {
-        /*
-         * If the objects are of differing sizes, then we only copy over the
-         * JSObject portion (things like class, etc.) and leave it to
-         * JSObject::clone to copy over the dynamic slots for us.
-         */
-        if (a->isFunction()) {
-            JSFunction tmp;
-            memcpy(&tmp, a, sizeof tmp);
-            memcpy(a, b, sizeof tmp);
-            memcpy(b, &tmp, sizeof tmp);
-        } else {
-            JSObject tmp;
-            memcpy(&tmp, a, sizeof tmp);
-            memcpy(a, b, sizeof tmp);
-            memcpy(b, &tmp, sizeof tmp);
-        }
-
-        JS_ASSERT(!aInline);
-        JS_ASSERT(!bInline);
-    }
-}
-
 /*
  * Use this method with extreme caution. It trades the guts of two objects and updates
  * scope ownership. This operation is not thread-safe, just as fast array to slow array
  * transitions are inherently not thread-safe. Don't perform a swap operation on objects
  * shared across threads or, or bad things will happen. You have been warned.
  */
 bool
 JSObject::swap(JSContext *cx, JSObject *other)
 {
-    /*
-     * If we are swapping objects with a different number of builtin slots, force
-     * both to not use their inline slots.
-     */
-    if (GetObjectSize(this) != GetObjectSize(other)) {
+    size_t size = GetObjectSize(this);
+
+    if (size != GetObjectSize(other)) {
+        /*
+         * Objects with different numbers of fixed slots can be swapped only if they
+         * are both shapeless non-natives, to preserve the invariant that objects with the
+         * same shape have the same number of fixed slots.  Use a dynamic array for both.
+         */
+        JS_ASSERT(!isNative());
+        JS_ASSERT(!other->isNative());
+        size = sizeof(JSObject);
         if (!hasSlotsArray()) {
             if (!allocSlots(cx, numSlots()))
                 return false;
         }
         if (!other->hasSlotsArray()) {
             if (!other->allocSlots(cx, other->numSlots()))
                 return false;
         }
     }
 
-    if (this->compartment() == other->compartment()) {
-        TradeGuts(this, other);
-        return true;
-    }
-
-    JSObject *thisClone;
-    JSObject *otherClone;
-    {
-        AutoCompartment ac(cx, other);
-        if (!ac.enter())
-            return false;
-        thisClone = this->clone(cx, other->getProto(), other->getParent());
-        if (!thisClone || !thisClone->copyPropertiesFrom(cx, this))
-            return false;
-    }
-    {
-        AutoCompartment ac(cx, this);
-        if (!ac.enter())
-            return false;
-        otherClone = other->clone(cx, other->getProto(), other->getParent());
-        if (!otherClone || !otherClone->copyPropertiesFrom(cx, other))
-            return false;
-    }
-    TradeGuts(this, otherClone);
-    TradeGuts(other, thisClone);
+    bool thisInline = !hasSlotsArray();
+    bool otherInline = !other->hasSlotsArray();
+
+    JS_STATIC_ASSERT(FINALIZE_OBJECT_LAST == FINALIZE_OBJECT16);
+
+    char tmp[tl::Max<sizeof(JSFunction), sizeof(JSObject_Slots16)>::result];
+    JS_ASSERT(size <= sizeof(tmp));
+
+    /* Trade the guts of the objects. */
+    memcpy(tmp, this, size);
+    memcpy(this, other, size);
+    memcpy(other, tmp, size);
+
+    /* Fixup pointers for inline slots on the objects. */
+    if (thisInline)
+        other->slots = other->fixedSlots();
+    if (otherInline)
+        this->slots = this->fixedSlots();
 
     return true;
 }
 
 #if JS_HAS_XDR
 
 #define NO_PARENT_INDEX ((uint32)-1)
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -547,18 +547,16 @@ struct JSObject : js::gc::Cell {
      * a doubly-linked list.
      */
     inline bool inDictionaryMode() const;
 
     inline uint32 propertyCount() const;
 
     inline bool hasPropertyTable() const;
 
-    /* gc::FinalizeKind */ unsigned finalizeKind() const;
-
     uint32 numSlots() const { return capacity; }
 
     size_t slotsAndStructSize(uint32 nslots) const;
     size_t slotsAndStructSize() const { return slotsAndStructSize(numSlots()); }
 
     inline js::Value* fixedSlots() const;
     inline size_t numFixedSlots() const;
 
@@ -1143,19 +1141,17 @@ struct JSObject : js::gc::Cell {
     }
 
     static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp);
 
     inline JSCompartment *getCompartment() const;
 
     inline JSObject *getThrowTypeError() const;
 
-    JSObject *clone(JSContext *cx, JSObject *proto, JSObject *parent);
-    bool copyPropertiesFrom(JSContext *cx, JSObject *obj);
-    bool swap(JSContext *cx, JSObject *other);
+    bool swap(JSContext *cx, JSObject *obj);
 
     const js::Shape *defineBlockVariable(JSContext *cx, jsid id, intN index);
 
     inline bool canHaveMethodBarrier() const;
 
     inline bool isArguments() const;
     inline bool isNormalArguments() const;
     inline bool isStrictArguments() const;
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -247,30 +247,30 @@ JSObject::getPrimitiveThis() const
 
 inline void
 JSObject::setPrimitiveThis(const js::Value &pthis)
 {
     JS_ASSERT(isPrimitive());
     setSlot(JSSLOT_PRIMITIVE_THIS, pthis);
 }
 
-inline /* gc::FinalizeKind */ unsigned
-JSObject::finalizeKind() const
+inline js::gc::FinalizeKind
+GetObjectFinalizeKind(const JSObject *obj)
 {
-    return js::gc::FinalizeKind(arena()->header()->thingKind);
+    return js::gc::FinalizeKind(obj->arena()->header()->thingKind);
 }
 
 inline size_t
 JSObject::numFixedSlots() const
 {
     if (isFunction())
         return JSObject::FUN_CLASS_RESERVED_SLOTS;
     if (!hasSlotsArray())
         return capacity;
-    return js::gc::GetGCKindSlots(js::gc::FinalizeKind(finalizeKind()));
+    return js::gc::GetGCKindSlots(GetObjectFinalizeKind(this));
 }
 
 inline size_t
 JSObject::slotsAndStructSize(uint32 nslots) const
 {
     bool isFun = isFunction() && this == (JSObject*) getPrivate();
 
     int ndslots = hasSlotsArray() ? nslots : 0;
@@ -1058,17 +1058,17 @@ NewObjectGCKind(JSContext *cx, js::Class
 
 /* Make an object with pregenerated shape from a NEWOBJECT bytecode. */
 static inline JSObject *
 CopyInitializerObject(JSContext *cx, JSObject *baseobj)
 {
     JS_ASSERT(baseobj->getClass() == &js_ObjectClass);
     JS_ASSERT(!baseobj->inDictionaryMode());
 
-    gc::FinalizeKind kind = gc::FinalizeKind(baseobj->finalizeKind());
+    gc::FinalizeKind kind = GetObjectFinalizeKind(baseobj);
     JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
 
     if (!obj || !obj->ensureSlots(cx, baseobj->numSlots()))
         return NULL;
 
     obj->flags = baseobj->flags;
     obj->lastProp = baseobj->lastProp;
     obj->objShape = baseobj->objShape;
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -378,18 +378,17 @@ AutoCompartment::leave()
         JS_ASSERT_IF(wasSane && context->hasfp(), context->compartment == origin);
         context->compartment->wrapException(context);
     }
     entered = false;
 }
 
 /* Cross compartment wrappers. */
 
-JSCrossCompartmentWrapper::JSCrossCompartmentWrapper(uintN flags)
-  : JSWrapper(CROSS_COMPARTMENT | flags)
+JSCrossCompartmentWrapper::JSCrossCompartmentWrapper(uintN flags) : JSWrapper(flags)
 {
 }
 
 JSCrossCompartmentWrapper::~JSCrossCompartmentWrapper()
 {
 }
 
 bool
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -98,24 +98,16 @@ class JS_FRIEND_API(JSWrapper) : public 
     static JSWrapper singleton;
 
     static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent,
                          JSWrapper *handler);
 
     static inline JSObject *wrappedObject(const JSObject *wrapper) {
         return wrapper->getProxyPrivate().toObjectOrNull();
     }
-    static inline JSWrapper *wrapperHandler(const JSObject *wrapper) {
-        return static_cast<JSWrapper *>(wrapper->getProxyHandler());
-    }
-
-    enum {
-        CROSS_COMPARTMENT = 1 << 0,
-        LAST_USED_FLAG = CROSS_COMPARTMENT
-    };
 
     static void *getWrapperFamily();
 };
 
 /* Base class for all cross compartment wrapper handlers. */
 class JS_FRIEND_API(JSCrossCompartmentWrapper) : public JSWrapper {
   public:
     JSCrossCompartmentWrapper(uintN flags);
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -1177,30 +1177,16 @@ nsXPConnect::InitClassesWithNewWrappedGl
         }
     }
 
     NS_ADDREF(*_retval = holder);
 
     return NS_OK;
 }
 
-nsresult
-xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph)
-{
-    nsWrapperCache *cache;
-    CallQueryInterface(tomorph, &cache);
-    if(!cache)
-        return NS_OK;
-
-    JSObject *obj = cache->GetWrapper();
-    if(!obj || !IS_SLIM_WRAPPER(obj))
-        return NS_OK;
-    return MorphSlimWrapper(cx, obj);
-}
-
 static nsresult
 NativeInterface2JSObject(XPCLazyCallContext & lccx,
                          JSObject * aScope,
                          nsISupports *aCOMObj,
                          nsWrapperCache *aCache,
                          const nsIID * aIID,
                          PRBool aAllowWrapping,
                          jsval *aVal,
@@ -1492,24 +1478,20 @@ nsXPConnect::ReparentWrappedNativeIfFoun
         ReparentWrapperIfFound(ccx, scope, scope2, aNewParent, aCOMObj,
                                (XPCWrappedNative**) _retval);
 }
 
 static JSDHashOperator
 MoveableWrapperFinder(JSDHashTable *table, JSDHashEntryHdr *hdr,
                       uint32 number, void *arg)
 {
+    // Every element counts.
     nsTArray<nsRefPtr<XPCWrappedNative> > *array =
         static_cast<nsTArray<nsRefPtr<XPCWrappedNative> > *>(arg);
-    XPCWrappedNative *wn = ((Native2WrappedNativeMap::Entry*)hdr)->value;
-
-    // If a wrapper is expired, then there are no references to it from JS, so
-    // we don't have to move it.
-    if(!wn->IsWrapperExpired())
-        array->AppendElement(wn);
+    array->AppendElement(((Native2WrappedNativeMap::Entry*)hdr)->value);
     return JS_DHASH_NEXT;
 }
 
 /* void moveWrappers(in JSContextPtr aJSContext, in JSObjectPtr  aOldScope, in JSObjectPtr  aNewScope); */
 NS_IMETHODIMP
 nsXPConnect::MoveWrappers(JSContext *aJSContext,
                           JSObject *aOldScope,
                           JSObject *aNewScope)
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -3232,19 +3232,20 @@ xpc_CreateSandboxObject(JSContext * cx, 
             return NS_ERROR_XPC_UNEXPECTED;
 
         if (proto) {
             bool ok = JS_WrapObject(cx, &proto);
             if (!ok)
                 return NS_ERROR_XPC_UNEXPECTED;
 
             if (xpc::WrapperFactory::IsXrayWrapper(proto) && !wantXrays) {
-                jsval v = OBJECT_TO_JSVAL(proto);
-                if (!xpc::WrapperFactory::WaiveXrayAndWrap(cx, &v))
-                    return NS_ERROR_FAILURE;
+                jsval v;
+                if (!JS_GetProperty(cx, proto, "wrappedJSObject", &v))
+                    return NS_ERROR_XPC_UNEXPECTED;
+
                 proto = JSVAL_TO_OBJECT(v);
             }
 
             ok = JS_SetPrototype(cx, sandbox, proto);
             if (!ok)
                 return NS_ERROR_XPC_UNEXPECTED;
         }
 
--- a/js/src/xpconnect/src/xpcpublic.h
+++ b/js/src/xpconnect/src/xpcpublic.h
@@ -36,17 +36,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef xpcpublic_h
 #define xpcpublic_h
 
 #include "jsapi.h"
-#include "nsISupports.h"
 #include "jsobj.h"
 #include "nsAString.h"
 #include "nsIPrincipal.h"
 #include "nsWrapperCache.h"
 
 class nsIPrincipal;
 
 nsresult
@@ -55,19 +54,16 @@ xpc_CreateGlobalObject(JSContext *cx, JS
                        bool wantXrays, JSObject **global,
                        JSCompartment **compartment);
 
 nsresult
 xpc_CreateMTGlobalObject(JSContext *cx, JSClass *clasp,
                          nsISupports *ptr, JSObject **global,
                          JSCompartment **compartment);
 
-nsresult
-xpc_MorphSlimWrapper(JSContext *cx, nsISupports *tomorph);
-
 extern JSBool
 XPC_WN_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp);
 
 #define IS_WRAPPER_CLASS(clazz)                                               \
     (clazz->ext.equality == js::Valueify(XPC_WN_Equality))
 
 inline JSBool
 DebugCheckWrapperClass(JSObject* obj)
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -514,18 +514,18 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
             return NS_ERROR_FAILURE;
 
         nsISupports *Object = helper.Object();
         if(nsXPCWrappedJSClass::IsWrappedJS(Object))
         {
             nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
             JSObject *obj;
             wrappedjs->GetJSObject(&obj);
-            if(xpc::AccessCheck::isChrome(obj->compartment()) &&
-               !xpc::AccessCheck::isChrome(Scope->GetGlobalJSObject()->compartment()))
+            if(xpc::AccessCheck::isChrome(obj->getCompartment()) &&
+               !xpc::AccessCheck::isChrome(Scope->GetGlobalJSObject()->getCompartment()))
             {
                 needsCOW = JS_TRUE;
             }
         }
     }
 
     AutoMarkingWrappedNativeProtoPtr proto(ccx);
 
@@ -1503,41 +1503,27 @@ XPCWrappedNative::ReparentWrapperIfFound
     }
 
     if(!flat)
     {
         *aWrapper = nsnull;
         return NS_OK;
     }
 
-    bool crosscompartment = aOldScope->GetGlobalJSObject()->compartment() !=
-                            aNewScope->GetGlobalJSObject()->compartment();
-#ifdef DEBUG
-    if(crosscompartment)
-    {
-        NS_ASSERTION(aNewParent, "won't be able to find the new parent");
-        NS_ASSERTION(wrapper, "can't transplant slim wrappers");
-    }
-#endif
-
     // ReparentWrapperIfFound is really only meant to be called from DOM code
     // which must happen only on the main thread. Bail if we're on some other
     // thread or have a non-main-thread-only wrapper.
     if (!XPCPerThreadData::IsMainThread(ccx) ||
         (wrapper &&
          wrapper->GetProto() &&
          !wrapper->GetProto()->ClassIsMainThreadOnly()))
     {
         return NS_ERROR_FAILURE;
     }
 
-    JSAutoEnterCompartment ac;
-    if(!ac.enter(ccx, aNewScope->GetGlobalJSObject()))
-        return NS_ERROR_FAILURE;
-
     if(aOldScope != aNewScope)
     {
         // Oh, so now we need to move the wrapper to a different scope.
         AutoMarkingWrappedNativeProtoPtr oldProto(ccx);
         AutoMarkingWrappedNativeProtoPtr newProto(ccx);
 
         if(!wrapper)
             oldProto = GetSlimWrapperProto(flat);
@@ -1599,56 +1585,30 @@ XPCWrappedNative::ReparentWrapperIfFound
                              "wrapper already in new scope!");
 
                 (void) newMap->Add(wrapper);
             }
 
             // We only try to fixup the __proto__ JSObject if the wrapper
             // is directly using that of its XPCWrappedNativeProto.
 
-            if(crosscompartment)
+            if(wrapper->HasProto() &&
+               flat->getProto() == oldProto->GetJSProtoObject())
             {
-                JSObject *newobj = flat->clone(ccx, newProto->GetJSProtoObject(),
-                                               aNewParent);
-                if(!newobj)
+                if(!JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject()))
+                {
+                    // this is bad, very bad
+                    NS_ERROR("JS_SetPrototype failed");
                     return NS_ERROR_FAILURE;
-
-                JS_SetPrivate(ccx, flat, nsnull);
-
-                JSObject *propertyHolder =
-                    JS_NewObjectWithGivenProto(ccx, NULL, NULL, aNewParent);
-                if(!propertyHolder || !propertyHolder->copyPropertiesFrom(ccx, flat))
-                    return NS_ERROR_OUT_OF_MEMORY;
-
-                flat = JS_TransplantObject(ccx, flat, newobj);
-                if(!flat)
-                    return NS_ERROR_FAILURE;
-                wrapper->mFlatJSObject = flat;
-                if(cache)
-                    cache->SetWrapper(flat);
-                if (!flat->copyPropertiesFrom(ccx, propertyHolder))
-                    return NS_ERROR_FAILURE;
+                }
             }
             else
             {
-                if(wrapper->HasProto() &&
-                   flat->getProto() == oldProto->GetJSProtoObject())
-                {
-                    if(!JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject()))
-                    {
-                        // this is bad, very bad
-                        NS_ERROR("JS_SetPrototype failed");
-                        return NS_ERROR_FAILURE;
-                    }
-                }
-                else
-                {
-                    NS_WARNING("Moving XPConnect wrappedNative to new scope, "
-                               "but can't fixup __proto__");
-                }
+                NS_WARNING("Moving XPConnect wrappedNative to new scope, "
+                           "but can't fixup __proto__");
             }
         }
         else
         {
             if(!JS_SetReservedSlot(ccx, flat, 0,
                                    PRIVATE_TO_JSVAL(newProto.get())) ||
                !JS_SetPrototype(ccx, flat, newProto->GetJSProtoObject()))
             {
--- a/js/src/xpconnect/tests/chrome/Makefile.in
+++ b/js/src/xpconnect/tests/chrome/Makefile.in
@@ -52,17 +52,16 @@ include $(topsrcdir)/config/rules.mk
 		test_doublewrappedcompartments.xul \
 		test_evalInSandbox.xul \
 		test_sandboxImport.xul \
 		test_wrappers.xul \
 		test_bug484459.xul \
 		test_cows.xul \
 		test_bug517163.xul \
 		test_bug571849.xul \
-		test_bug601803.xul \
 		$(NULL)
 
 # Disabled until this test gets updated to test the new proxy based
 # wrappers.
 #		test_wrappers-2.xul \
 
 libs:: $(_CHROME_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
deleted file mode 100644
--- a/js/src/xpconnect/tests/chrome/test_bug601803.xul
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
-<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
-                 type="text/css"?>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=500931
--->
-<window title="Mozilla Bug 601803"
-  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-  <script type="application/javascript"
-          src="chrome://mochikit/content/MochiKit/packed.js"></script>
-  <script type="application/javascript"
-          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-
-  <!-- test results are displayed in the html:body -->
-  <body xmlns="http://www.w3.org/1999/xhtml">
-  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=601803"
-     target="_blank">Mozilla Bug 601803</a>
-
-  <!-- test code goes here -->
-  <script type="application/javascript"><![CDATA[
-
-  /** Test for Bug 601803 **/
-
-  function go() {
-    var ifr = document.getElementById('ifr');
-    var elem = document.createElementNS("http://www.w3.org/1999/xhtml","html:div");
-    elem.appendChild(document.createTextNode("hello, world"));
-    elem.expando = 42;
-    ifr.contentDocument.body.appendChild(elem);
-    is(elem.wrappedJSObject.expando, 42, "expando is preserved");
-    SimpleTest.finish();
-  }
-
-  SimpleTest.waitForExplicitFinish();
-
-  ]]></script>
-  <iframe type="content" src="about:blank" onload="go()" id="ifr" />
-  </body>
-</window>
--- a/js/src/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/src/xpconnect/wrappers/WrapperFactory.cpp
@@ -204,17 +204,17 @@ WrapperFactory::Rewrap(JSContext *cx, JS
             if (!obj->getGlobal()->isSystem() &&
                 (IS_WN_WRAPPER(obj) || obj->getClass()->ext.innerObject)) {
                 typedef XrayWrapper<JSCrossCompartmentWrapper, CrossCompartmentXray> Xray;
                 wrapper = &Xray::singleton;
                 xrayHolder = Xray::createHolder(cx, obj, parent);
                 if (!xrayHolder)
                     return nsnull;
             } else {
-                wrapper = &CrossOriginWrapper::singleton;
+                wrapper = &JSCrossCompartmentWrapper::singleton;
             }
         }
     } else if (AccessCheck::isChrome(origin)) {
         wrapper = &FilteringWrapper<JSCrossCompartmentWrapper,
                                     ExposedPropertiesOnly>::singleton;
     } else if (AccessCheck::isSameOrigin(origin, target)) {
         // Same origin we use a transparent wrapper, unless the compartment asks
         // for an Xray or the wrapper needs a SOW.
--- a/js/src/xpconnect/wrappers/WrapperFactory.h
+++ b/js/src/xpconnect/wrappers/WrapperFactory.h
@@ -39,21 +39,21 @@
 
 #include "jsapi.h"
 #include "jswrapper.h"
 
 namespace xpc {
 
 class WrapperFactory {
   public:
-    enum { WAIVE_XRAY_WRAPPER_FLAG = JSWrapper::LAST_USED_FLAG << 1,
-           IS_XRAY_WRAPPER_FLAG    = WAIVE_XRAY_WRAPPER_FLAG << 1,
-           SCRIPT_ACCESS_ONLY_FLAG = IS_XRAY_WRAPPER_FLAG << 1,
-           PARTIALLY_TRANSPARENT   = SCRIPT_ACCESS_ONLY_FLAG << 1,
-           SOW_FLAG                = PARTIALLY_TRANSPARENT << 1 };
+    enum { WAIVE_XRAY_WRAPPER_FLAG = (1<<0),
+           IS_XRAY_WRAPPER_FLAG = (1<<1),
+           SCRIPT_ACCESS_ONLY_FLAG = (1<<2),
+           PARTIALLY_TRANSPARENT = (1<<3),
+           SOW_FLAG = (1<<4) };
 
     // Return true if any of any of the nested wrappers have the flag set.
     static bool HasWrapperFlag(JSObject *wrapper, uintN flag) {
         uintN flags = 0;
         wrapper->unwrap(&flags);
         return !!(flags & flag);
     }