Replace NPObject usage in ppapi with gin

This replaces usage of NPObject in pepper with gin-backed V8 objects. It is unfortunate that this CL is so large, but there isn't a nice way to have the old implementation and the new one side-by-side.

There are 4 major parts to this CL:
1) Changing the HostVarTracker to track V8ObjectVars rather than NPObjectVars (host_var_tracker.cc).
2) Changing plugin elements (in plugin_object.cc) to be gin-backed objects.
3) Changing postMessage bindings (message_channel.cc) be gin-backed objects.
4) Changing the implementation of PPB_Var_Deprecated (ppb_var_deprecated_impl.cc) to call directly into V8.

BUG=351636

Review URL: https://codereview.chromium.org/459553003

Cr-Commit-Position: refs/heads/master@{#293366}
diff --git a/content/renderer/pepper/host_var_tracker.cc b/content/renderer/pepper/host_var_tracker.cc
index 700fbaf..494d9b9a 100644
--- a/content/renderer/pepper/host_var_tracker.cc
+++ b/content/renderer/pepper/host_var_tracker.cc
@@ -6,16 +6,37 @@
 
 #include "base/logging.h"
 #include "content/renderer/pepper/host_array_buffer_var.h"
+#include "content/renderer/pepper/host_globals.h"
 #include "content/renderer/pepper/host_resource_var.h"
-#include "content/renderer/pepper/npobject_var.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/v8object_var.h"
 #include "ppapi/c/pp_var.h"
 
 using ppapi::ArrayBufferVar;
-using ppapi::NPObjectVar;
+using ppapi::V8ObjectVar;
 
 namespace content {
 
+HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(V8ObjectVar* object_var)
+    : instance(object_var->instance()->pp_instance()) {
+  v8::Local<v8::Object> object = object_var->GetHandle();
+  hash = object.IsEmpty() ? 0 : object->GetIdentityHash();
+}
+
+HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(PP_Instance instance,
+                                               v8::Handle<v8::Object> object)
+    : instance(instance),
+      hash(object.IsEmpty() ? 0 : object->GetIdentityHash()) {}
+
+HostVarTracker::V8ObjectVarKey::~V8ObjectVarKey() {}
+
+bool HostVarTracker::V8ObjectVarKey::operator<(
+    const V8ObjectVarKey& other) const {
+  if (instance == other.instance)
+    return hash < other.hash;
+  return instance < other.instance;
+}
+
 HostVarTracker::HostVarTracker()
     : VarTracker(SINGLE_THREADED), last_shared_memory_map_id_(0) {}
 
@@ -31,74 +52,44 @@
   return new HostArrayBufferVar(size_in_bytes, handle);
 }
 
-void HostVarTracker::AddNPObjectVar(NPObjectVar* object_var) {
+void HostVarTracker::AddV8ObjectVar(V8ObjectVar* object_var) {
   CheckThreadingPreconditions();
-
-  InstanceMap::iterator found_instance =
-      instance_map_.find(object_var->pp_instance());
-  if (found_instance == instance_map_.end()) {
-    // Lazily create the instance map.
-    DCHECK(object_var->pp_instance() != 0);
-    found_instance =
-        instance_map_.insert(std::make_pair(
-                                 object_var->pp_instance(),
-                                 linked_ptr<NPObjectToNPObjectVarMap>(
-                                     new NPObjectToNPObjectVarMap))).first;
-  }
-  NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
-
-  DCHECK(np_object_map->find(object_var->np_object()) == np_object_map->end())
-      << "NPObjectVar already in map";
-  np_object_map->insert(std::make_pair(object_var->np_object(), object_var));
+  v8::HandleScope handle_scope(object_var->instance()->GetIsolate());
+  DCHECK(GetForV8Object(object_var->instance()->pp_instance(),
+                        object_var->GetHandle()) == object_map_.end());
+  object_map_.insert(std::make_pair(V8ObjectVarKey(object_var), object_var));
 }
 
-void HostVarTracker::RemoveNPObjectVar(NPObjectVar* object_var) {
+void HostVarTracker::RemoveV8ObjectVar(V8ObjectVar* object_var) {
   CheckThreadingPreconditions();
-
-  InstanceMap::iterator found_instance =
-      instance_map_.find(object_var->pp_instance());
-  if (found_instance == instance_map_.end()) {
-    NOTREACHED() << "NPObjectVar has invalid instance.";
-    return;
-  }
-  NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
-
-  NPObjectToNPObjectVarMap::iterator found_object =
-      np_object_map->find(object_var->np_object());
-  if (found_object == np_object_map->end()) {
-    NOTREACHED() << "NPObjectVar not registered.";
-    return;
-  }
-  if (found_object->second != object_var) {
-    NOTREACHED() << "NPObjectVar doesn't match.";
-    return;
-  }
-  np_object_map->erase(found_object);
+  v8::HandleScope handle_scope(object_var->instance()->GetIsolate());
+  ObjectMap::iterator it = GetForV8Object(
+      object_var->instance()->pp_instance(), object_var->GetHandle());
+  DCHECK(it != object_map_.end());
+  object_map_.erase(it);
 }
 
-NPObjectVar* HostVarTracker::NPObjectVarForNPObject(PP_Instance instance,
-                                                    NPObject* np_object) {
+PP_Var HostVarTracker::V8ObjectVarForV8Object(PP_Instance instance,
+                                              v8::Handle<v8::Object> object) {
   CheckThreadingPreconditions();
-
-  InstanceMap::iterator found_instance = instance_map_.find(instance);
-  if (found_instance == instance_map_.end())
-    return NULL;  // No such instance.
-  NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
-
-  NPObjectToNPObjectVarMap::iterator found_object =
-      np_object_map->find(np_object);
-  if (found_object == np_object_map->end())
-    return NULL;  // No such object.
-  return found_object->second;
+  ObjectMap::const_iterator it = GetForV8Object(instance, object);
+  if (it == object_map_.end())
+    return (new V8ObjectVar(instance, object))->GetPPVar();
+  return it->second->GetPPVar();
 }
 
-int HostVarTracker::GetLiveNPObjectVarsForInstance(PP_Instance instance) const {
+int HostVarTracker::GetLiveV8ObjectVarsForTest(PP_Instance instance) {
   CheckThreadingPreconditions();
-
-  InstanceMap::const_iterator found = instance_map_.find(instance);
-  if (found == instance_map_.end())
-    return 0;
-  return static_cast<int>(found->second->size());
+  int count = 0;
+  // Use a key with an empty handle to find the v8 object var in the map with
+  // the given instance and the lowest hash.
+  V8ObjectVarKey key(instance, v8::Handle<v8::Object>());
+  ObjectMap::const_iterator it = object_map_.lower_bound(key);
+  while (it != object_map_.end() && it->first.instance == instance) {
+    ++count;
+    ++it;
+  }
+  return count;
 }
 
 PP_Var HostVarTracker::MakeResourcePPVarFromMessage(
@@ -116,27 +107,27 @@
   return new HostResourceVar(pp_resource);
 }
 
-void HostVarTracker::DidDeleteInstance(PP_Instance instance) {
+void HostVarTracker::DidDeleteInstance(PP_Instance pp_instance) {
   CheckThreadingPreconditions();
 
-  InstanceMap::iterator found_instance = instance_map_.find(instance);
-  if (found_instance == instance_map_.end())
-    return;  // Nothing to do.
-  NPObjectToNPObjectVarMap* np_object_map = found_instance->second.get();
-
-  // Force delete all var references. ForceReleaseNPObject() will cause
+  PepperPluginInstanceImpl* instance =
+      HostGlobals::Get()->GetInstance(pp_instance);
+  v8::HandleScope handle_scope(instance->GetIsolate());
+  // Force delete all var references. ForceReleaseV8Object() will cause
   // this object, and potentially others it references, to be removed from
-  // |np_object_map|.
-  while (!np_object_map->empty()) {
-    ForceReleaseNPObject(np_object_map->begin()->second);
-  }
+  // |live_vars_|.
 
-  // Remove the record for this instance since it should be empty.
-  DCHECK(np_object_map->empty());
-  instance_map_.erase(found_instance);
+  // Use a key with an empty handle to find the v8 object var in the map with
+  // the given instance and the lowest hash.
+  V8ObjectVarKey key(pp_instance, v8::Handle<v8::Object>());
+  ObjectMap::iterator it = object_map_.lower_bound(key);
+  while (it != object_map_.end() && it->first.instance == pp_instance) {
+    ForceReleaseV8Object(it->second);
+    object_map_.erase(it++);
+  }
 }
 
-void HostVarTracker::ForceReleaseNPObject(ppapi::NPObjectVar* object_var) {
+void HostVarTracker::ForceReleaseV8Object(ppapi::V8ObjectVar* object_var) {
   object_var->InstanceDeleted();
   VarMap::iterator iter = live_vars_.find(object_var->GetExistingVarID());
   if (iter == live_vars_.end()) {
@@ -148,6 +139,19 @@
   DeleteObjectInfoIfNecessary(iter);
 }
 
+HostVarTracker::ObjectMap::iterator HostVarTracker::GetForV8Object(
+    PP_Instance instance,
+    v8::Handle<v8::Object> object) {
+  std::pair<ObjectMap::iterator, ObjectMap::iterator> range =
+      object_map_.equal_range(V8ObjectVarKey(instance, object));
+
+  for (ObjectMap::iterator it = range.first; it != range.second; ++it) {
+    if (object == it->second->GetHandle())
+      return it;
+  }
+  return object_map_.end();
+}
+
 int HostVarTracker::TrackSharedMemoryHandle(PP_Instance instance,
                                             base::SharedMemoryHandle handle,
                                             uint32 size_in_bytes) {
diff --git a/content/renderer/pepper/host_var_tracker.h b/content/renderer/pepper/host_var_tracker.h
index 8d8176a..a5518c8 100644
--- a/content/renderer/pepper/host_var_tracker.h
+++ b/content/renderer/pepper/host_var_tracker.h
@@ -20,52 +20,30 @@
 #include "ppapi/shared_impl/var_tracker.h"
 #include "v8/include/v8.h"
 
-typedef struct NPObject NPObject;
-
 namespace ppapi {
 class ArrayBufferVar;
-class NPObjectVar;
 class V8ObjectVar;
 class Var;
 }
 
 namespace content {
 
-// Adds NPObject var tracking to the standard PPAPI VarTracker for use in the
-// renderer.
 class HostVarTracker : public ppapi::VarTracker {
  public:
   HostVarTracker();
   virtual ~HostVarTracker();
 
-  // Tracks all live NPObjectVar. This is so we can map between instance +
-  // NPObject and get the NPObjectVar corresponding to it. This Add/Remove
-  // function is called by the NPObjectVar when it is created and
-  // destroyed.
-  void AddNPObjectVar(ppapi::NPObjectVar* object_var);
-  void RemoveNPObjectVar(ppapi::NPObjectVar* object_var);
-
-  // Looks up a previously registered NPObjectVar for the given NPObject and
-  // instance. Returns NULL if there is no NPObjectVar corresponding to the
-  // given NPObject for the given instance. See AddNPObjectVar above.
-  ppapi::NPObjectVar* NPObjectVarForNPObject(PP_Instance instance,
-                                             NPObject* np_object);
-
-  // Returns the number of NPObjectVar's associated with the given instance.
-  // Returns 0 if the instance isn't known.
-  CONTENT_EXPORT int GetLiveNPObjectVarsForInstance(PP_Instance instance) const;
-
   // Tracks all live V8ObjectVar. This is so we can map between instance +
   // V8Object and get the V8ObjectVar corresponding to it. This Add/Remove
   // function is called by the V8ObjectVar when it is created and destroyed.
-  void AddV8ObjectVar(ppapi::V8ObjectVar* object_var) { NOTIMPLEMENTED(); }
-  void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var) { NOTIMPLEMENTED(); }
+  void AddV8ObjectVar(ppapi::V8ObjectVar* object_var);
+  void RemoveV8ObjectVar(ppapi::V8ObjectVar* object_var);
   // Creates or retrieves a V8ObjectVar.
   PP_Var V8ObjectVarForV8Object(PP_Instance instance,
-                                v8::Handle<v8::Object> object) {
-    NOTIMPLEMENTED();
-    return PP_MakeUndefined();
-  }
+                                v8::Handle<v8::Object> object);
+  // Returns the number of V8ObjectVars associated with the given instance.
+  // Returns 0 if the instance isn't known.
+  CONTENT_EXPORT int GetLiveV8ObjectVarsForTest(PP_Instance instance);
 
   // VarTracker public implementation.
   virtual PP_Var MakeResourcePPVarFromMessage(
@@ -74,7 +52,7 @@
       int pending_renderer_id,
       int pending_browser_id) OVERRIDE;
   virtual ppapi::ResourceVar* MakeResourceVar(PP_Resource pp_resource) OVERRIDE;
-  virtual void DidDeleteInstance(PP_Instance instance) OVERRIDE;
+  virtual void DidDeleteInstance(PP_Instance pp_instance) OVERRIDE;
 
   virtual int TrackSharedMemoryHandle(PP_Instance instance,
                                       base::SharedMemoryHandle file,
@@ -94,20 +72,30 @@
 
   // Clear the reference count of the given object and remove it from
   // live_vars_.
-  void ForceReleaseNPObject(ppapi::NPObjectVar* object_var);
+  void ForceReleaseV8Object(ppapi::V8ObjectVar* object_var);
 
-  typedef std::map<NPObject*, ppapi::NPObjectVar*> NPObjectToNPObjectVarMap;
+  // A non-unique, ordered key for a V8ObjectVar. Contains the hash of the v8
+  // and the instance it is associated with.
+  struct V8ObjectVarKey {
+    explicit V8ObjectVarKey(ppapi::V8ObjectVar* object_var);
+    V8ObjectVarKey(PP_Instance i, v8::Handle<v8::Object> object);
+    ~V8ObjectVarKey();
 
-  // Lists all known NPObjects, first indexed by the corresponding instance,
-  // then by the NPObject*. This allows us to look up an NPObjectVar given
-  // these two pieces of information.
-  //
-  // The instance map is lazily managed, so we'll add the
-  // NPObjectToNPObjectVarMap lazily when the first NPObject var is created,
-  // and delete it when it's empty.
-  typedef std::map<PP_Instance, linked_ptr<NPObjectToNPObjectVarMap> >
-      InstanceMap;
-  InstanceMap instance_map_;
+    bool operator<(const V8ObjectVarKey& other) const;
+
+    PP_Instance instance;
+    int hash;
+  };
+  typedef std::multimap<V8ObjectVarKey, ppapi::V8ObjectVar*> ObjectMap;
+
+  // Returns an iterator into |object_map| which points to V8Object which
+  // is associated with the given instance and object.
+  ObjectMap::iterator GetForV8Object(PP_Instance instance,
+                                     v8::Handle<v8::Object> object);
+
+
+  // A multimap of V8ObjectVarKey -> ObjectMap.
+  ObjectMap object_map_;
 
   // Tracks all shared memory handles used for transmitting array buffers.
   struct SharedMemoryMapEntry {
diff --git a/content/renderer/pepper/host_var_tracker_unittest.cc b/content/renderer/pepper/host_var_tracker_unittest.cc
index 07b759d..43ce27e 100644
--- a/content/renderer/pepper/host_var_tracker_unittest.cc
+++ b/content/renderer/pepper/host_var_tracker_unittest.cc
@@ -2,56 +2,65 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/renderer/pepper/host_globals.h"
 #include "content/renderer/pepper/host_var_tracker.h"
 #include "content/renderer/pepper/mock_resource.h"
-#include "content/renderer/pepper/npapi_glue.h"
-#include "content/renderer/pepper/npobject_var.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/pepper_try_catch.h"
+#include "content/renderer/pepper/v8object_var.h"
 #include "content/test/ppapi_unittest.h"
+#include "gin/handle.h"
+#include "gin/wrappable.h"
 #include "ppapi/c/pp_var.h"
 #include "ppapi/c/ppp_instance.h"
-#include "third_party/npapi/bindings/npruntime.h"
 #include "third_party/WebKit/public/web/WebBindings.h"
 
-using ppapi::NPObjectVar;
+using ppapi::V8ObjectVar;
 
 namespace content {
 
 namespace {
 
-// Tracked NPObjects -----------------------------------------------------------
+int g_v8objects_alive = 0;
 
-int g_npobjects_alive = 0;
+class MyObject : public gin::Wrappable<MyObject> {
+ public:
+  static gin::WrapperInfo kWrapperInfo;
 
-void TrackedClassDeallocate(NPObject* npobject) {
-  g_npobjects_alive--;
-  delete npobject;
-}
+  static v8::Handle<v8::Value> Create(v8::Isolate* isolate) {
+    return gin::CreateHandle(isolate, new MyObject()).ToV8();
+  }
 
-NPClass g_tracked_npclass = {
-    NP_CLASS_STRUCT_VERSION, NULL, &TrackedClassDeallocate, NULL, NULL, NULL,
-    NULL,                    NULL, NULL,                    NULL, NULL, NULL, };
+ private:
+  MyObject() { ++g_v8objects_alive; }
+  virtual ~MyObject() { --g_v8objects_alive; }
 
-// Returns a new tracked NPObject with a refcount of 1. You'll want to put this
-// in a NPObjectReleaser to free this ref when the test completes.
-NPObject* NewTrackedNPObject() {
-  NPObject* object = new NPObject;
-  object->_class = &g_tracked_npclass;
-  object->referenceCount = 1;
-
-  g_npobjects_alive++;
-  return object;
-}
-
-struct ReleaseNPObject {
-  void operator()(NPObject* o) const { blink::WebBindings::releaseObject(o); }
+  DISALLOW_COPY_AND_ASSIGN(MyObject);
 };
 
-// Handles automatically releasing a reference to the NPObject on destruction.
-// It's assumed the input has a ref already taken.
-typedef scoped_ptr<NPObject, ReleaseNPObject> NPObjectReleaser;
+gin::WrapperInfo MyObject::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+class PepperTryCatchForTest : public PepperTryCatch {
+ public:
+  explicit PepperTryCatchForTest(PepperPluginInstanceImpl* instance)
+      : PepperTryCatch(instance, V8VarConverter::kAllowObjectVars),
+        handle_scope_(instance->GetIsolate()),
+        context_scope_(v8::Context::New(instance->GetIsolate())) {}
+
+  virtual void SetException(const char* message) OVERRIDE { NOTREACHED(); }
+  virtual bool HasException() OVERRIDE { return false; }
+  virtual v8::Handle<v8::Context> GetContext() OVERRIDE {
+    return instance_->GetIsolate()->GetCurrentContext();
+  }
+
+ private:
+  v8::HandleScope handle_scope_;
+  v8::Context::Scope context_scope_;
+
+  DISALLOW_COPY_AND_ASSIGN(PepperTryCatchForTest);
+};
 
 }  // namespace
 
@@ -59,58 +68,68 @@
  public:
   HostVarTrackerTest() {}
 
+  virtual void TearDown() OVERRIDE {
+    v8::Isolate::GetCurrent()->RequestGarbageCollectionForTesting(
+        v8::Isolate::kFullGarbageCollection);
+    EXPECT_EQ(0, g_v8objects_alive);
+    PpapiUnittest::TearDown();
+  }
+
   HostVarTracker& tracker() { return *HostGlobals::Get()->host_var_tracker(); }
 };
 
 TEST_F(HostVarTrackerTest, DeleteObjectVarWithInstance) {
+  v8::Isolate* test_isolate = v8::Isolate::GetCurrent();
+
   // Make a second instance (the test harness already creates & manages one).
   scoped_refptr<PepperPluginInstanceImpl> instance2(
       PepperPluginInstanceImpl::Create(NULL, module(), NULL, GURL()));
   PP_Instance pp_instance2 = instance2->pp_instance();
 
-  // Make an object var.
-  NPObjectReleaser npobject(NewTrackedNPObject());
-  NPObjectToPPVarForTest(instance2.get(), npobject.get());
-
-  EXPECT_EQ(1, g_npobjects_alive);
-  EXPECT_EQ(1, tracker().GetLiveNPObjectVarsForInstance(pp_instance2));
+  {
+    PepperTryCatchForTest try_catch(instance2.get());
+    // Make an object var.
+    ppapi::ScopedPPVar var = try_catch.FromV8(MyObject::Create(test_isolate));
+    EXPECT_EQ(1, g_v8objects_alive);
+    EXPECT_EQ(1, tracker().GetLiveV8ObjectVarsForTest(pp_instance2));
+    // Purposely leak the var.
+    var.Release();
+  }
 
   // Free the instance, this should release the ObjectVar.
   instance2 = NULL;
-  EXPECT_EQ(0, tracker().GetLiveNPObjectVarsForInstance(pp_instance2));
+  EXPECT_EQ(0, tracker().GetLiveV8ObjectVarsForTest(pp_instance2));
 }
 
 // Make sure that using the same NPObject should give the same PP_Var
 // each time.
 TEST_F(HostVarTrackerTest, ReuseVar) {
-  NPObjectReleaser npobject(NewTrackedNPObject());
+  PepperTryCatchForTest try_catch(instance());
 
-  PP_Var pp_object1 = NPObjectToPPVarForTest(instance(), npobject.get());
-  PP_Var pp_object2 = NPObjectToPPVarForTest(instance(), npobject.get());
+  v8::Handle<v8::Value> v8_object = MyObject::Create(v8::Isolate::GetCurrent());
+  ppapi::ScopedPPVar pp_object1 = try_catch.FromV8(v8_object);
+  ppapi::ScopedPPVar pp_object2 = try_catch.FromV8(v8_object);
 
   // The two results should be the same.
-  EXPECT_EQ(pp_object1.value.as_id, pp_object2.value.as_id);
+  EXPECT_EQ(pp_object1.get().value.as_id, pp_object2.get().value.as_id);
 
-  // The objects should be able to get us back to the associated NPObject.
-  // This ObjectVar must be released before we do NPObjectToPPVarForTest again
-  // below so it gets freed and we get a new identifier.
+  // The objects should be able to get us back to the associated v8 object.
   {
-    scoped_refptr<NPObjectVar> check_object(NPObjectVar::FromPPVar(pp_object1));
+    scoped_refptr<V8ObjectVar> check_object(
+        V8ObjectVar::FromPPVar(pp_object1.get()));
     ASSERT_TRUE(check_object.get());
-    EXPECT_EQ(instance()->pp_instance(), check_object->pp_instance());
-    EXPECT_EQ(npobject.get(), check_object->np_object());
+    EXPECT_EQ(instance(), check_object->instance());
+    EXPECT_EQ(v8_object, check_object->GetHandle());
   }
 
   // Remove both of the refs we made above.
-  ppapi::VarTracker* var_tracker = ppapi::PpapiGlobals::Get()->GetVarTracker();
-  var_tracker->ReleaseVar(static_cast<int32_t>(pp_object2.value.as_id));
-  var_tracker->ReleaseVar(static_cast<int32_t>(pp_object1.value.as_id));
+  pp_object1 = ppapi::ScopedPPVar();
+  pp_object2 = ppapi::ScopedPPVar();
 
   // Releasing the resource should free the internal ref, and so making a new
   // one now should generate a new ID.
-  PP_Var pp_object3 = NPObjectToPPVarForTest(instance(), npobject.get());
-  EXPECT_NE(pp_object1.value.as_id, pp_object3.value.as_id);
-  var_tracker->ReleaseVar(static_cast<int32_t>(pp_object3.value.as_id));
+  ppapi::ScopedPPVar pp_object3 = try_catch.FromV8(v8_object);
+  EXPECT_NE(pp_object1.get().value.as_id, pp_object3.get().value.as_id);
 }
 
 }  // namespace content
diff --git a/content/renderer/pepper/message_channel.cc b/content/renderer/pepper/message_channel.cc
index 150f16e..d5bbef9f 100644
--- a/content/renderer/pepper/message_channel.cc
+++ b/content/renderer/pepper/message_channel.cc
@@ -13,10 +13,16 @@
 #include "content/public/common/content_client.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/renderer/pepper/host_array_buffer_var.h"
-#include "content/renderer/pepper/npapi_glue.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/pepper_try_catch.h"
 #include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/plugin_object.h"
 #include "content/renderer/pepper/v8_var_converter.h"
+#include "gin/arguments.h"
+#include "gin/converter.h"
+#include "gin/function_template.h"
+#include "gin/object_template_builder.h"
+#include "gin/public/gin_embedders.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
 #include "ppapi/shared_impl/scoped_pp_var.h"
 #include "ppapi/shared_impl/var.h"
@@ -57,216 +63,10 @@
     "argument from a PP_Var to a Javascript value. It may have cycles or be of "
     "an unsupported type.";
 
-// Helper function to get the MessageChannel that is associated with an
-// NPObject*.
-MessageChannel* ToMessageChannel(NPObject* object) {
-  return static_cast<MessageChannel::MessageChannelNPObject*>(object)
-      ->message_channel.get();
-}
-
-NPObject* ToPassThroughObject(NPObject* object) {
-  MessageChannel* channel = ToMessageChannel(object);
-  return channel ? channel->passthrough_object() : NULL;
-}
-
-// Return true iff |identifier| is equal to |string|.
-bool IdentifierIs(NPIdentifier identifier, const char string[]) {
-  return WebBindings::getStringIdentifier(string) == identifier;
-}
-
-bool HasDevChannelPermission(NPObject* channel_object) {
-  MessageChannel* channel = ToMessageChannel(channel_object);
-  if (!channel)
-    return false;
+bool HasDevPermission() {
   return GetContentClient()->renderer()->IsPluginAllowedToUseDevChannelAPIs();
 }
 
-//------------------------------------------------------------------------------
-// Implementations of NPClass functions.  These are here to:
-// - Implement postMessage behavior.
-// - Forward calls to the 'passthrough' object to allow backwards-compatibility
-//   with GetInstanceObject() objects.
-//------------------------------------------------------------------------------
-NPObject* MessageChannelAllocate(NPP npp, NPClass* the_class) {
-  return new MessageChannel::MessageChannelNPObject;
-}
-
-void MessageChannelDeallocate(NPObject* object) {
-  MessageChannel::MessageChannelNPObject* instance =
-      static_cast<MessageChannel::MessageChannelNPObject*>(object);
-  delete instance;
-}
-
-bool MessageChannelHasMethod(NPObject* np_obj, NPIdentifier name) {
-  if (!np_obj)
-    return false;
-
-  if (IdentifierIs(name, kPostMessage))
-    return true;
-  if (IdentifierIs(name, kPostMessageAndAwaitResponse) &&
-      HasDevChannelPermission(np_obj)) {
-    return true;
-  }
-  // Other method names we will pass to the passthrough object, if we have one.
-  NPObject* passthrough = ToPassThroughObject(np_obj);
-  if (passthrough)
-    return WebBindings::hasMethod(NULL, passthrough, name);
-  return false;
-}
-
-bool MessageChannelInvoke(NPObject* np_obj,
-                          NPIdentifier name,
-                          const NPVariant* args,
-                          uint32 arg_count,
-                          NPVariant* result) {
-  if (!np_obj)
-    return false;
-
-  MessageChannel* message_channel = ToMessageChannel(np_obj);
-  if (!message_channel)
-    return false;
-
-  // Check to see if we should handle this function ourselves.
-  if (IdentifierIs(name, kPostMessage) && (arg_count == 1)) {
-    message_channel->PostMessageToNative(&args[0]);
-    return true;
-  } else if (IdentifierIs(name, kPostMessageAndAwaitResponse) &&
-             (arg_count == 1) &&
-             HasDevChannelPermission(np_obj)) {
-    message_channel->PostBlockingMessageToNative(&args[0], result);
-    return true;
-  }
-
-  // Other method calls we will pass to the passthrough object, if we have one.
-  NPObject* passthrough = ToPassThroughObject(np_obj);
-  if (passthrough) {
-    return WebBindings::invoke(
-        NULL, passthrough, name, args, arg_count, result);
-  }
-  return false;
-}
-
-bool MessageChannelInvokeDefault(NPObject* np_obj,
-                                 const NPVariant* args,
-                                 uint32 arg_count,
-                                 NPVariant* result) {
-  if (!np_obj)
-    return false;
-
-  // Invoke on the passthrough object, if we have one.
-  NPObject* passthrough = ToPassThroughObject(np_obj);
-  if (passthrough) {
-    return WebBindings::invokeDefault(
-        NULL, passthrough, args, arg_count, result);
-  }
-  return false;
-}
-
-bool MessageChannelHasProperty(NPObject* np_obj, NPIdentifier name) {
-  if (!np_obj)
-    return false;
-
-  MessageChannel* message_channel = ToMessageChannel(np_obj);
-  if (message_channel) {
-    if (message_channel->GetReadOnlyProperty(name, NULL))
-      return true;
-  }
-
-  // Invoke on the passthrough object, if we have one.
-  NPObject* passthrough = ToPassThroughObject(np_obj);
-  if (passthrough)
-    return WebBindings::hasProperty(NULL, passthrough, name);
-  return false;
-}
-
-bool MessageChannelGetProperty(NPObject* np_obj,
-                               NPIdentifier name,
-                               NPVariant* result) {
-  if (!np_obj)
-    return false;
-
-  // Don't allow getting the postMessage functions.
-  if (IdentifierIs(name, kPostMessage))
-    return false;
-  if (IdentifierIs(name, kPostMessageAndAwaitResponse) &&
-      HasDevChannelPermission(np_obj)) {
-     return false;
-  }
-  MessageChannel* message_channel = ToMessageChannel(np_obj);
-  if (message_channel) {
-    if (message_channel->GetReadOnlyProperty(name, result))
-      return true;
-  }
-
-  // Invoke on the passthrough object, if we have one.
-  NPObject* passthrough = ToPassThroughObject(np_obj);
-  if (passthrough)
-    return WebBindings::getProperty(NULL, passthrough, name, result);
-  return false;
-}
-
-bool MessageChannelSetProperty(NPObject* np_obj,
-                               NPIdentifier name,
-                               const NPVariant* variant) {
-  if (!np_obj)
-    return false;
-
-  // Don't allow setting the postMessage functions.
-  if (IdentifierIs(name, kPostMessage))
-    return false;
-  if (IdentifierIs(name, kPostMessageAndAwaitResponse) &&
-      HasDevChannelPermission(np_obj)) {
-    return false;
-  }
-  // Invoke on the passthrough object, if we have one.
-  NPObject* passthrough = ToPassThroughObject(np_obj);
-  if (passthrough)
-    return WebBindings::setProperty(NULL, passthrough, name, variant);
-  return false;
-}
-
-bool MessageChannelEnumerate(NPObject* np_obj,
-                             NPIdentifier** value,
-                             uint32_t* count) {
-  if (!np_obj)
-    return false;
-
-  // Invoke on the passthrough object, if we have one, to enumerate its
-  // properties.
-  NPObject* passthrough = ToPassThroughObject(np_obj);
-  if (passthrough) {
-    bool success = WebBindings::enumerate(NULL, passthrough, value, count);
-    if (success) {
-      // Add postMessage to the list and return it.
-      if (std::numeric_limits<size_t>::max() / sizeof(NPIdentifier) <=
-          static_cast<size_t>(*count) + 1)  // Else, "always false" x64 warning.
-        return false;
-      NPIdentifier* new_array = static_cast<NPIdentifier*>(
-          std::malloc(sizeof(NPIdentifier) * (*count + 1)));
-      std::memcpy(new_array, *value, sizeof(NPIdentifier) * (*count));
-      new_array[*count] = WebBindings::getStringIdentifier(kPostMessage);
-      std::free(*value);
-      *value = new_array;
-      ++(*count);
-      return true;
-    }
-  }
-
-  // Otherwise, build an array that includes only postMessage.
-  *value = static_cast<NPIdentifier*>(malloc(sizeof(NPIdentifier)));
-  (*value)[0] = WebBindings::getStringIdentifier(kPostMessage);
-  *count = 1;
-  return true;
-}
-
-NPClass message_channel_class = {
-    NP_CLASS_STRUCT_VERSION,      &MessageChannelAllocate,
-    &MessageChannelDeallocate,    NULL,
-    &MessageChannelHasMethod,     &MessageChannelInvoke,
-    &MessageChannelInvokeDefault, &MessageChannelHasProperty,
-    &MessageChannelGetProperty,   &MessageChannelSetProperty,
-    NULL,                         &MessageChannelEnumerate, };
-
 }  // namespace
 
 // MessageChannel --------------------------------------------------------------
@@ -288,71 +88,29 @@
   bool conversion_completed_;
 };
 
-MessageChannel::MessageChannelNPObject::MessageChannelNPObject() {}
+// static
+gin::WrapperInfo MessageChannel::kWrapperInfo = {gin::kEmbedderNativeGin};
 
-MessageChannel::MessageChannelNPObject::~MessageChannelNPObject() {}
-
-MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance)
-    : instance_(instance),
-      passthrough_object_(NULL),
-      np_object_(NULL),
-      early_message_queue_state_(QUEUE_MESSAGES),
-      weak_ptr_factory_(this) {
-  // Now create an NPObject for receiving calls to postMessage. This sets the
-  // reference count to 1.  We release it in the destructor.
-  NPObject* obj = WebBindings::createObject(instance_->instanceNPP(),
-                                            &message_channel_class);
-  DCHECK(obj);
-  np_object_ = static_cast<MessageChannel::MessageChannelNPObject*>(obj);
-  np_object_->message_channel = weak_ptr_factory_.GetWeakPtr();
+// static
+MessageChannel* MessageChannel::Create(PepperPluginInstanceImpl* instance,
+                                       v8::Persistent<v8::Object>* result) {
+  MessageChannel* message_channel = new MessageChannel(instance);
+  v8::HandleScope handle_scope(instance->GetIsolate());
+  v8::Context::Scope context_scope(instance->GetContext());
+  gin::Handle<MessageChannel> handle =
+      gin::CreateHandle(instance->GetIsolate(), message_channel);
+  result->Reset(instance->GetIsolate(), handle.ToV8()->ToObject());
+  return message_channel;
 }
 
 MessageChannel::~MessageChannel() {
-  WebBindings::releaseObject(np_object_);
-  if (passthrough_object_)
-    WebBindings::releaseObject(passthrough_object_);
+  passthrough_object_.Reset();
+  if (instance_)
+    instance_->MessageChannelDestroyed();
 }
 
-void MessageChannel::Start() {
-  // We PostTask here instead of draining the message queue directly
-  // since we haven't finished initializing the PepperWebPluginImpl yet, so
-  // the plugin isn't available in the DOM.
-  base::MessageLoop::current()->PostTask(
-      FROM_HERE,
-      base::Bind(&MessageChannel::DrainEarlyMessageQueue,
-                 weak_ptr_factory_.GetWeakPtr()));
-}
-
-void MessageChannel::SetPassthroughObject(NPObject* passthrough) {
-  // Retain the passthrough object; We need to ensure it lives as long as this
-  // MessageChannel.
-  if (passthrough)
-    WebBindings::retainObject(passthrough);
-
-  // If we had a passthrough set already, release it. Note that we retain the
-  // incoming passthrough object first, so that we behave correctly if anyone
-  // invokes:
-  //   SetPassthroughObject(passthrough_object());
-  if (passthrough_object_)
-    WebBindings::releaseObject(passthrough_object_);
-
-  passthrough_object_ = passthrough;
-}
-
-bool MessageChannel::GetReadOnlyProperty(NPIdentifier key,
-                                         NPVariant* value) const {
-  std::map<NPIdentifier, ScopedPPVar>::const_iterator it =
-      internal_properties_.find(key);
-  if (it != internal_properties_.end()) {
-    if (value)
-      return PPVarToNPVariant(it->second.get(), value);
-    return true;
-  }
-  return false;
-}
-
-void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) {
-  internal_properties_[PPVarToNPIdentifier(key)] = ScopedPPVar(value);
+void MessageChannel::InstanceDeleted() {
+  instance_ = NULL;
 }
 
 void MessageChannel::PostMessageToJavaScript(PP_Var message_data) {
@@ -360,17 +118,10 @@
 
   // Because V8 is probably not on the stack for Native->JS calls, we need to
   // enter the appropriate context for the plugin.
-  WebPluginContainer* container = instance_->container();
-  // It's possible that container() is NULL if the plugin has been removed from
-  // the DOM (but the PluginInstance is not destroyed yet).
-  if (!container)
-    return;
-
-  v8::Local<v8::Context> context =
-      container->element().document().frame()->mainWorldScriptContext();
-  // If the page is being destroyed, the context may be empty.
+  v8::Local<v8::Context> context = instance_->GetContext();
   if (context.IsEmpty())
     return;
+
   v8::Context::Scope context_scope(context);
 
   v8::Handle<v8::Value> v8_val;
@@ -399,16 +150,144 @@
   }
 }
 
-void MessageChannel::PostMessageToNative(const NPVariant* message_data) {
+void MessageChannel::Start() {
+  // We PostTask here instead of draining the message queue directly
+  // since we haven't finished initializing the PepperWebPluginImpl yet, so
+  // the plugin isn't available in the DOM.
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE,
+      base::Bind(&MessageChannel::DrainEarlyMessageQueue,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MessageChannel::SetPassthroughObject(v8::Handle<v8::Object> passthrough) {
+  passthrough_object_.Reset(instance_->GetIsolate(), passthrough);
+}
+
+void MessageChannel::SetReadOnlyProperty(PP_Var key, PP_Var value) {
+  StringVar* key_string = StringVar::FromPPVar(key);
+  if (key_string) {
+    internal_named_properties_[key_string->value()] = ScopedPPVar(value);
+  } else {
+    NOTREACHED();
+  }
+}
+
+MessageChannel::MessageChannel(PepperPluginInstanceImpl* instance)
+    : gin::NamedPropertyInterceptor(instance->GetIsolate(), this),
+      instance_(instance),
+      early_message_queue_state_(QUEUE_MESSAGES),
+      weak_ptr_factory_(this) {
+}
+
+gin::ObjectTemplateBuilder MessageChannel::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return Wrappable<MessageChannel>::GetObjectTemplateBuilder(isolate)
+      .AddNamedPropertyInterceptor();
+}
+
+v8::Local<v8::Value> MessageChannel::GetNamedProperty(
+    v8::Isolate* isolate,
+    const std::string& identifier) {
+  if (!instance_)
+    return v8::Local<v8::Value>();
+
+  PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars,
+                             isolate);
+  if (identifier == kPostMessage) {
+    return gin::CreateFunctionTemplate(isolate,
+        base::Bind(&MessageChannel::PostMessageToNative,
+                   weak_ptr_factory_.GetWeakPtr()))->GetFunction();
+  } else if (identifier == kPostMessageAndAwaitResponse && HasDevPermission()) {
+    return gin::CreateFunctionTemplate(isolate,
+        base::Bind(&MessageChannel::PostBlockingMessageToNative,
+                   weak_ptr_factory_.GetWeakPtr()))->GetFunction();
+  }
+
+  std::map<std::string, ScopedPPVar>::const_iterator it =
+      internal_named_properties_.find(identifier);
+  if (it != internal_named_properties_.end()) {
+    v8::Handle<v8::Value> result = try_catch.ToV8(it->second.get());
+    if (try_catch.ThrowException())
+      return v8::Local<v8::Value>();
+    return result;
+  }
+
+  PluginObject* plugin_object = GetPluginObject(isolate);
+  if (plugin_object)
+    return plugin_object->GetNamedProperty(isolate, identifier);
+  return v8::Local<v8::Value>();
+}
+
+bool MessageChannel::SetNamedProperty(v8::Isolate* isolate,
+                                      const std::string& identifier,
+                                      v8::Local<v8::Value> value) {
+  if (!instance_)
+    return false;
+  PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars,
+                             isolate);
+  if (identifier == kPostMessage ||
+      (identifier == kPostMessageAndAwaitResponse && HasDevPermission())) {
+    try_catch.ThrowException("Cannot set properties with the name postMessage"
+                             "or postMessageAndAwaitResponse");
+    return true;
+  }
+
+  // We don't forward this to the passthrough object; no plugins use that
+  // feature.
+  // TODO(raymes): Remove SetProperty support from PPP_Class.
+
+  return false;
+}
+
+std::vector<std::string> MessageChannel::EnumerateNamedProperties(
+    v8::Isolate* isolate) {
+  std::vector<std::string> result;
+  PluginObject* plugin_object = GetPluginObject(isolate);
+  if (plugin_object)
+    result = plugin_object->EnumerateNamedProperties(isolate);
+  result.push_back(kPostMessage);
+  if (HasDevPermission())
+    result.push_back(kPostMessageAndAwaitResponse);
+  return result;
+}
+
+void MessageChannel::PostMessageToNative(gin::Arguments* args) {
+  if (!instance_)
+    return;
+  if (args->Length() != 1) {
+    // TODO(raymes): Consider throwing an exception here. We don't now for
+    // backward compatibility.
+    return;
+  }
+
+  v8::Handle<v8::Value> message_data;
+  if (!args->GetNext(&message_data)) {
+    NOTREACHED();
+  }
+
   EnqueuePluginMessage(message_data);
   DrainCompletedPluginMessages();
 }
 
-void MessageChannel::PostBlockingMessageToNative(const NPVariant* message_data,
-                                                 NPVariant* np_result) {
+void MessageChannel::PostBlockingMessageToNative(gin::Arguments* args) {
+  if (!instance_)
+    return;
+  PepperTryCatchV8 try_catch(instance_, V8VarConverter::kDisallowObjectVars,
+                             args->isolate());
+  if (args->Length() != 1) {
+    try_catch.ThrowException(
+        "postMessageAndAwaitResponse requires one argument");
+    return;
+  }
+
+  v8::Handle<v8::Value> message_data;
+  if (!args->GetNext(&message_data)) {
+    NOTREACHED();
+  }
+
   if (early_message_queue_state_ == QUEUE_MESSAGES) {
-    WebBindings::setException(
-        np_object_,
+    try_catch.ThrowException(
         "Attempted to call a synchronous method on a plugin that was not "
         "yet loaded.");
     return;
@@ -424,58 +303,31 @@
   // TODO(dmichael): Fix this.
   // See https://code.google.com/p/chromium/issues/detail?id=367896#c4
   if (!plugin_message_queue_.empty()) {
-    WebBindings::setException(
-        np_object_,
+    try_catch.ThrowException(
         "Failed to convert parameter synchronously, because a prior "
         "call to postMessage contained a type which required asynchronous "
         "transfer which has not completed. Not all types are supported yet by "
         "postMessageAndAwaitResponse. See crbug.com/367896.");
     return;
   }
-  ScopedPPVar param;
-  if (message_data->type == NPVariantType_Object) {
-    // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary,
-    // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var,
-    // which we don't support for Messaging.
-    v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(message_data);
-    V8VarConverter v8_var_converter(instance_->pp_instance());
-    bool success = v8_var_converter.FromV8ValueSync(
-        v8_value,
-        v8::Isolate::GetCurrent()->GetCurrentContext(),
-        &param);
-    if (!success) {
-      WebBindings::setException(
-          np_object_,
-          "Failed to convert the given parameter to a PP_Var to send to "
-          "the plugin.");
-      return;
-    }
-  } else {
-    param = ScopedPPVar(ScopedPPVar::PassRef(),
-                        NPVariantToPPVar(instance(), message_data));
-  }
+  ScopedPPVar param = try_catch.FromV8(message_data);
+  if (try_catch.ThrowException())
+    return;
+
   ScopedPPVar pp_result;
   bool was_handled = instance_->HandleBlockingMessage(param, &pp_result);
   if (!was_handled) {
-    WebBindings::setException(
-        np_object_,
+    try_catch.ThrowException(
         "The plugin has not registered a handler for synchronous messages. "
         "See the documentation for PPB_Messaging::RegisterMessageHandler "
         "and PPP_MessageHandler.");
     return;
   }
-  v8::Handle<v8::Value> v8_val;
-  if (!V8VarConverter(instance_->pp_instance()).ToV8Value(
-          pp_result.get(),
-          v8::Isolate::GetCurrent()->GetCurrentContext(),
-          &v8_val)) {
-    WebBindings::setException(
-        np_object_,
-        "Failed to convert the plugin's result to a JavaScript type.");
+  v8::Handle<v8::Value> v8_result = try_catch.ToV8(pp_result.get());
+  if (try_catch.ThrowException())
     return;
-  }
-  // Success! Convert the result to an NPVariant.
-  WebBindings::toNPVariant(v8_val, NULL, np_result);
+
+  args->Return(v8_result);
 }
 
 void MessageChannel::PostMessageToJavaScriptImpl(
@@ -509,46 +361,44 @@
   container->element().dispatchEvent(msg_event);
 }
 
-void MessageChannel::EnqueuePluginMessage(const NPVariant* variant) {
-  plugin_message_queue_.push_back(VarConversionResult());
-  if (variant->type == NPVariantType_Object) {
-    // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary,
-    // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var,
-    // which we don't support for Messaging.
+PluginObject* MessageChannel::GetPluginObject(v8::Isolate* isolate) {
+  return PluginObject::FromV8Object(isolate,
+      v8::Local<v8::Object>::New(isolate, passthrough_object_));
+}
 
-    // Calling WebBindings::toV8Value creates a wrapper around NPVariant so it
-    // won't result in a deep copy.
-    v8::Handle<v8::Value> v8_value = WebBindings::toV8Value(variant);
-    V8VarConverter v8_var_converter(instance_->pp_instance());
-    V8VarConverter::VarResult conversion_result =
-        v8_var_converter.FromV8Value(
-            v8_value,
-            v8::Isolate::GetCurrent()->GetCurrentContext(),
-            base::Bind(&MessageChannel::FromV8ValueComplete,
-                       weak_ptr_factory_.GetWeakPtr(),
-                       &plugin_message_queue_.back()));
-    if (conversion_result.completed_synchronously) {
-      plugin_message_queue_.back().ConversionCompleted(
-          conversion_result.var,
-          conversion_result.success);
-    }
-  } else {
+void MessageChannel::EnqueuePluginMessage(v8::Handle<v8::Value> v8_value) {
+  plugin_message_queue_.push_back(VarConversionResult());
+  // Convert NPVariantType_Object in to an appropriate PP_Var like Dictionary,
+  // Array, etc. Note NPVariantToVar would convert to an "Object" PP_Var,
+  // which we don't support for Messaging.
+  // TODO(raymes): Possibly change this to use TryCatch to do the conversion and
+  // throw an exception if necessary.
+  V8VarConverter v8_var_converter(instance_->pp_instance());
+  V8VarConverter::VarResult conversion_result =
+      v8_var_converter.FromV8Value(
+          v8_value,
+          v8::Isolate::GetCurrent()->GetCurrentContext(),
+          base::Bind(&MessageChannel::FromV8ValueComplete,
+                     weak_ptr_factory_.GetWeakPtr(),
+                     &plugin_message_queue_.back()));
+  if (conversion_result.completed_synchronously) {
     plugin_message_queue_.back().ConversionCompleted(
-        ScopedPPVar(ScopedPPVar::PassRef(),
-                    NPVariantToPPVar(instance(), variant)),
-        true);
-    DCHECK(plugin_message_queue_.back().var().get().type != PP_VARTYPE_OBJECT);
+        conversion_result.var,
+        conversion_result.success);
   }
 }
 
 void MessageChannel::FromV8ValueComplete(VarConversionResult* result_holder,
                                          const ScopedPPVar& result,
                                          bool success) {
+  if (!instance_)
+    return;
   result_holder->ConversionCompleted(result, success);
   DrainCompletedPluginMessages();
 }
 
 void MessageChannel::DrainCompletedPluginMessages() {
+  DCHECK(instance_);
   if (early_message_queue_state_ == QUEUE_MESSAGES)
     return;
 
@@ -568,6 +418,8 @@
 }
 
 void MessageChannel::DrainEarlyMessageQueue() {
+  if (!instance_)
+    return;
   DCHECK(early_message_queue_state_ == QUEUE_MESSAGES);
 
   // Take a reference on the PluginInstance. This is because JavaScript code
diff --git a/content/renderer/pepper/message_channel.h b/content/renderer/pepper/message_channel.h
index 4682399..3caef263 100644
--- a/content/renderer/pepper/message_channel.h
+++ b/content/renderer/pepper/message_channel.h
@@ -9,20 +9,29 @@
 #include <list>
 #include <map>
 
+#include "base/basictypes.h"
 #include "base/memory/weak_ptr.h"
+#include "gin/handle.h"
+#include "gin/interceptor.h"
+#include "gin/wrappable.h"
 #include "ppapi/shared_impl/resource.h"
 #include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
-#include "third_party/npapi/bindings/npruntime.h"
+#include "v8/include/v8.h"
 
 struct PP_Var;
 
+namespace gin {
+class Arguments;
+}  // namespace gin
+
 namespace ppapi {
 class ScopedPPVar;
-}
+}  // namespace ppapi
 
 namespace content {
 
 class PepperPluginInstanceImpl;
+class PluginObject;
 
 // MessageChannel implements bidirectional postMessage functionality, allowing
 // calls from JavaScript to plugins and vice-versa. See
@@ -37,64 +46,77 @@
 //   - The message target won't be limited to instance, and should support
 //     either plugin-provided or JS objects.
 // TODO(dmichael):  Add support for separate MessagePorts.
-class MessageChannel {
+class MessageChannel : public gin::Wrappable<MessageChannel>,
+                       public gin::NamedPropertyInterceptor {
  public:
-  // MessageChannelNPObject is a simple struct that adds a pointer back to a
-  // MessageChannel instance.  This way, we can use an NPObject to allow
-  // JavaScript interactions without forcing MessageChannel to inherit from
-  // NPObject.
-  struct MessageChannelNPObject : public NPObject {
-    MessageChannelNPObject();
-    ~MessageChannelNPObject();
+  static gin::WrapperInfo kWrapperInfo;
 
-    base::WeakPtr<MessageChannel> message_channel;
-  };
+  // Creates a MessageChannel, returning a pointer to it and sets |result| to
+  // the v8 object which is backed by the message channel. The returned pointer
+  // is only valid as long as the object in |result| is alive.
+  static MessageChannel* Create(PepperPluginInstanceImpl* instance,
+                                v8::Persistent<v8::Object>* result);
 
-  explicit MessageChannel(PepperPluginInstanceImpl* instance);
-  ~MessageChannel();
+  virtual ~MessageChannel();
+
+  // Called when the instance is deleted. The MessageChannel might outlive the
+  // plugin instance because it is garbage collected.
+  void InstanceDeleted();
+
+  // Post a message to the onmessage handler for this channel's instance
+  // asynchronously.
+  void PostMessageToJavaScript(PP_Var message_data);
 
   // Messages are queued initially. After the PepperPluginInstanceImpl is ready
   // to send and handle messages, users of MessageChannel should call
   // Start().
   void Start();
 
-  // Return the NPObject* to which we should forward any calls which aren't
-  // related to postMessage.  Note that this can be NULL;  it only gets set if
+  // Set the V8Object to which we should forward any calls which aren't
+  // related to postMessage. Note that this can be empty; it only gets set if
   // there is a scriptable 'InstanceObject' associated with this channel's
   // instance.
-  NPObject* passthrough_object() { return passthrough_object_; }
-  void SetPassthroughObject(NPObject* passthrough);
-
-  NPObject* np_object() { return np_object_; }
+  void SetPassthroughObject(v8::Handle<v8::Object> passthrough);
 
   PepperPluginInstanceImpl* instance() { return instance_; }
 
-  bool GetReadOnlyProperty(NPIdentifier key, NPVariant* value) const;
   void SetReadOnlyProperty(PP_Var key, PP_Var value);
 
-  // Post a message to the onmessage handler for this channel's instance
-  // asynchronously.
-  void PostMessageToJavaScript(PP_Var message_data);
+ private:
+  // Struct for storing the result of a v8 object being converted to a PP_Var.
+  struct VarConversionResult;
+
+  explicit MessageChannel(PepperPluginInstanceImpl* instance);
+
+  // gin::NamedPropertyInterceptor
+  virtual v8::Local<v8::Value> GetNamedProperty(
+      v8::Isolate* isolate,
+      const std::string& property) OVERRIDE;
+  virtual bool SetNamedProperty(v8::Isolate* isolate,
+                                const std::string& property,
+                                v8::Local<v8::Value> value) OVERRIDE;
+  virtual std::vector<std::string> EnumerateNamedProperties(
+      v8::Isolate* isolate) OVERRIDE;
+
+  // gin::Wrappable
+  virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) OVERRIDE;
 
   // Post a message to the plugin's HandleMessage function for this channel's
   // instance.
-  void PostMessageToNative(const NPVariant* message_data);
-
+  void PostMessageToNative(gin::Arguments* args);
   // Post a message to the plugin's HandleBlocking Message function for this
   // channel's instance synchronously, and return a result.
-  void PostBlockingMessageToNative(const NPVariant* message_data,
-                                   NPVariant* np_result);
-
- private:
-  // Struct for storing the result of a NPVariant being converted to a PP_Var.
-  struct VarConversionResult;
+  void PostBlockingMessageToNative(gin::Arguments* args);
 
   // Post a message to the onmessage handler for this channel's instance
   // synchronously.  This is used by PostMessageToJavaScript.
   void PostMessageToJavaScriptImpl(
       const blink::WebSerializedScriptValue& message_data);
 
-  void EnqueuePluginMessage(const NPVariant* variant);
+  PluginObject* GetPluginObject(v8::Isolate* isolate);
+
+  void EnqueuePluginMessage(v8::Handle<v8::Value> v8_value);
 
   void FromV8ValueComplete(VarConversionResult* result_holder,
                            const ppapi::ScopedPPVar& result_var,
@@ -110,10 +132,7 @@
   // postMessage.  This is necessary to support backwards-compatibility, and
   // also trusted plugins for which we will continue to support synchronous
   // scripting.
-  NPObject* passthrough_object_;
-
-  // The NPObject we use to expose postMessage to JavaScript.
-  MessageChannelNPObject* np_object_;
+  v8::Persistent<v8::Object> passthrough_object_;
 
   std::deque<blink::WebSerializedScriptValue> early_message_queue_;
   enum EarlyMessageQueueState {
@@ -132,7 +151,7 @@
   // probably also work, but is less clearly specified).
   std::list<VarConversionResult> plugin_message_queue_;
 
-  std::map<NPIdentifier, ppapi::ScopedPPVar> internal_properties_;
+  std::map<std::string, ppapi::ScopedPPVar> internal_named_properties_;
 
   // This is used to ensure pending tasks will not fire after this object is
   // destroyed.
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index 1fee1a7..304fdf8 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -33,12 +33,12 @@
 #include "content/renderer/pepper/host_dispatcher_wrapper.h"
 #include "content/renderer/pepper/host_globals.h"
 #include "content/renderer/pepper/message_channel.h"
-#include "content/renderer/pepper/npapi_glue.h"
 #include "content/renderer/pepper/pepper_browser_connection.h"
 #include "content/renderer/pepper/pepper_compositor_host.h"
 #include "content/renderer/pepper/pepper_file_ref_renderer_host.h"
 #include "content/renderer/pepper/pepper_graphics_2d_host.h"
 #include "content/renderer/pepper/pepper_in_process_router.h"
+#include "content/renderer/pepper/pepper_try_catch.h"
 #include "content/renderer/pepper/pepper_url_loader_host.h"
 #include "content/renderer/pepper/plugin_module.h"
 #include "content/renderer/pepper/plugin_object.h"
@@ -115,6 +115,7 @@
 #include "third_party/WebKit/public/web/WebPrintParams.h"
 #include "third_party/WebKit/public/web/WebPrintScalingOption.h"
 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
 #include "third_party/WebKit/public/web/WebView.h"
@@ -543,6 +544,7 @@
       fullscreen_container_(NULL),
       flash_fullscreen_(false),
       desired_fullscreen_state_(false),
+      message_channel_(NULL),
       sad_plugin_(NULL),
       input_event_mask_(0),
       filtered_input_event_mask_(0),
@@ -555,7 +557,6 @@
       pending_user_gesture_(0.0),
       document_loader_(NULL),
       external_document_load_(false),
-      npp_(new NPP_t),
       isolate_(v8::Isolate::GetCurrent()),
       is_deleted_(false),
       last_input_number_(0),
@@ -616,8 +617,8 @@
 PepperPluginInstanceImpl::~PepperPluginInstanceImpl() {
   DCHECK(!fullscreen_container_);
 
-  // Free all the plugin objects. This will automatically clear the back-
-  // pointer from the NPObject so WebKit can't call into the plugin any more.
+  // Notify all the plugin objects of deletion. This will prevent blink from
+  // calling into the plugin any more.
   //
   // Swap out the set so we can delete from it (the objects will try to
   // unregister themselves inside the delete call).
@@ -625,8 +626,13 @@
   live_plugin_objects_.swap(plugin_object_copy);
   for (PluginObjectSet::iterator i = plugin_object_copy.begin();
        i != plugin_object_copy.end();
-       ++i)
-    delete *i;
+       ++i) {
+    (*i)->InstanceDeleted();
+  }
+
+  if (message_channel_)
+    message_channel_->InstanceDeleted();
+  message_channel_object_.Reset();
 
   if (TrackedCallback::IsPending(lock_mouse_callback_))
     lock_mouse_callback_->Abort();
@@ -657,6 +663,15 @@
 // If a method needs to access a member of the instance after the call has
 // returned, then it needs to keep its own reference on the stack.
 
+v8::Local<v8::Object> PepperPluginInstanceImpl::GetMessageChannelObject() {
+  return v8::Local<v8::Object>::New(isolate_, message_channel_object_);
+}
+
+void PepperPluginInstanceImpl::MessageChannelDestroyed() {
+  message_channel_ = NULL;
+  message_channel_object_.Reset();
+}
+
 v8::Local<v8::Context> PepperPluginInstanceImpl::GetContext() {
   if (!container_)
     return v8::Handle<v8::Context>();
@@ -683,7 +698,8 @@
   // release our last reference to the "InstanceObject" and will probably
   // destroy it. We want to do this prior to calling DidDestroy in case the
   // destructor of the instance object tries to use the instance.
-  message_channel_->SetPassthroughObject(NULL);
+  if (message_channel_)
+    message_channel_->SetPassthroughObject(v8::Handle<v8::Object>());
   // If this is a NaCl plugin instance, shut down the NaCl plugin by calling
   // its DidDestroy. Don't call DidDestroy on the untrusted plugin instance,
   // since there is little that it can do at this point.
@@ -845,7 +861,7 @@
     bool full_frame) {
   if (!render_frame_)
     return false;
-  message_channel_.reset(new MessageChannel(this));
+  message_channel_ = MessageChannel::Create(this, &message_channel_object_);
 
   full_frame_ = full_frame;
 
@@ -868,9 +884,11 @@
   // messages. (E.g., NaCl trusted plugin starting a child NaCl app.)
   //
   // A host for external plugins will call ResetAsProxied later, at which point
-  // we can Start() the message_channel_.
-  if (success && (!module_->renderer_ppapi_host()->IsExternalPluginHost()))
-    message_channel_->Start();
+  // we can Start() the MessageChannel.
+  if (success && (!module_->renderer_ppapi_host()->IsExternalPluginHost())) {
+    if (message_channel_)
+      message_channel_->Start();
+  }
   return success;
 }
 
@@ -1173,6 +1191,8 @@
 
 void PepperPluginInstanceImpl::HandleMessage(ScopedPPVar message) {
   TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleMessage");
+  if (is_deleted_)
+    return;
   ppapi::proxy::HostDispatcher* dispatcher =
       ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
   if (!dispatcher || (message.get().type == PP_VARTYPE_OBJECT)) {
@@ -1191,6 +1211,8 @@
 bool PepperPluginInstanceImpl::HandleBlockingMessage(ScopedPPVar message,
                                                      ScopedPPVar* result) {
   TRACE_EVENT0("ppapi", "PepperPluginInstanceImpl::HandleBlockingMessage");
+  if (is_deleted_)
+    return false;
   ppapi::proxy::HostDispatcher* dispatcher =
       ppapi::proxy::HostDispatcher::GetForInstance(pp_instance());
   if (!dispatcher || (message.get().type == PP_VARTYPE_OBJECT)) {
@@ -1214,10 +1236,12 @@
   return was_handled;
 }
 
-PP_Var PepperPluginInstanceImpl::GetInstanceObject() {
+PP_Var PepperPluginInstanceImpl::GetInstanceObject(v8::Isolate* isolate) {
   // Keep a reference on the stack. See NOTE above.
   scoped_refptr<PepperPluginInstanceImpl> ref(this);
 
+  DCHECK_EQ(isolate, isolate_);
+
   // If the plugin supports the private instance interface, try to retrieve its
   // instance object.
   if (LoadPrivateInterface())
@@ -1353,7 +1377,8 @@
 }
 
 void PepperPluginInstanceImpl::PostMessageToJavaScript(PP_Var message) {
-  message_channel_->PostMessageToJavaScript(message);
+  if (message_channel_)
+    message_channel_->PostMessageToJavaScript(message);
 }
 
 int32_t PepperPluginInstanceImpl::RegisterMessageHandler(
@@ -2352,70 +2377,76 @@
   if (!container_)
     return PP_MakeUndefined();
 
+  PepperTryCatchVar try_catch(this, NULL);
   WebLocalFrame* frame = container_->element().document().frame();
-  if (!frame)
+  if (!frame) {
+    try_catch.SetException("No frame exists for window object.");
     return PP_MakeUndefined();
+  }
 
-  return NPObjectToPPVar(this, frame->windowObject());
+  ScopedPPVar result =
+      try_catch.FromV8(frame->mainWorldScriptContext()->Global());
+  DCHECK(!try_catch.HasException());
+  return result.Release();
 }
 
 PP_Var PepperPluginInstanceImpl::GetOwnerElementObject(PP_Instance instance) {
   if (!container_)
     return PP_MakeUndefined();
-  return NPObjectToPPVar(this, container_->scriptableObjectForElement());
+  PepperTryCatchVar try_catch(this, NULL);
+  ScopedPPVar result = try_catch.FromV8(container_->v8ObjectForElement());
+  DCHECK(!try_catch.HasException());
+  return result.Release();
 }
 
 PP_Var PepperPluginInstanceImpl::ExecuteScript(PP_Instance instance,
-                                               PP_Var script,
+                                               PP_Var script_var,
                                                PP_Var* exception) {
+  if (!container_)
+    return PP_MakeUndefined();
+
   // Executing the script may remove the plugin from the DOM, so we need to keep
   // a reference to ourselves so that we can still process the result after the
   // WebBindings::evaluate() below.
   scoped_refptr<PepperPluginInstanceImpl> ref(this);
-  TryCatch try_catch(exception);
-  if (try_catch.has_exception())
+  PepperTryCatchVar try_catch(this, exception);
+
+  // Check for an exception due to the context being destroyed.
+  if (try_catch.HasException())
     return PP_MakeUndefined();
 
-  // Convert the script into an inconvenient NPString object.
-  StringVar* script_string = StringVar::FromPPVar(script);
-  if (!script_string) {
+  WebLocalFrame* frame = container_->element().document().frame();
+  if (!frame) {
+    try_catch.SetException("No frame to execute script in.");
+    return PP_MakeUndefined();
+  }
+
+  StringVar* script_string_var = StringVar::FromPPVar(script_var);
+  if (!script_string_var) {
     try_catch.SetException("Script param to ExecuteScript must be a string.");
     return PP_MakeUndefined();
   }
-  NPString np_script;
-  np_script.UTF8Characters = script_string->value().c_str();
-  np_script.UTF8Length = script_string->value().length();
 
-  // Get the current frame to pass to the evaluate function.
-  WebLocalFrame* frame = NULL;
-  if (container_)
-    frame = container_->element().document().frame();
-  if (!frame || !frame->windowObject()) {
-    try_catch.SetException("No context in which to execute script.");
-    return PP_MakeUndefined();
-  }
-
-  NPVariant result;
-  bool ok = false;
+  std::string script_string = script_string_var->value();
+  blink::WebScriptSource script(
+      blink::WebString::fromUTF8(script_string.c_str()));
+  v8::Handle<v8::Value> result;
   if (IsProcessingUserGesture()) {
     blink::WebScopedUserGesture user_gesture(CurrentUserGestureToken());
-    ok =
-        WebBindings::evaluate(NULL, frame->windowObject(), &np_script, &result);
+    result = frame->executeScriptAndReturnValue(script);
   } else {
-    ok =
-        WebBindings::evaluate(NULL, frame->windowObject(), &np_script, &result);
-  }
-  if (!ok) {
-    // TryCatch doesn't catch the exceptions properly. Since this is only for
-    // a trusted API, just set to a general exception message.
-    try_catch.SetException("Exception caught");
-    WebBindings::releaseVariantValue(&result);
-    return PP_MakeUndefined();
+    result = frame->executeScriptAndReturnValue(script);
   }
 
-  PP_Var ret = NPVariantToPPVar(this, &result);
-  WebBindings::releaseVariantValue(&result);
-  return ret;
+  // Check for an exception due to the context being destroyed.
+  if (try_catch.HasException())
+    return PP_MakeUndefined();
+
+  ScopedPPVar var_result = try_catch.FromV8(result);
+  if (try_catch.HasException())
+    return PP_MakeUndefined();
+
+  return var_result.Release();
 }
 
 uint32_t PepperPluginInstanceImpl::GetAudioHardwareOutputSampleRate(
@@ -2944,7 +2975,8 @@
   if (!instance_interface_->DidCreate(
           pp_instance(), argn_.size(), argn_array.get(), argv_array.get()))
     return PP_EXTERNAL_PLUGIN_ERROR_INSTANCE;
-  message_channel_->Start();
+  if (message_channel_)
+    message_channel_->Start();
 
   // Clear sent_initial_did_change_view_ and cancel any pending DidChangeView
   // event. This way, SendDidChangeView will send the "current" view
@@ -2973,8 +3005,6 @@
   return module == module_.get() || module == original_module_.get();
 }
 
-NPP PepperPluginInstanceImpl::instanceNPP() { return npp_.get(); }
-
 PepperPluginInstance* PepperPluginInstance::Get(PP_Instance instance_id) {
   return HostGlobals::Get()->GetInstance(instance_id);
 }
@@ -3181,7 +3211,8 @@
 }
 
 void PepperPluginInstanceImpl::SetEmbedProperty(PP_Var key, PP_Var value) {
-  message_channel_->SetReadOnlyProperty(key, value);
+  if (message_channel_)
+    message_channel_->SetReadOnlyProperty(key, value);
 }
 
 bool PepperPluginInstanceImpl::CanAccessMainFrame() const {
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.h b/content/renderer/pepper/pepper_plugin_instance_impl.h
index 4b86e6e6..6ef11c2e3 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.h
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.h
@@ -23,6 +23,7 @@
 #include "content/public/renderer/pepper_plugin_instance.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "content/renderer/mouse_lock_dispatcher.h"
+#include "gin/handle.h"
 #include "ppapi/c/dev/pp_cursor_type_dev.h"
 #include "ppapi/c/dev/ppp_printing_dev.h"
 #include "ppapi/c/dev/ppp_selection_dev.h"
@@ -131,7 +132,6 @@
                                           const GURL& plugin_url);
   RenderFrameImpl* render_frame() const { return render_frame_; }
   PluginModule* module() const { return module_.get(); }
-  MessageChannel& message_channel() { return *message_channel_; }
 
   blink::WebPluginContainer* container() const { return container_; }
 
@@ -143,6 +143,12 @@
     return *resource_creation_.get();
   }
 
+  MessageChannel* message_channel() { return message_channel_; }
+  v8::Local<v8::Object> GetMessageChannelObject();
+  // Called when |message_channel_| is destroyed as it may be destroyed prior to
+  // the plugin being destroyed.
+  void MessageChannelDestroyed();
+
   // Return the v8 context that the plugin is in.
   v8::Local<v8::Context> GetContext();
 
@@ -189,7 +195,7 @@
   bool HandleDocumentLoad(const blink::WebURLResponse& response);
   bool HandleInputEvent(const blink::WebInputEvent& event,
                         blink::WebCursorInfo* cursor_info);
-  PP_Var GetInstanceObject();
+  PP_Var GetInstanceObject(v8::Isolate* isolate);
   void ViewChanged(const gfx::Rect& position,
                    const gfx::Rect& clip,
                    const std::vector<gfx::Rect>& cut_outs_rects);
@@ -518,10 +524,6 @@
   // the given module.
   bool IsValidInstanceOf(PluginModule* module);
 
-  // Returns the plugin NPP identifier that this plugin will use to identify
-  // itself when making NPObject scripting calls to WebBindings.
-  struct _NPP* instanceNPP();
-
   // cc::TextureLayerClient implementation.
   virtual bool PrepareTextureMailbox(
       cc::TextureMailbox* mailbox,
@@ -830,7 +832,11 @@
 
   // The MessageChannel used to implement bidirectional postMessage for the
   // instance.
-  scoped_ptr<MessageChannel> message_channel_;
+  v8::Persistent<v8::Object> message_channel_object_;
+
+  // A pointer to the MessageChannel underlying |message_channel_object_|. It is
+  // only valid as long as |message_channel_object_| is alive.
+  MessageChannel* message_channel_;
 
   // Bitmap for crashed plugin. Lazily initialized, non-owning pointer.
   SkBitmap* sad_plugin_;
@@ -880,10 +886,6 @@
   // The link currently under the cursor.
   base::string16 link_under_cursor_;
 
-  // Dummy NPP value used when calling in to WebBindings, to allow the bindings
-  // to correctly track NPObjects belonging to this plugin instance.
-  scoped_ptr<struct _NPP> npp_;
-
   // We store the isolate at construction so that we can be sure to use the
   // Isolate in which this Instance was created when interacting with v8.
   v8::Isolate* isolate_;
diff --git a/content/renderer/pepper/pepper_try_catch.cc b/content/renderer/pepper/pepper_try_catch.cc
index f5d8b3b..0d1aacc 100644
--- a/content/renderer/pepper/pepper_try_catch.cc
+++ b/content/renderer/pepper/pepper_try_catch.cc
@@ -5,7 +5,6 @@
 #include "content/renderer/pepper/pepper_try_catch.h"
 
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
-#include "content/renderer/pepper/v8_var_converter.h"
 #include "gin/converter.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
 #include "ppapi/shared_impl/var_tracker.h"
@@ -21,7 +20,7 @@
 }  // namespace
 
 PepperTryCatch::PepperTryCatch(PepperPluginInstanceImpl* instance,
-                               bool convert_objects)
+                               V8VarConverter::AllowObjectVars convert_objects)
     : instance_(instance),
       convert_objects_(convert_objects) {}
 
@@ -32,6 +31,11 @@
 }
 
 v8::Handle<v8::Value> PepperTryCatch::ToV8(PP_Var var) {
+  if (HasException()) {
+    SetException(kConversionException);
+    return v8::Handle<v8::Value>();
+  }
+
   V8VarConverter converter(instance_->pp_instance(), convert_objects_);
   v8::Handle<v8::Value> result;
   bool success = converter.ToV8Value(var, GetContext(), &result);
@@ -43,7 +47,7 @@
 }
 
 ppapi::ScopedPPVar PepperTryCatch::FromV8(v8::Handle<v8::Value> v8_value) {
-  if (v8_value.IsEmpty()) {
+  if (HasException() || v8_value.IsEmpty()) {
     SetException(kConversionException);
     return ppapi::ScopedPPVar();
   }
@@ -57,9 +61,10 @@
   return result;
 }
 
-PepperTryCatchV8::PepperTryCatchV8(PepperPluginInstanceImpl* instance,
-                                   bool convert_objects,
-                                   v8::Isolate* isolate)
+PepperTryCatchV8::PepperTryCatchV8(
+    PepperPluginInstanceImpl* instance,
+    V8VarConverter::AllowObjectVars convert_objects,
+    v8::Isolate* isolate)
     : PepperTryCatch(instance, convert_objects),
       exception_(PP_MakeUndefined()) {
   // Typically when using PepperTryCatchV8 we are passed an isolate. We verify
@@ -74,13 +79,18 @@
 }
 
 bool PepperTryCatchV8::HasException() {
-  return exception_.type != PP_VARTYPE_UNDEFINED;
+  return GetContext().IsEmpty() || exception_.type != PP_VARTYPE_UNDEFINED;
 }
 
 bool PepperTryCatchV8::ThrowException() {
   if (!HasException())
     return false;
 
+  // If the plugin context is gone, then we have an exception but we don't try
+  // to throw it into v8.
+  if (GetContext().IsEmpty())
+    return true;
+
   std::string message(kInvalidException);
   ppapi::StringVar* message_var = ppapi::StringVar::FromPPVar(exception_);
   if (message_var)
@@ -107,29 +117,39 @@
 }
 
 PepperTryCatchVar::PepperTryCatchVar(PepperPluginInstanceImpl* instance,
-                                     bool convert_objects,
                                      PP_Var* exception)
-    : PepperTryCatch(instance, convert_objects),
+    : PepperTryCatch(instance, V8VarConverter::kAllowObjectVars),
       handle_scope_(instance_->GetIsolate()),
       exception_(exception),
       exception_is_set_(false) {
   // We switch to the plugin context.
-  GetContext()->Enter();
+  v8::Handle<v8::Context> context = GetContext();
+  if (!context.IsEmpty())
+    context->Enter();
 }
 
 PepperTryCatchVar::~PepperTryCatchVar() {
-  GetContext()->Exit();
+  v8::Handle<v8::Context> context = GetContext();
+  if (!context.IsEmpty())
+    context->Exit();
 }
 
 bool PepperTryCatchVar::HasException() {
-  // Check if a v8 exception was caught.
-  if (!exception_is_set_ && try_catch_.HasCaught()) {
+  if (exception_is_set_)
+    return true;
+
+  std::string exception_message;
+  if (GetContext().IsEmpty()) {
+    exception_message = "The v8 context has been destroyed.";
+  } else if (try_catch_.HasCaught()) {
     v8::String::Utf8Value utf8(try_catch_.Message()->Get());
-    if (exception_) {
-      *exception_ = ppapi::StringVar::StringToPPVar(
-          std::string(*utf8, utf8.length()));
-    }
+    exception_message = std::string(*utf8, utf8.length());
+  }
+
+  if (!exception_message.empty()) {
     exception_is_set_ = true;
+    if (exception_)
+      *exception_ = ppapi::StringVar::StringToPPVar(exception_message);
   }
 
   return exception_is_set_;
diff --git a/content/renderer/pepper/pepper_try_catch.h b/content/renderer/pepper/pepper_try_catch.h
index 6b76717..459cb2c 100644
--- a/content/renderer/pepper/pepper_try_catch.h
+++ b/content/renderer/pepper/pepper_try_catch.h
@@ -7,6 +7,7 @@
 
 #include "base/basictypes.h"
 #include "content/common/content_export.h"
+#include "content/renderer/pepper/v8_var_converter.h"
 #include "ppapi/c/pp_var.h"
 #include "ppapi/shared_impl/scoped_pp_var.h"
 #include "v8/include/v8.h"
@@ -19,10 +20,11 @@
 class CONTENT_EXPORT PepperTryCatch {
  public:
   PepperTryCatch(PepperPluginInstanceImpl* instance,
-                 bool convert_objects);
+                 V8VarConverter::AllowObjectVars convert_objects);
   virtual ~PepperTryCatch();
 
   virtual void SetException(const char* message) = 0;
+  virtual bool HasException() = 0;
   // Gets the plugin context. Virtual so it can be overriden for testing.
   virtual v8::Handle<v8::Context> GetContext();
 
@@ -34,26 +36,27 @@
  protected:
   PepperPluginInstanceImpl* instance_;
 
-  // Whether To/FromV8 should convert object vars. If set to false, an exception
-  // should be set if they are encountered during conversion.
-  bool convert_objects_;
+  // Whether To/FromV8 should convert object vars. If set to
+  // kDisallowObjectVars, an exception should be set if they are encountered
+  // during conversion.
+  V8VarConverter::AllowObjectVars convert_objects_;
 };
 
 // Catches var exceptions and emits a v8 exception.
 class PepperTryCatchV8 : public PepperTryCatch {
  public:
   PepperTryCatchV8(PepperPluginInstanceImpl* instance,
-                   bool convert_objects,
+                   V8VarConverter::AllowObjectVars convert_objects,
                    v8::Isolate* isolate);
   virtual ~PepperTryCatchV8();
 
-  bool HasException();
   bool ThrowException();
   void ThrowException(const char* message);
   PP_Var* exception() { return &exception_; }
 
   // PepperTryCatch
   virtual void SetException(const char* message) OVERRIDE;
+  virtual bool HasException() OVERRIDE;
 
  private:
   PP_Var exception_;
@@ -68,14 +71,12 @@
   // is responsible for managing the lifetime of the exception. It is valid to
   //  pass NULL for |exception| in which case no exception will be set.
   PepperTryCatchVar(PepperPluginInstanceImpl* instance,
-                    bool convert_objects,
                     PP_Var* exception);
   virtual ~PepperTryCatchVar();
 
-  bool HasException();
-
   // PepperTryCatch
   virtual void SetException(const char* message) OVERRIDE;
+  virtual bool HasException() OVERRIDE;
 
  private:
   // Code which uses PepperTryCatchVar doesn't typically have a HandleScope,
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc
index 828da7a3..ecdd9e5 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -11,9 +11,9 @@
 #include "content/public/common/page_zoom.h"
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/renderer/pepper/message_channel.h"
-#include "content/renderer/pepper/npobject_var.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
 #include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/v8object_var.h"
 #include "content/renderer/render_frame_impl.h"
 #include "ppapi/shared_impl/ppapi_globals.h"
 #include "ppapi/shared_impl/var_tracker.h"
@@ -31,7 +31,7 @@
 #include "third_party/WebKit/public/web/WebPrintScalingOption.h"
 #include "url/gurl.h"
 
-using ppapi::NPObjectVar;
+using ppapi::V8ObjectVar;
 using blink::WebCanvas;
 using blink::WebPlugin;
 using blink::WebPluginContainer;
@@ -126,29 +126,30 @@
   base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
 }
 
-NPObject* PepperWebPluginImpl::scriptableObject() {
+v8::Local<v8::Object> PepperWebPluginImpl::v8ScriptableObject(
+      v8::Isolate* isolate) {
   // Call through the plugin to get its instance object. The plugin should pass
   // us a reference which we release in destroy().
   if (instance_object_.type == PP_VARTYPE_UNDEFINED)
-    instance_object_ = instance_->GetInstanceObject();
+    instance_object_ = instance_->GetInstanceObject(isolate);
   // GetInstanceObject talked to the plugin which may have removed the instance
   // from the DOM, in which case instance_ would be NULL now.
   if (!instance_.get())
-    return NULL;
+    return v8::Local<v8::Object>();
 
-  scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(instance_object_));
+  scoped_refptr<V8ObjectVar> object_var(
+      V8ObjectVar::FromPPVar(instance_object_));
   // If there's an InstanceObject, tell the Instance's MessageChannel to pass
   // any non-postMessage calls to it.
-  if (object.get()) {
-    instance_->message_channel().SetPassthroughObject(object->np_object());
+  if (object_var.get()) {
+    MessageChannel* message_channel = instance_->message_channel();
+    if (message_channel)
+      message_channel->SetPassthroughObject(object_var->GetHandle());
   }
-  NPObject* message_channel_np_object(instance_->message_channel().np_object());
-  // The object is expected to be retained before it is returned.
-  blink::WebBindings::retainObject(message_channel_np_object);
-  return message_channel_np_object;
-}
 
-NPP PepperWebPluginImpl::pluginNPP() { return instance_->instanceNPP(); }
+  v8::Handle<v8::Object> result = instance_->GetMessageChannelObject();
+  return result;
+}
 
 bool PepperWebPluginImpl::getFormValue(WebString& value) { return false; }
 
diff --git a/content/renderer/pepper/pepper_webplugin_impl.h b/content/renderer/pepper/pepper_webplugin_impl.h
index cee6690..291e5c1 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.h
+++ b/content/renderer/pepper/pepper_webplugin_impl.h
@@ -41,8 +41,8 @@
   virtual blink::WebPluginContainer* container() const;
   virtual bool initialize(blink::WebPluginContainer* container);
   virtual void destroy();
-  virtual NPObject* scriptableObject();
-  virtual struct _NPP* pluginNPP();
+  virtual v8::Local<v8::Object> v8ScriptableObject(
+      v8::Isolate* isolate) OVERRIDE;
   virtual bool getFormValue(blink::WebString& value);
   virtual void paint(blink::WebCanvas* canvas, const blink::WebRect& rect);
   virtual void updateGeometry(
diff --git a/content/renderer/pepper/plugin_object.cc b/content/renderer/pepper/plugin_object.cc
index 256c0a3..7260b01 100644
--- a/content/renderer/pepper/plugin_object.cc
+++ b/content/renderer/pepper/plugin_object.cc
@@ -4,14 +4,23 @@
 
 #include "content/renderer/pepper/plugin_object.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
-#include "content/renderer/pepper/npapi_glue.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/pepper_try_catch.h"
 #include "content/renderer/pepper/plugin_module.h"
+#include "content/renderer/pepper/v8_var_converter.h"
+#include "gin/arguments.h"
+#include "gin/converter.h"
+#include "gin/function_template.h"
+#include "gin/handle.h"
+#include "gin/interceptor.h"
+#include "gin/object_template_builder.h"
+#include "gin/public/gin_embedders.h"
 #include "ppapi/c/dev/ppb_var_deprecated.h"
 #include "ppapi/c/dev/ppp_class_deprecated.h"
 #include "ppapi/c/pp_resource.h"
@@ -20,14 +29,12 @@
 #include "ppapi/shared_impl/resource_tracker.h"
 #include "ppapi/shared_impl/var.h"
 #include "ppapi/shared_impl/var_tracker.h"
-#include "third_party/WebKit/public/web/WebBindings.h"
-#include "third_party/npapi/bindings/npapi.h"
-#include "third_party/npapi/bindings/npruntime.h"
 
 using ppapi::PpapiGlobals;
+using ppapi::ScopedPPVar;
+using ppapi::ScopedPPVarArray;
 using ppapi::StringVar;
 using ppapi::Var;
-using blink::WebBindings;
 
 namespace content {
 
@@ -35,333 +42,191 @@
 
 const char kInvalidValueException[] = "Error: Invalid value";
 
-// NPObject implementation in terms of PPP_Class_Deprecated --------------------
-
-NPObject* WrapperClass_Allocate(NPP npp, NPClass* unused) {
-  return PluginObject::AllocateObjectWrapper();
-}
-
-void WrapperClass_Deallocate(NPObject* np_object) {
-  PluginObject* plugin_object = PluginObject::FromNPObject(np_object);
-  if (plugin_object) {
-    plugin_object->ppp_class()->Deallocate(plugin_object->ppp_class_data());
-    delete plugin_object;
-  }
-  delete np_object;
-}
-
-void WrapperClass_Invalidate(NPObject* object) {}
-
-bool WrapperClass_HasMethod(NPObject* object, NPIdentifier method_name) {
-  NPObjectAccessorWithIdentifier accessor(object, method_name, false);
-  if (!accessor.is_valid())
-    return false;
-
-  PPResultAndExceptionToNPResult result_converter(
-      accessor.object()->GetNPObject(), NULL);
-  bool rv = accessor.object()->ppp_class()->HasMethod(
-      accessor.object()->ppp_class_data(),
-      accessor.identifier(),
-      result_converter.exception());
-  result_converter.CheckExceptionForNoResult();
-  return rv;
-}
-
-bool WrapperClass_Invoke(NPObject* object,
-                         NPIdentifier method_name,
-                         const NPVariant* argv,
-                         uint32_t argc,
-                         NPVariant* result) {
-  NPObjectAccessorWithIdentifier accessor(object, method_name, false);
-  if (!accessor.is_valid())
-    return false;
-
-  PPResultAndExceptionToNPResult result_converter(
-      accessor.object()->GetNPObject(), result);
-  PPVarArrayFromNPVariantArray args(accessor.object()->instance(), argc, argv);
-
-  // For the OOP plugin case we need to grab a reference on the plugin module
-  // object to ensure that it is not destroyed courtsey an incoming
-  // ExecuteScript call which destroys the plugin module and in turn the
-  // dispatcher.
-  scoped_refptr<PluginModule> ref(accessor.object()->instance()->module());
-
-  return result_converter.SetResult(
-      accessor.object()->ppp_class()->Call(accessor.object()->ppp_class_data(),
-                                           accessor.identifier(),
-                                           argc,
-                                           args.array(),
-                                           result_converter.exception()));
-}
-
-bool WrapperClass_InvokeDefault(NPObject* np_object,
-                                const NPVariant* argv,
-                                uint32_t argc,
-                                NPVariant* result) {
-  PluginObject* obj = PluginObject::FromNPObject(np_object);
-  if (!obj)
-    return false;
-
-  PPVarArrayFromNPVariantArray args(obj->instance(), argc, argv);
-  PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result);
-
-  // For the OOP plugin case we need to grab a reference on the plugin module
-  // object to ensure that it is not destroyed courtsey an incoming
-  // ExecuteScript call which destroys the plugin module and in turn the
-  // dispatcher.
-  scoped_refptr<PluginModule> ref(obj->instance()->module());
-
-  result_converter.SetResult(
-      obj->ppp_class()->Call(obj->ppp_class_data(),
-                             PP_MakeUndefined(),
-                             argc,
-                             args.array(),
-                             result_converter.exception()));
-  return result_converter.success();
-}
-
-bool WrapperClass_HasProperty(NPObject* object, NPIdentifier property_name) {
-  NPObjectAccessorWithIdentifier accessor(object, property_name, true);
-  if (!accessor.is_valid())
-    return false;
-
-  PPResultAndExceptionToNPResult result_converter(
-      accessor.object()->GetNPObject(), NULL);
-  bool rv = accessor.object()->ppp_class()->HasProperty(
-      accessor.object()->ppp_class_data(),
-      accessor.identifier(),
-      result_converter.exception());
-  result_converter.CheckExceptionForNoResult();
-  return rv;
-}
-
-bool WrapperClass_GetProperty(NPObject* object,
-                              NPIdentifier property_name,
-                              NPVariant* result) {
-  NPObjectAccessorWithIdentifier accessor(object, property_name, true);
-  if (!accessor.is_valid())
-    return false;
-
-  PPResultAndExceptionToNPResult result_converter(
-      accessor.object()->GetNPObject(), result);
-  return result_converter.SetResult(accessor.object()->ppp_class()->GetProperty(
-      accessor.object()->ppp_class_data(),
-      accessor.identifier(),
-      result_converter.exception()));
-}
-
-bool WrapperClass_SetProperty(NPObject* object,
-                              NPIdentifier property_name,
-                              const NPVariant* value) {
-  NPObjectAccessorWithIdentifier accessor(object, property_name, true);
-  if (!accessor.is_valid())
-    return false;
-
-  PPResultAndExceptionToNPResult result_converter(
-      accessor.object()->GetNPObject(), NULL);
-  PP_Var value_var = NPVariantToPPVar(accessor.object()->instance(), value);
-  accessor.object()->ppp_class()->SetProperty(
-      accessor.object()->ppp_class_data(),
-      accessor.identifier(),
-      value_var,
-      result_converter.exception());
-  PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(value_var);
-  return result_converter.CheckExceptionForNoResult();
-}
-
-bool WrapperClass_RemoveProperty(NPObject* object, NPIdentifier property_name) {
-  NPObjectAccessorWithIdentifier accessor(object, property_name, true);
-  if (!accessor.is_valid())
-    return false;
-
-  PPResultAndExceptionToNPResult result_converter(
-      accessor.object()->GetNPObject(), NULL);
-  accessor.object()->ppp_class()->RemoveProperty(
-      accessor.object()->ppp_class_data(),
-      accessor.identifier(),
-      result_converter.exception());
-  return result_converter.CheckExceptionForNoResult();
-}
-
-bool WrapperClass_Enumerate(NPObject* object,
-                            NPIdentifier** values,
-                            uint32_t* count) {
-  *values = NULL;
-  *count = 0;
-  PluginObject* obj = PluginObject::FromNPObject(object);
-  if (!obj)
-    return false;
-
-  uint32_t property_count = 0;
-  PP_Var* properties = NULL;  // Must be freed!
-  PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), NULL);
-  obj->ppp_class()->GetAllPropertyNames(obj->ppp_class_data(),
-                                        &property_count,
-                                        &properties,
-                                        result_converter.exception());
-
-  // Convert the array of PP_Var to an array of NPIdentifiers. If any
-  // conversions fail, we will set the exception.
-  if (!result_converter.has_exception()) {
-    if (property_count > 0) {
-      *values = static_cast<NPIdentifier*>(
-          calloc(property_count, sizeof(NPIdentifier)));
-      *count = 0;  // Will be the number of items successfully converted.
-      for (uint32_t i = 0; i < property_count; ++i) {
-        (*values)[i] = PPVarToNPIdentifier(properties[i]);
-        if (!(*values)[i]) {
-          // Throw an exception for the failed convertion.
-          *result_converter.exception() =
-              StringVar::StringToPPVar(kInvalidValueException);
-          break;
-        }
-        (*count)++;
-      }
-
-      if (result_converter.has_exception()) {
-        // We don't actually have to free the identifiers we converted since
-        // all identifiers leak anyway :( .
-        free(*values);
-        *values = NULL;
-        *count = 0;
-      }
-    }
-  }
-
-  // This will actually throw the exception, either from GetAllPropertyNames,
-  // or if anything was set during the conversion process.
-  result_converter.CheckExceptionForNoResult();
-
-  // Release the PP_Var that the plugin allocated. On success, they will all
-  // be converted to NPVariants, and on failure, we want them to just go away.
-  ppapi::VarTracker* var_tracker = PpapiGlobals::Get()->GetVarTracker();
-  for (uint32_t i = 0; i < property_count; ++i)
-    var_tracker->ReleaseVar(properties[i]);
-  free(properties);
-  return result_converter.success();
-}
-
-bool WrapperClass_Construct(NPObject* object,
-                            const NPVariant* argv,
-                            uint32_t argc,
-                            NPVariant* result) {
-  PluginObject* obj = PluginObject::FromNPObject(object);
-  if (!obj)
-    return false;
-
-  PPVarArrayFromNPVariantArray args(obj->instance(), argc, argv);
-  PPResultAndExceptionToNPResult result_converter(obj->GetNPObject(), result);
-  return result_converter.SetResult(obj->ppp_class()->Construct(
-      obj->ppp_class_data(), argc, args.array(), result_converter.exception()));
-}
-
-const NPClass wrapper_class = {
-    NP_CLASS_STRUCT_VERSION,     WrapperClass_Allocate,
-    WrapperClass_Deallocate,     WrapperClass_Invalidate,
-    WrapperClass_HasMethod,      WrapperClass_Invoke,
-    WrapperClass_InvokeDefault,  WrapperClass_HasProperty,
-    WrapperClass_GetProperty,    WrapperClass_SetProperty,
-    WrapperClass_RemoveProperty, WrapperClass_Enumerate,
-    WrapperClass_Construct};
-
 }  // namespace
 
 // PluginObject ----------------------------------------------------------------
 
-struct PluginObject::NPObjectWrapper : public NPObject {
-  // Points to the var object that owns this wrapper. This value may be NULL
-  // if there is no var owning this wrapper. This can happen if the plugin
-  // releases all references to the var, but a reference to the underlying
-  // NPObject is still held by script on the page.
-  PluginObject* obj;
-};
-
-PluginObject::PluginObject(PepperPluginInstanceImpl* instance,
-                           NPObjectWrapper* object_wrapper,
-                           const PPP_Class_Deprecated* ppp_class,
-                           void* ppp_class_data)
-    : instance_(instance),
-      object_wrapper_(object_wrapper),
-      ppp_class_(ppp_class),
-      ppp_class_data_(ppp_class_data) {
-  // Make the object wrapper refer back to this class so our NPObject
-  // implementation can call back into the Pepper layer.
-  object_wrapper_->obj = this;
-  instance_->AddPluginObject(this);
-}
-
 PluginObject::~PluginObject() {
-  // The wrapper we made for this NPObject may still have a reference to it
-  // from JavaScript, so we clear out its ObjectVar back pointer which will
-  // cause all calls "up" to the plugin to become NOPs. Our ObjectVar base
-  // class will release our reference to the object, which may or may not
-  // delete the NPObject.
-  DCHECK(object_wrapper_->obj == this);
-  object_wrapper_->obj = NULL;
-  instance_->RemovePluginObject(this);
+  if (instance_) {
+    ppp_class_->Deallocate(ppp_class_data_);
+    instance_->RemovePluginObject(this);
+  }
 }
 
+// static
+gin::WrapperInfo PluginObject::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+// static
+PluginObject* PluginObject::FromV8Object(v8::Isolate* isolate,
+                                         v8::Handle<v8::Object> v8_object) {
+  PluginObject* plugin_object;
+  if (!v8_object.IsEmpty() &&
+      gin::ConvertFromV8(isolate, v8_object, &plugin_object)) {
+    return plugin_object;
+  }
+  return NULL;
+}
+
+// static
 PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance,
                             const PPP_Class_Deprecated* ppp_class,
                             void* ppp_class_data) {
-  // This will internally end up calling our AllocateObjectWrapper via the
-  // WrapperClass_Allocated function which will have created an object wrapper
-  // appropriate for this class (derived from NPObject).
-  NPObjectWrapper* wrapper =
-      static_cast<NPObjectWrapper*>(WebBindings::createObject(
-          instance->instanceNPP(), const_cast<NPClass*>(&wrapper_class)));
-
-  // This object will register itself both with the NPObject and with the
-  // PluginModule. The NPObject will normally handle its lifetime, and it
-  // will get deleted in the destroy method. It may also get deleted when the
-  // plugin module is deallocated.
-  new PluginObject(instance, wrapper, ppp_class, ppp_class_data);
-
-  // We can just use a normal ObjectVar to refer to this object from the
-  // plugin. It will hold a ref to the underlying NPObject which will in turn
-  // hold our pluginObject.
-  PP_Var obj_var(NPObjectToPPVar(instance, wrapper));
-
-  // Note that the ObjectVar constructor incremented the reference count, and so
-  // did WebBindings::createObject above. Now that the PP_Var has taken
-  // ownership, we need to release to balance out the createObject reference
-  // count bump.
-  WebBindings::releaseObject(wrapper);
-  return obj_var;
+  PepperTryCatchVar try_catch(instance, NULL);
+  gin::Handle<PluginObject> object =
+      gin::CreateHandle(instance->GetIsolate(),
+                        new PluginObject(instance, ppp_class, ppp_class_data));
+  ScopedPPVar result = try_catch.FromV8(object.ToV8());
+  DCHECK(!try_catch.HasException());
+  return result.Release();
 }
 
-NPObject* PluginObject::GetNPObject() const { return object_wrapper_; }
-
-// static
-bool PluginObject::IsInstanceOf(NPObject* np_object,
-                                const PPP_Class_Deprecated* ppp_class,
-                                void** ppp_class_data) {
-  // Validate that this object is implemented by our wrapper class before
-  // trying to get the PluginObject.
-  if (np_object->_class != &wrapper_class)
-    return false;
-
-  PluginObject* plugin_object = FromNPObject(np_object);
-  if (!plugin_object)
-    return false;  // Object is no longer alive.
-
-  if (plugin_object->ppp_class() != ppp_class)
-    return false;
-  if (ppp_class_data)
-    *ppp_class_data = plugin_object->ppp_class_data();
-  return true;
+v8::Local<v8::Value> PluginObject::GetNamedProperty(
+    v8::Isolate* isolate,
+    const std::string& identifier) {
+  ScopedPPVar identifier_var(ScopedPPVar::PassRef(),
+                             StringVar::StringToPPVar(identifier));
+  return GetPropertyOrMethod(instance_->GetIsolate(), identifier_var.get());
 }
 
-// static
-PluginObject* PluginObject::FromNPObject(NPObject* object) {
-  return static_cast<NPObjectWrapper*>(object)->obj;
+std::vector<std::string> PluginObject::EnumerateNamedProperties(
+    v8::Isolate* isolate) {
+  std::vector<std::string> result;
+  if (!instance_)
+    return result;
+
+  PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars,
+                             isolate);
+
+  PP_Var* name_vars;
+  uint32_t count = 0;
+  ppp_class_->GetAllPropertyNames(ppp_class_data_, &count, &name_vars,
+                                  try_catch.exception());
+  ScopedPPVarArray scoped_name_vars(
+      ScopedPPVarArray::PassPPBMemoryAllocatedArray(), name_vars, count);
+
+  if (try_catch.ThrowException())
+    return result;
+
+  for (uint32_t i = 0; i < count; ++i) {
+    StringVar* string_var = StringVar::FromPPVar(name_vars[i]);
+    if (string_var) {
+      result.push_back(string_var->value());
+    } else {
+      try_catch.ThrowException(kInvalidValueException);
+      result.clear();
+      return result;
+    }
+  }
+
+  return result;
 }
 
-// static
-NPObject* PluginObject::AllocateObjectWrapper() {
-  NPObjectWrapper* wrapper = new NPObjectWrapper;
-  memset(wrapper, 0, sizeof(NPObjectWrapper));
-  return wrapper;
+void PluginObject::InstanceDeleted() {
+  instance_ = NULL;
+}
+
+PluginObject::PluginObject(PepperPluginInstanceImpl* instance,
+                           const PPP_Class_Deprecated* ppp_class,
+                           void* ppp_class_data)
+    : gin::NamedPropertyInterceptor(instance->GetIsolate(), this),
+      instance_(instance),
+      ppp_class_(ppp_class),
+      ppp_class_data_(ppp_class_data),
+      weak_factory_(this) {
+  instance_->AddPluginObject(this);
+}
+
+gin::ObjectTemplateBuilder PluginObject::GetObjectTemplateBuilder(
+    v8::Isolate* isolate) {
+  return Wrappable<PluginObject>::GetObjectTemplateBuilder(isolate)
+      .AddNamedPropertyInterceptor();
+}
+
+v8::Local<v8::Value> PluginObject::GetPropertyOrMethod(v8::Isolate* isolate,
+                                                       PP_Var identifier_var) {
+  if (!instance_)
+    return v8::Local<v8::Value>();
+
+  PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars,
+                             isolate);
+  bool has_property =
+      ppp_class_->HasProperty(ppp_class_data_, identifier_var,
+                              try_catch.exception());
+  if (try_catch.ThrowException())
+    return v8::Local<v8::Value>();
+
+  if (has_property) {
+    ScopedPPVar result_var(ScopedPPVar::PassRef(),
+        ppp_class_->GetProperty(ppp_class_data_, identifier_var,
+                                try_catch.exception()));
+    if (try_catch.ThrowException())
+      return v8::Local<v8::Value>();
+
+    v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get());
+    if (try_catch.ThrowException())
+      return v8::Local<v8::Value>();
+
+    return result;
+  }
+
+  bool has_method = identifier_var.type == PP_VARTYPE_STRING &&
+                    ppp_class_->HasMethod(ppp_class_data_, identifier_var,
+                                          try_catch.exception());
+  if (try_catch.ThrowException())
+    return v8::Local<v8::Value>();
+
+  if (has_method) {
+    const std::string& identifier =
+        StringVar::FromPPVar(identifier_var)->value();
+    return gin::CreateFunctionTemplate(isolate,
+                                       base::Bind(&PluginObject::Call,
+                                                  weak_factory_.GetWeakPtr(),
+                                                  identifier))->GetFunction();
+  }
+
+  return v8::Local<v8::Value>();
+}
+
+void PluginObject::Call(const std::string& identifier,
+                        gin::Arguments* args) {
+  if (!instance_)
+    return;
+
+  PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars,
+                             args->isolate());
+  ScopedPPVar identifier_var(ScopedPPVar::PassRef(),
+                             StringVar::StringToPPVar(identifier));
+  ScopedPPVarArray argument_vars(args->Length());
+
+  for (uint32_t i = 0; i < argument_vars.size(); ++i) {
+    v8::Handle<v8::Value> arg;
+    if (!args->GetNext(&arg)) {
+      NOTREACHED();
+    }
+
+    argument_vars.Set(i, try_catch.FromV8(arg));
+    if (try_catch.ThrowException())
+      return;
+  }
+
+  // For the OOP plugin case we need to grab a reference on the plugin module
+  // object to ensure that it is not destroyed courtesy an incoming
+  // ExecuteScript call which destroys the plugin module and in turn the
+  // dispatcher.
+  scoped_refptr<PluginModule> ref(instance_->module());
+
+  ScopedPPVar result_var(ScopedPPVar::PassRef(),
+      ppp_class_->Call(ppp_class_data_, identifier_var.get(),
+                       argument_vars.size(), argument_vars.get(),
+                       try_catch.exception()));
+  if (try_catch.ThrowException())
+    return;
+
+  v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get());
+  if (try_catch.ThrowException())
+    return;
+
+  args->Return(result);
 }
 
 }  // namespace content
diff --git a/content/renderer/pepper/plugin_object.h b/content/renderer/pepper/plugin_object.h
index 62ffd2e..4f640b8 100644
--- a/content/renderer/pepper/plugin_object.h
+++ b/content/renderer/pepper/plugin_object.h
@@ -8,11 +8,16 @@
 #include <string>
 
 #include "base/basictypes.h"
+#include "base/memory/weak_ptr.h"
+#include "gin/interceptor.h"
+#include "gin/wrappable.h"
+#include "ppapi/c/pp_var.h"
 
-struct PP_Var;
 struct PPP_Class_Deprecated;
-typedef struct NPObject NPObject;
-typedef struct _NPVariant NPVariant;
+
+namespace gin {
+  class Arguments;
+}  // namespace gin
 
 namespace content {
 
@@ -22,71 +27,59 @@
 //
 // In contrast, a var of type PP_VARTYPE_OBJECT is a reference to a JS object,
 // which might be implemented by the plugin (here) or by the JS engine.
-class PluginObject {
+class PluginObject : public gin::Wrappable<PluginObject>,
+                     public gin::NamedPropertyInterceptor {
  public:
+  static gin::WrapperInfo kWrapperInfo;
+
   virtual ~PluginObject();
 
+  // Returns the PluginObject which is contained in the given v8 object, or NULL
+  // if the object isn't backed by a PluginObject.
+  static PluginObject* FromV8Object(v8::Isolate* isolate,
+                                    v8::Handle<v8::Object> v8_object);
+
   // Allocates a new PluginObject and returns it as a PP_Var with a
   // refcount of 1.
   static PP_Var Create(PepperPluginInstanceImpl* instance,
                        const PPP_Class_Deprecated* ppp_class,
                        void* ppp_class_data);
 
-  PepperPluginInstanceImpl* instance() const { return instance_; }
+  // gin::NamedPropertyInterceptor
+  virtual v8::Local<v8::Value> GetNamedProperty(
+      v8::Isolate* isolate,
+      const std::string& property) OVERRIDE;
+  virtual std::vector<std::string> EnumerateNamedProperties(
+      v8::Isolate* isolate) OVERRIDE;
 
   const PPP_Class_Deprecated* ppp_class() { return ppp_class_; }
-  void* ppp_class_data() {
-    return ppp_class_data_;
-  };
+  void* ppp_class_data() { return ppp_class_data_; }
 
-  NPObject* GetNPObject() const;
-
-  // Returns true if the given var is an object implemented by the same plugin
-  // that owns the var object, and that the class matches. If it matches,
-  // returns true and places the class data into |*ppp_class_data| (which can
-  // optionally be NULL if no class data is desired).
-  static bool IsInstanceOf(NPObject* np_object,
-                           const PPP_Class_Deprecated* ppp_class,
-                           void** ppp_class_data);
-
-  // Converts the given NPObject to the corresponding ObjectVar.
-  //
-  // The given NPObject must be one corresponding to a PluginObject or this
-  // will crash. If the object is a PluginObject but the plugin has gone
-  // away (the object could still be alive because of a reference from JS),
-  // then the return value will be NULL.
-  static PluginObject* FromNPObject(NPObject* object);
-
-  // Allocates a plugin wrapper object and returns it as an NPObject. This is
-  // used internally only.
-  static NPObject* AllocateObjectWrapper();
+  // Called when the instance is destroyed.
+  void InstanceDeleted();
 
  private:
-  struct NPObjectWrapper;
-
-  // This object must be created using the CreateObject function of the which
-  // will set up the correct NPObject.
-  //
-  // The NPObjectWrapper (an NPObject) should already have the reference
-  // incremented on it, and this class will take ownership of that reference.
   PluginObject(PepperPluginInstanceImpl* instance,
-               NPObjectWrapper* object_wrapper,
                const PPP_Class_Deprecated* ppp_class,
                void* ppp_class_data);
 
-  PepperPluginInstanceImpl* instance_;
+  // gin::Wrappable
+  virtual gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+      v8::Isolate* isolate) OVERRIDE;
 
-  // Holds a pointer to the NPObject wrapper backing the var. This class
-  // derives from NPObject and we hold a reference to it, so it must be
-  // refcounted. When the type is not an object, this value will be NULL.
-  //
-  // We don't actually own this pointer, it's the NPObject that actually
-  // owns us.
-  NPObjectWrapper* object_wrapper_;
+  // Helper method to get named properties.
+  v8::Local<v8::Value> GetPropertyOrMethod(v8::Isolate* isolate,
+                                           PP_Var identifier_var);
+
+  void Call(const std::string& identifier, gin::Arguments* args);
+
+  PepperPluginInstanceImpl* instance_;
 
   const PPP_Class_Deprecated* ppp_class_;
   void* ppp_class_data_;
 
+  base::WeakPtrFactory<PluginObject> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PluginObject);
 };
 
diff --git a/content/renderer/pepper/ppb_var_deprecated_impl.cc b/content/renderer/pepper/ppb_var_deprecated_impl.cc
index bafbada..a0712778 100644
--- a/content/renderer/pepper/ppb_var_deprecated_impl.cc
+++ b/content/renderer/pepper/ppb_var_deprecated_impl.cc
@@ -7,314 +7,259 @@
 #include <limits>
 
 #include "content/renderer/pepper/host_globals.h"
-#include "content/renderer/pepper/npapi_glue.h"
-#include "content/renderer/pepper/npobject_var.h"
+#include "content/renderer/pepper/message_channel.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
+#include "content/renderer/pepper/pepper_try_catch.h"
 #include "content/renderer/pepper/plugin_module.h"
 #include "content/renderer/pepper/plugin_object.h"
+#include "content/renderer/pepper/v8object_var.h"
 #include "ppapi/c/dev/ppb_var_deprecated.h"
 #include "ppapi/c/ppb_var.h"
-#include "ppapi/c/pp_var.h"
 #include "ppapi/shared_impl/ppb_var_shared.h"
-#include "third_party/WebKit/public/web/WebBindings.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebPluginContainer.h"
 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
 
-using ppapi::NPObjectVar;
+using ppapi::V8ObjectVar;
 using ppapi::PpapiGlobals;
+using ppapi::ScopedPPVar;
+using ppapi::ScopedPPVarArray;
 using ppapi::StringVar;
 using ppapi::Var;
-using blink::WebBindings;
 
 namespace content {
 
 namespace {
 
+const char kInvalidIdentifierException[] = "Error: Invalid identifier.";
 const char kInvalidObjectException[] = "Error: Invalid object";
-const char kInvalidPropertyException[] = "Error: Invalid property";
-const char kInvalidValueException[] = "Error: Invalid value";
-const char kUnableToGetPropertyException[] = "Error: Unable to get property";
-const char kUnableToSetPropertyException[] = "Error: Unable to set property";
-const char kUnableToRemovePropertyException[] =
-    "Error: Unable to remove property";
-const char kUnableToGetAllPropertiesException[] =
-    "Error: Unable to get all properties";
 const char kUnableToCallMethodException[] = "Error: Unable to call method";
-const char kUnableToConstructException[] = "Error: Unable to construct";
 
-// ---------------------------------------------------------------------------
-// Utilities
+class ObjectAccessor {
+ public:
+  ObjectAccessor(PP_Var var)
+      : object_var_(V8ObjectVar::FromPPVar(var)),
+        instance_(object_var_ ? object_var_->instance() : NULL) {
+  }
 
-// Converts the given PP_Var to an NPVariant, returning true on success.
-// False means that the given variant is invalid. In this case, the result
-// NPVariant will be set to a void one.
-//
-// The contents of the PP_Var will NOT be copied, so you need to ensure that
-// the PP_Var remains valid while the resultant NPVariant is in use.
-bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
-  switch (var.type) {
-    case PP_VARTYPE_UNDEFINED:
-      VOID_TO_NPVARIANT(*result);
-      break;
-    case PP_VARTYPE_NULL:
-      NULL_TO_NPVARIANT(*result);
-      break;
-    case PP_VARTYPE_BOOL:
-      BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
-      break;
-    case PP_VARTYPE_INT32:
-      INT32_TO_NPVARIANT(var.value.as_int, *result);
-      break;
-    case PP_VARTYPE_DOUBLE:
-      DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
-      break;
-    case PP_VARTYPE_STRING: {
-      StringVar* string = StringVar::FromPPVar(var);
-      if (!string) {
-        VOID_TO_NPVARIANT(*result);
-        return false;
-      }
-      const std::string& value = string->value();
-      STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result);
-      break;
-    }
-    case PP_VARTYPE_OBJECT: {
-      scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
-      if (!object.get()) {
-        VOID_TO_NPVARIANT(*result);
-        return false;
-      }
-      OBJECT_TO_NPVARIANT(object->np_object(), *result);
-      break;
-    }
-    default:
-      VOID_TO_NPVARIANT(*result);
+  // Check if the object is valid. If it isn't, set an exception and return
+  // false.
+  bool IsValid(PP_Var* exception) {
+    // If we already have an exception, then the call is invalid according to
+    // the unittests.
+    if (exception && exception->type != PP_VARTYPE_UNDEFINED)
       return false;
+    if (instance_)
+      return true;
+    if (exception)
+      *exception = ppapi::StringVar::StringToPPVar(kInvalidObjectException);
+    return false;
   }
-  return true;
-}
-
-// ObjectAccessorTryCatch ------------------------------------------------------
-
-// Automatically sets up a TryCatch for accessing the object identified by the
-// given PP_Var. The module from the object will be used for the exception
-// strings generated by the TryCatch.
-//
-// This will automatically retrieve the ObjectVar from the object and throw
-// an exception if it's invalid. At the end of construction, if there is no
-// exception, you know that there is no previously set exception, that the
-// object passed in is valid and ready to use (via the object() getter), and
-// that the TryCatch's pp_module() getter is also set up properly and ready to
-// use.
-class ObjectAccessorTryCatch : public TryCatch {
- public:
-  ObjectAccessorTryCatch(PP_Var object, PP_Var* exception)
-      : TryCatch(exception), object_(NPObjectVar::FromPPVar(object)) {
-    if (!object_.get()) {
-      SetException(kInvalidObjectException);
-    }
-  }
-
-  NPObjectVar* object() { return object_.get(); }
-
-  PepperPluginInstanceImpl* GetPluginInstance() {
-    return HostGlobals::Get()->GetInstance(object()->pp_instance());
-  }
-
- protected:
-  scoped_refptr<NPObjectVar> object_;
-
-  DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch);
-};
-
-// ObjectAccessiorWithIdentifierTryCatch ---------------------------------------
-
-// Automatically sets up a TryCatch for accessing the identifier on the given
-// object. This just extends ObjectAccessorTryCatch to additionally convert
-// the given identifier to an NPIdentifier and validate it, throwing an
-// exception if it's invalid.
-//
-// At the end of construction, if there is no exception, you know that there is
-// no previously set exception, that the object passed in is valid and ready to
-// use (via the object() getter), that the identifier is valid and ready to
-// use (via the identifier() getter), and that the TryCatch's pp_module() getter
-// is also set up properly and ready to use.
-class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch {
- public:
-  ObjectAccessorWithIdentifierTryCatch(PP_Var object,
-                                       PP_Var identifier,
-                                       PP_Var* exception)
-      : ObjectAccessorTryCatch(object, exception), identifier_(0) {
-    if (!has_exception()) {
-      identifier_ = PPVarToNPIdentifier(identifier);
-      if (!identifier_)
-        SetException(kInvalidPropertyException);
-    }
-  }
-
-  NPIdentifier identifier() const { return identifier_; }
+  // Lazily grab the object so that the handle is created in the current handle
+  // scope.
+  v8::Handle<v8::Object> GetObject() { return object_var_->GetHandle(); }
+  PepperPluginInstanceImpl* instance() { return instance_; }
 
  private:
-  NPIdentifier identifier_;
-
-  DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch);
+  V8ObjectVar* object_var_;
+  PepperPluginInstanceImpl* instance_;
 };
 
-PP_Bool HasProperty(PP_Var var, PP_Var name, PP_Var* exception) {
-  ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
-  if (accessor.has_exception())
-    return PP_FALSE;
-  return PP_FromBool(WebBindings::hasProperty(
-      NULL, accessor.object()->np_object(), accessor.identifier()));
+bool IsValidIdentifer(PP_Var identifier, PP_Var* exception) {
+  if (identifier.type == PP_VARTYPE_INT32 ||
+      identifier.type == PP_VARTYPE_STRING) {
+    return true;
+  }
+  if (exception)
+    *exception = ppapi::StringVar::StringToPPVar(kInvalidIdentifierException);
+  return false;
 }
 
 bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
-  return PP_ToBool(HasProperty(var, name, exception));
+  ObjectAccessor accessor(var);
+  if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
+    return false;
+
+  PepperTryCatchVar try_catch(accessor.instance(), exception);
+  v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+  if (try_catch.HasException())
+    return false;
+
+  bool result = accessor.GetObject()->Has(v8_name);
+  if (try_catch.HasException())
+    return false;
+  return result;
 }
 
 bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
-  ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
-  if (accessor.has_exception())
+  ObjectAccessor accessor(var);
+  if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
     return false;
-  return WebBindings::hasMethod(
-      NULL, accessor.object()->np_object(), accessor.identifier());
+
+  PepperTryCatchVar try_catch(accessor.instance(), exception);
+  v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+  if (try_catch.HasException())
+    return false;
+
+  bool result = accessor.GetObject()->Has(v8_name) &&
+      accessor.GetObject()->Get(v8_name)->IsFunction();
+  if (try_catch.HasException())
+    return false;
+  return result;
 }
 
 PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) {
-  ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
-  if (accessor.has_exception())
+  ObjectAccessor accessor(var);
+  if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
     return PP_MakeUndefined();
 
-  NPVariant result;
-  if (!WebBindings::getProperty(NULL,
-                                accessor.object()->np_object(),
-                                accessor.identifier(),
-                                &result)) {
-    // An exception may have been raised.
-    accessor.SetException(kUnableToGetPropertyException);
+  PepperTryCatchVar try_catch(accessor.instance(), exception);
+  v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+  if (try_catch.HasException())
     return PP_MakeUndefined();
-  }
 
-  PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
-  WebBindings::releaseVariantValue(&result);
-  return ret;
+  ScopedPPVar result_var = try_catch.FromV8(accessor.GetObject()->Get(v8_name));
+  if (try_catch.HasException())
+    return PP_MakeUndefined();
+
+  return result_var.Release();
 }
 
 void EnumerateProperties(PP_Var var,
                          uint32_t* property_count,
                          PP_Var** properties,
                          PP_Var* exception) {
+  ObjectAccessor accessor(var);
+  if (!accessor.IsValid(exception))
+    return;
+
+  PepperTryCatchVar try_catch(accessor.instance(), exception);
+
   *properties = NULL;
   *property_count = 0;
 
-  ObjectAccessorTryCatch accessor(var, exception);
-  if (accessor.has_exception())
+  v8::Local<v8::Array> identifiers = accessor.GetObject()->GetPropertyNames();
+  if (try_catch.HasException())
     return;
-
-  NPIdentifier* identifiers = NULL;
-  uint32_t count = 0;
-  if (!WebBindings::enumerate(
-          NULL, accessor.object()->np_object(), &identifiers, &count)) {
-    accessor.SetException(kUnableToGetAllPropertiesException);
-    return;
+  ScopedPPVarArray identifier_vars(identifiers->Length());
+  for (uint32_t i = 0; i < identifiers->Length(); ++i) {
+    ScopedPPVar var = try_catch.FromV8(identifiers->Get(i));
+    if (try_catch.HasException())
+      return;
+    identifier_vars.Set(i, var);
   }
 
-  if (count == 0)
-    return;
-
-  *property_count = count;
-  *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count));
-  for (uint32_t i = 0; i < count; ++i) {
-    (*properties)[i] = NPIdentifierToPPVar(identifiers[i]);
-  }
-  free(identifiers);
+  size_t size = identifier_vars.size();
+  *properties = identifier_vars.Release(
+      ScopedPPVarArray::PassPPBMemoryAllocatedArray());
+  *property_count = size;
 }
 
 void SetPropertyDeprecated(PP_Var var,
                            PP_Var name,
                            PP_Var value,
                            PP_Var* exception) {
-  ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
-  if (accessor.has_exception())
+  ObjectAccessor accessor(var);
+  if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
     return;
 
-  NPVariant variant;
-  if (!PPVarToNPVariantNoCopy(value, &variant)) {
-    accessor.SetException(kInvalidValueException);
+  PepperTryCatchVar try_catch(accessor.instance(), exception);
+  v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+  v8::Handle<v8::Value> v8_value = try_catch.ToV8(value);
+
+  if (try_catch.HasException())
     return;
-  }
-  if (!WebBindings::setProperty(NULL,
-                                accessor.object()->np_object(),
-                                accessor.identifier(),
-                                &variant))
-    accessor.SetException(kUnableToSetPropertyException);
+
+  accessor.GetObject()->Set(v8_name, v8_value);
+  try_catch.HasException();  // Ensure an exception gets set if one occured.
 }
 
 void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
-  ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
-  if (accessor.has_exception())
+  ObjectAccessor accessor(var);
+  if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
     return;
 
-  if (!WebBindings::removeProperty(
-          NULL, accessor.object()->np_object(), accessor.identifier()))
-    accessor.SetException(kUnableToRemovePropertyException);
+  PepperTryCatchVar try_catch(accessor.instance(), exception);
+  v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
+
+  if (try_catch.HasException())
+    return;
+
+  accessor.GetObject()->Delete(v8_name);
+  try_catch.HasException();  // Ensure an exception gets set if one occured.
 }
 
-PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor,
+PP_Var CallDeprecatedInternal(PP_Var var,
                               PP_Var method_name,
                               uint32_t argc,
                               PP_Var* argv,
                               PP_Var* exception) {
-  NPIdentifier identifier;
+  ObjectAccessor accessor(var);
+  if (!accessor.IsValid(exception))
+    return PP_MakeUndefined();
+
+  // If the method name is undefined, set it to the empty string to trigger
+  // calling |var| as a function.
+  ScopedPPVar scoped_name(method_name);
   if (method_name.type == PP_VARTYPE_UNDEFINED) {
-    identifier = NULL;
-  } else if (method_name.type == PP_VARTYPE_STRING) {
-    // Specifically allow only string functions to be called.
-    identifier = PPVarToNPIdentifier(method_name);
-    if (!identifier) {
-      accessor->SetException(kInvalidPropertyException);
+    scoped_name = ScopedPPVar(ScopedPPVar::PassRef(),
+                                StringVar::StringToPPVar(""));
+  }
+
+  PepperTryCatchVar try_catch(accessor.instance(), exception);
+  v8::Handle<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get());
+  if (try_catch.HasException())
+    return PP_MakeUndefined();
+
+  if (!v8_method_name->IsString()) {
+    try_catch.SetException(kUnableToCallMethodException);
+    return PP_MakeUndefined();
+  }
+
+  v8::Handle<v8::Object> function = accessor.GetObject();
+  v8::Handle<v8::Object> recv =
+      accessor.instance()->GetContext()->Global();
+  if (v8_method_name.As<v8::String>()->Length() != 0) {
+    function = function->Get(v8_method_name)->ToObject();
+    recv = accessor.GetObject();
+  }
+
+  if (try_catch.HasException())
+    return PP_MakeUndefined();
+
+  if (!function->IsFunction()) {
+    try_catch.SetException(kUnableToCallMethodException);
+    return PP_MakeUndefined();
+  }
+
+  scoped_ptr<v8::Handle<v8::Value>[] > converted_args(
+      new v8::Handle<v8::Value>[argc]);
+  for (uint32_t i = 0; i < argc; ++i) {
+    converted_args[i] = try_catch.ToV8(argv[i]);
+    if (try_catch.HasException())
       return PP_MakeUndefined();
-    }
-  } else {
-    accessor->SetException(kInvalidPropertyException);
+  }
+
+  blink::WebPluginContainer* container = accessor.instance()->container();
+  blink::WebLocalFrame* frame = NULL;
+  if (container)
+    frame = container->element().document().frame();
+
+  if (!frame) {
+    try_catch.SetException("No frame to execute script in.");
     return PP_MakeUndefined();
   }
 
-  scoped_ptr<NPVariant[]> args;
-  if (argc) {
-    args.reset(new NPVariant[argc]);
-    for (uint32_t i = 0; i < argc; ++i) {
-      if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
-        // This argument was invalid, throw an exception & give up.
-        accessor->SetException(kInvalidValueException);
-        return PP_MakeUndefined();
-      }
-    }
-  }
+  v8::Handle<v8::Value> result = frame->callFunctionEvenIfScriptDisabled(
+      function.As<v8::Function>(), recv, argc, converted_args.get());
+  ScopedPPVar result_var = try_catch.FromV8(result);
 
-  bool ok;
-
-  NPVariant result;
-  if (identifier) {
-    ok = WebBindings::invoke(NULL,
-                             accessor->object()->np_object(),
-                             identifier,
-                             args.get(),
-                             argc,
-                             &result);
-  } else {
-    ok = WebBindings::invokeDefault(
-        NULL, accessor->object()->np_object(), args.get(), argc, &result);
-  }
-
-  if (!ok) {
-    // An exception may have been raised.
-    accessor->SetException(kUnableToCallMethodException);
+  if (try_catch.HasException())
     return PP_MakeUndefined();
-  }
 
-  PP_Var ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result);
-  WebBindings::releaseVariantValue(&result);
-  return ret;
+  return result_var.Release();
 }
 
 PP_Var CallDeprecated(PP_Var var,
@@ -322,57 +267,39 @@
                       uint32_t argc,
                       PP_Var* argv,
                       PP_Var* exception) {
-  ObjectAccessorTryCatch accessor(var, exception);
-  if (accessor.has_exception())
-    return PP_MakeUndefined();
-  PepperPluginInstanceImpl* plugin = accessor.GetPluginInstance();
-  if (plugin && plugin->IsProcessingUserGesture()) {
-    blink::WebScopedUserGesture user_gesture(plugin->CurrentUserGestureToken());
-    return InternalCallDeprecated(
-        &accessor, method_name, argc, argv, exception);
+  ObjectAccessor accessor(var);
+  if (accessor.instance() && accessor.instance()->IsProcessingUserGesture()) {
+    blink::WebScopedUserGesture user_gesture(
+        accessor.instance()->CurrentUserGestureToken());
+    return CallDeprecatedInternal(var, method_name, argc, argv, exception);
   }
-  return InternalCallDeprecated(&accessor, method_name, argc, argv, exception);
+  return CallDeprecatedInternal(var, method_name, argc, argv, exception);
 }
 
 PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) {
-  ObjectAccessorTryCatch accessor(var, exception);
-  if (accessor.has_exception())
-    return PP_MakeUndefined();
-
-  scoped_ptr<NPVariant[]> args;
-  if (argc) {
-    args.reset(new NPVariant[argc]);
-    for (uint32_t i = 0; i < argc; ++i) {
-      if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
-        // This argument was invalid, throw an exception & give up.
-        accessor.SetException(kInvalidValueException);
-        return PP_MakeUndefined();
-      }
-    }
-  }
-
-  NPVariant result;
-  if (!WebBindings::construct(
-          NULL, accessor.object()->np_object(), args.get(), argc, &result)) {
-    // An exception may have been raised.
-    accessor.SetException(kUnableToConstructException);
-    return PP_MakeUndefined();
-  }
-
-  PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
-  WebBindings::releaseVariantValue(&result);
-  return ret;
+  // Deprecated.
+  NOTREACHED();
+  return PP_MakeUndefined();
 }
 
 bool IsInstanceOfDeprecated(PP_Var var,
                             const PPP_Class_Deprecated* ppp_class,
                             void** ppp_class_data) {
-  scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
+  scoped_refptr<V8ObjectVar> object(V8ObjectVar::FromPPVar(var));
   if (!object.get())
     return false;  // Not an object at all.
 
-  return PluginObject::IsInstanceOf(
-      object->np_object(), ppp_class, ppp_class_data);
+  v8::HandleScope handle_scope(object->instance()->GetIsolate());
+  v8::Context::Scope context_scope(object->instance()->GetContext());
+  PluginObject* plugin_object = PluginObject::FromV8Object(
+      object->instance()->GetIsolate(), object->GetHandle());
+  if (plugin_object && plugin_object->ppp_class() == ppp_class) {
+    if (ppp_class_data)
+      *ppp_class_data = plugin_object->ppp_class_data();
+    return true;
+  }
+
+  return false;
 }
 
 PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
diff --git a/content/renderer/pepper/v8_var_converter.cc b/content/renderer/pepper/v8_var_converter.cc
index 5fdd87f..f36f8cf5 100644
--- a/content/renderer/pepper/v8_var_converter.cc
+++ b/content/renderer/pepper/v8_var_converter.cc
@@ -83,7 +83,7 @@
 // value was created as a result of calling the function.
 bool GetOrCreateV8Value(v8::Handle<v8::Context> context,
                         const PP_Var& var,
-                        bool object_vars_allowed,
+                        V8VarConverter::AllowObjectVars object_vars_allowed,
                         v8::Handle<v8::Value>* result,
                         bool* did_create,
                         VarHandleMap* visited_ids,
@@ -155,7 +155,7 @@
       *result = v8::Object::New(isolate);
       break;
     case PP_VARTYPE_OBJECT: {
-      DCHECK(object_vars_allowed);
+      DCHECK(object_vars_allowed == V8VarConverter::kAllowObjectVars);
       scoped_refptr<V8ObjectVar> v8_object_var = V8ObjectVar::FromPPVar(var);
       if (!v8_object_var.get()) {
         NOTREACHED();
@@ -187,7 +187,7 @@
 bool GetOrCreateVar(v8::Handle<v8::Value> val,
                     v8::Handle<v8::Context> context,
                     PP_Instance instance,
-                    bool object_vars_allowed,
+                    V8VarConverter::AllowObjectVars object_vars_allowed,
                     PP_Var* result,
                     bool* did_create,
                     HandleVarMap* visited_handles,
@@ -234,7 +234,7 @@
       scoped_refptr<HostArrayBufferVar> buffer_var(
           new HostArrayBufferVar(*web_array_buffer));
       *result = buffer_var->GetPPVar();
-    } else if (object_vars_allowed) {
+    } else if (object_vars_allowed == V8VarConverter::kAllowObjectVars) {
       v8::Handle<v8::Object> object = val->ToObject();
       *result = content::HostGlobals::Get()->
           host_var_tracker()->V8ObjectVarForV8Object(instance, object);
@@ -271,13 +271,14 @@
 
 V8VarConverter::V8VarConverter(PP_Instance instance)
     : instance_(instance),
-      object_vars_allowed_(false),
+      object_vars_allowed_(kDisallowObjectVars),
       message_loop_proxy_(base::MessageLoopProxy::current()) {
   resource_converter_.reset(new ResourceConverterImpl(
       instance, RendererPpapiHost::GetForPPInstance(instance)));
 }
 
-V8VarConverter::V8VarConverter(PP_Instance instance, bool object_vars_allowed)
+V8VarConverter::V8VarConverter(PP_Instance instance,
+                               AllowObjectVars object_vars_allowed)
     : instance_(instance),
       object_vars_allowed_(object_vars_allowed),
       message_loop_proxy_(base::MessageLoopProxy::current()) {
@@ -288,7 +289,7 @@
 V8VarConverter::V8VarConverter(PP_Instance instance,
                                scoped_ptr<ResourceConverter> resource_converter)
     : instance_(instance),
-      object_vars_allowed_(false),
+      object_vars_allowed_(kDisallowObjectVars),
       message_loop_proxy_(base::MessageLoopProxy::current()),
       resource_converter_(resource_converter.release()) {}
 
diff --git a/content/renderer/pepper/v8_var_converter.h b/content/renderer/pepper/v8_var_converter.h
index e6206cd..77687e4 100644
--- a/content/renderer/pepper/v8_var_converter.h
+++ b/content/renderer/pepper/v8_var_converter.h
@@ -21,8 +21,14 @@
 
 class CONTENT_EXPORT V8VarConverter {
  public:
+  // Whether or not to allow converting object vars. If they are not allowed
+  // and they are passed in, conversion will fail.
+  enum AllowObjectVars {
+    kDisallowObjectVars,
+    kAllowObjectVars
+  };
   explicit V8VarConverter(PP_Instance instance);
-  V8VarConverter(PP_Instance instance, bool object_vars_allowed);
+  V8VarConverter(PP_Instance instance, AllowObjectVars object_vars_allowed);
 
   // Constructor for testing.
   V8VarConverter(PP_Instance instance,
@@ -76,7 +82,7 @@
   PP_Instance instance_;
 
   // Whether or not to support conversion to PP_VARTYPE_OBJECT.
-  bool object_vars_allowed_;
+  AllowObjectVars object_vars_allowed_;
 
   // The message loop to run the callback to |FromV8Value| from.
   scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
diff --git a/content/renderer/pepper/v8object_var.h b/content/renderer/pepper/v8object_var.h
index 79af9e3..e77901bc 100644
--- a/content/renderer/pepper/v8object_var.h
+++ b/content/renderer/pepper/v8object_var.h
@@ -28,7 +28,7 @@
 // PP_Var IDs) for each module. This allows us to track all references owned by
 // a given module and free them when the plugin exits independently of other
 // plugins that may be running at the same time.
-class V8ObjectVar : public Var {
+class CONTENT_EXPORT V8ObjectVar : public Var {
  public:
   V8ObjectVar(PP_Instance instance, v8::Handle<v8::Object> v8_object);
 
@@ -49,7 +49,7 @@
 
   // Helper function that converts a PP_Var to an object. This will return NULL
   // if the PP_Var is not of object type or the object is invalid.
-  CONTENT_EXPORT static scoped_refptr<V8ObjectVar> FromPPVar(PP_Var var);
+  static scoped_refptr<V8ObjectVar> FromPPVar(PP_Var var);
 
  private:
   virtual ~V8ObjectVar();