diff options
Diffstat (limited to 'ppapi/proxy/plugin_var_tracker.cc')
-rw-r--r-- | ppapi/proxy/plugin_var_tracker.cc | 395 |
1 files changed, 167 insertions, 228 deletions
diff --git a/ppapi/proxy/plugin_var_tracker.cc b/ppapi/proxy/plugin_var_tracker.cc index 16d5992..0c834a5 100644 --- a/ppapi/proxy/plugin_var_tracker.cc +++ b/ppapi/proxy/plugin_var_tracker.cc @@ -10,18 +10,16 @@ #include "ppapi/proxy/plugin_dispatcher.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/proxy/interface_id.h" +#include "ppapi/proxy/proxy_object_var.h" +#include "ppapi/shared_impl/var.h" + +using ppapi::ProxyObjectVar; +using ppapi::Var; namespace pp { namespace proxy { -namespace { - -// When non-NULL, this object overrides the VarTrackerSingleton. -PluginVarTracker* var_tracker_override = NULL; - -} // namespace - -PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, VarID i) +PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, int32 i) : dispatcher(d), host_object_id(i) { } @@ -34,160 +32,33 @@ bool PluginVarTracker::HostVar::operator<(const HostVar& other) const { return host_object_id < other.host_object_id; } -PluginVarTracker::PluginVarInfo::PluginVarInfo(const HostVar& host_var) - : host_var(host_var), - ref_count(0), - track_with_no_reference_count(0) { -} - -PluginVarTracker::PluginVarTracker() : last_plugin_var_id_(0) { +PluginVarTracker::PluginVarTracker() { } PluginVarTracker::~PluginVarTracker() { } -// static -void PluginVarTracker::SetInstanceForTest(PluginVarTracker* tracker) { - var_tracker_override = tracker; -} - -// static -PluginVarTracker* PluginVarTracker::GetInstance() { - if (var_tracker_override) - return var_tracker_override; - return Singleton<PluginVarTracker>::get(); -} - -PluginVarTracker::VarID PluginVarTracker::MakeString(const std::string& str) { - return MakeString(str.c_str(), str.length()); -} - -PluginVarTracker::VarID PluginVarTracker::MakeString(const char* str, - uint32_t len) { - std::pair<VarIDStringMap::iterator, bool> - iter_success_pair(var_id_to_string_.end(), false); - VarID new_id(0); - RefCountedStringPtr str_ptr(new RefCountedString(str, len)); - // Pick new IDs until one is successfully inserted. This loop is very unlikely - // to ever run a 2nd time, since we have ~2^63 possible IDs to exhaust. - while (!iter_success_pair.second) { - new_id = GetNewVarID(); - iter_success_pair = - var_id_to_string_.insert(VarIDStringMap::value_type(new_id, str_ptr)); - } - // Release the local pointer. - str_ptr = NULL; - // Now the map should have the only reference. - DCHECK(iter_success_pair.first->second->HasOneRef()); - iter_success_pair.first->second->AddRef(); - return new_id; -} - -const std::string* PluginVarTracker::GetExistingString( - const PP_Var& var) const { - if (var.type != PP_VARTYPE_STRING) - return NULL; - VarIDStringMap::const_iterator found = - var_id_to_string_.find(var.value.as_id); - if (found != var_id_to_string_.end()) - return &found->second->value(); - return NULL; -} - -void PluginVarTracker::AddRef(const PP_Var& var) { - if (var.type == PP_VARTYPE_STRING) { - VarIDStringMap::iterator found = var_id_to_string_.find(var.value.as_id); - if (found == var_id_to_string_.end()) { - NOTREACHED() << "Requesting to addref an unknown string."; - return; - } - found->second->AddRef(); - } else if (var.type == PP_VARTYPE_OBJECT && var.value.as_id != 0) { - PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); - if (found == plugin_var_info_.end()) { - NOTREACHED() << "Requesting to addref an unknown object."; - return; - } - - PluginVarInfo& info = found->second; - if (info.ref_count == 0) { - // Got an AddRef for an object we have no existing reference for. - // We need to tell the browser we've taken a ref. This comes up when the - // browser passes an object as an input param and holds a ref for us. - // This must be a sync message since otherwise the "addref" will actually - // occur after the return to the browser of the sync function that - // presumably sent the object. - SendAddRefObjectMsg(info.host_var); - } - info.ref_count++; - } -} - -void PluginVarTracker::Release(const PP_Var& var) { - if (var.type == PP_VARTYPE_STRING) { - VarIDStringMap::iterator found = var_id_to_string_.find(var.value.as_id); - if (found == var_id_to_string_.end()) { - NOTREACHED() << "Requesting to release an unknown string."; - return; - } - found->second->Release(); - // If there is only 1 reference left, it's the map's reference. Erase it - // from the map, which will delete the string. - if (found->second->HasOneRef()) - var_id_to_string_.erase(found); - } else if (var.type == PP_VARTYPE_OBJECT) { - PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); - if (found == plugin_var_info_.end()) { - NOTREACHED() << "Requesting to release an unknown object."; - return; - } - - PluginVarInfo& info = found->second; - if (info.ref_count == 0) { - NOTREACHED() << "Releasing an object with zero ref."; - return; - } - - info.ref_count--; - if (info.ref_count == 0) - SendReleaseObjectMsg(info.host_var); - DeletePluginVarInfoIfNecessary(found); - } -} - -PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& var, +PP_Var PluginVarTracker::ReceiveObjectPassRef(const PP_Var& host_var, PluginDispatcher* dispatcher) { - DCHECK(var.type == PP_VARTYPE_OBJECT); - - // Find the plugin info. - PluginVarInfoMap::iterator found = - FindOrMakePluginVarFromHostVar(var, dispatcher); - if (found == plugin_var_info_.end()) { - // The above code should have always made an entry in the map. - NOTREACHED(); - return PP_MakeUndefined(); - } + DCHECK(host_var.type == PP_VARTYPE_OBJECT); - // Fix up the references. The host (renderer) just sent us a ref. The - // renderer has addrefed the var in its tracker for us since it's returning - // it. - PluginVarInfo& info = found->second; - if (info.ref_count == 0) { - // We don't have a reference to this already, then we just add it to our - // tracker and use that one ref. - info.ref_count = 1; - } else { - // We already have a reference to it, that means the renderer now has two - // references on our behalf. We want to transfer that extra reference to - // our list. This means we addref in the plugin, and release the extra one - // in the renderer. - SendReleaseObjectMsg(info.host_var); - info.ref_count++; + // Get the object. + scoped_refptr<ProxyObjectVar> object( + FindOrMakePluginVarFromHostVar(host_var, dispatcher)); + + // Actually create the PP_Var, this will add all the tracking info but not + // adjust any refcounts. + PP_Var ret = GetOrCreateObjectVarID(object.get()); + + VarInfo& info = GetLiveVar(ret)->second; + if (info.ref_count > 0) { + // We already had a reference to it before. That means the renderer now has + // two references on our behalf. We want to transfer that extra reference + // to our list. This means we addref in the plugin, and release the extra + // one in the renderer. + SendReleaseObjectMsg(*object); } - - PP_Var ret; - ret.type = PP_VARTYPE_OBJECT; - ret.value.as_id = found->first; + info.ref_count++; return ret; } @@ -196,58 +67,66 @@ PP_Var PluginVarTracker::TrackObjectWithNoReference( PluginDispatcher* dispatcher) { DCHECK(host_var.type == PP_VARTYPE_OBJECT); - PluginVarInfoMap::iterator found = - FindOrMakePluginVarFromHostVar(host_var, dispatcher); - if (found == plugin_var_info_.end()) { - // The above code should have always made an entry in the map. - NOTREACHED(); - return PP_MakeUndefined(); - } + // Get the object. + scoped_refptr<ProxyObjectVar> object( + FindOrMakePluginVarFromHostVar(host_var, dispatcher)); - found->second.track_with_no_reference_count++; + // Actually create the PP_Var, this will add all the tracking info but not + // adjust any refcounts. + PP_Var ret = GetOrCreateObjectVarID(object.get()); - PP_Var ret; - ret.type = PP_VARTYPE_OBJECT; - ret.value.as_id = found->first; + VarInfo& info = GetLiveVar(ret)->second; + info.track_with_no_reference_count++; return ret; } void PluginVarTracker::StopTrackingObjectWithNoReference( const PP_Var& plugin_var) { DCHECK(plugin_var.type == PP_VARTYPE_OBJECT); - PluginVarInfoMap::iterator found = plugin_var_info_.find( - plugin_var.value.as_id); - if (found == plugin_var_info_.end()) { + VarMap::iterator found = GetLiveVar(plugin_var); + if (found == live_vars_.end()) { NOTREACHED(); return; } + DCHECK(found->second.track_with_no_reference_count > 0); found->second.track_with_no_reference_count--; - DeletePluginVarInfoIfNecessary(found); + DeleteObjectInfoIfNecessary(found); } PP_Var PluginVarTracker::GetHostObject(const PP_Var& plugin_object) const { - DCHECK(plugin_object.type == PP_VARTYPE_OBJECT); - PluginVarInfoMap::const_iterator found = plugin_var_info_.find( - plugin_object.value.as_id); - if (found == plugin_var_info_.end()) { + if (plugin_object.type != PP_VARTYPE_OBJECT) { NOTREACHED(); return PP_MakeUndefined(); } + + Var* var = GetVar(plugin_object); + ProxyObjectVar* object = var->AsProxyObjectVar(); + if (!object) { + NOTREACHED(); + return PP_MakeUndefined(); + } + + // Make a var with the host ID. PP_Var ret; ret.type = PP_VARTYPE_OBJECT; - ret.value.as_id = found->second.host_var.host_object_id; + ret.value.as_id = object->host_var_id(); return ret; } PluginDispatcher* PluginVarTracker::DispatcherForPluginObject( const PP_Var& plugin_object) const { - DCHECK(plugin_object.type == PP_VARTYPE_OBJECT); - PluginVarInfoMap::const_iterator found = plugin_var_info_.find( - plugin_object.value.as_id); - if (found != plugin_var_info_.end()) - return found->second.host_var.dispatcher; - return NULL; + if (plugin_object.type != PP_VARTYPE_OBJECT) + return NULL; + + VarMap::const_iterator found = GetLiveVar(plugin_object); + if (found == live_vars_.end()) + return NULL; + + ProxyObjectVar* object = found->second.var->AsProxyObjectVar(); + if (!object) + return NULL; + return object->dispatcher(); } void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher, @@ -255,85 +134,145 @@ void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher, // Convert the host object to a normal var valid in the plugin. DCHECK(host_object.type == PP_VARTYPE_OBJECT); HostVarToPluginVarMap::iterator found = host_var_to_plugin_var_.find( - HostVar(dispatcher, host_object.value.as_id)); + HostVar(dispatcher, static_cast<int32>(host_object.value.as_id))); if (found == host_var_to_plugin_var_.end()) { NOTREACHED(); return; } - // Now just release the object like normal. - PP_Var plugin_object; - plugin_object.type = PP_VARTYPE_OBJECT; - plugin_object.value.as_id = found->second; - Release(plugin_object); + // Now just release the object given the plugin var ID. + ReleaseVar(found->second); } int PluginVarTracker::GetRefCountForObject(const PP_Var& plugin_object) { - PluginVarInfoMap::iterator found = plugin_var_info_.find( - plugin_object.value.as_id); - if (found == plugin_var_info_.end()) + VarMap::iterator found = GetLiveVar(plugin_object); + if (found == live_vars_.end()) return -1; return found->second.ref_count; } int PluginVarTracker::GetTrackedWithNoReferenceCountForObject( const PP_Var& plugin_object) { - PluginVarInfoMap::iterator found = plugin_var_info_.find( - plugin_object.value.as_id); - if (found == plugin_var_info_.end()) + VarMap::iterator found = GetLiveVar(plugin_object); + if (found == live_vars_.end()) return -1; return found->second.track_with_no_reference_count; } -void PluginVarTracker::SendAddRefObjectMsg(const HostVar& host_var) { +int32 PluginVarTracker::AddVarInternal(Var* var, AddVarRefMode mode) { + // Normal adding. + int32 new_id = VarTracker::AddVarInternal(var, mode); + + // Need to add proxy objects to the host var map. + ProxyObjectVar* proxy_object = var->AsProxyObjectVar(); + if (proxy_object) { + HostVar host_var(proxy_object->dispatcher(), proxy_object->host_var_id()); + DCHECK(host_var_to_plugin_var_.find(host_var) == + host_var_to_plugin_var_.end()); // Adding an object twice, use + // FindOrMakePluginVarFromHostVar. + host_var_to_plugin_var_[host_var] = new_id; + } + return new_id; +} + +void PluginVarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator iter) { + ProxyObjectVar* object = iter->second.var->AsProxyObjectVar(); + if (!object) { + NOTREACHED(); + return; + } + + DCHECK(iter->second.ref_count == 0); + + // Got an AddRef for an object we have no existing reference for. + // We need to tell the browser we've taken a ref. This comes up when the + // browser passes an object as an input param and holds a ref for us. + // This must be a sync message since otherwise the "addref" will actually + // occur after the return to the browser of the sync function that + // presumably sent the object. + SendAddRefObjectMsg(*object); +} + +void PluginVarTracker::ObjectGettingZeroRef(VarMap::iterator iter) { + ProxyObjectVar* object = iter->second.var->AsProxyObjectVar(); + if (!object) { + NOTREACHED(); + return; + } + + // Notify the host we're no longer holding our ref. + DCHECK(iter->second.ref_count == 0); + SendReleaseObjectMsg(*object); + + // This will optionally delete the info from live_vars_. + VarTracker::ObjectGettingZeroRef(iter); +} + +bool PluginVarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) { + // Get the info before calling the base class's version of this function, + // which may delete the object. + ProxyObjectVar* object = iter->second.var->AsProxyObjectVar(); + HostVar host_var(object->dispatcher(), object->host_var_id()); + + if (!VarTracker::DeleteObjectInfoIfNecessary(iter)) + return false; + + // Clean up the host var mapping. + DCHECK(host_var_to_plugin_var_.find(host_var) != + host_var_to_plugin_var_.end()); + host_var_to_plugin_var_.erase(host_var); + return true; +} + +PP_Var PluginVarTracker::GetOrCreateObjectVarID(ProxyObjectVar* object) { + // We can't use object->GetPPVar() because we don't want to affect the + // refcount, so we have to add everything manually here. + int32 var_id = object->GetExistingVarID(); + if (!var_id) { + var_id = AddVarInternal(object, ADD_VAR_CREATE_WITH_NO_REFERENCE); + object->AssignVarID(var_id); + } + + PP_Var ret; + ret.type = PP_VARTYPE_OBJECT; + ret.value.as_id = var_id; + return ret; +} + +void PluginVarTracker::SendAddRefObjectMsg( + const ProxyObjectVar& proxy_object) { int unused; - host_var.dispatcher->Send(new PpapiHostMsg_PPBVar_AddRefObject( - INTERFACE_ID_PPB_VAR_DEPRECATED, host_var.host_object_id, &unused)); + proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_AddRefObject( + INTERFACE_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id(), &unused)); } -void PluginVarTracker::SendReleaseObjectMsg(const HostVar& host_var) { - host_var.dispatcher->Send(new PpapiHostMsg_PPBVar_ReleaseObject( - INTERFACE_ID_PPB_VAR_DEPRECATED, host_var.host_object_id)); +void PluginVarTracker::SendReleaseObjectMsg( + const ProxyObjectVar& proxy_object) { + proxy_object.dispatcher()->Send(new PpapiHostMsg_PPBVar_ReleaseObject( + INTERFACE_ID_PPB_VAR_DEPRECATED, proxy_object.host_var_id())); } -PluginVarTracker::PluginVarInfoMap::iterator -PluginVarTracker::FindOrMakePluginVarFromHostVar(const PP_Var& var, - PluginDispatcher* dispatcher) { +scoped_refptr<ProxyObjectVar> PluginVarTracker::FindOrMakePluginVarFromHostVar( + const PP_Var& var, + PluginDispatcher* dispatcher) { DCHECK(var.type == PP_VARTYPE_OBJECT); HostVar host_var(dispatcher, var.value.as_id); HostVarToPluginVarMap::iterator found = host_var_to_plugin_var_.find(host_var); - if (found != host_var_to_plugin_var_.end()) { - PluginVarInfoMap::iterator ret = plugin_var_info_.find(found->second); - DCHECK(ret != plugin_var_info_.end()); - return ret; // Already know about this var return the ID. + if (found == host_var_to_plugin_var_.end()) { + // Create a new object. + return scoped_refptr<ProxyObjectVar>( + new ProxyObjectVar(dispatcher, static_cast<int32>(var.value.as_id))); } - // Make a new var, adding references to both maps. - VarID new_plugin_var_id = GetNewVarID(); - host_var_to_plugin_var_[host_var] = new_plugin_var_id; - return plugin_var_info_.insert( - std::make_pair(new_plugin_var_id, PluginVarInfo(host_var))).first; -} - -void PluginVarTracker::DeletePluginVarInfoIfNecessary( - PluginVarInfoMap::iterator iter) { - if (iter->second.ref_count != 0 || - iter->second.track_with_no_reference_count != 0) - return; // Object still alive. - - // Object ref counts are all zero, delete from both maps. - DCHECK(host_var_to_plugin_var_.find(iter->second.host_var) != - host_var_to_plugin_var_.end()); - host_var_to_plugin_var_.erase(iter->second.host_var); - plugin_var_info_.erase(iter); -} + // Have this host var, look up the object. + VarMap::iterator ret = live_vars_.find(found->second); + DCHECK(ret != live_vars_.end()); -PluginVarTracker::VarID PluginVarTracker::GetNewVarID() { - if (last_plugin_var_id_ == std::numeric_limits<VarID>::max()) - last_plugin_var_id_ = 0; - return ++last_plugin_var_id_; + // All objects should be proxy objects. + DCHECK(ret->second.var->AsProxyObjectVar()); + return scoped_refptr<ProxyObjectVar>(ret->second.var->AsProxyObjectVar()); } } // namesace proxy |