Backed out changeset 2acbf923b6a8 (bug 650161) for causing hazards
authorJon Coppeard <jcoppeard@mozilla.com>
Wed, 05 Nov 2014 10:57:33 +0000
changeset 214082 054bd325286d46da8596538afb8122c19aa9f157
parent 214081 c891f30c5a5f645a8ad8628697748e28a78dd8c7
child 214083 43a51201545a2f950d012c6561be42f06b275885
push id27771
push userryanvm@gmail.com
push dateWed, 05 Nov 2014 19:04:24 +0000
treeherdermozilla-central@305b4fecce99 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs650161
milestone36.0a1
backs out2acbf923b6a82bb6b038c6076bd210c2e52d5a00
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 2acbf923b6a8 (bug 650161) for causing hazards
dom/base/nsObjectLoadingContent.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/plugins/base/nsJSNPRuntime.h
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -3597,19 +3597,19 @@ nsObjectLoadingContent::TeardownProtoCha
   DebugOnly<bool> removed = false;
   while (obj) {
     if (!::JS_GetPrototype(cx, obj, &proto)) {
       return;
     }
     if (!proto) {
       break;
     }
-    // Unwrap while checking the class - if the prototype is a wrapper for
+    // Unwrap while checking the jsclass - if the prototype is a wrapper for
     // an NP object, that counts too.
-    if (nsNPObjWrapper::IsWrapper(js::UncheckedUnwrap(proto))) {
+    if (JS_GetClass(js::UncheckedUnwrap(proto)) == &sNPObjectJSWrapperClass) {
       // We found an NPObject on the proto chain, get its prototype...
       if (!::JS_GetPrototype(cx, proto, &proto)) {
         return;
       }
 
       MOZ_ASSERT(!removed, "more than one NPObject in prototype chain");
       removed = true;
 
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -49,24 +49,16 @@ struct JSObjWrapperHasher : public js::D
   }
 
   static void rekey(Key &k, const Key& newKey) {
     MOZ_ASSERT(k.mNpp == newKey.mNpp);
     k.mJSObj = newKey.mJSObj;
   }
 };
 
-class NPObjWrapperHashEntry : public PLDHashEntryHdr
-{
-public:
-  NPObject *mNPObj; // Must be the first member for the PLDHash stubs to work
-  JS::TenuredHeap<JSObject*> mJSObj;
-  NPP mNpp;
-};
-
 // Hash of JSObject wrappers that wraps JSObjects as NPObjects. There
 // will be one wrapper per JSObject per plugin instance, i.e. if two
 // plugins access the JSObject x, two wrappers for x will be
 // created. This is needed to be able to properly drop the wrappers
 // when a plugin is torn down in case there's a leak in the plugin (we
 // don't want to leak the world just because a plugin leaks an
 // NPObject).
 typedef js::HashMap<nsJSObjWrapperKey,
@@ -82,18 +74,19 @@ static bool sJSObjWrappersAccessible = f
 // Hash of NPObject wrappers that wrap NPObjects as JSObjects.
 static PLDHashTable sNPObjWrappers;
 
 // Global wrapper count. This includes JSObject wrappers *and*
 // NPObject wrappers. When this count goes to zero, there are no more
 // wrappers and we can kill off hash tables etc.
 static int32_t sWrapperCount;
 
-// The runtime service used to register/unregister GC callbacks.
-nsCOMPtr<nsIJSRuntimeService> sCallbackRuntime;
+// The JSRuntime. Used to unroot JSObjects when no JSContext is
+// reachable.
+static JSRuntime *sJSRuntime;
 
 static nsTArray<NPObject*>* sDelayedReleases;
 
 namespace {
 
 inline bool
 NPObjectIsOutOfProcessProxy(NPObject *obj)
 {
@@ -160,57 +153,44 @@ NPObjWrapper_newEnumerate(JSContext *cx,
 static bool
 NPObjWrapper_NewResolve(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                         JS::MutableHandle<JSObject*> objp);
 
 static bool
 NPObjWrapper_Convert(JSContext *cx, JS::Handle<JSObject*> obj, JSType type, JS::MutableHandle<JS::Value> vp);
 
 static void
-NPObjWrapper_Finalize(js::FreeOp *fop, JSObject *obj);
-
-static void
-NPObjWrapper_ObjectMoved(JSObject *obj, const JSObject *old);
+NPObjWrapper_Finalize(JSFreeOp *fop, JSObject *obj);
 
 static bool
 NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp);
 
 static bool
 NPObjWrapper_Construct(JSContext *cx, unsigned argc, JS::Value *vp);
 
 static bool
 CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj,
                      JS::Handle<jsid> id,  NPVariant* getPropertyResult,
                      JS::MutableHandle<JS::Value> vp);
 
-const static js::Class sNPObjectJSWrapperClass =
+const JSClass sNPObjectJSWrapperClass =
   {
     NPRUNTIME_JSCLASS_NAME,
     JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE,
     NPObjWrapper_AddProperty,
     NPObjWrapper_DelProperty,
     NPObjWrapper_GetProperty,
     NPObjWrapper_SetProperty,
     (JSEnumerateOp)NPObjWrapper_newEnumerate,
     (JSResolveOp)NPObjWrapper_NewResolve,
     NPObjWrapper_Convert,
     NPObjWrapper_Finalize,
     NPObjWrapper_Call,
     nullptr,                                                /* hasInstance */
-    NPObjWrapper_Construct,
-    nullptr,                                                /* trace */
-    JS_NULL_CLASS_SPEC,
-    {
-      nullptr,                                              /* outerObject */
-      nullptr,                                              /* innerObject */
-      nullptr,                                              /* iteratorObject */
-      false,                                                /* isWrappedNative */
-      nullptr,                                              /* weakmapKeyDelegateOp */
-      NPObjWrapper_ObjectMoved
-    }
+    NPObjWrapper_Construct
   };
 
 typedef struct NPObjectMemberPrivate {
     JS::Heap<JSObject *> npobjWrapper;
     JS::Heap<JS::Value> fieldValue;
     JS::Heap<jsid> methodName;
     NPP   npp;
 } NPObjectMemberPrivate;
@@ -236,38 +216,16 @@ static const JSClass sNPObjectMemberClas
     NPObjectMember_Finalize, NPObjectMember_Call,
     nullptr, nullptr, NPObjectMember_Trace
   };
 
 static void
 OnWrapperDestroyed();
 
 static void
-TraceJSObjWrappers(JSTracer *trc, void *data)
-{
-  if (!sJSObjWrappers.initialized()) {
-    return;
-  }
-
-  // Trace all JSObjects in the sJSObjWrappers table and rekey the entries if
-  // any of them moved.
-  for (JSObjWrapperTable::Enum e(sJSObjWrappers); !e.empty(); e.popFront()) {
-    nsJSObjWrapperKey key = e.front().key();
-    JS_CallUnbarrieredObjectTracer(trc, &key.mJSObj, "sJSObjWrappers key object");
-    nsJSObjWrapper *wrapper = e.front().value();
-    if (wrapper->mJSObj) {
-      JS_CallObjectTracer(trc, &wrapper->mJSObj, "sJSObjWrappers wrapper object");
-    }
-    if (key != e.front().key()) {
-      e.rekeyFront(key);
-    }
-  }
-}
-
-static void
 DelayedReleaseGCCallback(JSGCStatus status)
 {
   if (JSGC_END == status) {
     // Take ownership of sDelayedReleases and null it out now. The
     // _releaseobject call below can reenter GC and double-free these objects.
     nsAutoPtr<nsTArray<NPObject*> > delayedReleases(sDelayedReleases);
     sDelayedReleases = nullptr;
 
@@ -277,145 +235,61 @@ DelayedReleaseGCCallback(JSGCStatus stat
         if (obj)
           _releaseobject(obj);
         OnWrapperDestroyed();
       }
     }
   }
 }
 
-static bool
-RegisterGCCallbacks()
-{
-  if (sCallbackRuntime) {
-    return true;
-  }
-
-  static const char rtsvc_id[] = "@mozilla.org/js/xpc/RuntimeService;1";
-  nsCOMPtr<nsIJSRuntimeService> rtsvc(do_GetService(rtsvc_id));
-  if (!rtsvc) {
-    return false;
-  }
-
-  JSRuntime *jsRuntime = nullptr;
-  rtsvc->GetRuntime(&jsRuntime);
-  MOZ_ASSERT(jsRuntime != nullptr);
-
-  // Register a callback to trace wrapped JSObjects.
-  if (!JS_AddExtraGCRootsTracer(jsRuntime, TraceJSObjWrappers, nullptr)) {
-    return false;
-  }
-
-  // Register our GC callback to perform delayed destruction of finalized
-  // NPObjects.
-  rtsvc->RegisterGCCallback(DelayedReleaseGCCallback);
-
-  // Set runtime pointer to indicate that callbacks have been registered.
-  sCallbackRuntime = rtsvc;
-  return true;
-}
-
-static void
-UnregisterGCCallbacks()
-{
-  MOZ_ASSERT(sCallbackRuntime);
-
-  JSRuntime *jsRuntime = nullptr;
-  sCallbackRuntime->GetRuntime(&jsRuntime);
-  MOZ_ASSERT(jsRuntime != nullptr);
-
-  // Remove tracing callback.
-  JS_RemoveExtraGCRootsTracer(jsRuntime, TraceJSObjWrappers, nullptr);
-
-  // Remove delayed destruction callback.
-  sCallbackRuntime->UnregisterGCCallback(DelayedReleaseGCCallback);
-
-  // Unset runtime pointer to indicate callbacks are no longer registered.
-  sCallbackRuntime = nullptr;
-}
-
-static bool
-CreateJSObjWrapperTable()
-{
-  MOZ_ASSERT(!sJSObjWrappersAccessible);
-  MOZ_ASSERT(!sJSObjWrappers.initialized());
-
-  if (!RegisterGCCallbacks()) {
-    return false;
-  }
-
-  if (!sJSObjWrappers.init(16)) {
-    NS_ERROR("Error initializing PLDHashTable sJSObjWrappers!");
-    return false;
-  }
-
-  sJSObjWrappersAccessible = true;
-  return true;
-}
-
-static void
-DestroyJSObjWrapperTable()
-{
-  MOZ_ASSERT(sJSObjWrappersAccessible);
-  MOZ_ASSERT(sJSObjWrappers.initialized());
-  MOZ_ASSERT(sJSObjWrappers.count() == 0);
-
-  // No more wrappers, and our hash was initialized. Finish the
-  // hash to prevent leaking it.
-  sJSObjWrappers.finish();
-  sJSObjWrappersAccessible = false;
-}
-
-static bool
-CreateNPObjWrapperTable()
-{
-  MOZ_ASSERT(!sNPObjWrappers.ops);
-
-  if (!RegisterGCCallbacks()) {
-    return false;
-  }
-
-  PL_DHashTableInit(&sNPObjWrappers, PL_DHashGetStubOps(), nullptr,
-                    sizeof(NPObjWrapperHashEntry));
-  return true;
-}
-
-static void
-DestroyNPObjWrapperTable()
-{
-  MOZ_ASSERT(sNPObjWrappers.EntryCount() == 0);
-
-  PL_DHashTableFinish(&sNPObjWrappers);
-
-  sNPObjWrappers.ops = nullptr;
-}
-
 static void
 OnWrapperCreated()
 {
-  ++sWrapperCount;
+  if (sWrapperCount++ == 0) {
+    static const char rtsvc_id[] = "@mozilla.org/js/xpc/RuntimeService;1";
+    nsCOMPtr<nsIJSRuntimeService> rtsvc(do_GetService(rtsvc_id));
+    if (!rtsvc)
+      return;
+
+    rtsvc->GetRuntime(&sJSRuntime);
+    NS_ASSERTION(sJSRuntime != nullptr, "no JSRuntime?!");
+
+    // Register our GC callback to perform delayed destruction of finalized
+    // NPObjects. Leave this callback around and don't ever unregister it.
+    rtsvc->RegisterGCCallback(DelayedReleaseGCCallback);
+  }
 }
 
 static void
 OnWrapperDestroyed()
 {
   NS_ASSERTION(sWrapperCount, "Whaaa, unbalanced created/destroyed calls!");
 
   if (--sWrapperCount == 0) {
     if (sJSObjWrappersAccessible) {
-      DestroyJSObjWrapperTable();
+      MOZ_ASSERT(sJSObjWrappers.count() == 0);
+
+      // No more wrappers, and our hash was initialized. Finish the
+      // hash to prevent leaking it.
+      sJSObjWrappers.finish();
+      sJSObjWrappersAccessible = false;
     }
 
     if (sNPObjWrappers.ops) {
+      MOZ_ASSERT(sNPObjWrappers.EntryCount() == 0);
+
       // No more wrappers, and our hash was initialized. Finish the
       // hash to prevent leaking it.
-      DestroyNPObjWrapperTable();
+      PL_DHashTableFinish(&sNPObjWrappers);
+
+      sNPObjWrappers.ops = nullptr;
     }
 
-    UnregisterGCCallbacks();
+    // No more need for this.
+    sJSRuntime = nullptr;
   }
 }
 
 namespace mozilla {
 namespace plugins {
 namespace parent {
 
 static nsIGlobalObject*
@@ -628,27 +502,27 @@ ReportExceptionIfPending(JSContext *cx)
   }
 
   ThrowJSException(cx, nullptr);
 
   return false;
 }
 
 nsJSObjWrapper::nsJSObjWrapper(NPP npp)
-  : mJSObj(nullptr), mNpp(npp)
+  : mJSObj(GetJSContext(npp), nullptr), mNpp(npp)
 {
   MOZ_COUNT_CTOR(nsJSObjWrapper);
   OnWrapperCreated();
 }
 
 nsJSObjWrapper::~nsJSObjWrapper()
 {
   MOZ_COUNT_DTOR(nsJSObjWrapper);
 
-  // Invalidate first, since it relies on sJSObjWrappers.
+  // Invalidate first, since it relies on sJSRuntime and sJSObjWrappers.
   NP_Invalidate(this);
 
   OnWrapperDestroyed();
 }
 
 // static
 NPObject *
 nsJSObjWrapper::NP_Allocate(NPP npp, NPClass *aClass)
@@ -1103,17 +977,19 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
       return nullptr;
     }
   }
 
   // No need to enter the right compartment here as we only get the
   // class and private from the JSObject, neither of which cares about
   // compartments.
 
-  if (nsNPObjWrapper::IsWrapper(obj)) {
+  const JSClass *clazz = JS_GetClass(obj);
+
+  if (clazz == &sNPObjectJSWrapperClass) {
     // obj is one of our own, its private data is the NPObject we're
     // looking for.
 
     NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
 
     // If the private is null, that means that the object has already been torn
     // down, possible because the owning plugin was destroyed (there can be
     // multiple plugins, so the fact that it was destroyed does not prevent one
@@ -1124,18 +1000,22 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
       return nullptr;
 
     if (LookupNPP(npobj) == npp)
       return _retainobject(npobj);
   }
 
   if (!sJSObjWrappers.initialized()) {
     // No hash yet (or any more), initialize it.
-    if (!CreateJSObjWrapperTable())
+    if (!sJSObjWrappers.init(16)) {
+      NS_ERROR("Error initializing PLDHashTable!");
+
       return nullptr;
+    }
+    sJSObjWrappersAccessible = true;
   }
   MOZ_ASSERT(sJSObjWrappersAccessible);
 
   JSObjWrapperTable::Ptr p = sJSObjWrappers.lookupForAdd(nsJSObjWrapperKey(obj, npp));
   if (p) {
     MOZ_ASSERT(p->value());
     // Found a live nsJSObjWrapper, return it.
 
@@ -1147,20 +1027,20 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
   nsJSObjWrapper *wrapper =
     (nsJSObjWrapper *)_createobject(npp, &sJSObjWrapperNPClass);
 
   if (!wrapper) {
     // Out of memory, entry not yet added to table.
     return nullptr;
   }
 
+  // Assign mJSObj, rooting the JSObject. Its lifetime is now tied to that of
+  // the NPObject.
   wrapper->mJSObj = obj;
 
-  // Insert the new wrapper into the hashtable, rooting the JSObject. Its
-  // lifetime is now tied to that of the NPObject.
   nsJSObjWrapperKey key(obj, npp);
   if (!sJSObjWrappers.putNew(key, wrapper)) {
     // Out of memory, free the wrapper we created.
     _releaseobject(wrapper);
     return nullptr;
   }
 
   // Add postbarrier for the hashtable key
@@ -1175,17 +1055,17 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS
 // Because this function unwraps, its return value must be wrapped for the cx
 // compartment for callers that plan to hold onto the result or do anything
 // substantial with it.
 static JSObject *
 GetNPObjectWrapper(JSContext *cx, JSObject *aObj, bool wrapResult = true)
 {
   JS::Rooted<JSObject*> obj(cx, aObj);
   while (obj && (obj = js::CheckedUnwrap(obj))) {
-    if (nsNPObjWrapper::IsWrapper(obj)) {
+    if (JS_GetClass(obj) == &sNPObjectJSWrapperClass) {
       if (wrapResult && !JS_WrapObject(cx, &obj)) {
         return nullptr;
       }
       return obj;
     }
     if (!::JS_GetPrototype(cx, obj, &obj)) {
       return nullptr;
     }
@@ -1742,73 +1622,54 @@ NPObjWrapper_Convert(JSContext *cx, JS::
                        ? "primitive type"
                        : hint == JSTYPE_NUMBER
                        ? "number"
                        : "string");
   return false;
 }
 
 static void
-NPObjWrapper_Finalize(js::FreeOp *fop, JSObject *obj)
+NPObjWrapper_Finalize(JSFreeOp *fop, JSObject *obj)
 {
   NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
   if (npobj) {
     if (sNPObjWrappers.ops) {
       PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_REMOVE);
     }
   }
 
   if (!sDelayedReleases)
     sDelayedReleases = new nsTArray<NPObject*>;
   sDelayedReleases->AppendElement(npobj);
 }
 
-static void
-NPObjWrapper_ObjectMoved(JSObject *obj, const JSObject *old)
-{
-  // The wrapper JSObject has been moved, so we need to update the entry in the
-  // sNPObjWrappers hash table, if present.
-
-  if (!sNPObjWrappers.ops) {
-    return;
-  }
-
-  NPObject *npobj = (NPObject *)::JS_GetPrivate(obj);
-  if (!npobj) {
-    return;
-  }
-
-  NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
-    (PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_LOOKUP));
-  MOZ_ASSERT(PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mJSObj);
-  MOZ_ASSERT(entry->mJSObj == old);
-  entry->mJSObj = obj;
-}
-
 static bool
 NPObjWrapper_Call(JSContext *cx, unsigned argc, JS::Value *vp)
 {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   JS::Rooted<JSObject*> obj(cx, &args.callee());
   return CallNPMethodInternal(cx, obj, args.length(), args.array(), vp, false);
 }
 
 static bool
 NPObjWrapper_Construct(JSContext *cx, unsigned argc, JS::Value *vp)
 {
   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
   JS::Rooted<JSObject*> obj(cx, &args.callee());
   return CallNPMethodInternal(cx, obj, args.length(), args.array(), vp, true);
 }
 
-bool
-nsNPObjWrapper::IsWrapper(JSObject *obj)
+class NPObjWrapperHashEntry : public PLDHashEntryHdr
 {
-  return js::GetObjectClass(obj) == &sNPObjectJSWrapperClass;
-}
+public:
+  NPObject *mNPObj; // Must be the first member for the PLDHash stubs to work
+  JSObject *mJSObj;
+  NPP mNpp;
+};
+
 
 // An NPObject is going away, make sure we null out the JS object's
 // private data in case this is an NPObject that came from a plugin
 // and it's destroyed prematurely.
 
 // static
 void
 nsNPObjWrapper::OnDestroy(NPObject *npobj)
@@ -1870,19 +1731,18 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
   if (!npp) {
     NS_ERROR("No npp passed to nsNPObjWrapper::GetNewOrUsed()!");
 
     return nullptr;
   }
 
   if (!sNPObjWrappers.ops) {
     // No hash yet (or any more), initialize it.
-    if (!CreateNPObjWrapperTable()) {
-      return nullptr;
-    }
+    PL_DHashTableInit(&sNPObjWrappers, PL_DHashGetStubOps(), nullptr,
+                      sizeof(NPObjWrapperHashEntry));
   }
 
   NPObjWrapperHashEntry *entry = static_cast<NPObjWrapperHashEntry *>
     (PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_ADD));
 
   if (!entry) {
     // Out of memory
     JS_ReportOutOfMemory(cx);
@@ -1902,18 +1762,18 @@ nsNPObjWrapper::GetNewOrUsed(NPP npp, JS
 
   entry->mNPObj = npobj;
   entry->mNpp = npp;
 
   uint32_t generation = sNPObjWrappers.Generation();
 
   // No existing JSObject, create one.
 
-  JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, js::Jsvalify(&sNPObjectJSWrapperClass),
-                                               JS::NullPtr(), JS::NullPtr()));
+  JS::Rooted<JSObject*> obj(cx, ::JS_NewObject(cx, &sNPObjectJSWrapperClass, JS::NullPtr(),
+                                               JS::NullPtr()));
 
   if (generation != sNPObjWrappers.Generation()) {
       // Reload entry if the JS_NewObject call caused a GC and reallocated
       // the table (see bug 445229). This is guaranteed to succeed.
 
       entry = static_cast<NPObjWrapperHashEntry *>
         (PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_LOOKUP));
       NS_ASSERTION(entry && PL_DHASH_ENTRY_IS_BUSY(entry),
--- a/dom/plugins/base/nsJSNPRuntime.h
+++ b/dom/plugins/base/nsJSNPRuntime.h
@@ -31,20 +31,22 @@ public:
   bool operator!=(const nsJSObjWrapperKey& other) const {
     return !(*this == other);
   }
 
   JSObject * mJSObj;
   const NPP mNpp;
 };
 
+extern const JSClass sNPObjectJSWrapperClass;
+
 class nsJSObjWrapper : public NPObject
 {
 public:
-  JS::Heap<JSObject *> mJSObj;
+  JS::PersistentRooted<JSObject *> mJSObj;
   const NPP mNpp;
 
   static NPObject *GetNewOrUsed(NPP npp, JSContext *cx,
                                 JS::Handle<JSObject*> obj);
 
 protected:
   explicit nsJSObjWrapper(NPP npp);
   ~nsJSObjWrapper();
@@ -71,17 +73,16 @@ protected:
 
 public:
   static NPClass sJSObjWrapperNPClass;
 };
 
 class nsNPObjWrapper
 {
 public:
-  static bool IsWrapper(JSObject *obj);
   static void OnDestroy(NPObject *npobj);
   static JSObject *GetNewOrUsed(NPP npp, JSContext *cx, NPObject *npobj);
 };
 
 bool
 JSValToNPVariant(NPP npp, JSContext *cx, JS::Value val, NPVariant *variant);