From edb5b05700f53fb7b1827727777cc15b50370ccb Mon Sep 17 00:00:00 2001 From: "brettw@chromium.org" Date: Mon, 18 Jun 2012 19:41:30 +0000 Subject: Actually free plugin implement vars when running out of process when the plugin holds a reference beyond the lifetime of the instance. Review URL: https://chromiumcodereview.appspot.com/10542150 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142787 0039d316-1c4b-4281-b951-d872f2087c98 --- ppapi/proxy/plugin_var_tracker.cc | 90 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'ppapi/proxy/plugin_var_tracker.cc') diff --git a/ppapi/proxy/plugin_var_tracker.cc b/ppapi/proxy/plugin_var_tracker.cc index 74cd557..52ecad8 100644 --- a/ppapi/proxy/plugin_var_tracker.cc +++ b/ppapi/proxy/plugin_var_tracker.cc @@ -6,6 +6,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/singleton.h" +#include "ppapi/c/dev/ppp_class_deprecated.h" #include "ppapi/c/ppb_var.h" #include "ppapi/proxy/plugin_array_buffer_var.h" #include "ppapi/proxy/plugin_dispatcher.h" @@ -151,10 +152,79 @@ void PluginVarTracker::ReleaseHostObject(PluginDispatcher* dispatcher, ReleaseVar(found->second); } +void PluginVarTracker::DidDeleteInstance(PP_Instance instance) { + // See the comment above user_data_to_plugin_ in the header file. We assume + // there aren't that many objects so a brute-force search is reasonable. + UserDataToPluginImplementedVarMap::iterator i = + user_data_to_plugin_.begin(); + while (i != user_data_to_plugin_.end()) { + if (i->second.instance == instance) { + if (!i->second.plugin_object_id) { + // This object is for the freed instance and the plugin is not holding + // any references to it. Deallocate immediately. + UserDataToPluginImplementedVarMap::iterator to_remove = i; + ++i; + to_remove->second.ppp_class->Deallocate(to_remove->first); + user_data_to_plugin_.erase(to_remove); + } else { + // The plugin is holding refs to this object. We don't want to call + // Deallocate since the plugin may be depending on those refs to keep + // its data alive. To avoid crashes in this case, just clear out the + // instance to mark it and continue. When the plugin refs go to 0, + // we'll notice there is no instance and call Deallocate. + i->second.instance = 0; + ++i; + } + } else { + ++i; + } + } +} + ArrayBufferVar* PluginVarTracker::CreateArrayBuffer(uint32 size_in_bytes) { return new PluginArrayBufferVar(size_in_bytes); } +void PluginVarTracker::PluginImplementedObjectCreated( + PP_Instance instance, + const PP_Var& created_var, + const PPP_Class_Deprecated* ppp_class, + void* ppp_class_data) { + PluginImplementedVar p; + p.ppp_class = ppp_class; + p.instance = instance; + p.plugin_object_id = created_var.value.as_id; + user_data_to_plugin_[ppp_class_data] = p; + + // Link the user data to the object. + ProxyObjectVar* object = GetVar(created_var)->AsProxyObjectVar(); + object->set_user_data(ppp_class_data); +} + +void PluginVarTracker::PluginImplementedObjectDestroyed(void* user_data) { + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(user_data); + if (found == user_data_to_plugin_.end()) { + NOTREACHED(); + return; + } + user_data_to_plugin_.erase(found); +} + +bool PluginVarTracker::IsPluginImplementedObjectAlive(void* user_data) { + return user_data_to_plugin_.find(user_data) != user_data_to_plugin_.end(); +} + +bool PluginVarTracker::ValidatePluginObjectCall( + const PPP_Class_Deprecated* ppp_class, + void* user_data) { + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(user_data); + if (found == user_data_to_plugin_.end()) + return false; + return found->second.ppp_class == ppp_class; +} + int32 PluginVarTracker::AddVarInternal(Var* var, AddVarRefMode mode) { // Normal adding. int32 new_id = VarTracker::AddVarInternal(var, mode); @@ -200,6 +270,26 @@ void PluginVarTracker::ObjectGettingZeroRef(VarMap::iterator iter) { DCHECK(iter->second.ref_count == 0); SendReleaseObjectMsg(*object); + UserDataToPluginImplementedVarMap::iterator found = + user_data_to_plugin_.find(object->user_data()); + if (found != user_data_to_plugin_.end()) { + // This object is implemented in the plugin. + if (found->second.instance == 0) { + // Instance is destroyed. This means that we'll never get a Deallocate + // call from the renderer and we should do so now. + found->second.ppp_class->Deallocate(found->first); + user_data_to_plugin_.erase(found); + } else { + // The plugin is releasing its last reference to an object it implements. + // Clear the tracking data that links our "plugin implemented object" to + // the var. If the instance is destroyed and there is no ID, we know that + // we should just call Deallocate on the object data. + // + // See the plugin_object_id declaration for more info. + found->second.plugin_object_id = 0; + } + } + // This will optionally delete the info from live_vars_. VarTracker::ObjectGettingZeroRef(iter); } -- cgit v1.1