XPCWrappedNativeProto.cpp (4543B)
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/. */ 6 7 /* Shared proto object for XPCWrappedNative. */ 8 9 #include "xpcprivate.h" 10 #include "js/Object.h" // JS::SetReservedSlot 11 #include "pratom.h" 12 #include "XPCMaps.h" 13 14 using namespace mozilla; 15 16 #ifdef DEBUG 17 int32_t XPCWrappedNativeProto::gDEBUG_LiveProtoCount = 0; 18 #endif 19 20 XPCWrappedNativeProto::XPCWrappedNativeProto(XPCWrappedNativeScope* Scope, 21 nsIClassInfo* ClassInfo, 22 RefPtr<XPCNativeSet>&& Set) 23 : mScope(Scope), 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). 29 30 MOZ_COUNT_CTOR(XPCWrappedNativeProto); 31 MOZ_ASSERT(mScope); 32 33 #ifdef DEBUG 34 gDEBUG_LiveProtoCount++; 35 #endif 36 } 37 38 XPCWrappedNativeProto::~XPCWrappedNativeProto() { 39 MOZ_ASSERT(!mJSProtoObject, "JSProtoObject still alive"); 40 41 MOZ_COUNT_DTOR(XPCWrappedNativeProto); 42 43 #ifdef DEBUG 44 gDEBUG_LiveProtoCount--; 45 #endif 46 47 // Note that our weak ref to mScope is not to be trusted at this point. 48 49 XPCNativeSet::ClearCacheEntryForClassInfo(mClassInfo); 50 51 DeferredFinalize(mClassInfo.forget().take()); 52 } 53 54 bool XPCWrappedNativeProto::Init(JSContext* cx, nsIXPCScriptable* scriptable) { 55 mScriptable = scriptable; 56 57 JS::RootedObject proto(cx, JS::GetRealmObjectPrototype(cx)); 58 mJSProtoObject = JS_NewObjectWithGivenProto(cx, &XPC_WN_Proto_JSClass, proto); 59 60 bool success = !!mJSProtoObject; 61 if (success) { 62 JS::SetReservedSlot(mJSProtoObject, ProtoSlot, JS::PrivateValue(this)); 63 } 64 65 return success; 66 } 67 68 void XPCWrappedNativeProto::JSProtoObjectFinalized(JS::GCContext* gcx, 69 JSObject* obj) { 70 MOZ_ASSERT(obj == mJSProtoObject, "huh?"); 71 72 #ifdef DEBUG 73 // Check that this object has already been swept from the map. 74 ClassInfo2WrappedNativeProtoMap* map = GetScope()->GetWrappedNativeProtoMap(); 75 MOZ_ASSERT(map->Find(mClassInfo) != this); 76 #endif 77 78 MOZ_ALWAYS_TRUE(GetRuntime()->GetDyingWrappedNativeProtos().append(this)); 79 mJSProtoObject = nullptr; 80 } 81 82 void XPCWrappedNativeProto::JSProtoObjectMoved(JSObject* obj, 83 const JSObject* old) { 84 // Update without triggering barriers. 85 MOZ_ASSERT(mJSProtoObject == old); 86 mJSProtoObject.unbarrieredSet(obj); 87 } 88 89 void XPCWrappedNativeProto::SystemIsBeingShutDown() { 90 // Note that the instance might receive this call multiple times 91 // as we walk to here from various places. 92 93 if (mJSProtoObject) { 94 // short circuit future finalization 95 JS::SetReservedSlot(mJSProtoObject, ProtoSlot, JS::UndefinedValue()); 96 mJSProtoObject = nullptr; 97 } 98 } 99 100 // static 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"); 106 107 AutoMarkingWrappedNativeProtoPtr proto(cx); 108 ClassInfo2WrappedNativeProtoMap* map = nullptr; 109 110 map = scope->GetWrappedNativeProtoMap(); 111 proto = map->Find(classInfo); 112 if (proto) { 113 return proto; 114 } 115 116 RefPtr<XPCNativeSet> set = XPCNativeSet::GetNewOrUsed(cx, classInfo); 117 if (!set) { 118 return nullptr; 119 } 120 121 proto = new XPCWrappedNativeProto(scope, classInfo, std::move(set)); 122 123 if (!proto->Init(cx, scriptable)) { 124 delete proto.get(); 125 return nullptr; 126 } 127 128 map->Add(classInfo, proto); 129 130 return proto; 131 } 132 133 void XPCWrappedNativeProto::DebugDump(int16_t depth) { 134 #ifdef DEBUG 135 depth--; 136 XPC_LOG_ALWAYS(("XPCWrappedNativeProto @ %p", this)); 137 XPC_LOG_INDENT(); 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) { 144 XPC_LOG_INDENT(); 145 XPC_LOG_ALWAYS(("mFlags of %x", mScriptable->GetScriptableFlags())); 146 XPC_LOG_ALWAYS(("mJSClass @ %p", mScriptable->GetJSClass())); 147 XPC_LOG_OUTDENT(); 148 } 149 XPC_LOG_OUTDENT(); 150 #endif 151 }