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

Side by Side Diff: ppapi/proxy/raw_var_data.cc

Issue 16140011: Don't send PP_Vars/V8 values with cycles across PostMessage (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ppapi/proxy/raw_var_data.h" 5 #include "ppapi/proxy/raw_var_data.h"
6 6
7 #include <stack> 7 #include <stack>
8 8
9 #include "base/containers/hash_tables.h" 9 #include "base/containers/hash_tables.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 13 matching lines...) Expand all
24 24
25 namespace { 25 namespace {
26 26
27 // When sending array buffers, if the size is over 256K, we use shared 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 28 // memory instead of sending the data over IPC. Light testing suggests
29 // shared memory is much faster for 256K and larger messages. 29 // shared memory is much faster for 256K and larger messages.
30 static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024; 30 static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024;
31 static uint32 g_minimum_array_buffer_size_for_shmem = 31 static uint32 g_minimum_array_buffer_size_for_shmem =
32 kMinimumArrayBufferSizeForShmem; 32 kMinimumArrayBufferSizeForShmem;
33 33
34 void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) { 34 struct StackEntry {
35 IPC::ParamTraits<SerializedHandle>::Write(m, handle); 35 StackEntry(PP_Var v, size_t i) : var(v), data_index(i) {}
36 } 36 PP_Var var;
37 size_t data_index;
38 };
37 39
38 // For a given PP_Var, returns the RawVarData associated with it, or creates a 40 // 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 41 // 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. 42 // 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. 43 // |visited_map| keeps track of RawVarDatas that have already been created.
42 size_t GetOrCreateRawVarData(const PP_Var& var, 44 size_t GetOrCreateRawVarData(const PP_Var& var,
43 base::hash_map<int64_t, size_t>* id_map, 45 base::hash_map<int64_t, size_t>* visited_map,
44 ScopedVector<RawVarData>* data) { 46 ScopedVector<RawVarData>* data) {
45 if (VarTracker::IsVarTypeRefcounted(var.type)) { 47 if (VarTracker::IsVarTypeRefcounted(var.type)) {
46 base::hash_map<int64_t, size_t>::iterator it = id_map->find( 48 base::hash_map<int64_t, size_t>::iterator it = visited_map->find(
47 var.value.as_id); 49 var.value.as_id);
48 if (it != id_map->end()) { 50 if (it != visited_map->end()) {
49 return it->second; 51 return it->second;
50 } else { 52 } else {
51 data->push_back(RawVarData::Create(var.type)); 53 data->push_back(RawVarData::Create(var.type));
52 (*id_map)[var.value.as_id] = data->size() - 1; 54 (*visited_map)[var.value.as_id] = data->size() - 1;
53 } 55 }
54 } else { 56 } else {
55 data->push_back(RawVarData::Create(var.type)); 57 data->push_back(RawVarData::Create(var.type));
56 } 58 }
57 return data->size() - 1; 59 return data->size() - 1;
58 } 60 }
59 61
62 bool CanHaveChildren(PP_Var var) {
63 return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY;
64 }
65
60 } // namespace 66 } // namespace
61 67
62 // RawVarDataGraph ------------------------------------------------------------ 68 // RawVarDataGraph ------------------------------------------------------------
63 RawVarDataGraph::RawVarDataGraph() { 69 RawVarDataGraph::RawVarDataGraph() {
64 } 70 }
65 71
66 RawVarDataGraph::~RawVarDataGraph() { 72 RawVarDataGraph::~RawVarDataGraph() {
67 } 73 }
68 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|.
69 // static 84 // static
70 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var, 85 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
71 PP_Instance instance) { 86 PP_Instance instance) {
72 scoped_ptr<RawVarDataGraph> graph(new RawVarDataGraph); 87 scoped_ptr<RawVarDataGraph> graph(new RawVarDataGraph);
73 // Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph. 88 // Map of |var.value.as_id| to a RawVarData index in RawVarDataGraph.
74 base::hash_map<int64_t, size_t> id_map; 89 base::hash_map<int64_t, size_t> visited_map;
90 base::hash_set<int64_t> parent_ids;
75 91
76 std::stack<std::pair<PP_Var, size_t> > stack; 92 std::stack<StackEntry> stack;
77 stack.push(make_pair(var, GetOrCreateRawVarData(var, &id_map, 93 stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_map,
78 &graph->data_))); 94 &graph->data_)));
79 95
80 // Traverse the PP_Var graph with DFS.
81 while (!stack.empty()) { 96 while (!stack.empty()) {
82 PP_Var current_var = stack.top().first; 97 PP_Var current_var = stack.top().var;
83 RawVarData* current_var_data = graph->data_[stack.top().second]; 98 RawVarData* current_var_data = graph->data_[stack.top().data_index];
84 stack.pop();
85 99
86 // If the node is initialized, it means we have visited it. 100 if (current_var_data->initialized()) {
87 if (current_var_data->initialized()) 101 stack.pop();
102 if (CanHaveChildren(current_var))
103 parent_ids.erase(current_var.value.as_id);
88 continue; 104 continue;
105 }
89 106
107 if (CanHaveChildren(current_var))
108 parent_ids.insert(current_var.value.as_id);
90 if (!current_var_data->Init(current_var, instance)) { 109 if (!current_var_data->Init(current_var, instance)) {
91 NOTREACHED(); 110 NOTREACHED();
92 return scoped_ptr<RawVarDataGraph>(); 111 return scoped_ptr<RawVarDataGraph>();
93 } 112 }
94 113
95 // Add child nodes to the stack. 114 // Add child nodes to the stack.
96 if (current_var.type == PP_VARTYPE_ARRAY) { 115 if (current_var.type == PP_VARTYPE_ARRAY) {
97 ArrayVar* array_var = ArrayVar::FromPPVar(current_var); 116 ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
98 if (!array_var) { 117 if (!array_var) {
99 NOTREACHED(); 118 NOTREACHED();
100 return scoped_ptr<RawVarDataGraph>(); 119 return scoped_ptr<RawVarDataGraph>();
101 } 120 }
102 for (ArrayVar::ElementVector::const_iterator iter = 121 for (ArrayVar::ElementVector::const_iterator iter =
103 array_var->elements().begin(); 122 array_var->elements().begin();
104 iter != array_var->elements().end(); 123 iter != array_var->elements().end();
105 ++iter) { 124 ++iter) {
106 size_t child_id = GetOrCreateRawVarData(iter->get(), &id_map, 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,
107 &graph->data_); 131 &graph->data_);
108 static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id); 132 static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id);
109 stack.push(make_pair(iter->get(), child_id)); 133 if (!graph->data_[child_id]->initialized())
134 stack.push(StackEntry(child, child_id));
110 } 135 }
111 } else if (current_var.type == PP_VARTYPE_DICTIONARY) { 136 } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
112 DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var); 137 DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
113 if (!dict_var) { 138 if (!dict_var) {
114 NOTREACHED(); 139 NOTREACHED();
115 return scoped_ptr<RawVarDataGraph>(); 140 return scoped_ptr<RawVarDataGraph>();
116 } 141 }
117 for (DictionaryVar::KeyValueMap::const_iterator iter = 142 for (DictionaryVar::KeyValueMap::const_iterator iter =
118 dict_var->key_value_map().begin(); 143 dict_var->key_value_map().begin();
119 iter != dict_var->key_value_map().end(); 144 iter != dict_var->key_value_map().end();
120 ++iter) { 145 ++iter) {
121 size_t child_id = GetOrCreateRawVarData(iter->second.get(), &id_map, 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,
122 &graph->data_); 150 &graph->data_);
123 static_cast<DictionaryRawVarData*>( 151 static_cast<DictionaryRawVarData*>(
124 current_var_data)->AddChild(iter->first, child_id); 152 current_var_data)->AddChild(iter->first, child_id);
125 stack.push(make_pair(iter->second.get(), child_id)); 153 if (!graph->data_[child_id]->initialized())
154 stack.push(StackEntry(child, child_id));
126 } 155 }
127 } 156 }
128 } 157 }
129 return graph.Pass(); 158 return graph.Pass();
130 } 159 }
131 160
132 PP_Var RawVarDataGraph::CreatePPVar(PP_Instance instance) { 161 PP_Var RawVarDataGraph::CreatePPVar(PP_Instance instance) {
133 // Create and initialize each node in the graph. 162 // Create and initialize each node in the graph.
134 std::vector<PP_Var> graph; 163 std::vector<PP_Var> graph;
135 for (size_t i = 0; i < data_.size(); ++i) 164 for (size_t i = 0; i < data_.size(); ++i)
(...skipping 10 matching lines...) Expand all
146 void RawVarDataGraph::Write(IPC::Message* m, 175 void RawVarDataGraph::Write(IPC::Message* m,
147 const HandleWriter& handle_writer) { 176 const HandleWriter& handle_writer) {
148 // Write the size, followed by each node in the graph. 177 // Write the size, followed by each node in the graph.
149 m->WriteUInt32(static_cast<uint32_t>(data_.size())); 178 m->WriteUInt32(static_cast<uint32_t>(data_.size()));
150 for (size_t i = 0; i < data_.size(); ++i) { 179 for (size_t i = 0; i < data_.size(); ++i) {
151 m->WriteInt(data_[i]->Type()); 180 m->WriteInt(data_[i]->Type());
152 data_[i]->Write(m, handle_writer); 181 data_[i]->Write(m, handle_writer);
153 } 182 }
154 } 183 }
155 184
156 void RawVarDataGraph::Write(IPC::Message* m) {
157 Write(m, base::Bind(&DefaultHandleWriter));
158 }
159
160 // static 185 // static
161 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m, 186 scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m,
162 PickleIterator* iter) { 187 PickleIterator* iter) {
163 scoped_ptr<RawVarDataGraph> result(new RawVarDataGraph); 188 scoped_ptr<RawVarDataGraph> result(new RawVarDataGraph);
164 uint32_t size = 0; 189 uint32_t size = 0;
165 if (!m->ReadUInt32(iter, &size)) 190 if (!m->ReadUInt32(iter, &size))
166 return scoped_ptr<RawVarDataGraph>(); 191 return scoped_ptr<RawVarDataGraph>();
167 for (uint32_t i = 0; i < size; ++i) { 192 for (uint32_t i = 0; i < size; ++i) {
168 int32_t type; 193 int32_t type;
169 if (!m->ReadInt(iter, &type)) 194 if (!m->ReadInt(iter, &type))
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 return false; 656 return false;
632 if (!m->ReadUInt32(iter, &value)) 657 if (!m->ReadUInt32(iter, &value))
633 return false; 658 return false;
634 children_.push_back(make_pair(key, value)); 659 children_.push_back(make_pair(key, value));
635 } 660 }
636 return true; 661 return true;
637 } 662 }
638 663
639 } // namespace proxy 664 } // namespace proxy
640 } // namespace ppapi 665 } // namespace ppapi
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698