diff options
-rw-r--r-- | ppapi/api/ppb_messaging.idl | 4 | ||||
-rw-r--r-- | ppapi/api/ppp_messaging.idl | 7 | ||||
-rw-r--r-- | ppapi/c/ppb_messaging.h | 6 | ||||
-rw-r--r-- | ppapi/c/ppp_messaging.h | 9 | ||||
-rw-r--r-- | ppapi/cpp/instance.h | 24 | ||||
-rw-r--r-- | ppapi/proxy/handle_converter.cc | 8 | ||||
-rw-r--r-- | ppapi/proxy/ppb_instance_proxy.cc | 10 | ||||
-rw-r--r-- | ppapi/proxy/raw_var_data.cc | 77 | ||||
-rw-r--r-- | ppapi/proxy/raw_var_data.h | 2 | ||||
-rw-r--r-- | ppapi/proxy/raw_var_data_unittest.cc | 32 | ||||
-rw-r--r-- | ppapi/proxy/serialized_var.cc | 39 | ||||
-rw-r--r-- | ppapi/proxy/serialized_var.h | 31 | ||||
-rw-r--r-- | ppapi/tests/test_post_message.cc | 48 | ||||
-rw-r--r-- | ppapi/tests/test_post_message.h | 4 | ||||
-rw-r--r-- | webkit/plugins/ppapi/message_channel.cc | 30 | ||||
-rw-r--r-- | webkit/plugins/ppapi/v8_var_converter.cc | 127 | ||||
-rw-r--r-- | webkit/plugins/ppapi/v8_var_converter.h | 36 | ||||
-rw-r--r-- | webkit/plugins/ppapi/v8_var_converter_unittest.cc | 86 |
18 files changed, 184 insertions, 396 deletions
diff --git a/ppapi/api/ppb_messaging.idl b/ppapi/api/ppb_messaging.idl index 0f9a3aa..647f7f6 100644 --- a/ppapi/api/ppb_messaging.idl +++ b/ppapi/api/ppb_messaging.idl @@ -36,8 +36,8 @@ interface PPB_Messaging { * JavaScript. * * When passing array or dictionary <code>PP_Var</code>s, the entire reference - * graph will be converted and transferred. If the reference graph has cycles, - * the message will not be sent and an error will be logged to the console. + * graph will be converted and transferred, including reference cycles if they + * exist. * * Listeners for message events in JavaScript code will receive an object * conforming to the HTML 5 <code>MessageEvent</code> interface. diff --git a/ppapi/api/ppp_messaging.idl b/ppapi/api/ppp_messaging.idl index 83c2010..150f771 100644 --- a/ppapi/api/ppp_messaging.idl +++ b/ppapi/api/ppp_messaging.idl @@ -36,9 +36,10 @@ interface PPP_Messaging { * * When converting JavaScript arrays, any object properties whose name * is not an array index are ignored. When passing arrays and objects, the - * entire reference graph will be converted and transferred. If the reference - * graph has cycles, the message will not be sent and an error will be logged - * to the console. + * entire reference graph will be converted and transferred, including + * reference cycles if they exist. Since <code>PP_Var</code>s are ref-counted, + * the author of the plugin must take care if they expect to receive vars with + * cycles. Cycles must be manually broken to correctly release the vars. * * The following JavaScript code invokes <code>HandleMessage</code>, passing * the module instance on which it was invoked, with <code>message</code> diff --git a/ppapi/c/ppb_messaging.h b/ppapi/c/ppb_messaging.h index 06e31205..404a11c 100644 --- a/ppapi/c/ppb_messaging.h +++ b/ppapi/c/ppb_messaging.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* From ppb_messaging.idl modified Wed Jun 5 10:32:59 2013. */ +/* From ppb_messaging.idl modified Mon May 20 15:31:07 2013. */ #ifndef PPAPI_C_PPB_MESSAGING_H_ #define PPAPI_C_PPB_MESSAGING_H_ @@ -50,8 +50,8 @@ struct PPB_Messaging_1_0 { * JavaScript. * * When passing array or dictionary <code>PP_Var</code>s, the entire reference - * graph will be converted and transferred. If the reference graph has cycles, - * the message will not be sent and an error will be logged to the console. + * graph will be converted and transferred, including reference cycles if they + * exist. * * Listeners for message events in JavaScript code will receive an object * conforming to the HTML 5 <code>MessageEvent</code> interface. diff --git a/ppapi/c/ppp_messaging.h b/ppapi/c/ppp_messaging.h index 28d40d6..b2e1f3c 100644 --- a/ppapi/c/ppp_messaging.h +++ b/ppapi/c/ppp_messaging.h @@ -3,7 +3,7 @@ * found in the LICENSE file. */ -/* From ppp_messaging.idl modified Wed Jun 5 10:32:43 2013. */ +/* From ppp_messaging.idl modified Tue May 21 09:01:17 2013. */ #ifndef PPAPI_C_PPP_MESSAGING_H_ #define PPAPI_C_PPP_MESSAGING_H_ @@ -52,9 +52,10 @@ struct PPP_Messaging_1_0 { * * When converting JavaScript arrays, any object properties whose name * is not an array index are ignored. When passing arrays and objects, the - * entire reference graph will be converted and transferred. If the reference - * graph has cycles, the message will not be sent and an error will be logged - * to the console. + * entire reference graph will be converted and transferred, including + * reference cycles if they exist. Since <code>PP_Var</code>s are ref-counted, + * the author of the plugin must take care if they expect to receive vars with + * cycles. Cycles must be manually broken to correctly release the vars. * * The following JavaScript code invokes <code>HandleMessage</code>, passing * the module instance on which it was invoked, with <code>message</code> diff --git a/ppapi/cpp/instance.h b/ppapi/cpp/instance.h index 6bf4e83..48bca90 100644 --- a/ppapi/cpp/instance.h +++ b/ppapi/cpp/instance.h @@ -244,12 +244,6 @@ class Instance { /// JavaScript execution will not be blocked while HandleMessage() is /// processing the message. /// - /// When converting JavaScript arrays, any object properties whose name - /// is not an array index are ignored. When passing arrays and objects, the - /// entire reference graph will be converted and transferred. If the reference - /// graph has cycles, the message will not be sent and an error will be logged - /// to the console. - /// /// <strong>Example:</strong> /// /// The following JavaScript code invokes <code>HandleMessage</code>, passing @@ -270,10 +264,9 @@ class Instance { /// /// Refer to PostMessage() for sending messages to JavaScript. /// - /// @param[in] message A <code>Var</code> which has been converted from a - /// JavaScript value. JavaScript array/object types are supported from Chrome - /// M29 onward. All JavaScript values are copied when passing them to the - /// plugin. + /// @param[in] message A <code>Var</code> containing the data sent from + /// JavaScript. Message can have an int32_t, double, bool, or string value + /// (objects are not supported). virtual void HandleMessage(const Var& message); /// @} @@ -460,11 +453,6 @@ class Instance { /// /// The browser will pop-up an alert saying "Hello world!" /// - /// When passing array or dictionary <code>PP_Var</code>s, the entire - /// reference graph will be converted and transferred. If the reference graph - /// has cycles, the message will not be sent and an error will be logged to - /// the console. - /// /// Listeners for message events in JavaScript code will receive an object /// conforming to the HTML 5 <code>MessageEvent</code> interface. /// Specifically, the value of message will be contained as a property called @@ -478,9 +466,9 @@ class Instance { /// Refer to HandleMessage() for receiving events from JavaScript. /// /// @param[in] message A <code>Var</code> containing the data to be sent to - /// JavaScript. Message can have a numeric, boolean, or string value. - /// Array/Dictionary types are supported from Chrome M29 onward. - /// All var types are copied when passing them to JavaScript. + /// JavaScript. Message can have a numeric, boolean, or string value; arrays + /// and dictionaries are not yet supported. Ref-counted var types are copied, + /// and are therefore not shared between the instance and the browser. void PostMessage(const Var& message); /// @} diff --git a/ppapi/proxy/handle_converter.cc b/ppapi/proxy/handle_converter.cc index d2fc4a9..b77ee49 100644 --- a/ppapi/proxy/handle_converter.cc +++ b/ppapi/proxy/handle_converter.cc @@ -54,14 +54,18 @@ void ConvertHandlesInParam(const ppapi::proxy::SerializedVar& var, Handles* handles, IPC::Message* msg, int* handle_index) { - std::vector<ppapi::proxy::SerializedHandle*> var_handles = var.GetHandles(); + if (!var.raw_var_data()) + return; + + std::vector<ppapi::proxy::SerializedHandle*> var_handles = + var.raw_var_data()->GetHandles(); if (var_handles.empty()) return; for (size_t i = 0; i < var_handles.size(); ++i) handles->push_back(*var_handles[i]); if (msg) - var.WriteDataToMessage(msg, base::Bind(&HandleWriter, handle_index)); + var.raw_var_data()->Write(msg, base::Bind(&HandleWriter, handle_index)); } // For PpapiMsg_ResourceReply and the reply to PpapiHostMsg_ResourceSyncCall, diff --git a/ppapi/proxy/ppb_instance_proxy.cc b/ppapi/proxy/ppb_instance_proxy.cc index e3948f06a..4009a19 100644 --- a/ppapi/proxy/ppb_instance_proxy.cc +++ b/ppapi/proxy/ppb_instance_proxy.cc @@ -56,10 +56,6 @@ namespace proxy { namespace { -const char kSerializationError[] = "Failed to convert a PostMessage " - "argument from a PP_Var to a Javascript value. It may have cycles or be of " - "an unsupported type."; - InterfaceProxy* CreateInstanceProxy(Dispatcher* dispatcher) { return new PPB_Instance_Proxy(dispatcher); } @@ -937,12 +933,6 @@ void PPB_Instance_Proxy::OnHostMsgPostMessage( PP_Instance instance, SerializedVarReceiveInput message) { EnterInstanceNoLock enter(instance); - if (!message.is_valid_var()) { - PpapiGlobals::Get()->LogWithSource( - instance, PP_LOGLEVEL_ERROR, std::string(), kSerializationError); - return; - } - if (enter.succeeded()) enter.functions()->PostMessage(instance, message.GetForInstance(dispatcher(), diff --git a/ppapi/proxy/raw_var_data.cc b/ppapi/proxy/raw_var_data.cc index a550c3f..4de51ae 100644 --- a/ppapi/proxy/raw_var_data.cc +++ b/ppapi/proxy/raw_var_data.cc @@ -31,27 +31,25 @@ static const uint32 kMinimumArrayBufferSizeForShmem = 256 * 1024; static uint32 g_minimum_array_buffer_size_for_shmem = kMinimumArrayBufferSizeForShmem; -struct StackEntry { - StackEntry(PP_Var v, size_t i) : var(v), data_index(i) {} - PP_Var var; - size_t data_index; -}; +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. -// |visited_map| keeps track of RawVarDatas that have already been created. +// |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>* visited_map, + 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 = visited_map->find( + base::hash_map<int64_t, size_t>::iterator it = id_map->find( var.value.as_id); - if (it != visited_map->end()) { + if (it != id_map->end()) { return it->second; } else { data->push_back(RawVarData::Create(var.type)); - (*visited_map)[var.value.as_id] = data->size() - 1; + (*id_map)[var.value.as_id] = data->size() - 1; } } else { data->push_back(RawVarData::Create(var.type)); @@ -59,10 +57,6 @@ 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 ------------------------------------------------------------ @@ -72,40 +66,27 @@ 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> visited_map; - base::hash_set<int64_t> parent_ids; + base::hash_map<int64_t, size_t> id_map; - std::stack<StackEntry> stack; - stack.push(StackEntry(var, GetOrCreateRawVarData(var, &visited_map, - &graph->data_))); + 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().var; - RawVarData* current_var_data = graph->data_[stack.top().data_index]; + PP_Var current_var = stack.top().first; + RawVarData* current_var_data = graph->data_[stack.top().second]; + stack.pop(); - if (current_var_data->initialized()) { - stack.pop(); - if (CanHaveChildren(current_var)) - parent_ids.erase(current_var.value.as_id); + // If the node is initialized, it means we have visited it. + if (current_var_data->initialized()) 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>(); @@ -122,16 +103,10 @@ scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var, array_var->elements().begin(); iter != array_var->elements().end(); ++iter) { - 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, + size_t child_id = GetOrCreateRawVarData(iter->get(), &id_map, &graph->data_); static_cast<ArrayRawVarData*>(current_var_data)->AddChild(child_id); - if (!graph->data_[child_id]->initialized()) - stack.push(StackEntry(child, 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); @@ -143,15 +118,11 @@ scoped_ptr<RawVarDataGraph> RawVarDataGraph::Create(const PP_Var& var, dict_var->key_value_map().begin(); iter != dict_var->key_value_map().end(); ++iter) { - 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, + size_t child_id = GetOrCreateRawVarData(iter->second.get(), &id_map, &graph->data_); static_cast<DictionaryRawVarData*>( current_var_data)->AddChild(iter->first, child_id); - if (!graph->data_[child_id]->initialized()) - stack.push(StackEntry(child, child_id)); + stack.push(make_pair(iter->second.get(), child_id)); } } } @@ -182,6 +153,10 @@ 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) { diff --git a/ppapi/proxy/raw_var_data.h b/ppapi/proxy/raw_var_data.h index c7981d3..1e8746f 100644 --- a/ppapi/proxy/raw_var_data.h +++ b/ppapi/proxy/raw_var_data.h @@ -65,6 +65,8 @@ class PPAPI_PROXY_EXPORT RawVarDataGraph { // Write the graph to a message using the given HandleWriter. void Write(IPC::Message* m, const HandleWriter& handle_writer); + // Write the graph to a message using the default handle writer. + void Write(IPC::Message* m); // Create a RawVarDataGraph from the given message. static scoped_ptr<RawVarDataGraph> Read(const IPC::Message* m, diff --git a/ppapi/proxy/raw_var_data_unittest.cc b/ppapi/proxy/raw_var_data_unittest.cc index 2ee6914..2b134af 100644 --- a/ppapi/proxy/raw_var_data_unittest.cc +++ b/ppapi/proxy/raw_var_data_unittest.cc @@ -26,10 +26,6 @@ namespace proxy { namespace { -void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) { - IPC::ParamTraits<SerializedHandle>::Write(m, handle); -} - class RawVarDataTest : public testing::Test { public: RawVarDataTest() {} @@ -48,28 +44,21 @@ class RawVarDataTest : public testing::Test { TestGlobals globals_; }; -bool WriteAndRead(const PP_Var& var, PP_Var* result) { +PP_Var WriteAndRead(const PP_Var& var) { PP_Instance dummy_instance = 1234; scoped_ptr<RawVarDataGraph> expected_data(RawVarDataGraph::Create( var, dummy_instance)); - if (!expected_data) - return false; IPC::Message m; - expected_data->Write(&m, base::Bind(&DefaultHandleWriter)); + expected_data->Write(&m); PickleIterator iter(m); scoped_ptr<RawVarDataGraph> actual_data(RawVarDataGraph::Read(&m, &iter)); - *result = actual_data->CreatePPVar(dummy_instance); - return true; + return actual_data->CreatePPVar(dummy_instance); } // Assumes a ref for var. bool WriteReadAndCompare(const PP_Var& var) { ScopedPPVar expected(ScopedPPVar::PassRef(), var); - PP_Var result; - bool success = WriteAndRead(expected.get(), &result); - if (!success) - return false; - ScopedPPVar actual(ScopedPPVar::PassRef(), result); + ScopedPPVar actual(ScopedPPVar::PassRef(), WriteAndRead(expected.get())); return TestEqual(expected.get(), actual.get()); } @@ -171,18 +160,25 @@ TEST_F(RawVarDataTest, DictionaryArrayTest) { // Array <-> dictionary cycle. dictionary->SetWithStringKey("10", release_array.get()); - PP_Var result; - ASSERT_FALSE(WriteAndRead(release_dictionary.get(), &result)); + ScopedPPVar result = ScopedPPVar(ScopedPPVar::PassRef(), + WriteAndRead(release_dictionary.get())); + EXPECT_TRUE(TestEqual(release_dictionary.get(), result.get())); // Break the cycle. // TODO(raymes): We need some better machinery for releasing vars with // cycles. Remove the code below once we have that. dictionary->DeleteWithStringKey("10"); + DictionaryVar* result_dictionary = DictionaryVar::FromPPVar(result.get()); + result_dictionary->DeleteWithStringKey("10"); // Array with self references. array->Set(index, release_array.get()); - ASSERT_FALSE(WriteAndRead(release_array.get(), &result)); + result = ScopedPPVar(ScopedPPVar::PassRef(), + WriteAndRead(release_array.get())); + EXPECT_TRUE(TestEqual(release_array.get(), result.get())); // Break the self reference. array->Set(index, PP_MakeUndefined()); + ArrayVar* result_array = ArrayVar::FromPPVar(result.get()); + result_array->Set(index, PP_MakeUndefined()); } } // namespace proxy diff --git a/ppapi/proxy/serialized_var.cc b/ppapi/proxy/serialized_var.cc index 72e7cc8..1217a83 100644 --- a/ppapi/proxy/serialized_var.cc +++ b/ppapi/proxy/serialized_var.cc @@ -18,20 +18,13 @@ namespace ppapi { namespace proxy { -namespace { -void DefaultHandleWriter(IPC::Message* m, const SerializedHandle& handle) { - IPC::ParamTraits<SerializedHandle>::Write(m, handle); -} -} // namespace - // SerializedVar::Inner -------------------------------------------------------- SerializedVar::Inner::Inner() : serialization_rules_(NULL), var_(PP_MakeUndefined()), instance_(0), - cleanup_mode_(CLEANUP_NONE), - is_valid_var_(true) { + cleanup_mode_(CLEANUP_NONE) { #ifndef NDEBUG has_been_serialized_ = false; has_been_deserialized_ = false; @@ -114,24 +107,7 @@ void SerializedVar::Inner::WriteToMessage(IPC::Message* m) const { DCHECK(!has_been_serialized_); has_been_serialized_ = true; #endif - scoped_ptr<RawVarDataGraph> data = RawVarDataGraph::Create(var_, instance_); - if (data) { - m->WriteBool(true); // Success. - data->Write(m, base::Bind(&DefaultHandleWriter)); - } else { - m->WriteBool(false); // Failure. - } -} - -void SerializedVar::Inner::WriteDataToMessage( - IPC::Message* m, - const HandleWriter& handle_writer) const { - if (raw_var_data_) { - m->WriteBool(true); // Success. - raw_var_data_->Write(m, handle_writer); - } else { - m->WriteBool(false); // Failure. - } + RawVarDataGraph::Create(var_, instance_)->Write(m); } bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, @@ -149,15 +125,8 @@ bool SerializedVar::Inner::ReadFromMessage(const IPC::Message* m, #endif // When reading, the dispatcher should be set when we get a Deserialize // call (which will supply a dispatcher). - if (!m->ReadBool(iter, &is_valid_var_)) - return false; - if (is_valid_var_) { - raw_var_data_ = RawVarDataGraph::Read(m, iter); - if (!raw_var_data_) - return false; - } - - return true; + raw_var_data_ = RawVarDataGraph::Read(m, iter); + return raw_var_data_.get() != NULL; } void SerializedVar::Inner::SetCleanupModeToEndSendPassRef() { diff --git a/ppapi/proxy/serialized_var.h b/ppapi/proxy/serialized_var.h index 0b8e796..98cafa0 100644 --- a/ppapi/proxy/serialized_var.h +++ b/ppapi/proxy/serialized_var.h @@ -80,24 +80,12 @@ class PPAPI_PROXY_EXPORT SerializedVar { void WriteToMessage(IPC::Message* m) const { inner_->WriteToMessage(m); } - // If ReadFromMessage has been called, WriteDataToMessage will write the var - // that has been read from ReadFromMessage back to a message. This is used - // when converting handles for use in NaCl. - void WriteDataToMessage(IPC::Message* m, - const HandleWriter& handle_writer) const { - inner_->WriteDataToMessage(m, handle_writer); - } bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter) { return inner_->ReadFromMessage(m, iter); } - bool is_valid_var() const { - return inner_->is_valid_var(); - } - - // Returns the shared memory handles associated with this SerializedVar. - std::vector<SerializedHandle*> GetHandles() const { - return inner_->GetHandles(); + RawVarDataGraph* raw_var_data() const { + return inner_->raw_var_data(); } protected: @@ -122,13 +110,8 @@ class PPAPI_PROXY_EXPORT SerializedVar { serialization_rules_ = serialization_rules; } - bool is_valid_var() const { - return is_valid_var_; - } - - std::vector<SerializedHandle*> GetHandles() { - return (raw_var_data_ ? raw_var_data_->GetHandles() : - std::vector<SerializedHandle*>()); + RawVarDataGraph* raw_var_data() { + return raw_var_data_.get(); } // See outer class's declarations above. @@ -141,8 +124,6 @@ class PPAPI_PROXY_EXPORT SerializedVar { void ForceSetVarValueForTest(PP_Var value); void WriteToMessage(IPC::Message* m) const; - void WriteDataToMessage(IPC::Message* m, - const HandleWriter& handle_writer) const; bool ReadFromMessage(const IPC::Message* m, PickleIterator* iter); // Sets the cleanup mode. See the CleanupMode enum below. @@ -181,9 +162,6 @@ class PPAPI_PROXY_EXPORT SerializedVar { CleanupMode cleanup_mode_; - // If the var is not properly serialized, this will be false. - bool is_valid_var_; - #ifndef NDEBUG // When being sent or received over IPC, we should only be serialized or // deserialized once. These flags help us assert this is true. @@ -364,7 +342,6 @@ class PPAPI_PROXY_EXPORT SerializedVarReceiveInput { PP_Var Get(Dispatcher* dispatcher); PP_Var GetForInstance(Dispatcher* dispatcher, PP_Instance instance); - bool is_valid_var() { return serialized_.is_valid_var(); } private: const SerializedVar& serialized_; diff --git a/ppapi/tests/test_post_message.cc b/ppapi/tests/test_post_message.cc index 944b5614..8c67ee5 100644 --- a/ppapi/tests/test_post_message.cc +++ b/ppapi/tests/test_post_message.cc @@ -238,16 +238,6 @@ bool TestPostMessage::AddEchoingListener(const std::string& expression) { return true; } -bool TestPostMessage::PostMessageFromJavaScript(const std::string& func) { - std::string js_code; - js_code += "var plugin = document.getElementById('plugin');" - "plugin.postMessage("; - js_code += func + "()"; - js_code += " );"; - instance_->EvalScript(js_code); - return true; -} - bool TestPostMessage::ClearListeners() { std::string js_code; js_code += "var plugin = document.getElementById('plugin');" @@ -533,7 +523,6 @@ std::string TestPostMessage::TestSendingComplexVar() { // if we didn't run the 'SendInInit' test. All tests other than 'SendInInit' // should start with these. WaitForMessages(); - message_data_.clear(); ASSERT_TRUE(ClearListeners()); pp::Var string(kTestString); @@ -542,6 +531,7 @@ std::string TestPostMessage::TestSendingComplexVar() { dictionary.Set(pp::Var("bar"), string); dictionary.Set(pp::Var("abc"), pp::Var(kTestInt)); dictionary.Set(pp::Var("def"), pp::Var()); + dictionary.Set(pp::Var("dictionary"), dictionary); // Self-reference. // Reference to array. pp::VarArray_Dev array; @@ -554,9 +544,15 @@ std::string TestPostMessage::TestSendingComplexVar() { dictionary.Set(pp::Var("array-ref1"), array); dictionary.Set(pp::Var("array-ref2"), array); + // Set up a (dictionary -> array -> dictionary) cycle. + pp::VarArray_Dev array2; + array2.Set(0, dictionary); + dictionary.Set(pp::Var("array2"), array2); + // Set up the JavaScript message event listener to echo the data part of the // message event back to us. ASSERT_TRUE(AddEchoingListener("message_event.data")); + message_data_.clear(); instance_->PostMessage(dictionary); // PostMessage is asynchronous, so we should not receive a response yet. ASSERT_EQ(message_data_.size(), 0); @@ -565,36 +561,12 @@ std::string TestPostMessage::TestSendingComplexVar() { pp::VarDictionary_Dev result(message_data_.back()); ASSERT_TRUE(VarsEqual(dictionary, message_data_.back())); - WaitForMessages(); - message_data_.clear(); - ASSERT_TRUE(ClearListeners()); - - // Set up a (dictionary -> array -> dictionary) cycle. Cycles shouldn't be - // transmitted. - pp::VarArray_Dev array2; - array2.Set(0, dictionary); - dictionary.Set(pp::Var("array2"), array2); - - ASSERT_TRUE(AddEchoingListener("message_event.data")); - instance_->PostMessage(dictionary); - // PostMessage is asynchronous, so we should not receive a response yet. - ASSERT_EQ(message_data_.size(), 0); - ASSERT_EQ(WaitForMessages(), 0); - // Break the cycles. + dictionary.Delete(pp::Var("dictionary")); dictionary.Delete(pp::Var("array2")); + result.Delete(pp::Var("dictionary")); + result.Delete(pp::Var("array2")); - WaitForMessages(); - message_data_.clear(); - ASSERT_TRUE(ClearListeners()); - - // Test sending a cycle from JavaScript to the plugin. - ASSERT_TRUE(AddEchoingListener("message_event.data")); - PostMessageFromJavaScript("function() { var x = []; x[0] = x; return x; }"); - ASSERT_EQ(message_data_.size(), 0); - ASSERT_EQ(WaitForMessages(), 0); - - WaitForMessages(); message_data_.clear(); ASSERT_TRUE(ClearListeners()); diff --git a/ppapi/tests/test_post_message.h b/ppapi/tests/test_post_message.h index 2f2f628..3ea69e8 100644 --- a/ppapi/tests/test_post_message.h +++ b/ppapi/tests/test_post_message.h @@ -34,10 +34,6 @@ class TestPostMessage : public TestCase { // Returns true on success, false on failure. bool AddEchoingListener(const std::string& expression); - // Posts a message from JavaScript to the plugin. |func| should be a - // JavaScript function which returns the variable to post. - bool PostMessageFromJavaScript(const std::string& func); - // Clear any listeners that have been added using AddEchoingListener by // calling removeEventListener for each. // Returns true on success, false on failure. diff --git a/webkit/plugins/ppapi/message_channel.cc b/webkit/plugins/ppapi/message_channel.cc index 76e0f3e..2984a92 100644 --- a/webkit/plugins/ppapi/message_channel.cc +++ b/webkit/plugins/ppapi/message_channel.cc @@ -45,12 +45,6 @@ namespace ppapi { namespace { const char kPostMessage[] = "postMessage"; -const char kV8ToVarConversionError[] = "Failed to convert a PostMessage " - "argument from a JavaScript value to a PP_Var. It may have cycles or be of " - "an unsupported type."; -const char kVarToV8ConversionError[] = "Failed to convert a PostMessage " - "argument from a PP_Var to a Javascript value. It may have cycles or be of " - "an unsupported type."; // Helper function to get the MessageChannel that is associated with an // NPObject*. @@ -91,16 +85,12 @@ bool NPVariantToPPVar(const NPVariant* variant, PP_Var* result) { NPVARIANT_TO_STRING(*variant).UTF8Characters, NPVARIANT_TO_STRING(*variant).UTF8Length); return true; - case NPVariantType_Object: { + case NPVariantType_Object: + V8VarConverter converter; // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it // shouldn't result in a deep copy. - v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant); - if (!V8VarConverter::FromV8Value(v8_value, v8::Context::GetCurrent(), - result)) { - return false; - } - return true; - } + return converter.FromV8Value(WebBindings::toV8Value(variant), + v8::Context::GetCurrent(), result); } return false; } @@ -192,9 +182,7 @@ bool MessageChannelInvoke(NPObject* np_obj, NPIdentifier name, if (message_channel) { PP_Var argument = PP_MakeUndefined(); if (!NPVariantToPPVar(&args[0], &argument)) { - PpapiGlobals::Get()->LogWithSource( - message_channel->instance()->pp_instance(), - PP_LOGLEVEL_ERROR, std::string(), kV8ToVarConversionError); + NOTREACHED(); return false; } message_channel->PostMessageToNative(argument); @@ -358,10 +346,10 @@ void MessageChannel::PostMessageToJavaScript(PP_Var message_data) { container->element().document().frame()->mainWorldScriptContext(); v8::Context::Scope context_scope(context); - v8::Handle<v8::Value> v8_val; - if (!V8VarConverter::ToV8Value(message_data, context, &v8_val)) { - PpapiGlobals::Get()->LogWithSource(instance_->pp_instance(), - PP_LOGLEVEL_ERROR, std::string(), kVarToV8ConversionError); + v8::Local<v8::Value> v8_val; + V8VarConverter converter; + if (!converter.ToV8Value(message_data, context, &v8_val)) { + NOTREACHED(); return; } diff --git a/webkit/plugins/ppapi/v8_var_converter.cc b/webkit/plugins/ppapi/v8_var_converter.cc index 6f6baf7..95b0e04 100644 --- a/webkit/plugins/ppapi/v8_var_converter.cc +++ b/webkit/plugins/ppapi/v8_var_converter.cc @@ -27,14 +27,6 @@ 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 while traversing the graph. - bool sentinel; -}; - struct HashedHandle { HashedHandle(v8::Handle<v8::Object> h) : handle(h) {} size_t hash() const { return handle->GetIdentityHash(); } @@ -62,17 +54,14 @@ inline size_t hash_value(const HashedHandle& handle) { namespace webkit { namespace ppapi { -namespace V8VarConverter { 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 @@ -82,13 +71,10 @@ typedef base::hash_set<HashedHandle> ParentHandleSet; bool GetOrCreateV8Value(const PP_Var& var, v8::Handle<v8::Value>* result, bool* did_create, - VarHandleMap* visited_ids, - ParentVarSet* parent_ids) { + VarHandleMap* visited_ids) { *did_create = false; if (::ppapi::VarTracker::IsVarTypeRefcounted(var.type)) { - if (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; @@ -165,8 +151,7 @@ bool GetOrCreateV8Value(const PP_Var& var, bool GetOrCreateVar(v8::Handle<v8::Value> val, PP_Var* result, bool* did_create, - HandleVarMap* visited_handles, - ParentHandleSet* parent_handles) { + HandleVarMap* visited_handles) { CHECK(!val.IsEmpty()); *did_create = false; @@ -174,9 +159,6 @@ 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 (parent_handles->count(HashedHandle(val->ToObject())) != 0) - return false; - HandleVarMap::const_iterator it = visited_handles->find( HashedHandle(val->ToObject())); if (it != visited_handles->end()) { @@ -211,10 +193,8 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val, *result = (new DictionaryVar())->GetPPVar(); } } else { - // 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; + NOTREACHED(); + return false; } *did_create = true; @@ -226,52 +206,31 @@ bool GetOrCreateVar(v8::Handle<v8::Value> val, return true; } -bool CanHaveChildren(PP_Var var) { - return var.type == PP_VARTYPE_ARRAY || var.type == PP_VARTYPE_DICTIONARY; -} - } // namespace -// To/FromV8Value use a stack-based DFS search to traverse V8/Var graph. Each -// iteration, the top node on the stack examined. If the node has not been -// visited yet (i.e. sentinel == false) then it is added to the list of parents -// which contains all of the nodes on the path from the start node to the -// current node. Each of the current nodes children are examined. If they appear -// in the list of parents it means we have a cycle and we return NULL. -// Otherwise, if they can have children, 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 the list of parents. -// static -bool ToV8Value(const PP_Var& var, - v8::Handle<v8::Context> context, - v8::Handle<v8::Value>* result) { +V8VarConverter::V8VarConverter() { +} + +bool V8VarConverter::ToV8Value(const PP_Var& var, + v8::Handle<v8::Context> context, + v8::Handle<v8::Value>* result) const { v8::Context::Scope context_scope(context); v8::HandleScope handle_scope; VarHandleMap visited_ids; - ParentVarSet parent_ids; - std::stack<StackEntry<PP_Var> > stack; - stack.push(StackEntry<PP_Var>(var)); + std::stack<PP_Var> stack; + stack.push(var); v8::Handle<v8::Value> root; bool is_root = true; while (!stack.empty()) { - const PP_Var& current_var = stack.top().val; + const PP_Var& current_var = stack.top(); v8::Handle<v8::Value> current_v8; - - if (stack.top().sentinel) { - stack.pop(); - if (CanHaveChildren(current_var)) - parent_ids.erase(current_var.value.as_id); - continue; - } else { - stack.top().sentinel = true; - } - + stack.pop(); bool did_create = false; if (!GetOrCreateV8Value(current_var, ¤t_v8, &did_create, - &visited_ids, &parent_ids)) { + &visited_ids)) { return false; } @@ -282,7 +241,6 @@ bool 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(); @@ -295,11 +253,14 @@ bool 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, &parent_ids)) { + &visited_ids)) { return false; } - if (did_create && CanHaveChildren(child_var)) + if (did_create && + (child_var.type == PP_VARTYPE_DICTIONARY || + child_var.type == PP_VARTYPE_ARRAY)) { stack.push(child_var); + } v8::TryCatch try_catch; v8_array->Set(static_cast<uint32>(i), child_v8); if (try_catch.HasCaught()) { @@ -308,7 +269,6 @@ bool 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(); @@ -325,11 +285,14 @@ bool 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, &parent_ids)) { + &visited_ids)) { return false; } - if (did_create && CanHaveChildren(child_var)) + if (did_create && + (child_var.type == PP_VARTYPE_DICTIONARY || + child_var.type == PP_VARTYPE_ARRAY)) { stack.push(child_var); + } v8::TryCatch try_catch; v8_object->Set(v8::String::New(key.c_str(), key.length()), child_v8); if (try_catch.HasCaught()) { @@ -345,36 +308,26 @@ bool ToV8Value(const PP_Var& var, return true; } -bool FromV8Value(v8::Handle<v8::Value> val, - v8::Handle<v8::Context> context, - PP_Var* result) { +bool V8VarConverter::FromV8Value(v8::Handle<v8::Value> val, + v8::Handle<v8::Context> context, + PP_Var* result) const { v8::Context::Scope context_scope(context); v8::HandleScope handle_scope; HandleVarMap visited_handles; - ParentHandleSet parent_handles; - std::stack<StackEntry<v8::Handle<v8::Value> > > stack; - stack.push(StackEntry<v8::Handle<v8::Value> >(val)); + std::stack<v8::Handle<v8::Value> > stack; + stack.push(val); ScopedPPVar root; bool is_root = true; while (!stack.empty()) { - v8::Handle<v8::Value> current_v8 = stack.top().val; + v8::Handle<v8::Value> current_v8 = stack.top(); PP_Var current_var; - - if (stack.top().sentinel) { - stack.pop(); - if (current_v8->IsObject()) - parent_handles.erase(HashedHandle(current_v8->ToObject())); - continue; - } else { - stack.top().sentinel = true; - } - + stack.pop(); bool did_create = false; if (!GetOrCreateVar(current_v8, ¤t_var, &did_create, - &visited_handles, &parent_handles)) { + &visited_handles)) { return false; } @@ -387,7 +340,6 @@ bool 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) { @@ -406,8 +358,11 @@ bool FromV8Value(v8::Handle<v8::Value> val, PP_Var child_var; if (!GetOrCreateVar(child_v8, &child_var, &did_create, - &visited_handles, &parent_handles)) { - return false; + &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; } if (did_create && child_v8->IsObject()) stack.push(child_v8); @@ -417,7 +372,6 @@ bool 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) { @@ -449,8 +403,8 @@ bool FromV8Value(v8::Handle<v8::Value> val, PP_Var child_var; if (!GetOrCreateVar(child_v8, &child_var, &did_create, - &visited_handles, &parent_handles)) { - return false; + &visited_handles)) { + continue; } if (did_create && child_v8->IsObject()) stack.push(child_v8); @@ -465,6 +419,5 @@ bool FromV8Value(v8::Handle<v8::Value> val, return true; } -} // namespace V8VarConverter } // namespace ppapi } // namespace webkit diff --git a/webkit/plugins/ppapi/v8_var_converter.h b/webkit/plugins/ppapi/v8_var_converter.h index 9dcae4f8..c19644c 100644 --- a/webkit/plugins/ppapi/v8_var_converter.h +++ b/webkit/plugins/ppapi/v8_var_converter.h @@ -14,21 +14,27 @@ namespace webkit { namespace ppapi { -namespace V8VarConverter { - -// Converts the given PP_Var to a v8::Value. True is returned upon success. -bool WEBKIT_PLUGINS_EXPORT ToV8Value(const PP_Var& var, - v8::Handle<v8::Context> context, - v8::Handle<v8::Value>* result); -// Converts the given v8::Value to a PP_Var. True is returned upon success. -// Every PP_Var in the reference graph of which |result| is apart will have -// a refcount equal to the number of references to it in the graph. |result| -// will have one additional reference. -bool WEBKIT_PLUGINS_EXPORT FromV8Value(v8::Handle<v8::Value> val, - v8::Handle<v8::Context> context, - PP_Var* result); - -} // namespace V8VarConverter + +// Class to convert between PP_Vars and V8 values. +class WEBKIT_PLUGINS_EXPORT V8VarConverter { + public: + V8VarConverter(); + + // Converts the given PP_Var to a v8::Value. True is returned upon success. + bool ToV8Value(const PP_Var& var, + v8::Handle<v8::Context> context, + v8::Handle<v8::Value>* result) const; + // Converts the given v8::Value to a PP_Var. True is returned upon success. + // Every PP_Var in the reference graph of which |result| is apart will have + // a refcount equal to the number of references to it in the graph. |result| + // will have one additional reference. + bool FromV8Value(v8::Handle<v8::Value> val, + v8::Handle<v8::Context> context, + PP_Var* result) const; + + DISALLOW_COPY_AND_ASSIGN(V8VarConverter); +}; + } // namespace ppapi } // namespace webkit diff --git a/webkit/plugins/ppapi/v8_var_converter_unittest.cc b/webkit/plugins/ppapi/v8_var_converter_unittest.cc index fc4c841..2198cf8 100644 --- a/webkit/plugins/ppapi/v8_var_converter_unittest.cc +++ b/webkit/plugins/ppapi/v8_var_converter_unittest.cc @@ -152,16 +152,17 @@ class V8VarConverterTest : public testing::Test { protected: bool RoundTrip(const PP_Var& var, PP_Var* result) { + V8VarConverter converter; v8::HandleScope handle_scope(isolate_); v8::Context::Scope context_scope(isolate_, context_); v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolate_, context_); v8::Handle<v8::Value> v8_result; - if (!V8VarConverter::ToV8Value(var, context, &v8_result)) + if (!converter.ToV8Value(var, context, &v8_result)) return false; if (!Equals(var, v8_result)) return false; - if (!V8VarConverter::FromV8Value(v8_result, context, result)) + if (!converter.FromV8Value(v8_result, context, result)) return false; return true; } @@ -270,61 +271,29 @@ TEST_F(V8VarConverterTest, DictionaryArrayRoundTripTest) { array2->Set(0, PP_MakeInt32(100)); dictionary->SetWithStringKey("9", release_array2.get()); EXPECT_TRUE(RoundTripAndCompare(array->GetPPVar())); -} - -TEST_F(V8VarConverterTest, Cycles) { - // Check that cycles aren't converted. - v8::Context::Scope context_scope(context_); - v8::HandleScope handle_scope; - - // Var->V8 conversion. - { - scoped_refptr<DictionaryVar> dictionary(new DictionaryVar); - ScopedPPVar release_dictionary(ScopedPPVar::PassRef(), - dictionary->GetPPVar()); - scoped_refptr<ArrayVar> array(new ArrayVar); - ScopedPPVar release_array(ScopedPPVar::PassRef(), array->GetPPVar()); - - dictionary->SetWithStringKey("1", release_array.get()); - array->Set(0, release_dictionary.get()); - - v8::Handle<v8::Value> v8_result; - // Array <-> dictionary cycle. - dictionary->SetWithStringKey("1", release_array.get()); - ASSERT_FALSE(V8VarConverter::ToV8Value(release_dictionary.get(), - context_, &v8_result)); - // Break the cycle. - // TODO(raymes): We need some better machinery for releasing vars with - // cycles. Remove the code below once we have that. - dictionary->DeleteWithStringKey("1"); - - // Array with self reference. - array->Set(0, release_array.get()); - ASSERT_FALSE(V8VarConverter::ToV8Value(release_array.get(), - context_, &v8_result)); - // Break the self reference. - array->Set(0, PP_MakeUndefined()); - } - - // V8->Var conversion. - { - v8::Handle<v8::Object> object = v8::Object::New(); - v8::Handle<v8::Array> array = v8::Array::New(); - - PP_Var var_result; - - // Array <-> dictionary cycle. - std::string key = "1"; - object->Set(v8::String::New(key.c_str(), key.length()), array); - array->Set(0, object); - - ASSERT_FALSE(V8VarConverter::FromV8Value(object, context_, &var_result)); - - // Array with self reference. - array->Set(0, array); - ASSERT_FALSE(V8VarConverter::FromV8Value(array, context_, &var_result)); - } + // Array <-> dictionary cycle. + dictionary->SetWithStringKey("10", release_array.get()); + PP_Var result_var; + EXPECT_TRUE(RoundTrip(release_dictionary.get(), &result_var)); + ScopedPPVar result = ScopedPPVar(ScopedPPVar::PassRef(), result_var); + EXPECT_TRUE(TestEqual(release_dictionary.get(), result.get())); + // Break the cycle. + // TODO(raymes): We need some better machinery for releasing vars with + // cycles. Remove the code below once we have that. + dictionary->DeleteWithStringKey("10"); + DictionaryVar* result_dictionary = DictionaryVar::FromPPVar(result.get()); + result_dictionary->DeleteWithStringKey("10"); + + // Array with self references. + array->Set(index, release_array.get()); + EXPECT_TRUE(RoundTrip(release_array.get(), &result_var)); + result = ScopedPPVar(ScopedPPVar::PassRef(), result_var); + EXPECT_TRUE(TestEqual(release_array.get(), result.get())); + // Break the self reference. + array->Set(index, PP_MakeUndefined()); + ArrayVar* result_array = ArrayVar::FromPPVar(result.get()); + result_array->Set(index, PP_MakeUndefined()); } TEST_F(V8VarConverterTest, StrangeDictionaryKeyTest) { @@ -356,9 +325,10 @@ TEST_F(V8VarConverterTest, StrangeDictionaryKeyTest) { v8::Handle<v8::Object> object = script->Run().As<v8::Object>(); ASSERT_FALSE(object.IsEmpty()); + V8VarConverter converter; PP_Var actual; - ASSERT_TRUE(V8VarConverter::FromV8Value(object, - v8::Local<v8::Context>::New(isolate_, context_), &actual)); + ASSERT_TRUE(converter.FromV8Value( + object, v8::Local<v8::Context>::New(isolate_, context_), &actual)); ScopedPPVar release_actual(ScopedPPVar::PassRef(), actual); scoped_refptr<DictionaryVar> expected(new DictionaryVar); |