| Index: ppapi/proxy/raw_var_data.cc
|
| diff --git a/ppapi/proxy/raw_var_data.cc b/ppapi/proxy/raw_var_data.cc
|
| index 4de51ae1c4b4a4ced1edcda4e7d9b084eb51ce70..a550c3fca052892976c32288a6b807fa4cff211f 100644
|
| --- a/ppapi/proxy/raw_var_data.cc
|
| +++ b/ppapi/proxy/raw_var_data.cc
|
| @@ -31,25 +31,27 @@ static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024;
|
| static uint32 g_minimum_array_buffer_size_for_shmem =
|
| kMinimumArrayBufferSizeForShmem;
|
|
|
| -void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) {
|
| - IPC::ParamTraits<SerializedHandle>::Write(m, handle);
|
| -}
|
| +struct StackEntry {
|
| + StackEntry(PP_Var v, size_t i) : var(v), data_index(i) {}
|
| + PP_Var var;
|
| + size_t data_index;
|
| +};
|
|
|
| // 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.
|
| +// |visited_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,
|
| + base::hash_map<int64_t, size_t>* visited_map,
|
| ScopedVector<RawVarData>* data) {
|
| if (VarTracker::IsVarTypeRefcounted(var.type)) {
|
| - base::hash_map<int64_t, size_t>::iterator it = id_map->find(
|
| + base::hash_map<int64_t, size_t>::iterator it = visited_map->find(
|
| var.value.as_id);
|
| - if (it != id_map->end()) {
|
| + if (it != visited_map->end()) {
|
| return it->second;
|
| } else {
|
| data->push_back(RawVarData::Create(var.type));
|
| - (*id_map)[var.value.as_id] = data->size() - 1;
|
| + (*visited_map)[var.value.as_id] = data->size() - 1;
|
| }
|
| } else {
|
| data->push_back(RawVarData::Create(var.type));
|
| @@ -57,6 +59,10 @@ size_t GetOrCreateRawVarData(const PP_Var& var,
|
| return data->size() - 1;
|
| }
|
|
|
| +bool CanHaveChildren(PP_Var var) {
|
| + return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // RawVarDataGraph ------------------------------------------------------------
|
| @@ -66,27 +72,40 @@ RawVarDataGraph::RawVarDataGraph() {
|
| RawVarDataGraph::~RawVarDataGraph() {
|
| }
|
|
|
| +// This function uses a stack-based DFS search to traverse the var graph. Each
|
| +// iteration, the top node on the stack examined. If the node has not been
|
| +// visited yet (i.e. !initialized()) then it is added to the list of
|
| +// |parent_ids| which contains all of the nodes on the path from the start node
|
| +// to the current node. Each of that nodes children are examined. If they appear
|
| +// in the list of |parent_ids| it means we have a cycle and we return NULL.
|
| +// Otherwise, if they haven't been visited yet we add them to the stack, If the
|
| +// node at the top of the stack has already been visited, then we pop it off the
|
| +// stack and erase it from |parent_ids|.
|
| // 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;
|
| + base::hash_map<int64_t, size_t> visited_map;
|
| + base::hash_set<int64_t> parent_ids;
|
|
|
| - std::stack<std::pair<PP_Var, size_t> > stack;
|
| - stack.push(make_pair(var, GetOrCreateRawVarData(var, &id_map,
|
| - &graph->data_)));
|
| + std::stack<StackEntry> stack;
|
| + stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_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();
|
| + PP_Var current_var = stack.top().var;
|
| + RawVarData* current_var_data = graph->data_[stack.top().data_index];
|
|
|
| - // If the node is initialized, it means we have visited it.
|
| - if (current_var_data->initialized())
|
| + if (current_var_data->initialized()) {
|
| + stack.pop();
|
| + if (CanHaveChildren(current_var))
|
| + parent_ids.erase(current_var.value.as_id);
|
| continue;
|
| + }
|
|
|
| + if (CanHaveChildren(current_var))
|
| + parent_ids.insert(current_var.value.as_id);
|
| if (!current_var_data->Init(current_var, instance)) {
|
| NOTREACHED();
|
| return scoped_ptr<RawVarDataGraph>();
|
| @@ -103,10 +122,16 @@ scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
|
| array_var->elements().begin();
|
| iter != array_var->elements().end();
|
| ++iter) {
|
| - size_t child_id = GetOrCreateRawVarData(iter->get(), &id_map,
|
| + const PP_Var& child = iter->get();
|
| + // If a child of this node is already in parent_ids, we have a cycle so
|
| + // we just return null.
|
| + if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0)
|
| + return scoped_ptr<RawVarDataGraph>();
|
| + size_t child_id = GetOrCreateRawVarData(child, &visited_map,
|
| &graph->data_);
|
| static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id);
|
| - stack.push(make_pair(iter->get(), child_id));
|
| + if (!graph->data_[child_id]->initialized())
|
| + stack.push(StackEntry(child, child_id));
|
| }
|
| } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
|
| DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
|
| @@ -118,11 +143,15 @@ scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var,
|
| dict_var->key_value_map().begin();
|
| iter != dict_var->key_value_map().end();
|
| ++iter) {
|
| - size_t child_id = GetOrCreateRawVarData(iter->second.get(), &id_map,
|
| + const PP_Var& child = iter->second.get();
|
| + if (CanHaveChildren(child) && parent_ids.count(child.value.as_id) != 0)
|
| + return scoped_ptr<RawVarDataGraph>();
|
| + size_t child_id = GetOrCreateRawVarData(child, &visited_map,
|
| &graph->data_);
|
| static_cast<DictionaryRawVarData*>(
|
| current_var_data)->AddChild(iter->first, child_id);
|
| - stack.push(make_pair(iter->second.get(), child_id));
|
| + if (!graph->data_[child_id]->initialized())
|
| + stack.push(StackEntry(child, child_id));
|
| }
|
| }
|
| }
|
| @@ -153,10 +182,6 @@ void RawVarDataGraph::Write(IPC::Message* m,
|
| }
|
| }
|
|
|
| -void RawVarDataGraph::Write(IPC::Message* m) {
|
| - Write(m, base::Bind(&DefaultHandleWriter));
|
| -}
|
| -
|
| // static
|
| scoped_ptr<RawVarDataGraph> RawVarDataGraph::Read(const IPC::Message* m,
|
| PickleIterator* iter) {
|
|
|