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