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
|