blob: 7fabb80641cc7a12942180855f6bfe335985860e [file] [log] [blame]
[email protected]73097562012-01-12 19:38:551// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]2bbd2c672011-08-09 23:14:132// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/shared_impl/var_tracker.h"
6
[email protected]10305deb2012-02-16 19:39:227#include <string.h>
8
[email protected]2bbd2c672011-08-09 23:14:139#include <limits>
10
11#include "base/logging.h"
[email protected]8299b712013-07-17 19:55:2312#include "base/memory/shared_memory.h"
[email protected]30e1cb752013-03-19 20:42:3313#include "ppapi/shared_impl/host_resource.h"
[email protected]2bbd2c672011-08-09 23:14:1314#include "ppapi/shared_impl/id_assignment.h"
[email protected]712835ff2013-02-26 04:54:2215#include "ppapi/shared_impl/proxy_lock.h"
[email protected]c82b0142013-09-23 15:09:2116#include "ppapi/shared_impl/resource_var.h"
[email protected]2bbd2c672011-08-09 23:14:1317#include "ppapi/shared_impl/var.h"
18
19namespace ppapi {
20
21VarTracker::VarInfo::VarInfo()
[email protected]665b5c542014-02-22 08:06:2622 : var(), ref_count(0), track_with_no_reference_count(0) {}
[email protected]2bbd2c672011-08-09 23:14:1323
24VarTracker::VarInfo::VarInfo(Var* v, int input_ref_count)
[email protected]665b5c542014-02-22 08:06:2625 : var(v), ref_count(input_ref_count), track_with_no_reference_count(0) {}
[email protected]2bbd2c672011-08-09 23:14:1326
[email protected]b73c6592013-03-30 17:08:1327VarTracker::VarTracker(ThreadMode thread_mode) : last_var_id_(0) {
28 if (thread_mode == SINGLE_THREADED)
29 thread_checker_.reset(new base::ThreadChecker);
[email protected]2bbd2c672011-08-09 23:14:1330}
31
[email protected]665b5c542014-02-22 08:06:2632VarTracker::~VarTracker() {}
[email protected]2bbd2c672011-08-09 23:14:1333
[email protected]b73c6592013-03-30 17:08:1334void VarTracker::CheckThreadingPreconditions() const {
35 DCHECK(!thread_checker_ || thread_checker_->CalledOnValidThread());
36#ifndef NDEBUG
[email protected]41e52fb52013-03-29 20:27:1637 ProxyLock::AssertAcquired();
[email protected]b73c6592013-03-30 17:08:1338#endif
39}
40
41int32 VarTracker::AddVar(Var* var) {
42 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:2443
[email protected]2bbd2c672011-08-09 23:14:1344 return AddVarInternal(var, ADD_VAR_TAKE_ONE_REFERENCE);
45}
46
47Var* VarTracker::GetVar(int32 var_id) const {
[email protected]b73c6592013-03-30 17:08:1348 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:2449
[email protected]2bbd2c672011-08-09 23:14:1350 VarMap::const_iterator result = live_vars_.find(var_id);
51 if (result == live_vars_.end())
52 return NULL;
53 return result->second.var.get();
54}
55
56Var* VarTracker::GetVar(const PP_Var& var) const {
[email protected]b73c6592013-03-30 17:08:1357 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:2458
[email protected]2bbd2c672011-08-09 23:14:1359 if (!IsVarTypeRefcounted(var.type))
60 return NULL;
61 return GetVar(static_cast<int32>(var.value.as_id));
62}
63
64bool VarTracker::AddRefVar(int32 var_id) {
[email protected]b73c6592013-03-30 17:08:1365 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:2466
[email protected]2bbd2c672011-08-09 23:14:1367 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
68 << var_id << " is not a PP_Var ID.";
69 VarMap::iterator found = live_vars_.find(var_id);
70 if (found == live_vars_.end()) {
71 NOTREACHED(); // Invalid var.
72 return false;
73 }
74
75 VarInfo& info = found->second;
76 if (info.ref_count == 0) {
77 // All live vars with no refcount should be tracked objects.
78 DCHECK(info.track_with_no_reference_count > 0);
79 DCHECK(info.var->GetType() == PP_VARTYPE_OBJECT);
80
81 TrackedObjectGettingOneRef(found);
82 }
83
84 // Basic refcount increment.
85 info.ref_count++;
86 return true;
87}
88
89bool VarTracker::AddRefVar(const PP_Var& var) {
[email protected]b73c6592013-03-30 17:08:1390 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:2491
[email protected]2bbd2c672011-08-09 23:14:1392 if (!IsVarTypeRefcounted(var.type))
[email protected]d9e5f4122013-03-18 20:42:5093 return true;
[email protected]2bbd2c672011-08-09 23:14:1394 return AddRefVar(static_cast<int32>(var.value.as_id));
95}
96
97bool VarTracker::ReleaseVar(int32 var_id) {
[email protected]b73c6592013-03-30 17:08:1398 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:2499
[email protected]2bbd2c672011-08-09 23:14:13100 DLOG_IF(ERROR, !CheckIdType(var_id, PP_ID_TYPE_VAR))
101 << var_id << " is not a PP_Var ID.";
102 VarMap::iterator found = live_vars_.find(var_id);
[email protected]aa976442012-04-25 20:20:19103 if (found == live_vars_.end())
[email protected]2bbd2c672011-08-09 23:14:13104 return false;
[email protected]2bbd2c672011-08-09 23:14:13105
106 VarInfo& info = found->second;
107 if (info.ref_count == 0) {
108 NOTREACHED() << "Releasing an object with zero ref";
109 return false;
110 }
111 info.ref_count--;
112
113 if (info.ref_count == 0) {
[email protected]e8c44e62013-05-13 20:06:06114 // Hold a reference to the Var until it is erased so that we don't re-enter
115 // live_vars_.erase() during deletion.
116 // TODO(raymes): Make deletion of Vars iterative instead of recursive.
117 scoped_refptr<Var> var(info.var);
118 if (var->GetType() == PP_VARTYPE_OBJECT) {
[email protected]2bbd2c672011-08-09 23:14:13119 // Objects have special requirements and may not necessarily be released
120 // when the refcount goes to 0.
121 ObjectGettingZeroRef(found);
122 } else {
123 // All other var types can just be released.
124 DCHECK(info.track_with_no_reference_count == 0);
[email protected]e8c44e62013-05-13 20:06:06125 var->ResetVarID();
[email protected]2bbd2c672011-08-09 23:14:13126 live_vars_.erase(found);
127 }
128 }
129 return true;
130}
131
132bool VarTracker::ReleaseVar(const PP_Var& var) {
[email protected]b73c6592013-03-30 17:08:13133 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:24134
[email protected]2bbd2c672011-08-09 23:14:13135 if (!IsVarTypeRefcounted(var.type))
136 return false;
137 return ReleaseVar(static_cast<int32>(var.value.as_id));
138}
139
140int32 VarTracker::AddVarInternal(Var* var, AddVarRefMode mode) {
141 // If the plugin manages to create millions of strings.
142 if (last_var_id_ == std::numeric_limits<int32>::max() >> kPPIdTypeBits)
143 return 0;
144
145 int32 new_id = MakeTypedId(++last_var_id_, PP_ID_TYPE_VAR);
[email protected]e8c44e62013-05-13 20:06:06146 std::pair<VarMap::iterator, bool> was_inserted =
[email protected]665b5c542014-02-22 08:06:26147 live_vars_.insert(std::make_pair(
148 new_id, VarInfo(var, mode == ADD_VAR_TAKE_ONE_REFERENCE ? 1 : 0)));
[email protected]e8c44e62013-05-13 20:06:06149 // We should never insert an ID that already exists.
150 DCHECK(was_inserted.second);
[email protected]2bbd2c672011-08-09 23:14:13151
152 return new_id;
153}
154
155VarTracker::VarMap::iterator VarTracker::GetLiveVar(int32 id) {
156 return live_vars_.find(id);
157}
158
[email protected]73097562012-01-12 19:38:55159int VarTracker::GetRefCountForObject(const PP_Var& plugin_object) {
[email protected]b73c6592013-03-30 17:08:13160 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:24161
[email protected]73097562012-01-12 19:38:55162 VarMap::iterator found = GetLiveVar(plugin_object);
163 if (found == live_vars_.end())
164 return -1;
165 return found->second.ref_count;
166}
167
168int VarTracker::GetTrackedWithNoReferenceCountForObject(
169 const PP_Var& plugin_object) {
[email protected]b73c6592013-03-30 17:08:13170 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:24171
[email protected]73097562012-01-12 19:38:55172 VarMap::iterator found = GetLiveVar(plugin_object);
173 if (found == live_vars_.end())
174 return -1;
175 return found->second.track_with_no_reference_count;
176}
177
[email protected]42a37482013-04-17 17:51:06178// static
179bool VarTracker::IsVarTypeRefcounted(PP_VarType type) {
180 return type >= PP_VARTYPE_STRING;
181}
182
[email protected]2bbd2c672011-08-09 23:14:13183VarTracker::VarMap::iterator VarTracker::GetLiveVar(const PP_Var& var) {
184 return live_vars_.find(static_cast<int32>(var.value.as_id));
185}
186
[email protected]665b5c542014-02-22 08:06:26187VarTracker::VarMap::const_iterator VarTracker::GetLiveVar(const PP_Var& var)
188 const {
[email protected]2bbd2c672011-08-09 23:14:13189 return live_vars_.find(static_cast<int32>(var.value.as_id));
190}
191
[email protected]8cc26a42011-12-15 21:22:31192PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes) {
[email protected]b73c6592013-03-30 17:08:13193 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:24194
[email protected]8cc26a42011-12-15 21:22:31195 scoped_refptr<ArrayBufferVar> array_buffer(CreateArrayBuffer(size_in_bytes));
[email protected]f0c86242013-06-02 21:25:43196 if (!array_buffer.get())
[email protected]8cc26a42011-12-15 21:22:31197 return PP_MakeNull();
198 return array_buffer->GetPPVar();
[email protected]2bbd2c672011-08-09 23:14:13199}
200
[email protected]10305deb2012-02-16 19:39:22201PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes,
202 const void* data) {
[email protected]b73c6592013-03-30 17:08:13203 CheckThreadingPreconditions();
[email protected]712835ff2013-02-26 04:54:22204
[email protected]8ced4f3f2013-02-04 16:53:07205 ArrayBufferVar* array_buffer = MakeArrayBufferVar(size_in_bytes, data);
206 return array_buffer ? array_buffer->GetPPVar() : PP_MakeNull();
207}
[email protected]a5717f032013-02-02 03:37:59208
[email protected]8ced4f3f2013-02-04 16:53:07209ArrayBufferVar* VarTracker::MakeArrayBufferVar(uint32 size_in_bytes,
210 const void* data) {
[email protected]b73c6592013-03-30 17:08:13211 CheckThreadingPreconditions();
[email protected]712835ff2013-02-26 04:54:22212
[email protected]8ced4f3f2013-02-04 16:53:07213 ArrayBufferVar* array_buffer(CreateArrayBuffer(size_in_bytes));
[email protected]10305deb2012-02-16 19:39:22214 if (!array_buffer)
[email protected]8ced4f3f2013-02-04 16:53:07215 return NULL;
[email protected]10305deb2012-02-16 19:39:22216 memcpy(array_buffer->Map(), data, size_in_bytes);
[email protected]8ced4f3f2013-02-04 16:53:07217 return array_buffer;
[email protected]10305deb2012-02-16 19:39:22218}
219
[email protected]30e1cb752013-03-19 20:42:33220PP_Var VarTracker::MakeArrayBufferPPVar(uint32 size_in_bytes,
221 base::SharedMemoryHandle handle) {
[email protected]b73c6592013-03-30 17:08:13222 CheckThreadingPreconditions();
[email protected]30e1cb752013-03-19 20:42:33223
224 scoped_refptr<ArrayBufferVar> array_buffer(
225 CreateShmArrayBuffer(size_in_bytes, handle));
[email protected]f0c86242013-06-02 21:25:43226 if (!array_buffer.get())
[email protected]30e1cb752013-03-19 20:42:33227 return PP_MakeNull();
228 return array_buffer->GetPPVar();
229}
230
[email protected]c82b0142013-09-23 15:09:21231PP_Var VarTracker::MakeResourcePPVar(PP_Resource pp_resource) {
232 CheckThreadingPreconditions();
233
234 ResourceVar* resource_var = MakeResourceVar(pp_resource);
235 return resource_var ? resource_var->GetPPVar() : PP_MakeNull();
236}
237
[email protected]a732cec2011-12-22 08:35:52238std::vector<PP_Var> VarTracker::GetLiveVars() {
[email protected]b73c6592013-03-30 17:08:13239 CheckThreadingPreconditions();
[email protected]cf9a5302012-03-21 01:35:24240
[email protected]a732cec2011-12-22 08:35:52241 std::vector<PP_Var> var_vector;
242 var_vector.reserve(live_vars_.size());
243 for (VarMap::const_iterator iter = live_vars_.begin();
244 iter != live_vars_.end();
245 ++iter) {
246 var_vector.push_back(iter->second.var->GetPPVar());
247 }
248 return var_vector;
249}
250
[email protected]2bbd2c672011-08-09 23:14:13251void VarTracker::TrackedObjectGettingOneRef(VarMap::const_iterator obj) {
252 // Anybody using tracked objects should override this.
253 NOTREACHED();
254}
255
256void VarTracker::ObjectGettingZeroRef(VarMap::iterator iter) {
257 DeleteObjectInfoIfNecessary(iter);
258}
259
260bool VarTracker::DeleteObjectInfoIfNecessary(VarMap::iterator iter) {
261 if (iter->second.ref_count != 0 ||
262 iter->second.track_with_no_reference_count != 0)
263 return false; // Object still alive.
[email protected]e0c18c72011-12-16 07:09:59264 iter->second.var->ResetVarID();
[email protected]2bbd2c672011-08-09 23:14:13265 live_vars_.erase(iter);
266 return true;
267}
268
269} // namespace ppapi