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"
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"
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(
48 if (it
!= id_map
->end()) {
51 data
->push_back(RawVarData::Create(var
.type
));
52 (*id_map
)[var
.value
.as_id
] = data
->size() - 1;
55 data
->push_back(RawVarData::Create(var
.type
));
57 return data
->size() - 1;
62 // RawVarDataGraph ------------------------------------------------------------
63 RawVarDataGraph::RawVarDataGraph() {
66 RawVarDataGraph::~RawVarDataGraph() {
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
,
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
];
86 // If the node is initialized, it means we have visited it.
87 if (current_var_data
->initialized())
90 if (!current_var_data
->Init(current_var
, instance
)) {
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
);
100 return scoped_ptr
<RawVarDataGraph
>();
102 for (ArrayVar::ElementVector::const_iterator iter
=
103 array_var
->elements().begin();
104 iter
!= array_var
->elements().end();
106 size_t child_id
= GetOrCreateRawVarData(iter
->get(), &id_map
,
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
);
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();
121 size_t child_id
= GetOrCreateRawVarData(iter
->second
.get(), &id_map
,
123 static_cast<DictionaryRawVarData
*>(
124 current_var_data
)->AddChild(iter
->first
, child_id
);
125 stack
.push(make_pair(iter
->second
.get(), child_id
));
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.
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
));
161 scoped_ptr
<RawVarDataGraph
> RawVarDataGraph::Read(const IPC::Message
* m
,
162 PickleIterator
* iter
) {
163 scoped_ptr
<RawVarDataGraph
> result(new RawVarDataGraph
);
165 if (!m
->ReadUInt32(iter
, &size
))
166 return scoped_ptr
<RawVarDataGraph
>();
167 for (uint32_t i
= 0; i
< size
; ++i
) {
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();
184 result
.push_back(handle
);
190 void RawVarDataGraph::SetMinimumArrayBufferSizeForShmemForTest(
193 g_minimum_array_buffer_size_for_shmem
= kMinimumArrayBufferSizeForShmem
;
195 g_minimum_array_buffer_size_for_shmem
= threshold
;
198 // RawVarData ------------------------------------------------------------------
201 RawVarData
* RawVarData::Create(PP_VarType 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();
223 RawVarData::RawVarData() : initialized_(false) {
226 RawVarData::~RawVarData() {
229 SerializedHandle
* RawVarData::GetHandle() {
233 // BasicRawVarData -------------------------------------------------------------
234 BasicRawVarData::BasicRawVarData() {
237 BasicRawVarData::~BasicRawVarData() {
240 PP_VarType
BasicRawVarData::Type() {
244 bool BasicRawVarData::Init(const PP_Var
& var
, PP_Instance
/*instance*/) {
250 PP_Var
BasicRawVarData::CreatePPVar(PP_Instance instance
) {
254 void BasicRawVarData::PopulatePPVar(const PP_Var
& var
,
255 const std::vector
<PP_Var
>& graph
) {
258 void BasicRawVarData::Write(
260 const HandleWriter
& handle_writer
) {
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
267 case PP_VARTYPE_BOOL
:
268 m
->WriteBool(PP_ToBool(var_
.value
.as_bool
));
270 case PP_VARTYPE_INT32
:
271 m
->WriteInt(var_
.value
.as_int
);
273 case PP_VARTYPE_DOUBLE
:
274 IPC::ParamTraits
<double>::Write(m
, var_
.value
.as_double
);
276 case PP_VARTYPE_OBJECT
:
277 m
->WriteInt64(var_
.value
.as_id
);
285 bool BasicRawVarData::Read(PP_VarType type
,
286 const IPC::Message
* m
,
287 PickleIterator
* iter
) {
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
296 case PP_VARTYPE_BOOL
: {
298 if (!m
->ReadBool(iter
, &bool_value
))
300 result
.value
.as_bool
= PP_FromBool(bool_value
);
303 case PP_VARTYPE_INT32
:
304 if (!m
->ReadInt(iter
, &result
.value
.as_int
))
307 case PP_VARTYPE_DOUBLE
:
308 if (!IPC::ParamTraits
<double>::Read(m
, iter
, &result
.value
.as_double
))
311 case PP_VARTYPE_OBJECT
:
312 if (!m
->ReadInt64(iter
, &result
.value
.as_id
))
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
);
339 data_
= string_var
->value();
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_
))
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
);
382 bool using_shmem
= false;
383 if (buffer_var
->ByteLength() >= g_minimum_array_buffer_size_for_shmem
&&
386 base::SharedMemoryHandle plugin_handle
;
387 using_shmem
= buffer_var
->CopyToNewShmem(instance
,
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
;
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());
406 type_
= ARRAY_BUFFER_NO_SHMEM
;
407 data_
= std::string(static_cast<const char*>(buffer_var
->Map()),
408 buffer_var
->ByteLength());
414 PP_Var
ArrayBufferRawVarData::CreatePPVar(PP_Instance instance
) {
415 PP_Var result
= PP_MakeUndefined();
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_
,
426 result
= PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
427 size_in_bytes
, host_handle
);
429 LOG(ERROR
) << "Couldn't find array buffer id: " << host_shm_handle_id_
;
430 return PP_MakeUndefined();
434 case ARRAY_BUFFER_SHMEM_PLUGIN
: {
435 result
= PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
436 plugin_shm_handle_
.size(),
437 plugin_shm_handle_
.shmem());
440 case ARRAY_BUFFER_NO_SHMEM
: {
441 result
= PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
442 static_cast<uint32
>(data_
.size()), data_
.data());
447 return PP_MakeUndefined();
449 DCHECK(result
.type
== PP_VARTYPE_ARRAY_BUFFER
);
453 void ArrayBufferRawVarData::PopulatePPVar(const PP_Var
& var
,
454 const std::vector
<PP_Var
>& graph
) {
457 void ArrayBufferRawVarData::Write(
459 const HandleWriter
& handle_writer
) {
462 case ARRAY_BUFFER_SHMEM_HOST
:
463 m
->WriteInt(host_shm_handle_id_
);
465 case ARRAY_BUFFER_SHMEM_PLUGIN
:
466 handle_writer
.Run(m
, plugin_shm_handle_
);
468 case ARRAY_BUFFER_NO_SHMEM
:
469 m
->WriteString(data_
);
474 bool ArrayBufferRawVarData::Read(PP_VarType type
,
475 const IPC::Message
* m
,
476 PickleIterator
* iter
) {
478 if (!m
->ReadInt(iter
, &shmem_type
))
480 type_
= static_cast<ShmemType
>(shmem_type
);
482 case ARRAY_BUFFER_SHMEM_HOST
:
483 if (!m
->ReadInt(iter
, &host_shm_handle_id_
))
486 case ARRAY_BUFFER_SHMEM_PLUGIN
:
487 if (!IPC::ParamTraits
<SerializedHandle
>::Read(
488 m
, iter
, &plugin_shm_handle_
)) {
492 case ARRAY_BUFFER_NO_SHMEM
:
493 if (!m
->ReadString(iter
, &data_
))
497 // We read an invalid ID.
504 SerializedHandle
* ArrayBufferRawVarData::GetHandle() {
505 if (type_
== ARRAY_BUFFER_SHMEM_PLUGIN
&& plugin_shm_handle_
.size() != 0)
506 return &plugin_shm_handle_
;
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*/) {
527 DCHECK(var
.type
== PP_VARTYPE_ARRAY
);
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
) {
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
) {
559 if (!m
->ReadUInt32(iter
, &size
))
561 for (uint32_t i
= 0; i
< size
; ++i
) {
563 if (!m
->ReadUInt32(iter
, &index
))
565 children_
.push_back(index
);
570 // DictionaryRawVarData --------------------------------------------------------
571 DictionaryRawVarData::DictionaryRawVarData() {
574 DictionaryRawVarData::~DictionaryRawVarData() {
577 void DictionaryRawVarData::AddChild(const std::string
& key
,
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
);
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
) {
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
]);
611 void DictionaryRawVarData::Write(
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
) {
625 if (!m
->ReadUInt32(iter
, &size
))
627 for (uint32_t i
= 0; i
< size
; ++i
) {
630 if (!m
->ReadString(iter
, &key
))
632 if (!m
->ReadUInt32(iter
, &value
))
634 children_
.push_back(make_pair(key
, value
));