Cache function templates in PluginObject to avoid memory leak.
[chromium-blink-merge.git] / content / renderer / pepper / plugin_object.cc
blob93c4b72943d07557ef71b78553598335832f59e6
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/pepper/plugin_object.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/memory/ref_counted.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
14 #include "content/renderer/pepper/pepper_try_catch.h"
15 #include "content/renderer/pepper/plugin_module.h"
16 #include "content/renderer/pepper/v8_var_converter.h"
17 #include "gin/arguments.h"
18 #include "gin/converter.h"
19 #include "gin/function_template.h"
20 #include "gin/handle.h"
21 #include "gin/interceptor.h"
22 #include "gin/object_template_builder.h"
23 #include "gin/public/gin_embedders.h"
24 #include "ppapi/c/dev/ppb_var_deprecated.h"
25 #include "ppapi/c/dev/ppp_class_deprecated.h"
26 #include "ppapi/c/pp_resource.h"
27 #include "ppapi/c/pp_var.h"
28 #include "ppapi/shared_impl/ppapi_globals.h"
29 #include "ppapi/shared_impl/resource_tracker.h"
30 #include "ppapi/shared_impl/var.h"
31 #include "ppapi/shared_impl/var_tracker.h"
33 using ppapi::PpapiGlobals;
34 using ppapi::ScopedPPVar;
35 using ppapi::ScopedPPVarArray;
36 using ppapi::StringVar;
37 using ppapi::Var;
39 namespace content {
41 namespace {
43 const char kInvalidValueException[] = "Error: Invalid value";
45 } // namespace
47 // PluginObject ----------------------------------------------------------------
49 PluginObject::~PluginObject() {
50 if (instance_) {
51 ppp_class_->Deallocate(ppp_class_data_);
52 instance_->RemovePluginObject(this);
56 // static
57 gin::WrapperInfo PluginObject::kWrapperInfo = {gin::kEmbedderNativeGin};
59 // static
60 PluginObject* PluginObject::FromV8Object(v8::Isolate* isolate,
61 v8::Handle<v8::Object> v8_object) {
62 PluginObject* plugin_object;
63 if (!v8_object.IsEmpty() &&
64 gin::ConvertFromV8(isolate, v8_object, &plugin_object)) {
65 return plugin_object;
67 return NULL;
70 // static
71 PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance,
72 const PPP_Class_Deprecated* ppp_class,
73 void* ppp_class_data) {
74 V8VarConverter var_converter(instance->pp_instance(),
75 V8VarConverter::kAllowObjectVars);
76 PepperTryCatchVar try_catch(instance, &var_converter, NULL);
77 gin::Handle<PluginObject> object =
78 gin::CreateHandle(instance->GetIsolate(),
79 new PluginObject(instance, ppp_class, ppp_class_data));
80 ScopedPPVar result = try_catch.FromV8(object.ToV8());
81 DCHECK(!try_catch.HasException());
82 return result.Release();
85 v8::Local<v8::Value> PluginObject::GetNamedProperty(
86 v8::Isolate* isolate,
87 const std::string& identifier) {
88 ScopedPPVar identifier_var(ScopedPPVar::PassRef(),
89 StringVar::StringToPPVar(identifier));
90 return GetPropertyOrMethod(instance_->GetIsolate(), identifier_var.get());
93 bool PluginObject::SetNamedProperty(v8::Isolate* isolate,
94 const std::string& identifier,
95 v8::Local<v8::Value> value) {
96 if (!instance_)
97 return false;
98 ScopedPPVar identifier_var(ScopedPPVar::PassRef(),
99 StringVar::StringToPPVar(identifier));
100 V8VarConverter var_converter(instance_->pp_instance(),
101 V8VarConverter::kAllowObjectVars);
102 PepperTryCatchV8 try_catch(instance_, &var_converter, isolate);
104 bool has_property =
105 ppp_class_->HasProperty(ppp_class_data_, identifier_var.get(),
106 try_catch.exception());
107 if (try_catch.ThrowException())
108 return false;
110 if (!has_property)
111 return false;
113 ScopedPPVar var = try_catch.FromV8(value);
114 if (try_catch.ThrowException())
115 return false;
117 ppp_class_->SetProperty(ppp_class_data_, identifier_var.get(), var.get(),
118 try_catch.exception());
120 // If the plugin threw an exception, then throw a V8 version of it to
121 // JavaScript. Either way, return true, because we successfully dispatched
122 // the call to the plugin.
123 try_catch.ThrowException();
124 return true;
127 std::vector<std::string> PluginObject::EnumerateNamedProperties(
128 v8::Isolate* isolate) {
129 std::vector<std::string> result;
130 if (!instance_)
131 return result;
133 V8VarConverter var_converter(instance_->pp_instance(),
134 V8VarConverter::kAllowObjectVars);
135 PepperTryCatchV8 try_catch(instance_, &var_converter, isolate);
137 PP_Var* name_vars;
138 uint32_t count = 0;
139 ppp_class_->GetAllPropertyNames(ppp_class_data_, &count, &name_vars,
140 try_catch.exception());
141 ScopedPPVarArray scoped_name_vars(
142 ScopedPPVarArray::PassPPBMemoryAllocatedArray(), name_vars, count);
144 if (try_catch.ThrowException())
145 return result;
147 for (uint32_t i = 0; i < count; ++i) {
148 StringVar* string_var = StringVar::FromPPVar(name_vars[i]);
149 if (string_var) {
150 result.push_back(string_var->value());
151 } else {
152 try_catch.ThrowException(kInvalidValueException);
153 result.clear();
154 return result;
158 return result;
161 void PluginObject::InstanceDeleted() {
162 instance_ = NULL;
165 PluginObject::PluginObject(PepperPluginInstanceImpl* instance,
166 const PPP_Class_Deprecated* ppp_class,
167 void* ppp_class_data)
168 : gin::NamedPropertyInterceptor(instance->GetIsolate(), this),
169 instance_(instance),
170 ppp_class_(ppp_class),
171 ppp_class_data_(ppp_class_data),
172 weak_factory_(this),
173 template_cache_(instance->GetIsolate()) {
174 instance_->AddPluginObject(this);
177 gin::ObjectTemplateBuilder PluginObject::GetObjectTemplateBuilder(
178 v8::Isolate* isolate) {
179 return Wrappable<PluginObject>::GetObjectTemplateBuilder(isolate)
180 .AddNamedPropertyInterceptor();
183 v8::Local<v8::Value> PluginObject::GetPropertyOrMethod(v8::Isolate* isolate,
184 PP_Var identifier_var) {
185 if (!instance_)
186 return v8::Local<v8::Value>();
188 V8VarConverter var_converter(instance_->pp_instance(),
189 V8VarConverter::kAllowObjectVars);
190 PepperTryCatchV8 try_catch(instance_, &var_converter, isolate);
191 bool has_property =
192 ppp_class_->HasProperty(ppp_class_data_, identifier_var,
193 try_catch.exception());
194 if (try_catch.ThrowException())
195 return v8::Local<v8::Value>();
197 if (has_property) {
198 ScopedPPVar result_var(ScopedPPVar::PassRef(),
199 ppp_class_->GetProperty(ppp_class_data_, identifier_var,
200 try_catch.exception()));
201 if (try_catch.ThrowException())
202 return v8::Local<v8::Value>();
204 v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get());
205 if (try_catch.ThrowException())
206 return v8::Local<v8::Value>();
208 return result;
211 bool has_method = identifier_var.type == PP_VARTYPE_STRING &&
212 ppp_class_->HasMethod(ppp_class_data_, identifier_var,
213 try_catch.exception());
214 if (try_catch.ThrowException())
215 return v8::Local<v8::Value>();
217 if (has_method) {
218 const std::string& identifier =
219 StringVar::FromPPVar(identifier_var)->value();
220 return GetFunctionTemplate(isolate, identifier)->GetFunction();
223 return v8::Local<v8::Value>();
226 void PluginObject::Call(const std::string& identifier,
227 gin::Arguments* args) {
228 if (!instance_)
229 return;
231 V8VarConverter var_converter(instance_->pp_instance(),
232 V8VarConverter::kAllowObjectVars);
233 PepperTryCatchV8 try_catch(instance_, &var_converter, args->isolate());
234 ScopedPPVar identifier_var(ScopedPPVar::PassRef(),
235 StringVar::StringToPPVar(identifier));
236 ScopedPPVarArray argument_vars(args->Length());
238 for (uint32_t i = 0; i < argument_vars.size(); ++i) {
239 v8::Handle<v8::Value> arg;
240 if (!args->GetNext(&arg)) {
241 NOTREACHED();
244 argument_vars.Set(i, try_catch.FromV8(arg));
245 if (try_catch.ThrowException())
246 return;
249 // For the OOP plugin case we need to grab a reference on the plugin module
250 // object to ensure that it is not destroyed courtesy an incoming
251 // ExecuteScript call which destroys the plugin module and in turn the
252 // dispatcher.
253 scoped_refptr<PluginModule> ref(instance_->module());
255 ScopedPPVar result_var(ScopedPPVar::PassRef(),
256 ppp_class_->Call(ppp_class_data_, identifier_var.get(),
257 argument_vars.size(), argument_vars.get(),
258 try_catch.exception()));
259 if (try_catch.ThrowException())
260 return;
262 v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get());
263 if (try_catch.ThrowException())
264 return;
266 args->Return(result);
269 v8::Local<v8::FunctionTemplate> PluginObject::GetFunctionTemplate(
270 v8::Isolate* isolate,
271 const std::string& name) {
272 v8::Local<v8::FunctionTemplate> function_template = template_cache_.Get(name);
273 if (!function_template.IsEmpty())
274 return function_template;
275 function_template =
276 gin::CreateFunctionTemplate(
277 isolate, base::Bind(&PluginObject::Call, weak_factory_.GetWeakPtr(),
278 name));
279 template_cache_.Set(name, function_template);
280 return function_template;
283 } // namespace content