Index: ppapi/proxy/plugin_var_tracker.cc |
=================================================================== |
--- ppapi/proxy/plugin_var_tracker.cc (revision 96002) |
+++ ppapi/proxy/plugin_var_tracker.cc (working copy) |
@@ -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 @@ |
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() { |
} |
-PluginVarTracker::PluginVarTracker() : last_plugin_var_id_(0) { |
-} |
- |
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); |
+ DCHECK(host_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(); |
- } |
+ // Get the object. |
+ scoped_refptr<ProxyObjectVar> object( |
+ FindOrMakePluginVarFromHostVar(host_var, dispatcher)); |
- // 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++; |
- } |
+ // 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; |
+ 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); |
+ } |
+ info.ref_count++; |
return ret; |
} |
@@ -196,58 +67,66 @@ |
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,86 +134,146 @@ |
// 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; |
-} |
+ // Have this host var, look up the object. |
+ VarMap::iterator ret = live_vars_.find(found->second); |
+ DCHECK(ret != live_vars_.end()); |
-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); |
+ // All objects should be proxy objects. |
+ DCHECK(ret->second.var->AsProxyObjectVar()); |
+ return scoped_refptr<ProxyObjectVar>(ret->second.var->AsProxyObjectVar()); |
} |
-PluginVarTracker::VarID PluginVarTracker::GetNewVarID() { |
- if (last_plugin_var_id_ == std::numeric_limits<VarID>::max()) |
- last_plugin_var_id_ = 0; |
- return ++last_plugin_var_id_; |
-} |
- |
} // namesace proxy |
} // namespace pp |