JSBool
WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj,
                     XPCWrappedNativeScope *newScope)
{
  typedef WrappedNative2WrapperMap::Link Link;
  XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
  WrappedNative2WrapperMap *map = innerObj->GetScope()->GetWrapperMap();
  Link *link;

  { // Scoped lock
    XPCAutoLock al(rt->GetMapLock());
    link = map->FindLink(innerObj->GetFlatJSObject());
  }

  if (!link) {
    // No link here means that there were no XOWs for this object.
    return JS_TRUE;
  }

  JSObject *xow = link->obj;

  { // Scoped lock.
    XPCAutoLock al(rt->GetMapLock());
    if (!newScope->GetWrapperMap()->AddLink(innerObj->GetFlatJSObject(), link))
      return JS_FALSE;
    map->Remove(innerObj->GetFlatJSObject());
  }

  if (!xow) {
    // Nothing else to do.
    return JS_TRUE;
  }

  return JS_SetReservedSlot(cx, xow, XPC_XOW_ScopeSlot,
                            PRIVATE_TO_JSVAL(newScope)) &&
         JS_SetParent(cx, xow, newScope->GetGlobalJSObject());
}
JSBool
WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn)
{
  NS_ASSERTION(XPCPerThreadData::IsMainThread(cx),
               "Can't do this off the main thread!");

  // Our argument should be a wrapped native object, but the caller may have
  // passed it in as an optimization.
  JSObject *wrappedObj;
  if (JSVAL_IS_PRIMITIVE(*vp) ||
      !(wrappedObj = JSVAL_TO_OBJECT(*vp)) ||
      wrappedObj->getClass() == &XOWClass) {
    return JS_TRUE;
  }

  if (!wn &&
      !(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, wrappedObj))) {
    return JS_TRUE;
  }

  CheckWindow(wn);

  // The parent must be the inner global object for its scope.
  parent = JS_GetGlobalForObject(cx, parent);
  OBJ_TO_INNER_OBJECT(cx, parent);
  if (!parent) {
    return JS_FALSE;
  }

  XPCWrappedNativeWithXOW *wnxow = nsnull;
  if (wn->NeedsXOW()) {
    JSObject *innerWrappedObj = wrappedObj;
    OBJ_TO_INNER_OBJECT(cx, innerWrappedObj);
    if (!innerWrappedObj) {
      return JS_FALSE;
    }

    if (innerWrappedObj == parent) {
      wnxow = static_cast<XPCWrappedNativeWithXOW *>(wn);
      JSObject *xow = wnxow->GetXOW();
      if (xow) {
        *vp = OBJECT_TO_JSVAL(xow);
        return JS_TRUE;
      }
    }
  }

  XPCWrappedNative *parentwn =
    XPCWrappedNative::GetWrappedNativeOfJSObject(cx, parent);
  XPCWrappedNativeScope *parentScope;
  if (NS_LIKELY(parentwn)) {
    parentScope = parentwn->GetScope();
  } else {
    parentScope = XPCWrappedNativeScope::FindInJSObjectScope(cx, parent);
  }

  JSObject *outerObj = nsnull;
  WrappedNative2WrapperMap *map = parentScope->GetWrapperMap();

  outerObj = map->Find(wrappedObj);
  if (outerObj) {
    NS_ASSERTION(outerObj->getClass() == &XOWClass,
                 "What crazy object are we getting here?");
    *vp = OBJECT_TO_JSVAL(outerObj);

    if (wnxow) {
      // NB: wnxow->GetXOW() must have returned false.
      SetFlags(cx, outerObj, AddFlags(GetFlags(cx, outerObj), FLAG_IS_CACHED));
      wnxow->SetXOW(outerObj);
    }

    return JS_TRUE;
  }

  outerObj = JS_NewObjectWithGivenProto(cx, js::Jsvalify(&XOWClass), nsnull,
                                        parent);
  if (!outerObj) {
    return JS_FALSE;
  }

  jsval flags = INT_TO_JSVAL(wnxow ? FLAG_IS_CACHED : 0);
  if (!JS_SetReservedSlot(cx, outerObj, sWrappedObjSlot, *vp) ||
      !JS_SetReservedSlot(cx, outerObj, sFlagsSlot, flags) ||
      !JS_SetReservedSlot(cx, outerObj, XPC_XOW_ScopeSlot,
                          PRIVATE_TO_JSVAL(parentScope))) {
    return JS_FALSE;
  }

  *vp = OBJECT_TO_JSVAL(outerObj);

  map->Add(wn->GetScope()->GetWrapperMap(), wrappedObj, outerObj);
  if(wnxow) {
    wnxow->SetXOW(outerObj);
  }

  return JS_TRUE;
}
JSBool
XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp,
                   XPCWrappedNative* wn)
{
  NS_ASSERTION(XPCPerThreadData::IsMainThread(cx),
               "Can't do this off the main thread!");

  // Our argument should be a wrapped native object, but the caller may have
  // passed it in as an optimization.
  JSObject *wrappedObj;
  if (!JSVAL_IS_OBJECT(*vp) ||
      !(wrappedObj = JSVAL_TO_OBJECT(*vp)) ||
      STOBJ_GET_CLASS(wrappedObj) == &sXPC_XOW_JSClass.base) {
    return JS_TRUE;
  }

  if (!wn &&
      !(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, wrappedObj))) {
    return JS_TRUE;
  }

  XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();

  // The parent must be the inner global object for its scope.
  parent = JS_GetGlobalForObject(cx, parent);

  JSClass *clasp = STOBJ_GET_CLASS(parent);
  if (clasp->flags & JSCLASS_IS_EXTENDED) {
    JSExtendedClass *xclasp = reinterpret_cast<JSExtendedClass *>(clasp);
    if (xclasp->innerObject) {
      parent = xclasp->innerObject(cx, parent);
      if (!parent) {
        return JS_FALSE;
      }
    }
  }

  XPCWrappedNativeScope *parentScope =
    XPCWrappedNativeScope::FindInJSObjectScope(cx, parent, nsnull, rt);

#ifdef DEBUG_mrbkap_off
  printf("Wrapping object at %p (%s) [%p]\n",
         (void *)wrappedObj, STOBJ_GET_CLASS(wrappedObj)->name,
         (void *)parentScope);
#endif

  JSObject *outerObj = nsnull;
  WrappedNative2WrapperMap *map = parentScope->GetWrapperMap();

  outerObj = map->Find(wrappedObj);
  if (outerObj) {
    NS_ASSERTION(STOBJ_GET_CLASS(outerObj) == &sXPC_XOW_JSClass.base,
                              "What crazy object are we getting here?");
#ifdef DEBUG_mrbkap_off
    printf("But found a wrapper in the map %p!\n", (void *)outerObj);
#endif
    *vp = OBJECT_TO_JSVAL(outerObj);
    return JS_TRUE;
  }

  outerObj = JS_NewObjectWithGivenProto(cx, &sXPC_XOW_JSClass.base, nsnull,
                                        parent);
  if (!outerObj) {
    return JS_FALSE;
  }

  if (!JS_SetReservedSlot(cx, outerObj, XPCWrapper::sWrappedObjSlot, *vp) ||
      !JS_SetReservedSlot(cx, outerObj, XPCWrapper::sFlagsSlot,
                          JSVAL_ZERO) ||
      !JS_SetReservedSlot(cx, outerObj, XPC_XOW_ScopeSlot,
                          PRIVATE_TO_JSVAL(parentScope))) {
    return JS_FALSE;
  }

  *vp = OBJECT_TO_JSVAL(outerObj);

  map->Add(wn->GetScope()->GetWrapperMap(), wrappedObj, outerObj);

  return JS_TRUE;
}