1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/src/XPCWrappedNativeProto.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,222 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* Shared proto object for XPCWrappedNative. */ 1.11 + 1.12 +#include "xpcprivate.h" 1.13 +#include "nsCxPusher.h" 1.14 +#include "pratom.h" 1.15 + 1.16 +using namespace mozilla; 1.17 + 1.18 +#ifdef DEBUG 1.19 +int32_t XPCWrappedNativeProto::gDEBUG_LiveProtoCount = 0; 1.20 +#endif 1.21 + 1.22 +XPCWrappedNativeProto::XPCWrappedNativeProto(XPCWrappedNativeScope* Scope, 1.23 + nsIClassInfo* ClassInfo, 1.24 + uint32_t ClassInfoFlags, 1.25 + XPCNativeSet* Set) 1.26 + : mScope(Scope), 1.27 + mJSProtoObject(nullptr), 1.28 + mClassInfo(ClassInfo), 1.29 + mClassInfoFlags(ClassInfoFlags), 1.30 + mSet(Set), 1.31 + mScriptableInfo(nullptr) 1.32 +{ 1.33 + // This native object lives as long as its associated JSObject - killed 1.34 + // by finalization of the JSObject (or explicitly if Init fails). 1.35 + 1.36 + MOZ_COUNT_CTOR(XPCWrappedNativeProto); 1.37 + MOZ_ASSERT(mScope); 1.38 + 1.39 +#ifdef DEBUG 1.40 + PR_ATOMIC_INCREMENT(&gDEBUG_LiveProtoCount); 1.41 +#endif 1.42 +} 1.43 + 1.44 +XPCWrappedNativeProto::~XPCWrappedNativeProto() 1.45 +{ 1.46 + MOZ_ASSERT(!mJSProtoObject, "JSProtoObject still alive"); 1.47 + 1.48 + MOZ_COUNT_DTOR(XPCWrappedNativeProto); 1.49 + 1.50 +#ifdef DEBUG 1.51 + PR_ATOMIC_DECREMENT(&gDEBUG_LiveProtoCount); 1.52 +#endif 1.53 + 1.54 + // Note that our weak ref to mScope is not to be trusted at this point. 1.55 + 1.56 + XPCNativeSet::ClearCacheEntryForClassInfo(mClassInfo); 1.57 + 1.58 + delete mScriptableInfo; 1.59 +} 1.60 + 1.61 +bool 1.62 +XPCWrappedNativeProto::Init(const XPCNativeScriptableCreateInfo* scriptableCreateInfo, 1.63 + bool callPostCreatePrototype) 1.64 +{ 1.65 + AutoJSContext cx; 1.66 + nsIXPCScriptable *callback = scriptableCreateInfo ? 1.67 + scriptableCreateInfo->GetCallback() : 1.68 + nullptr; 1.69 + if (callback) { 1.70 + mScriptableInfo = 1.71 + XPCNativeScriptableInfo::Construct(scriptableCreateInfo); 1.72 + if (!mScriptableInfo) 1.73 + return false; 1.74 + } 1.75 + 1.76 + const js::Class* jsclazz; 1.77 + 1.78 + if (mScriptableInfo) { 1.79 + const XPCNativeScriptableFlags& flags(mScriptableInfo->GetFlags()); 1.80 + 1.81 + if (flags.AllowPropModsToPrototype()) { 1.82 + jsclazz = flags.WantCall() ? 1.83 + &XPC_WN_ModsAllowed_WithCall_Proto_JSClass : 1.84 + &XPC_WN_ModsAllowed_NoCall_Proto_JSClass; 1.85 + } else { 1.86 + jsclazz = flags.WantCall() ? 1.87 + &XPC_WN_NoMods_WithCall_Proto_JSClass : 1.88 + &XPC_WN_NoMods_NoCall_Proto_JSClass; 1.89 + } 1.90 + } else { 1.91 + jsclazz = &XPC_WN_NoMods_NoCall_Proto_JSClass; 1.92 + } 1.93 + 1.94 + JS::RootedObject parent(cx, mScope->GetGlobalJSObject()); 1.95 + JS::RootedObject proto(cx, JS_GetObjectPrototype(cx, parent)); 1.96 + mJSProtoObject = JS_NewObjectWithUniqueType(cx, js::Jsvalify(jsclazz), 1.97 + proto, parent); 1.98 + 1.99 + bool success = !!mJSProtoObject; 1.100 + if (success) { 1.101 + JS_SetPrivate(mJSProtoObject, this); 1.102 + if (callPostCreatePrototype) 1.103 + success = CallPostCreatePrototype(); 1.104 + } 1.105 + 1.106 + return success; 1.107 +} 1.108 + 1.109 +bool 1.110 +XPCWrappedNativeProto::CallPostCreatePrototype() 1.111 +{ 1.112 + AutoJSContext cx; 1.113 + 1.114 + // Nothing to do if we don't have a scriptable callback. 1.115 + nsIXPCScriptable *callback = mScriptableInfo ? mScriptableInfo->GetCallback() 1.116 + : nullptr; 1.117 + if (!callback) 1.118 + return true; 1.119 + 1.120 + // Call the helper. This can handle being called if it's not implemented, 1.121 + // so we don't have to check any sort of "want" here. See xpc_map_end.h. 1.122 + nsresult rv = callback->PostCreatePrototype(cx, mJSProtoObject); 1.123 + if (NS_FAILED(rv)) { 1.124 + JS_SetPrivate(mJSProtoObject, nullptr); 1.125 + mJSProtoObject = nullptr; 1.126 + XPCThrower::Throw(rv, cx); 1.127 + return false; 1.128 + } 1.129 + 1.130 + return true; 1.131 +} 1.132 + 1.133 +void 1.134 +XPCWrappedNativeProto::JSProtoObjectFinalized(js::FreeOp *fop, JSObject *obj) 1.135 +{ 1.136 + MOZ_ASSERT(obj == mJSProtoObject, "huh?"); 1.137 + 1.138 + // Only remove this proto from the map if it is the one in the map. 1.139 + ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap(); 1.140 + if (map->Find(mClassInfo) == this) 1.141 + map->Remove(mClassInfo); 1.142 + 1.143 + GetRuntime()->GetDetachedWrappedNativeProtoMap()->Remove(this); 1.144 + GetRuntime()->GetDyingWrappedNativeProtoMap()->Add(this); 1.145 + 1.146 + mJSProtoObject.finalize(js::CastToJSFreeOp(fop)->runtime()); 1.147 +} 1.148 + 1.149 +void 1.150 +XPCWrappedNativeProto::SystemIsBeingShutDown() 1.151 +{ 1.152 + // Note that the instance might receive this call multiple times 1.153 + // as we walk to here from various places. 1.154 + 1.155 + if (mJSProtoObject) { 1.156 + // short circuit future finalization 1.157 + JS_SetPrivate(mJSProtoObject, nullptr); 1.158 + mJSProtoObject = nullptr; 1.159 + } 1.160 +} 1.161 + 1.162 +// static 1.163 +XPCWrappedNativeProto* 1.164 +XPCWrappedNativeProto::GetNewOrUsed(XPCWrappedNativeScope* scope, 1.165 + nsIClassInfo* classInfo, 1.166 + const XPCNativeScriptableCreateInfo* scriptableCreateInfo, 1.167 + bool callPostCreatePrototype) 1.168 +{ 1.169 + AutoJSContext cx; 1.170 + MOZ_ASSERT(scope, "bad param"); 1.171 + MOZ_ASSERT(classInfo, "bad param"); 1.172 + 1.173 + AutoMarkingWrappedNativeProtoPtr proto(cx); 1.174 + ClassInfo2WrappedNativeProtoMap* map = nullptr; 1.175 + 1.176 + uint32_t ciFlags; 1.177 + if (NS_FAILED(classInfo->GetFlags(&ciFlags))) 1.178 + ciFlags = 0; 1.179 + 1.180 + map = scope->GetWrappedNativeProtoMap(); 1.181 + proto = map->Find(classInfo); 1.182 + if (proto) 1.183 + return proto; 1.184 + 1.185 + AutoMarkingNativeSetPtr set(cx); 1.186 + set = XPCNativeSet::GetNewOrUsed(classInfo); 1.187 + if (!set) 1.188 + return nullptr; 1.189 + 1.190 + proto = new XPCWrappedNativeProto(scope, classInfo, ciFlags, set); 1.191 + 1.192 + if (!proto || !proto->Init(scriptableCreateInfo, callPostCreatePrototype)) { 1.193 + delete proto.get(); 1.194 + return nullptr; 1.195 + } 1.196 + 1.197 + map->Add(classInfo, proto); 1.198 + 1.199 + return proto; 1.200 +} 1.201 + 1.202 +void 1.203 +XPCWrappedNativeProto::DebugDump(int16_t depth) 1.204 +{ 1.205 +#ifdef DEBUG 1.206 + depth-- ; 1.207 + XPC_LOG_ALWAYS(("XPCWrappedNativeProto @ %x", this)); 1.208 + XPC_LOG_INDENT(); 1.209 + XPC_LOG_ALWAYS(("gDEBUG_LiveProtoCount is %d", gDEBUG_LiveProtoCount)); 1.210 + XPC_LOG_ALWAYS(("mScope @ %x", mScope)); 1.211 + XPC_LOG_ALWAYS(("mJSProtoObject @ %x", mJSProtoObject.get())); 1.212 + XPC_LOG_ALWAYS(("mSet @ %x", mSet)); 1.213 + XPC_LOG_ALWAYS(("mScriptableInfo @ %x", mScriptableInfo)); 1.214 + if (depth && mScriptableInfo) { 1.215 + XPC_LOG_INDENT(); 1.216 + XPC_LOG_ALWAYS(("mScriptable @ %x", mScriptableInfo->GetCallback())); 1.217 + XPC_LOG_ALWAYS(("mFlags of %x", (uint32_t)mScriptableInfo->GetFlags())); 1.218 + XPC_LOG_ALWAYS(("mJSClass @ %x", mScriptableInfo->GetJSClass())); 1.219 + XPC_LOG_OUTDENT(); 1.220 + } 1.221 + XPC_LOG_OUTDENT(); 1.222 +#endif 1.223 +} 1.224 + 1.225 +