Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(594)

Unified Diff: ppapi/proxy/raw_var_data.cc

Issue 13887007: Introduce RawVarData and associated classes for serializing PP_Vars (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ppapi/proxy/raw_var_data.h ('k') | ppapi/proxy/raw_var_data_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..1c91556f7d59b9c15b8aa317dff4b765fa1efa99
--- /dev/null
+++ b/ppapi/proxy/raw_var_data.cc
@@ -0,0 +1,609 @@
+// 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.
+ 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::SwapValidatedUTF8StringIntoPPVar(&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) {
+ bool success = dictionary_var->SetWithStringKey(children_[i].first,
+ graph[children_[i].second]);
+ DCHECK(success);
+ }
+}
+
+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
« no previous file with comments | « ppapi/proxy/raw_var_data.h ('k') | ppapi/proxy/raw_var_data_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698