Chromium Code Reviews| Index: ppapi/proxy/raw_var_data.cc |
| diff --git a/ppapi/proxy/raw_var_data.cc b/ppapi/proxy/raw_var_data.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..360af669e9b86f38a14045bdfac287498259a593 |
| --- /dev/null |
| +++ b/ppapi/proxy/raw_var_data.cc |
| @@ -0,0 +1,608 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "ppapi/proxy/raw_var_data.h" |
| + |
| +#include <stack> |
| + |
| +#include "base/hash_tables.h" |
| +#include "base/stl_util.h" |
| +#include "ipc/ipc_message.h" |
| +#include "ppapi/proxy/ppapi_param_traits.h" |
| +#include "ppapi/shared_impl/array_var.h" |
| +#include "ppapi/shared_impl/dictionary_var.h" |
| +#include "ppapi/shared_impl/ppapi_globals.h" |
| +#include "ppapi/shared_impl/scoped_pp_var.h" |
| +#include "ppapi/shared_impl/var.h" |
| +#include "ppapi/shared_impl/var_tracker.h" |
| + |
| +using std::make_pair; |
| + |
| +namespace ppapi { |
| +namespace proxy { |
| + |
| +namespace { |
| + |
| +// When sending array buffers, if the size is over 256K, we use shared |
| +// memory instead of sending the data over IPC. Light testing suggests |
| +// shared memory is much faster for 256K and larger messages. |
| +static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024; |
| + |
| +void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) { |
| + IPC::ParamTraits<SerializedHandle>::Write(m, handle); |
| +} |
| + |
| +// For a given PP_Var, returns the RawVarData associated with it, or creates a |
| +// new one if there is no existing one. The data is appended to |data| if it |
| +// is newly created. The index into |data| pointing to the result is returned. |
| +// |id_map| keeps track of RawVarDatas that have already been created. |
| +size_t GetOrCreateRawVarData(const PP_Var& var, |
| + base::hash_map<int64_t, size_t>* id_map, |
| + ScopedVector<RawVarData>* data) { |
| + if (VarTracker::IsVarTypeRefcounted(var.type)) { |
| + base::hash_map<int64_t, size_t>::iterator it = id_map->find( |
| + var.value.as_id); |
| + if (it != id_map->end()) { |
| + return it->second; |
| + } else { |
| + data->push_back(RawVarData::Create(var.type)); |
| + (*id_map)[var.value.as_id] = data->size() - 1; |
| + } |
| + } else { |
| + data->push_back(RawVarData::Create(var.type)); |
| + } |
| + return data->size() - 1; |
| +} |
| + |
| +} // namespace |
| + |
| +// RawVarDataGraph ------------------------------------------------------------ |
| +RawVarDataGraph::RawVarDataGraph() { |
| +} |
| + |
| +RawVarDataGraph::~RawVarDataGraph() { |
| +} |
| + |
| +// static |
| +scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var, |
| + PP_Instance instance) { |
| + scoped_ptr<RawVarDataGraph> graph(new RawVarDataGraph); |
| + // Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph. |
| + base::hash_map<int64_t, size_t> id_map; |
| + |
| + std::stack<std::pair<PP_Var, size_t> > stack; |
| + stack.push(make_pair(var, GetOrCreateRawVarData(var, &id_map, |
| + &graph->data_))); |
| + |
| + // Traverse the PP_Var graph with DFS. |
| + while (!stack.empty()) { |
| + PP_Var current_var = stack.top().first; |
| + RawVarData* current_var_data = graph->data_[stack.top().second]; |
| + stack.pop(); |
| + |
| + // If the node is initialized, it means we have visited it. |
| + if (current_var_data->initialized()) |
| + continue; |
| + |
| + if (!current_var_data->Init(current_var, instance)) { |
| + NOTREACHED(); |
| + return scoped_ptr<RawVarDataGraph>(); |
| + } |
| + |
| + // Add child nodes to the stack. |
| + if (current_var.type == PP_VARTYPE_ARRAY) { |
| + ArrayVar* array_var = ArrayVar::FromPPVar(current_var); |
| + if (!array_var) { |
| + NOTREACHED(); |
| + return scoped_ptr<RawVarDataGraph>(); |
| + } |
| + for (ArrayVar::ElementVector::const_iterator iter = |
| + array_var->elements().begin(); |
| + iter != array_var->elements().end(); |
| + ++iter) { |
| + size_t child_id = GetOrCreateRawVarData(iter->get(), &id_map, |
| + &graph->data_); |
| + static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id); |
| + stack.push(make_pair(iter->get(), child_id)); |
| + } |
| + } else if (current_var.type == PP_VARTYPE_DICTIONARY) { |
| + DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var); |
| + if (!dict_var) { |
| + NOTREACHED(); |
| + return scoped_ptr<RawVarDataGraph>(); |
| + } |
| + for (DictionaryVar::KeyValueMap::const_iterator iter = |
| + dict_var->key_value_map().begin(); |
| + iter != dict_var->key_value_map().end(); |
| + ++iter) { |
| + size_t child_id = GetOrCreateRawVarData(iter->second.get(), &id_map, |
| + &graph->data_); |
| + static_cast<DictionaryRawVarData*>( |
| + current_var_data)->AddChild(iter->first, child_id); |
| + stack.push(make_pair(iter->second.get(), child_id)); |
| + } |
| + } |
| + } |
| + return graph.Pass(); |
| +} |
| + |
| +PP_Var RawVarDataGraph::CreatePPVar(PP_Instance instance) { |
| + // Create and initialize each node in the graph. |
| + std::vector<PP_Var> graph; |
| + for (size_t i = 0; i < data_.size(); ++i) |
| + graph.push_back(data_[i]->CreatePPVar(instance)); |
| + for (size_t i = 0; i < data_.size(); ++i) |
| + data_[i]->PopulatePPVar(graph[i], graph); |
| + // Everything except the root will have one extra ref. Remove that ref. |
|
dmichael (off chromium)
2013/04/15 17:40:04
I'm surprised this is the case. I'm expecting they
|
| + for (size_t i = 1; i < data_.size(); ++i) |
| + ScopedPPVar(ScopedPPVar::PassRef(), graph[i]); |
| + // The first element is the root. |
| + return graph[0]; |
| +} |
| + |
| +void RawVarDataGraph::Write(IPC::Message* m, |
| + const HandleWriter& handle_writer) { |
| + // Write the size, followed by each node in the graph. |
| + m->WriteUInt32(static_cast<uint32_t>(data_.size())); |
| + for (size_t i = 0; i < data_.size(); ++i) { |
| + m->WriteInt(data_[i]->Type()); |
| + data_[i]->Write(m, handle_writer); |
| + } |
| +} |
| + |
| +void RawVarDataGraph::Write(IPC::Message* m) { |
| + Write(m, base::Bind(&DefaultHandleWriter)); |
| +} |
| + |
| +// static |
| +scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m, |
| + PickleIterator* iter) { |
| + scoped_ptr<RawVarDataGraph> result(new RawVarDataGraph); |
| + uint32_t size = 0; |
| + if (!m->ReadUInt32(iter, &size)) |
| + return scoped_ptr<RawVarDataGraph>(); |
| + for (uint32_t i = 0; i < size; ++i) { |
| + int32_t type; |
| + if (!m->ReadInt(iter, &type)) |
| + return scoped_ptr<RawVarDataGraph>(); |
| + PP_VarType var_type = static_cast<PP_VarType>(type); |
| + result->data_.push_back(RawVarData::Create(var_type)); |
| + if (!result->data_.back()->Read(var_type, m, iter)) |
| + return scoped_ptr<RawVarDataGraph>(); |
| + } |
| + return result.Pass(); |
| +} |
| + |
| +// RawVarData ------------------------------------------------------------------ |
| + |
| +// static |
| +RawVarData* RawVarData::Create(PP_VarType type) { |
| + switch (type) { |
| + case PP_VARTYPE_UNDEFINED: |
| + case PP_VARTYPE_NULL: |
| + case PP_VARTYPE_BOOL: |
| + case PP_VARTYPE_INT32: |
| + case PP_VARTYPE_DOUBLE: |
| + case PP_VARTYPE_OBJECT: |
| + return new BasicRawVarData(); |
| + case PP_VARTYPE_STRING: |
| + return new StringRawVarData(); |
| + case PP_VARTYPE_ARRAY_BUFFER: |
| + return new ArrayBufferRawVarData(); |
| + case PP_VARTYPE_ARRAY: |
| + return new ArrayRawVarData(); |
| + case PP_VARTYPE_DICTIONARY: |
| + return new DictionaryRawVarData(); |
| + } |
| + NOTREACHED(); |
| + return NULL; |
| +} |
| + |
| +RawVarData::RawVarData() : initialized_(false) { |
| +} |
| + |
| +RawVarData::~RawVarData() { |
| +} |
| + |
| +// BasicRawVarData ------------------------------------------------------------- |
| +BasicRawVarData::BasicRawVarData() { |
| +} |
| + |
| +BasicRawVarData::~BasicRawVarData() { |
| +} |
| + |
| +PP_VarType BasicRawVarData::Type() { |
| + return var_.type; |
| +} |
| + |
| +bool BasicRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| + var_ = var; |
| + initialized_ = true; |
| + return true; |
| +} |
| + |
| +PP_Var BasicRawVarData::CreatePPVar(PP_Instance instance) { |
| + return var_; |
| +} |
| + |
| +void BasicRawVarData::PopulatePPVar(const PP_Var& var, |
| + const std::vector<PP_Var>& graph) { |
| +} |
| + |
| +void BasicRawVarData::Write( |
| + IPC::Message* m, |
| + const HandleWriter& handle_writer) { |
| + switch (var_.type) { |
| + case PP_VARTYPE_UNDEFINED: |
| + case PP_VARTYPE_NULL: |
| + // These don't need any data associated with them other than the type we |
| + // just serialized. |
| + break; |
| + case PP_VARTYPE_BOOL: |
| + m->WriteBool(PP_ToBool(var_.value.as_bool)); |
| + break; |
| + case PP_VARTYPE_INT32: |
| + m->WriteInt(var_.value.as_int); |
| + break; |
| + case PP_VARTYPE_DOUBLE: |
| + IPC::ParamTraits<double>::Write(m, var_.value.as_double); |
| + break; |
| + case PP_VARTYPE_OBJECT: |
| + m->WriteInt64(var_.value.as_id); |
| + break; |
| + default: |
| + NOTREACHED(); |
| + break; |
| + } |
| +} |
| + |
| +bool BasicRawVarData::Read(PP_VarType type, |
| + const IPC::Message* m, |
| + PickleIterator* iter) { |
| + PP_Var result; |
| + result.type = type; |
| + switch (type) { |
| + case PP_VARTYPE_UNDEFINED: |
| + case PP_VARTYPE_NULL: |
| + // These don't have any data associated with them other than the type we |
| + // just serialized. |
| + break; |
| + case PP_VARTYPE_BOOL: { |
| + bool bool_value; |
| + if (!m->ReadBool(iter, &bool_value)) |
| + return false; |
| + result.value.as_bool = PP_FromBool(bool_value); |
| + break; |
| + } |
| + case PP_VARTYPE_INT32: |
| + if (!m->ReadInt(iter, &result.value.as_int)) |
| + return false; |
| + break; |
| + case PP_VARTYPE_DOUBLE: |
| + if (!IPC::ParamTraits<double>::Read(m, iter, &result.value.as_double)) |
| + return false; |
| + break; |
| + case PP_VARTYPE_OBJECT: |
| + if (!m->ReadInt64(iter, &result.value.as_id)) |
| + return false; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + return false; |
| + } |
| + var_ = result; |
| + return true; |
| +} |
| + |
| +// StringRawVarData ------------------------------------------------------------ |
| +StringRawVarData::StringRawVarData() { |
| +} |
| + |
| +StringRawVarData::~StringRawVarData() { |
| +} |
| + |
| +PP_VarType StringRawVarData::Type() { |
| + return PP_VARTYPE_STRING; |
| +} |
| + |
| +bool StringRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| + DCHECK(var.type == PP_VARTYPE_STRING); |
| + StringVar* string_var = StringVar::FromPPVar(var); |
| + if (!string_var) |
| + return false; |
| + data_ = string_var->value(); |
| + initialized_ = true; |
| + return true; |
| +} |
| + |
| +PP_Var StringRawVarData::CreatePPVar(PP_Instance instance) { |
| + return StringVar::StringToPPVar(data_); |
| +} |
| + |
| +void StringRawVarData::PopulatePPVar(const PP_Var& var, |
| + const std::vector<PP_Var>& graph) { |
| +} |
| + |
| +void StringRawVarData::Write(IPC::Message* m, |
| + const HandleWriter& handle_writer) { |
| + m->WriteString(data_); |
| +} |
| + |
| +bool StringRawVarData::Read(PP_VarType type, |
| + const IPC::Message* m, |
| + PickleIterator* iter) { |
| + if (!m->ReadString(iter, &data_)) |
| + return false; |
| + return true; |
| +} |
| + |
| +// ArrayBufferRawVarData ------------------------------------------------------- |
| +ArrayBufferRawVarData::ArrayBufferRawVarData() { |
| +} |
| + |
| +ArrayBufferRawVarData::~ArrayBufferRawVarData() { |
| +} |
| + |
| +PP_VarType ArrayBufferRawVarData::Type() { |
| + return PP_VARTYPE_ARRAY_BUFFER; |
| +} |
| + |
| +bool ArrayBufferRawVarData::Init(const PP_Var& var, |
| + PP_Instance instance) { |
| + DCHECK(var.type == PP_VARTYPE_ARRAY_BUFFER); |
| + ArrayBufferVar* buffer_var = ArrayBufferVar::FromPPVar(var); |
| + if (!buffer_var) |
| + return false; |
| + bool using_shmem = false; |
| + if (buffer_var->ByteLength() >= kMinimumArrayBufferSizeForShmem && |
| + instance != 0) { |
| + int host_handle_id; |
| + base::SharedMemoryHandle plugin_handle; |
| + using_shmem = buffer_var->CopyToNewShmem(instance, |
| + &host_handle_id, |
| + &plugin_handle); |
| + if (using_shmem) { |
| + if (host_shm_handle_id_ != -1) { |
| + DCHECK(!base::SharedMemory::IsHandleValid(plugin_handle)); |
| + DCHECK(PpapiGlobals::Get()->IsPluginGlobals()); |
| + type_ = ARRAY_BUFFER_SHMEM_HOST; |
| + host_shm_handle_id_ = host_handle_id; |
| + } else { |
| + DCHECK(base::SharedMemory::IsHandleValid(plugin_handle)); |
| + DCHECK(PpapiGlobals::Get()->IsHostGlobals()); |
| + type_ = ARRAY_BUFFER_SHMEM_PLUGIN; |
| + plugin_shm_handle_ = SerializedHandle(plugin_handle, |
| + buffer_var->ByteLength()); |
| + } |
| + } |
| + } |
| + if (!using_shmem) { |
| + type_ = ARRAY_BUFFER_NO_SHMEM; |
| + data_ = std::string(static_cast<const char*>(buffer_var->Map()), |
| + buffer_var->ByteLength()); |
| + } |
| + initialized_ = true; |
| + return true; |
| +} |
| + |
| +PP_Var ArrayBufferRawVarData::CreatePPVar(PP_Instance instance) { |
| + PP_Var result = PP_MakeUndefined(); |
| + switch (type_) { |
| + case ARRAY_BUFFER_SHMEM_HOST: { |
| + base::SharedMemoryHandle host_handle; |
| + uint32 size_in_bytes; |
| + bool ok = PpapiGlobals::Get()->GetVarTracker()-> |
| + StopTrackingSharedMemoryHandle(host_shm_handle_id_, |
| + instance, |
| + &host_handle, |
| + &size_in_bytes); |
| + if (ok) { |
| + result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( |
| + size_in_bytes, host_handle); |
| + } else { |
| + LOG(ERROR) << "Couldn't find array buffer id: " << host_shm_handle_id_; |
| + return PP_MakeUndefined(); |
| + } |
| + break; |
| + } |
| + case ARRAY_BUFFER_SHMEM_PLUGIN: { |
| + result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( |
| + plugin_shm_handle_.size(), |
| + plugin_shm_handle_.shmem()); |
| + break; |
| + } |
| + case ARRAY_BUFFER_NO_SHMEM: { |
| + result = PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar( |
| + static_cast<uint32>(data_.size()), data_.data()); |
| + break; |
| + } |
| + default: |
| + NOTREACHED(); |
| + return PP_MakeUndefined(); |
| + } |
| + DCHECK(result.type == PP_VARTYPE_ARRAY_BUFFER); |
| + return result; |
| +} |
| + |
| +void ArrayBufferRawVarData::PopulatePPVar(const PP_Var& var, |
| + const std::vector<PP_Var>& graph) { |
| +} |
| + |
| +void ArrayBufferRawVarData::Write( |
| + IPC::Message* m, |
| + const HandleWriter& handle_writer) { |
| + m->WriteInt(type_); |
| + switch (type_) { |
| + case ARRAY_BUFFER_SHMEM_HOST: |
| + m->WriteInt(host_shm_handle_id_); |
| + break; |
| + case ARRAY_BUFFER_SHMEM_PLUGIN: |
| + handle_writer.Run(m, plugin_shm_handle_); |
| + break; |
| + case ARRAY_BUFFER_NO_SHMEM: |
| + m->WriteString(data_); |
| + break; |
| + } |
| +} |
| + |
| +bool ArrayBufferRawVarData::Read(PP_VarType type, |
| + const IPC::Message* m, |
| + PickleIterator* iter) { |
| + int shmem_type; |
| + if (!m->ReadInt(iter, &shmem_type)) |
| + return false; |
| + type_ = static_cast<ShmemType>(shmem_type); |
| + switch (type_) { |
| + case ARRAY_BUFFER_SHMEM_HOST: |
| + if (!m->ReadInt(iter, &host_shm_handle_id_)) |
| + return false; |
| + break; |
| + case ARRAY_BUFFER_SHMEM_PLUGIN: |
| + if (!IPC::ParamTraits<SerializedHandle>::Read( |
| + m, iter, &plugin_shm_handle_)) { |
| + return false; |
| + } |
| + break; |
| + case ARRAY_BUFFER_NO_SHMEM: |
| + if (!m->ReadString(iter, &data_)) |
| + return false; |
| + break; |
| + default: |
| + // We read an invalid ID. |
| + NOTREACHED(); |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +// ArrayRawVarData ------------------------------------------------------------- |
| +ArrayRawVarData::ArrayRawVarData() { |
| +} |
| + |
| +ArrayRawVarData::~ArrayRawVarData() { |
| +} |
| + |
| +void ArrayRawVarData::AddChild(size_t element) { |
| + children_.push_back(element); |
| +} |
| + |
| +PP_VarType ArrayRawVarData::Type() { |
| + return PP_VARTYPE_ARRAY; |
| +} |
| + |
| +bool ArrayRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| + initialized_ = true; |
| + DCHECK(var.type == PP_VARTYPE_ARRAY); |
| + initialized_ = true; |
| + return true; |
| +} |
| + |
| +PP_Var ArrayRawVarData::CreatePPVar(PP_Instance instance) { |
| + return (new ArrayVar())->GetPPVar(); |
| +} |
| + |
| +void ArrayRawVarData::PopulatePPVar(const PP_Var& var, |
| + const std::vector<PP_Var>& graph) { |
| + if (var.type != PP_VARTYPE_ARRAY) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + ArrayVar* array_var = ArrayVar::FromPPVar(var); |
| + DCHECK(array_var->elements().empty()); |
| + for (size_t i = 0; i < children_.size(); ++i) |
| + array_var->elements().push_back(ScopedPPVar(graph[children_[i]])); |
| +} |
| + |
| +void ArrayRawVarData::Write(IPC::Message* m, |
| + const HandleWriter& handle_writer) { |
| + m->WriteUInt32(static_cast<uint32_t>(children_.size())); |
| + for (size_t i = 0; i < children_.size(); ++i) |
| + m->WriteUInt32(static_cast<uint32_t>(children_[i])); |
| +} |
| + |
| +bool ArrayRawVarData::Read(PP_VarType type, |
| + const IPC::Message* m, |
| + PickleIterator* iter) { |
| + uint32_t size; |
| + if (!m->ReadUInt32(iter, &size)) |
| + return false; |
| + for (uint32_t i = 0; i < size; ++i) { |
| + uint32_t index; |
| + if (!m->ReadUInt32(iter, &index)) |
| + return false; |
| + children_.push_back(index); |
| + } |
| + return true; |
| +} |
| + |
| +// DictionaryRawVarData -------------------------------------------------------- |
| +DictionaryRawVarData::DictionaryRawVarData() { |
| +} |
| + |
| +DictionaryRawVarData::~DictionaryRawVarData() { |
| +} |
| + |
| +void DictionaryRawVarData::AddChild(const std::string& key, |
| + size_t value) { |
| + children_.push_back(make_pair(key, value)); |
| +} |
| + |
| +PP_VarType DictionaryRawVarData::Type() { |
| + return PP_VARTYPE_DICTIONARY; |
| +} |
| + |
| +bool DictionaryRawVarData::Init(const PP_Var& var, PP_Instance /*instance*/) { |
| + DCHECK(var.type == PP_VARTYPE_DICTIONARY); |
| + initialized_ = true; |
| + return true; |
| +} |
| + |
| +PP_Var DictionaryRawVarData::CreatePPVar(PP_Instance instance) { |
| + return (new DictionaryVar())->GetPPVar(); |
| +} |
| + |
| +void DictionaryRawVarData::PopulatePPVar(const PP_Var& var, |
| + const std::vector<PP_Var>& graph) { |
| + if (var.type != PP_VARTYPE_DICTIONARY) { |
| + NOTREACHED(); |
| + return; |
| + } |
| + DictionaryVar* dictionary_var = DictionaryVar::FromPPVar(var); |
| + DCHECK(dictionary_var->key_value_map().empty()); |
| + for (size_t i = 0; i < children_.size(); ++i) { |
| + dictionary_var->Set(StringVar::StringToPPVar(children_[i].first), |
| + graph[children_[i].second]); |
| + } |
| +} |
| + |
| +void DictionaryRawVarData::Write( |
| + IPC::Message* m, |
| + const HandleWriter& handle_writer) { |
| + m->WriteUInt32(static_cast<uint32_t>(children_.size())); |
| + for (size_t i = 0; i < children_.size(); ++i) { |
| + m->WriteString(children_[i].first); |
| + m->WriteUInt32(static_cast<uint32_t>(children_[i].second)); |
| + } |
| +} |
| + |
| +bool DictionaryRawVarData::Read(PP_VarType type, |
| + const IPC::Message* m, |
| + PickleIterator* iter) { |
| + uint32_t size; |
| + if (!m->ReadUInt32(iter, &size)) |
| + return false; |
| + for (uint32_t i = 0; i < size; ++i) { |
| + std::string key; |
| + uint32_t value; |
| + if (!m->ReadString(iter, &key)) |
| + return false; |
| + if (!m->ReadUInt32(iter, &value)) |
| + return false; |
| + children_.push_back(make_pair(key, value)); |
| + } |
| + return true; |
| +} |
| + |
| +} // namespace proxy |
| +} // namespace ppapi |
|
dmichael (off chromium)
2013/04/15 17:40:04
I notice that you deleted VarGraph and this file i
|