// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "content/renderer/pepper/host_globals.h" #include "content/renderer/pepper/host_var_tracker.h" #include "content/renderer/pepper/mock_resource.h" #include "content/renderer/pepper/pepper_plugin_instance_impl.h" #include "content/renderer/pepper/pepper_try_catch.h" #include "content/renderer/pepper/v8_var_converter.h" #include "content/renderer/pepper/v8object_var.h" #include "content/test/ppapi_unittest.h" #include "gin/handle.h" #include "gin/wrappable.h" #include "ppapi/c/pp_var.h" #include "ppapi/c/ppp_instance.h" #include "third_party/WebKit/public/web/WebBindings.h" using ppapi::V8ObjectVar; namespace content { namespace { int g_v8objects_alive = 0; class MyObject : public gin::Wrappable { public: static gin::WrapperInfo kWrapperInfo; static v8::Local Create(v8::Isolate* isolate) { return gin::CreateHandle(isolate, new MyObject()).ToV8(); } private: MyObject() { ++g_v8objects_alive; } ~MyObject() override { --g_v8objects_alive; } DISALLOW_COPY_AND_ASSIGN(MyObject); }; gin::WrapperInfo MyObject::kWrapperInfo = {gin::kEmbedderNativeGin}; class PepperTryCatchForTest : public PepperTryCatch { public: PepperTryCatchForTest(PepperPluginInstanceImpl* instance, V8VarConverter* converter) : PepperTryCatch(instance, converter), handle_scope_(instance->GetIsolate()), context_scope_(v8::Context::New(instance->GetIsolate())) {} void SetException(const char* message) override { NOTREACHED(); } bool HasException() override { return false; } v8::Local GetContext() override { return instance_->GetIsolate()->GetCurrentContext(); } private: v8::HandleScope handle_scope_; v8::Context::Scope context_scope_; DISALLOW_COPY_AND_ASSIGN(PepperTryCatchForTest); }; } // namespace class HostVarTrackerTest : public PpapiUnittest { public: HostVarTrackerTest() {} void TearDown() override { v8::Isolate::GetCurrent()->RequestGarbageCollectionForTesting( v8::Isolate::kFullGarbageCollection); EXPECT_EQ(0, g_v8objects_alive); PpapiUnittest::TearDown(); } HostVarTracker& tracker() { return *HostGlobals::Get()->host_var_tracker(); } }; TEST_F(HostVarTrackerTest, DeleteObjectVarWithInstance) { v8::Isolate* test_isolate = v8::Isolate::GetCurrent(); // Make a second instance (the test harness already creates & manages one). scoped_refptr instance2( PepperPluginInstanceImpl::Create(NULL, module(), NULL, GURL())); PP_Instance pp_instance2 = instance2->pp_instance(); { V8VarConverter converter( instance2->pp_instance(), V8VarConverter::kAllowObjectVars); PepperTryCatchForTest try_catch(instance2.get(), &converter); // Make an object var. ppapi::ScopedPPVar var = try_catch.FromV8(MyObject::Create(test_isolate)); EXPECT_EQ(1, g_v8objects_alive); EXPECT_EQ(1, tracker().GetLiveV8ObjectVarsForTest(pp_instance2)); // Purposely leak the var. var.Release(); } // Free the instance, this should release the ObjectVar. instance2 = NULL; EXPECT_EQ(0, tracker().GetLiveV8ObjectVarsForTest(pp_instance2)); } // Make sure that using the same v8 object should give the same PP_Var // each time. TEST_F(HostVarTrackerTest, ReuseVar) { V8VarConverter converter( instance()->pp_instance(), V8VarConverter::kAllowObjectVars); PepperTryCatchForTest try_catch(instance(), &converter); v8::Local v8_object = MyObject::Create(v8::Isolate::GetCurrent()); ppapi::ScopedPPVar pp_object1 = try_catch.FromV8(v8_object); ppapi::ScopedPPVar pp_object2 = try_catch.FromV8(v8_object); // The two results should be the same. EXPECT_EQ(pp_object1.get().value.as_id, pp_object2.get().value.as_id); // The objects should be able to get us back to the associated v8 object. { scoped_refptr check_object( V8ObjectVar::FromPPVar(pp_object1.get())); ASSERT_TRUE(check_object.get()); EXPECT_EQ(instance(), check_object->instance()); EXPECT_EQ(v8_object, check_object->GetHandle()); } // Remove both of the refs we made above. pp_object1 = ppapi::ScopedPPVar(); pp_object2 = ppapi::ScopedPPVar(); // Releasing the resource should free the internal ref, and so making a new // one now should generate a new ID. ppapi::ScopedPPVar pp_object3 = try_catch.FromV8(v8_object); EXPECT_NE(pp_object1.get().value.as_id, pp_object3.get().value.as_id); } } // namespace content