OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |