Change NPAPI not to cast to from NPIdentifier and jsval. Fix silly JSObject::resizeDenseArrayElements bug introduced by earlier commit
authorLuke Wagner <lw@mozilla.com>
Fri, 11 Jun 2010 18:09:58 -0700
changeset 52862 a84dcaa853760ab1af981e04f0cfac3c05914284
parent 52861 8bb6fc99933e9bcdb6f78d81eeba6e69736ff951
child 52863 f56150fe1756ae280ca5ee76a8abc07553a43cbb
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone1.9.3a5pre
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
Change NPAPI not to cast to from NPIdentifier and jsval. Fix silly JSObject::resizeDenseArrayElements bug introduced by earlier commit
js/src/jsarray.cpp
modules/plugin/base/src/nsJSNPRuntime.cpp
modules/plugin/base/src/nsNPAPIPlugin.cpp
modules/plugin/base/src/nsNPAPIPlugin.h
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -349,17 +349,17 @@ JSObject::resizeDenseArrayElements(JSCon
     if (!newslots)
         return false;
 
     dslots = newslots + 1;
     setDenseArrayCapacity(newcap);
 
     if (initializeAllSlots) {
         Value *base = addressOfDenseArrayElement(0);
-        for (Value *vp = base + oldcap, *end = base + newcap; vp != end; ++vp)
+        for (Value *vp = base + oldcap, *end = base + newcap; vp < end; ++vp)
             vp->setMagic(JS_ARRAY_HOLE);
     }
 
     return true;
 }
 
 bool
 JSObject::ensureDenseArrayElements(JSContext *cx, uint32 newcap, bool initializeAllSlots)
--- a/modules/plugin/base/src/nsJSNPRuntime.cpp
+++ b/modules/plugin/base/src/nsJSNPRuntime.cpp
@@ -192,17 +192,17 @@ static JSClass sNPObjectJSWrapperClass =
     (JSResolveOp)NPObjWrapper_NewResolve, NPObjWrapper_Convert,
     NPObjWrapper_Finalize, nsnull, nsnull, NPObjWrapper_Call,
     NPObjWrapper_Construct, nsnull, nsnull
   };
 
 typedef struct NPObjectMemberPrivate {
     JSObject *npobjWrapper;
     jsval fieldValue;
-    jsval methodName;
+    NPIdentifier methodName;
     NPP   npp;
 } NPObjectMemberPrivate;
 
 static JSBool
 NPObjectMember_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
 
 static void
 NPObjectMember_Finalize(JSContext *cx, JSObject *obj);
@@ -593,35 +593,33 @@ nsJSObjWrapper::NP_Invalidate(NPObject *
     }
 
     // Forget our reference to the JSObject.
     jsnpobj->mJSObj = nsnull;
   }
 }
 
 static JSBool
-GetProperty(JSContext *cx, JSObject *obj, NPIdentifier identifier, jsval *rval)
+GetProperty(JSContext *cx, JSObject *obj, NPIdentifier id, jsval *rval)
 {
-  jsval id = (jsval)identifier;
-
-  if (JSVAL_IS_STRING(id)) {
-    JSString *str = JSVAL_TO_STRING(id);
+  if (NPIdentifierIsString(id)) {
+    JSString *str = NPIdentifierToString(id);
 
     return ::JS_GetUCProperty(cx, obj, ::JS_GetStringChars(str),
                               ::JS_GetStringLength(str), rval);
   }
 
-  NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
-
-  return ::JS_GetElement(cx, obj, JSVAL_TO_INT(id), rval);
+  NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n");
+
+  return ::JS_GetElement(cx, obj, NPIdentifierToInt(id), rval);
 }
 
 // static
 bool
-nsJSObjWrapper::NP_HasMethod(NPObject *npobj, NPIdentifier identifier)
+nsJSObjWrapper::NP_HasMethod(NPObject *npobj, NPIdentifier id)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
 
   if (!cx) {
     return PR_FALSE;
   }
 
@@ -634,17 +632,17 @@ nsJSObjWrapper::NP_HasMethod(NPObject *n
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
 
   jsval v;
-  JSBool ok = GetProperty(cx, npjsobj->mJSObj, identifier, &v);
+  JSBool ok = GetProperty(cx, npjsobj->mJSObj, id, &v);
 
   return ok && !JSVAL_IS_PRIMITIVE(v) &&
     ::JS_ObjectIsFunction(cx, JSVAL_TO_OBJECT(v));
 }
 
 static bool
 doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args,
          uint32_t argCount, PRBool ctorCall, NPVariant *result)
@@ -667,17 +665,17 @@ doInvoke(NPObject *npobj, NPIdentifier m
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
   jsval fv;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
 
-  if ((jsval)method != JSVAL_VOID) {
+  if (method != NPIdentifier_VOID) {
     if (!GetProperty(cx, npjsobj->mJSObj, method, &fv) ||
         ::JS_TypeOfValue(cx, fv) != JSTYPE_FUNCTION) {
       return PR_FALSE;
     }
   } else {
     fv = OBJECT_TO_JSVAL(npjsobj->mJSObj);
   }
 
@@ -737,75 +735,74 @@ doInvoke(NPObject *npobj, NPIdentifier m
 }
 
 // static
 bool
 nsJSObjWrapper::NP_Invoke(NPObject *npobj, NPIdentifier method,
                           const NPVariant *args, uint32_t argCount,
                           NPVariant *result)
 {
-  if ((jsval)method == JSVAL_VOID) {
+  if (method == NPIdentifier_VOID) {
     return PR_FALSE;
   }
 
   return doInvoke(npobj, method, args, argCount, PR_FALSE, result);
 }
 
 // static
 bool
 nsJSObjWrapper::NP_InvokeDefault(NPObject *npobj, const NPVariant *args,
                                  uint32_t argCount, NPVariant *result)
 {
-  return doInvoke(npobj, (NPIdentifier)JSVAL_VOID, args, argCount, PR_FALSE,
+  return doInvoke(npobj, NPIdentifier_VOID, args, argCount, PR_FALSE,
                   result);
 }
 
 // static
 bool
-nsJSObjWrapper::NP_HasProperty(NPObject *npobj, NPIdentifier identifier)
+nsJSObjWrapper::NP_HasProperty(NPObject *npobj, NPIdentifier id)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
 
   if (!cx) {
     return PR_FALSE;
   }
 
   if (!npobj) {
     ThrowJSException(cx,
                      "Null npobj in nsJSObjWrapper::NP_HasProperty!");
 
     return PR_FALSE;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
-  jsval id = (jsval)identifier;
   JSBool found, ok = JS_FALSE;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
 
-  if (JSVAL_IS_STRING(id)) {
-    JSString *str = JSVAL_TO_STRING(id);
+  if (NPIdentifierIsString(id)) {
+    JSString *str = NPIdentifierToString(id);
 
     ok = ::JS_HasUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
                             ::JS_GetStringLength(str), &found);
   } else {
-    NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
-
-    ok = ::JS_HasElement(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &found);
+    NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n");
+
+    ok = ::JS_HasElement(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &found);
   }
 
   return ok && found;
 }
 
 // static
 bool
-nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier identifier,
+nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier id,
                                NPVariant *result)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
 
   if (!cx) {
     return PR_FALSE;
   }
@@ -819,23 +816,23 @@ nsJSObjWrapper::NP_GetProperty(NPObject 
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
 
   jsval v;
-  return (GetProperty(cx, npjsobj->mJSObj, identifier, &v) &&
+  return (GetProperty(cx, npjsobj->mJSObj, id, &v) &&
           JSValToNPVariant(npp, cx, v, result));
 }
 
 // static
 bool
-nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier,
+nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier id,
                                const NPVariant *value)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
 
   if (!cx) {
     return PR_FALSE;
   }
@@ -843,71 +840,69 @@ nsJSObjWrapper::NP_SetProperty(NPObject 
   if (!npobj) {
     ThrowJSException(cx,
                      "Null npobj in nsJSObjWrapper::NP_SetProperty!");
 
     return PR_FALSE;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
-  jsval id = (jsval)identifier;
   JSBool ok = JS_FALSE;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
 
   jsval v = NPVariantToJSVal(npp, cx, value);
   js::AutoValueRooter tvr(cx, js::Valueify(v));
 
-  if (JSVAL_IS_STRING(id)) {
-    JSString *str = JSVAL_TO_STRING(id);
+  if (NPIdentifierIsString(id)) {
+    JSString *str = NPIdentifierToString(id);
 
     ok = ::JS_SetUCProperty(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
                             ::JS_GetStringLength(str), &v);
   } else {
-    NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
-
-    ok = ::JS_SetElement(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &v);
+    NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n");
+
+    ok = ::JS_SetElement(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &v);
   }
 
   // return ok == JS_TRUE to quiet down compiler warning, even if
   // return ok is what we really want.
   return ok == JS_TRUE;
 }
 
 // static
 bool
-nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier identifier)
+nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier id)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
 
   if (!cx) {
     return PR_FALSE;
   }
 
   if (!npobj) {
     ThrowJSException(cx,
                      "Null npobj in nsJSObjWrapper::NP_RemoveProperty!");
 
     return PR_FALSE;
   }
 
   nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj;
-  jsval id = (jsval)identifier;
   JSBool ok = JS_FALSE;
 
   AutoCXPusher pusher(cx);
   JSAutoRequest ar(cx);
   AutoJSExceptionReporter reporter(cx);
   jsval deleted = JSVAL_FALSE;
 
-  if (JSVAL_IS_STRING(id)) {
-    JSString *str = JSVAL_TO_STRING(id);
+  if (NPIdentifierIsString(id)) {
+    JSString *str = NPIdentifierToString(id);
 
     ok = ::JS_DeleteUCProperty2(cx, npjsobj->mJSObj, ::JS_GetStringChars(str),
                                 ::JS_GetStringLength(str), &deleted);
 
     if (ok && deleted) {
       // FIXME: See bug 425823, we shouldn't need to do this, and once
       // that bug is fixed we can remove this code.
 
@@ -918,26 +913,26 @@ nsJSObjWrapper::NP_RemoveProperty(NPObje
       if (ok && hasProp) {
         // The property might have been deleted, but it got
         // re-resolved, so no, it's not really deleted.
 
         deleted = JSVAL_FALSE;
       }
     }
   } else {
-    NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n");
-
-    ok = ::JS_DeleteElement2(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &deleted);
+    NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n");
+
+    ok = ::JS_DeleteElement2(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &deleted);
 
     if (ok && deleted) {
       // FIXME: See bug 425823, we shouldn't need to do this, and once
       // that bug is fixed we can remove this code.
 
       JSBool hasProp;
-      ok = ::JS_HasElement(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &hasProp);
+      ok = ::JS_HasElement(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &hasProp);
 
       if (ok && hasProp) {
         // The property might have been deleted, but it got
         // re-resolved, so no, it's not really deleted.
 
         deleted = JSVAL_FALSE;
       }
     }
@@ -945,23 +940,23 @@ nsJSObjWrapper::NP_RemoveProperty(NPObje
 
   // return ok == JS_TRUE to quiet down compiler warning, even if
   // return ok is what we really want.
   return ok == JS_TRUE && deleted == JSVAL_TRUE;
 }
 
 //static
 bool
-nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **identifier,
+nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **idarray,
                              uint32_t *count)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
 
-  *identifier = 0;
+  *idarray = 0;
   *count = 0;
 
   if (!cx) {
     return PR_FALSE;
   }
 
   if (!npobj) {
     ThrowJSException(cx,
@@ -977,63 +972,65 @@ nsJSObjWrapper::NP_Enumerate(NPObject *n
   AutoJSExceptionReporter reporter(cx);
 
   JSIdArray *ida = ::JS_Enumerate(cx, npjsobj->mJSObj);
   if (!ida) {
     return PR_FALSE;
   }
 
   *count = ida->length;
-  *identifier = (NPIdentifier *)PR_Malloc(*count * sizeof(NPIdentifier));
-  if (!*identifier) {
+  *idarray = (NPIdentifier *)PR_Malloc(*count * sizeof(NPIdentifier));
+  if (!*idarray) {
     ThrowJSException(cx, "Memory allocation failed for NPIdentifier!");
 
     ::JS_DestroyIdArray(cx, ida);
 
     return PR_FALSE;
   }
 
   for (PRUint32 i = 0; i < *count; i++) {
     jsval v;
     if (!::JS_IdToValue(cx, ida->vector[i], &v)) {
       ::JS_DestroyIdArray(cx, ida);
-      PR_Free(*identifier);
+      PR_Free(*idarray);
       return PR_FALSE;
     }
 
+    NPIdentifier id;
     if (JSVAL_IS_STRING(v)) {
       JSString *str = JSVAL_TO_STRING(v);
 
       if (!JS_InternUCStringN(cx, ::JS_GetStringChars(str),
                               ::JS_GetStringLength(str))) {
         ::JS_DestroyIdArray(cx, ida);
-        PR_Free(*identifier);
+        PR_Free(*idarray);
 
         return PR_FALSE;
       }
+      id = StringToNPIdentifier(str);
     } else {
       NS_ASSERTION(JSVAL_IS_INT(v),
                    "The element in ida must be either string or int!\n");
+      id = IntToNPIdentifier(JSVAL_TO_INT(v));
     }
 
-    (*identifier)[i] = (NPIdentifier)v;
+    (*idarray)[i] = id;
   }
 
   ::JS_DestroyIdArray(cx, ida);
 
   return PR_TRUE;
 }
 
 //static
 bool
 nsJSObjWrapper::NP_Construct(NPObject *npobj, const NPVariant *args,
                              uint32_t argCount, NPVariant *result)
 {
-  return doInvoke(npobj, (NPIdentifier)JSVAL_VOID, args, argCount, PR_TRUE,
-                  result);
+  return doInvoke(npobj, NPIdentifier_VOID, args, argCount, PR_TRUE, result);
 }
 
 
 class JSObjWrapperHashEntry : public PLDHashEntryHdr
 {
 public:
   nsJSObjWrapper *mJSObjWrapper;
 };
@@ -1200,26 +1197,27 @@ NPObjWrapper_AddProperty(JSContext *cx, 
   }
 
   if (NPObjectIsOutOfProcessProxy(npobj)) {
     return JS_TRUE;
   }
 
   PluginDestructionGuard pdg(LookupNPP(npobj));
 
-  JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
+  NPIdentifier identifier = JSValToNPIdentifier(id);
+  JSBool hasProperty = npobj->_class->hasProperty(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   if (hasProperty)
     return JS_TRUE;
 
   // We must permit methods here since JS_DefineUCFunction() will add
   // the function as a property
-  JSBool hasMethod = npobj->_class->hasMethod(npobj, (NPIdentifier)id);
+  JSBool hasMethod = npobj->_class->hasMethod(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   if (!hasMethod) {
     ThrowJSException(cx, "Trying to add unsupported property on NPObject!");
 
     return JS_FALSE;
   }
@@ -1236,26 +1234,28 @@ NPObjWrapper_DelProperty(JSContext *cx, 
       !npobj->_class->removeProperty) {
     ThrowJSException(cx, "Bad NPObject as private data!");
 
     return JS_FALSE;
   }
 
   PluginDestructionGuard pdg(LookupNPP(npobj));
 
+  NPIdentifier identifier = JSValToNPIdentifier(id);
+
   if (!NPObjectIsOutOfProcessProxy(npobj)) {
-    JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
+    JSBool hasProperty = npobj->_class->hasProperty(npobj, identifier);
     if (!ReportExceptionIfPending(cx))
       return JS_FALSE;
 
     if (!hasProperty)
       return JS_TRUE;
   }
 
-  if (!npobj->_class->removeProperty(npobj, (NPIdentifier)id))
+  if (!npobj->_class->removeProperty(npobj, identifier))
     *vp = JSVAL_FALSE;
 
   return ReportExceptionIfPending(cx);
 }
 
 static JSBool
 NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
 {
@@ -1275,18 +1275,20 @@ NPObjWrapper_SetProperty(JSContext *cx, 
   if (!npp) {
     ThrowJSException(cx, "No NPP found for NPObject!");
 
     return JS_FALSE;
   }
 
   PluginDestructionGuard pdg(npp);
 
+  NPIdentifier identifier = JSValToNPIdentifier(id);
+
   if (!NPObjectIsOutOfProcessProxy(npobj)) {
-    JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
+    JSBool hasProperty = npobj->_class->hasProperty(npobj, identifier);
     if (!ReportExceptionIfPending(cx))
       return JS_FALSE;
 
     if (!hasProperty) {
       ThrowJSException(cx, "Trying to set unsupported property on NPObject!");
 
       return JS_FALSE;
     }
@@ -1294,17 +1296,17 @@ NPObjWrapper_SetProperty(JSContext *cx, 
 
   NPVariant npv;
   if (!JSValToNPVariant(npp, cx, *vp, &npv)) {
     ThrowJSException(cx, "Error converting jsval to NPVariant!");
 
     return JS_FALSE;
   }
 
-  JSBool ok = npobj->_class->setProperty(npobj, (NPIdentifier)id, &npv);
+  JSBool ok = npobj->_class->setProperty(npobj, identifier, &npv);
   _releasevariantvalue(&npv); // Release the variant
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   if (!ok) {
     ThrowJSException(cx, "Error setting property on NPObject!");
 
     return JS_FALSE;
@@ -1336,26 +1338,28 @@ NPObjWrapper_GetProperty(JSContext *cx, 
 
   PluginDestructionGuard pdg(npp);
 
   PRBool hasProperty, hasMethod;
 
   NPVariant npv;
   VOID_TO_NPVARIANT(npv);
 
+  NPIdentifier identifier = JSValToNPIdentifier(id);
+
 #ifdef MOZ_IPC
   if (NPObjectIsOutOfProcessProxy(npobj)) {
     PluginScriptableObjectParent* actor =
       static_cast<ParentNPObject*>(npobj)->parent;
 
     // actor may be null if the plugin crashed.
     if (!actor)
       return JS_FALSE;
 
-    JSBool success = actor->GetPropertyHelper((NPIdentifier)id, &hasProperty,
+    JSBool success = actor->GetPropertyHelper(identifier, &hasProperty,
                                               &hasMethod, &npv);
     if (!ReportExceptionIfPending(cx)) {
       if (success)
         _releasevariantvalue(&npv);
       return JS_FALSE;
     }
 
     if (success) {
@@ -1370,30 +1374,30 @@ NPObjWrapper_GetProperty(JSContext *cx, 
         if (!ReportExceptionIfPending(cx))
           return JS_FALSE;
       }
     }
     return JS_TRUE;
   }
 #endif
 
-  hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
+  hasProperty = npobj->_class->hasProperty(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
-  hasMethod = npobj->_class->hasMethod(npobj, (NPIdentifier)id);
+  hasMethod = npobj->_class->hasMethod(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   // We return NPObject Member class here to support ambiguous members.
   if (hasProperty && hasMethod)
     return CreateNPObjectMember(npp, cx, obj, npobj, id, nsnull, vp);
 
   if (hasProperty) {
-    if (npobj->_class->getProperty(npobj, (NPIdentifier)id, &npv))
+    if (npobj->_class->getProperty(npobj, identifier, &npv))
       *vp = NPVariantToJSVal(npp, cx, &npv);
 
     _releasevariantvalue(&npv);
 
     if (!ReportExceptionIfPending(cx))
       return JS_FALSE;
   }
 
@@ -1483,20 +1487,20 @@ CallNPMethodInternal(JSContext *cx, JSOb
       msg = "Attempt to construct object from class with no constructor.";
     }
   } else if (funobj != obj) {
     // A obj.function() style call is made, get the method name from
     // the function object.
 
     if (npobj->_class->invoke) {
       JSFunction *fun = (JSFunction *)::JS_GetPrivate(cx, funobj);
-      jsval method = STRING_TO_JSVAL(::JS_GetFunctionId(fun));
-
-      ok = npobj->_class->invoke(npobj, (NPIdentifier)method, npargs, argc,
-                                 &v);
+      JSString *name = ::JS_GetFunctionId(fun);
+      NPIdentifier id = StringToNPIdentifier(name);
+
+      ok = npobj->_class->invoke(npobj, id, npargs, argc, &v);
     } else {
       ok = JS_FALSE;
 
       msg = "Attempt to call a method on object with no invoke method.";
     }
   } else {
     if (npobj->_class->invokeDefault) {
       // obj is a callable object that is being called, no method name
@@ -1605,17 +1609,18 @@ NPObjWrapper_newEnumerate(JSContext *cx,
 
     break;
 
   case JSENUMERATE_NEXT:
     state = (NPObjectEnumerateState *)JSVAL_TO_PRIVATE(*statep);
     enum_value = state->value;
     length = state->length;
     if (state->index != length) {
-      return ::JS_ValueToId(cx, (jsval)enum_value[state->index++], idp);
+      jsval val = NPIdentifierToJSVal(enum_value[state->index++]);
+      return ::JS_ValueToId(cx, val, idp);
     }
 
     // FALL THROUGH
 
   case JSENUMERATE_DESTROY:
     state = (NPObjectEnumerateState *)JSVAL_TO_PRIVATE(*statep);
     if (state->value)
       PR_Free(state->value);
@@ -1638,17 +1643,19 @@ NPObjWrapper_NewResolve(JSContext *cx, J
       !npobj->_class->hasMethod) {
     ThrowJSException(cx, "Bad NPObject as private data!");
 
     return JS_FALSE;
   }
 
   PluginDestructionGuard pdg(LookupNPP(npobj));
 
-  PRBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id);
+  NPIdentifier identifier = JSValToNPIdentifier(id);
+
+  PRBool hasProperty = npobj->_class->hasProperty(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   if (hasProperty) {
     JSBool ok;
 
     if (JSVAL_IS_STRING(id)) {
       JSString *str = JSVAL_TO_STRING(id);
@@ -1665,17 +1672,17 @@ NPObjWrapper_NewResolve(JSContext *cx, J
       return JS_FALSE;
     }
 
     *objp = obj;
 
     return JS_TRUE;
   }
 
-  PRBool hasMethod = npobj->_class->hasMethod(npobj, (NPIdentifier)id);
+  PRBool hasMethod = npobj->_class->hasMethod(npobj, identifier);
   if (!ReportExceptionIfPending(cx))
     return JS_FALSE;
 
   if (hasMethod) {
     JSString *str = nsnull;
 
     if (JSVAL_IS_STRING(id)) {
       str = JSVAL_TO_STRING(id);
@@ -2136,29 +2143,31 @@ CreateNPObjectMember(NPP npp, JSContext 
     return JS_FALSE;
   }
 
   *vp = OBJECT_TO_JSVAL(memobj);
   ::JS_AddValueRoot(cx, vp);
 
   ::JS_SetPrivate(cx, memobj, (void *)memberPrivate);
 
+  NPIdentifier identifier = JSValToNPIdentifier(id);
+
   jsval fieldValue;
   NPVariant npv;
   NPBool hasProperty;
 
   if (getPropertyResult) {
     // Plugin has already handed us the value we want here.
     npv = *getPropertyResult;
     hasProperty = true;
   }
   else {
     VOID_TO_NPVARIANT(npv);
 
-    NPBool hasProperty = npobj->_class->getProperty(npobj, (NPIdentifier)id,
+    NPBool hasProperty = npobj->_class->getProperty(npobj, identifier,
                                                     &npv);
     if (!ReportExceptionIfPending(cx)) {
       ::JS_RemoveValueRoot(cx, vp);
       return JS_FALSE;
     }
 
     if (!hasProperty) {
       ::JS_RemoveValueRoot(cx, vp);
@@ -2173,17 +2182,17 @@ CreateNPObjectMember(NPP npp, JSContext 
   // real JSObject wrapper for the NPObject.
   while (JS_GET_CLASS(cx, obj) != &sNPObjectJSWrapperClass) {
     obj = ::JS_GetPrototype(cx, obj);
   }
 
   memberPrivate->npobjWrapper = obj;
 
   memberPrivate->fieldValue = fieldValue;
-  memberPrivate->methodName = id;
+  memberPrivate->methodName = identifier;
   memberPrivate->npp = npp;
 
   ::JS_RemoveValueRoot(cx, vp);
 
   return JS_TRUE;
 }
 
 static JSBool
@@ -2272,19 +2281,20 @@ NPObjectMember_Call(JSContext *cx, JSObj
       if (npargs != npargs_buf) {
         PR_Free(npargs);
       }
 
       return JS_FALSE;
     }
   }
 
+
   NPVariant npv;
   JSBool ok;
-  ok = npobj->_class->invoke(npobj, (NPIdentifier)memberPrivate->methodName,
+  ok = npobj->_class->invoke(npobj, memberPrivate->methodName,
                              npargs, argc, &npv);
 
   // Release arguments.
   for (i = 0; i < argc; ++i) {
     _releasevariantvalue(npargs + i);
   }
 
   if (npargs != npargs_buf) {
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -685,17 +685,17 @@ doGetIdentifier(JSContext *cx, const NPU
   NS_ConvertUTF8toUTF16 utf16name(name);
 
   JSString *str = ::JS_InternUCStringN(cx, (jschar *)utf16name.get(),
                                        utf16name.Length());
 
   if (!str)
     return NULL;
 
-  return (NPIdentifier)STRING_TO_JSVAL(str);
+  return StringToNPIdentifier(str);
 }
 
 #if defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_WINCE)
 BOOL
 InHeap(HANDLE hHeap, LPVOID lpMem)
 {
   BOOL success = FALSE;
   PROCESS_HEAP_ENTRY he;
@@ -1348,65 +1348,61 @@ void NP_CALLBACK
 }
 
 NPIdentifier NP_CALLBACK
 _getintidentifier(int32_t intid)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getstringidentifier called from the wrong thread\n"));
   }
-  return (NPIdentifier)INT_TO_JSVAL(intid);
+  return IntToNPIdentifier(intid);
 }
 
 NPUTF8* NP_CALLBACK
-_utf8fromidentifier(NPIdentifier identifier)
+_utf8fromidentifier(NPIdentifier id)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_utf8fromidentifier called from the wrong thread\n"));
   }
-  if (!identifier)
+  if (!id)
     return NULL;
 
-  jsval v = (jsval)identifier;
-
-  if (!JSVAL_IS_STRING(v)) {
+  if (!NPIdentifierIsString(id)) {
     return nsnull;
   }
 
-  JSString *str = JSVAL_TO_STRING(v);
+  JSString *str = NPIdentifierToString(id);
 
   return
     ToNewUTF8String(nsDependentString((PRUnichar *)::JS_GetStringChars(str),
                                       ::JS_GetStringLength(str)));
 }
 
 int32_t NP_CALLBACK
-_intfromidentifier(NPIdentifier identifier)
+_intfromidentifier(NPIdentifier id)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_intfromidentifier called from the wrong thread\n"));
   }
-  jsval v = (jsval)identifier;
-
-  if (!JSVAL_IS_INT(v)) {
+
+  if (!NPIdentifierIsInt(id)) {
     return PR_INT32_MIN;
   }
 
-  return JSVAL_TO_INT(v);
+  return NPIdentifierToInt(id);
 }
 
 bool NP_CALLBACK
-_identifierisstring(NPIdentifier identifier)
+_identifierisstring(NPIdentifier id)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_identifierisstring called from the wrong thread\n"));
   }
-  jsval v = (jsval)identifier;
-
-  return JSVAL_IS_STRING(v);
+
+  return NPIdentifierIsString(id);
 }
 
 NPObject* NP_CALLBACK
 _createobject(NPP npp, NPClass* aClass)
 {
   if (!NS_IsMainThread()) {
     NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_createobject called from the wrong thread\n"));
     return nsnull;
--- a/modules/plugin/base/src/nsNPAPIPlugin.h
+++ b/modules/plugin/base/src/nsNPAPIPlugin.h
@@ -38,16 +38,18 @@
 #ifndef nsNPAPIPlugin_h_
 #define nsNPAPIPlugin_h_
 
 #include "nsIPlugin.h"
 #include "prlink.h"
 #include "npfunctions.h"
 #include "nsPluginHost.h"
 
+#include "jsapi.h"
+
 #include "mozilla/PluginLibrary.h"
 
 /*
  * Use this macro before each exported function
  * (between the return address and the function
  * itself), to ensure that the function has the
  * right calling conventions on OS/2.
  */
@@ -109,16 +111,139 @@ protected:
   NPPluginFuncs mPluginFuncs;
   PluginLibrary* mLibrary;
 };
 
 namespace mozilla {
 namespace plugins {
 namespace parent {
 
+// On 32-bit platforms, sizeof(jsval) != sizeof(NPIdentifier), so we need to
+// use an alternate encoding scheme. The following inline helpers provide an
+// abstraction for setting and getting the values of NPIdentifiers that should
+// always be used instead of casting an NPIdentifier to a jsval and using the
+// jsapi.
+
+#if JS_BITS_PER_WORD == 64
+
+JS_STATIC_ASSERT(sizeof(NPIdentifier) == sizeof(jsval));
+
+static inline bool
+NPIdentifierIsString(NPIdentifer id)
+{
+    return JSVAL_IS_STRING((jsval)id);
+}
+
+static inline JSString *
+NPIdentifierToString(NPIdentifer id)
+{
+    return JSVAL_TO_STRING((jsval)id);
+}
+
+static inline NPIdentifier
+StringToNPIdentifier(JSString *str)
+{
+    return (NPIdentifier)STRING_TO_JSVAL(str);
+}
+
+static inline bool
+NPIdentifierIsInt(NPIdentifer id)
+{
+    return JSVAL_IS_INT((jsval)id);
+}
+
+static inline jsint
+NPIdentifierToInt(NPIdentifer id)
+{
+    return JSVAL_TO_INT((jsval)id);
+}
+
+static inline bool
+IntToNPIdentifier(JSContext *, jsint i, NPIdentifier *pid)
+{
+    *pid = (NPIdentifier)INT_TO_JSVAL(i);
+    return true;
+}
+
+static inline bool
+NPIdentifierIsVoid(NPIdentifier id)
+{
+    return JSVAL_IS_VOID((NPIdentifier)id);
+}
+
+static const NPIdentifier NPIdentifier_VOID = (NPIdentifier)JSVAL_VOID;
+
+#else  /* JS_BITS_PER_WORD == 32 */
+
+static inline bool
+NPIdentifierIsString(NPIdentifier id)
+{
+    return ((size_t)id & 0x3) == 0;
+}
+
+static inline JSString *
+NPIdentifierToString(NPIdentifier id)
+{
+    NS_ASSERTION(NPIdentifierIsString(id), "id must be string");
+    return (JSString *)id;
+}
+
+static inline NPIdentifier
+StringToNPIdentifier(JSString *str)
+{
+    NS_ASSERTION(((size_t)str & 3) == 0, "Strings are assumed to be at least 4-byte aligned");
+    return (NPIdentifier)str;
+}
+
+static inline bool
+NPIdentifierIsInt(NPIdentifier id)
+{
+    return ((size_t)id & 1) != 0;
+}
+
+static inline jsint
+NPIdentifierToInt(NPIdentifier id)
+{
+    NS_ASSERTION(NPIdentifierIsInt(id), "id must be int");
+    return (jsint)id >> 1;
+}
+
+static inline NPIdentifier
+IntToNPIdentifier(jsint i)
+{
+    NS_ASSERTION(i < (1 << 30) - 1, "integer id is too big, will be truncated");
+    return (NPIdentifier)((i << 1) | 0x1);
+}
+
+static inline bool
+NPIdentifierIsVoid(NPIdentifier id)
+{
+    return (size_t)id == 0x2;
+}
+
+static const NPIdentifier NPIdentifier_VOID = (NPIdentifier)0x2;
+
+#endif
+
+static inline jsval
+NPIdentifierToJSVal(NPIdentifier id)
+{
+    if (NPIdentifierIsString(id))
+        return STRING_TO_JSVAL(NPIdentifierToString(id));
+    return INT_TO_JSVAL(NPIdentifierToInt(id));
+}
+
+static inline NPIdentifier
+JSValToNPIdentifier(jsval val)
+{
+    if (JSVAL_IS_STRING(val))
+        return StringToNPIdentifier(JSVAL_TO_STRING(val));
+    return IntToNPIdentifier(JSVAL_TO_INT(val));
+}
+
 NPObject* NP_CALLBACK
 _getwindowobject(NPP npp);
 
 NPObject* NP_CALLBACK
 _getpluginelement(NPP npp);
 
 NPIdentifier NP_CALLBACK
 _getstringidentifier(const NPUTF8* name);