| Index: webkit/plugins/ppapi/v8_var_converter.cc
|
| diff --git a/webkit/plugins/ppapi/v8_var_converter.cc b/webkit/plugins/ppapi/v8_var_converter.cc
|
| index a8952ff108b93a6afc9343d581de19236fb15678..ee7a64b31780f0d23f2dcb7f34002df19b2b7d4d 100644
|
| --- a/webkit/plugins/ppapi/v8_var_converter.cc
|
| +++ b/webkit/plugins/ppapi/v8_var_converter.cc
|
| @@ -27,6 +27,14 @@ using std::make_pair;
|
|
|
| namespace {
|
|
|
| +template <class T>
|
| +struct StackEntry {
|
| + StackEntry(T v) : val(v), sentinel(false) {}
|
| + T val;
|
| + // Used to track parent nodes on the stack as traversing the graph.
|
| + bool sentinel;
|
| +};
|
| +
|
| struct HashedHandle {
|
| HashedHandle(v8::Handle<v8::Object> h) : handle(h) {}
|
| size_t hash() const { return handle->GetIdentityHash(); }
|
| @@ -59,9 +67,11 @@ namespace {
|
|
|
| // Maps PP_Var IDs to the V8 value handle they correspond to.
|
| typedef base::hash_map<int64_t, v8::Handle<v8::Value> > VarHandleMap;
|
| +typedef base::hash_set<int64_t> ParentVarSet;
|
|
|
| // Maps V8 value handles to the PP_Var they correspond to.
|
| typedef base::hash_map<HashedHandle, ScopedPPVar> HandleVarMap;
|
| +typedef base::hash_set<HashedHandle> ParentHandleSet;
|
|
|
| // Returns a V8 value which corresponds to a given PP_Var. If |var| is a
|
| // reference counted PP_Var type, and it exists in |visited_ids|, the V8 value
|
| @@ -71,10 +81,14 @@ typedef base::hash_map<HashedHandle, ScopedPPVar> HandleVarMap;
|
| bool GetOrCreateV8Value(const PP_Var& var,
|
| v8::Handle<v8::Value>* result,
|
| bool* did_create,
|
| - VarHandleMap* visited_ids) {
|
| + VarHandleMap* visited_ids,
|
| + ParentVarSet* parent_ids,
|
| + bool allow_cycles) {
|
| *did_create = false;
|
|
|
| if (::ppapi::VarTracker::IsVarTypeRefcounted(var.type)) {
|
| + if (!allow_cycles && parent_ids->count(var.value.as_id) != 0)
|
| + return false;
|
| VarHandleMap::iterator it = visited_ids->find(var.value.as_id);
|
| if (it != visited_ids->end()) {
|
| *result = it->second;
|
| @@ -151,7 +165,9 @@ bool GetOrCreateV8Value(const PP_Var& var,
|
| bool GetOrCreateVar(v8::Handle<v8::Value> val,
|
| PP_Var* result,
|
| bool* did_create,
|
| - HandleVarMap* visited_handles) {
|
| + HandleVarMap* visited_handles,
|
| + ParentHandleSet* parent_handles,
|
| + bool allow_cycles) {
|
| CHECK(!val.IsEmpty());
|
| *did_create = false;
|
|
|
| @@ -159,6 +175,11 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val,
|
| // we still add them to |visited_handles| so that the corresponding string
|
| // PP_Var created will be properly refcounted.
|
| if (val->IsObject() || val->IsString()) {
|
| + if (!allow_cycles &&
|
| + parent_handles->count(HashedHandle(val->ToObject())) != 0) {
|
| + return false;
|
| + }
|
| +
|
| HandleVarMap::const_iterator it = visited_handles->find(
|
| HashedHandle(val->ToObject()));
|
| if (it != visited_handles->end()) {
|
| @@ -193,8 +214,10 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val,
|
| *result = (new DictionaryVar())->GetPPVar();
|
| }
|
| } else {
|
| - NOTREACHED();
|
| - return false;
|
| + // Silently ignore the case where we can't convert to a Var as we may
|
| + // be trying to convert a type that doesn't have a corresponding
|
| + // PP_Var type.
|
| + return true;
|
| }
|
|
|
| *did_create = true;
|
| @@ -208,7 +231,8 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val,
|
|
|
| } // namespace
|
|
|
| -V8VarConverter::V8VarConverter() {
|
| +V8VarConverter::V8VarConverter(bool allow_cycles)
|
| + : allow_cycles_(allow_cycles) {
|
| }
|
|
|
| bool V8VarConverter::ToV8Value(const PP_Var& var,
|
| @@ -218,19 +242,29 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
|
| v8::HandleScope handle_scope;
|
|
|
| VarHandleMap visited_ids;
|
| + ParentVarSet parent_ids;
|
|
|
| - std::stack<PP_Var> stack;
|
| - stack.push(var);
|
| + std::stack<StackEntry<PP_Var> > stack;
|
| + stack.push(StackEntry<PP_Var>(var));
|
| v8::Handle<v8::Value> root;
|
| bool is_root = true;
|
|
|
| while (!stack.empty()) {
|
| - const PP_Var& current_var = stack.top();
|
| + const PP_Var& current_var = stack.top().val;
|
| v8::Handle<v8::Value> current_v8;
|
| - stack.pop();
|
| +
|
| + if (stack.top().sentinel) {
|
| + stack.pop();
|
| + if (::ppapi::VarTracker::IsVarTypeRefcounted(current_var.type))
|
| + parent_ids.erase(current_var.value.as_id);
|
| + continue;
|
| + } else {
|
| + stack.top().sentinel = true;
|
| + }
|
| +
|
| bool did_create = false;
|
| if (!GetOrCreateV8Value(current_var, ¤t_v8, &did_create,
|
| - &visited_ids)) {
|
| + &visited_ids, &parent_ids, allow_cycles_)) {
|
| return false;
|
| }
|
|
|
| @@ -241,6 +275,7 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
|
|
|
| // Add child nodes to the stack.
|
| if (current_var.type == PP_VARTYPE_ARRAY) {
|
| + parent_ids.insert(current_var.value.as_id);
|
| ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
|
| if (!array_var) {
|
| NOTREACHED();
|
| @@ -253,7 +288,7 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
|
| const PP_Var& child_var = array_var->elements()[i].get();
|
| v8::Handle<v8::Value> child_v8;
|
| if (!GetOrCreateV8Value(child_var, &child_v8, &did_create,
|
| - &visited_ids)) {
|
| + &visited_ids, &parent_ids, allow_cycles_)) {
|
| return false;
|
| }
|
| if (did_create &&
|
| @@ -269,6 +304,7 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
|
| }
|
| }
|
| } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
|
| + parent_ids.insert(current_var.value.as_id);
|
| DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
|
| if (!dict_var) {
|
| NOTREACHED();
|
| @@ -285,7 +321,7 @@ bool V8VarConverter::ToV8Value(const PP_Var& var,
|
| const PP_Var& child_var = iter->second.get();
|
| v8::Handle<v8::Value> child_v8;
|
| if (!GetOrCreateV8Value(child_var, &child_v8, &did_create,
|
| - &visited_ids)) {
|
| + &visited_ids, &parent_ids, allow_cycles_)) {
|
| return false;
|
| }
|
| if (did_create &&
|
| @@ -315,19 +351,29 @@ bool V8VarConverter::FromV8Value(v8::Handle<v8::Value> val,
|
| v8::HandleScope handle_scope;
|
|
|
| HandleVarMap visited_handles;
|
| + ParentHandleSet parent_handles;
|
|
|
| - std::stack<v8::Handle<v8::Value> > stack;
|
| - stack.push(val);
|
| + std::stack<StackEntry<v8::Handle<v8::Value> > > stack;
|
| + stack.push(StackEntry<v8::Handle<v8::Value> >(val));
|
| ScopedPPVar root;
|
| bool is_root = true;
|
|
|
| while (!stack.empty()) {
|
| - v8::Handle<v8::Value> current_v8 = stack.top();
|
| + v8::Handle<v8::Value> current_v8 = stack.top().val;
|
| PP_Var current_var;
|
| - stack.pop();
|
| +
|
| + if (stack.top().sentinel) {
|
| + stack.pop();
|
| + if (current_v8->IsObject())
|
| + parent_handles.erase(HashedHandle(current_v8->ToObject()));
|
| + continue;
|
| + } else {
|
| + stack.top().sentinel = true;
|
| + }
|
| +
|
| bool did_create = false;
|
| if (!GetOrCreateVar(current_v8, ¤t_var, &did_create,
|
| - &visited_handles)) {
|
| + &visited_handles, &parent_handles, allow_cycles_)) {
|
| return false;
|
| }
|
|
|
| @@ -340,6 +386,7 @@ bool V8VarConverter::FromV8Value(v8::Handle<v8::Value> val,
|
| if (current_var.type == PP_VARTYPE_ARRAY) {
|
| DCHECK(current_v8->IsArray());
|
| v8::Handle<v8::Array> v8_array = current_v8.As<v8::Array>();
|
| + parent_handles.insert(HashedHandle(v8_array));
|
|
|
| ArrayVar* array_var = ArrayVar::FromPPVar(current_var);
|
| if (!array_var) {
|
| @@ -358,11 +405,8 @@ bool V8VarConverter::FromV8Value(v8::Handle<v8::Value> val,
|
|
|
| PP_Var child_var;
|
| if (!GetOrCreateVar(child_v8, &child_var, &did_create,
|
| - &visited_handles)) {
|
| - // Silently ignore the case where we can't convert to a Var as we may
|
| - // be trying to convert a type that doesn't have a corresponding
|
| - // PP_Var type.
|
| - continue;
|
| + &visited_handles, &parent_handles, allow_cycles_)) {
|
| + return false;
|
| }
|
| if (did_create && child_v8->IsObject())
|
| stack.push(child_v8);
|
| @@ -372,6 +416,7 @@ bool V8VarConverter::FromV8Value(v8::Handle<v8::Value> val,
|
| } else if (current_var.type == PP_VARTYPE_DICTIONARY) {
|
| DCHECK(current_v8->IsObject());
|
| v8::Handle<v8::Object> v8_object = current_v8->ToObject();
|
| + parent_handles.insert(HashedHandle(v8_object));
|
|
|
| DictionaryVar* dict_var = DictionaryVar::FromPPVar(current_var);
|
| if (!dict_var) {
|
| @@ -403,8 +448,8 @@ bool V8VarConverter::FromV8Value(v8::Handle<v8::Value> val,
|
|
|
| PP_Var child_var;
|
| if (!GetOrCreateVar(child_v8, &child_var, &did_create,
|
| - &visited_handles)) {
|
| - continue;
|
| + &visited_handles, &parent_handles, allow_cycles_)) {
|
| + return false;
|
| }
|
| if (did_create && child_v8->IsObject())
|
| stack.push(child_v8);
|
|
|