| 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
|
|
|