js/xpconnect/src/XPCWrappedNativeProto.cpp

changeset 0
6474c204b198
     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 +

mercurial