Line data Source code
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/. */
6 :
7 : /* Shared proto object for XPCWrappedNative. */
8 :
9 : #include "xpcprivate.h"
10 : #include "pratom.h"
11 :
12 : using namespace mozilla;
13 :
14 : #ifdef DEBUG
15 : int32_t XPCWrappedNativeProto::gDEBUG_LiveProtoCount = 0;
16 : #endif
17 :
18 1824 : XPCWrappedNativeProto::XPCWrappedNativeProto(XPCWrappedNativeScope* Scope,
19 : nsIClassInfo* ClassInfo,
20 1824 : already_AddRefed<XPCNativeSet>&& Set)
21 : : mScope(Scope),
22 : mJSProtoObject(nullptr),
23 : mClassInfo(ClassInfo),
24 1824 : mSet(Set)
25 : {
26 : // This native object lives as long as its associated JSObject - killed
27 : // by finalization of the JSObject (or explicitly if Init fails).
28 :
29 1824 : MOZ_COUNT_CTOR(XPCWrappedNativeProto);
30 1824 : MOZ_ASSERT(mScope);
31 :
32 : #ifdef DEBUG
33 1824 : gDEBUG_LiveProtoCount++;
34 : #endif
35 1824 : }
36 :
37 0 : XPCWrappedNativeProto::~XPCWrappedNativeProto()
38 : {
39 0 : MOZ_ASSERT(!mJSProtoObject, "JSProtoObject still alive");
40 :
41 0 : MOZ_COUNT_DTOR(XPCWrappedNativeProto);
42 :
43 : #ifdef DEBUG
44 0 : gDEBUG_LiveProtoCount--;
45 : #endif
46 :
47 : // Note that our weak ref to mScope is not to be trusted at this point.
48 :
49 0 : XPCNativeSet::ClearCacheEntryForClassInfo(mClassInfo);
50 0 : }
51 :
52 : bool
53 1824 : XPCWrappedNativeProto::Init(nsIXPCScriptable* scriptable,
54 : bool callPostCreatePrototype)
55 : {
56 3648 : AutoJSContext cx;
57 1824 : mScriptable = scriptable;
58 :
59 : const js::Class* jsclazz =
60 2577 : (mScriptable && mScriptable->AllowPropModsToPrototype())
61 1867 : ? &XPC_WN_ModsAllowed_Proto_JSClass
62 1824 : : &XPC_WN_NoMods_Proto_JSClass;
63 :
64 3648 : JS::RootedObject global(cx, mScope->GetGlobalJSObject());
65 3648 : JS::RootedObject proto(cx, JS_GetObjectPrototype(cx, global));
66 : mJSProtoObject = JS_NewObjectWithUniqueType(cx, js::Jsvalify(jsclazz),
67 1824 : proto);
68 :
69 1824 : bool success = !!mJSProtoObject;
70 1824 : if (success) {
71 1824 : JS_SetPrivate(mJSProtoObject, this);
72 1824 : if (callPostCreatePrototype)
73 1564 : success = CallPostCreatePrototype();
74 : }
75 :
76 3648 : return success;
77 : }
78 :
79 : bool
80 1564 : XPCWrappedNativeProto::CallPostCreatePrototype()
81 : {
82 3128 : AutoJSContext cx;
83 :
84 : // Nothing to do if we don't have a scriptable callback.
85 1564 : if (!mScriptable)
86 1071 : return true;
87 :
88 : // Call the helper. This can handle being called if it's not implemented,
89 : // so we don't have to check any sort of "want" here. See xpc_map_end.h.
90 493 : nsresult rv = mScriptable->PostCreatePrototype(cx, mJSProtoObject);
91 493 : if (NS_FAILED(rv)) {
92 0 : JS_SetPrivate(mJSProtoObject, nullptr);
93 0 : mJSProtoObject = nullptr;
94 0 : XPCThrower::Throw(rv, cx);
95 0 : return false;
96 : }
97 :
98 493 : return true;
99 : }
100 :
101 : void
102 0 : XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp* fop, JSObject* obj)
103 : {
104 0 : MOZ_ASSERT(obj == mJSProtoObject, "huh?");
105 :
106 : #ifdef DEBUG
107 : // Check that this object has already been swept from the map.
108 0 : ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap();
109 0 : MOZ_ASSERT(map->Find(mClassInfo) != this);
110 : #endif
111 :
112 0 : GetRuntime()->GetDyingWrappedNativeProtoMap()->Add(this);
113 :
114 0 : mJSProtoObject.finalize(js::CastToJSFreeOp(fop)->runtime());
115 0 : }
116 :
117 : void
118 0 : XPCWrappedNativeProto::JSProtoObjectMoved(JSObject* obj, const JSObject* old)
119 : {
120 0 : MOZ_ASSERT(mJSProtoObject == old);
121 0 : mJSProtoObject.init(obj); // Update without triggering barriers.
122 0 : }
123 :
124 : void
125 0 : XPCWrappedNativeProto::SystemIsBeingShutDown()
126 : {
127 : // Note that the instance might receive this call multiple times
128 : // as we walk to here from various places.
129 :
130 0 : if (mJSProtoObject) {
131 : // short circuit future finalization
132 0 : JS_SetPrivate(mJSProtoObject, nullptr);
133 0 : mJSProtoObject = nullptr;
134 : }
135 0 : }
136 :
137 : // static
138 : XPCWrappedNativeProto*
139 4378 : XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope,
140 : nsIClassInfo* classInfo,
141 : nsIXPCScriptable* scriptable,
142 : bool callPostCreatePrototype)
143 : {
144 8756 : AutoJSContext cx;
145 4378 : MOZ_ASSERT(scope, "bad param");
146 4378 : MOZ_ASSERT(classInfo, "bad param");
147 :
148 8756 : AutoMarkingWrappedNativeProtoPtr proto(cx);
149 4378 : ClassInfo2WrappedNativeProtoMap* map = nullptr;
150 :
151 4378 : map = scope->GetWrappedNativeProtoMap();
152 4378 : proto = map->Find(classInfo);
153 4378 : if (proto)
154 2554 : return proto;
155 :
156 3648 : RefPtr<XPCNativeSet> set = XPCNativeSet::GetNewOrUsed(classInfo);
157 1824 : if (!set)
158 0 : return nullptr;
159 :
160 3648 : proto = new XPCWrappedNativeProto(scope, classInfo, set.forget());
161 :
162 1824 : if (!proto || !proto->Init(scriptable, callPostCreatePrototype)) {
163 0 : delete proto.get();
164 0 : return nullptr;
165 : }
166 :
167 1824 : map->Add(classInfo, proto);
168 :
169 1824 : return proto;
170 : }
171 :
172 : void
173 0 : XPCWrappedNativeProto::DebugDump(int16_t depth)
174 : {
175 : #ifdef DEBUG
176 0 : depth-- ;
177 0 : XPC_LOG_ALWAYS(("XPCWrappedNativeProto @ %p", this));
178 0 : XPC_LOG_INDENT();
179 0 : XPC_LOG_ALWAYS(("gDEBUG_LiveProtoCount is %d", gDEBUG_LiveProtoCount));
180 0 : XPC_LOG_ALWAYS(("mScope @ %p", mScope));
181 0 : XPC_LOG_ALWAYS(("mJSProtoObject @ %p", mJSProtoObject.get()));
182 0 : XPC_LOG_ALWAYS(("mSet @ %p", mSet.get()));
183 0 : XPC_LOG_ALWAYS(("mScriptable @ %p", mScriptable.get()));
184 0 : if (depth && mScriptable) {
185 0 : XPC_LOG_INDENT();
186 0 : XPC_LOG_ALWAYS(("mFlags of %x", mScriptable->GetScriptableFlags()));
187 0 : XPC_LOG_ALWAYS(("mJSClass @ %p", mScriptable->GetJSClass()));
188 0 : XPC_LOG_OUTDENT();
189 : }
190 0 : XPC_LOG_OUTDENT();
191 : #endif
192 0 : }
193 :
194 :
|