1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Shared proto object for XPCWrappedNative. */
9 #include "xpcprivate.h"
10 #include "js/Object.h" // JS::SetReservedSlot
14 using namespace mozilla
;
17 int32_t XPCWrappedNativeProto::gDEBUG_LiveProtoCount
= 0;
20 XPCWrappedNativeProto::XPCWrappedNativeProto(XPCWrappedNativeScope
* Scope
,
21 nsIClassInfo
* ClassInfo
,
22 RefPtr
<XPCNativeSet
>&& Set
)
24 mJSProtoObject(nullptr),
25 mClassInfo(ClassInfo
),
26 mSet(std::move(Set
)) {
27 // This native object lives as long as its associated JSObject - killed
28 // by finalization of the JSObject (or explicitly if Init fails).
30 MOZ_COUNT_CTOR(XPCWrappedNativeProto
);
34 gDEBUG_LiveProtoCount
++;
38 XPCWrappedNativeProto::~XPCWrappedNativeProto() {
39 MOZ_ASSERT(!mJSProtoObject
, "JSProtoObject still alive");
41 MOZ_COUNT_DTOR(XPCWrappedNativeProto
);
44 gDEBUG_LiveProtoCount
--;
47 // Note that our weak ref to mScope is not to be trusted at this point.
49 XPCNativeSet::ClearCacheEntryForClassInfo(mClassInfo
);
51 DeferredFinalize(mClassInfo
.forget().take());
54 bool XPCWrappedNativeProto::Init(JSContext
* cx
, nsIXPCScriptable
* scriptable
) {
55 mScriptable
= scriptable
;
57 JS::RootedObject
proto(cx
, JS::GetRealmObjectPrototype(cx
));
58 mJSProtoObject
= JS_NewObjectWithGivenProto(cx
, &XPC_WN_Proto_JSClass
, proto
);
60 bool success
= !!mJSProtoObject
;
62 JS::SetReservedSlot(mJSProtoObject
, ProtoSlot
, JS::PrivateValue(this));
68 void XPCWrappedNativeProto::JSProtoObjectFinalized(JS::GCContext
* gcx
,
70 MOZ_ASSERT(obj
== mJSProtoObject
, "huh?");
73 // Check that this object has already been swept from the map.
74 ClassInfo2WrappedNativeProtoMap
* map
= GetScope()->GetWrappedNativeProtoMap();
75 MOZ_ASSERT(map
->Find(mClassInfo
) != this);
78 MOZ_ALWAYS_TRUE(GetRuntime()->GetDyingWrappedNativeProtos().append(this));
79 mJSProtoObject
= nullptr;
82 void XPCWrappedNativeProto::JSProtoObjectMoved(JSObject
* obj
,
83 const JSObject
* old
) {
84 // Update without triggering barriers.
85 MOZ_ASSERT(mJSProtoObject
== old
);
86 mJSProtoObject
.unbarrieredSet(obj
);
89 void XPCWrappedNativeProto::SystemIsBeingShutDown() {
90 // Note that the instance might receive this call multiple times
91 // as we walk to here from various places.
94 // short circuit future finalization
95 JS::SetReservedSlot(mJSProtoObject
, ProtoSlot
, JS::UndefinedValue());
96 mJSProtoObject
= nullptr;
101 XPCWrappedNativeProto
* XPCWrappedNativeProto::GetNewOrUsed(
102 JSContext
* cx
, XPCWrappedNativeScope
* scope
, nsIClassInfo
* classInfo
,
103 nsIXPCScriptable
* scriptable
) {
104 MOZ_ASSERT(scope
, "bad param");
105 MOZ_ASSERT(classInfo
, "bad param");
107 AutoMarkingWrappedNativeProtoPtr
proto(cx
);
108 ClassInfo2WrappedNativeProtoMap
* map
= nullptr;
110 map
= scope
->GetWrappedNativeProtoMap();
111 proto
= map
->Find(classInfo
);
116 RefPtr
<XPCNativeSet
> set
= XPCNativeSet::GetNewOrUsed(cx
, classInfo
);
121 proto
= new XPCWrappedNativeProto(scope
, classInfo
, std::move(set
));
123 if (!proto
->Init(cx
, scriptable
)) {
128 map
->Add(classInfo
, proto
);
133 void XPCWrappedNativeProto::DebugDump(int16_t depth
) {
136 XPC_LOG_ALWAYS(("XPCWrappedNativeProto @ %p", this));
138 XPC_LOG_ALWAYS(("gDEBUG_LiveProtoCount is %d", gDEBUG_LiveProtoCount
));
139 XPC_LOG_ALWAYS(("mScope @ %p", mScope
));
140 XPC_LOG_ALWAYS(("mJSProtoObject @ %p", mJSProtoObject
.get()));
141 XPC_LOG_ALWAYS(("mSet @ %p", mSet
.get()));
142 XPC_LOG_ALWAYS(("mScriptable @ %p", mScriptable
.get()));
143 if (depth
&& mScriptable
) {
145 XPC_LOG_ALWAYS(("mFlags of %x", mScriptable
->GetScriptableFlags()));
146 XPC_LOG_ALWAYS(("mJSClass @ %p", mScriptable
->GetJSClass()));