Home | History | Annotate | Download | only in proxy
      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.
      4 
      5 #include "ppapi/proxy/raw_var_data.h"
      6 
      7 #include <stack>
      8 
      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"
     19 
     20 using std::make_pair;
     21 
     22 namespace ppapi {
     23 namespace proxy {
     24 
     25 namespace {
     26 
     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;
     33 
     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;
     38 };
     39 
     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;
     55     }
     56   } else {
     57     data->push_back(RawVarData::Create(var.type));
     58   }
     59   return data->size() - 1;
     60 }
     61 
     62 bool CanHaveChildren(PP_Var var) {
     63   return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY;
     64 }
     65 
     66 }  // namespace
     67 
     68 // RawVarDataGraph ------------------------------------------------------------
     69 RawVarDataGraph::RawVarDataGraph() {
     70 }
     71 
     72 RawVarDataGraph::~RawVarDataGraph() {
     73 }
     74 
     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;
     91 
     92   std::stack<StackEntry> stack;
     93   stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_map,
     94                                                    &graph->data_)));
     95 
     96   while (!stack.empty()) {
     97     PP_Var current_var = stack.top().var;
     98     RawVarData* current_var_data = graph->data_[stack.top().data_index];
     99 
    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;
    105     }
    106 
    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>();
    112     }
    113 
    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>();
    120       }
    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));
    135       }
    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>();
    141       }
    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));
    155       }
    156     }
    157   }
    158   return graph.Pass();
    159 }
    160 
    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];
    173 }
    174 
    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);
    182   }
    183 }
    184 
    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>();
    200   }
    201   return result.Pass();
    202 }
    203 
    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);
    210   }
    211   return result;
    212 }
    213 
    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;
    221 }
    222 
    223 // RawVarData ------------------------------------------------------------------
    224 
    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();
    243   }
    244   NOTREACHED();
    245   return NULL;
    246 }
    247 
    248 RawVarData::RawVarData() : initialized_(false) {
    249 }
    250 
    251 RawVarData::~RawVarData() {
    252 }
    253 
    254 SerializedHandle* RawVarData::GetHandle() {
    255   return NULL;
    256 }
    257 
    258 // BasicRawVarData -------------------------------------------------------------
    259 BasicRawVarData::BasicRawVarData() {
    260 }
    261 
    262 BasicRawVarData::~BasicRawVarData() {
    263 }
    264 
    265 PP_VarType BasicRawVarData::Type() {
    266   return var_.type;
    267 }
    268 
    269 bool BasicRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
    270   var_ = var;
    271   initialized_ = true;
    272   return true;
    273 }
    274 
    275 PP_Var BasicRawVarData::CreatePPVar(PP_Instance instance) {
    276   return var_;
    277 }
    278 
    279 void BasicRawVarData::PopulatePPVar(const PP_Var& var,
    280                                     const std::vector<PP_Var>& graph) {
    281 }
    282 
    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;
    307   }
    308 }
    309 
    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;
    327     }
    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;
    343   }
    344   var_ = result;
    345   return true;
    346 }
    347 
    348 // StringRawVarData ------------------------------------------------------------
    349 StringRawVarData::StringRawVarData() {
    350 }
    351 
    352 StringRawVarData::~StringRawVarData() {
    353 }
    354 
    355 PP_VarType StringRawVarData::Type() {
    356   return PP_VARTYPE_STRING;
    357 }
    358 
    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;
    367 }
    368 
    369 PP_Var StringRawVarData::CreatePPVar(PP_Instance instance) {
    370   return StringVar::SwapValidatedUTF8StringIntoPPVar(&data_);
    371 }
    372 
    373 void StringRawVarData::PopulatePPVar(const PP_Var& var,
    374                                      const std::vector<PP_Var>& graph) {
    375 }
    376 
    377 void StringRawVarData::Write(IPC::Message* m,
    378                              const HandleWriter& handle_writer) {
    379   m->WriteString(data_);
    380 }
    381 
    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;
    388 }
    389 
    390 // ArrayBufferRawVarData -------------------------------------------------------
    391 ArrayBufferRawVarData::ArrayBufferRawVarData() {
    392 }
    393 
    394 ArrayBufferRawVarData::~ArrayBufferRawVarData() {
    395 }
    396 
    397 PP_VarType ArrayBufferRawVarData::Type() {
    398   return PP_VARTYPE_ARRAY_BUFFER;
    399 }
    400 
    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());
    427       }
    428     }
    429   }
    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());
    434   }
    435   initialized_ = true;
    436   return true;
    437 }
    438 
    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();
    456       }
    457       break;
    458     }
    459     case ARRAY_BUFFER_SHMEM_PLUGIN: {
    460       result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
    461           plugin_shm_handle_.size(),
    462           plugin_shm_handle_.shmem());
    463       break;
    464     }
    465     case ARRAY_BUFFER_NO_SHMEM: {
    466       result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
    467           static_cast<uint32>(data_.size()), data_.data());
    468       break;
    469     }
    470     default:
    471       NOTREACHED();
    472       return PP_MakeUndefined();
    473   }
    474   DCHECK(result.type == PP_VARTYPE_ARRAY_BUFFER);
    475   return result;
    476 }
    477 
    478 void ArrayBufferRawVarData::PopulatePPVar(const PP_Var& var,
    479                                           const std::vector<PP_Var>& graph) {
    480 }
    481 
    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;
    496   }
    497 }
    498 
    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;
    515       }
    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;
    525   }
    526   return true;
    527 }
    528 
    529 SerializedHandle* ArrayBufferRawVarData::GetHandle() {
    530   if (type_ == ARRAY_BUFFER_SHMEM_PLUGIN && plugin_shm_handle_.size() != 0)
    531     return &plugin_shm_handle_;
    532   return NULL;
    533 }
    534 
    535 // ArrayRawVarData -------------------------------------------------------------
    536 ArrayRawVarData::ArrayRawVarData() {
    537 }
    538 
    539 ArrayRawVarData::~ArrayRawVarData() {
    540 }
    541 
    542 void ArrayRawVarData::AddChild(size_t element) {
    543   children_.push_back(element);
    544 }
    545 
    546 PP_VarType ArrayRawVarData::Type() {
    547   return PP_VARTYPE_ARRAY;
    548 }
    549 
    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;
    555 }
    556 
    557 PP_Var ArrayRawVarData::CreatePPVar(PP_Instance instance) {
    558   return (new ArrayVar())->GetPPVar();
    559 }
    560 
    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;
    566   }
    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]]));
    571 }
    572 
    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]));
    578 }
    579 
    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);
    591   }
    592   return true;
    593 }
    594 
    595 // DictionaryRawVarData --------------------------------------------------------
    596 DictionaryRawVarData::DictionaryRawVarData() {
    597 }
    598 
    599 DictionaryRawVarData::~DictionaryRawVarData() {
    600 }
    601 
    602 void DictionaryRawVarData::AddChild(const std::string& key,
    603                                     size_t value) {
    604   children_.push_back(make_pair(key, value));
    605 }
    606 
    607 PP_VarType DictionaryRawVarData::Type() {
    608   return PP_VARTYPE_DICTIONARY;
    609 }
    610 
    611 bool DictionaryRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) {
    612   DCHECK(var.type == PP_VARTYPE_DICTIONARY);
    613   initialized_ = true;
    614   return true;
    615 }
    616 
    617 PP_Var DictionaryRawVarData::CreatePPVar(PP_Instance instance) {
    618   return (new DictionaryVar())->GetPPVar();
    619 }
    620 
    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;
    626   }
    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);
    633   }
    634 }
    635 
    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));
    643   }
    644 }
    645 
    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));
    660   }
    661   return true;
    662 }
    663 
    664 }  // namespace proxy
    665 }  // namespace ppapi
    666