Cherry-pick "[Android] Cache function templates in GinJavaBridgeObject to avoid memory leak"
Original description (https://codereview.chromium.org/969353004/)
[Android] Cache function templates in GinJavaBridgeObject to avoid memory leak
V8 caches all function templates internally for the lifetime of a web page in an
unbounded cache. Thus, creating a new function template for each call to a
method of injected object caused JS heap memory to grow linearly.
This is similar to a fix for Pepper Plugin objects (https://codereview.chromium.org/785213002/)
BUG=462664
Bug: 19578263
Change-Id: Ie259ceab8625e9e80670b9084aa3cd5813330648
diff --git a/content/renderer/java/gin_java_bridge_object.cc b/content/renderer/java/gin_java_bridge_object.cc
index b4cf3bf..d5798a8 100644
--- a/content/renderer/java/gin_java_bridge_object.cc
+++ b/content/renderer/java/gin_java_bridge_object.cc
@@ -66,7 +66,8 @@
: gin::NamedPropertyInterceptor(isolate, this),
dispatcher_(dispatcher),
object_id_(object_id),
- converter_(new GinJavaBridgeValueConverter()) {
+ converter_(new GinJavaBridgeValueConverter()),
+ template_cache_(isolate) {
}
GinJavaBridgeObject::~GinJavaBridgeObject() {
@@ -91,15 +92,10 @@
}
known_methods_[property] = dispatcher_->HasJavaMethod(object_id_, property);
}
- if (known_methods_[property]) {
- return gin::CreateFunctionTemplate(
- isolate,
- base::Bind(&GinJavaBridgeObject::InvokeMethod,
- base::Unretained(this),
- property))->GetFunction();
- } else {
+ if (known_methods_[property])
+ return GetFunctionTemplate(isolate, property)->GetFunction();
+ else
return v8::Local<v8::Value>();
- }
}
std::vector<std::string> GinJavaBridgeObject::EnumerateNamedProperties(
@@ -110,6 +106,19 @@
return std::vector<std::string> (method_names.begin(), method_names.end());
}
+v8::Local<v8::FunctionTemplate> GinJavaBridgeObject::GetFunctionTemplate(
+ v8::Isolate* isolate,
+ const std::string& name) {
+ v8::Local<v8::FunctionTemplate> function_template = template_cache_.Get(name);
+ if (!function_template.IsEmpty())
+ return function_template;
+ function_template = gin::CreateFunctionTemplate(
+ isolate, base::Bind(&GinJavaBridgeObject::InvokeMethod,
+ base::Unretained(this), name));
+ template_cache_.Set(name, function_template);
+ return function_template;
+}
+
v8::Handle<v8::Value> GinJavaBridgeObject::InvokeMethod(
const std::string& name,
gin::Arguments* args) {
diff --git a/content/renderer/java/gin_java_bridge_object.h b/content/renderer/java/gin_java_bridge_object.h
index f3a4c7b..a9346b6 100644
--- a/content/renderer/java/gin_java_bridge_object.h
+++ b/content/renderer/java/gin_java_bridge_object.h
@@ -14,6 +14,7 @@
#include "gin/interceptor.h"
#include "gin/object_template_builder.h"
#include "gin/wrappable.h"
+#include "v8/include/v8-util.h"
namespace blink {
class WebFrame;
@@ -55,6 +56,8 @@
GinJavaBridgeDispatcher::ObjectID object_id);
virtual ~GinJavaBridgeObject();
+ v8::Local<v8::FunctionTemplate> GetFunctionTemplate(v8::Isolate* isolate,
+ const std::string& name);
v8::Handle<v8::Value> InvokeMethod(const std::string& name,
gin::Arguments* args);
@@ -62,6 +65,7 @@
GinJavaBridgeDispatcher::ObjectID object_id_;
scoped_ptr<GinJavaBridgeValueConverter> converter_;
std::map<std::string, bool> known_methods_;
+ v8::StdPersistentValueMap<std::string, v8::FunctionTemplate> template_cache_;
DISALLOW_COPY_AND_ASSIGN(GinJavaBridgeObject);
};