Disable DeviceOrientationEventPumpTest.* under Valgrind on Mac
[chromium-blink-merge.git] / ppapi / proxy / raw_var_data.cc
bloba550c3fca052892976c32288a6b807fa4cff211f
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/containers/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 struct StackEntry {
35 StackEntry(PP_Var v, size_t i) : var(v), data_index(i) {}
36 PP_Var var;
37 size_t data_index;
40 // For a given PP_Var, returns the RawVarData associated with it, or creates a
41 // new one if there is no existing one. The data is appended to |data| if it
42 // is newly created. The index into |data| pointing to the result is returned.
43 // |visited_map| keeps track of RawVarDatas that have already been created.
44 size_t GetOrCreateRawVarData(const PP_Var& var,
45 base::hash_map<int64_t, size_t>* visited_map,
46 ScopedVector<RawVarData>* data) {
47 if (VarTracker::IsVarTypeRefcounted(var.type)) {
48 base::hash_map<int64_t, size_t>::iterator it = visited_map->find(
49 var.value.as_id);
50 if (it != visited_map->end()) {
51 return it->second;
52 } else {
53 data->push_back(RawVarData::Create(var.type));
54 (*visited_map)[var.value.as_id] = data->size() - 1;
56 } else {
57 data->push_back(RawVarData::Create(var.type));
59 return data->size() - 1;
62 bool CanHaveChildren(PP_Var var) {
63 return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY;
66 } // namespace
68 // RawVarDataGraph ------------------------------------------------------------
69 RawVarDataGraph::RawVarDataGraph() {
72 RawVarDataGraph::~RawVarDataGraph() {
75 // This function uses a stack-based DFS search to traverse the var graph. Each
76 // iteration, the top node on the stack examined. If the node has not been
77 // visited yet (i.e. !initialized()) then it is added to the list of
78 // |parent_ids| which contains all of the nodes on the path from the start node
79 // to the current node. Each of that nodes children are examined. If they appear
80 // in the list of |parent_ids| it means we have a cycle and we return NULL.
81 // Otherwise, if they haven't been visited yet we add them to the stack, If the
82 // node at the top of the stack has already been visited, then we pop it off the
83 // stack and erase it from |parent_ids|.
84 // static
85 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
86 PP_Instance instance) {
87 scoped_ptr<RawVarDataGraph> graph(new RawVarDataGraph);
88 // Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph.
89 base::hash_map<int64_t, size_t> visited_map;
90 base::hash_set<int64_t> parent_ids;
92 std::stack<StackEntry> stack;
93 stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_map,
94 &graph->data_)));
96 while (!stack.empty()) {
97 PP_Var current_var = stack.top().var;
98 RawVarData* current_var_data = graph->data_[stack.top().data_index];
100 if (current_var_data->initialized()) {
101 stack.pop();
102 if (CanHaveChildren(current_var))
103 parent_ids.erase(current_var.value.as_id);
104 continue;
107 if (CanHaveChildren(current_var))
108 parent_ids.insert(current_var.value.as_id);
109 if (!current_var_data->Init(current_var, instance)) {
110 NOTREACHED();
111 return scoped_ptr<RawVarDataGraph>();
114 // Add child nodes to the stack.
115 if (current_var.type == PP_VARTYPE_ARRAY) {
116 ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
117 if (!array_var) {
118 NOTREACHED();
119 return scoped_ptr<RawVarDataGraph>();
121 for (ArrayVar::ElementVector::const_iterator iter =
122 array_var->elements().begin();
123 iter != array_var->elements().end();
124 ++iter) {
125 const PP_Var& child = iter->get();
126 // If a child of this node is already in parent_ids, we have a cycle so
127 // we just return null.
128 if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0)
129 return scoped_ptr<RawVarDataGraph>();
130 size_t child_id = GetOrCreateRawVarData(child, &visited_map,
131 &graph->data_);
132 static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id);
133 if (!graph->data_[child_id]->initialized())
134 stack.push(StackEntry(child, child_id));
136 } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
137 DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
138 if (!dict_var) {
139 NOTREACHED();
140 return scoped_ptr<RawVarDataGraph>();
142 for (DictionaryVar::KeyValueMap::const_iterator iter =
143 dict_var->key_value_map().begin();
144 iter != dict_var->key_value_map().end();
145 ++iter) {
146 const PP_Var& child = iter->second.get();
147 if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0)
148 return scoped_ptr<RawVarDataGraph>();
149 size_t child_id = GetOrCreateRawVarData(child, &visited_map,
150 &graph->data_);
151 static_cast<DictionaryRawVarData*>(
152 current_var_data)->AddChild(iter->first, child_id);
153 if (!graph->data_[child_id]->initialized())
154 stack.push(StackEntry(child, child_id));
158 return graph.Pass();
161 PP_Var RawVarDataGraph::CreatePPVar(PP_Instance instance) {
162 // Create and initialize each node in the graph.
163 std::vector<PP_Var> graph;
164 for (size_t i = 0; i < data_.size(); ++i)
165 graph.push_back(data_[i]->CreatePPVar(instance));
166 for (size_t i = 0; i < data_.size(); ++i)
167 data_[i]->PopulatePPVar(graph[i], graph);
168 // Everything except the root will have one extra ref. Remove that ref.
169 for (size_t i = 1; i < data_.size(); ++i)
170 ScopedPPVar(ScopedPPVar::PassRef(), graph[i]);
171 // The first element is the root.
172 return graph[0];
175 void RawVarDataGraph::Write(IPC::Message* m,
176 const HandleWriter& handle_writer) {
177 // Write the size, followed by each node in the graph.
178 m->WriteUInt32(static_cast<uint32_t>(data_.size()));
179 for (size_t i = 0; i < data_.size(); ++i) {
180 m->WriteInt(data_[i]->Type());
181 data_[i]->Write(m, handle_writer);
185 // static
186 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m,
187 PickleIterator* iter) {
188 scoped_ptr<RawVarDataGraph> result(new RawVarDataGraph);
189 uint32_t size = 0;
190 if (!m->ReadUInt32(iter, &size))
191 return scoped_ptr<RawVarDataGraph>();
192 for (uint32_t i = 0; i < size; ++i) {
193 int32_t type;
194 if (!m->ReadInt(iter, &type))
195 return scoped_ptr<RawVarDataGraph>();
196 PP_VarType var_type = static_cast<PP_VarType>(type);
197 result->data_.push_back(RawVarData::Create(var_type));
198 if (!result->data_.back()->Read(var_type, m, iter))
199 return scoped_ptr<RawVarDataGraph>();
201 return result.Pass();
204 std::vector<SerializedHandle*> RawVarDataGraph::GetHandles() {
205 std::vector<SerializedHandle*> result;
206 for (size_t i = 0; i < data_.size(); ++i) {
207 SerializedHandle* handle = data_[i]->GetHandle();
208 if (handle)
209 result.push_back(handle);
211 return result;
214 // static
215 void RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(
216 uint32 threshold) {
217 if (threshold == 0)
218 g_minimum_array_buffer_size_for_shmem = kMinimumArrayBufferSizeForShmem;
219 else
220 g_minimum_array_buffer_size_for_shmem = threshold;
223 // RawVarData ------------------------------------------------------------------
225 // static
226 RawVarData* RawVarData::Create(PP_VarType type) {
227 switch (type) {
228 case PP_VARTYPE_UNDEFINED:
229 case PP_VARTYPE_NULL:
230 case PP_VARTYPE_BOOL:
231 case PP_VARTYPE_INT32:
232 case PP_VARTYPE_DOUBLE:
233 case PP_VARTYPE_OBJECT:
234 return new BasicRawVarData();
235 case PP_VARTYPE_STRING:
236 return new StringRawVarData();
237 case PP_VARTYPE_ARRAY_BUFFER:
238 return new ArrayBufferRawVarData();
239 case PP_VARTYPE_ARRAY:
240 return new ArrayRawVarData();
241 case PP_VARTYPE_DICTIONARY:
242 return new DictionaryRawVarData();
244 NOTREACHED();
245 return NULL;
248 RawVarData::RawVarData() : initialized_(false) {
251 RawVarData::~RawVarData() {
254 SerializedHandle* RawVarData::GetHandle() {
255 return NULL;
258 // BasicRawVarData -------------------------------------------------------------
259 BasicRawVarData::BasicRawVarData() {
262 BasicRawVarData::~BasicRawVarData() {
265 PP_VarType BasicRawVarData::Type() {
266 return var_.type;
269 bool BasicRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
270 var_ = var;
271 initialized_ = true;
272 return true;
275 PP_Var BasicRawVarData::CreatePPVar(PP_Instance instance) {
276 return var_;
279 void BasicRawVarData::PopulatePPVar(const PP_Var& var,
280 const std::vector<PP_Var>& graph) {
283 void BasicRawVarData::Write(
284 IPC::Message* m,
285 const HandleWriter& handle_writer) {
286 switch (var_.type) {
287 case PP_VARTYPE_UNDEFINED:
288 case PP_VARTYPE_NULL:
289 // These don't need any data associated with them other than the type we
290 // just serialized.
291 break;
292 case PP_VARTYPE_BOOL:
293 m->WriteBool(PP_ToBool(var_.value.as_bool));
294 break;
295 case PP_VARTYPE_INT32:
296 m->WriteInt(var_.value.as_int);
297 break;
298 case PP_VARTYPE_DOUBLE:
299 IPC::ParamTraits<double>::Write(m, var_.value.as_double);
300 break;
301 case PP_VARTYPE_OBJECT:
302 m->WriteInt64(var_.value.as_id);
303 break;
304 default:
305 NOTREACHED();
306 break;
310 bool BasicRawVarData::Read(PP_VarType type,
311 const IPC::Message* m,
312 PickleIterator* iter) {
313 PP_Var result;
314 result.type = type;
315 switch (type) {
316 case PP_VARTYPE_UNDEFINED:
317 case PP_VARTYPE_NULL:
318 // These don't have any data associated with them other than the type we
319 // just serialized.
320 break;
321 case PP_VARTYPE_BOOL: {
322 bool bool_value;
323 if (!m->ReadBool(iter, &bool_value))
324 return false;
325 result.value.as_bool = PP_FromBool(bool_value);
326 break;
328 case PP_VARTYPE_INT32:
329 if (!m->ReadInt(iter, &result.value.as_int))
330 return false;
331 break;
332 case PP_VARTYPE_DOUBLE:
333 if (!IPC::ParamTraits<double>::Read(m, iter, &result.value.as_double))
334 return false;
335 break;
336 case PP_VARTYPE_OBJECT:
337 if (!m->ReadInt64(iter, &result.value.as_id))
338 return false;
339 break;
340 default:
341 NOTREACHED();
342 return false;
344 var_ = result;
345 return true;
348 // StringRawVarData ------------------------------------------------------------
349 StringRawVarData::StringRawVarData() {
352 StringRawVarData::~StringRawVarData() {
355 PP_VarType StringRawVarData::Type() {
356 return PP_VARTYPE_STRING;
359 bool StringRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
360 DCHECK(var.type == PP_VARTYPE_STRING);
361 StringVar* string_var = StringVar::FromPPVar(var);
362 if (!string_var)
363 return false;
364 data_ = string_var->value();
365 initialized_ = true;
366 return true;
369 PP_Var StringRawVarData::CreatePPVar(PP_Instance instance) {
370 return StringVar::SwapValidatedUTF8StringIntoPPVar(&data_);
373 void StringRawVarData::PopulatePPVar(const PP_Var& var,
374 const std::vector<PP_Var>& graph) {
377 void StringRawVarData::Write(IPC::Message* m,
378 const HandleWriter& handle_writer) {
379 m->WriteString(data_);
382 bool StringRawVarData::Read(PP_VarType type,
383 const IPC::Message* m,
384 PickleIterator* iter) {
385 if (!m->ReadString(iter, &data_))
386 return false;
387 return true;
390 // ArrayBufferRawVarData -------------------------------------------------------
391 ArrayBufferRawVarData::ArrayBufferRawVarData() {
394 ArrayBufferRawVarData::~ArrayBufferRawVarData() {
397 PP_VarType ArrayBufferRawVarData::Type() {
398 return PP_VARTYPE_ARRAY_BUFFER;
401 bool ArrayBufferRawVarData::Init(const PP_Var& var,
402 PP_Instance instance) {
403 DCHECK(var.type == PP_VARTYPE_ARRAY_BUFFER);
404 ArrayBufferVar* buffer_var = ArrayBufferVar::FromPPVar(var);
405 if (!buffer_var)
406 return false;
407 bool using_shmem = false;
408 if (buffer_var->ByteLength() >= g_minimum_array_buffer_size_for_shmem &&
409 instance != 0) {
410 int host_handle_id;
411 base::SharedMemoryHandle plugin_handle;
412 using_shmem = buffer_var->CopyToNewShmem(instance,
413 &host_handle_id,
414 &plugin_handle);
415 if (using_shmem) {
416 if (host_handle_id != -1) {
417 DCHECK(!base::SharedMemory::IsHandleValid(plugin_handle));
418 DCHECK(PpapiGlobals::Get()->IsPluginGlobals());
419 type_ = ARRAY_BUFFER_SHMEM_HOST;
420 host_shm_handle_id_ = host_handle_id;
421 } else {
422 DCHECK(base::SharedMemory::IsHandleValid(plugin_handle));
423 DCHECK(PpapiGlobals::Get()->IsHostGlobals());
424 type_ = ARRAY_BUFFER_SHMEM_PLUGIN;
425 plugin_shm_handle_ = SerializedHandle(plugin_handle,
426 buffer_var->ByteLength());
430 if (!using_shmem) {
431 type_ = ARRAY_BUFFER_NO_SHMEM;
432 data_ = std::string(static_cast<const char*>(buffer_var->Map()),
433 buffer_var->ByteLength());
435 initialized_ = true;
436 return true;
439 PP_Var ArrayBufferRawVarData::CreatePPVar(PP_Instance instance) {
440 PP_Var result = PP_MakeUndefined();
441 switch (type_) {
442 case ARRAY_BUFFER_SHMEM_HOST: {
443 base::SharedMemoryHandle host_handle;
444 uint32 size_in_bytes;
445 bool ok = PpapiGlobals::Get()->GetVarTracker()->
446 StopTrackingSharedMemoryHandle(host_shm_handle_id_,
447 instance,
448 &host_handle,
449 &size_in_bytes);
450 if (ok) {
451 result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
452 size_in_bytes, host_handle);
453 } else {
454 LOG(ERROR) << "Couldn't find array buffer id: " << host_shm_handle_id_;
455 return PP_MakeUndefined();
457 break;
459 case ARRAY_BUFFER_SHMEM_PLUGIN: {
460 result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
461 plugin_shm_handle_.size(),
462 plugin_shm_handle_.shmem());
463 break;
465 case ARRAY_BUFFER_NO_SHMEM: {
466 result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
467 static_cast<uint32>(data_.size()), data_.data());
468 break;
470 default:
471 NOTREACHED();
472 return PP_MakeUndefined();
474 DCHECK(result.type == PP_VARTYPE_ARRAY_BUFFER);
475 return result;
478 void ArrayBufferRawVarData::PopulatePPVar(const PP_Var& var,
479 const std::vector<PP_Var>& graph) {
482 void ArrayBufferRawVarData::Write(
483 IPC::Message* m,
484 const HandleWriter& handle_writer) {
485 m->WriteInt(type_);
486 switch (type_) {
487 case ARRAY_BUFFER_SHMEM_HOST:
488 m->WriteInt(host_shm_handle_id_);
489 break;
490 case ARRAY_BUFFER_SHMEM_PLUGIN:
491 handle_writer.Run(m, plugin_shm_handle_);
492 break;
493 case ARRAY_BUFFER_NO_SHMEM:
494 m->WriteString(data_);
495 break;
499 bool ArrayBufferRawVarData::Read(PP_VarType type,
500 const IPC::Message* m,
501 PickleIterator* iter) {
502 int shmem_type;
503 if (!m->ReadInt(iter, &shmem_type))
504 return false;
505 type_ = static_cast<ShmemType>(shmem_type);
506 switch (type_) {
507 case ARRAY_BUFFER_SHMEM_HOST:
508 if (!m->ReadInt(iter, &host_shm_handle_id_))
509 return false;
510 break;
511 case ARRAY_BUFFER_SHMEM_PLUGIN:
512 if (!IPC::ParamTraits<SerializedHandle>::Read(
513 m, iter, &plugin_shm_handle_)) {
514 return false;
516 break;
517 case ARRAY_BUFFER_NO_SHMEM:
518 if (!m->ReadString(iter, &data_))
519 return false;
520 break;
521 default:
522 // We read an invalid ID.
523 NOTREACHED();
524 return false;
526 return true;
529 SerializedHandle* ArrayBufferRawVarData::GetHandle() {
530 if (type_ == ARRAY_BUFFER_SHMEM_PLUGIN && plugin_shm_handle_.size() != 0)
531 return &plugin_shm_handle_;
532 return NULL;
535 // ArrayRawVarData -------------------------------------------------------------
536 ArrayRawVarData::ArrayRawVarData() {
539 ArrayRawVarData::~ArrayRawVarData() {
542 void ArrayRawVarData::AddChild(size_t element) {
543 children_.push_back(element);
546 PP_VarType ArrayRawVarData::Type() {
547 return PP_VARTYPE_ARRAY;
550 bool ArrayRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
551 initialized_ = true;
552 DCHECK(var.type == PP_VARTYPE_ARRAY);
553 initialized_ = true;
554 return true;
557 PP_Var ArrayRawVarData::CreatePPVar(PP_Instance instance) {
558 return (new ArrayVar())->GetPPVar();
561 void ArrayRawVarData::PopulatePPVar(const PP_Var& var,
562 const std::vector<PP_Var>& graph) {
563 if (var.type != PP_VARTYPE_ARRAY) {
564 NOTREACHED();
565 return;
567 ArrayVar* array_var = ArrayVar::FromPPVar(var);
568 DCHECK(array_var->elements().empty());
569 for (size_t i = 0; i < children_.size(); ++i)
570 array_var->elements().push_back(ScopedPPVar(graph[children_[i]]));
573 void ArrayRawVarData::Write(IPC::Message* m,
574 const HandleWriter& handle_writer) {
575 m->WriteUInt32(static_cast<uint32_t>(children_.size()));
576 for (size_t i = 0; i < children_.size(); ++i)
577 m->WriteUInt32(static_cast<uint32_t>(children_[i]));
580 bool ArrayRawVarData::Read(PP_VarType type,
581 const IPC::Message* m,
582 PickleIterator* iter) {
583 uint32_t size;
584 if (!m->ReadUInt32(iter, &size))
585 return false;
586 for (uint32_t i = 0; i < size; ++i) {
587 uint32_t index;
588 if (!m->ReadUInt32(iter, &index))
589 return false;
590 children_.push_back(index);
592 return true;
595 // DictionaryRawVarData --------------------------------------------------------
596 DictionaryRawVarData::DictionaryRawVarData() {
599 DictionaryRawVarData::~DictionaryRawVarData() {
602 void DictionaryRawVarData::AddChild(const std::string& key,
603 size_t value) {
604 children_.push_back(make_pair(key, value));
607 PP_VarType DictionaryRawVarData::Type() {
608 return PP_VARTYPE_DICTIONARY;
611 bool DictionaryRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
612 DCHECK(var.type == PP_VARTYPE_DICTIONARY);
613 initialized_ = true;
614 return true;
617 PP_Var DictionaryRawVarData::CreatePPVar(PP_Instance instance) {
618 return (new DictionaryVar())->GetPPVar();
621 void DictionaryRawVarData::PopulatePPVar(const PP_Var& var,
622 const std::vector<PP_Var>& graph) {
623 if (var.type != PP_VARTYPE_DICTIONARY) {
624 NOTREACHED();
625 return;
627 DictionaryVar* dictionary_var = DictionaryVar::FromPPVar(var);
628 DCHECK(dictionary_var->key_value_map().empty());
629 for (size_t i = 0; i < children_.size(); ++i) {
630 bool success = dictionary_var->SetWithStringKey(children_[i].first,
631 graph[children_[i].second]);
632 DCHECK(success);
636 void DictionaryRawVarData::Write(
637 IPC::Message* m,
638 const HandleWriter& handle_writer) {
639 m->WriteUInt32(static_cast<uint32_t>(children_.size()));
640 for (size_t i = 0; i < children_.size(); ++i) {
641 m->WriteString(children_[i].first);
642 m->WriteUInt32(static_cast<uint32_t>(children_[i].second));
646 bool DictionaryRawVarData::Read(PP_VarType type,
647 const IPC::Message* m,
648 PickleIterator* iter) {
649 uint32_t size;
650 if (!m->ReadUInt32(iter, &size))
651 return false;
652 for (uint32_t i = 0; i < size; ++i) {
653 std::string key;
654 uint32_t value;
655 if (!m->ReadString(iter, &key))
656 return false;
657 if (!m->ReadUInt32(iter, &value))
658 return false;
659 children_.push_back(make_pair(key, value));
661 return true;
664 } // namespace proxy
665 } // namespace ppapi