Un-breaking the code due to failed test case with htmlunit

Review by: conroy@google.com

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10424 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/plugins/npapi/JavaObject.cpp b/plugins/npapi/JavaObject.cpp
index adbdbc8..16f7a09 100644
--- a/plugins/npapi/JavaObject.cpp
+++ b/plugins/npapi/JavaObject.cpp
@@ -18,7 +18,6 @@
 
 #include "JavaObject.h"
 #include "Plugin.h"
-#include "NPVariantUtil.h"
 #include "NPVariantWrapper.h"
 
 using std::string;
@@ -117,8 +116,8 @@
 }
 
 bool JavaObject::invokeDefault(const NPVariant *args, uint32_t argCount, NPVariant *result) {
-  if (argCount < 2 || !NPVariantUtil::isInt(args[0])
-      || (!NPVariantUtil::isNull(args[1]) && !NPVariantUtil::isObject(args[1]))) {
+  if (argCount < 2 || !NPVariantProxy::isInt(args[0])
+      || (!NPVariantProxy::isNull(args[1]) && !NPVariantProxy::isObject(args[1]))) {
     Debug::log(Debug::Error) << "incorrect arguments to invokeDefault" << Debug::flush;
     return false;
   }
@@ -133,10 +132,10 @@
     Debug::log(Debug::Debugging) << ", " << NPVariantProxy::toString(args[i]);
   }
   Debug::log(Debug::Debugging) << ")" << Debug::flush;
-  int dispId = NPVariantUtil::getAsInt(args[0]);
+  int dispId = NPVariantProxy::getAsInt(args[0]);
   int objId = objectId;
-  if (!NPVariantUtil::isNull(args[1])) {
-    NPObject* thisObj = NPVariantUtil::getAsObject(args[1]);
+  if (!NPVariantProxy::isNull(args[1])) {
+    NPObject* thisObj = NPVariantProxy::getAsObject(args[1]);
     if (isInstance(thisObj)) {
       JavaObject* thisJavaObj = static_cast<JavaObject*>(thisObj);
       objId = thisJavaObj->objectId;
diff --git a/plugins/npapi/LocalObjectTable.h b/plugins/npapi/LocalObjectTable.h
index 57a5887..acfbf2f 100644
--- a/plugins/npapi/LocalObjectTable.h
+++ b/plugins/npapi/LocalObjectTable.h
@@ -21,43 +21,24 @@
 #include "Debug.h"
 
 #include "mozincludes.h"
-#include "NPVariantUtil.h"
 
 class LocalObjectTable {
 private:
-  /* The host expects Value objects to have int's for JSO id's, hence the
-   * dual mapping.  ObjectMap is for host communication (Value.getJsObjectId)
-   * and the IdMap is for browser communication (NPObject to ID).
-   */
   typedef std::map<int, NPObject*> ObjectMap;
-  typedef std::map<NPObject*,int> IdMap;
-
-  NPP npp;
 
   int nextId;
   ObjectMap objects;
-  IdMap ids;
   bool dontFree;
 
-  bool jsIdentitySafe;
-
-  const NPIdentifier gwtId;
-
   void setFree(int id) {
-    NPObject *obj = getById(id);
-    if(!obj) {
+    if (objects.erase(id) != 1) {
       Debug::log(Debug::Error) << "setFree(id=" << id << "): object not in table"
         << Debug::flush;
-      return;
     }
-    ids.erase(obj);
-    objects.erase(id);
   }
 
 public:
-  LocalObjectTable(NPP npp, bool jsIdentitySafe):
-    nextId(0), dontFree(false), jsIdentitySafe(jsIdentitySafe),
-    gwtId(NPN_GetStringIdentifier("__gwt_ObjectId")) {
+  LocalObjectTable(): nextId(0), dontFree(false) {
   }
 
   virtual ~LocalObjectTable();
@@ -68,67 +49,29 @@
   int add(NPObject* obj) {
     int id = nextId++;
     set(id, obj);
-
-    if (!jsIdentitySafe) {
-      NPVariant idVariant;
-      Debug::log(Debug::Debugging) << "LocalObjectTable::set(): setting expando("
-          << id << ")" << Debug::flush;
-      INT32_TO_NPVARIANT(id,idVariant);
-      if (!NPN_SetProperty(npp, obj, gwtId, &idVariant)) {
-        Debug::log(Debug::Error) << "Setting GWT id on object failed" << Debug::flush;
-      }
-    }
-
     return id;
   }
 
   void set(int id, NPObject* obj) {
-    Debug::log(Debug::Debugging) << "LocalObjectTable::set(id=" << id << ",obj=" << (void*)obj
+    Debug::log(Debug::Spam) << "LocalObjectTable::set(id=" << id << ",obj=" << (void*)obj
         << ")" << Debug::flush;
-    if (!jsIdentitySafe) {
-      ObjectMap::iterator it;
-      it = objects.find(id);
-      if( it != objects.end() ) {
-        if (it->second != obj) {
-          //The JSO has changed and we need to update the map, releasing
-          //the old and remembering the new object.
-          ids.erase(it->second);
-          NPN_ReleaseObject(it->second);
-          NPN_RetainObject(obj);
-        } else {
-          //do nothing; object exists and is already mapped
-          return;
-        }
-      } else {
-        //New insertion, retain the object in the table
-        NPN_RetainObject(obj);
-      }
-    } else {
-      //Not dealing with identity hack, retain
-      NPN_RetainObject(obj);
-    }
     objects[id] = obj;
-    ids[obj] = id;
-
     // keep track that we hold a reference in the table
+    NPN_RetainObject(obj);
   }
 
   void free(int id) {
-    Debug::log(Debug::Debugging) << "LocalObjectTable::free(id=" << id << ")" << Debug::flush;
+    Debug::log(Debug::Spam) << "LocalObjectTable::free(id=" << id << ")" << Debug::flush;
     ObjectMap::iterator it = objects.find(id);
     if (it == objects.end()) {
       Debug::log(Debug::Error) << "Freeing freed object slot " << id << Debug::flush;
       return;
     }
-    if (!jsIdentitySafe) {
-      Debug::log(Debug::Debugging) << "removing expando!" << Debug::flush;
-      NPN_RemoveProperty(npp, it->second, gwtId);
-    }
-    setFree(id);
     if (!dontFree) {
       NPObject* obj = it->second;
       NPN_ReleaseObject(obj);
     }
+    setFree(id);
   }
 
   void freeAll() {
@@ -142,7 +85,7 @@
     objects.clear();
   }
 
-  NPObject* getById(int id) {
+  NPObject* get(int id) {
     ObjectMap::iterator it = objects.find(id);
     if (it == objects.end()) {
       Debug::log(Debug::Error) << "LocalObjectTable::get(id=" << id
@@ -151,30 +94,6 @@
     return it->second;
   }
 
-  int getObjectId(NPObject* jsObject) {
-    int id = -1;
-    if(!jsIdentitySafe) {
-      NPVariant idVariant;
-      VOID_TO_NPVARIANT(idVariant);
-      Debug::log(Debug::Debugging) << "LocalObjectTable::get(): expando test"
-          << Debug::flush;
-      if (NPN_GetProperty(npp, jsObject, gwtId, &idVariant) &&
-          NPVariantUtil::isInt(idVariant)) {
-        id = NPVariantUtil::getAsInt(idVariant);
-        Debug::log(Debug::Debugging) << "LocalObjectTable::get(): expando: "
-            << id << Debug::flush;
-        set(id, jsObject);
-      }
-      NPN_ReleaseVariantValue(&idVariant);
-    } else {
-      IdMap::iterator it = ids.find(jsObject);
-      if (it != ids.end()) {
-        id = it->second;
-      }
-    }
-    return id;
-  }
-
   void setDontFree(bool dontFree) {
     this->dontFree = dontFree;
   }
diff --git a/plugins/npapi/NPVariantUtil.h b/plugins/npapi/NPVariantUtil.h
deleted file mode 100644
index 2ca7ea5..0000000
--- a/plugins/npapi/NPVariantUtil.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef _H_NPVariantUtil
-#define _H_NPVariantUtil
-
-#include "Debug.h"
-#include "mozincludes.h"
-
-/**
- * Wraps an NPVariant and provides various helper functions
- */
-class NPVariantUtil {
-public:
-  static int isBoolean(const NPVariant& variant) {
-    return NPVARIANT_IS_BOOLEAN(variant);
-  }
-
-  static bool getAsBoolean(const NPVariant& variant) {
-    return NPVARIANT_TO_BOOLEAN(variant);
-  }
-
-  // Return true if the variant is holding a regular integer or an integral double.
-  static int isInt(const NPVariant& variant) {
-    if (NPVARIANT_IS_INT32(variant)) {
-      return 1;
-    } else if (NPVARIANT_IS_DOUBLE(variant)) {
-      // As of http://trac.webkit.org/changeset/72974 we get doubles for all
-      // numerical variants out of V8.
-      double d = NPVARIANT_TO_DOUBLE(variant);
-      int i = static_cast<int>(d);
-      // Verify that d is an integral value in range.
-      return (d == static_cast<double>(i));
-    } else {
-      return 0;
-    }
-  }
-
-  static int getAsInt(const NPVariant& variant) {
-    if (isInt(variant)) {
-      if (NPVARIANT_IS_INT32(variant)) {
-        return NPVARIANT_TO_INT32(variant);
-      } else if (NPVARIANT_IS_DOUBLE(variant)) {
-        return static_cast<int>(NPVARIANT_TO_DOUBLE(variant));
-      }
-    }
-
-    Debug::log(Debug::Error) << "getAsInt: variant " <<
-      NPVariantUtil::toString(variant) << "not int" << Debug::flush;
-    return 0;
-  }
-
-  static int isNull(const NPVariant& variant) {
-    return NPVARIANT_IS_NULL(variant);
-  }
-
-  static int isObject(const NPVariant& variant) {
-    return NPVARIANT_IS_OBJECT(variant);
-  }
-
-  static NPObject* getAsObject(const NPVariant& variant) {
-    if (NPVARIANT_IS_OBJECT(variant)) {
-      return NPVARIANT_TO_OBJECT(variant);
-    }
-    Debug::log(Debug::Error) << "getAsObject: variant not object" << Debug::flush;
-    return 0;
-  }
-
-  static int isString(const NPVariant& variant) {
-    return NPVARIANT_IS_STRING(variant);
-  }
-
-  static const NPString* getAsNPString(const NPVariant& variant) {
-    if (NPVARIANT_IS_STRING(variant)) {
-      return &NPVARIANT_TO_STRING(variant);
-    }
-    Debug::log(Debug::Error) << "getAsNPString: variant not string" << Debug::flush;
-    return 0;
-  }
-
-  static std::string toString(const NPVariant& variant) {
-    std::string retval;
-    // TODO(jat): remove sprintfs
-    char buf[40];
-    NPObject* npObj;
-    switch (variant.type) {
-      case NPVariantType_Void:
-        retval = "undef";
-        break;
-      case NPVariantType_Null:
-        retval = "null";
-        break;
-      case NPVariantType_Bool:
-        retval = "bool(";
-        retval += (NPVARIANT_TO_BOOLEAN(variant) ? "true" : "false");
-        retval += ')';
-        break;
-      case NPVariantType_Int32:
-        retval = "int(";
-        snprintf(buf, sizeof(buf), "%d)", NPVARIANT_TO_INT32(variant));
-        retval += buf;
-        break;
-      case NPVariantType_Double:
-        retval = "double(";
-        snprintf(buf, sizeof(buf), "%g)", NPVARIANT_TO_DOUBLE(variant));
-        retval += buf;
-        break;
-      case NPVariantType_String:
-        {
-          retval = "string(";
-          NPString str = NPVARIANT_TO_STRING(variant);
-          retval += std::string(str.UTF8Characters, str.UTF8Length);
-          retval += ')';
-        }
-        break;
-      case NPVariantType_Object:
-        npObj = NPVARIANT_TO_OBJECT(variant);
-        snprintf(buf, sizeof(buf), "obj(class=%p, ", npObj->_class);
-        retval = buf;
-        snprintf(buf, sizeof(buf), "count=%d, ", npObj->referenceCount);
-        retval += buf;
-        snprintf(buf, sizeof(buf), "%p)", npObj);
-        retval += buf;
-        break;
-      default:
-        snprintf(buf, sizeof(buf), "Unknown type %d", variant.type);
-        retval = buf;
-        break;
-    }
-    return retval;
-  }
-
-};
-
-#endif
diff --git a/plugins/npapi/NPVariantWrapper.h b/plugins/npapi/NPVariantWrapper.h
index a1844c5..6d7689d 100644
--- a/plugins/npapi/NPVariantWrapper.h
+++ b/plugins/npapi/NPVariantWrapper.h
@@ -15,7 +15,6 @@
 #include "Platform.h"
 
 #include "mozincludes.h"
-#include "NPVariantUtil.h"
 
 #include "Value.h"
 #include "LocalObjectTable.h"
@@ -63,39 +62,105 @@
   }
 
   int isBoolean() const {
-    return NPVariantUtil::isBoolean(variant);
+    return isBoolean(variant);
+  }
+
+  static int isBoolean(const NPVariant& variant) {
+    return NPVARIANT_IS_BOOLEAN(variant);
   }
 
   bool getAsBoolean() const {
-    return NPVariantUtil::getAsBoolean(variant);
+    return getAsBoolean(variant);
+  }
+
+  static bool getAsBoolean(const NPVariant& variant) {
+    return NPVARIANT_TO_BOOLEAN(variant);
   }
 
   int isInt() const {
-    return NPVariantUtil::isInt(variant);
+    return isInt(variant);
   }
   
+  // Return true if the variant is holding a regular integer or an integral double.
+  static int isInt(const NPVariant& variant) {
+    if (NPVARIANT_IS_INT32(variant)) {
+      return 1;
+    } else if (NPVARIANT_IS_DOUBLE(variant)) {
+      // As of http://trac.webkit.org/changeset/72974 we get doubles for all
+      // numerical variants out of V8.
+      double d = NPVARIANT_TO_DOUBLE(variant);
+      int i = static_cast<int>(d);
+      // Verify that d is an integral value in range.
+      return (d == static_cast<double>(i));
+    } else {
+      return 0;
+    }
+  }
+
   int getAsInt() const {
-    return NPVariantUtil::getAsInt(variant);
+    return getAsInt(variant);
+  }
+
+  static int getAsInt(const NPVariant& variant) {
+    if (isInt(variant)) {
+      if (NPVARIANT_IS_INT32(variant)) {
+        return NPVARIANT_TO_INT32(variant);
+      } else if (NPVARIANT_IS_DOUBLE(variant)) {
+        return static_cast<int>(NPVARIANT_TO_DOUBLE(variant));
+      }
+    }
+
+    Debug::log(Debug::Error) << "getAsInt: variant " <<
+      NPVariantProxy::toString(variant) << "not int" << Debug::flush;
+    return 0;
   }
 
   int isNull() const {
-    return NPVariantUtil::isNull(variant);
+    return isNull(variant);
   }
   
+  static int isNull(const NPVariant& variant) {
+    return NPVARIANT_IS_NULL(variant);
+  }
+
   int isObject() const {
-    return NPVariantUtil::isObject(variant);
+    return isObject(variant);
   }
   
+  static int isObject(const NPVariant& variant) {
+    return NPVARIANT_IS_OBJECT(variant);
+  }
+
   NPObject* getAsObject() const {
-    return NPVariantUtil::getAsObject(variant);
+    return getAsObject(variant);
+  }
+
+  static NPObject* getAsObject(const NPVariant& variant) {
+    if (NPVARIANT_IS_OBJECT(variant)) {
+      return NPVARIANT_TO_OBJECT(variant);
+    }
+    Debug::log(Debug::Error) << "getAsObject: variant not object" << Debug::flush;
+    return 0;
   }
 
   int isString() const {
-    return NPVariantUtil::isString(variant);
+    return isString(variant);
   }
   
+  static int isString(const NPVariant& variant) {
+    return NPVARIANT_IS_STRING(variant);
+  }
+
   const NPString* getAsNPString() const {
-    return NPVariantUtil::getAsNPString(variant);
+    return getAsNPString(variant);
+  }
+
+  static const NPString* getAsNPString(const NPVariant& variant) {
+    if (NPVARIANT_IS_STRING(variant)) {
+      return &NPVARIANT_TO_STRING(variant);
+    }
+    Debug::log(Debug::Error) << "getAsNPString: variant not string" << Debug::flush;
+    return 0;
   }
 
   Value getAsValue(ScriptableInstance& scriptInstance, bool unwrapJava = true) const {
@@ -400,35 +465,35 @@
   }
   
   bool isBoolean() const {
-    return NPVariantUtil::isBoolean(variant);
+    return NPVariantProxy::isBoolean(variant);
   }
 
   int isInt() const {
-    return NPVariantUtil::isInt(variant);
+    return NPVariantProxy::isInt(variant);
   }
   
   int isObject() const {
-    return NPVariantUtil::isObject(variant);
+    return NPVariantProxy::isObject(variant);
   }
   
   int isString() const {
-    return NPVariantUtil::isString(variant);
+    return NPVariantProxy::isString(variant);
   }
   
   bool getAsBoolean() const {
-    return NPVariantUtil::getAsBoolean(variant);
+    return NPVariantProxy::getAsBoolean(variant);
   }
 
   int getAsInt() const {
-    return NPVariantUtil::getAsInt(variant);
+    return NPVariantProxy::getAsInt(variant);
   }
 
   NPObject* getAsObject() const {
-    return NPVariantUtil::getAsObject(variant);
+    return NPVariantProxy::getAsObject(variant);
   }
 
   const NPString* getAsNPString() const {
-    return NPVariantUtil::getAsNPString(variant);
+    return NPVariantProxy::getAsNPString(variant);
   }
 
   Value getAsValue(ScriptableInstance& scriptInstance, bool unwrapJava = true) const {
diff --git a/plugins/npapi/ScriptableInstance.cpp b/plugins/npapi/ScriptableInstance.cpp
index bc79d17..4344a5b 100644
--- a/plugins/npapi/ScriptableInstance.cpp
+++ b/plugins/npapi/ScriptableInstance.cpp
@@ -33,8 +33,6 @@
 const static string INCLUDE_STR = "include";
 const static string EXCLUDE_STR = "exclude";
 
-bool ScriptableInstance::jsIdentitySafe = false;
-
 static inline string convertToString(const NPString& str) {
   return string(GetNPStringUTF8Characters(str), GetNPStringUTF8Length(str));
 }
@@ -60,7 +58,7 @@
 ScriptableInstance::ScriptableInstance(NPP npp) : NPObjectWrapper<ScriptableInstance>(npp),
     plugin(*reinterpret_cast<Plugin*>(npp->pdata)),
     _channel(new HostChannel()),
-    localObjects(npp,ScriptableInstance::jsIdentitySafe),
+    localObjects(),
     _connectId(NPN_GetStringIdentifier("connect")),
     initID(NPN_GetStringIdentifier("init")),
     toStringID(NPN_GetStringIdentifier("toString")),
@@ -70,9 +68,9 @@
     urlID(NPN_GetStringIdentifier("url")),
     includeID(NPN_GetStringIdentifier("include")),
     getHostPermissionID(NPN_GetStringIdentifier("getHostPermission")),
-    testJsIdentityID(NPN_GetStringIdentifier("testJsIdentity")),
     connectedID(NPN_GetStringIdentifier("connected")),
     statsID(NPN_GetStringIdentifier("stats")),
+    gwtId(NPN_GetStringIdentifier("__gwt_ObjectId")),
     jsDisconnectedID(NPN_GetStringIdentifier("__gwt_disconnected")),
     jsInvokeID(NPN_GetStringIdentifier("__gwt_jsInvoke")),
     jsResultID(NPN_GetStringIdentifier("__gwt_makeResult")),
@@ -84,7 +82,6 @@
   if (NPN_GetValue(npp, NPNVWindowNPObject, &window) != NPERR_NO_ERROR) {
     Debug::log(Debug::Error) << "Error getting window object" << Debug::flush;
   }
-
 }
 
 ScriptableInstance::~ScriptableInstance() {
@@ -118,7 +115,7 @@
 bool ScriptableInstance::tryGetStringPrimitive(NPObject* obj, NPVariant& result) {
   if (NPN_HasMethod(getNPP(), obj, jsValueOfID)) {
     if (NPN_Invoke(getNPP(), obj, jsValueOfID, 0, 0, &result)
-        && NPVariantUtil::isString(result)) {
+        && NPVariantProxy::isString(result)) {
       return true;
     }
     NPVariantProxy::release(result);
@@ -191,8 +188,7 @@
       name == initID ||
       name == toStringID ||
       name == loadHostEntriesID ||
-      name == getHostPermissionID ||
-      name == testJsIdentityID ) {
+      name == getHostPermissionID) {
     return true;
   }
   return false;
@@ -218,8 +214,6 @@
     loadHostEntries(args, argCount, result);
   } else if (name == getHostPermissionID) {
     getHostPermission(args, argCount, result);
-  } else if (name == testJsIdentityID) {
-    testJsIdentity(args, argCount, result);
   }
   return true;
 }
@@ -248,7 +242,7 @@
 //=============================================================================
 
 void ScriptableInstance::init(const NPVariant* args, unsigned argCount, NPVariant* result) {
-  if (argCount != 1 || !NPVariantUtil::isObject(args[0])) {
+  if (argCount != 1 || !NPVariantProxy::isObject(args[0])) {
     // TODO: better failure?
     Debug::log(Debug::Error) << "ScriptableInstance::init called with incorrect arguments:\n";
     for (unsigned i = 0; i < argCount; ++i) {
@@ -262,7 +256,7 @@
     NPN_ReleaseObject(window);
   }
   // replace our window object with that passed by the caller
-  window = NPVariantUtil::getAsObject(args[0]);
+  window = NPVariantProxy::getAsObject(args[0]);
   NPN_RetainObject(window);
   BOOLEAN_TO_NPVARIANT(true, *result);
   result->type = NPVariantType_Bool;
@@ -277,7 +271,7 @@
   //window.location.href
   NPN_GetProperty(getNPP(), locationVariant.getAsObject(), hrefID, hrefVariant.addressForReturn());
 
-  const NPString* locationHref = NPVariantUtil::getAsNPString(hrefVariant);
+  const NPString* locationHref = NPVariantProxy::getAsNPString(hrefVariant);
   return convertToString(*locationHref);
 }
 
@@ -288,7 +282,7 @@
     AllowedConnections::clearRules();
     for (unsigned i = 0; i < argCount; ++i) {
       //Get the host entry object {url: "somehost.net", include: true/false}
-      NPObject* hostEntry = NPVariantUtil::getAsObject(args[i]);
+      NPObject* hostEntry = NPVariantProxy::getAsObject(args[i]);
       if (!hostEntry) {
         Debug::log(Debug::Error) << "Got a host entry that is not an object.\n";
         break;
@@ -328,7 +322,7 @@
 }
 
 void ScriptableInstance::getHostPermission(const NPVariant* args, unsigned argCount, NPVariant* result) {
-  if (argCount != 1 || !NPVariantUtil::isString(args[0])) {
+  if (argCount != 1 || !NPVariantProxy::isString(args[0])) {
     Debug::log(Debug::Error) << "ScriptableInstance::getHostPermission called with incorrect arguments.\n";
   }
 
@@ -353,34 +347,12 @@
   NPVariantProxy(*this, *result) = retStr;
 }
 
-void ScriptableInstance::testJsIdentity(const NPVariant* args, unsigned argCount, NPVariant* result) {
-  if (argCount != 2 || !NPVariantUtil::isObject(args[0]) ||
-      !NPVariantUtil::isObject(args[1]) ) {
-    Debug::log(Debug::Error) << "ScriptableInstance::testJsIdentity called"
-        << " with incorrect arguments.\n";
-  }
-  NPObject* obj1 = NPVariantUtil::getAsObject(args[0]);
-  NPObject* obj2 = NPVariantUtil::getAsObject(args[1]);
-  Debug::log(Debug::Info) << "obj1:" << obj1 << " obj2:" << obj2
-      << Debug::flush;
-  if( obj1 == obj2 ) {
-    Debug::log(Debug::Info) << "Idenity check passed; not using expando!"
-        << Debug::flush;
-    ScriptableInstance::jsIdentitySafe = true;
-  } else {
-    Debug::log(Debug::Info) << "Idenity check failed; using expando"
-        << Debug::flush;
-    ScriptableInstance::jsIdentitySafe = false;
-  }
-}
-
-
 void ScriptableInstance::connect(const NPVariant* args, unsigned argCount, NPVariant* result) {
-  if (argCount != 5 || !NPVariantUtil::isString(args[0])
-      || !NPVariantUtil::isString(args[1])
-      || !NPVariantUtil::isString(args[2])
-      || !NPVariantUtil::isString(args[3])
-      || !NPVariantUtil::isString(args[4])) {
+  if (argCount != 5 || !NPVariantProxy::isString(args[0])
+      || !NPVariantProxy::isString(args[1])
+      || !NPVariantProxy::isString(args[2])
+      || !NPVariantProxy::isString(args[3])
+      || !NPVariantProxy::isString(args[4])) {
     // TODO: better failure?
     Debug::log(Debug::Error) << "ScriptableInstance::connect called with incorrect arguments:\n";
     for (unsigned i = 0; i < argCount; ++i) {
@@ -460,9 +432,18 @@
 }
 
 int ScriptableInstance::getLocalObjectRef(NPObject* obj) {
-  int id = localObjects.getObjectId(obj);
-  if(id == -1) {
+  NPVariantWrapper wrappedRetVal(*this);
+  int id;
+  if (NPN_GetProperty(getNPP(), obj, gwtId, wrappedRetVal.addressForReturn())
+      && wrappedRetVal.isInt()) {
+    id = wrappedRetVal.getAsInt();
+    localObjects.set(id, obj);
+  } else {
     id = localObjects.add(obj);
+    wrappedRetVal = id;
+    if (!NPN_SetProperty(getNPP(), obj, gwtId, wrappedRetVal.address())) {
+      Debug::log(Debug::Error) << "Setting GWT id on object failed" << Debug::flush;
+    }
   }
   return id;
 }
@@ -483,8 +464,13 @@
 void ScriptableInstance::freeValue(HostChannel& channel, int idCount, const int* const ids) {
   Debug::log(Debug::Debugging) << "freeValue(#ids=" << idCount << ")" << Debug::flush;
   for (int i = 0; i < idCount; ++i) {
-    Debug::log(Debug::Spam) << " id=" << ids[i] << Debug::flush;
-    localObjects.free(ids[i]);
+	  Debug::log(Debug::Spam) << " id=" << ids[i] << Debug::flush;
+    NPObject* obj = localObjects.get(ids[i]);
+    if (!NPN_RemoveProperty(getNPP(), obj, gwtId)) {
+      Debug::log(Debug::Error) << "Unable to remove GWT ID from object " << ids[i] << Debug::flush;
+    } else {
+      localObjects.free(ids[i]);
+    }
   }
 }
 
@@ -508,7 +494,7 @@
     return Value();
   }
   int id = args[0].getInt();
-  NPObject* obj = localObjects.getById(id);
+  NPObject* obj = localObjects.get(id);
   NPIdentifier propID;
   if (args[1].isString()) {
     string propName = args[1].getString();
@@ -537,7 +523,7 @@
     return Value();
   }
   int id = args[0].getInt();
-  NPObject* obj = localObjects.getById(id);
+  NPObject* obj = localObjects.get(id);
   NPIdentifier propID;
   if (args[1].isString()) {
     string propName = args[1].getString();
@@ -691,7 +677,7 @@
   Value propertyValue = ServerMethods::getProperty(*_channel, this, objectId, dispId);
   if (propertyValue.isJsObject()) {
     // TODO(jat): special-case for testing
-    NPObject* npObj = localObjects.getById(propertyValue.getJsObjectId());
+    NPObject* npObj = localObjects.get(propertyValue.getJsObjectId());
     OBJECT_TO_NPVARIANT(npObj, *result);
     NPN_RetainObject(npObj);
   } else {
@@ -699,12 +685,12 @@
   }
   Debug::log(Debug::Debugging) << " return val=" << propertyValue
       << ", NPVariant=" << *result << Debug::flush;
-  if (NPVariantUtil::isObject(*result)) {
-    dumpObjectBytes(NPVariantUtil::getAsObject(*result));
+  if (NPVariantProxy::isObject(*result)) {
+    dumpObjectBytes(NPVariantProxy::getAsObject(*result));
   }
-  if (NPVariantUtil::isObject(*result)) {
+  if (NPVariantProxy::isObject(*result)) {
     Debug::log(Debug::Debugging) << "  final return refcount = "
-        << NPVariantUtil::getAsObject(*result)->referenceCount << Debug::flush;
+        << NPVariantProxy::getAsObject(*result)->referenceCount << Debug::flush; 
   }
   return true;
 }
@@ -713,17 +699,17 @@
     const NPVariant* npValue) {
   Debug::log(Debug::Debugging) << "JavaObject_setProperty(objectid="
       << objectId << ", dispId=" << dispId << ", value=" << *npValue << ")" << Debug::flush;
-  if (NPVariantUtil::isObject(*npValue)) {
+  if (NPVariantProxy::isObject(*npValue)) {
     Debug::log(Debug::Debugging) << "  before localObj: refcount = "
-        << NPVariantUtil::getAsObject(*npValue)->referenceCount << Debug::flush;
+        << NPVariantProxy::getAsObject(*npValue)->referenceCount << Debug::flush; 
   }
   Value value = NPVariantProxy::getAsValue(*npValue, *this, true);
-  if (NPVariantUtil::isObject(*npValue)) {
+  if (NPVariantProxy::isObject(*npValue)) {
     Debug::log(Debug::Debugging) << "  after localObj: refcount = "
-        << NPVariantUtil::getAsObject(*npValue)->referenceCount << Debug::flush;
+        << NPVariantProxy::getAsObject(*npValue)->referenceCount << Debug::flush; 
   }
-  if (NPVariantUtil::isObject(*npValue)) {
-    dumpObjectBytes(NPVariantUtil::getAsObject(*npValue));
+  if (NPVariantProxy::isObject(*npValue)) {
+    dumpObjectBytes(NPVariantProxy::getAsObject(*npValue));
   }
   Debug::log(Debug::Debugging) << "  as value: " << value << Debug::flush;
   // TODO: no way to set an actual exception object! (Could ClassCastException on server.)
diff --git a/plugins/npapi/ScriptableInstance.h b/plugins/npapi/ScriptableInstance.h
index 1bea653..a24e085 100644
--- a/plugins/npapi/ScriptableInstance.h
+++ b/plugins/npapi/ScriptableInstance.h
@@ -64,8 +64,7 @@
   void dumpJSresult(const char* js);
   
   int getLocalObjectRef(NPObject* obj);
-
-  NPObject* getLocalObject(int refid) { return localObjects.getById(refid); }
+  NPObject* getLocalObject(int refid) { return localObjects.get(refid); }
   
   bool tryGetStringPrimitive(NPObject* obj, NPVariant& result);
 
@@ -88,7 +87,6 @@
   HostChannel* _channel;
   LocalObjectTable localObjects;
 
-  static bool jsIdentitySafe;
   int savedValueIdx;
 
   // Identifiers
@@ -102,10 +100,10 @@
   const NPIdentifier urlID;
   const NPIdentifier includeID;
   const NPIdentifier getHostPermissionID;
-  const NPIdentifier testJsIdentityID;
   
   const NPIdentifier connectedID;
   const NPIdentifier statsID;
+  const NPIdentifier gwtId;
 
   const NPIdentifier jsDisconnectedID;
   const NPIdentifier jsInvokeID;
@@ -135,7 +133,7 @@
   void init(const NPVariant* args, unsigned argCount, NPVariant* result);
   void loadHostEntries(const NPVariant* args, unsigned argCount, NPVariant* result);
   void getHostPermission(const NPVariant* args, unsigned argCount, NPVariant* result);
-  void testJsIdentity(const NPVariant* args, unsigned argCount, NPVariant* result);
+  
   Value clientMethod_getProperty(HostChannel& channel, int numArgs, const Value* const args);
   Value clientMethod_setProperty(HostChannel& channel, int numArgs, const Value* const args);
   
diff --git a/plugins/npapi/prebuilt/gwt-dev-plugin/background.html b/plugins/npapi/prebuilt/gwt-dev-plugin/background.html
index 73f674d..fe60956 100644
--- a/plugins/npapi/prebuilt/gwt-dev-plugin/background.html
+++ b/plugins/npapi/prebuilt/gwt-dev-plugin/background.html
@@ -65,9 +65,6 @@
     var icon = null;
     console.log("got permission " + permission + " for host " + host + '/ code ' + code);
 
-    var idObject = {};
-    plugin.testJsIdentity( idObject, idObject );
-
     if (permission == 'include') {
       icon = enabledIcon;
     } else if (permission == 'exclude') {
diff --git a/user/test/com/google/gwt/core/CoreSuite.java b/user/test/com/google/gwt/core/CoreSuite.java
index 4be1c9e..0e7b5d6 100644
--- a/user/test/com/google/gwt/core/CoreSuite.java
+++ b/user/test/com/google/gwt/core/CoreSuite.java
@@ -20,7 +20,6 @@
 import com.google.gwt.core.client.JavaScriptExceptionTest;
 import com.google.gwt.core.client.JsArrayMixedTest;
 import com.google.gwt.core.client.JsArrayTest;
-import com.google.gwt.core.client.JsIdentityTest;
 import com.google.gwt.core.client.SchedulerTest;
 import com.google.gwt.core.client.ScriptInjectorTest;
 import com.google.gwt.core.client.impl.AsyncFragmentLoaderTest;
@@ -44,7 +43,6 @@
     suite.addTestSuite(GWTTest.class);
     suite.addTestSuite(HttpThrowableReporterTest.class);
     suite.addTestSuite(JavaScriptExceptionTest.class);
-    suite.addTestSuite(JsIdentityTest.class);
     suite.addTestSuite(JsArrayTest.class);
     suite.addTestSuite(JsArrayMixedTest.class);
     suite.addTestSuite(SchedulerImplTest.class);
diff --git a/user/test/com/google/gwt/core/client/JsIdentityTest.java b/user/test/com/google/gwt/core/client/JsIdentityTest.java
deleted file mode 100644
index b45cb01..0000000
--- a/user/test/com/google/gwt/core/client/JsIdentityTest.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright 2011 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.gwt.core.client;
-
-import com.google.gwt.junit.client.GWTTestCase;
-
-/**
- * Test Js Identity.
- */
-public class JsIdentityTest extends GWTTestCase {
-  /*
-   * (non-Javadoc)
-   * 
-   * @see com.google.gwt.junit.client.GWTTestCase#getModuleName()
-   */
-  @Override
-  public String getModuleName() {
-    return "com.google.gwt.core.Core";
-  }
-
-  /**
-   * Store some JavaObjects in a JsArrayOf, then ask Javascript to run find
-   * elements via indexOf().
-   */
-  public void testJsIdentity() {
-    JsArrayOf<Object> elements = JsArrayOf.create();
-    Object id1 = new Object();
-    Object id2 = new Object();
-    Object id3 = new Object();
-    Object id4 = new Object();
-
-    elements.push(id1);
-    elements.push(id2);
-    elements.push(id3);
-    // id4 not pushed for failure test.
-
-    assertEquals(true, elements.contains(id1)); // pass (0)
-    assertEquals(true, elements.contains(id2)); // pass (1)
-    assertEquals(true, elements.contains(id3)); // pass (2)
-    assertEquals(false, elements.contains(id4)); // pass (-1)
-  }
-
-  /**
-   * Test that the same  Java object passed twice is in fact the same in JS. 
-   */
-  public void testJavaToJs() {
-    Object Foo = new Object();
-    assertTrue(jsID(Foo,Foo));
-  }
-  
-  /**
-   * Store a JavaObject in Javascript, then pass the object back to JS to test
-   * for identity.
-   */
-  public void testJavaObjectStorage() {
-    Object Foo = new Object();
-    set(Foo);
-    assertTrue(isSet(Foo));
-    assertTrue(isStrictlySet(Foo));
-  }
-
-  /**
-   * Store a JavaScriptObject in Javascript, then fetch the JSO twice to test
-   * for identity (multiple NPObject requests).
-   */
-  public void testJsoJavaComparison() {
-    storeJsoIdentity();
-    JavaScriptObject obj1 = getJsoIdentity();
-    JavaScriptObject obj2 = getJsoIdentity();
-    assertSame(obj1,obj2);
-  }
-
-  /**
-   * Store a JavaObject in JavascriptArray and store it in an array, then try to
-   * fetch it back. Specific test for old plugin problem.
-   */
-  public void testJavaArrayArray() {
-    Object id1 = new Object();
-    Object id2 = new Object();
-    JsArray<JsoTestArray<Object>> elements = JavaScriptObject.createArray().cast();
-
-    elements.push(JsoTestArray.create(id1));
-    elements.push(JsoTestArray.create(id2));
-
-    Object get1 = elements.get(0).getT();
-    Object get2 = elements.get(1).getT();
-
-    assertEquals(2, elements.length());
-    assertSame(id1,get1);
-    assertSame(id2,get2);
-  }
-
-  static final class JsoTestArray<T> extends JavaScriptObject {
-    public static native <T> JsoTestArray<T> create(T cmd) /*-{
-      return [cmd, false];
-    }-*/;
-
-    protected JsoTestArray() {
-    }
-
-    /**
-     * Has implicit cast.
-     */
-    public native T getT() /*-{
-      return this[0];
-    }-*/;
-
-    public native boolean isRepeating() /*-{
-      return this[1];
-    }-*/;
-  }
-
-  static native void set(Object obj) /*-{
-    $wnd.__idTest_JavaObj = obj;
-  }-*/;
-
-  static native boolean isSet(Object obj) /*-{
-    return $wnd.__idTest_JavaObj == obj;
-  }-*/;
-
-  static native boolean isStrictlySet(Object obj) /*-{
-    return $wnd.__idTest_JavaObj === obj;
-  }-*/;
-
-  static native void storeJsoIdentity() /*-{
-    var idObject = {
-        something : 'another',
-        another : 1234
-    };
-    $wnd.__idTest_Jso = idObject;
-  }-*/;
-
-  static native JavaScriptObject getJsoIdentity() /*-{
-    return $wnd.__idTest_Jso;
-  }-*/;
-
-  static native boolean jsID(Object a, Object b) /*-{
-    return a === b;
-  }-*/;
-}
-
-/**
- * JavaScript native implementation for arrays.
- */
-final class JsArrayOf<T> extends JavaScriptObject {
-
-  /**
-   * Create a new empty Array instance.
-   */
-  public static <T> JsArrayOf<T> create() {
-    return JavaScriptObject.createArray().cast();
-  }
-
-  protected JsArrayOf() {
-  }
-
-  public boolean contains(T value) {
-    return indexOf(value) != -1;
-  }
-
-  public native T get(int index) /*-{
-    return this[index];
-  }-*/;
-
-  public native int indexOf(T value) /*-{
-    return this.indexOf(value);
-  }-*/;
-
-  public native int length() /*-{
-    return this.length;
-  }-*/;
-
-  /**
-   * Pushes the given value onto the end of the array.
-   */
-  public native void push(T value) /*-{
-    this[this.length] = value;
-  }-*/;
-
-  public native void set(int index, T value) /*-{
-    this[index] = value;
-  }-*/;
-}