Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
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 "nsCxPusher.h"
11 #include "pratom.h"
13 using namespace mozilla;
15 #ifdef DEBUG
16 int32_t XPCWrappedNativeProto::gDEBUG_LiveProtoCount = 0;
17 #endif
19 XPCWrappedNativeProto::XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
20 nsIClassInfo* ClassInfo,
21 uint32_t ClassInfoFlags,
22 XPCNativeSet* Set)
23 : mScope(Scope),
24 mJSProtoObject(nullptr),
25 mClassInfo(ClassInfo),
26 mClassInfoFlags(ClassInfoFlags),
27 mSet(Set),
28 mScriptableInfo(nullptr)
29 {
30 // This native object lives as long as its associated JSObject - killed
31 // by finalization of the JSObject (or explicitly if Init fails).
33 MOZ_COUNT_CTOR(XPCWrappedNativeProto);
34 MOZ_ASSERT(mScope);
36 #ifdef DEBUG
37 PR_ATOMIC_INCREMENT(&gDEBUG_LiveProtoCount);
38 #endif
39 }
41 XPCWrappedNativeProto::~XPCWrappedNativeProto()
42 {
43 MOZ_ASSERT(!mJSProtoObject, "JSProtoObject still alive");
45 MOZ_COUNT_DTOR(XPCWrappedNativeProto);
47 #ifdef DEBUG
48 PR_ATOMIC_DECREMENT(&gDEBUG_LiveProtoCount);
49 #endif
51 // Note that our weak ref to mScope is not to be trusted at this point.
53 XPCNativeSet::ClearCacheEntryForClassInfo(mClassInfo);
55 delete mScriptableInfo;
56 }
58 bool
59 XPCWrappedNativeProto::Init(const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
60 bool callPostCreatePrototype)
61 {
62 AutoJSContext cx;
63 nsIXPCScriptable *callback = scriptableCreateInfo ?
64 scriptableCreateInfo->GetCallback() :
65 nullptr;
66 if (callback) {
67 mScriptableInfo =
68 XPCNativeScriptableInfo::Construct(scriptableCreateInfo);
69 if (!mScriptableInfo)
70 return false;
71 }
73 const js::Class* jsclazz;
75 if (mScriptableInfo) {
76 const XPCNativeScriptableFlags& flags(mScriptableInfo->GetFlags());
78 if (flags.AllowPropModsToPrototype()) {
79 jsclazz = flags.WantCall() ?
80 &XPC_WN_ModsAllowed_WithCall_Proto_JSClass :
81 &XPC_WN_ModsAllowed_NoCall_Proto_JSClass;
82 } else {
83 jsclazz = flags.WantCall() ?
84 &XPC_WN_NoMods_WithCall_Proto_JSClass :
85 &XPC_WN_NoMods_NoCall_Proto_JSClass;
86 }
87 } else {
88 jsclazz = &XPC_WN_NoMods_NoCall_Proto_JSClass;
89 }
91 JS::RootedObject parent(cx, mScope->GetGlobalJSObject());
92 JS::RootedObject proto(cx, JS_GetObjectPrototype(cx, parent));
93 mJSProtoObject = JS_NewObjectWithUniqueType(cx, js::Jsvalify(jsclazz),
94 proto, parent);
96 bool success = !!mJSProtoObject;
97 if (success) {
98 JS_SetPrivate(mJSProtoObject, this);
99 if (callPostCreatePrototype)
100 success = CallPostCreatePrototype();
101 }
103 return success;
104 }
106 bool
107 XPCWrappedNativeProto::CallPostCreatePrototype()
108 {
109 AutoJSContext cx;
111 // Nothing to do if we don't have a scriptable callback.
112 nsIXPCScriptable *callback = mScriptableInfo ? mScriptableInfo->GetCallback()
113 : nullptr;
114 if (!callback)
115 return true;
117 // Call the helper. This can handle being called if it's not implemented,
118 // so we don't have to check any sort of "want" here. See xpc_map_end.h.
119 nsresult rv = callback->PostCreatePrototype(cx, mJSProtoObject);
120 if (NS_FAILED(rv)) {
121 JS_SetPrivate(mJSProtoObject, nullptr);
122 mJSProtoObject = nullptr;
123 XPCThrower::Throw(rv, cx);
124 return false;
125 }
127 return true;
128 }
130 void
131 XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp *fop, JSObject *obj)
132 {
133 MOZ_ASSERT(obj == mJSProtoObject, "huh?");
135 // Only remove this proto from the map if it is the one in the map.
136 ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap();
137 if (map->Find(mClassInfo) == this)
138 map->Remove(mClassInfo);
140 GetRuntime()->GetDetachedWrappedNativeProtoMap()->Remove(this);
141 GetRuntime()->GetDyingWrappedNativeProtoMap()->Add(this);
143 mJSProtoObject.finalize(js::CastToJSFreeOp(fop)->runtime());
144 }
146 void
147 XPCWrappedNativeProto::SystemIsBeingShutDown()
148 {
149 // Note that the instance might receive this call multiple times
150 // as we walk to here from various places.
152 if (mJSProtoObject) {
153 // short circuit future finalization
154 JS_SetPrivate(mJSProtoObject, nullptr);
155 mJSProtoObject = nullptr;
156 }
157 }
159 // static
160 XPCWrappedNativeProto*
161 XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope,
162 nsIClassInfo* classInfo,
163 const XPCNativeScriptableCreateInfo* scriptableCreateInfo,
164 bool callPostCreatePrototype)
165 {
166 AutoJSContext cx;
167 MOZ_ASSERT(scope, "bad param");
168 MOZ_ASSERT(classInfo, "bad param");
170 AutoMarkingWrappedNativeProtoPtr proto(cx);
171 ClassInfo2WrappedNativeProtoMap* map = nullptr;
173 uint32_t ciFlags;
174 if (NS_FAILED(classInfo->GetFlags(&ciFlags)))
175 ciFlags = 0;
177 map = scope->GetWrappedNativeProtoMap();
178 proto = map->Find(classInfo);
179 if (proto)
180 return proto;
182 AutoMarkingNativeSetPtr set(cx);
183 set = XPCNativeSet::GetNewOrUsed(classInfo);
184 if (!set)
185 return nullptr;
187 proto = new XPCWrappedNativeProto(scope, classInfo, ciFlags, set);
189 if (!proto || !proto->Init(scriptableCreateInfo, callPostCreatePrototype)) {
190 delete proto.get();
191 return nullptr;
192 }
194 map->Add(classInfo, proto);
196 return proto;
197 }
199 void
200 XPCWrappedNativeProto::DebugDump(int16_t depth)
201 {
202 #ifdef DEBUG
203 depth-- ;
204 XPC_LOG_ALWAYS(("XPCWrappedNativeProto @ %x", this));
205 XPC_LOG_INDENT();
206 XPC_LOG_ALWAYS(("gDEBUG_LiveProtoCount is %d", gDEBUG_LiveProtoCount));
207 XPC_LOG_ALWAYS(("mScope @ %x", mScope));
208 XPC_LOG_ALWAYS(("mJSProtoObject @ %x", mJSProtoObject.get()));
209 XPC_LOG_ALWAYS(("mSet @ %x", mSet));
210 XPC_LOG_ALWAYS(("mScriptableInfo @ %x", mScriptableInfo));
211 if (depth && mScriptableInfo) {
212 XPC_LOG_INDENT();
213 XPC_LOG_ALWAYS(("mScriptable @ %x", mScriptableInfo->GetCallback()));
214 XPC_LOG_ALWAYS(("mFlags of %x", (uint32_t)mScriptableInfo->GetFlags()));
215 XPC_LOG_ALWAYS(("mJSClass @ %x", mScriptableInfo->GetJSClass()));
216 XPC_LOG_OUTDENT();
217 }
218 XPC_LOG_OUTDENT();
219 #endif
220 }