Use Persistent::Reset.
[chromium-blink-merge.git] / ppapi / proxy / raw_var_data.cc
blobd4ad2799010d650cb1d3100cd8f757e02d82063d
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi/proxy/raw_var_data.h"
7 #include <stack>
9 #include "base/hash_tables.h"
10 #include "base/stl_util.h"
11 #include "ipc/ipc_message.h"
12 #include "ppapi/proxy/ppapi_param_traits.h"
13 #include "ppapi/shared_impl/array_var.h"
14 #include "ppapi/shared_impl/dictionary_var.h"
15 #include "ppapi/shared_impl/ppapi_globals.h"
16 #include "ppapi/shared_impl/scoped_pp_var.h"
17 #include "ppapi/shared_impl/var.h"
18 #include "ppapi/shared_impl/var_tracker.h"
20 using std::make_pair;
22 namespace ppapi {
23 namespace proxy {
25 namespace {
27 // When sending array buffers, if the size is over 256K, we use shared
28 // memory instead of sending the data over IPC. Light testing suggests
29 // shared memory is much faster for 256K and larger messages.
30 static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024;
31 static uint32 g_minimum_array_buffer_size_for_shmem =
32 kMinimumArrayBufferSizeForShmem;
34 void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) {
35 IPC::ParamTraits<SerializedHandle>::Write(m, handle);
38 // For a given PP_Var, returns the RawVarData associated with it, or creates a
39 // new one if there is no existing one. The data is appended to |data| if it
40 // is newly created. The index into |data| pointing to the result is returned.
41 // |id_map| keeps track of RawVarDatas that have already been created.
42 size_t GetOrCreateRawVarData(const PP_Var& var,
43 base::hash_map<int64_t, size_t>* id_map,
44 ScopedVector<RawVarData>* data) {
45 if (VarTracker::IsVarTypeRefcounted(var.type)) {
46 base::hash_map<int64_t, size_t>::iterator it = id_map->find(
47 var.value.as_id);
48 if (it != id_map->end()) {
49 return it->second;
50 } else {
51 data->push_back(RawVarData::Create(var.type));
52 (*id_map)[var.value.as_id] = data->size() - 1;
54 } else {
55 data->push_back(RawVarData::Create(var.type));
57 return data->size() - 1;
60 } // namespace
62 // RawVarDataGraph ------------------------------------------------------------
63 RawVarDataGraph::RawVarDataGraph() {
66 RawVarDataGraph::~RawVarDataGraph() {
69 // static
70 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
71 PP_Instance instance) {
72 scoped_ptr<RawVarDataGraph> graph(new RawVarDataGraph);
73 // Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph.
74 base::hash_map<int64_t, size_t> id_map;
76 std::stack<std::pair<PP_Var, size_t> > stack;
77 stack.push(make_pair(var, GetOrCreateRawVarData(var, &id_map,
78 &graph->data_)));
80 // Traverse the PP_Var graph with DFS.
81 while (!stack.empty()) {
82 PP_Var current_var = stack.top().first;
83 RawVarData* current_var_data = graph->data_[stack.top().second];
84 stack.pop();
86 // If the node is initialized, it means we have visited it.
87 if (current_var_data->initialized())
88 continue;
90 if (!current_var_data->Init(current_var, instance)) {
91 NOTREACHED();
92 return scoped_ptr<RawVarDataGraph>();
95 // Add child nodes to the stack.
96 if (current_var.type == PP_VARTYPE_ARRAY) {
97 ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
98 if (!array_var) {
99 NOTREACHED();
100 return scoped_ptr<RawVarDataGraph>();
102 for (ArrayVar::ElementVector::const_iterator iter =
103 array_var->elements().begin();
104 iter != array_var->elements().end();
105 ++iter) {
106 size_t child_id = GetOrCreateRawVarData(iter->get(), &id_map,
107 &graph->data_);
108 static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id);
109 stack.push(make_pair(iter->get(), child_id));
111 } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
112 DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
113 if (!dict_var) {
114 NOTREACHED();
115 return scoped_ptr<RawVarDataGraph>();
117 for (DictionaryVar::KeyValueMap::const_iterator iter =
118 dict_var->key_value_map().begin();
119 iter != dict_var->key_value_map().end();
120 ++iter) {
121 size_t child_id = GetOrCreateRawVarData(iter->second.get(), &id_map,
122 &graph->data_);
123 static_cast<DictionaryRawVarData*>(
124 current_var_data)->AddChild(iter->first, child_id);
125 stack.push(make_pair(iter->second.get(), child_id));
129 return graph.Pass();
132 PP_Var RawVarDataGraph::CreatePPVar(PP_Instance instance) {
133 // Create and initialize each node in the graph.
134 std::vector<PP_Var> graph;
135 for (size_t i = 0; i < data_.size(); ++i)
136 graph.push_back(data_[i]->CreatePPVar(instance));
137 for (size_t i = 0; i < data_.size(); ++i)
138 data_[i]->PopulatePPVar(graph[i], graph);
139 // Everything except the root will have one extra ref. Remove that ref.
140 for (size_t i = 1; i < data_.size(); ++i)
141 ScopedPPVar(ScopedPPVar::PassRef(), graph[i]);
142 // The first element is the root.
143 return graph[0];
146 void RawVarDataGraph::Write(IPC::Message* m,
147 const HandleWriter& handle_writer) {
148 // Write the size, followed by each node in the graph.
149 m->WriteUInt32(static_cast<uint32_t>(data_.size()));
150 for (size_t i = 0; i < data_.size(); ++i) {
151 m->WriteInt(data_[i]->Type());
152 data_[i]->Write(m, handle_writer);
156 void RawVarDataGraph::Write(IPC::Message* m) {
157 Write(m, base::Bind(&DefaultHandleWriter));
160 // static
161 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m,
162 PickleIterator* iter) {
163 scoped_ptr<RawVarDataGraph> result(new RawVarDataGraph);
164 uint32_t size = 0;
165 if (!m->ReadUInt32(iter, &size))
166 return scoped_ptr<RawVarDataGraph>();
167 for (uint32_t i = 0; i < size; ++i) {
168 int32_t type;
169 if (!m->ReadInt(iter, &type))
170 return scoped_ptr<RawVarDataGraph>();
171 PP_VarType var_type = static_cast<PP_VarType>(type);
172 result->data_.push_back(RawVarData::Create(var_type));
173 if (!result->data_.back()->Read(var_type, m, iter))
174 return scoped_ptr<RawVarDataGraph>();
176 return result.Pass();
179 std::vector<SerializedHandle*> RawVarDataGraph::GetHandles() {
180 std::vector<SerializedHandle*> result;
181 for (size_t i = 0; i < data_.size(); ++i) {
182 SerializedHandle* handle = data_[i]->GetHandle();
183 if (handle)
184 result.push_back(handle);
186 return result;
189 // static
190 void RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(
191 uint32 threshold) {
192 if (threshold == 0)
193 g_minimum_array_buffer_size_for_shmem = kMinimumArrayBufferSizeForShmem;
194 else
195 g_minimum_array_buffer_size_for_shmem = threshold;
198 // RawVarData ------------------------------------------------------------------
200 // static
201 RawVarData* RawVarData::Create(PP_VarType type) {
202 switch (type) {
203 case PP_VARTYPE_UNDEFINED:
204 case PP_VARTYPE_NULL:
205 case PP_VARTYPE_BOOL:
206 case PP_VARTYPE_INT32:
207 case PP_VARTYPE_DOUBLE:
208 case PP_VARTYPE_OBJECT:
209 return new BasicRawVarData();
210 case PP_VARTYPE_STRING:
211 return new StringRawVarData();
212 case PP_VARTYPE_ARRAY_BUFFER:
213 return new ArrayBufferRawVarData();
214 case PP_VARTYPE_ARRAY:
215 return new ArrayRawVarData();
216 case PP_VARTYPE_DICTIONARY:
217 return new DictionaryRawVarData();
219 NOTREACHED();
220 return NULL;
223 RawVarData::RawVarData() : initialized_(false) {
226 RawVarData::~RawVarData() {
229 SerializedHandle* RawVarData::GetHandle() {
230 return NULL;
233 // BasicRawVarData -------------------------------------------------------------
234 BasicRawVarData::BasicRawVarData() {
237 BasicRawVarData::~BasicRawVarData() {
240 PP_VarType BasicRawVarData::Type() {
241 return var_.type;
244 bool BasicRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
245 var_ = var;
246 initialized_ = true;
247 return true;
250 PP_Var BasicRawVarData::CreatePPVar(PP_Instance instance) {
251 return var_;
254 void BasicRawVarData::PopulatePPVar(const PP_Var& var,
255 const std::vector<PP_Var>& graph) {
258 void BasicRawVarData::Write(
259 IPC::Message* m,
260 const HandleWriter& handle_writer) {
261 switch (var_.type) {
262 case PP_VARTYPE_UNDEFINED:
263 case PP_VARTYPE_NULL:
264 // These don't need any data associated with them other than the type we
265 // just serialized.
266 break;
267 case PP_VARTYPE_BOOL:
268 m->WriteBool(PP_ToBool(var_.value.as_bool));
269 break;
270 case PP_VARTYPE_INT32:
271 m->WriteInt(var_.value.as_int);
272 break;
273 case PP_VARTYPE_DOUBLE:
274 IPC::ParamTraits<double>::Write(m, var_.value.as_double);
275 break;
276 case PP_VARTYPE_OBJECT:
277 m->WriteInt64(var_.value.as_id);
278 break;
279 default:
280 NOTREACHED();
281 break;
285 bool BasicRawVarData::Read(PP_VarType type,
286 const IPC::Message* m,
287 PickleIterator* iter) {
288 PP_Var result;
289 result.type = type;
290 switch (type) {
291 case PP_VARTYPE_UNDEFINED:
292 case PP_VARTYPE_NULL:
293 // These don't have any data associated with them other than the type we
294 // just serialized.
295 break;
296 case PP_VARTYPE_BOOL: {
297 bool bool_value;
298 if (!m->ReadBool(iter, &bool_value))
299 return false;
300 result.value.as_bool = PP_FromBool(bool_value);
301 break;
303 case PP_VARTYPE_INT32:
304 if (!m->ReadInt(iter, &result.value.as_int))
305 return false;
306 break;
307 case PP_VARTYPE_DOUBLE:
308 if (!IPC::ParamTraits<double>::Read(m, iter, &result.value.as_double))
309 return false;
310 break;
311 case PP_VARTYPE_OBJECT:
312 if (!m->ReadInt64(iter, &result.value.as_id))
313 return false;
314 break;
315 default:
316 NOTREACHED();
317 return false;
319 var_ = result;
320 return true;
323 // StringRawVarData ------------------------------------------------------------
324 StringRawVarData::StringRawVarData() {
327 StringRawVarData::~StringRawVarData() {
330 PP_VarType StringRawVarData::Type() {
331 return PP_VARTYPE_STRING;
334 bool StringRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
335 DCHECK(var.type == PP_VARTYPE_STRING);
336 StringVar* string_var = StringVar::FromPPVar(var);
337 if (!string_var)
338 return false;
339 data_ = string_var->value();
340 initialized_ = true;
341 return true;
344 PP_Var StringRawVarData::CreatePPVar(PP_Instance instance) {
345 return StringVar::SwapValidatedUTF8StringIntoPPVar(&data_);
348 void StringRawVarData::PopulatePPVar(const PP_Var& var,
349 const std::vector<PP_Var>& graph) {
352 void StringRawVarData::Write(IPC::Message* m,
353 const HandleWriter& handle_writer) {
354 m->WriteString(data_);
357 bool StringRawVarData::Read(PP_VarType type,
358 const IPC::Message* m,
359 PickleIterator* iter) {
360 if (!m->ReadString(iter, &data_))
361 return false;
362 return true;
365 // ArrayBufferRawVarData -------------------------------------------------------
366 ArrayBufferRawVarData::ArrayBufferRawVarData() {
369 ArrayBufferRawVarData::~ArrayBufferRawVarData() {
372 PP_VarType ArrayBufferRawVarData::Type() {
373 return PP_VARTYPE_ARRAY_BUFFER;
376 bool ArrayBufferRawVarData::Init(const PP_Var& var,
377 PP_Instance instance) {
378 DCHECK(var.type == PP_VARTYPE_ARRAY_BUFFER);
379 ArrayBufferVar* buffer_var = ArrayBufferVar::FromPPVar(var);
380 if (!buffer_var)
381 return false;
382 bool using_shmem = false;
383 if (buffer_var->ByteLength() >= g_minimum_array_buffer_size_for_shmem &&
384 instance != 0) {
385 int host_handle_id;
386 base::SharedMemoryHandle plugin_handle;
387 using_shmem = buffer_var->CopyToNewShmem(instance,
388 &host_handle_id,
389 &plugin_handle);
390 if (using_shmem) {
391 if (host_handle_id != -1) {
392 DCHECK(!base::SharedMemory::IsHandleValid(plugin_handle));
393 DCHECK(PpapiGlobals::Get()->IsPluginGlobals());
394 type_ = ARRAY_BUFFER_SHMEM_HOST;
395 host_shm_handle_id_ = host_handle_id;
396 } else {
397 DCHECK(base::SharedMemory::IsHandleValid(plugin_handle));
398 DCHECK(PpapiGlobals::Get()->IsHostGlobals());
399 type_ = ARRAY_BUFFER_SHMEM_PLUGIN;
400 plugin_shm_handle_ = SerializedHandle(plugin_handle,
401 buffer_var->ByteLength());
405 if (!using_shmem) {
406 type_ = ARRAY_BUFFER_NO_SHMEM;
407 data_ = std::string(static_cast<const char*>(buffer_var->Map()),
408 buffer_var->ByteLength());
410 initialized_ = true;
411 return true;
414 PP_Var ArrayBufferRawVarData::CreatePPVar(PP_Instance instance) {
415 PP_Var result = PP_MakeUndefined();
416 switch (type_) {
417 case ARRAY_BUFFER_SHMEM_HOST: {
418 base::SharedMemoryHandle host_handle;
419 uint32 size_in_bytes;
420 bool ok = PpapiGlobals::Get()->GetVarTracker()->
421 StopTrackingSharedMemoryHandle(host_shm_handle_id_,
422 instance,
423 &host_handle,
424 &size_in_bytes);
425 if (ok) {
426 result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
427 size_in_bytes, host_handle);
428 } else {
429 LOG(ERROR) << "Couldn't find array buffer id: " << host_shm_handle_id_;
430 return PP_MakeUndefined();
432 break;
434 case ARRAY_BUFFER_SHMEM_PLUGIN: {
435 result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
436 plugin_shm_handle_.size(),
437 plugin_shm_handle_.shmem());
438 break;
440 case ARRAY_BUFFER_NO_SHMEM: {
441 result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
442 static_cast<uint32>(data_.size()), data_.data());
443 break;
445 default:
446 NOTREACHED();
447 return PP_MakeUndefined();
449 DCHECK(result.type == PP_VARTYPE_ARRAY_BUFFER);
450 return result;
453 void ArrayBufferRawVarData::PopulatePPVar(const PP_Var& var,
454 const std::vector<PP_Var>& graph) {
457 void ArrayBufferRawVarData::Write(
458 IPC::Message* m,
459 const HandleWriter& handle_writer) {
460 m->WriteInt(type_);
461 switch (type_) {
462 case ARRAY_BUFFER_SHMEM_HOST:
463 m->WriteInt(host_shm_handle_id_);
464 break;
465 case ARRAY_BUFFER_SHMEM_PLUGIN:
466 handle_writer.Run(m, plugin_shm_handle_);
467 break;
468 case ARRAY_BUFFER_NO_SHMEM:
469 m->WriteString(data_);
470 break;
474 bool ArrayBufferRawVarData::Read(PP_VarType type,
475 const IPC::Message* m,
476 PickleIterator* iter) {
477 int shmem_type;
478 if (!m->ReadInt(iter, &shmem_type))
479 return false;
480 type_ = static_cast<ShmemType>(shmem_type);
481 switch (type_) {
482 case ARRAY_BUFFER_SHMEM_HOST:
483 if (!m->ReadInt(iter, &host_shm_handle_id_))
484 return false;
485 break;
486 case ARRAY_BUFFER_SHMEM_PLUGIN:
487 if (!IPC::ParamTraits<SerializedHandle>::Read(
488 m, iter, &plugin_shm_handle_)) {
489 return false;
491 break;
492 case ARRAY_BUFFER_NO_SHMEM:
493 if (!m->ReadString(iter, &data_))
494 return false;
495 break;
496 default:
497 // We read an invalid ID.
498 NOTREACHED();
499 return false;
501 return true;
504 SerializedHandle* ArrayBufferRawVarData::GetHandle() {
505 if (type_ == ARRAY_BUFFER_SHMEM_PLUGIN && plugin_shm_handle_.size() != 0)
506 return &plugin_shm_handle_;
507 return NULL;
510 // ArrayRawVarData -------------------------------------------------------------
511 ArrayRawVarData::ArrayRawVarData() {
514 ArrayRawVarData::~ArrayRawVarData() {
517 void ArrayRawVarData::AddChild(size_t element) {
518 children_.push_back(element);
521 PP_VarType ArrayRawVarData::Type() {
522 return PP_VARTYPE_ARRAY;
525 bool ArrayRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
526 initialized_ = true;
527 DCHECK(var.type == PP_VARTYPE_ARRAY);
528 initialized_ = true;
529 return true;
532 PP_Var ArrayRawVarData::CreatePPVar(PP_Instance instance) {
533 return (new ArrayVar())->GetPPVar();
536 void ArrayRawVarData::PopulatePPVar(const PP_Var& var,
537 const std::vector<PP_Var>& graph) {
538 if (var.type != PP_VARTYPE_ARRAY) {
539 NOTREACHED();
540 return;
542 ArrayVar* array_var = ArrayVar::FromPPVar(var);
543 DCHECK(array_var->elements().empty());
544 for (size_t i = 0; i < children_.size(); ++i)
545 array_var->elements().push_back(ScopedPPVar(graph[children_[i]]));
548 void ArrayRawVarData::Write(IPC::Message* m,
549 const HandleWriter& handle_writer) {
550 m->WriteUInt32(static_cast<uint32_t>(children_.size()));
551 for (size_t i = 0; i < children_.size(); ++i)
552 m->WriteUInt32(static_cast<uint32_t>(children_[i]));
555 bool ArrayRawVarData::Read(PP_VarType type,
556 const IPC::Message* m,
557 PickleIterator* iter) {
558 uint32_t size;
559 if (!m->ReadUInt32(iter, &size))
560 return false;
561 for (uint32_t i = 0; i < size; ++i) {
562 uint32_t index;
563 if (!m->ReadUInt32(iter, &index))
564 return false;
565 children_.push_back(index);
567 return true;
570 // DictionaryRawVarData --------------------------------------------------------
571 DictionaryRawVarData::DictionaryRawVarData() {
574 DictionaryRawVarData::~DictionaryRawVarData() {
577 void DictionaryRawVarData::AddChild(const std::string& key,
578 size_t value) {
579 children_.push_back(make_pair(key, value));
582 PP_VarType DictionaryRawVarData::Type() {
583 return PP_VARTYPE_DICTIONARY;
586 bool DictionaryRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
587 DCHECK(var.type == PP_VARTYPE_DICTIONARY);
588 initialized_ = true;
589 return true;
592 PP_Var DictionaryRawVarData::CreatePPVar(PP_Instance instance) {
593 return (new DictionaryVar())->GetPPVar();
596 void DictionaryRawVarData::PopulatePPVar(const PP_Var& var,
597 const std::vector<PP_Var>& graph) {
598 if (var.type != PP_VARTYPE_DICTIONARY) {
599 NOTREACHED();
600 return;
602 DictionaryVar* dictionary_var = DictionaryVar::FromPPVar(var);
603 DCHECK(dictionary_var->key_value_map().empty());
604 for (size_t i = 0; i < children_.size(); ++i) {
605 bool success = dictionary_var->SetWithStringKey(children_[i].first,
606 graph[children_[i].second]);
607 DCHECK(success);
611 void DictionaryRawVarData::Write(
612 IPC::Message* m,
613 const HandleWriter& handle_writer) {
614 m->WriteUInt32(static_cast<uint32_t>(children_.size()));
615 for (size_t i = 0; i < children_.size(); ++i) {
616 m->WriteString(children_[i].first);
617 m->WriteUInt32(static_cast<uint32_t>(children_[i].second));
621 bool DictionaryRawVarData::Read(PP_VarType type,
622 const IPC::Message* m,
623 PickleIterator* iter) {
624 uint32_t size;
625 if (!m->ReadUInt32(iter, &size))
626 return false;
627 for (uint32_t i = 0; i < size; ++i) {
628 std::string key;
629 uint32_t value;
630 if (!m->ReadString(iter, &key))
631 return false;
632 if (!m->ReadUInt32(iter, &value))
633 return false;
634 children_.push_back(make_pair(key, value));
636 return true;
639 } // namespace proxy
640 } // namespace ppapi