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);
 };