DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* Shared proto object for XPCWrappedNative. */

#include "xpcprivate.h"
#include "pratom.h"

using namespace mozilla;

#ifdef DEBUG
int32_t XPCWrappedNativeProto::gDEBUG_LiveProtoCount = 0;
#endif

XPCWrappedNativeProto::XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
                                             nsIClassInfo* ClassInfo,
                                             RefPtr<XPCNativeSet>&& Set)
    : mScope(Scope),
      mJSProtoObject(nullptr),
      mClassInfo(ClassInfo),
      mSet(std::move(Set)) {
  // This native object lives as long as its associated JSObject - killed
  // by finalization of the JSObject (or explicitly if Init fails).

  MOZ_COUNT_CTOR(XPCWrappedNativeProto);
  MOZ_ASSERT(mScope);

#ifdef DEBUG
  gDEBUG_LiveProtoCount++;
#endif
}

XPCWrappedNativeProto::~XPCWrappedNativeProto() {
  MOZ_ASSERT(!mJSProtoObject, "JSProtoObject still alive");

  MOZ_COUNT_DTOR(XPCWrappedNativeProto);

#ifdef DEBUG
  gDEBUG_LiveProtoCount--;
#endif

  // Note that our weak ref to mScope is not to be trusted at this point.

  XPCNativeSet::ClearCacheEntryForClassInfo(mClassInfo);

  DeferredFinalize(mClassInfo.forget().take());
}

bool XPCWrappedNativeProto::Init(JSContext* cx, nsIXPCScriptable* scriptable) {
  mScriptable = scriptable;

  JS::RootedObject proto(cx, JS::GetRealmObjectPrototype(cx));
  mJSProtoObject = JS_NewObjectWithUniqueType(cx, &XPC_WN_Proto_JSClass, proto);

  bool success = !!mJSProtoObject;
  if (success) {
    JS_SetPrivate(mJSProtoObject, this);
  }

  return success;
}

void XPCWrappedNativeProto::JSProtoObjectFinalized(JSFreeOp* fop,
                                                   JSObject* obj) {
  MOZ_ASSERT(obj == mJSProtoObject, "huh?");

#ifdef DEBUG
  // Check that this object has already been swept from the map.
  ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap();
  MOZ_ASSERT(map->Find(mClassInfo) != this);
#endif

  GetRuntime()->GetDyingWrappedNativeProtoMap()->Add(this);
  mJSProtoObject = nullptr;
}

void XPCWrappedNativeProto::JSProtoObjectMoved(JSObject* obj,
                                               const JSObject* old) {
  // Update without triggering barriers.
  MOZ_ASSERT(mJSProtoObject == old);
  mJSProtoObject.unbarrieredSet(obj);
}

void XPCWrappedNativeProto::SystemIsBeingShutDown() {
  // Note that the instance might receive this call multiple times
  // as we walk to here from various places.

  if (mJSProtoObject) {
    // short circuit future finalization
    JS_SetPrivate(mJSProtoObject, nullptr);
    mJSProtoObject = nullptr;
  }
}

// static
XPCWrappedNativeProto* XPCWrappedNativeProto::GetNewOrUsed(
    JSContext* cx, XPCWrappedNativeScope* scope, nsIClassInfo* classInfo,
    nsIXPCScriptable* scriptable) {
  MOZ_ASSERT(scope, "bad param");
  MOZ_ASSERT(classInfo, "bad param");

  AutoMarkingWrappedNativeProtoPtr proto(cx);
  ClassInfo2WrappedNativeProtoMap* map = nullptr;

  map = scope->GetWrappedNativeProtoMap();
  proto = map->Find(classInfo);
  if (proto) {
    return proto;
  }

  RefPtr<XPCNativeSet> set = XPCNativeSet::GetNewOrUsed(cx, classInfo);
  if (!set) {
    return nullptr;
  }

  proto = new XPCWrappedNativeProto(scope, classInfo, std::move(set));

  if (!proto->Init(cx, scriptable)) {
    delete proto.get();
    return nullptr;
  }

  map->Add(classInfo, proto);

  return proto;
}

void XPCWrappedNativeProto::DebugDump(int16_t depth) {
#ifdef DEBUG
  depth--;
  XPC_LOG_ALWAYS(("XPCWrappedNativeProto @ %p", this));
  XPC_LOG_INDENT();
  XPC_LOG_ALWAYS(("gDEBUG_LiveProtoCount is %d", gDEBUG_LiveProtoCount));
  XPC_LOG_ALWAYS(("mScope @ %p", mScope));
  XPC_LOG_ALWAYS(("mJSProtoObject @ %p", mJSProtoObject.get()));
  XPC_LOG_ALWAYS(("mSet @ %p", mSet.get()));
  XPC_LOG_ALWAYS(("mScriptable @ %p", mScriptable.get()));
  if (depth && mScriptable) {
    XPC_LOG_INDENT();
    XPC_LOG_ALWAYS(("mFlags of %x", mScriptable->GetScriptableFlags()));
    XPC_LOG_ALWAYS(("mJSClass @ %p", mScriptable->GetJSClass()));
    XPC_LOG_OUTDENT();
  }
  XPC_LOG_OUTDENT();
#endif
}