OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/basictypes.h" | |
6 #include "base/memory/scoped_ptr.h" | 5 #include "base/memory/scoped_ptr.h" |
7 #include "content/renderer/pepper/host_globals.h" | 6 #include "content/renderer/pepper/host_globals.h" |
8 #include "content/renderer/pepper/host_var_tracker.h" | 7 #include "content/renderer/pepper/host_var_tracker.h" |
9 #include "content/renderer/pepper/mock_resource.h" | 8 #include "content/renderer/pepper/mock_resource.h" |
| 9 #include "content/renderer/pepper/npapi_glue.h" |
| 10 #include "content/renderer/pepper/npobject_var.h" |
10 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" | 11 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" |
11 #include "content/renderer/pepper/pepper_try_catch.h" | |
12 #include "content/renderer/pepper/v8object_var.h" | |
13 #include "content/test/ppapi_unittest.h" | 12 #include "content/test/ppapi_unittest.h" |
14 #include "gin/handle.h" | |
15 #include "gin/wrappable.h" | |
16 #include "ppapi/c/pp_var.h" | 13 #include "ppapi/c/pp_var.h" |
17 #include "ppapi/c/ppp_instance.h" | 14 #include "ppapi/c/ppp_instance.h" |
| 15 #include "third_party/npapi/bindings/npruntime.h" |
18 #include "third_party/WebKit/public/web/WebBindings.h" | 16 #include "third_party/WebKit/public/web/WebBindings.h" |
19 | 17 |
20 using ppapi::V8ObjectVar; | 18 using ppapi::NPObjectVar; |
21 | 19 |
22 namespace content { | 20 namespace content { |
23 | 21 |
24 namespace { | 22 namespace { |
25 | 23 |
26 int g_v8objects_alive = 0; | 24 // Tracked NPObjects ----------------------------------------------------------- |
27 | 25 |
28 class MyObject : public gin::Wrappable<MyObject> { | 26 int g_npobjects_alive = 0; |
29 public: | |
30 static gin::WrapperInfo kWrapperInfo; | |
31 | 27 |
32 static v8::Handle<v8::Value> Create(v8::Isolate* isolate) { | 28 void TrackedClassDeallocate(NPObject* npobject) { |
33 return gin::CreateHandle(isolate, new MyObject()).ToV8(); | 29 g_npobjects_alive--; |
34 } | 30 delete npobject; |
| 31 } |
35 | 32 |
36 private: | 33 NPClass g_tracked_npclass = { |
37 MyObject() { ++g_v8objects_alive; } | 34 NP_CLASS_STRUCT_VERSION, NULL, &TrackedClassDeallocate, NULL, NULL, NULL, |
38 virtual ~MyObject() { --g_v8objects_alive; } | 35 NULL, NULL, NULL, NULL, NULL, NULL, }; |
39 | 36 |
40 DISALLOW_COPY_AND_ASSIGN(MyObject); | 37 // Returns a new tracked NPObject with a refcount of 1. You'll want to put this |
| 38 // in a NPObjectReleaser to free this ref when the test completes. |
| 39 NPObject* NewTrackedNPObject() { |
| 40 NPObject* object = new NPObject; |
| 41 object->_class = &g_tracked_npclass; |
| 42 object->referenceCount = 1; |
| 43 |
| 44 g_npobjects_alive++; |
| 45 return object; |
| 46 } |
| 47 |
| 48 struct ReleaseNPObject { |
| 49 void operator()(NPObject* o) const { blink::WebBindings::releaseObject(o); } |
41 }; | 50 }; |
42 | 51 |
43 gin::WrapperInfo MyObject::kWrapperInfo = {gin::kEmbedderNativeGin}; | 52 // Handles automatically releasing a reference to the NPObject on destruction. |
44 | 53 // It's assumed the input has a ref already taken. |
45 class PepperTryCatchForTest : public PepperTryCatch { | 54 typedef scoped_ptr<NPObject, ReleaseNPObject> NPObjectReleaser; |
46 public: | |
47 explicit PepperTryCatchForTest(PepperPluginInstanceImpl* instance) | |
48 : PepperTryCatch(instance, V8VarConverter::kAllowObjectVars), | |
49 handle_scope_(instance->GetIsolate()), | |
50 context_scope_(v8::Context::New(instance->GetIsolate())) {} | |
51 | |
52 virtual void SetException(const char* message) OVERRIDE { NOTREACHED(); } | |
53 virtual v8::Handle<v8::Context> GetContext() OVERRIDE { | |
54 return instance_->GetIsolate()->GetCurrentContext(); | |
55 } | |
56 | |
57 private: | |
58 v8::HandleScope handle_scope_; | |
59 v8::Context::Scope context_scope_; | |
60 | |
61 DISALLOW_COPY_AND_ASSIGN(PepperTryCatchForTest); | |
62 }; | |
63 | 55 |
64 } // namespace | 56 } // namespace |
65 | 57 |
66 class HostVarTrackerTest : public PpapiUnittest { | 58 class HostVarTrackerTest : public PpapiUnittest { |
67 public: | 59 public: |
68 HostVarTrackerTest() {} | 60 HostVarTrackerTest() {} |
69 | 61 |
70 HostVarTracker& tracker() { return *HostGlobals::Get()->host_var_tracker(); } | 62 HostVarTracker& tracker() { return *HostGlobals::Get()->host_var_tracker(); } |
71 }; | 63 }; |
72 | 64 |
73 TEST_F(HostVarTrackerTest, DeleteObjectVarWithInstance) { | 65 TEST_F(HostVarTrackerTest, DeleteObjectVarWithInstance) { |
74 v8::Isolate* test_isolate = v8::Isolate::GetCurrent(); | |
75 | |
76 // Make a second instance (the test harness already creates & manages one). | 66 // Make a second instance (the test harness already creates & manages one). |
77 scoped_refptr<PepperPluginInstanceImpl> instance2( | 67 scoped_refptr<PepperPluginInstanceImpl> instance2( |
78 PepperPluginInstanceImpl::Create(NULL, module(), NULL, GURL())); | 68 PepperPluginInstanceImpl::Create(NULL, module(), NULL, GURL())); |
79 PP_Instance pp_instance2 = instance2->pp_instance(); | 69 PP_Instance pp_instance2 = instance2->pp_instance(); |
80 | 70 |
81 { | 71 // Make an object var. |
82 PepperTryCatchForTest try_catch(instance2.get()); | 72 NPObjectReleaser npobject(NewTrackedNPObject()); |
83 // Make an object var. | 73 NPObjectToPPVarForTest(instance2.get(), npobject.get()); |
84 ppapi::ScopedPPVar var = try_catch.FromV8(MyObject::Create(test_isolate)); | 74 |
85 EXPECT_EQ(1, g_v8objects_alive); | 75 EXPECT_EQ(1, g_npobjects_alive); |
86 EXPECT_EQ(1, tracker().GetLiveV8ObjectVarsForTest(pp_instance2)); | 76 EXPECT_EQ(1, tracker().GetLiveNPObjectVarsForInstance(pp_instance2)); |
87 // Purposely leak the var. | |
88 var.Release(); | |
89 } | |
90 | 77 |
91 // Free the instance, this should release the ObjectVar. | 78 // Free the instance, this should release the ObjectVar. |
92 instance2 = NULL; | 79 instance2 = NULL; |
93 EXPECT_EQ(0, tracker().GetLiveV8ObjectVarsForTest(pp_instance2)); | 80 EXPECT_EQ(0, tracker().GetLiveNPObjectVarsForInstance(pp_instance2)); |
94 test_isolate->RequestGarbageCollectionForTesting( | |
95 v8::Isolate::kFullGarbageCollection); | |
96 EXPECT_EQ(0, g_v8objects_alive); | |
97 } | 81 } |
98 | 82 |
99 // Make sure that using the same NPObject should give the same PP_Var | 83 // Make sure that using the same NPObject should give the same PP_Var |
100 // each time. | 84 // each time. |
101 TEST_F(HostVarTrackerTest, ReuseVar) { | 85 TEST_F(HostVarTrackerTest, ReuseVar) { |
102 PepperTryCatchForTest try_catch(instance()); | 86 NPObjectReleaser npobject(NewTrackedNPObject()); |
103 | 87 |
104 v8::Handle<v8::Value> v8_object = MyObject::Create(v8::Isolate::GetCurrent()); | 88 PP_Var pp_object1 = NPObjectToPPVarForTest(instance(), npobject.get()); |
105 ppapi::ScopedPPVar pp_object1 = try_catch.FromV8(v8_object); | 89 PP_Var pp_object2 = NPObjectToPPVarForTest(instance(), npobject.get()); |
106 ppapi::ScopedPPVar pp_object2 = try_catch.FromV8(v8_object); | |
107 | 90 |
108 // The two results should be the same. | 91 // The two results should be the same. |
109 EXPECT_EQ(pp_object1.get().value.as_id, pp_object2.get().value.as_id); | 92 EXPECT_EQ(pp_object1.value.as_id, pp_object2.value.as_id); |
110 | 93 |
111 // The objects should be able to get us back to the associated v8 object. | 94 // The objects should be able to get us back to the associated NPObject. |
| 95 // This ObjectVar must be released before we do NPObjectToPPVarForTest again |
| 96 // below so it gets freed and we get a new identifier. |
112 { | 97 { |
113 scoped_refptr<V8ObjectVar> check_object( | 98 scoped_refptr<NPObjectVar> check_object(NPObjectVar::FromPPVar(pp_object1)); |
114 V8ObjectVar::FromPPVar(pp_object1.get())); | |
115 ASSERT_TRUE(check_object.get()); | 99 ASSERT_TRUE(check_object.get()); |
116 EXPECT_EQ(instance(), check_object->instance()); | 100 EXPECT_EQ(instance()->pp_instance(), check_object->pp_instance()); |
117 EXPECT_EQ(v8_object, check_object->GetHandle()); | 101 EXPECT_EQ(npobject.get(), check_object->np_object()); |
118 } | 102 } |
119 | 103 |
120 // Remove both of the refs we made above. | 104 // Remove both of the refs we made above. |
121 pp_object1 = ppapi::ScopedPPVar(); | 105 ppapi::VarTracker* var_tracker = ppapi::PpapiGlobals::Get()->GetVarTracker(); |
122 pp_object2 = ppapi::ScopedPPVar(); | 106 var_tracker->ReleaseVar(static_cast<int32_t>(pp_object2.value.as_id)); |
| 107 var_tracker->ReleaseVar(static_cast<int32_t>(pp_object1.value.as_id)); |
123 | 108 |
124 // Releasing the resource should free the internal ref, and so making a new | 109 // Releasing the resource should free the internal ref, and so making a new |
125 // one now should generate a new ID. | 110 // one now should generate a new ID. |
126 ppapi::ScopedPPVar pp_object3 = try_catch.FromV8(v8_object); | 111 PP_Var pp_object3 = NPObjectToPPVarForTest(instance(), npobject.get()); |
127 EXPECT_NE(pp_object1.get().value.as_id, pp_object3.get().value.as_id); | 112 EXPECT_NE(pp_object1.value.as_id, pp_object3.value.as_id); |
| 113 var_tracker->ReleaseVar(static_cast<int32_t>(pp_object3.value.as_id)); |
128 } | 114 } |
129 | 115 |
130 } // namespace content | 116 } // namespace content |
OLD | NEW |