| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ppapi/proxy/plugin_var_tracker.h" | 5 #include "ppapi/proxy/plugin_var_tracker.h" |
| 6 | 6 |
| 7 #include "base/memory/ref_counted.h" | 7 #include "base/memory/ref_counted.h" |
| 8 #include "base/memory/singleton.h" | 8 #include "base/memory/singleton.h" |
| 9 #include "ppapi/c/ppb_var.h" | 9 #include "ppapi/c/ppb_var.h" |
| 10 #include "ppapi/proxy/plugin_dispatcher.h" | 10 #include "ppapi/proxy/plugin_dispatcher.h" |
| 11 #include "ppapi/proxy/ppapi_messages.h" | 11 #include "ppapi/proxy/ppapi_messages.h" |
| 12 #include "ppapi/proxy/interface_id.h" | 12 #include "ppapi/proxy/interface_id.h" |
| 13 | 13 |
| 14 namespace pp { | 14 namespace pp { |
| 15 namespace proxy { | 15 namespace proxy { |
| 16 | 16 |
| 17 namespace { | 17 namespace { |
| 18 | 18 |
| 19 // When non-NULL, this object overrides the VarTrackerSingleton. | 19 // When non-NULL, this object overrides the VarTrackerSingleton. |
| 20 PluginVarTracker* var_tracker_override = NULL; | 20 PluginVarTracker* var_tracker_override = NULL; |
| 21 | 21 |
| 22 class RefCountedString : public base::RefCounted<RefCountedString> { | |
| 23 public: | |
| 24 RefCountedString() { | |
| 25 } | |
| 26 RefCountedString(const std::string& str) : value_(str) { | |
| 27 } | |
| 28 RefCountedString(const char* data, size_t len) | |
| 29 : value_(data, len) { | |
| 30 } | |
| 31 | |
| 32 const std::string& value() const { return value_; } | |
| 33 | |
| 34 private: | |
| 35 std::string value_; | |
| 36 }; | |
| 37 | |
| 38 // When running in the plugin, this will convert the string ID to the object | |
| 39 // using casting. No validity checking is done. | |
| 40 RefCountedString* PluginStringFromID(PluginVarTracker::VarID id) { | |
| 41 return reinterpret_cast<RefCountedString*>(static_cast<intptr_t>(id)); | |
| 42 } | |
| 43 | |
| 44 } // namespace | 22 } // namespace |
| 45 | 23 |
| 46 PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, VarID i) | 24 PluginVarTracker::HostVar::HostVar(PluginDispatcher* d, VarID i) |
| 47 : dispatcher(d), | 25 : dispatcher(d), |
| 48 host_object_id(i) { | 26 host_object_id(i) { |
| 49 } | 27 } |
| 50 | 28 |
| 51 bool PluginVarTracker::HostVar::operator<(const HostVar& other) const { | 29 bool PluginVarTracker::HostVar::operator<(const HostVar& other) const { |
| 52 if (dispatcher < other.dispatcher) | 30 if (dispatcher < other.dispatcher) |
| 53 return true; | 31 return true; |
| 54 if (other.dispatcher < dispatcher) | 32 if (other.dispatcher < dispatcher) |
| 55 return false; | 33 return false; |
| 56 return host_object_id < other.host_object_id; | 34 return host_object_id < other.host_object_id; |
| 57 } | 35 } |
| 58 | 36 |
| 59 PluginVarTracker::PluginVarInfo::PluginVarInfo(const HostVar& host_var) | 37 PluginVarTracker::PluginVarInfo::PluginVarInfo(const HostVar& host_var) |
| 60 : host_var(host_var), | 38 : host_var(host_var), |
| 61 ref_count(0), | 39 ref_count(0), |
| 62 track_with_no_reference_count(0) { | 40 track_with_no_reference_count(0) { |
| 63 } | 41 } |
| 64 | 42 |
| 65 PluginVarTracker::PluginVarTracker() : last_plugin_object_id_(0) { | 43 PluginVarTracker::PluginVarTracker() : last_plugin_var_id_(0) { |
| 66 } | 44 } |
| 67 | 45 |
| 68 PluginVarTracker::~PluginVarTracker() { | 46 PluginVarTracker::~PluginVarTracker() { |
| 69 } | 47 } |
| 70 | 48 |
| 71 // static | 49 // static |
| 72 void PluginVarTracker::SetInstanceForTest(PluginVarTracker* tracker) { | 50 void PluginVarTracker::SetInstanceForTest(PluginVarTracker* tracker) { |
| 73 var_tracker_override = tracker; | 51 var_tracker_override = tracker; |
| 74 } | 52 } |
| 75 | 53 |
| 76 // static | 54 // static |
| 77 PluginVarTracker* PluginVarTracker::GetInstance() { | 55 PluginVarTracker* PluginVarTracker::GetInstance() { |
| 78 if (var_tracker_override) | 56 if (var_tracker_override) |
| 79 return var_tracker_override; | 57 return var_tracker_override; |
| 80 return Singleton<PluginVarTracker>::get(); | 58 return Singleton<PluginVarTracker>::get(); |
| 81 } | 59 } |
| 82 | 60 |
| 83 PluginVarTracker::VarID PluginVarTracker::MakeString(const std::string& str) { | 61 PluginVarTracker::VarID PluginVarTracker::MakeString(const std::string& str) { |
| 84 RefCountedString* out = new RefCountedString(str); | 62 return MakeString(str.c_str(), str.length()); |
| 85 out->AddRef(); | |
| 86 return static_cast<VarID>(reinterpret_cast<intptr_t>(out)); | |
| 87 } | 63 } |
| 88 | 64 |
| 89 PluginVarTracker::VarID PluginVarTracker::MakeString(const char* str, | 65 PluginVarTracker::VarID PluginVarTracker::MakeString(const char* str, |
| 90 uint32_t len) { | 66 uint32_t len) { |
| 91 RefCountedString* out = new RefCountedString(str, len); | 67 std::pair<VarIDStringMap::iterator, bool> |
| 92 out->AddRef(); | 68 iter_success_pair(var_id_to_string_.end(), false); |
| 93 return static_cast<VarID>(reinterpret_cast<intptr_t>(out)); | 69 VarID new_id(0); |
| 94 } | 70 RefCountedStringPtr str_ptr(new RefCountedString(str, len)); |
| 95 | 71 // Pick new IDs until one is successfully inserted. This loop is very unlikely |
| 96 std::string PluginVarTracker::GetString(const PP_Var& var) const { | 72 // to ever run a 2nd time, since we have ~2^63 possible IDs to exhaust. |
| 97 return PluginStringFromID(var.value.as_id)->value(); | 73 while (!iter_success_pair.second) { |
| 74 new_id = GetNewVarID(); |
| 75 iter_success_pair = |
| 76 var_id_to_string_.insert(VarIDStringMap::value_type(new_id, str_ptr)); |
| 77 } |
| 78 iter_success_pair.first->second->AddRef(); |
| 79 return new_id; |
| 98 } | 80 } |
| 99 | 81 |
| 100 const std::string* PluginVarTracker::GetExistingString( | 82 const std::string* PluginVarTracker::GetExistingString( |
| 101 const PP_Var& var) const { | 83 const PP_Var& var) const { |
| 102 if (var.type != PP_VARTYPE_STRING) | 84 if (var.type != PP_VARTYPE_STRING) |
| 103 return NULL; | 85 return NULL; |
| 104 RefCountedString* str = PluginStringFromID(var.value.as_id); | 86 VarIDStringMap::const_iterator found = |
| 105 return &str->value(); | 87 var_id_to_string_.find(var.value.as_id); |
| 88 if (found != var_id_to_string_.end()) |
| 89 return &found->second->value(); |
| 90 return NULL; |
| 106 } | 91 } |
| 107 | 92 |
| 108 void PluginVarTracker::AddRef(const PP_Var& var) { | 93 void PluginVarTracker::AddRef(const PP_Var& var) { |
| 109 if (var.type == PP_VARTYPE_STRING) { | 94 if (var.type == PP_VARTYPE_STRING) { |
| 110 PluginStringFromID(var.value.as_id)->AddRef(); | 95 VarIDStringMap::iterator found = var_id_to_string_.find(var.value.as_id); |
| 96 if (found == var_id_to_string_.end()) { |
| 97 NOTREACHED() << "Requesting to addref an unknown string."; |
| 98 return; |
| 99 } |
| 100 found->second->AddRef(); |
| 111 } else if (var.type == PP_VARTYPE_OBJECT && var.value.as_id != 0) { | 101 } else if (var.type == PP_VARTYPE_OBJECT && var.value.as_id != 0) { |
| 112 PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); | 102 PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); |
| 113 if (found == plugin_var_info_.end()) { | 103 if (found == plugin_var_info_.end()) { |
| 114 NOTREACHED() << "Requesting to addref an unknown object."; | 104 NOTREACHED() << "Requesting to addref an unknown object."; |
| 115 return; | 105 return; |
| 116 } | 106 } |
| 117 | 107 |
| 118 PluginVarInfo& info = found->second; | 108 PluginVarInfo& info = found->second; |
| 119 if (info.ref_count == 0) { | 109 if (info.ref_count == 0) { |
| 120 // Got an AddRef for an object we have no existing reference for. | 110 // Got an AddRef for an object we have no existing reference for. |
| 121 // We need to tell the browser we've taken a ref. This comes up when the | 111 // We need to tell the browser we've taken a ref. This comes up when the |
| 122 // browser passes an object as an input param and holds a ref for us. | 112 // browser passes an object as an input param and holds a ref for us. |
| 123 // This must be a sync message since otherwise the "addref" will actually | 113 // This must be a sync message since otherwise the "addref" will actually |
| 124 // occur after the return to the browser of the sync function that | 114 // occur after the return to the browser of the sync function that |
| 125 // presumably sent the object. | 115 // presumably sent the object. |
| 126 SendAddRefObjectMsg(info.host_var); | 116 SendAddRefObjectMsg(info.host_var); |
| 127 } | 117 } |
| 128 info.ref_count++; | 118 info.ref_count++; |
| 129 } | 119 } |
| 130 } | 120 } |
| 131 | 121 |
| 132 void PluginVarTracker::Release(const PP_Var& var) { | 122 void PluginVarTracker::Release(const PP_Var& var) { |
| 133 if (var.type == PP_VARTYPE_STRING) { | 123 if (var.type == PP_VARTYPE_STRING) { |
| 134 PluginStringFromID(var.value.as_id)->Release(); | 124 VarIDStringMap::iterator found = var_id_to_string_.find(var.value.as_id); |
| 125 if (found == var_id_to_string_.end()) { |
| 126 NOTREACHED() << "Requesting to release an unknown string."; |
| 127 return; |
| 128 } |
| 129 found->second->Release(); |
| 130 // If there is only 1 reference left, it's the map's reference. Erase it |
| 131 // from the map, which will delete the string. |
| 132 if (found->second->HasOneRef()) |
| 133 var_id_to_string_.erase(found); |
| 135 } else if (var.type == PP_VARTYPE_OBJECT) { | 134 } else if (var.type == PP_VARTYPE_OBJECT) { |
| 136 PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); | 135 PluginVarInfoMap::iterator found = plugin_var_info_.find(var.value.as_id); |
| 137 if (found == plugin_var_info_.end()) { | 136 if (found == plugin_var_info_.end()) { |
| 138 NOTREACHED() << "Requesting to release an unknown object."; | 137 NOTREACHED() << "Requesting to release an unknown object."; |
| 139 return; | 138 return; |
| 140 } | 139 } |
| 141 | 140 |
| 142 PluginVarInfo& info = found->second; | 141 PluginVarInfo& info = found->second; |
| 143 if (info.ref_count == 0) { | 142 if (info.ref_count == 0) { |
| 144 NOTREACHED() << "Releasing an object with zero ref."; | 143 NOTREACHED() << "Releasing an object with zero ref."; |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 | 300 |
| 302 HostVarToPluginVarMap::iterator found = | 301 HostVarToPluginVarMap::iterator found = |
| 303 host_var_to_plugin_var_.find(host_var); | 302 host_var_to_plugin_var_.find(host_var); |
| 304 if (found != host_var_to_plugin_var_.end()) { | 303 if (found != host_var_to_plugin_var_.end()) { |
| 305 PluginVarInfoMap::iterator ret = plugin_var_info_.find(found->second); | 304 PluginVarInfoMap::iterator ret = plugin_var_info_.find(found->second); |
| 306 DCHECK(ret != plugin_var_info_.end()); | 305 DCHECK(ret != plugin_var_info_.end()); |
| 307 return ret; // Already know about this var return the ID. | 306 return ret; // Already know about this var return the ID. |
| 308 } | 307 } |
| 309 | 308 |
| 310 // Make a new var, adding references to both maps. | 309 // Make a new var, adding references to both maps. |
| 311 VarID new_plugin_var_id = ++last_plugin_object_id_; | 310 VarID new_plugin_var_id = GetNewVarID(); |
| 312 host_var_to_plugin_var_[host_var] = new_plugin_var_id; | 311 host_var_to_plugin_var_[host_var] = new_plugin_var_id; |
| 313 return plugin_var_info_.insert( | 312 return plugin_var_info_.insert( |
| 314 std::make_pair(new_plugin_var_id, PluginVarInfo(host_var))).first; | 313 std::make_pair(new_plugin_var_id, PluginVarInfo(host_var))).first; |
| 315 } | 314 } |
| 316 | 315 |
| 317 void PluginVarTracker::DeletePluginVarInfoIfNecessary( | 316 void PluginVarTracker::DeletePluginVarInfoIfNecessary( |
| 318 PluginVarInfoMap::iterator iter) { | 317 PluginVarInfoMap::iterator iter) { |
| 319 if (iter->second.ref_count != 0 || | 318 if (iter->second.ref_count != 0 || |
| 320 iter->second.track_with_no_reference_count != 0) | 319 iter->second.track_with_no_reference_count != 0) |
| 321 return; // Object still alive. | 320 return; // Object still alive. |
| 322 | 321 |
| 323 // Object ref counts are all zero, delete from both maps. | 322 // Object ref counts are all zero, delete from both maps. |
| 324 DCHECK(host_var_to_plugin_var_.find(iter->second.host_var) != | 323 DCHECK(host_var_to_plugin_var_.find(iter->second.host_var) != |
| 325 host_var_to_plugin_var_.end()); | 324 host_var_to_plugin_var_.end()); |
| 326 host_var_to_plugin_var_.erase(iter->second.host_var); | 325 host_var_to_plugin_var_.erase(iter->second.host_var); |
| 327 plugin_var_info_.erase(iter); | 326 plugin_var_info_.erase(iter); |
| 328 } | 327 } |
| 329 | 328 |
| 329 PluginVarTracker::VarID PluginVarTracker::GetNewVarID() { |
| 330 if (last_plugin_var_id_ == std::numeric_limits<VarID>::max()) |
| 331 last_plugin_var_id_ = 0; |
| 332 return ++last_plugin_var_id_; |
| 333 } |
| 334 |
| 330 } // namesace proxy | 335 } // namesace proxy |
| 331 } // namespace pp | 336 } // namespace pp |
| OLD | NEW |