diff --git a/caps/idl/nsIScriptSecurityManager.idl b/caps/idl/nsIScriptSecurityManager.idl index 1c5fdc71f6e3..6ea73652a64f 100644 --- a/caps/idl/nsIScriptSecurityManager.idl +++ b/caps/idl/nsIScriptSecurityManager.idl @@ -51,7 +51,7 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager [noscript] void checkPropertyAccess(in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in string aClassName, - in jsval aProperty, + in jsid aProperty, in PRUint32 aAction); /** diff --git a/caps/include/nsScriptSecurityManager.h b/caps/include/nsScriptSecurityManager.h index b4ddf6f558c5..ce1eb610c68f 100644 --- a/caps/include/nsScriptSecurityManager.h +++ b/caps/include/nsScriptSecurityManager.h @@ -175,7 +175,7 @@ union SecurityLevel struct PropertyPolicy : public PLDHashEntryHdr { - jsval key; // property name as jsval + JSString *key; // interned string SecurityLevel mGet; SecurityLevel mSet; }; @@ -186,7 +186,7 @@ InitPropertyPolicyEntry(PLDHashTable *table, const void *key) { PropertyPolicy* pp = (PropertyPolicy*)entry; - pp->key = (jsval)key; + pp->key = (JSString *)key; pp->mGet.level = SCRIPT_SECURITY_UNDEFINED_ACCESS; pp->mSet.level = SCRIPT_SECURITY_UNDEFINED_ACCESS; return PR_TRUE; @@ -196,7 +196,7 @@ static void ClearPropertyPolicyEntry(PLDHashTable *table, PLDHashEntryHdr *entry) { PropertyPolicy* pp = (PropertyPolicy*)entry; - pp->key = JSVAL_VOID; + pp->key = NULL; } // Class Policy @@ -426,7 +426,7 @@ private: static JSBool CheckObjectAccess(JSContext *cx, JSObject *obj, - jsval id, JSAccessMode mode, + jsid id, JSAccessMode mode, jsval *vp); // Decides, based on CSP, whether or not eval() and stuff can be executed. @@ -453,7 +453,7 @@ private: JSContext* cx, JSObject* aJSObject, nsISupports* aObj, nsIURI* aTargetURI, nsIClassInfo* aClassInfo, - const char* aClassName, jsval aProperty, + const char* aClassName, jsid aProperty, void** aCachedClassPolicy); nsresult @@ -463,7 +463,7 @@ private: nsresult LookupPolicy(nsIPrincipal* principal, - ClassInfoData& aClassData, jsval aProperty, + ClassInfoData& aClassData, jsid aProperty, PRUint32 aAction, ClassPolicy** aCachedClassPolicy, SecurityLevel* result); @@ -612,7 +612,7 @@ private: }; // JS strings we need to clean up on shutdown - static jsval sEnabledID; + static jsid sEnabledID; inline void ScriptSecurityPrefChanged(); diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index e5d0e7388c43..36ae51c1f916 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -116,9 +116,15 @@ static JSEqualityOp sXPCWrappedNativeEqualityOps; /////////////////////////// // Result of this function should not be freed. static inline const PRUnichar * -JSValIDToString(JSContext *cx, const jsval idval) +IDToString(JSContext *cx, jsid id) { + if (JSID_IS_STRING(id)) + return reinterpret_cast(JS_GetStringChars(JSID_TO_STRING(id))); + JSAutoRequest ar(cx); + jsval idval; + if (!JS_IdToValue(cx, id, &idval)) + return nsnull; JSString *str = JS_ValueToString(cx, idval); if(!str) return nsnull; @@ -565,7 +571,7 @@ nsScriptSecurityManager::ContentSecurityPolicyPermitsJSAction(JSContext *cx) JSBool nsScriptSecurityManager::CheckObjectAccess(JSContext *cx, JSObject *obj, - jsval id, JSAccessMode mode, + jsid id, JSAccessMode mode, jsval *vp) { // Get the security manager @@ -604,7 +610,7 @@ NS_IMETHODIMP nsScriptSecurityManager::CheckPropertyAccess(JSContext* cx, JSObject* aJSObject, const char* aClassName, - jsval aProperty, + jsid aProperty, PRUint32 aAction) { return CheckPropertyAccessImpl(aAction, nsnull, cx, aJSObject, @@ -684,7 +690,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, JSContext* cx, JSObject* aJSObject, nsISupports* aObj, nsIURI* aTargetURI, nsIClassInfo* aClassInfo, - const char* aClassName, jsval aProperty, + const char* aClassName, jsid aProperty, void** aCachedClassPolicy) { nsresult rv; @@ -703,7 +709,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, ClassInfoData classInfoData(aClassInfo, aClassName); #ifdef DEBUG_CAPS_CheckPropertyAccessImpl nsCAutoString propertyName; - propertyName.AssignWithConversion((PRUnichar*)JSValIDToString(cx, aProperty)); + propertyName.AssignWithConversion((PRUnichar*)IDToString(cx, aProperty)); printf("### CanAccess(%s.%s, %i) ", classInfoData.GetName(), propertyName.get(), aAction); #endif @@ -825,17 +831,17 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, { case nsIXPCSecurityManager::ACCESS_GET_PROPERTY: checkedComponent->CanGetProperty(objIID, - JSValIDToString(cx, aProperty), + IDToString(cx, aProperty), getter_Copies(objectSecurityLevel)); break; case nsIXPCSecurityManager::ACCESS_SET_PROPERTY: checkedComponent->CanSetProperty(objIID, - JSValIDToString(cx, aProperty), + IDToString(cx, aProperty), getter_Copies(objectSecurityLevel)); break; case nsIXPCSecurityManager::ACCESS_CALL_METHOD: checkedComponent->CanCallMethod(objIID, - JSValIDToString(cx, aProperty), + IDToString(cx, aProperty), getter_Copies(objectSecurityLevel)); } } @@ -906,7 +912,7 @@ nsScriptSecurityManager::CheckPropertyAccessImpl(PRUint32 aAction, { subjectOriginUnicode.get(), className.get(), - JSValIDToString(cx, aProperty), + IDToString(cx, aProperty), objectOriginUnicode.get(), subjectDomainUnicode.get(), objectDomainUnicode.get() @@ -1075,7 +1081,7 @@ nsScriptSecurityManager::CheckSameOriginDOMProp(nsIPrincipal* aSubject, nsresult nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal, ClassInfoData& aClassData, - jsval aProperty, + jsid aProperty, PRUint32 aAction, ClassPolicy** aCachedClassPolicy, SecurityLevel* result) @@ -1186,6 +1192,15 @@ nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal, *aCachedClassPolicy = cpolicy; } + NS_ASSERTION(JSID_IS_INT(aProperty) || JSID_IS_OBJECT(aProperty) || + JSID_IS_STRING(aProperty), "Property must be a valid id"); + + // Only atomized strings are stored in the policies' hash tables. + if (!JSID_IS_STRING(aProperty)) + return NS_OK; + + JSString *propertyKey = JSID_TO_STRING(aProperty); + // We look for a PropertyPolicy in the following places: // 1) The ClassPolicy for our class we got from our DomainPolicy // 2) The mWildcardPolicy of our DomainPolicy @@ -1196,7 +1211,7 @@ nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal, { ppolicy = static_cast (PL_DHashTableOperate(cpolicy->mPolicy, - (void*)aProperty, + propertyKey, PL_DHASH_LOOKUP)); } @@ -1208,7 +1223,7 @@ nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal, ppolicy = static_cast (PL_DHashTableOperate(dpolicy->mWildcardPolicy->mPolicy, - (void*)aProperty, + propertyKey, PL_DHASH_LOOKUP)); } @@ -1228,7 +1243,7 @@ nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal, ppolicy = static_cast (PL_DHashTableOperate(cpolicy->mPolicy, - (void*)aProperty, + propertyKey, PL_DHASH_LOOKUP)); } @@ -1238,7 +1253,7 @@ nsScriptSecurityManager::LookupPolicy(nsIPrincipal* aPrincipal, ppolicy = static_cast (PL_DHashTableOperate(mDefaultPolicy->mWildcardPolicy->mPolicy, - (void*)aProperty, + propertyKey, PL_DHASH_LOOKUP)); } } @@ -2368,7 +2383,7 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj JSObject* origObj = aObj; #endif - const JSClass *jsClass = aObj->getClass(); + js::Class *jsClass = aObj->getClass(); // A common case seen in this code is that we enter this function // with aObj being a Function object, whose parent is a Call @@ -3041,11 +3056,11 @@ nsScriptSecurityManager::CheckComponentPermissions(JSContext *cx, // Look up the policy for this class. // while this isn't a property we'll treat it as such, using ACCESS_CALL_METHOD JSAutoRequest ar(cx); - jsval cidVal = STRING_TO_JSVAL(::JS_InternString(cx, cid.get())); + jsid cidId = INTERNED_STRING_TO_JSID(::JS_InternString(cx, cid.get())); ClassInfoData nameData(nsnull, "ClassID"); SecurityLevel securityLevel; - rv = LookupPolicy(subjectPrincipal, nameData, cidVal, + rv = LookupPolicy(subjectPrincipal, nameData, cidId, nsIXPCSecurityManager::ACCESS_CALL_METHOD, nsnull, &securityLevel); if (NS_FAILED(rv)) @@ -3148,7 +3163,7 @@ nsScriptSecurityManager::CanAccess(PRUint32 aAction, JSObject* aJSObject, nsISupports* aObj, nsIClassInfo* aClassInfo, - jsval aPropertyName, + jsid aPropertyName, void** aPolicy) { return CheckPropertyAccessImpl(aAction, aCallContext, cx, @@ -3348,8 +3363,8 @@ nsresult nsScriptSecurityManager::Init() if (!cx) return NS_ERROR_FAILURE; // this can happen of xpt loading fails ::JS_BeginRequest(cx); - if (sEnabledID == JSVAL_VOID) - sEnabledID = STRING_TO_JSVAL(::JS_InternString(cx, "enabled")); + if (sEnabledID == JSID_VOID) + sEnabledID = INTERNED_STRING_TO_JSID(::JS_InternString(cx, "enabled")); ::JS_EndRequest(cx); InitPrefs(); @@ -3402,7 +3417,7 @@ nsresult nsScriptSecurityManager::Init() static nsScriptSecurityManager *gScriptSecMan = nsnull; -jsval nsScriptSecurityManager::sEnabledID = JSVAL_VOID; +jsid nsScriptSecurityManager::sEnabledID = JSID_VOID; nsScriptSecurityManager::~nsScriptSecurityManager(void) { @@ -3421,7 +3436,7 @@ nsScriptSecurityManager::Shutdown() JS_SetRuntimeSecurityCallbacks(sRuntime, NULL); sRuntime = nsnull; } - sEnabledID = JSVAL_VOID; + sEnabledID = JSID_VOID; NS_IF_RELEASE(sIOService); NS_IF_RELEASE(sXPConnect); @@ -3751,11 +3766,9 @@ nsScriptSecurityManager::InitDomainPolicy(JSContext* cx, return NS_ERROR_OUT_OF_MEMORY; // Store this property in the class policy - const void* ppkey = - reinterpret_cast(STRING_TO_JSVAL(propertyKey)); PropertyPolicy* ppolicy = static_cast - (PL_DHashTableOperate(cpolicy->mPolicy, ppkey, + (PL_DHashTableOperate(cpolicy->mPolicy, propertyKey, PL_DHASH_ADD)); if (!ppolicy) break; @@ -4023,7 +4036,7 @@ PrintPropertyPolicy(PLDHashTable *table, PLDHashEntryHdr *entry, JSContext* cx = (JSContext*)arg; prop.AppendInt((PRUint32)pp->key); prop += ' '; - prop.AppendWithConversion((PRUnichar*)JSValIDToString(cx, pp->key)); + prop.AppendWithConversion((PRUnichar*)JS_GetStringChars(pp->key)); prop += ": Get="; if (SECURITY_ACCESS_LEVEL_FLAG(pp->mGet)) prop.AppendInt(pp->mGet.level); diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 6f33425af17e..34e03d72b27e 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1803,7 +1803,7 @@ public: ~nsAutoGCRoot() { if (NS_SUCCEEDED(mResult)) { - RemoveJSGCRoot(mPtr, mRootType); + RemoveJSGCRoot((jsval *)mPtr, mRootType); } } diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index d6ac8646d8cc..eb44e9499bf5 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -5619,15 +5619,6 @@ CloneSimpleValues(JSContext* cx, return SetPropertyOnValueOrObject(cx, val, rval, robj, rid); } - // Clone doubles. - if (JSVAL_IS_DOUBLE(val)) { - jsval newVal; - if (!JS_NewDoubleValue(cx, *JSVAL_TO_DOUBLE(val), &newVal)) { - return NS_ERROR_OUT_OF_MEMORY; - } - return SetPropertyOnValueOrObject(cx, newVal, rval, robj, rid); - } - // We'll use immutable strings to prevent copying if we can. if (JSVAL_IS_STRING(val)) { if (!JS_MakeStringImmutable(cx, JSVAL_TO_STRING(val))) { diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index 105af5c478b0..f27c5617862d 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -422,11 +422,11 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget, NS_ENSURE_SUCCESS(rv, rv); js::AutoValueRooter argv(ctx); - argv.setObject(param); + argv.set(OBJECT_TO_JSVAL(param)); JSObject* thisObject = JSVAL_TO_OBJECT(thisValue); JS_CallFunctionValue(ctx, thisObject, - funval, 1, argv.addr(), &rval); + funval, 1, argv.jsval_addr(), &rval); if (aJSONRetVal) { nsString json; if (JS_TryJSON(ctx, &rval) && diff --git a/content/canvas/src/CustomQS_Canvas2D.h b/content/canvas/src/CustomQS_Canvas2D.h index 4ca619fef476..375878c2b2a5 100644 --- a/content/canvas/src/CustomQS_Canvas2D.h +++ b/content/canvas/src/CustomQS_Canvas2D.h @@ -44,14 +44,14 @@ typedef nsresult (NS_STDCALL nsIDOMCanvasRenderingContext2D::*CanvasStyleSetterT typedef nsresult (NS_STDCALL nsIDOMCanvasRenderingContext2D::*CanvasStyleGetterType)(nsAString &, nsISupports **, PRInt32 *); static JSBool -Canvas2D_SetStyleHelper(JSContext *cx, JSObject *obj, jsval id, jsval *vp, +Canvas2D_SetStyleHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, CanvasStyleSetterType setfunc) { XPC_QS_ASSERT_CONTEXT_OK(cx); nsIDOMCanvasRenderingContext2D *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; nsresult rv; @@ -69,7 +69,7 @@ Canvas2D_SetStyleHelper(JSContext *cx, JSObject *obj, jsval id, jsval *vp, xpc_qsSelfRef arg0ref; rv = xpc_qsUnwrapArg(cx, *vp, &arg0, &arg0ref.ptr, vp); if (NS_FAILED(rv)) { - xpc_qsThrowBadSetterValue(cx, rv, JSVAL_TO_OBJECT(*tvr.addr()), id); + xpc_qsThrowBadSetterValue(cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id); return JS_FALSE; } @@ -80,13 +80,13 @@ Canvas2D_SetStyleHelper(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } if (NS_FAILED(rv)) - return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(*tvr.addr()), id); + return xpc_qsThrowGetterSetterFailed(cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id); return JS_TRUE; } static JSBool -Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsval id, jsval *vp, +Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsid id, jsval *vp, CanvasStyleGetterType getfunc) { XPC_QS_ASSERT_CONTEXT_OK(cx); @@ -122,25 +122,25 @@ Canvas2D_GetStyleHelper(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } static JSBool -nsIDOMCanvasRenderingContext2D_SetStrokeStyle(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +nsIDOMCanvasRenderingContext2D_SetStrokeStyle(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return Canvas2D_SetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::SetStrokeStyle_multi); } static JSBool -nsIDOMCanvasRenderingContext2D_GetStrokeStyle(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +nsIDOMCanvasRenderingContext2D_GetStrokeStyle(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return Canvas2D_GetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::GetStrokeStyle_multi); } static JSBool -nsIDOMCanvasRenderingContext2D_SetFillStyle(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +nsIDOMCanvasRenderingContext2D_SetFillStyle(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return Canvas2D_SetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::SetFillStyle_multi); } static JSBool -nsIDOMCanvasRenderingContext2D_GetFillStyle(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +nsIDOMCanvasRenderingContext2D_GetFillStyle(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return Canvas2D_GetStyleHelper(cx, obj, id, vp, &nsIDOMCanvasRenderingContext2D::GetFillStyle_multi); } @@ -179,14 +179,14 @@ nsIDOMCanvasRenderingContext2D_CreateImageData(JSContext *cx, uintN argc, jsval // create the fast typed array; it's initialized to 0 by default JSObject *darray = js_CreateTypedArray(cx, js::TypedArray::TYPE_UINT8_CLAMPED, len); - js::AutoValueRooter rd(cx, darray); + js::AutoObjectRooter rd(cx, darray); if (!darray) return JS_FALSE; // Do JS_NewObject after CreateTypedArray, so that gc will get // triggered here if necessary JSObject *result = JS_NewObject(cx, NULL, NULL, NULL); - js::AutoValueRooter rr(cx, result); + js::AutoObjectRooter rr(cx, result); if (!result) return JS_FALSE; @@ -213,7 +213,7 @@ nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, uintN argc, jsval *vp nsIDOMCanvasRenderingContext2D *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 4) @@ -246,7 +246,7 @@ nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, uintN argc, jsval *vp // create the fast typed array JSObject *darray = js_CreateTypedArray(cx, js::TypedArray::TYPE_UINT8_CLAMPED, len); - js::AutoValueRooter rd(cx, darray); + js::AutoObjectRooter rd(cx, darray); if (!darray) return JS_FALSE; @@ -260,7 +260,7 @@ nsIDOMCanvasRenderingContext2D_GetImageData(JSContext *cx, uintN argc, jsval *vp // Do JS_NewObject after CreateTypedArray, so that gc will get // triggered here if necessary JSObject *result = JS_NewObject(cx, NULL, NULL, NULL); - js::AutoValueRooter rr(cx, result); + js::AutoObjectRooter rr(cx, result); if (!result) return JS_FALSE; @@ -287,7 +287,7 @@ nsIDOMCanvasRenderingContext2D_PutImageData(JSContext *cx, uintN argc, jsval *vp nsIDOMCanvasRenderingContext2D *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 3) @@ -310,12 +310,12 @@ nsIDOMCanvasRenderingContext2D_PutImageData(JSContext *cx, uintN argc, jsval *vp // grab width, height, and the dense array from the dataObject js::AutoValueRooter tv(cx); - if (!JS_GetProperty(cx, dataObject, "width", tv.addr()) || - !JS_ValueToECMAInt32(cx, tv.value(), &wi)) + if (!JS_GetProperty(cx, dataObject, "width", tv.jsval_addr()) || + !JS_ValueToECMAInt32(cx, tv.jsval_value(), &wi)) return JS_FALSE; - if (!JS_GetProperty(cx, dataObject, "height", tv.addr()) || - !JS_ValueToECMAInt32(cx, tv.value(), &hi)) + if (!JS_GetProperty(cx, dataObject, "height", tv.jsval_addr()) || + !JS_ValueToECMAInt32(cx, tv.jsval_value(), &hi)) return JS_FALSE; if (wi <= 0 || hi <= 0) @@ -324,10 +324,10 @@ nsIDOMCanvasRenderingContext2D_PutImageData(JSContext *cx, uintN argc, jsval *vp uint32 w = (uint32) wi; uint32 h = (uint32) hi; - if (!JS_GetProperty(cx, dataObject, "data", tv.addr()) || - JSVAL_IS_PRIMITIVE(tv.value())) + if (!JS_GetProperty(cx, dataObject, "data", tv.jsval_addr()) || + JSVAL_IS_PRIMITIVE(tv.jsval_value())) return JS_FALSE; - darray = JSVAL_TO_OBJECT(tv.value()); + darray = JSVAL_TO_OBJECT(tv.jsval_value()); js::AutoValueRooter tsrc_tvr(cx); @@ -342,7 +342,7 @@ nsIDOMCanvasRenderingContext2D_PutImageData(JSContext *cx, uintN argc, jsval *vp if (!nobj) return JS_FALSE; - *tsrc_tvr.addr() = OBJECT_TO_JSVAL(nobj); + *tsrc_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj); tsrc = js::TypedArray::fromJSObject(nobj); } else { // yeah, no. diff --git a/content/canvas/src/CustomQS_WebGL.h b/content/canvas/src/CustomQS_WebGL.h index 8ebc277c6b8f..3a24b2ed8b25 100644 --- a/content/canvas/src/CustomQS_WebGL.h +++ b/content/canvas/src/CustomQS_WebGL.h @@ -92,7 +92,7 @@ nsICanvasRenderingContextWebGL_BufferData(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 3) @@ -158,7 +158,7 @@ nsICanvasRenderingContextWebGL_BufferSubData(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 3) @@ -226,7 +226,7 @@ nsICanvasRenderingContextWebGL_ReadPixels(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; // XXX we currently allow passing only 6 args to support the API. Eventually drop that. @@ -323,7 +323,7 @@ nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp) nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; // XXX we currently allow passing only 3 args to support the API. Eventually drop that. @@ -447,7 +447,7 @@ nsICanvasRenderingContextWebGL_TexSubImage2D(JSContext *cx, uintN argc, jsval *v nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 7 || argc == 8) @@ -548,7 +548,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 2) @@ -584,7 +584,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv(JSContext *cx, uintN argc, js return JS_FALSE; } - *obj_tvr.addr() = OBJECT_TO_JSVAL(nobj); + *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj); wa = js::TypedArray::fromJSObject(nobj); } else { xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1); @@ -622,7 +622,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 2) @@ -658,7 +658,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv(JSContext *cx, uintN argc, js return JS_FALSE; } - *obj_tvr.addr() = OBJECT_TO_JSVAL(nobj); + *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj); wa = js::TypedArray::fromJSObject(nobj); } else { xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1); @@ -696,7 +696,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 3) @@ -736,7 +736,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv(JSContext *cx, uintN ar return JS_FALSE; } - *obj_tvr.addr() = OBJECT_TO_JSVAL(nobj); + *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj); wa = js::TypedArray::fromJSObject(nobj); } else { xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 2); @@ -771,7 +771,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg nsICanvasRenderingContextWebGL *self; xpc_qsSelfRef selfref; js::AutoValueRooter tvr(cx); - if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull)) + if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.jsval_addr(), nsnull)) return JS_FALSE; if (argc < 2) @@ -803,7 +803,7 @@ helper_nsICanvasRenderingContextWebGL_VertexAttrib_x_fv(JSContext *cx, uintN arg return JS_FALSE; } - *obj_tvr.addr() = OBJECT_TO_JSVAL(nobj); + *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj); wa = js::TypedArray::fromJSObject(nobj); } else { xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 1); @@ -919,7 +919,7 @@ nsICanvasRenderingContextWebGL_VertexAttrib4fv(JSContext *cx, uintN argc, jsval #ifdef JS_TRACER -static inline jsval FASTCALL +static inline void FASTCALL helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *obj, JSObject *locationobj, JSObject *arg, int nElements) { @@ -930,7 +930,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *o xpc_qsArgValArray<3> vp(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) { js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } js::AutoValueRooter obj_tvr(cx); @@ -941,7 +941,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *o = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull); if (NS_FAILED(rv_convert_arg0)) { js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } js::TypedArray *wa = 0; @@ -953,15 +953,15 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *o if (!nobj) { // XXX this will likely return a strange error message if it goes wrong js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } - *obj_tvr.addr() = OBJECT_TO_JSVAL(nobj); + *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj); wa = js::TypedArray::fromJSObject(nobj); } else { xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsICanvasRenderingContextWebGL", "uniformNiv"); js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } nsresult rv; @@ -980,11 +980,9 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(JSContext *cx, JSObject *o xpc_qsThrowMethodFailedWithDetails(cx, rv, "nsICanvasRenderingContextWebGL", "uniformNiv"); js_SetTraceableNativeFailed(cx); } - - return JSVAL_VOID; } -static inline jsval FASTCALL +static inline void FASTCALL helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *obj, JSObject *locationobj, JSObject *arg, int nElements) { @@ -995,7 +993,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *o xpc_qsArgValArray<3> vp(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) { js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } js::AutoValueRooter obj_tvr(cx); @@ -1006,7 +1004,7 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *o = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull); if (NS_FAILED(rv_convert_arg0)) { js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } js::TypedArray *wa = 0; @@ -1018,15 +1016,15 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *o if (!nobj) { // XXX this will likely return a strange error message if it goes wrong js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } - *obj_tvr.addr() = OBJECT_TO_JSVAL(nobj); + *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj); wa = js::TypedArray::fromJSObject(nobj); } else { xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsICanvasRenderingContextWebGL", "uniformNfv"); js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } nsresult rv; @@ -1046,10 +1044,10 @@ helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(JSContext *cx, JSObject *o js_SetTraceableNativeFailed(cx); } - return JSVAL_VOID; + return; } -static inline jsval FASTCALL +static inline void FASTCALL helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObject *obj, JSObject *locationobj, JSBool transpose, JSObject *arg, int nElements) { @@ -1060,7 +1058,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObj xpc_qsArgValArray<4> vp(cx); if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, &vp.array[0], nsnull)) { js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } js::AutoValueRooter obj_tvr(cx); @@ -1071,7 +1069,7 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObj = xpc_qsUnwrapThis(cx, locationobj, nsnull, &location, &location_selfref.ptr, &vp.array[1], nsnull); if (NS_FAILED(rv_convert_arg0)) { js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } js::TypedArray *wa = 0; @@ -1083,15 +1081,15 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObj if (!nobj) { // XXX this will likely return a strange error message if it goes wrong js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } - *obj_tvr.addr() = OBJECT_TO_JSVAL(nobj); + *obj_tvr.jsval_addr() = OBJECT_TO_JSVAL(nobj); wa = js::TypedArray::fromJSObject(nobj); } else { xpc_qsThrowMethodFailedWithDetails(cx, NS_ERROR_FAILURE, "nsICanvasRenderingContextWebGL", "uniformMatrixNfv"); js_SetTraceableNativeFailed(cx); - return JSVAL_VOID; + return; } nsresult rv; @@ -1107,107 +1105,138 @@ helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(JSContext *cx, JSObj xpc_qsThrowMethodFailedWithDetails(cx, rv, "nsICanvasRenderingContextWebGL", "uniformMatrixNfv"); js_SetTraceableNativeFailed(cx); } - - return JSVAL_VOID; } -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_Uniform1iv_tn(JSContext *cx, JSObject *obj, JSObject *location, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(cx, obj, location, arg, 1); + helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(cx, obj, location, arg, 1); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_Uniform1iv, - (4, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_Uniform1iv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (4, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_Uniform1iv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_Uniform2iv_tn(JSContext *cx, JSObject *obj, JSObject *location, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(cx, obj, location, arg, 2); + helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(cx, obj, location, arg, 2); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_Uniform2iv, - (4, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_Uniform2iv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (4, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_Uniform2iv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_Uniform3iv_tn(JSContext *cx, JSObject *obj, JSObject *location, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(cx, obj, location, arg, 3); + helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(cx, obj, location, arg, 3); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_Uniform3iv, - (4, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_Uniform3iv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (4, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_Uniform3iv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_Uniform4iv_tn(JSContext *cx, JSObject *obj, JSObject *location, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(cx, obj, location, arg, 4); + helper_nsICanvasRenderingContextWebGL_Uniform_x_iv_tn(cx, obj, location, arg, 4); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_Uniform4iv, - (4, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_Uniform4iv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (4, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_Uniform4iv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_Uniform1fv_tn(JSContext *cx, JSObject *obj, JSObject *location, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(cx, obj, location, arg, 1); + helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(cx, obj, location, arg, 1); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_Uniform1fv, - (4, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_Uniform1fv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (4, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_Uniform1fv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_Uniform2fv_tn(JSContext *cx, JSObject *obj, JSObject *location, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(cx, obj, location, arg, 2); + helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(cx, obj, location, arg, 2); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_Uniform2fv, - (4, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_Uniform2fv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (4, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_Uniform2fv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_Uniform3fv_tn(JSContext *cx, JSObject *obj, JSObject *location, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(cx, obj, location, arg, 3); + helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(cx, obj, location, arg, 3); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_Uniform3fv, - (4, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_Uniform3fv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (4, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_Uniform3fv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_Uniform4fv_tn(JSContext *cx, JSObject *obj, JSObject *location, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(cx, obj, location, arg, 4); + helper_nsICanvasRenderingContextWebGL_Uniform_x_fv_tn(cx, obj, location, arg, 4); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_Uniform4fv, - (4, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_Uniform4fv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (4, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_Uniform4fv_tn, CONTEXT, THIS, OBJECT, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_UniformMatrix2fv_tn(JSContext *cx, JSObject *obj, JSObject *loc, JSBool transpose, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(cx, obj, loc, transpose, arg, 2); + helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(cx, obj, loc, transpose, arg, 2); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_UniformMatrix2fv, - (5, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_UniformMatrix2fv_tn, CONTEXT, THIS, OBJECT, BOOL, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (5, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_UniformMatrix2fv_tn, CONTEXT, THIS, OBJECT, BOOL, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_UniformMatrix3fv_tn(JSContext *cx, JSObject *obj, JSObject *loc, JSBool transpose, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(cx, obj, loc, transpose, arg, 3); + helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(cx, obj, loc, transpose, arg, 3); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_UniformMatrix3fv, - (5, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_UniformMatrix3fv_tn, CONTEXT, THIS, OBJECT, BOOL, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (5, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_UniformMatrix3fv_tn, CONTEXT, THIS, OBJECT, BOOL, OBJECT, 0, nanojit::ACC_STORE_ANY))) -static jsval FASTCALL +// FIXME This should return void, not uint32 +// (waiting for https://bugzilla.mozilla.org/show_bug.cgi?id=572798) +static uint32 FASTCALL nsICanvasRenderingContextWebGL_UniformMatrix4fv_tn(JSContext *cx, JSObject *obj, JSObject *loc, JSBool transpose, JSObject *arg) { - return helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(cx, obj, loc, transpose, arg, 4); + helper_nsICanvasRenderingContextWebGL_UniformMatrix_x_fv_tn(cx, obj, loc, transpose, arg, 4); + return 0; } JS_DEFINE_TRCINFO_1(nsICanvasRenderingContextWebGL_UniformMatrix4fv, - (5, (static, JSVAL_FAIL, nsICanvasRenderingContextWebGL_UniformMatrix4fv_tn, CONTEXT, THIS, OBJECT, BOOL, OBJECT, 0, nanojit::ACC_STORE_ANY))) + (5, (static, UINT32_FAIL, nsICanvasRenderingContextWebGL_UniformMatrix4fv_tn, CONTEXT, THIS, OBJECT, BOOL, OBJECT, 0, nanojit::ACC_STORE_ANY))) #endif /* JS_TRACER */ diff --git a/content/canvas/src/NativeJSContext.cpp b/content/canvas/src/NativeJSContext.cpp index 3703d7c81f8f..13a761d8f9a8 100644 --- a/content/canvas/src/NativeJSContext.cpp +++ b/content/canvas/src/NativeJSContext.cpp @@ -15,6 +15,5 @@ void NativeJSContext::ReleaseGCRoot(JSObject **aPtr) { NS_ASSERTION(NS_SUCCEEDED(error), "class failed to initialize and caller used class without checking!"); - ::JS_RemoveObjectRoot(ctx, aPtr); } diff --git a/content/canvas/src/NativeJSContext.h b/content/canvas/src/NativeJSContext.h index 0f7e265e06b0..1556c95f6b17 100644 --- a/content/canvas/src/NativeJSContext.h +++ b/content/canvas/src/NativeJSContext.h @@ -67,33 +67,22 @@ public: void SetRetVal (PRInt32 val) { NS_ASSERTION(NS_SUCCEEDED(error), "class failed to initialize and caller used class without checking!"); - if (INT_FITS_IN_JSVAL(val)) - SetRetValAsJSVal(INT_TO_JSVAL(val)); - else - SetRetVal((double) val); + SetRetValAsJSVal(INT_TO_JSVAL(val)); } void SetRetVal (PRUint32 val) { NS_ASSERTION(NS_SUCCEEDED(error), "class failed to initialize and caller used class without checking!"); - if (INT_FITS_IN_JSVAL(val)) - SetRetValAsJSVal(INT_TO_JSVAL((int) val)); - else - SetRetVal((double) val); + SetRetValAsJSVal(UINT_TO_JSVAL(val)); } void SetRetVal (double val) { NS_ASSERTION(NS_SUCCEEDED(error), "class failed to initialize and caller used class without checking!"); - jsval *vp; - ncc->GetRetValPtr(&vp); - JS_NewDoubleValue(ctx, val, vp); + SetRetValAsJSVal(DOUBLE_TO_JSVAL(val)); } void SetBoolRetVal (PRBool val) { NS_ASSERTION(NS_SUCCEEDED(error), "class failed to initialize and caller used class without checking!"); - if (val) - SetRetValAsJSVal(JSVAL_TRUE); - else - SetRetValAsJSVal(JSVAL_FALSE); + SetRetValAsJSVal(BOOLEAN_TO_JSVAL(val)); } void SetRetVal (PRInt32 *vp, PRUint32 len) { @@ -103,13 +92,8 @@ public: if (!JS_EnterLocalRootScope(ctx)) return; // XXX ??? - for (PRUint32 i = 0; i < len; i++) { - if (INT_FITS_IN_JSVAL(vp[i])) { - jsvector[i] = INT_TO_JSVAL(vp[i]); - } else { - JS_NewDoubleValue(ctx, vp[i], &jsvector[i]); - } - } + for (PRUint32 i = 0; i < len; i++) + jsvector[i] = INT_TO_JSVAL(vp[i]); JSObject *jsarr = JS_NewArrayObject(ctx, len, jsvector.get()); SetRetVal(jsarr); @@ -124,9 +108,8 @@ public: if (!JS_EnterLocalRootScope(ctx)) return; // XXX ??? - for (PRUint32 i = 0; i < len; i++) { - JS_NewNumberValue(ctx, vp[i], &jsvector[i]); - } + for (PRUint32 i = 0; i < len; i++) + jsvector[i] = UINT_TO_JSVAL(vp[i]); JSObject *jsarr = JS_NewArrayObject(ctx, len, jsvector.get()); SetRetVal(jsarr); @@ -142,8 +125,8 @@ public: return; // XXX ??? for (PRUint32 i = 0; i < len; i++) - JS_NewDoubleValue(ctx, (jsdouble) dp[i], &jsvector[i]); - + jsvector[i] = DOUBLE_TO_JSVAL(dp[i]); + JSObject *jsarr = JS_NewArrayObject(ctx, len, jsvector.get()); SetRetVal(jsarr); @@ -158,7 +141,8 @@ public: return; // XXX ??? for (PRUint32 i = 0; i < len; i++) - JS_NewDoubleValue(ctx, (jsdouble) fp[i], &jsvector[i]); + jsvector[i] = DOUBLE_TO_JSVAL(fp[i]); + JSObject *jsarr = JS_NewArrayObject(ctx, len, jsvector.get()); SetRetVal(jsarr); @@ -342,11 +326,7 @@ public: } PRBool DefineProperty(const char *name, double val) { - jsval dv; - - if (!JS_NewDoubleValue(mCtx->ctx, val, &dv)) - return PR_FALSE; - + jsval dv = DOUBLE_TO_JSVAL(val); if (!JS_DefineProperty(mCtx->ctx, mObject, name, dv, NULL, NULL, JSPROP_ENUMERATE)) return PR_FALSE; return PR_TRUE; @@ -360,7 +340,7 @@ public: // Blah. We can't name this DefineProperty also because PRBool is the same as PRInt32 PRBool DefineBoolProperty(const char *name, PRBool val) { - if (!JS_DefineProperty(mCtx->ctx, mObject, name, val ? JS_TRUE : JS_FALSE, NULL, NULL, JSPROP_ENUMERATE)) + if (!JS_DefineProperty(mCtx->ctx, mObject, name, val ? JSVAL_TRUE : JSVAL_FALSE, NULL, NULL, JSPROP_ENUMERATE)) return PR_FALSE; return PR_TRUE; } diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index c6363a388a95..77907e0a0809 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -311,7 +311,7 @@ void nsEventListenerManager::Shutdown() { NS_IF_RELEASE(gSystemEventGroup); - sAddListenerID = JSVAL_VOID; + sAddListenerID = JSID_VOID; nsDOMEvent::Shutdown(); } @@ -841,8 +841,8 @@ nsEventListenerManager::RemoveScriptEventListener(nsIAtom* aName) return NS_OK; } -jsval -nsEventListenerManager::sAddListenerID = JSVAL_VOID; +jsid +nsEventListenerManager::sAddListenerID = JSID_VOID; NS_IMETHODIMP nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext, @@ -866,10 +866,10 @@ nsEventListenerManager::RegisterScriptEventListener(nsIScriptContext *aContext, return rv; if (cx) { - if (sAddListenerID == JSVAL_VOID) { + if (sAddListenerID == JSID_VOID) { JSAutoRequest ar(cx); sAddListenerID = - STRING_TO_JSVAL(::JS_InternString(cx, "addEventListener")); + INTERNED_STRING_TO_JSID(::JS_InternString(cx, "addEventListener")); } if (aContext->GetScriptTypeID() == nsIProgrammingLanguage::JAVASCRIPT) { diff --git a/content/events/src/nsEventListenerManager.h b/content/events/src/nsEventListenerManager.h index daf8be595d4e..61ba60df3bad 100644 --- a/content/events/src/nsEventListenerManager.h +++ b/content/events/src/nsEventListenerManager.h @@ -231,7 +231,7 @@ protected: nsCOMPtr mNoListenerForEventAtom; static PRUint32 mInstanceCount; - static jsval sAddListenerID; + static jsid sAddListenerID; friend class nsEventTargetChainItem; static PRUint32 sCreatedCount; diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 698ae4a7e628..1b3c66867c72 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -3635,10 +3635,10 @@ ConvertToMidasInternalCommand(const nsAString & inCommandID, dummyBool, dummyBool, PR_TRUE); } -jsval -nsHTMLDocument::sCutCopyInternal_id = JSVAL_VOID; -jsval -nsHTMLDocument::sPasteInternal_id = JSVAL_VOID; +jsid +nsHTMLDocument::sCutCopyInternal_id = JSID_VOID; +jsid +nsHTMLDocument::sPasteInternal_id = JSID_VOID; /* Helper function to check security of clipboard commands. If aPaste is */ /* true, we check paste, else we check cutcopy */ @@ -3664,17 +3664,17 @@ nsHTMLDocument::DoClipboardSecurityCheck(PRBool aPaste) nsIScriptSecurityManager *secMan = nsContentUtils::GetSecurityManager(); if (aPaste) { - if (nsHTMLDocument::sPasteInternal_id == JSVAL_VOID) { + if (nsHTMLDocument::sPasteInternal_id == JSID_VOID) { nsHTMLDocument::sPasteInternal_id = - STRING_TO_JSVAL(::JS_InternString(cx, "paste")); + INTERNED_STRING_TO_JSID(::JS_InternString(cx, "paste")); } rv = secMan->CheckPropertyAccess(cx, nsnull, classNameStr.get(), nsHTMLDocument::sPasteInternal_id, nsIXPCSecurityManager::ACCESS_GET_PROPERTY); } else { - if (nsHTMLDocument::sCutCopyInternal_id == JSVAL_VOID) { + if (nsHTMLDocument::sCutCopyInternal_id == JSID_VOID) { nsHTMLDocument::sCutCopyInternal_id = - STRING_TO_JSVAL(::JS_InternString(cx, "cutcopy")); + INTERNED_STRING_TO_JSID(::JS_InternString(cx, "cutcopy")); } rv = secMan->CheckPropertyAccess(cx, nsnull, classNameStr.get(), nsHTMLDocument::sCutCopyInternal_id, diff --git a/content/html/document/src/nsHTMLDocument.h b/content/html/document/src/nsHTMLDocument.h index 6c5cfa88d7a0..8d2dba6e6d51 100644 --- a/content/html/document/src/nsHTMLDocument.h +++ b/content/html/document/src/nsHTMLDocument.h @@ -371,8 +371,8 @@ protected: EditingState mEditingState; nsresult DoClipboardSecurityCheck(PRBool aPaste); - static jsval sCutCopyInternal_id; - static jsval sPasteInternal_id; + static jsid sCutCopyInternal_id; + static jsid sPasteInternal_id; // When false, the .cookies property is completely disabled PRBool mDisableCookieAccess; diff --git a/content/xbl/src/nsXBLBinding.cpp b/content/xbl/src/nsXBLBinding.cpp index a328cedc9d1f..3e2cebdd706f 100644 --- a/content/xbl/src/nsXBLBinding.cpp +++ b/content/xbl/src/nsXBLBinding.cpp @@ -123,7 +123,7 @@ XBLFinalize(JSContext *cx, JSObject *obj) } static JSBool -XBLResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XBLResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { // Note: if we get here, that means that the implementation for some binding @@ -136,7 +136,7 @@ XBLResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject* origObj = *objp; *objp = NULL; - if (!JSVAL_IS_STRING(id)) { + if (!JSID_IS_STRING(id)) { return JS_TRUE; } diff --git a/content/xbl/src/nsXBLDocumentInfo.cpp b/content/xbl/src/nsXBLDocumentInfo.cpp index 3f318c86ca96..93a84d8c76cd 100644 --- a/content/xbl/src/nsXBLDocumentInfo.cpp +++ b/content/xbl/src/nsXBLDocumentInfo.cpp @@ -81,7 +81,7 @@ public: // nsIScriptObjectPrincipal methods virtual nsIPrincipal* GetPrincipal(); - static JSBool doCheckAccess(JSContext *cx, JSObject *obj, jsval id, + static JSBool doCheckAccess(JSContext *cx, JSObject *obj, jsid id, PRUint32 accessType); NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsXBLDocGlobalObject, @@ -104,7 +104,7 @@ protected: }; JSBool -nsXBLDocGlobalObject::doCheckAccess(JSContext *cx, JSObject *obj, jsval id, PRUint32 accessType) +nsXBLDocGlobalObject::doCheckAccess(JSContext *cx, JSObject *obj, jsid id, PRUint32 accessType) { nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager(); if (!ssm) { @@ -129,7 +129,7 @@ nsXBLDocGlobalObject::doCheckAccess(JSContext *cx, JSObject *obj, jsval id, PRUi static JSBool nsXBLDocGlobalObject_getProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp) + jsid id, jsval *vp) { return nsXBLDocGlobalObject:: doCheckAccess(cx, obj, id, nsIXPCSecurityManager::ACCESS_GET_PROPERTY); @@ -137,14 +137,14 @@ nsXBLDocGlobalObject_getProperty(JSContext *cx, JSObject *obj, static JSBool nsXBLDocGlobalObject_setProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp) + jsid id, jsval *vp) { return nsXBLDocGlobalObject:: doCheckAccess(cx, obj, id, nsIXPCSecurityManager::ACCESS_SET_PROPERTY); } static JSBool -nsXBLDocGlobalObject_checkAccess(JSContext *cx, JSObject *obj, jsval id, +nsXBLDocGlobalObject_checkAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp) { PRUint32 translated; @@ -173,7 +173,7 @@ nsXBLDocGlobalObject_finalize(JSContext *cx, JSObject *obj) } static JSBool -nsXBLDocGlobalObject_resolve(JSContext *cx, JSObject *obj, jsval id) +nsXBLDocGlobalObject_resolve(JSContext *cx, JSObject *obj, jsid id) { JSBool did_resolve = JS_FALSE; return JS_ResolveStandardClass(cx, obj, id, &did_resolve); diff --git a/content/xul/document/src/nsXULPrototypeDocument.cpp b/content/xul/document/src/nsXULPrototypeDocument.cpp index b9baaaf24d50..6200e431ddae 100644 --- a/content/xul/document/src/nsXULPrototypeDocument.cpp +++ b/content/xul/document/src/nsXULPrototypeDocument.cpp @@ -132,7 +132,7 @@ nsXULPDGlobalObject_finalize(JSContext *cx, JSObject *obj) JSBool -nsXULPDGlobalObject_resolve(JSContext *cx, JSObject *obj, jsval id) +nsXULPDGlobalObject_resolve(JSContext *cx, JSObject *obj, jsid id) { JSBool did_resolve = JS_FALSE; diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index 29b6a6ff51b2..81d82e496882 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1500,91 +1500,91 @@ PRBool nsDOMClassInfo::sDisableDocumentAllSupport = PR_FALSE; PRBool nsDOMClassInfo::sDisableGlobalScopePollutionSupport = PR_FALSE; -jsval nsDOMClassInfo::sTop_id = JSVAL_VOID; -jsval nsDOMClassInfo::sParent_id = JSVAL_VOID; -jsval nsDOMClassInfo::sScrollbars_id = JSVAL_VOID; -jsval nsDOMClassInfo::sLocation_id = JSVAL_VOID; -jsval nsDOMClassInfo::sConstructor_id = JSVAL_VOID; -jsval nsDOMClassInfo::s_content_id = JSVAL_VOID; -jsval nsDOMClassInfo::sContent_id = JSVAL_VOID; -jsval nsDOMClassInfo::sMenubar_id = JSVAL_VOID; -jsval nsDOMClassInfo::sToolbar_id = JSVAL_VOID; -jsval nsDOMClassInfo::sLocationbar_id = JSVAL_VOID; -jsval nsDOMClassInfo::sPersonalbar_id = JSVAL_VOID; -jsval nsDOMClassInfo::sStatusbar_id = JSVAL_VOID; -jsval nsDOMClassInfo::sDialogArguments_id = JSVAL_VOID; -jsval nsDOMClassInfo::sControllers_id = JSVAL_VOID; -jsval nsDOMClassInfo::sLength_id = JSVAL_VOID; -jsval nsDOMClassInfo::sInnerHeight_id = JSVAL_VOID; -jsval nsDOMClassInfo::sInnerWidth_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOuterHeight_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOuterWidth_id = JSVAL_VOID; -jsval nsDOMClassInfo::sScreenX_id = JSVAL_VOID; -jsval nsDOMClassInfo::sScreenY_id = JSVAL_VOID; -jsval nsDOMClassInfo::sStatus_id = JSVAL_VOID; -jsval nsDOMClassInfo::sName_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnmousedown_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnmouseup_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnclick_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOndblclick_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOncontextmenu_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnmouseover_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnmouseout_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnkeydown_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnkeyup_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnkeypress_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnmousemove_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnfocus_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnblur_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnsubmit_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnreset_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnchange_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnselect_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnload_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnpopstate_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnbeforeunload_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnunload_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnhashchange_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnreadystatechange_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnpageshow_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnpagehide_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnabort_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnerror_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnpaint_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnresize_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnscroll_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOndrag_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOndragend_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOndragenter_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOndragleave_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOndragover_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOndragstart_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOndrop_id = JSVAL_VOID; -jsval nsDOMClassInfo::sScrollX_id = JSVAL_VOID; -jsval nsDOMClassInfo::sScrollY_id = JSVAL_VOID; -jsval nsDOMClassInfo::sScrollMaxX_id = JSVAL_VOID; -jsval nsDOMClassInfo::sScrollMaxY_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOpen_id = JSVAL_VOID; -jsval nsDOMClassInfo::sItem_id = JSVAL_VOID; -jsval nsDOMClassInfo::sNamedItem_id = JSVAL_VOID; -jsval nsDOMClassInfo::sEnumerate_id = JSVAL_VOID; -jsval nsDOMClassInfo::sNavigator_id = JSVAL_VOID; -jsval nsDOMClassInfo::sDocument_id = JSVAL_VOID; -jsval nsDOMClassInfo::sWindow_id = JSVAL_VOID; -jsval nsDOMClassInfo::sFrames_id = JSVAL_VOID; -jsval nsDOMClassInfo::sSelf_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOpener_id = JSVAL_VOID; -jsval nsDOMClassInfo::sAll_id = JSVAL_VOID; -jsval nsDOMClassInfo::sTags_id = JSVAL_VOID; -jsval nsDOMClassInfo::sAddEventListener_id= JSVAL_VOID; -jsval nsDOMClassInfo::sBaseURIObject_id = JSVAL_VOID; -jsval nsDOMClassInfo::sNodePrincipal_id = JSVAL_VOID; -jsval nsDOMClassInfo::sDocumentURIObject_id=JSVAL_VOID; -jsval nsDOMClassInfo::sOncopy_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOncut_id = JSVAL_VOID; -jsval nsDOMClassInfo::sOnpaste_id = JSVAL_VOID; -jsval nsDOMClassInfo::sJava_id = JSVAL_VOID; -jsval nsDOMClassInfo::sPackages_id = JSVAL_VOID; +jsid nsDOMClassInfo::sTop_id = JSID_VOID; +jsid nsDOMClassInfo::sParent_id = JSID_VOID; +jsid nsDOMClassInfo::sScrollbars_id = JSID_VOID; +jsid nsDOMClassInfo::sLocation_id = JSID_VOID; +jsid nsDOMClassInfo::sConstructor_id = JSID_VOID; +jsid nsDOMClassInfo::s_content_id = JSID_VOID; +jsid nsDOMClassInfo::sContent_id = JSID_VOID; +jsid nsDOMClassInfo::sMenubar_id = JSID_VOID; +jsid nsDOMClassInfo::sToolbar_id = JSID_VOID; +jsid nsDOMClassInfo::sLocationbar_id = JSID_VOID; +jsid nsDOMClassInfo::sPersonalbar_id = JSID_VOID; +jsid nsDOMClassInfo::sStatusbar_id = JSID_VOID; +jsid nsDOMClassInfo::sDialogArguments_id = JSID_VOID; +jsid nsDOMClassInfo::sControllers_id = JSID_VOID; +jsid nsDOMClassInfo::sLength_id = JSID_VOID; +jsid nsDOMClassInfo::sInnerHeight_id = JSID_VOID; +jsid nsDOMClassInfo::sInnerWidth_id = JSID_VOID; +jsid nsDOMClassInfo::sOuterHeight_id = JSID_VOID; +jsid nsDOMClassInfo::sOuterWidth_id = JSID_VOID; +jsid nsDOMClassInfo::sScreenX_id = JSID_VOID; +jsid nsDOMClassInfo::sScreenY_id = JSID_VOID; +jsid nsDOMClassInfo::sStatus_id = JSID_VOID; +jsid nsDOMClassInfo::sName_id = JSID_VOID; +jsid nsDOMClassInfo::sOnmousedown_id = JSID_VOID; +jsid nsDOMClassInfo::sOnmouseup_id = JSID_VOID; +jsid nsDOMClassInfo::sOnclick_id = JSID_VOID; +jsid nsDOMClassInfo::sOndblclick_id = JSID_VOID; +jsid nsDOMClassInfo::sOncontextmenu_id = JSID_VOID; +jsid nsDOMClassInfo::sOnmouseover_id = JSID_VOID; +jsid nsDOMClassInfo::sOnmouseout_id = JSID_VOID; +jsid nsDOMClassInfo::sOnkeydown_id = JSID_VOID; +jsid nsDOMClassInfo::sOnkeyup_id = JSID_VOID; +jsid nsDOMClassInfo::sOnkeypress_id = JSID_VOID; +jsid nsDOMClassInfo::sOnmousemove_id = JSID_VOID; +jsid nsDOMClassInfo::sOnfocus_id = JSID_VOID; +jsid nsDOMClassInfo::sOnblur_id = JSID_VOID; +jsid nsDOMClassInfo::sOnsubmit_id = JSID_VOID; +jsid nsDOMClassInfo::sOnreset_id = JSID_VOID; +jsid nsDOMClassInfo::sOnchange_id = JSID_VOID; +jsid nsDOMClassInfo::sOnselect_id = JSID_VOID; +jsid nsDOMClassInfo::sOnload_id = JSID_VOID; +jsid nsDOMClassInfo::sOnpopstate_id = JSID_VOID; +jsid nsDOMClassInfo::sOnbeforeunload_id = JSID_VOID; +jsid nsDOMClassInfo::sOnunload_id = JSID_VOID; +jsid nsDOMClassInfo::sOnhashchange_id = JSID_VOID; +jsid nsDOMClassInfo::sOnreadystatechange_id = JSID_VOID; +jsid nsDOMClassInfo::sOnpageshow_id = JSID_VOID; +jsid nsDOMClassInfo::sOnpagehide_id = JSID_VOID; +jsid nsDOMClassInfo::sOnabort_id = JSID_VOID; +jsid nsDOMClassInfo::sOnerror_id = JSID_VOID; +jsid nsDOMClassInfo::sOnpaint_id = JSID_VOID; +jsid nsDOMClassInfo::sOnresize_id = JSID_VOID; +jsid nsDOMClassInfo::sOnscroll_id = JSID_VOID; +jsid nsDOMClassInfo::sOndrag_id = JSID_VOID; +jsid nsDOMClassInfo::sOndragend_id = JSID_VOID; +jsid nsDOMClassInfo::sOndragenter_id = JSID_VOID; +jsid nsDOMClassInfo::sOndragleave_id = JSID_VOID; +jsid nsDOMClassInfo::sOndragover_id = JSID_VOID; +jsid nsDOMClassInfo::sOndragstart_id = JSID_VOID; +jsid nsDOMClassInfo::sOndrop_id = JSID_VOID; +jsid nsDOMClassInfo::sScrollX_id = JSID_VOID; +jsid nsDOMClassInfo::sScrollY_id = JSID_VOID; +jsid nsDOMClassInfo::sScrollMaxX_id = JSID_VOID; +jsid nsDOMClassInfo::sScrollMaxY_id = JSID_VOID; +jsid nsDOMClassInfo::sOpen_id = JSID_VOID; +jsid nsDOMClassInfo::sItem_id = JSID_VOID; +jsid nsDOMClassInfo::sNamedItem_id = JSID_VOID; +jsid nsDOMClassInfo::sEnumerate_id = JSID_VOID; +jsid nsDOMClassInfo::sNavigator_id = JSID_VOID; +jsid nsDOMClassInfo::sDocument_id = JSID_VOID; +jsid nsDOMClassInfo::sWindow_id = JSID_VOID; +jsid nsDOMClassInfo::sFrames_id = JSID_VOID; +jsid nsDOMClassInfo::sSelf_id = JSID_VOID; +jsid nsDOMClassInfo::sOpener_id = JSID_VOID; +jsid nsDOMClassInfo::sAll_id = JSID_VOID; +jsid nsDOMClassInfo::sTags_id = JSID_VOID; +jsid nsDOMClassInfo::sAddEventListener_id= JSID_VOID; +jsid nsDOMClassInfo::sBaseURIObject_id = JSID_VOID; +jsid nsDOMClassInfo::sNodePrincipal_id = JSID_VOID; +jsid nsDOMClassInfo::sDocumentURIObject_id=JSID_VOID; +jsid nsDOMClassInfo::sOncopy_id = JSID_VOID; +jsid nsDOMClassInfo::sOncut_id = JSID_VOID; +jsid nsDOMClassInfo::sOnpaste_id = JSID_VOID; +jsid nsDOMClassInfo::sJava_id = JSID_VOID; +jsid nsDOMClassInfo::sPackages_id = JSID_VOID; static const JSClass *sObjectClass = nsnull; JSPropertyOp nsDOMClassInfo::sXPCNativeWrapperGetPropertyOp = nsnull; @@ -1604,7 +1604,7 @@ FindObjectClass(JSObject* aGlobalObject) proto = obj->getProto(); } while (proto); - sObjectClass = obj->getClass(); + sObjectClass = obj->getJSClass(); } static void @@ -1672,16 +1672,15 @@ PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty) } } -static jsval -GetInternedJSVal(JSContext *cx, const char *str) +static inline JSString * +IdToString(JSContext *cx, jsid id) { - JSString *s = ::JS_InternString(cx, str); - - if (!s) { - return JSVAL_VOID; - } - - return STRING_TO_JSVAL(s); + if (JSID_IS_STRING(id)) + return JSID_TO_STRING(id); + jsval idval; + if (!::JS_IdToValue(cx, id, &idval)) + return nsnull; + return JS_ValueToString(cx, idval); } // static @@ -1695,99 +1694,99 @@ nsDOMClassInfo::GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj) nsresult nsDOMClassInfo::DefineStaticJSVals(JSContext *cx) { -#define SET_JSVAL_TO_STRING(_val, _cx, _str) \ - _val = GetInternedJSVal(_cx, _str); \ - if (!JSVAL_IS_STRING(_val)) { \ - return NS_ERROR_OUT_OF_MEMORY; \ - } +#define SET_JSID_TO_STRING(_id, _cx, _str) \ + if (JSString *str = ::JS_InternString(_cx, _str)) \ + _id = INTERNED_STRING_TO_JSID(str); \ + else \ + return NS_ERROR_OUT_OF_MEMORY; JSAutoRequest ar(cx); - SET_JSVAL_TO_STRING(sTop_id, cx, "top"); - SET_JSVAL_TO_STRING(sParent_id, cx, "parent"); - SET_JSVAL_TO_STRING(sScrollbars_id, cx, "scrollbars"); - SET_JSVAL_TO_STRING(sLocation_id, cx, "location"); - SET_JSVAL_TO_STRING(sConstructor_id, cx, "constructor"); - SET_JSVAL_TO_STRING(s_content_id, cx, "_content"); - SET_JSVAL_TO_STRING(sContent_id, cx, "content"); - SET_JSVAL_TO_STRING(sMenubar_id, cx, "menubar"); - SET_JSVAL_TO_STRING(sToolbar_id, cx, "toolbar"); - SET_JSVAL_TO_STRING(sLocationbar_id, cx, "locationbar"); - SET_JSVAL_TO_STRING(sPersonalbar_id, cx, "personalbar"); - SET_JSVAL_TO_STRING(sStatusbar_id, cx, "statusbar"); - SET_JSVAL_TO_STRING(sDialogArguments_id, cx, "dialogArguments"); - SET_JSVAL_TO_STRING(sControllers_id, cx, "controllers"); - SET_JSVAL_TO_STRING(sLength_id, cx, "length"); - SET_JSVAL_TO_STRING(sInnerHeight_id, cx, "innerHeight"); - SET_JSVAL_TO_STRING(sInnerWidth_id, cx, "innerWidth"); - SET_JSVAL_TO_STRING(sOuterHeight_id, cx, "outerHeight"); - SET_JSVAL_TO_STRING(sOuterWidth_id, cx, "outerWidth"); - SET_JSVAL_TO_STRING(sScreenX_id, cx, "screenX"); - SET_JSVAL_TO_STRING(sScreenY_id, cx, "screenY"); - SET_JSVAL_TO_STRING(sStatus_id, cx, "status"); - SET_JSVAL_TO_STRING(sName_id, cx, "name"); - SET_JSVAL_TO_STRING(sOnmousedown_id, cx, "onmousedown"); - SET_JSVAL_TO_STRING(sOnmouseup_id, cx, "onmouseup"); - SET_JSVAL_TO_STRING(sOnclick_id, cx, "onclick"); - SET_JSVAL_TO_STRING(sOndblclick_id, cx, "ondblclick"); - SET_JSVAL_TO_STRING(sOncontextmenu_id, cx, "oncontextmenu"); - SET_JSVAL_TO_STRING(sOnmouseover_id, cx, "onmouseover"); - SET_JSVAL_TO_STRING(sOnmouseout_id, cx, "onmouseout"); - SET_JSVAL_TO_STRING(sOnkeydown_id, cx, "onkeydown"); - SET_JSVAL_TO_STRING(sOnkeyup_id, cx, "onkeyup"); - SET_JSVAL_TO_STRING(sOnkeypress_id, cx, "onkeypress"); - SET_JSVAL_TO_STRING(sOnmousemove_id, cx, "onmousemove"); - SET_JSVAL_TO_STRING(sOnfocus_id, cx, "onfocus"); - SET_JSVAL_TO_STRING(sOnblur_id, cx, "onblur"); - SET_JSVAL_TO_STRING(sOnsubmit_id, cx, "onsubmit"); - SET_JSVAL_TO_STRING(sOnreset_id, cx, "onreset"); - SET_JSVAL_TO_STRING(sOnchange_id, cx, "onchange"); - SET_JSVAL_TO_STRING(sOnselect_id, cx, "onselect"); - SET_JSVAL_TO_STRING(sOnload_id, cx, "onload"); - SET_JSVAL_TO_STRING(sOnpopstate_id, cx, "onpopstate"); - SET_JSVAL_TO_STRING(sOnbeforeunload_id, cx, "onbeforeunload"); - SET_JSVAL_TO_STRING(sOnunload_id, cx, "onunload"); - SET_JSVAL_TO_STRING(sOnhashchange_id, cx, "onhashchange"); - SET_JSVAL_TO_STRING(sOnreadystatechange_id, cx, "onreadystatechange"); - SET_JSVAL_TO_STRING(sOnpageshow_id, cx, "onpageshow"); - SET_JSVAL_TO_STRING(sOnpagehide_id, cx, "onpagehide"); - SET_JSVAL_TO_STRING(sOnabort_id, cx, "onabort"); - SET_JSVAL_TO_STRING(sOnerror_id, cx, "onerror"); - SET_JSVAL_TO_STRING(sOnpaint_id, cx, "onpaint"); - SET_JSVAL_TO_STRING(sOnresize_id, cx, "onresize"); - SET_JSVAL_TO_STRING(sOnscroll_id, cx, "onscroll"); - SET_JSVAL_TO_STRING(sOndrag_id, cx, "ondrag"); - SET_JSVAL_TO_STRING(sOndragend_id, cx, "ondragend"); - SET_JSVAL_TO_STRING(sOndragenter_id, cx, "ondragenter"); - SET_JSVAL_TO_STRING(sOndragleave_id, cx, "ondragleave"); - SET_JSVAL_TO_STRING(sOndragover_id, cx, "ondragover"); - SET_JSVAL_TO_STRING(sOndragstart_id, cx, "ondragstart"); - SET_JSVAL_TO_STRING(sOndrop_id, cx, "ondrop"); - SET_JSVAL_TO_STRING(sScrollX_id, cx, "scrollX"); - SET_JSVAL_TO_STRING(sScrollY_id, cx, "scrollY"); - SET_JSVAL_TO_STRING(sScrollMaxX_id, cx, "scrollMaxX"); - SET_JSVAL_TO_STRING(sScrollMaxY_id, cx, "scrollMaxY"); - SET_JSVAL_TO_STRING(sOpen_id, cx, "open"); - SET_JSVAL_TO_STRING(sItem_id, cx, "item"); - SET_JSVAL_TO_STRING(sNamedItem_id, cx, "namedItem"); - SET_JSVAL_TO_STRING(sEnumerate_id, cx, "enumerateProperties"); - SET_JSVAL_TO_STRING(sNavigator_id, cx, "navigator"); - SET_JSVAL_TO_STRING(sDocument_id, cx, "document"); - SET_JSVAL_TO_STRING(sWindow_id, cx, "window"); - SET_JSVAL_TO_STRING(sFrames_id, cx, "frames"); - SET_JSVAL_TO_STRING(sSelf_id, cx, "self"); - SET_JSVAL_TO_STRING(sOpener_id, cx, "opener"); - SET_JSVAL_TO_STRING(sAll_id, cx, "all"); - SET_JSVAL_TO_STRING(sTags_id, cx, "tags"); - SET_JSVAL_TO_STRING(sAddEventListener_id,cx, "addEventListener"); - SET_JSVAL_TO_STRING(sBaseURIObject_id, cx, "baseURIObject"); - SET_JSVAL_TO_STRING(sNodePrincipal_id, cx, "nodePrincipal"); - SET_JSVAL_TO_STRING(sDocumentURIObject_id,cx,"documentURIObject"); - SET_JSVAL_TO_STRING(sOncopy_id, cx, "oncopy"); - SET_JSVAL_TO_STRING(sOncut_id, cx, "oncut"); - SET_JSVAL_TO_STRING(sOnpaste_id, cx, "onpaste"); - SET_JSVAL_TO_STRING(sJava_id, cx, "java"); - SET_JSVAL_TO_STRING(sPackages_id, cx, "Packages"); + SET_JSID_TO_STRING(sTop_id, cx, "top"); + SET_JSID_TO_STRING(sParent_id, cx, "parent"); + SET_JSID_TO_STRING(sScrollbars_id, cx, "scrollbars"); + SET_JSID_TO_STRING(sLocation_id, cx, "location"); + SET_JSID_TO_STRING(sConstructor_id, cx, "constructor"); + SET_JSID_TO_STRING(s_content_id, cx, "_content"); + SET_JSID_TO_STRING(sContent_id, cx, "content"); + SET_JSID_TO_STRING(sMenubar_id, cx, "menubar"); + SET_JSID_TO_STRING(sToolbar_id, cx, "toolbar"); + SET_JSID_TO_STRING(sLocationbar_id, cx, "locationbar"); + SET_JSID_TO_STRING(sPersonalbar_id, cx, "personalbar"); + SET_JSID_TO_STRING(sStatusbar_id, cx, "statusbar"); + SET_JSID_TO_STRING(sDialogArguments_id, cx, "dialogArguments"); + SET_JSID_TO_STRING(sControllers_id, cx, "controllers"); + SET_JSID_TO_STRING(sLength_id, cx, "length"); + SET_JSID_TO_STRING(sInnerHeight_id, cx, "innerHeight"); + SET_JSID_TO_STRING(sInnerWidth_id, cx, "innerWidth"); + SET_JSID_TO_STRING(sOuterHeight_id, cx, "outerHeight"); + SET_JSID_TO_STRING(sOuterWidth_id, cx, "outerWidth"); + SET_JSID_TO_STRING(sScreenX_id, cx, "screenX"); + SET_JSID_TO_STRING(sScreenY_id, cx, "screenY"); + SET_JSID_TO_STRING(sStatus_id, cx, "status"); + SET_JSID_TO_STRING(sName_id, cx, "name"); + SET_JSID_TO_STRING(sOnmousedown_id, cx, "onmousedown"); + SET_JSID_TO_STRING(sOnmouseup_id, cx, "onmouseup"); + SET_JSID_TO_STRING(sOnclick_id, cx, "onclick"); + SET_JSID_TO_STRING(sOndblclick_id, cx, "ondblclick"); + SET_JSID_TO_STRING(sOncontextmenu_id, cx, "oncontextmenu"); + SET_JSID_TO_STRING(sOnmouseover_id, cx, "onmouseover"); + SET_JSID_TO_STRING(sOnmouseout_id, cx, "onmouseout"); + SET_JSID_TO_STRING(sOnkeydown_id, cx, "onkeydown"); + SET_JSID_TO_STRING(sOnkeyup_id, cx, "onkeyup"); + SET_JSID_TO_STRING(sOnkeypress_id, cx, "onkeypress"); + SET_JSID_TO_STRING(sOnmousemove_id, cx, "onmousemove"); + SET_JSID_TO_STRING(sOnfocus_id, cx, "onfocus"); + SET_JSID_TO_STRING(sOnblur_id, cx, "onblur"); + SET_JSID_TO_STRING(sOnsubmit_id, cx, "onsubmit"); + SET_JSID_TO_STRING(sOnreset_id, cx, "onreset"); + SET_JSID_TO_STRING(sOnchange_id, cx, "onchange"); + SET_JSID_TO_STRING(sOnselect_id, cx, "onselect"); + SET_JSID_TO_STRING(sOnload_id, cx, "onload"); + SET_JSID_TO_STRING(sOnpopstate_id, cx, "onpopstate"); + SET_JSID_TO_STRING(sOnbeforeunload_id, cx, "onbeforeunload"); + SET_JSID_TO_STRING(sOnunload_id, cx, "onunload"); + SET_JSID_TO_STRING(sOnhashchange_id, cx, "onhashchange"); + SET_JSID_TO_STRING(sOnreadystatechange_id, cx, "onreadystatechange"); + SET_JSID_TO_STRING(sOnpageshow_id, cx, "onpageshow"); + SET_JSID_TO_STRING(sOnpagehide_id, cx, "onpagehide"); + SET_JSID_TO_STRING(sOnabort_id, cx, "onabort"); + SET_JSID_TO_STRING(sOnerror_id, cx, "onerror"); + SET_JSID_TO_STRING(sOnpaint_id, cx, "onpaint"); + SET_JSID_TO_STRING(sOnresize_id, cx, "onresize"); + SET_JSID_TO_STRING(sOnscroll_id, cx, "onscroll"); + SET_JSID_TO_STRING(sOndrag_id, cx, "ondrag"); + SET_JSID_TO_STRING(sOndragend_id, cx, "ondragend"); + SET_JSID_TO_STRING(sOndragenter_id, cx, "ondragenter"); + SET_JSID_TO_STRING(sOndragleave_id, cx, "ondragleave"); + SET_JSID_TO_STRING(sOndragover_id, cx, "ondragover"); + SET_JSID_TO_STRING(sOndragstart_id, cx, "ondragstart"); + SET_JSID_TO_STRING(sOndrop_id, cx, "ondrop"); + SET_JSID_TO_STRING(sScrollX_id, cx, "scrollX"); + SET_JSID_TO_STRING(sScrollY_id, cx, "scrollY"); + SET_JSID_TO_STRING(sScrollMaxX_id, cx, "scrollMaxX"); + SET_JSID_TO_STRING(sScrollMaxY_id, cx, "scrollMaxY"); + SET_JSID_TO_STRING(sOpen_id, cx, "open"); + SET_JSID_TO_STRING(sItem_id, cx, "item"); + SET_JSID_TO_STRING(sNamedItem_id, cx, "namedItem"); + SET_JSID_TO_STRING(sEnumerate_id, cx, "enumerateProperties"); + SET_JSID_TO_STRING(sNavigator_id, cx, "navigator"); + SET_JSID_TO_STRING(sDocument_id, cx, "document"); + SET_JSID_TO_STRING(sWindow_id, cx, "window"); + SET_JSID_TO_STRING(sFrames_id, cx, "frames"); + SET_JSID_TO_STRING(sSelf_id, cx, "self"); + SET_JSID_TO_STRING(sOpener_id, cx, "opener"); + SET_JSID_TO_STRING(sAll_id, cx, "all"); + SET_JSID_TO_STRING(sTags_id, cx, "tags"); + SET_JSID_TO_STRING(sAddEventListener_id,cx, "addEventListener"); + SET_JSID_TO_STRING(sBaseURIObject_id, cx, "baseURIObject"); + SET_JSID_TO_STRING(sNodePrincipal_id, cx, "nodePrincipal"); + SET_JSID_TO_STRING(sDocumentURIObject_id,cx,"documentURIObject"); + SET_JSID_TO_STRING(sOncopy_id, cx, "oncopy"); + SET_JSID_TO_STRING(sOncut_id, cx, "oncut"); + SET_JSID_TO_STRING(sOnpaste_id, cx, "onpaste"); + SET_JSID_TO_STRING(sJava_id, cx, "java"); + SET_JSID_TO_STRING(sPackages_id, cx, "Packages"); return NS_OK; } @@ -1862,7 +1861,7 @@ nsDOMClassInfo::ObjectIsNativeWrapper(JSContext* cx, JSObject* obj) } #endif - JSPropertyOp op = obj->getClass()->getProperty; + JSPropertyOp op = obj->getJSClass()->getProperty; return !!op && (op == sXPCNativeWrapperGetPropertyOp || op == sXrayWrapperPropertyHolderGetPropertyOp); } @@ -4102,24 +4101,25 @@ nsDOMClassInfo::Init() // static PRInt32 -nsDOMClassInfo::GetArrayIndexFromId(JSContext *cx, jsval id, PRBool *aIsNumber) +nsDOMClassInfo::GetArrayIndexFromId(JSContext *cx, jsid id, PRBool *aIsNumber) { - jsdouble array_index; - if (aIsNumber) { *aIsNumber = PR_FALSE; } - JSAutoRequest ar(cx); + jsint i; + if (JSID_IS_INT(id)) { + i = JSID_TO_INT(id); + } else { + JSAutoRequest ar(cx); - if (!::JS_ValueToNumber(cx, id, &array_index)) { - return -1; - } - - jsint i = -1; - - if (!::JS_DoubleIsInt32(array_index, &i)) { - return -1; + jsval idval; + jsdouble array_index; + if (!::JS_IdToValue(cx, id, &idval) || + !::JS_ValueToNumber(cx, idval, &array_index) || + !::JS_DoubleIsInt32(array_index, &i)) { + return -1; + } } if (aIsNumber) { @@ -4281,7 +4281,7 @@ nsDOMClassInfo::PostCreate(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsDOMClassInfo::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { NS_WARNING("nsDOMClassInfo::AddProperty Don't call me!"); @@ -4291,7 +4291,7 @@ nsDOMClassInfo::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDOMClassInfo::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { NS_WARNING("nsDOMClassInfo::DelProperty Don't call me!"); @@ -4301,7 +4301,7 @@ nsDOMClassInfo::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDOMClassInfo::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { NS_WARNING("nsDOMClassInfo::GetProperty Don't call me!"); @@ -4311,7 +4311,7 @@ nsDOMClassInfo::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDOMClassInfo::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { NS_WARNING("nsDOMClassInfo::SetProperty Don't call me!"); @@ -4369,10 +4369,8 @@ nsDOMClassInfo::ResolveConstructor(JSContext *cx, JSObject *obj, // window.classname, just fall through and let the JS engine // return the Object constructor. - JSString *str = JSVAL_TO_STRING(sConstructor_id); - if (!::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), val, nsnull, nsnull, - JSPROP_ENUMERATE)) { + if (!::JS_DefinePropertyById(cx, obj, sConstructor_id, val, nsnull, nsnull, + JSPROP_ENUMERATE)) { return NS_ERROR_UNEXPECTED; } @@ -4384,7 +4382,7 @@ nsDOMClassInfo::ResolveConstructor(JSContext *cx, JSObject *obj, NS_IMETHODIMP nsDOMClassInfo::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { if (id == sConstructor_id && !(flags & JSRESOLVE_ASSIGNING)) { @@ -4415,7 +4413,7 @@ nsDOMClassInfo::Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDOMClassInfo::CheckAccess(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 mode, + JSObject *obj, jsid id, PRUint32 mode, jsval *vp, PRBool *_retval) { PRUint32 mode_type = mode & JSACC_TYPEMASK; @@ -4470,7 +4468,7 @@ nsDOMClassInfo::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDOMClassInfo::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval val, PRBool *bp, + JSObject *obj, const jsval &val, PRBool *bp, PRBool *_retval) { NS_WARNING("nsDOMClassInfo::HasInstance Don't call me!"); @@ -4489,7 +4487,7 @@ nsDOMClassInfo::Trace(nsIXPConnectWrappedNative *wrapper, JSTracer *trc, NS_IMETHODIMP nsDOMClassInfo::Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx, - JSObject * obj, jsval val, PRBool *bp) + JSObject * obj, const jsval &val, PRBool *bp) { NS_WARNING("nsDOMClassInfo::Equality Don't call me!"); @@ -4733,89 +4731,89 @@ nsDOMClassInfo::ShutDown() } } - sTop_id = JSVAL_VOID; - sParent_id = JSVAL_VOID; - sScrollbars_id = JSVAL_VOID; - sLocation_id = JSVAL_VOID; - sConstructor_id = JSVAL_VOID; - s_content_id = JSVAL_VOID; - sContent_id = JSVAL_VOID; - sMenubar_id = JSVAL_VOID; - sToolbar_id = JSVAL_VOID; - sLocationbar_id = JSVAL_VOID; - sPersonalbar_id = JSVAL_VOID; - sStatusbar_id = JSVAL_VOID; - sDialogArguments_id = JSVAL_VOID; - sControllers_id = JSVAL_VOID; - sLength_id = JSVAL_VOID; - sInnerHeight_id = JSVAL_VOID; - sInnerWidth_id = JSVAL_VOID; - sOuterHeight_id = JSVAL_VOID; - sOuterWidth_id = JSVAL_VOID; - sScreenX_id = JSVAL_VOID; - sScreenY_id = JSVAL_VOID; - sStatus_id = JSVAL_VOID; - sName_id = JSVAL_VOID; - sOnmousedown_id = JSVAL_VOID; - sOnmouseup_id = JSVAL_VOID; - sOnclick_id = JSVAL_VOID; - sOndblclick_id = JSVAL_VOID; - sOncontextmenu_id = JSVAL_VOID; - sOnmouseover_id = JSVAL_VOID; - sOnmouseout_id = JSVAL_VOID; - sOnkeydown_id = JSVAL_VOID; - sOnkeyup_id = JSVAL_VOID; - sOnkeypress_id = JSVAL_VOID; - sOnmousemove_id = JSVAL_VOID; - sOnfocus_id = JSVAL_VOID; - sOnblur_id = JSVAL_VOID; - sOnsubmit_id = JSVAL_VOID; - sOnreset_id = JSVAL_VOID; - sOnchange_id = JSVAL_VOID; - sOnselect_id = JSVAL_VOID; - sOnload_id = JSVAL_VOID; - sOnbeforeunload_id = JSVAL_VOID; - sOnunload_id = JSVAL_VOID; - sOnhashchange_id = JSVAL_VOID; - sOnreadystatechange_id = JSVAL_VOID; - sOnpageshow_id = JSVAL_VOID; - sOnpagehide_id = JSVAL_VOID; - sOnabort_id = JSVAL_VOID; - sOnerror_id = JSVAL_VOID; - sOnpaint_id = JSVAL_VOID; - sOnresize_id = JSVAL_VOID; - sOnscroll_id = JSVAL_VOID; - sOndrag_id = JSVAL_VOID; - sOndragend_id = JSVAL_VOID; - sOndragenter_id = JSVAL_VOID; - sOndragleave_id = JSVAL_VOID; - sOndragover_id = JSVAL_VOID; - sOndragstart_id = JSVAL_VOID; - sOndrop_id = JSVAL_VOID; - sScrollX_id = JSVAL_VOID; - sScrollY_id = JSVAL_VOID; - sScrollMaxX_id = JSVAL_VOID; - sScrollMaxY_id = JSVAL_VOID; - sOpen_id = JSVAL_VOID; - sItem_id = JSVAL_VOID; - sEnumerate_id = JSVAL_VOID; - sNavigator_id = JSVAL_VOID; - sDocument_id = JSVAL_VOID; - sWindow_id = JSVAL_VOID; - sFrames_id = JSVAL_VOID; - sSelf_id = JSVAL_VOID; - sOpener_id = JSVAL_VOID; - sAll_id = JSVAL_VOID; - sTags_id = JSVAL_VOID; - sAddEventListener_id= JSVAL_VOID; - sBaseURIObject_id = JSVAL_VOID; - sNodePrincipal_id = JSVAL_VOID; - sDocumentURIObject_id=JSVAL_VOID; - sOncopy_id = JSVAL_VOID; - sOncut_id = JSVAL_VOID; - sOnpaste_id = JSVAL_VOID; - sJava_id = JSVAL_VOID; - sPackages_id = JSVAL_VOID; + sTop_id = JSID_VOID; + sParent_id = JSID_VOID; + sScrollbars_id = JSID_VOID; + sLocation_id = JSID_VOID; + sConstructor_id = JSID_VOID; + s_content_id = JSID_VOID; + sContent_id = JSID_VOID; + sMenubar_id = JSID_VOID; + sToolbar_id = JSID_VOID; + sLocationbar_id = JSID_VOID; + sPersonalbar_id = JSID_VOID; + sStatusbar_id = JSID_VOID; + sDialogArguments_id = JSID_VOID; + sControllers_id = JSID_VOID; + sLength_id = JSID_VOID; + sInnerHeight_id = JSID_VOID; + sInnerWidth_id = JSID_VOID; + sOuterHeight_id = JSID_VOID; + sOuterWidth_id = JSID_VOID; + sScreenX_id = JSID_VOID; + sScreenY_id = JSID_VOID; + sStatus_id = JSID_VOID; + sName_id = JSID_VOID; + sOnmousedown_id = JSID_VOID; + sOnmouseup_id = JSID_VOID; + sOnclick_id = JSID_VOID; + sOndblclick_id = JSID_VOID; + sOncontextmenu_id = JSID_VOID; + sOnmouseover_id = JSID_VOID; + sOnmouseout_id = JSID_VOID; + sOnkeydown_id = JSID_VOID; + sOnkeyup_id = JSID_VOID; + sOnkeypress_id = JSID_VOID; + sOnmousemove_id = JSID_VOID; + sOnfocus_id = JSID_VOID; + sOnblur_id = JSID_VOID; + sOnsubmit_id = JSID_VOID; + sOnreset_id = JSID_VOID; + sOnchange_id = JSID_VOID; + sOnselect_id = JSID_VOID; + sOnload_id = JSID_VOID; + sOnbeforeunload_id = JSID_VOID; + sOnunload_id = JSID_VOID; + sOnhashchange_id = JSID_VOID; + sOnreadystatechange_id = JSID_VOID; + sOnpageshow_id = JSID_VOID; + sOnpagehide_id = JSID_VOID; + sOnabort_id = JSID_VOID; + sOnerror_id = JSID_VOID; + sOnpaint_id = JSID_VOID; + sOnresize_id = JSID_VOID; + sOnscroll_id = JSID_VOID; + sOndrag_id = JSID_VOID; + sOndragend_id = JSID_VOID; + sOndragenter_id = JSID_VOID; + sOndragleave_id = JSID_VOID; + sOndragover_id = JSID_VOID; + sOndragstart_id = JSID_VOID; + sOndrop_id = JSID_VOID; + sScrollX_id = JSID_VOID; + sScrollY_id = JSID_VOID; + sScrollMaxX_id = JSID_VOID; + sScrollMaxY_id = JSID_VOID; + sOpen_id = JSID_VOID; + sItem_id = JSID_VOID; + sEnumerate_id = JSID_VOID; + sNavigator_id = JSID_VOID; + sDocument_id = JSID_VOID; + sWindow_id = JSID_VOID; + sFrames_id = JSID_VOID; + sSelf_id = JSID_VOID; + sOpener_id = JSID_VOID; + sAll_id = JSID_VOID; + sTags_id = JSID_VOID; + sAddEventListener_id= JSID_VOID; + sBaseURIObject_id = JSID_VOID; + sNodePrincipal_id = JSID_VOID; + sDocumentURIObject_id=JSID_VOID; + sOncopy_id = JSID_VOID; + sOncut_id = JSID_VOID; + sOnpaste_id = JSID_VOID; + sJava_id = JSID_VOID; + sPackages_id = JSID_VOID; NS_IF_RELEASE(sXPConnect); NS_IF_RELEASE(sSecMan); @@ -4879,7 +4877,7 @@ static JSClass sGlobalScopePolluterClass = { // static JSBool nsWindowSH::GlobalScopePolluterGetProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp) + jsid id, jsval *vp) { // Someone is accessing a element by referencing its name/id in the // global scope, do a security check to make sure that's ok. @@ -4905,7 +4903,7 @@ nsWindowSH::GlobalScopePolluterGetProperty(JSContext *cx, JSObject *obj, // static JSBool -nsWindowSH::SecurityCheckOnSetProp(JSContext *cx, JSObject *obj, jsval id, +nsWindowSH::SecurityCheckOnSetProp(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { // Someone is accessing a element by referencing its name/id in the @@ -4924,12 +4922,12 @@ nsWindowSH::SecurityCheckOnSetProp(JSContext *cx, JSObject *obj, jsval id, // static JSBool nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj, - jsval id, uintN flags, + jsid id, uintN flags, JSObject **objp) { if (flags & (JSRESOLVE_ASSIGNING | JSRESOLVE_DECLARING | JSRESOLVE_CLASSNAME | JSRESOLVE_QUALIFIED) || - !JSVAL_IS_STRING(id)) { + !JSID_IS_STRING(id)) { // Nothing to do here if we're either assigning or declaring, // resolving a class name, doing a qualified resolve, or // resolving a number. @@ -4949,11 +4947,10 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj, } JSObject *proto = ::JS_GetPrototype(cx, obj); - JSString *jsstr = JSVAL_TO_STRING(id); + JSString *jsstr = JSID_TO_STRING(id); JSBool hasProp; - if (!proto || !::JS_HasUCProperty(cx, proto, ::JS_GetStringChars(jsstr), - ::JS_GetStringLength(jsstr), &hasProp) || + if (!proto || !::JS_HasPropertyById(cx, proto, id, &hasProp) || hasProp) { // No prototype, or the property exists on the prototype. Do // nothing. @@ -4975,9 +4972,7 @@ nsWindowSH::GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj, getter_AddRefs(holder)); NS_ENSURE_SUCCESS(rv, JS_FALSE); - if (!::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(jsstr), - ::JS_GetStringLength(jsstr), v, nsnull, nsnull, - 0)) { + if (!::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, 0)) { nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_UNEXPECTED); return JS_FALSE; @@ -5071,7 +5066,7 @@ nsWindowSH::InstallGlobalScopePolluter(JSContext *cx, JSObject *obj, static already_AddRefed -GetChildFrame(nsGlobalWindow *win, jsval id) +GetChildFrame(nsGlobalWindow *win, jsid id) { nsCOMPtr frames; win->GetFrames(getter_AddRefs(frames)); @@ -5079,7 +5074,7 @@ GetChildFrame(nsGlobalWindow *win, jsval id) nsIDOMWindow *frame = nsnull; if (frames) { - frames->Item(JSVAL_TO_INT(id), &frame); + frames->Item(JSID_TO_INT(id), &frame); } return frame; @@ -5087,7 +5082,7 @@ GetChildFrame(nsGlobalWindow *win, jsval id) NS_IMETHODIMP nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper); @@ -5127,13 +5122,10 @@ nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, #endif // Forward the get to the inner object - if (JSVAL_IS_STRING(id)) { - JSString *str = JSVAL_TO_STRING(id); - - *_retval = ::JS_GetUCProperty(cx, innerObj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), vp); - } else if (JSVAL_IS_INT(id)) { - *_retval = ::JS_GetElement(cx, innerObj, JSVAL_TO_INT(id), vp); + if (JSID_IS_STRING(id)) { + *_retval = ::JS_GetPropertyById(cx, innerObj, id, vp); + } else if (JSID_IS_INT(id)) { + *_retval = ::JS_GetElement(cx, innerObj, JSID_TO_INT(id), vp); } else { NS_ERROR("Write me!"); @@ -5148,7 +5140,7 @@ nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // whacky, that's because this method is *extremely* performace // critical. Don't touch this unless you know what you're doing. - if (JSVAL_IS_INT(id)) { + if (JSID_IS_INT(id)) { // If we're accessing a numeric property we'll treat that as if // window.frames[n] is accessed (since window.frames === window), // if window.frames[n] is a child frame, wrap the frame and return @@ -5184,7 +5176,7 @@ nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING; } - if (JSVAL_IS_STRING(id) && !JSVAL_IS_PRIMITIVE(*vp) && + if (JSID_IS_STRING(id) && !JSVAL_IS_PRIMITIVE(*vp) && ::JS_TypeOfValue(cx, *vp) != JSTYPE_FUNCTION) { // A named property accessed which could have been resolved to a // child frame in nsWindowSH::NewResolve() (*vp will tell us if @@ -5226,7 +5218,7 @@ nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper); @@ -5261,13 +5253,10 @@ nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, #endif // Forward the set to the inner object - if (JSVAL_IS_STRING(id)) { - JSString *str = JSVAL_TO_STRING(id); - - *_retval = ::JS_SetUCProperty(cx, innerObj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), vp); - } else if (JSVAL_IS_INT(id)) { - *_retval = ::JS_SetElement(cx, innerObj, JSVAL_TO_INT(id), vp); + if (JSID_IS_STRING(id)) { + *_retval = ::JS_SetPropertyById(cx, innerObj, id, vp); + } else if (JSID_IS_INT(id)) { + *_retval = ::JS_SetElement(cx, innerObj, JSID_TO_INT(id), vp); } else { NS_ERROR("Write me!"); @@ -5306,7 +5295,7 @@ nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsWindowSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper); @@ -5345,21 +5334,15 @@ nsWindowSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, printf(" --- Forwarding add to inner window %p\n", (void *)innerWin); #endif - jsid interned_id; - if (!JS_ValueToId(cx, id, &interned_id)) { - *_retval = JS_FALSE; - return NS_OK; - } - JSPropertyDescriptor desc; - if (!JS_GetPropertyDescriptorById(cx, obj, interned_id, + if (!JS_GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, &desc)) { *_retval = JS_FALSE; return NS_OK; } // Forward the add to the inner object - *_retval = JS_DefinePropertyById(cx, innerObj, interned_id, *vp, + *_retval = JS_DefinePropertyById(cx, innerObj, id, *vp, desc.getter, desc.setter, desc.attrs | JSPROP_ENUMERATE); return NS_OK; @@ -5371,7 +5354,7 @@ nsWindowSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsWindowSH::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper); @@ -5405,9 +5388,7 @@ nsWindowSH::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, #endif // Forward the del to the inner object - jsid interned_id; - *_retval = (JS_ValueToId(cx, id, &interned_id) && - JS_DeletePropertyById(cx, innerObj, interned_id)); + *_retval = JS_DeletePropertyById(cx, innerObj, id); return NS_OK; } @@ -5617,15 +5598,12 @@ DefineInterfaceConstants(JSContext *cx, JSObject *obj, const nsIID *aIID) NS_IMETHODIMP nsHTMLBodyElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext - *cx, JSObject *obj, jsval id, PRUint32 flags, + *cx, JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { if (id == sOnhashchange_id) { // Special handling so |"onhashchange" in document.body| returns true. - jsid interned_id; - - if (!JS_ValueToId(cx, id, &interned_id) || - !JS_DefinePropertyById(cx, obj, interned_id, JSVAL_VOID, + if (!JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull, nsnull, JSPROP_ENUMERATE)) { *_retval = PR_FALSE; return NS_ERROR_FAILURE; @@ -5640,16 +5618,12 @@ nsHTMLBodyElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext NS_IMETHODIMP nsHTMLBodyElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { if (id == sOnhashchange_id) { // Forward the request to the Window. - jsid interned_id; - - if (!JS_ValueToId(cx, id, &interned_id) || - !JS_GetPropertyById(cx, JS_GetGlobalForObject(cx, obj), - interned_id, vp)) { + if (!JS_GetPropertyById(cx, JS_GetGlobalForObject(cx, obj), id, vp)) { *_retval = PR_FALSE; return NS_ERROR_FAILURE; } @@ -5663,15 +5637,11 @@ nsHTMLBodyElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsHTMLBodyElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, - jsval id, jsval *vp, PRBool *_retval) + jsid id, jsval *vp, PRBool *_retval) { if (id == sOnhashchange_id) { // Forward the request to the Window. - jsid interned_id; - - if (!JS_ValueToId(cx, id, &interned_id) || - !JS_SetPropertyById(cx, JS_GetGlobalForObject(cx, obj), - interned_id, vp)) { + if (!JS_SetPropertyById(cx, JS_GetGlobalForObject(cx, obj), id, vp)) { *_retval = PR_FALSE; return NS_ERROR_FAILURE; } @@ -5710,7 +5680,7 @@ public: jsval *vp, PRBool *_retval); nsresult HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval val, PRBool *bp, + JSObject *obj, const jsval &val, PRBool *bp, PRBool *_retval); nsresult Install(JSContext *cx, JSObject *target, jsval thisAsVal) @@ -5870,7 +5840,7 @@ nsDOMConstructor::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx, nsresult nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval v, PRBool *bp, PRBool *_retval) + const jsval &v, PRBool *bp, PRBool *_retval) { // No need to look these up in the hash. @@ -6472,7 +6442,7 @@ nsWindowSH::sResolving = PR_FALSE; NS_IMETHODIMP nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper); @@ -6538,12 +6508,9 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, printf(" --- Forwarding resolve to inner window %p\n", (void *)innerWin); #endif - jsid interned_id; JSPropertyDescriptor desc; - *_retval = (JS_ValueToId(cx, id, &interned_id) && - JS_GetPropertyDescriptorById(cx, innerObj, interned_id, - flags, &desc)); + *_retval = JS_GetPropertyDescriptorById(cx, innerObj, id, flags, &desc); if (*_retval && desc.obj) { #ifdef DEBUG_SH_FORWARDING @@ -6566,7 +6533,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, PRBool oldResolving = sResolving; sResolving = PR_TRUE; - *_retval = JS_DefinePropertyById(cx, obj, interned_id, JSVAL_VOID, + *_retval = JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull, nsnull, desc.attrs & JSPROP_ENUMERATE); @@ -6583,8 +6550,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, } } - if (!JSVAL_IS_STRING(id)) { - if (JSVAL_IS_INT(id) && !(flags & JSRESOLVE_ASSIGNING)) { + if (!JSID_IS_STRING(id)) { + if (JSID_IS_INT(id) && !(flags & JSRESOLVE_ASSIGNING)) { // If we're resolving a numeric property, treat that as if // window.frames[n] is resolved (since window.frames === // window), if window.frames[n] is a child frame, define a @@ -6596,7 +6563,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // A numeric property accessed and the numeric property is a // child frame. Define a property for this index. - *_retval = ::JS_DefineElement(cx, obj, JSVAL_TO_INT(id), JSVAL_VOID, + *_retval = ::JS_DefineElement(cx, obj, JSID_TO_INT(id), JSVAL_VOID, nsnull, nsnull, JSPROP_SHARED); if (*_retval) { @@ -6692,7 +6659,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // method on an interface that would let us just call into the // window code directly... - JSString *str = JSVAL_TO_STRING(id); + JSString *str = JSID_TO_STRING(id); // Don't resolve named frames on native wrappers if (!ObjectIsNativeWrapper(cx, obj)) { @@ -6741,10 +6708,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSAutoRequest ar(cx); - PRBool ok = ::JS_DefineUCProperty(cx, obj, chars, - ::JS_GetStringLength(str), - v, nsnull, nsnull, 0); - + PRBool ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, 0); if (!ok) { return NS_ERROR_FAILURE; } @@ -6798,12 +6762,11 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, nsAutoGCRoot root(&funObj, &rv); NS_ENSURE_SUCCESS(rv, rv); - if (!::JS_DefineUCProperty(cx, windowObj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), JSVAL_VOID, - JS_DATA_TO_FUNC_PTR(JSPropertyOp, funObj), - nsnull, - JSPROP_ENUMERATE | JSPROP_GETTER | - JSPROP_SHARED)) { + if (!::JS_DefinePropertyById(cx, windowObj, id, JSVAL_VOID, + JS_DATA_TO_FUNC_PTR(JSPropertyOp, funObj), + nsnull, + JSPROP_ENUMERATE | JSPROP_GETTER | + JSPROP_SHARED)) { return NS_ERROR_FAILURE; } @@ -6862,11 +6825,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSAutoRequest ar(cx); - JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), v, nsnull, - nsnull, - JSPROP_PERMANENT | - JSPROP_ENUMERATE); + JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, + JSPROP_PERMANENT | JSPROP_ENUMERATE); if (!ok) { return NS_ERROR_FAILURE; @@ -6879,10 +6839,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, if (id == sOnhashchange_id) { // Special handling so |"onhashchange" in window| returns true - jsid interned_id; - - if (!JS_ValueToId(cx, id, &interned_id) || - !JS_DefinePropertyById(cx, obj, interned_id, JSVAL_VOID, + if (!JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull, nsnull, JSPROP_ENUMERATE)) { *_retval = PR_FALSE; return NS_ERROR_FAILURE; @@ -6902,10 +6859,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // for compatibility with other browsers. JSAutoRequest ar(cx); - if (!::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), - JSVAL_VOID, JS_PropertyStub, JS_PropertyStub, - JSPROP_ENUMERATE)) { + if (!::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, JS_PropertyStub, + JS_PropertyStub, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } *objp = obj; @@ -6926,10 +6881,9 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSAutoRequest ar(cx); - if (!::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), v, nsnull, nsnull, - JSPROP_READONLY | JSPROP_PERMANENT | - JSPROP_ENUMERATE)) { + if (!::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, + JSPROP_READONLY | JSPROP_PERMANENT | + JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } *objp = obj; @@ -6992,10 +6946,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_ENSURE_SUCCESS(rv, rv); } PRBool ok = - ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), - winVal, JS_PropertyStub, JS_PropertyStub, - JSPROP_READONLY | JSPROP_ENUMERATE); + ::JS_DefinePropertyById(cx, obj, id, winVal, JS_PropertyStub, JS_PropertyStub, + JSPROP_READONLY | JSPROP_ENUMERATE); if (!ok) { return NS_ERROR_FAILURE; @@ -7076,12 +7028,10 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, if (obj == realObj) { JSObject *proto = obj->getProto(); if (proto) { - jsid interned_id; JSObject *pobj = NULL; jsval val; - if (!::JS_ValueToId(cx, id, &interned_id) || - !::JS_LookupPropertyWithFlagsById(cx, proto, interned_id, flags, + if (!::JS_LookupPropertyWithFlagsById(cx, proto, id, flags, &pobj, &val)) { *_retval = JS_FALSE; @@ -7106,13 +7056,11 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // Since we always create the undeclared property here without given a // chance for the interpreter to report applicable strict mode warnings, // we must take care to check those warnings here. - JSString *str = JSVAL_TO_STRING(id); + JSString *str = JSID_TO_STRING(id); if ((!(flags & JSRESOLVE_QUALIFIED) && - !js_CheckUndeclaredVarAssignment(cx, id)) || - !::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), JSVAL_VOID, - JS_PropertyStub, JS_PropertyStub, - JSPROP_ENUMERATE)) { + !js_CheckUndeclaredVarAssignment(cx, str)) || + !::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, JS_PropertyStub, + JS_PropertyStub, JSPROP_ENUMERATE)) { *_retval = JS_FALSE; return NS_OK; @@ -7163,7 +7111,7 @@ nsWindowSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, if (idp) { // Note: With these property iterators, we can't tell ahead of time how // many properties we're going to be iterating over. - *idp = JSVAL_ZERO; + *idp = INT_TO_JSID(0); } break; } @@ -7174,7 +7122,7 @@ nsWindowSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_ERROR_UNEXPECTED; } - if (*idp != JSVAL_VOID) { + if (*idp != JSID_VOID) { break; } @@ -7203,7 +7151,7 @@ nsWindowSH::Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsWindowSH::Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx, - JSObject * obj, jsval val, PRBool *bp) + JSObject * obj, const jsval &val, PRBool *bp) { *bp = PR_FALSE; @@ -7300,7 +7248,7 @@ nsWindowSH::InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, NS_IMETHODIMP nsLocationSH::CheckAccess(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 mode, + JSObject *obj, jsid id, PRUint32 mode, jsval *vp, PRBool *_retval) { if ((mode & JSACC_TYPEMASK) == JSACC_PROTO && (mode & JSACC_WRITE)) { @@ -7405,19 +7353,16 @@ nsNodeSH::IsCapabilityEnabled(const char* aCapability) } nsresult -nsNodeSH::DefineVoidProp(JSContext* cx, JSObject* obj, jsval id, +nsNodeSH::DefineVoidProp(JSContext* cx, JSObject* obj, jsid id, JSObject** objp) { - NS_ASSERTION(JSVAL_IS_STRING(id), "id must be a string"); - - JSString* str = JSVAL_TO_STRING(id); + NS_ASSERTION(JSID_IS_STRING(id), "id must be a string"); // We want this to be as invisible to content script as possible. So // don't enumerate this, and set is as JSPROP_SHARED so it won't get // cached on the object. - JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), JSVAL_VOID, - nsnull, nsnull, JSPROP_SHARED); + JSBool ok = ::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, + nsnull, nsnull, JSPROP_SHARED); if (!ok) { return NS_ERROR_FAILURE; @@ -7568,7 +7513,7 @@ nsNodeSH::PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj, NS_IMETHODIMP nsNodeSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsNodeSH::PreserveWrapper(GetNative(wrapper, obj)); return nsEventReceiverSH::AddProperty(wrapper, cx, obj, id, vp, _retval); @@ -7576,7 +7521,7 @@ nsNodeSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsNodeSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { if ((id == sBaseURIObject_id || id == sNodePrincipal_id) && @@ -7596,7 +7541,7 @@ nsNodeSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsNodeSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { if (id == sBaseURIObject_id && IsPrivilegedScript()) { // I wish GetBaseURI lived on nsINode @@ -7636,7 +7581,7 @@ nsNodeSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsNodeSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { if ((id == sBaseURIObject_id || id == sNodePrincipal_id) && IsPrivilegedScript()) { @@ -7669,7 +7614,7 @@ nsNodeSH::PreserveWrapper(nsISupports *aNative) // static PRBool -nsEventReceiverSH::ReallyIsEventName(jsval id, jschar aFirstChar) +nsEventReceiverSH::ReallyIsEventName(jsid id, jschar aFirstChar) { // I wonder if this is faster than using a hash... @@ -7736,7 +7681,7 @@ nsEventReceiverSH::ReallyIsEventName(jsval id, jschar aFirstChar) nsresult nsEventReceiverSH::RegisterCompileHandler(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, - jsval id, PRBool compile, + jsid id, PRBool compile, PRBool remove, PRBool *did_define) { @@ -7788,10 +7733,10 @@ nsEventReceiverSH::RegisterCompileHandler(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { - if (!JSVAL_IS_STRING(id)) { + if (!JSID_IS_STRING(id)) { return NS_OK; } @@ -7805,21 +7750,16 @@ nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper, // now; the assignment will then set the right value. Only do this // in the case where the property isn't already defined on the // object's prototype chain though. - JSString* str = JSVAL_TO_STRING(id); JSAutoRequest ar(cx); JSObject *proto = ::JS_GetPrototype(cx, obj); PRBool ok = PR_TRUE, hasProp = PR_FALSE; - if (!proto || ((ok = ::JS_HasUCProperty(cx, proto, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), - &hasProp)) && + if (!proto || ((ok = ::JS_HasPropertyById(cx, proto, id, &hasProp)) && !hasProp)) { // Make sure the flags here match those in // nsJSContext::BindCompiledEventHandler - if (!::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), JSVAL_NULL, - nsnull, nsnull, - JSPROP_ENUMERATE | JSPROP_PERMANENT)) { + if (!::JS_DefinePropertyById(cx, obj, id, JSVAL_NULL, nsnull, nsnull, + JSPROP_ENUMERATE | JSPROP_PERMANENT)) { return NS_ERROR_FAILURE; } @@ -7849,13 +7789,13 @@ nsEventReceiverSH::NewResolve(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsEventReceiverSH::SetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { JSAutoRequest ar(cx); if ((::JS_TypeOfValue(cx, *vp) != JSTYPE_FUNCTION && !JSVAL_IS_NULL(*vp)) || - !JSVAL_IS_STRING(id) || id == sAddEventListener_id) { + !JSID_IS_STRING(id) || id == sAddEventListener_id) { return NS_OK; } @@ -7867,7 +7807,7 @@ nsEventReceiverSH::SetProperty(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsEventReceiverSH::AddProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { return nsEventReceiverSH::SetProperty(wrapper, cx, obj, id, vp, _retval); @@ -7892,7 +7832,7 @@ nsEventTargetSH::PreCreate(nsISupports *nativeObj, JSContext *cx, NS_IMETHODIMP nsEventTargetSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { if (id == sAddEventListener_id) { return NS_OK; @@ -8105,7 +8045,7 @@ nsElementSH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsGenericArraySH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { if (id == sLength_id) { @@ -8202,7 +8142,7 @@ nsGenericArraySH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { PRBool is_number = PR_FALSE; PRInt32 n = GetArrayIndexFromId(cx, id, &is_number); @@ -8328,10 +8268,10 @@ nsDOMTokenListSH::GetStringAt(nsISupports *aNative, PRInt32 aIndex, NS_IMETHODIMP nsNamedArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { - if (JSVAL_IS_STRING(id) && !ObjectIsNativeWrapper(cx, obj)) { + if (JSID_IS_STRING(id) && !ObjectIsNativeWrapper(cx, obj)) { nsresult rv = NS_OK; nsISupports* item = GetNamedItem(GetNative(wrapper, obj), nsDependentJSString(id), @@ -8486,7 +8426,7 @@ nsContentListSH::GetNamedItem(nsISupports *aNative, const nsAString& aName, NS_IMETHODIMP nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { nsresult rv; @@ -8511,12 +8451,8 @@ nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSAutoRequest ar(cx); - JSString *str = JSVAL_TO_STRING(id); - JSBool ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), v, nsnull, - nsnull, - JSPROP_PERMANENT | - JSPROP_ENUMERATE); + JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, + JSPROP_PERMANENT | JSPROP_ENUMERATE); if (!ok) { return NS_ERROR_FAILURE; @@ -8536,7 +8472,7 @@ nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { if (id == sDocumentURIObject_id && IsPrivilegedScript()) { nsCOMPtr doc = do_QueryWrappedNative(wrapper); @@ -8557,7 +8493,7 @@ nsDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDocumentSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { if (id == sLocation_id) { nsCOMPtr doc(do_QueryWrappedNative(wrapper)); @@ -8652,7 +8588,7 @@ nsDocumentSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // static nsresult nsHTMLDocumentSH::ResolveImpl(JSContext *cx, - nsIXPConnectWrappedNative *wrapper, jsval id, + nsIXPConnectWrappedNative *wrapper, jsid id, nsISupports **result) { nsHTMLDocument *doc = @@ -8662,7 +8598,7 @@ nsHTMLDocumentSH::ResolveImpl(JSContext *cx, // 'id' is not always a string, it can be a number since document.1 // should map to . Thus we can't use // JSVAL_TO_STRING() here. - JSString *str = JS_ValueToString(cx, id); + JSString *str = IdToString(cx, id); NS_ENSURE_TRUE(str, NS_ERROR_UNEXPECTED); return doc->ResolveName(nsDependentJSString(str), nsnull, result); @@ -8827,7 +8763,7 @@ nsHTMLDocumentSH::GetDocumentAllNodeList(JSContext *cx, JSObject *obj, JSBool nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp) + jsid id, jsval *vp) { // document.all.item and .namedItem get their value in the // newResolve hook, so nothing to do for those properties here. And @@ -8837,7 +8773,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSObject *obj, return JS_TRUE; } - while (obj->getClass() != &sHTMLDocumentAllClass) { + while (obj->getJSClass() != &sHTMLDocumentAllClass) { obj = obj->getProto(); if (!obj) { @@ -8852,7 +8788,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSObject *obj, nsCOMPtr result; nsresult rv = NS_OK; - if (JSVAL_IS_STRING(id)) { + if (JSID_IS_STRING(id)) { if (id == sLength_id) { // Map document.all.length to the length of the collection // document.getElementsByTagName("*"), and make sure
= 0) { + } else if (JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) { // Map document.all[n] (where n is a number) to the n:th item in // the document.all node list. @@ -8898,7 +8834,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSObject *obj, } nsCOMPtr node; - nodeList->Item(JSVAL_TO_INT(id), getter_AddRefs(node)); + nodeList->Item(JSID_TO_INT(id), getter_AddRefs(node)); result = node; } @@ -8918,7 +8854,7 @@ nsHTMLDocumentSH::DocumentAllGetProperty(JSContext *cx, JSObject *obj, } JSBool -nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsval id, +nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { if (flags & JSRESOLVE_ASSIGNING) { @@ -8933,7 +8869,7 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsval id, // Define the item() or namedItem() method. JSFunction *fnc = - ::JS_DefineFunction(cx, obj, ::JS_GetStringBytes(JSVAL_TO_STRING(id)), + ::JS_DefineFunction(cx, obj, ::JS_GetStringBytes(JSID_TO_STRING(id)), CallToGetPropMapper, 0, JSPROP_ENUMERATE); *objp = obj; @@ -8974,14 +8910,10 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsval id, JSBool ok = JS_TRUE; if (v != JSVAL_VOID) { - if (JSVAL_IS_STRING(id)) { - JSString *str = JSVAL_TO_STRING(id); - - ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), v, nsnull, nsnull, - 0); + if (JSID_IS_STRING(id)) { + ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, 0); } else { - ok = ::JS_DefineElement(cx, obj, JSVAL_TO_INT(id), v, nsnull, nsnull, 0); + ok = ::JS_DefineElement(cx, obj, JSID_TO_INT(id), v, nsnull, nsnull, 0); } *objp = obj; @@ -9052,9 +8984,23 @@ GetDocumentAllHelper(JSContext *cx, JSObject *obj) return obj; } +static inline void * +FlagsToPrivate(PRUint32 flags) +{ + JS_ASSERT((flags & (1 << 31)) == 0); + return (void *)(flags << 1); +} + +static inline PRUint32 +PrivateToFlags(void *priv) +{ + JS_ASSERT(size_t(priv) <= PR_UINT32_MAX && (size_t(priv) & 1) == 0); + return (PRUint32)(size_t(priv) >> 1); +} + JSBool nsHTMLDocumentSH::DocumentAllHelperGetProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp) + jsid id, jsval *vp) { if (id != nsDOMClassInfo::sAll_id) { return JS_TRUE; @@ -9070,7 +9016,7 @@ nsHTMLDocumentSH::DocumentAllHelperGetProperty(JSContext *cx, JSObject *obj, return JS_TRUE; } - PRUint32 flags = JSVAL_TO_INT(PRIVATE_TO_JSVAL(::JS_GetPrivate(cx, helper))); + PRUint32 flags = PrivateToFlags(::JS_GetPrivate(cx, helper)); if (flags & JSRESOLVE_DETECTING || !(flags & JSRESOLVE_QUALIFIED)) { // document.all is either being detected, e.g. if (document.all), @@ -9115,7 +9061,7 @@ nsHTMLDocumentSH::DocumentAllHelperGetProperty(JSContext *cx, JSObject *obj, JSBool nsHTMLDocumentSH::DocumentAllHelperNewResolve(JSContext *cx, JSObject *obj, - jsval id, uintN flags, + jsid id, uintN flags, JSObject **objp) { if (id == nsDOMClassInfo::sAll_id) { @@ -9138,13 +9084,13 @@ nsHTMLDocumentSH::DocumentAllHelperNewResolve(JSContext *cx, JSObject *obj, JSBool nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj, - jsval id, uintN flags, + jsid id, uintN flags, JSObject **objp) { - if (JSVAL_IS_STRING(id)) { + if (JSID_IS_STRING(id)) { nsIHTMLDocument *doc = (nsIHTMLDocument *)::JS_GetPrivate(cx, obj); - JSString *str = JSVAL_TO_STRING(id); + JSString *str = JSID_TO_STRING(id); JSObject *proto = ::JS_GetPrototype(cx, obj); if (NS_UNLIKELY(!proto)) { @@ -9152,9 +9098,7 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj, } JSBool found; - if (!::JS_HasUCProperty(cx, proto, - ::JS_GetStringChars(str), - ::JS_GetStringLength(str), &found)) { + if (!::JS_HasPropertyById(cx, proto, id, &found)) { return JS_FALSE; } @@ -9179,9 +9123,7 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj, return JS_FALSE; } - if (!::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), v, nsnull, nsnull, - 0)) { + if (!::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull, 0)) { return JS_FALSE; } @@ -9195,7 +9137,7 @@ nsHTMLDocumentSH::DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj, NS_IMETHODIMP nsHTMLDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { // nsDocumentSH::NewResolve() does a security check that we'd kinda @@ -9216,12 +9158,8 @@ nsHTMLDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_ENSURE_SUCCESS(rv, rv); if (result) { - JSString *str = JS_ValueToString(cx, id); - JSBool ok = *_retval = - ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), JSVAL_VOID, nsnull, - nsnull, 0); + ::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull, nsnull, 0); *objp = obj; return ok ? NS_OK : NS_ERROR_FAILURE; @@ -9229,7 +9167,7 @@ nsHTMLDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, } if (id == sOpen_id) { - JSString *str = JSVAL_TO_STRING(id); + JSString *str = JSID_TO_STRING(id); JSFunction *fnc = ::JS_DefineFunction(cx, obj, ::JS_GetStringBytes(str), DocumentOpen, 0, JSPROP_ENUMERATE); @@ -9299,9 +9237,7 @@ nsHTMLDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // If we have (or just created) a helper, pass the resolve flags // to the helper as its private data. - if (helper && - !::JS_SetPrivate(cx, helper, - JSVAL_TO_PRIVATE(INT_TO_JSVAL(flags)))) { + if (helper && !::JS_SetPrivate(cx, helper, FlagsToPrivate(flags))) { nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_UNEXPECTED); return NS_ERROR_UNEXPECTED; @@ -9317,7 +9253,7 @@ nsHTMLDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsHTMLDocumentSH::GetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { // For native wrappers, do not get random names on document @@ -9369,25 +9305,23 @@ nsHTMLFormElementSH::FindNamedItem(nsIForm *aForm, JSString *str, NS_IMETHODIMP nsHTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { // For native wrappers, do not resolve random names on form - if ((!(JSRESOLVE_ASSIGNING & flags)) && JSVAL_IS_STRING(id) && + if ((!(JSRESOLVE_ASSIGNING & flags)) && JSID_IS_STRING(id) && !ObjectIsNativeWrapper(cx, obj)) { nsCOMPtr form(do_QueryWrappedNative(wrapper, obj)); nsCOMPtr result; - JSString *str = JSVAL_TO_STRING(id); + JSString *str = JSID_TO_STRING(id); FindNamedItem(form, str, getter_AddRefs(result)); if (result) { JSAutoRequest ar(cx); - *_retval = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), - JSVAL_VOID, nsnull, nsnull, - JSPROP_ENUMERATE); + *_retval = ::JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull, + nsnull, JSPROP_ENUMERATE); *objp = obj; @@ -9401,17 +9335,17 @@ nsHTMLFormElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsHTMLFormElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsCOMPtr form(do_QueryWrappedNative(wrapper, obj)); - if (JSVAL_IS_STRING(id)) { + if (JSID_IS_STRING(id)) { // For native wrappers, do not get random names on form if (!ObjectIsNativeWrapper(cx, obj)) { nsCOMPtr result; - JSString *str = JSVAL_TO_STRING(id); + JSString *str = JSID_TO_STRING(id); FindNamedItem(form, str, getter_AddRefs(result)); if (result) { @@ -9459,7 +9393,7 @@ nsHTMLFormElementSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, if (idp) { PRUint32 count = form->GetElementCount(); - *idp = INT_TO_JSVAL(count); + *idp = INT_TO_JSID(count); } break; @@ -9518,7 +9452,7 @@ nsHTMLFormElementSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsHTMLSelectElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { PRInt32 n = GetArrayIndexFromId(cx, id); @@ -9574,7 +9508,7 @@ nsHTMLSelectElementSH::SetOption(JSContext *cx, jsval *vp, PRUint32 aIndex, NS_IMETHODIMP nsHTMLSelectElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { PRInt32 n = GetArrayIndexFromId(cx, id); @@ -9838,7 +9772,7 @@ nsHTMLPluginObjElementSH::PostCreate(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsHTMLPluginObjElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { JSAutoRequest ar(cx); @@ -9848,21 +9782,13 @@ nsHTMLPluginObjElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, return NS_OK; } - const jschar *id_chars = nsnull; - size_t id_length = 0; - JSBool found = PR_FALSE; if (!ObjectIsNativeWrapper(cx, obj)) { - if (JSVAL_IS_STRING(id)) { - JSString *id_str = JSVAL_TO_STRING(id); - - id_chars = ::JS_GetStringChars(id_str); - id_length = ::JS_GetStringLength(id_str); - - *_retval = ::JS_HasUCProperty(cx, pi_obj, id_chars, id_length, &found); + if (JSID_IS_STRING(id)) { + *_retval = ::JS_HasPropertyById(cx, pi_obj, id, &found); } else { - *_retval = JS_HasElement(cx, pi_obj, JSVAL_TO_INT(id), &found); + *_retval = ::JS_HasElement(cx, pi_obj, JSID_TO_INT(id), &found); } if (!*_retval) { @@ -9871,10 +9797,10 @@ nsHTMLPluginObjElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, } if (found) { - if (JSVAL_IS_STRING(id)) { - *_retval = ::JS_GetUCProperty(cx, pi_obj, id_chars, id_length, vp); + if (JSID_IS_STRING(id)) { + *_retval = ::JS_GetPropertyById(cx, pi_obj, id, vp); } else { - *_retval = ::JS_GetElement(cx, pi_obj, JSVAL_TO_INT(id), vp); + *_retval = ::JS_GetElement(cx, pi_obj, JSID_TO_INT(id), vp); } return *_retval ? NS_SUCCESS_I_DID_SOMETHING : NS_ERROR_FAILURE; @@ -9885,7 +9811,7 @@ nsHTMLPluginObjElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsHTMLPluginObjElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { JSAutoRequest ar(cx); @@ -9895,21 +9821,13 @@ nsHTMLPluginObjElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper, return NS_OK; } - const jschar *id_chars = nsnull; - size_t id_length = 0; - JSBool found = PR_FALSE; if (!ObjectIsNativeWrapper(cx, obj)) { - if (JSVAL_IS_STRING(id)) { - JSString *id_str = JSVAL_TO_STRING(id); - - id_chars = ::JS_GetStringChars(id_str); - id_length = ::JS_GetStringLength(id_str); - - *_retval = ::JS_HasUCProperty(cx, pi_obj, id_chars, id_length, &found); + if (JSID_IS_STRING(id)) { + *_retval = ::JS_HasPropertyById(cx, pi_obj, id, &found); } else { - *_retval = JS_HasElement(cx, pi_obj, JSVAL_TO_INT(id), &found); + *_retval = ::JS_HasElement(cx, pi_obj, JSID_TO_INT(id), &found); } if (!*_retval) { @@ -9918,10 +9836,10 @@ nsHTMLPluginObjElementSH::SetProperty(nsIXPConnectWrappedNative *wrapper, } if (found) { - if (JSVAL_IS_STRING(id)) { - *_retval = ::JS_SetUCProperty(cx, pi_obj, id_chars, id_length, vp); + if (JSID_IS_STRING(id)) { + *_retval = ::JS_SetPropertyById(cx, pi_obj, id, vp); } else { - *_retval = ::JS_SetElement(cx, pi_obj, JSVAL_TO_INT(id), vp); + *_retval = ::JS_SetElement(cx, pi_obj, JSID_TO_INT(id), vp); } return *_retval ? NS_SUCCESS_I_DID_SOMETHING : NS_ERROR_FAILURE; @@ -9989,7 +9907,7 @@ nsHTMLPluginObjElementSH::GetPluginJSObject(JSContext *cx, JSObject *obj, NS_IMETHODIMP nsHTMLPluginObjElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { @@ -10008,7 +9926,7 @@ nsHTMLPluginObjElementSH::NewResolve(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsHTMLOptionsCollectionSH::SetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { PRInt32 n = GetArrayIndexFromId(cx, id); @@ -10096,7 +10014,7 @@ nsMimeTypeArraySH::GetNamedItem(nsISupports *aNative, const nsAString& aName, NS_IMETHODIMP nsStringArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { PRBool is_number = PR_FALSE; @@ -10130,7 +10048,7 @@ nsStringArraySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsHistorySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { PRBool is_number = PR_FALSE; GetArrayIndexFromId(cx, id, &is_number); @@ -10324,26 +10242,19 @@ nsTreeColumnsSH::GetNamedItem(nsISupports *aNative, NS_IMETHODIMP nsStorageSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { JSObject *realObj; wrapper->GetJSObject(&realObj); - // First check to see if the property is defined on our prototype, - // after converting id to a string if it's an integer. - - JSString *jsstr = JS_ValueToString(cx, id); - if (!jsstr) { - return JS_FALSE; - } + // First check to see if the property is defined on our prototype. JSObject *proto = ::JS_GetPrototype(cx, realObj); JSBool hasProp; if (proto && - (::JS_HasUCProperty(cx, proto, ::JS_GetStringChars(jsstr), - ::JS_GetStringLength(jsstr), &hasProp) && + (::JS_HasPropertyById(cx, proto, id, &hasProp) && hasProp)) { // We found the property we're resolving on the prototype, // nothing left to do here then. @@ -10356,6 +10267,10 @@ nsStorageSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, nsCOMPtr storage(do_QueryWrappedNative(wrapper)); + JSString *jsstr = IdToString(cx, id); + if (!jsstr) + return JS_FALSE; + // GetItem() will return null if the caller can't access the session // storage item. nsCOMPtr item; @@ -10364,9 +10279,8 @@ nsStorageSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_ENSURE_SUCCESS(rv, rv); if (item) { - if (!::JS_DefineUCProperty(cx, realObj, ::JS_GetStringChars(jsstr), - ::JS_GetStringLength(jsstr), JSVAL_VOID, nsnull, - nsnull, JSPROP_ENUMERATE)) { + if (!::JS_DefinePropertyById(cx, realObj, id, JSVAL_VOID, nsnull, nsnull, + JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } @@ -10387,13 +10301,13 @@ nsStorageSH::GetNamedItem(nsISupports *aNative, const nsAString& aName, NS_IMETHODIMP nsStorageSH::SetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsCOMPtr storage(do_QueryWrappedNative(wrapper)); NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); - JSString *key = ::JS_ValueToString(cx, id); + JSString *key = IdToString(cx, id); NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); JSString *value = ::JS_ValueToString(cx, *vp); @@ -10410,13 +10324,13 @@ nsStorageSH::SetProperty(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsStorageSH::DelProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsCOMPtr storage(do_QueryWrappedNative(wrapper)); NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); - JSString *key = ::JS_ValueToString(cx, id); + JSString *key = IdToString(cx, id); NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); nsresult rv = storage->RemoveItem(nsDependentJSString(key)); @@ -10449,7 +10363,7 @@ nsStorageSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, *statep = PRIVATE_TO_JSVAL(keys); if (idp) { - *idp = INT_TO_JSVAL(keys->Length()); + *idp = INT_TO_JSID(keys->Length()); } break; } @@ -10495,7 +10409,7 @@ nsStorageSH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval) { JSObject *realObj; @@ -10504,7 +10418,7 @@ nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // First check to see if the property is defined on our prototype, // after converting id to a string if it's an integer. - JSString *jsstr = JS_ValueToString(cx, id); + JSString *jsstr = IdToString(cx, id); if (!jsstr) { return JS_FALSE; } @@ -10513,8 +10427,7 @@ nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSBool hasProp; if (proto && - (::JS_HasUCProperty(cx, proto, ::JS_GetStringChars(jsstr), - ::JS_GetStringLength(jsstr), &hasProp) && + (::JS_HasPropertyById(cx, proto, id, &hasProp) && hasProp)) { // We found the property we're resolving on the prototype, // nothing left to do here then. @@ -10534,9 +10447,8 @@ nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_ENSURE_SUCCESS(rv, rv); if (!DOMStringIsNull(data)) { - if (!::JS_DefineUCProperty(cx, realObj, ::JS_GetStringChars(jsstr), - ::JS_GetStringLength(jsstr), JSVAL_VOID, nsnull, - nsnull, JSPROP_ENUMERATE)) { + if (!::JS_DefinePropertyById(cx, realObj, id, JSVAL_VOID, nsnull, + nsnull, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } @@ -10548,7 +10460,7 @@ nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsStorage2SH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval) + JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsCOMPtr storage(do_QueryWrappedNative(wrapper)); NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); @@ -10556,7 +10468,7 @@ nsStorage2SH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, nsAutoString val; nsresult rv = NS_OK; - if (JSVAL_IS_STRING(id)) { + if (JSID_IS_STRING(id)) { // For native wrappers, do not get random names on storage objects. if (ObjectIsNativeWrapper(cx, obj)) { return NS_ERROR_NOT_AVAILABLE; @@ -10591,13 +10503,13 @@ nsStorage2SH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsStorage2SH::SetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsCOMPtr storage(do_QueryWrappedNative(wrapper)); NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); - JSString *key = ::JS_ValueToString(cx, id); + JSString *key = IdToString(cx, id); NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); JSString *value = ::JS_ValueToString(cx, *vp); @@ -10614,13 +10526,13 @@ nsStorage2SH::SetProperty(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsStorage2SH::DelProperty(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, jsval *vp, PRBool *_retval) { nsCOMPtr storage(do_QueryWrappedNative(wrapper)); NS_ENSURE_TRUE(storage, NS_ERROR_UNEXPECTED); - JSString *key = ::JS_ValueToString(cx, id); + JSString *key = IdToString(cx, id); NS_ENSURE_TRUE(key, NS_ERROR_UNEXPECTED); nsresult rv = storage->RemoveItem(nsDependentJSString(key)); @@ -10653,7 +10565,7 @@ nsStorage2SH::NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, *statep = PRIVATE_TO_JSVAL(keys); if (idp) { - *idp = INT_TO_JSVAL(keys->Length()); + *idp = INT_TO_JSID(keys->Length()); } break; } @@ -10775,7 +10687,7 @@ nsDOMConstructorSH::Construct(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_IMETHODIMP nsDOMConstructorSH::HasInstance(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval val, + JSContext *cx, JSObject *obj, const jsval &val, PRBool *bp, PRBool *_retval) { nsDOMConstructor *wrapped = diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index 426f9a1a8e38..efc386019f0b 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -217,10 +217,10 @@ protected: // Checks if id is a number and returns the number, if aIsNumber is // non-null it's set to true if the id is a number and false if it's // not a number. If id is not a number this method returns -1 - static PRInt32 GetArrayIndexFromId(JSContext *cx, jsval id, + static PRInt32 GetArrayIndexFromId(JSContext *cx, jsid id, PRBool *aIsNumber = nsnull); - static inline PRBool IsReadonlyReplaceable(jsval id) + static inline PRBool IsReadonlyReplaceable(jsid id) { return (id == sTop_id || id == sParent_id || @@ -241,7 +241,7 @@ protected: id == sSelf_id); } - static inline PRBool IsWritableReplaceable(jsval id) + static inline PRBool IsWritableReplaceable(jsid id) { return (id == sInnerHeight_id || id == sInnerWidth_id || @@ -264,91 +264,91 @@ protected: static PRBool sDisableDocumentAllSupport; static PRBool sDisableGlobalScopePollutionSupport; - static jsval sTop_id; - static jsval sParent_id; - static jsval sScrollbars_id; - static jsval sLocation_id; - static jsval sConstructor_id; - static jsval s_content_id; - static jsval sContent_id; - static jsval sMenubar_id; - static jsval sToolbar_id; - static jsval sLocationbar_id; - static jsval sPersonalbar_id; - static jsval sStatusbar_id; - static jsval sDialogArguments_id; - static jsval sControllers_id; - static jsval sLength_id; - static jsval sInnerHeight_id; - static jsval sInnerWidth_id; - static jsval sOuterHeight_id; - static jsval sOuterWidth_id; - static jsval sScreenX_id; - static jsval sScreenY_id; - static jsval sStatus_id; - static jsval sName_id; - static jsval sOnmousedown_id; - static jsval sOnmouseup_id; - static jsval sOnclick_id; - static jsval sOndblclick_id; - static jsval sOncontextmenu_id; - static jsval sOnmouseover_id; - static jsval sOnmouseout_id; - static jsval sOnkeydown_id; - static jsval sOnkeyup_id; - static jsval sOnkeypress_id; - static jsval sOnmousemove_id; - static jsval sOnfocus_id; - static jsval sOnblur_id; - static jsval sOnsubmit_id; - static jsval sOnreset_id; - static jsval sOnchange_id; - static jsval sOnselect_id; - static jsval sOnload_id; - static jsval sOnpopstate_id; - static jsval sOnbeforeunload_id; - static jsval sOnunload_id; - static jsval sOnhashchange_id; - static jsval sOnreadystatechange_id; - static jsval sOnpageshow_id; - static jsval sOnpagehide_id; - static jsval sOnabort_id; - static jsval sOnerror_id; - static jsval sOnpaint_id; - static jsval sOnresize_id; - static jsval sOnscroll_id; - static jsval sOndrag_id; - static jsval sOndragend_id; - static jsval sOndragenter_id; - static jsval sOndragleave_id; - static jsval sOndragover_id; - static jsval sOndragstart_id; - static jsval sOndrop_id; - static jsval sScrollX_id; - static jsval sScrollY_id; - static jsval sScrollMaxX_id; - static jsval sScrollMaxY_id; - static jsval sOpen_id; - static jsval sItem_id; - static jsval sNamedItem_id; - static jsval sEnumerate_id; - static jsval sNavigator_id; - static jsval sDocument_id; - static jsval sWindow_id; - static jsval sFrames_id; - static jsval sSelf_id; - static jsval sOpener_id; - static jsval sAll_id; - static jsval sTags_id; - static jsval sAddEventListener_id; - static jsval sBaseURIObject_id; - static jsval sNodePrincipal_id; - static jsval sDocumentURIObject_id; - static jsval sOncopy_id; - static jsval sOncut_id; - static jsval sOnpaste_id; - static jsval sJava_id; - static jsval sPackages_id; + static jsid sTop_id; + static jsid sParent_id; + static jsid sScrollbars_id; + static jsid sLocation_id; + static jsid sConstructor_id; + static jsid s_content_id; + static jsid sContent_id; + static jsid sMenubar_id; + static jsid sToolbar_id; + static jsid sLocationbar_id; + static jsid sPersonalbar_id; + static jsid sStatusbar_id; + static jsid sDialogArguments_id; + static jsid sControllers_id; + static jsid sLength_id; + static jsid sInnerHeight_id; + static jsid sInnerWidth_id; + static jsid sOuterHeight_id; + static jsid sOuterWidth_id; + static jsid sScreenX_id; + static jsid sScreenY_id; + static jsid sStatus_id; + static jsid sName_id; + static jsid sOnmousedown_id; + static jsid sOnmouseup_id; + static jsid sOnclick_id; + static jsid sOndblclick_id; + static jsid sOncontextmenu_id; + static jsid sOnmouseover_id; + static jsid sOnmouseout_id; + static jsid sOnkeydown_id; + static jsid sOnkeyup_id; + static jsid sOnkeypress_id; + static jsid sOnmousemove_id; + static jsid sOnfocus_id; + static jsid sOnblur_id; + static jsid sOnsubmit_id; + static jsid sOnreset_id; + static jsid sOnchange_id; + static jsid sOnselect_id; + static jsid sOnload_id; + static jsid sOnpopstate_id; + static jsid sOnbeforeunload_id; + static jsid sOnunload_id; + static jsid sOnhashchange_id; + static jsid sOnreadystatechange_id; + static jsid sOnpageshow_id; + static jsid sOnpagehide_id; + static jsid sOnabort_id; + static jsid sOnerror_id; + static jsid sOnpaint_id; + static jsid sOnresize_id; + static jsid sOnscroll_id; + static jsid sOndrag_id; + static jsid sOndragend_id; + static jsid sOndragenter_id; + static jsid sOndragleave_id; + static jsid sOndragover_id; + static jsid sOndragstart_id; + static jsid sOndrop_id; + static jsid sScrollX_id; + static jsid sScrollY_id; + static jsid sScrollMaxX_id; + static jsid sScrollMaxY_id; + static jsid sOpen_id; + static jsid sItem_id; + static jsid sNamedItem_id; + static jsid sEnumerate_id; + static jsid sNavigator_id; + static jsid sDocument_id; + static jsid sWindow_id; + static jsid sFrames_id; + static jsid sSelf_id; + static jsid sOpener_id; + static jsid sAll_id; + static jsid sTags_id; + static jsid sAddEventListener_id; + static jsid sBaseURIObject_id; + static jsid sNodePrincipal_id; + static jsid sDocumentURIObject_id; + static jsid sOncopy_id; + static jsid sOncut_id; + static jsid sOnpaste_id; + static jsid sJava_id; + static jsid sPackages_id; static JSPropertyOp sXPCNativeWrapperGetPropertyOp; static JSPropertyOp sXrayWrapperPropertyHolderGetPropertyOp; @@ -408,13 +408,13 @@ protected: { } - static PRBool ReallyIsEventName(jsval id, jschar aFirstChar); + static PRBool ReallyIsEventName(jsid id, jschar aFirstChar); - static inline PRBool IsEventName(jsval id) + static inline PRBool IsEventName(jsid id) { - NS_ASSERTION(JSVAL_IS_STRING(id), "Don't pass non-string jsval's here!"); + NS_ASSERTION(JSID_IS_STRING(id), "Don't pass non-string jsid's here!"); - jschar *str = ::JS_GetStringChars(JSVAL_TO_STRING(id)); + jschar *str = ::JS_GetStringChars(JSID_TO_STRING(id)); if (str[0] == 'o' && str[1] == 'n') { return ReallyIsEventName(id, str[2]); @@ -424,19 +424,19 @@ protected: } nsresult RegisterCompileHandler(nsIXPConnectWrappedNative *wrapper, - JSContext *cx, JSObject *obj, jsval id, + JSContext *cx, JSObject *obj, jsid id, PRBool compile, PRBool remove, PRBool *did_define); public: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); }; // Simpler than nsEventReceiverSH @@ -455,7 +455,7 @@ public: NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj, JSObject **parentObj); NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); virtual void PreserveWrapper(nsISupports *aNative); @@ -510,15 +510,15 @@ public: } #endif NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 enum_op, jsval *statep, @@ -526,18 +526,18 @@ public: NS_IMETHOD Finalize(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj); NS_IMETHOD Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx, - JSObject * obj, jsval val, PRBool *bp); + JSObject * obj, const jsval &val, PRBool *bp); NS_IMETHOD OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, JSObject * *_retval); NS_IMETHOD InnerObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, JSObject * *_retval); static JSBool GlobalScopePolluterNewResolve(JSContext *cx, JSObject *obj, - jsval id, uintN flags, + jsid id, uintN flags, JSObject **objp); static JSBool GlobalScopePolluterGetProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp); - static JSBool SecurityCheckOnSetProp(JSContext *cx, JSObject *obj, jsval id, + jsid id, jsval *vp); + static JSBool SecurityCheckOnSetProp(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static void InvalidateGlobalScopePolluter(JSContext *cx, JSObject *obj); static nsresult InstallGlobalScopePolluter(JSContext *cx, JSObject *obj, @@ -565,7 +565,7 @@ protected: public: NS_IMETHOD CheckAccess(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 mode, + JSObject *obj, jsid id, PRUint32 mode, jsval *vp, PRBool *_retval); NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, @@ -627,21 +627,21 @@ protected: // work so it's safe to just return whatever it returns. |obj| is the object // we're defining on, |id| is the name of the prop. This must be a string // jsval. |objp| is the out param if we define successfully. - nsresult DefineVoidProp(JSContext* cx, JSObject* obj, jsval id, + nsresult DefineVoidProp(JSContext* cx, JSObject* obj, jsid id, JSObject** objp); public: NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj, JSObject **parentObj); NS_IMETHOD AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD GetFlags(PRUint32 *aFlags); virtual void PreserveWrapper(nsISupports *aNative); @@ -696,7 +696,7 @@ protected: public: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRBool *_retval); @@ -731,7 +731,7 @@ protected: public: NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); private: // Not implemented, nothing should create an instance of this class. @@ -783,7 +783,7 @@ protected: public: NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); private: // Not implemented, nothing should create an instance of this class. @@ -895,12 +895,12 @@ public: public: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD GetFlags(PRUint32* aFlags); NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj); @@ -926,7 +926,7 @@ protected: } static nsresult ResolveImpl(JSContext *cx, - nsIXPConnectWrappedNative *wrapper, jsval id, + nsIXPConnectWrappedNative *wrapper, jsid id, nsISupports **result); static JSBool DocumentOpen(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); @@ -935,27 +935,27 @@ protected: nsIDOMNodeList **nodeList); public: - static JSBool DocumentAllGetProperty(JSContext *cx, JSObject *obj, jsval id, + static JSBool DocumentAllGetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); - static JSBool DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsval id, + static JSBool DocumentAllNewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static void ReleaseDocument(JSContext *cx, JSObject *obj); static JSBool CallToGetPropMapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool DocumentAllHelperGetProperty(JSContext *cx, JSObject *obj, - jsval id, jsval *vp); + jsid id, jsval *vp); static JSBool DocumentAllHelperNewResolve(JSContext *cx, JSObject *obj, - jsval id, uintN flags, + jsid id, uintN flags, JSObject **objp); static JSBool DocumentAllTagsNewResolve(JSContext *cx, JSObject *obj, - jsval id, uintN flags, + jsid id, uintN flags, JSObject **objp); NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { @@ -979,15 +979,15 @@ protected: public: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { @@ -1014,10 +1014,10 @@ protected: public: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, @@ -1047,10 +1047,10 @@ protected: public: NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); static nsresult SetOption(JSContext *cx, jsval *vp, PRUint32 aIndex, nsIDOMNSHTMLOptionCollection *aOptCollection); @@ -1087,16 +1087,16 @@ protected: public: NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, JSObject *globalObj, JSObject **parentObj); NS_IMETHOD PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj); NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD Call(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 argc, jsval *argv, jsval *vp, PRBool *_retval); @@ -1128,7 +1128,7 @@ protected: public: NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { @@ -1242,7 +1242,7 @@ protected: public: NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); }; @@ -1264,7 +1264,7 @@ protected: public: NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { @@ -1537,12 +1537,12 @@ protected: } NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 enum_op, jsval *statep, jsid *idp, PRBool *_retval); @@ -1577,14 +1577,14 @@ protected: } NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, PRUint32 flags, + JSObject *obj, jsid id, PRUint32 flags, JSObject **objp, PRBool *_retval); NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval id, jsval *vp, PRBool *_retval); + JSObject *obj, jsid id, jsval *vp, PRBool *_retval); NS_IMETHOD NewEnumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 enum_op, jsval *statep, jsid *idp, PRBool *_retval); @@ -1671,7 +1671,7 @@ public: jsval *vp, PRBool *_retval); NS_IMETHOD HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext *cx, - JSObject *obj, jsval val, PRBool *bp, + JSObject *obj, const jsval &val, PRBool *bp, PRBool *_retval); static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index c3620216e606..72ce55bf4421 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1222,7 +1222,7 @@ nsJSContext::DOMOperationCallback(JSContext *cx) cx->debugHooks-> debuggerHandlerData)) { case JSTRAP_RETURN: - fp->rval = rval; + fp->rval = js::Valueify(rval); return JS_TRUE; case JSTRAP_ERROR: cx->throwing = JS_FALSE; @@ -3053,10 +3053,10 @@ static JSPropertySpec OptionsProperties[] = { }; static JSBool -GetOptionsProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +GetOptionsProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - if (JSVAL_IS_INT(id)) { - uint32 optbit = (uint32) JSVAL_TO_INT(id); + if (JSID_IS_INT(id)) { + uint32 optbit = (uint32) JSID_TO_INT(id); if (((optbit & (optbit - 1)) == 0 && optbit <= JSOPTION_WERROR) || optbit == JSOPTION_RELIMIT) *vp = (JS_GetOptions(cx) & optbit) ? JSVAL_TRUE : JSVAL_FALSE; @@ -3065,10 +3065,10 @@ GetOptionsProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -SetOptionsProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +SetOptionsProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - if (JSVAL_IS_INT(id)) { - uint32 optbit = (uint32) JSVAL_TO_INT(id); + if (JSID_IS_INT(id)) { + uint32 optbit = (uint32) JSID_TO_INT(id); // Don't let options other than strict, werror, or relimit be set -- it // would be bad if web page script could clear @@ -3946,7 +3946,7 @@ SetMemoryHighWaterMarkPrefChangedCallback(const char* aPrefName, void* aClosure) // Let's limit the high water mark for the first one to 32MB, // and second one to 0xffffffff. JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MAX_MALLOC_BYTES, - 32L * 1024L * 1024L); + 64L * 1024L * 1024L); JS_SetGCParameter(nsJSRuntime::sRuntime, JSGC_MAX_BYTES, 0xffffffff); } else { diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index c376a9170190..44e27cfdf040 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -81,6 +81,12 @@ public: { } + explicit nsDependentJSString(jsid id) + : nsDependentString((PRUnichar *)::JS_GetStringChars(JSID_TO_STRING(id)), + ::JS_GetStringLength(JSID_TO_STRING(id))) + { + } + explicit nsDependentJSString(JSString *str) : nsDependentString((PRUnichar *)::JS_GetStringChars(str), ::JS_GetStringLength(str)) { diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp index dcb71a8da33f..902bbe7e2c26 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -365,7 +365,7 @@ IDBCursor::GetValue(JSContext* aCx, } NS_IMETHODIMP -IDBCursor::Continue(jsval aKey, +IDBCursor::Continue(const jsval &aKey, JSContext* aCx, PRUint8 aOptionalArgCount, PRBool* _retval) @@ -410,7 +410,7 @@ IDBCursor::Continue(jsval aKey, } NS_IMETHODIMP -IDBCursor::Update(jsval aValue, +IDBCursor::Update(const jsval &aValue, JSContext* aCx, nsIIDBRequest** _retval) { @@ -436,7 +436,7 @@ IDBCursor::Update(jsval aValue, js::AutoValueRooter clone(aCx); nsresult rv = nsContentUtils::CreateStructuredClone(aCx, aValue, - clone.addr()); + clone.jsval_addr()); if (NS_FAILED(rv)) { return rv; } @@ -449,22 +449,22 @@ IDBCursor::Update(jsval aValue, const size_t keyPathLen = keyPath.Length(); js::AutoValueRooter prop(aCx); - JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(clone.value()), - keyPathChars, keyPathLen, prop.addr()); + JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(clone.jsval_value()), + keyPathChars, keyPathLen, prop.jsval_addr()); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - if (JSVAL_IS_VOID(prop.value())) { - rv = IDBObjectStore::GetJSValFromKey(key, aCx, prop.addr()); + if (JSVAL_IS_VOID(prop.jsval_value())) { + rv = IDBObjectStore::GetJSValFromKey(key, aCx, prop.jsval_addr()); NS_ENSURE_SUCCESS(rv, rv); - ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(clone.value()), - keyPathChars, keyPathLen, prop.value(), nsnull, + ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(clone.jsval_value()), + keyPathChars, keyPathLen, prop.jsval_value(), nsnull, nsnull, JSPROP_ENUMERATE); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); } else { Key newKey; - rv = IDBObjectStore::GetKeyFromJSVal(prop.value(), newKey); + rv = IDBObjectStore::GetKeyFromJSVal(prop.jsval_value(), newKey); NS_ENSURE_SUCCESS(rv, rv); if (newKey.IsUnset() || newKey.IsNull() || newKey != key) { @@ -475,13 +475,13 @@ IDBCursor::Update(jsval aValue, nsTArray indexUpdateInfo; rv = IDBObjectStore::GetIndexUpdateInfo(mObjectStore->GetObjectStoreInfo(), - aCx, clone.value(), indexUpdateInfo); + aCx, clone.jsval_value(), indexUpdateInfo); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr json(new nsJSON()); nsString jsonValue; - rv = json->EncodeFromJSVal(clone.addr(), aCx, jsonValue); + rv = json->EncodeFromJSVal(clone.jsval_addr(), aCx, jsonValue); NS_ENSURE_SUCCESS(rv, rv); nsRefPtr request = GenerateWriteRequest(); diff --git a/dom/indexedDB/IDBEvents.cpp b/dom/indexedDB/IDBEvents.cpp index 932fa0ab1fcb..bc9e65681197 100644 --- a/dom/indexedDB/IDBEvents.cpp +++ b/dom/indexedDB/IDBEvents.cpp @@ -473,14 +473,14 @@ GetAllSuccessEvent::GetResult(JSContext* aCx, nsString jsonValue = values[index]; values[index].Truncate(); - nsresult rv = json->DecodeToJSVal(jsonValue, aCx, value.addr()); + nsresult rv = json->DecodeToJSVal(jsonValue, aCx, value.jsval_addr()); if (NS_FAILED(rv)) { mCachedValue = JSVAL_VOID; NS_ERROR("Failed to decode!"); return rv; } - if (!JS_SetElement(aCx, array, index, value.addr())) { + if (!JS_SetElement(aCx, array, index, value.jsval_addr())) { mCachedValue = JSVAL_VOID; NS_ERROR("Failed to set array element!"); return NS_ERROR_FAILURE; @@ -539,14 +539,14 @@ GetAllKeySuccessEvent::GetResult(JSContext* aCx, const Key& key = keys[index]; NS_ASSERTION(!key.IsUnset() && !key.IsNull(), "Bad key!"); - nsresult rv = IDBObjectStore::GetJSValFromKey(key, aCx, value.addr()); + nsresult rv = IDBObjectStore::GetJSValFromKey(key, aCx, value.jsval_addr()); if (NS_FAILED(rv)) { mCachedValue = JSVAL_VOID; NS_WARNING("Failed to get jsval for key!"); return rv; } - if (!JS_SetElement(aCx, array, index, value.addr())) { + if (!JS_SetElement(aCx, array, index, value.jsval_addr())) { mCachedValue = JSVAL_VOID; NS_WARNING("Failed to set array element!"); return NS_ERROR_FAILURE; diff --git a/dom/indexedDB/IDBObjectStore.cpp b/dom/indexedDB/IDBObjectStore.cpp index 88f056ba748d..8d50dc03c101 100644 --- a/dom/indexedDB/IDBObjectStore.cpp +++ b/dom/indexedDB/IDBObjectStore.cpp @@ -373,7 +373,7 @@ IDBObjectStore::GetKeyFromJSVal(jsval aKeyVal, aKey = JSVAL_TO_INT(aKeyVal); } else if (JSVAL_IS_DOUBLE(aKeyVal)) { - aKey = *JSVAL_TO_DOUBLE(aKeyVal); + aKey = JSVAL_TO_DOUBLE(aKeyVal); } else { return NS_ERROR_INVALID_ARG; @@ -452,14 +452,14 @@ IDBObjectStore::GetJSONFromArg0(/* jsval arg0, */ JSAutoRequest ar(cx); js::AutoValueRooter clone(cx); - rv = nsContentUtils::CreateStructuredClone(cx, argv[0], clone.addr()); + rv = nsContentUtils::CreateStructuredClone(cx, argv[0], clone.jsval_addr()); if (NS_FAILED(rv)) { return rv; } nsCOMPtr json(new nsJSON()); - rv = json->EncodeFromJSVal(clone.addr(), cx, aJSON); + rv = json->EncodeFromJSVal(clone.jsval_addr(), cx, aJSON); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; @@ -488,16 +488,16 @@ IDBObjectStore::GetKeyPathValueFromJSON(const nsAString& aJSON, js::AutoValueRooter clone(*aCx); nsCOMPtr json(new nsJSON()); - rv = json->DecodeToJSVal(aJSON, *aCx, clone.addr()); + rv = json->DecodeToJSVal(aJSON, *aCx, clone.jsval_addr()); NS_ENSURE_SUCCESS(rv, rv); - if (JSVAL_IS_PRIMITIVE(clone.value())) { + if (JSVAL_IS_PRIMITIVE(clone.jsval_value())) { // This isn't an object, so just leave the key unset. aValue = Key::UNSETKEY; return NS_OK; } - JSObject* obj = JSVAL_TO_OBJECT(clone.value()); + JSObject* obj = JSVAL_TO_OBJECT(clone.jsval_value()); const jschar* keyPathChars = reinterpret_cast(aKeyPath.BeginReading()); @@ -505,10 +505,10 @@ IDBObjectStore::GetKeyPathValueFromJSON(const nsAString& aJSON, js::AutoValueRooter value(*aCx); JSBool ok = JS_GetUCProperty(*aCx, obj, keyPathChars, keyPathLen, - value.addr()); + value.jsval_addr()); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - rv = GetKeyFromJSVal(value.value(), aValue); + rv = GetKeyFromJSVal(value.jsval_value(), aValue); if (NS_FAILED(rv) || aValue.IsNull()) { // If the object doesn't have a value that we can use for our index then we // leave it unset. @@ -729,7 +729,7 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, js::AutoValueRooter clone(aCx); nsresult rv = nsContentUtils::CreateStructuredClone(aCx, aValue, - clone.addr()); + clone.jsval_addr()); if (NS_FAILED(rv)) { return rv; } @@ -740,11 +740,11 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, } else { // Inline keys live on the object. Make sure it is an object. - if (JSVAL_IS_PRIMITIVE(clone.value())) { + if (JSVAL_IS_PRIMITIVE(clone.jsval_value())) { return NS_ERROR_INVALID_ARG; } - rv = GetKeyFromObject(aCx, JSVAL_TO_OBJECT(clone.value()), mKeyPath, aKey); + rv = GetKeyFromObject(aCx, JSVAL_TO_OBJECT(clone.jsval_value()), mKeyPath, aKey); NS_ENSURE_SUCCESS(rv, rv); // Except if null was passed, in which case we're supposed to generate the @@ -762,11 +762,11 @@ IDBObjectStore::GetAddInfo(JSContext* aCx, ObjectStoreInfo* objectStoreInfo = GetObjectStoreInfo(); NS_ENSURE_TRUE(objectStoreInfo, NS_ERROR_FAILURE); - rv = GetIndexUpdateInfo(objectStoreInfo, aCx, clone.value(), aUpdateInfoArray); + rv = GetIndexUpdateInfo(objectStoreInfo, aCx, clone.jsval_value(), aUpdateInfoArray); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr json(new nsJSON()); - rv = json->EncodeFromJSVal(clone.addr(), aCx, aJSON); + rv = json->EncodeFromJSVal(clone.jsval_addr(), aCx, aJSON); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; @@ -904,8 +904,8 @@ IDBObjectStore::GetAll(nsIIDBKeyRange* aKeyRange, } NS_IMETHODIMP -IDBObjectStore::Add(jsval aValue, - jsval aKey, +IDBObjectStore::Add(const jsval &aValue, + const jsval &aKey, JSContext* aCx, PRUint8 aOptionalArgCount, nsIIDBRequest** _retval) @@ -920,15 +920,13 @@ IDBObjectStore::Add(jsval aValue, return NS_ERROR_OBJECT_IS_IMMUTABLE; } - if (aOptionalArgCount < 1) { - aKey = JSVAL_VOID; - } + jsval keyval = (aOptionalArgCount >= 1) ? aKey : JSVAL_VOID; nsString jsonValue; Key key; nsTArray updateInfo; - nsresult rv = GetAddInfo(aCx, aValue, aKey, jsonValue, key, updateInfo); + nsresult rv = GetAddInfo(aCx, aValue, keyval, jsonValue, key, updateInfo); if (NS_FAILED(rv)) { return rv; } @@ -951,8 +949,8 @@ IDBObjectStore::Add(jsval aValue, } NS_IMETHODIMP -IDBObjectStore::Modify(jsval aValue, - jsval aKey, +IDBObjectStore::Modify(const jsval &aValue, + const jsval &aKey, JSContext* aCx, PRUint8 aOptionalArgCount, nsIIDBRequest** _retval) @@ -967,15 +965,13 @@ IDBObjectStore::Modify(jsval aValue, return NS_ERROR_OBJECT_IS_IMMUTABLE; } - if (aOptionalArgCount < 1) { - aKey = JSVAL_VOID; - } + jsval keyval = (aOptionalArgCount >= 1) ? aKey : JSVAL_VOID; nsString jsonValue; Key key; nsTArray updateInfo; - nsresult rv = GetAddInfo(aCx, aValue, aKey, jsonValue, key, updateInfo); + nsresult rv = GetAddInfo(aCx, aValue, keyval, jsonValue, key, updateInfo); if (NS_FAILED(rv)) { return rv; } @@ -998,8 +994,8 @@ IDBObjectStore::Modify(jsval aValue, } NS_IMETHODIMP -IDBObjectStore::AddOrModify(jsval aValue, - jsval aKey, +IDBObjectStore::AddOrModify(const jsval &aValue, + const jsval &aKey, JSContext* aCx, PRUint8 aOptionalArgCount, nsIIDBRequest** _retval) @@ -1014,15 +1010,13 @@ IDBObjectStore::AddOrModify(jsval aValue, return NS_ERROR_OBJECT_IS_IMMUTABLE; } - if (aOptionalArgCount < 1) { - aKey = JSVAL_VOID; - } + jsval keyval = (aOptionalArgCount >= 1) ? aKey : JSVAL_VOID; nsString jsonValue; Key key; nsTArray updateInfo; - nsresult rv = GetAddInfo(aCx, aValue, aKey, jsonValue, key, updateInfo); + nsresult rv = GetAddInfo(aCx, aValue, keyval, jsonValue, key, updateInfo); if (NS_FAILED(rv)) { return rv; } @@ -1473,10 +1467,10 @@ AddHelper::ModifyValueForNewKey() js::AutoValueRooter clone(cx); nsCOMPtr json(new nsJSON()); - rv = json->DecodeToJSVal(mValue, cx, clone.addr()); + rv = json->DecodeToJSVal(mValue, cx, clone.jsval_addr()); NS_ENSURE_SUCCESS(rv, rv); - JSObject* obj = JSVAL_TO_OBJECT(clone.value()); + JSObject* obj = JSVAL_TO_OBJECT(clone.jsval_value()); JSBool ok; js::AutoValueRooter key(cx); @@ -1484,18 +1478,18 @@ AddHelper::ModifyValueForNewKey() const size_t keyPathLen = mKeyPath.Length(); #ifdef DEBUG - ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, key.addr()); - NS_ASSERTION(ok && JSVAL_IS_VOID(key.value()), "Already has a key prop!"); + ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, key.jsval_addr()); + NS_ASSERTION(ok && JSVAL_IS_VOID(key.jsval_value()), "Already has a key prop!"); #endif - ok = JS_NewNumberValue(cx, mKey.IntValue(), key.addr()); + ok = JS_NewNumberValue(cx, mKey.IntValue(), key.jsval_addr()); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - ok = JS_DefineUCProperty(cx, obj, keyPathChars, keyPathLen, key.value(), + ok = JS_DefineUCProperty(cx, obj, keyPathChars, keyPathLen, key.jsval_value(), nsnull, nsnull, JSPROP_ENUMERATE); NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE); - rv = json->EncodeFromJSVal(clone.addr(), cx, mValue); + rv = json->EncodeFromJSVal(clone.jsval_addr(), cx, mValue); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; diff --git a/dom/src/threads/nsDOMWorker.cpp b/dom/src/threads/nsDOMWorker.cpp index 78e0e054d52b..61e8fe9405ee 100644 --- a/dom/src/threads/nsDOMWorker.cpp +++ b/dom/src/threads/nsDOMWorker.cpp @@ -116,7 +116,7 @@ public: #ifdef BUILD_CTYPES static JSBool - CTypesLazyGetter(JSContext* aCx, JSObject* aObj, jsval aId, jsval* aVp); + CTypesLazyGetter(JSContext* aCx, JSObject* aObj, jsid aId, jsval* aVp); #endif private: @@ -434,14 +434,14 @@ nsDOMWorkerFunctions::MakeNewWorker(JSContext* aCx, JSBool nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx, JSObject* aObj, - jsval aId, + jsid aId, jsval* aVp) { #ifdef DEBUG { NS_ASSERTION(JS_GetGlobalForObject(aCx, aObj) == aObj, "Bad object!"); - NS_ASSERTION(JSVAL_IS_STRING(aId), "Not a string!"); - JSString* str = JSVAL_TO_STRING(aId); + NS_ASSERTION(JSID_IS_STRING(aId), "Not a string!"); + JSString* str = JSID_TO_STRING(aId); NS_ASSERTION(nsDependentJSString(str).EqualsLiteral("ctypes"), "Bad id!"); } #endif @@ -453,11 +453,9 @@ nsDOMWorkerFunctions::CTypesLazyGetter(JSContext* aCx, return JS_FALSE; } - js::AutoIdRooter rooter(aCx); - return JS_ValueToId(aCx, aId, rooter.addr()) && - JS_DeletePropertyById(aCx, aObj, rooter.id()) && + return JS_DeletePropertyById(aCx, aObj, aId) && JS_InitCTypesClass(aCx, aObj) && - JS_GetPropertyById(aCx, aObj, rooter.id(), aVp); + JS_GetPropertyById(aCx, aObj, aId, aVp); } #endif @@ -586,7 +584,7 @@ NS_IMETHODIMP nsDOMWorkerScope::AddProperty(nsIXPConnectWrappedNative* aWrapper, JSContext* aCx, JSObject* aObj, - jsval aId, + jsid aId, jsval* aVp, PRBool* _retval) { @@ -598,14 +596,14 @@ nsDOMWorkerScope::AddProperty(nsIXPConnectWrappedNative* aWrapper, // someone making an 'onmessage' or 'onerror' function so aId must be a // string and aVp must be a function. JSObject* funObj; - if (!(JSVAL_IS_STRING(aId) && + if (!(JSID_IS_STRING(aId) && JSVAL_IS_OBJECT(*aVp) && (funObj = JSVAL_TO_OBJECT(*aVp)) && JS_ObjectIsFunction(aCx, funObj))) { return NS_OK; } - const char* name = JS_GetStringBytes(JSVAL_TO_STRING(aId)); + const char* name = JS_GetStringBytes(JSID_TO_STRING(aId)); // Figure out which listener we're setting. SetListenerFunc func; diff --git a/dom/src/threads/nsDOMWorkerSecurityManager.cpp b/dom/src/threads/nsDOMWorkerSecurityManager.cpp index e14540cf428f..1d579ff0c644 100644 --- a/dom/src/threads/nsDOMWorkerSecurityManager.cpp +++ b/dom/src/threads/nsDOMWorkerSecurityManager.cpp @@ -108,7 +108,7 @@ nsDOMWorkerSecurityManager::CanAccess(PRUint32 aAction, JSObject* aJSObject, nsISupports* aObj, nsIClassInfo* aClassInfo, - jsval aName, + jsid aName, void** aPolicy) { return NS_OK; @@ -123,7 +123,7 @@ nsDOMWorkerSecurityManager::WorkerPrincipal() JSBool nsDOMWorkerSecurityManager::JSCheckAccess(JSContext* aCx, JSObject* aObj, - jsval aId, + jsid aId, JSAccessMode aMode, jsval* aVp) { diff --git a/dom/src/threads/nsDOMWorkerSecurityManager.h b/dom/src/threads/nsDOMWorkerSecurityManager.h index bb3625fc90af..bfa16b157094 100644 --- a/dom/src/threads/nsDOMWorkerSecurityManager.h +++ b/dom/src/threads/nsDOMWorkerSecurityManager.h @@ -50,7 +50,7 @@ public: static JSPrincipals* WorkerPrincipal(); - static JSBool JSCheckAccess(JSContext* aCx, JSObject* aObj, jsval aId, + static JSBool JSCheckAccess(JSContext* aCx, JSObject* aObj, jsid aId, JSAccessMode aMode, jsval* aVp); static JSPrincipals* JSFindPrincipal(JSContext* aCx, JSObject* aObj); diff --git a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp index 22016495238e..3316a7b73c9f 100644 --- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp +++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp @@ -96,7 +96,7 @@ AutoConfigSecMan::CanAccess(PRUint32 aAction, nsAXPCNativeCallContext *aCallContext, JSContext *aJSContext, JSObject *aJSObject, nsISupports *aObj, nsIClassInfo *aClassInfo, - jsval aName, void **aPolicy) + jsid aName, void **aPolicy) { return NS_OK; } diff --git a/ipc/testshell/TestShellParent.cpp b/ipc/testshell/TestShellParent.cpp index bc95199d7a14..2f8aaed3d0ff 100644 --- a/ipc/testshell/TestShellParent.cpp +++ b/ipc/testshell/TestShellParent.cpp @@ -116,7 +116,7 @@ TestShellCommandParent::SetCallback(JSContext* aCx, JSBool TestShellCommandParent::RunCallback(const nsString& aResponse) { - NS_ENSURE_TRUE(mCallback && mCx, JS_FALSE); + NS_ENSURE_TRUE(mCallback != JSVAL_NULL && mCx, JS_FALSE); JSAutoRequest ar(mCx); diff --git a/ipc/testshell/XPCShellEnvironment.cpp b/ipc/testshell/XPCShellEnvironment.cpp index 6f38bb929dae..907b5296ddc2 100644 --- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -737,7 +737,7 @@ FullTrustSecMan::CanAccess(PRUint32 aAction, JSObject * aJSObject, nsISupports *aObj, nsIClassInfo *aClassInfo, - jsval aName, + jsid aName, void * *aPolicy) { return NS_OK; @@ -747,7 +747,7 @@ NS_IMETHODIMP FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext, JSObject * aJSObject, const char *aClassName, - jsval aProperty, + jsid aProperty, PRUint32 aAction) { return NS_OK; diff --git a/js/ipc/ObjectWrapperChild.cpp b/js/ipc/ObjectWrapperChild.cpp index 610b9f7ef104..f87ca1a82372 100644 --- a/js/ipc/ObjectWrapperChild.cpp +++ b/js/ipc/ObjectWrapperChild.cpp @@ -195,7 +195,7 @@ ObjectWrapperChild::jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to) if (JSVAL_IS_INT(from)) *to = JSVAL_TO_INT(from); else if (JSVAL_IS_DOUBLE(from)) - *to = *JSVAL_TO_DOUBLE(from); + *to = JSVAL_TO_DOUBLE(from); else return false; return true; case JSTYPE_BOOLEAN: @@ -216,7 +216,7 @@ JSObject_from_PObjectWrapperChild(JSContext*, { const ObjectWrapperChild* owc = static_cast(from); - *to = owc ? owc->mObj : JSVAL_NULL; + *to = owc ? owc->mObj : NULL; return true; } @@ -263,7 +263,7 @@ ObjectWrapperChild::jsval_from_JSVariant(JSContext* cx, const JSVariant& from, *to = INT_TO_JSVAL(from.get_int()); return true; case JSVariant::Tdouble: - return !!JS_NewDoubleValue(cx, from.get_double(), to); + return !!JS_NewNumberValue(cx, from.get_double(), to); case JSVariant::Tbool: *to = BOOLEAN_TO_JSVAL(from.get_bool()); return true; @@ -444,7 +444,7 @@ ObjectWrapperChild::AnswerNewEnumerateInit(/* no in-parameters */ JSObject* state = JS_NewObjectWithGivenProto(cx, clasp, NULL, NULL); if (!state) return false; - AutoValueRooter tvr(cx, state); + AutoObjectRooter tvr(cx, state); for (JSObject* proto = mObj; proto; diff --git a/js/ipc/ObjectWrapperParent.cpp b/js/ipc/ObjectWrapperParent.cpp index 919c138d787f..95f33b940116 100644 --- a/js/ipc/ObjectWrapperParent.cpp +++ b/js/ipc/ObjectWrapperParent.cpp @@ -230,7 +230,7 @@ ObjectWrapperParent::GetJSObject(JSContext* cx) const static ObjectWrapperParent* Unwrap(JSContext* cx, JSObject* obj) { - while (obj->getClass() != &ObjectWrapperParent::sCPOW_JSClass.base) + while (obj->getJSClass() != &ObjectWrapperParent::sCPOW_JSClass.base) if (!(obj = obj->getProto())) return NULL; @@ -275,7 +275,7 @@ ObjectWrapperParent::jsval_to_JSVariant(JSContext* cx, jsval from, if (JSVAL_IS_INT(from)) *to = JSVAL_TO_INT(from); else if (JSVAL_IS_DOUBLE(from)) - *to = *JSVAL_TO_DOUBLE(from); + *to = JSVAL_TO_DOUBLE(from); else return false; return true; case JSTYPE_BOOLEAN: @@ -310,7 +310,7 @@ ObjectWrapperParent::jsval_from_JSVariant(JSContext* cx, const JSVariant& from, *to = INT_TO_JSVAL(from.get_int()); return true; case JSVariant::Tdouble: - return !!JS_NewDoubleValue(cx, from.get_double(), to); + return !!JS_NewNumberValue(cx, from.get_double(), to); case JSVariant::Tbool: *to = BOOLEAN_TO_JSVAL(from.get_bool()); return true; @@ -379,10 +379,12 @@ jsid_from_nsString(JSContext* cx, const nsString& from, jsid* to) } static bool -jsval_to_nsString(JSContext* cx, jsval from, nsString* to) +jsval_to_nsString(JSContext* cx, jsid from, nsString* to) { JSString* str; - if ((str = JS_ValueToString(cx, from))) { + jsval idval; + if (JS_IdToValue(cx, from, &idval) && + (str = JS_ValueToString(cx, idval))) { *to = JS_GetStringChars(str); return true; } @@ -390,7 +392,7 @@ jsval_to_nsString(JSContext* cx, jsval from, nsString* to) } /*static*/ JSBool -ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, +ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { CPOW_LOG(("Calling CPOW_AddProperty (%s)...", @@ -417,7 +419,7 @@ ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, } /*static*/ JSBool -ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, +ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { CPOW_LOG(("Calling CPOW_GetProperty (%s)...", @@ -444,7 +446,7 @@ ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, } /*static*/ JSBool -ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, +ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { CPOW_LOG(("Calling CPOW_SetProperty (%s)...", @@ -473,7 +475,7 @@ ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, } /*static*/ JSBool -ObjectWrapperParent::CPOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, +ObjectWrapperParent::CPOW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { CPOW_LOG(("Calling CPOW_DelProperty (%s)...", @@ -580,7 +582,7 @@ ObjectWrapperParent::CPOW_NewEnumerate(JSContext *cx, JSObject *obj, } /*static*/ JSBool -ObjectWrapperParent::CPOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, +ObjectWrapperParent::CPOW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { CPOW_LOG(("Calling CPOW_NewResolve (%s)...", @@ -606,11 +608,9 @@ ObjectWrapperParent::CPOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, !JSObject_from_PObjectWrapperParent(cx, out_pobj, objp)) return JS_FALSE; - jsid interned_id; - if (*objp && - JS_ValueToId(cx, id, &interned_id)) { + if (*objp) { AutoResolveFlag arf(cx, *objp); - JS_DefinePropertyById(cx, *objp, interned_id, JSVAL_VOID, NULL, NULL, + JS_DefinePropertyById(cx, *objp, id, JSVAL_VOID, NULL, NULL, JSPROP_ENUMERATE); } return JS_TRUE; @@ -708,7 +708,7 @@ ObjectWrapperParent::CPOW_Construct(JSContext *cx, JSObject *obj, uintN argc, } /*static*/ JSBool -ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, +ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp) { CPOW_LOG(("Calling CPOW_HasInstance...")); @@ -723,7 +723,7 @@ ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSVariant in_v; - if (!jsval_to_JSVariant(cx, v, &in_v)) + if (!jsval_to_JSVariant(cx, *v, &in_v)) return JS_FALSE; return (self->Manager()->RequestRunToCompletion() && @@ -733,7 +733,7 @@ ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, } /*static*/ JSBool -ObjectWrapperParent::CPOW_Equality(JSContext *cx, JSObject *obj, jsval v, +ObjectWrapperParent::CPOW_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp) { CPOW_LOG(("Calling CPOW_Equality...")); @@ -744,10 +744,10 @@ ObjectWrapperParent::CPOW_Equality(JSContext *cx, JSObject *obj, jsval v, if (!self) return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Equality"); - if (JSVAL_IS_PRIMITIVE(v)) + if (JSVAL_IS_PRIMITIVE(*v)) return JS_TRUE; - ObjectWrapperParent* other = Unwrap(cx, JSVAL_TO_OBJECT(v)); + ObjectWrapperParent* other = Unwrap(cx, JSVAL_TO_OBJECT(*v)); if (!other) return JS_TRUE; diff --git a/js/ipc/ObjectWrapperParent.h b/js/ipc/ObjectWrapperParent.h index f19cdb2b38ad..da90172b26b3 100644 --- a/js/ipc/ObjectWrapperParent.h +++ b/js/ipc/ObjectWrapperParent.h @@ -88,16 +88,16 @@ private: mutable JSObject* mObj; static JSBool - CPOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + CPOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool - CPOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + CPOW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool - CPOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + CPOW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool - CPOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + CPOW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); JSBool NewEnumerateInit(JSContext* cx, jsval* statep, jsid* idp); JSBool NewEnumerateNext(JSContext* cx, jsval* statep, jsid* idp); @@ -107,7 +107,7 @@ private: jsval *statep, jsid *idp); static JSBool - CPOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, + CPOW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static JSBool @@ -125,10 +125,10 @@ private: jsval *rval); static JSBool - CPOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + CPOW_HasInstance(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); static JSBool - CPOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); + CPOW_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to); static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from, diff --git a/js/jetpack/Handle.h b/js/jetpack/Handle.h index 03335e7a492c..5afe06a2d9be 100644 --- a/js/jetpack/Handle.h +++ b/js/jetpack/Handle.h @@ -160,7 +160,7 @@ private: static Handle* Unwrap(JSContext* cx, JSObject* obj) { - while (obj && obj->getClass() != &sHandle_JSClass) + while (obj && obj->getJSClass() != &sHandle_JSClass) obj = obj->getProto(); if (!obj) @@ -175,7 +175,7 @@ private: } static JSBool - GetParent(JSContext* cx, JSObject* obj, jsval, jsval* vp) { + GetParent(JSContext* cx, JSObject* obj, jsid, jsval* vp) { JS_SET_RVAL(cx, vp, JSVAL_NULL); Handle* self = Unwrap(cx, obj); @@ -193,7 +193,7 @@ private: } static JSBool - GetIsValid(JSContext* cx, JSObject* obj, jsval, jsval* vp) { + GetIsValid(JSContext* cx, JSObject* obj, jsid, jsval* vp) { Handle* self = Unwrap(cx, obj); JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(!!self)); return JS_TRUE; diff --git a/js/jetpack/JetpackActorCommon.cpp b/js/jetpack/JetpackActorCommon.cpp index 723b6939290b..1529b0b0fd8d 100644 --- a/js/jetpack/JetpackActorCommon.cpp +++ b/js/jetpack/JetpackActorCommon.cpp @@ -146,7 +146,7 @@ JetpackActorCommon::jsval_to_PrimVariant(JSContext* cx, JSType type, jsval from, if (JSVAL_IS_INT(from)) *to = JSVAL_TO_INT(from); else if (JSVAL_IS_DOUBLE(from)) - *to = *JSVAL_TO_DOUBLE(from); + *to = JSVAL_TO_DOUBLE(from); else return false; return true; @@ -278,7 +278,7 @@ JetpackActorCommon::jsval_from_PrimVariant(JSContext* cx, return true; case PrimVariant::Tdouble: - return !!JS_NewDoubleValue(cx, from.get_double(), to); + return !!JS_NewNumberValue(cx, from.get_double(), to); case PrimVariant::TnsString: { const nsString& str = from.get_nsString(); @@ -349,11 +349,11 @@ JetpackActorCommon::jsval_from_CompVariant(JSContext* cx, for (PRUint32 i = 0; i < kvs.Length(); ++i) { const KeyValue& kv = kvs.ElementAt(i); js::AutoValueRooter toSet(cx); - if (!jsval_from_Variant(cx, kv.value(), toSet.addr(), seen) || + if (!jsval_from_Variant(cx, kv.value(), toSet.jsval_addr(), seen) || !JS_SetUCProperty(cx, obj, kv.key().get(), kv.key().Length(), - toSet.addr())) + toSet.jsval_addr())) return false; } @@ -456,11 +456,11 @@ JetpackActorCommon::RecvMessage(JSContext* cx, Variant* vp = results ? results->AppendElement() : NULL; rval.set(JSVAL_VOID); if (!JS_CallFunctionValue(cx, implGlobal, snapshot[i], argc, argv, - rval.addr())) { + rval.jsval_addr())) { (void) JS_ReportPendingException(cx); if (vp) *vp = void_t(); - } else if (vp && !jsval_to_Variant(cx, rval.value(), vp)) + } else if (vp && !jsval_to_Variant(cx, rval.jsval_value(), vp)) *vp = void_t(); } diff --git a/js/jetpack/JetpackChild.cpp b/js/jetpack/JetpackChild.cpp index e1fe61f2e4c8..6352d2557e1f 100644 --- a/js/jetpack/JetpackChild.cpp +++ b/js/jetpack/JetpackChild.cpp @@ -158,7 +158,7 @@ JetpackChild::RecvEvalScript(const nsString& code) js::AutoValueRooter ignored(mCx); (void) JS_EvaluateUCScript(mCx, JS_GetGlobalObject(mCx), code.get(), - code.Length(), "", 1, ignored.addr()); + code.Length(), "", 1, ignored.jsval_addr()); return true; } @@ -442,7 +442,7 @@ JetpackChild::EvalInSandbox(JSContext* cx, uintN argc, jsval* vp) js::AutoValueRooter ignored(cx); return JS_EvaluateUCScript(cx, obj, JS_GetStringChars(str), JS_GetStringLength(str), "", 1, - ignored.addr()); + ignored.jsval_addr()); } } // namespace jetpack diff --git a/js/jetpack/JetpackParent.cpp b/js/jetpack/JetpackParent.cpp index 42a4a9100622..d4274b205b10 100644 --- a/js/jetpack/JetpackParent.cpp +++ b/js/jetpack/JetpackParent.cpp @@ -103,7 +103,7 @@ JetpackParent::SendMessage(const nsAString& aMessageName) NS_IMETHODIMP JetpackParent::RegisterReceiver(const nsAString& aMessageName, - jsval aReceiver) + const jsval &aReceiver) { return JetpackActorCommon::RegisterReceiver(mContext, nsString(aMessageName), @@ -112,7 +112,7 @@ JetpackParent::RegisterReceiver(const nsAString& aMessageName, NS_IMETHODIMP JetpackParent::UnregisterReceiver(const nsAString& aMessageName, - jsval aReceiver) + const jsval &aReceiver) { JetpackActorCommon::UnregisterReceiver(nsString(aMessageName), aReceiver); diff --git a/js/jsd/jsd.h b/js/jsd/jsd.h index c07112dbdce9..75a48c931c75 100644 --- a/js/jsd/jsd.h +++ b/js/jsd/jsd.h @@ -966,7 +966,7 @@ jsd_GetValueBoolean(JSDContext* jsdc, JSDValue* jsdval); extern int32 jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval); -extern jsdouble* +extern jsdouble jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval); extern JSString* diff --git a/js/jsd/jsd_val.c b/js/jsd/jsd_val.c index 73b836681952..44a33f951123 100644 --- a/js/jsd/jsd_val.c +++ b/js/jsd/jsd_val.c @@ -203,13 +203,12 @@ jsd_GetValueInt(JSDContext* jsdc, JSDValue* jsdval) return JSVAL_TO_INT(val); } -jsdouble* +jsdouble jsd_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval) { - jsval val = jsdval->val; - if(!JSVAL_IS_DOUBLE(val)) + if(!JSVAL_IS_DOUBLE(jsdval->val)) return 0; - return JSVAL_TO_DOUBLE(val); + return JSVAL_TO_DOUBLE(jsdval->val); } JSString* @@ -492,7 +491,8 @@ jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name) JSPropertyDesc pd; const jschar * nameChars; size_t nameLen; - jsval val; + jsval val, nameval; + jsid nameid; if(!jsd_IsValueObject(jsdc, jsdval)) return NULL; @@ -548,8 +548,14 @@ jsd_GetValueProperty(JSDContext* jsdc, JSDValue* jsdval, JSString* name) JS_EndRequest(cx); - pd.id = STRING_TO_JSVAL(name); - pd.alias = pd.slot = pd.spare = 0; + nameval = STRING_TO_JSVAL(name); + if (!JS_ValueToId(cx, nameval, &nameid) || + !JS_IdToValue(cx, nameid, &pd.id)) { + return NULL; + } + + pd.slot = pd.spare = 0; + pd.alias = JSVAL_NULL; pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0 | (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0 | (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0; diff --git a/js/jsd/jsd_xpc.cpp b/js/jsd/jsd_xpc.cpp index d64ffa4365e1..800280c7bfc6 100644 --- a/js/jsd/jsd_xpc.cpp +++ b/js/jsd/jsd_xpc.cpp @@ -38,8 +38,6 @@ * ***** END LICENSE BLOCK ***** */ #include "jsdbgapi.h" -#include "jscntxt.h" -#include "jsfun.h" #include "jsd_xpc.h" #include "nsIXPConnect.h" @@ -1014,7 +1012,8 @@ jsdScript::CreatePPLineMap() PRBool scriptOwner = PR_FALSE; if (fun) { - if (fun->nargs > 12) + uintN nargs = JS_GetFunctionArgumentCount(cx, fun); + if (nargs > 12) return nsnull; JSString *jsstr = JS_DecompileFunctionBody (cx, fun, 4); if (!jsstr) @@ -1023,7 +1022,7 @@ jsdScript::CreatePPLineMap() const char *argnames[] = {"arg1", "arg2", "arg3", "arg4", "arg5", "arg6", "arg7", "arg8", "arg9", "arg10", "arg11", "arg12" }; - fun = JS_CompileUCFunction (cx, obj, "ppfun", fun->nargs, argnames, + fun = JS_CompileUCFunction (cx, obj, "ppfun", nargs, argnames, JS_GetStringChars(jsstr), JS_GetStringLength(jsstr), "x-jsd:ppbuffer?type=function", 3); @@ -1232,37 +1231,32 @@ jsdScript::GetParameterNames(PRUint32* count, PRUnichar*** paramNames) JSAutoRequest ar(cx); - if (!fun || !fun->hasLocalNames() || fun->nargs == 0) { + uintN nargs = JS_GetFunctionArgumentCount(cx, fun); + if (!fun || !JS_FunctionHasLocalNames(cx, fun) || nargs == 0) { *count = 0; *paramNames = nsnull; return NS_OK; } PRUnichar **ret = - static_cast(NS_Alloc(fun->nargs * sizeof(PRUnichar*))); + static_cast(NS_Alloc(nargs * sizeof(PRUnichar*))); if (!ret) return NS_ERROR_OUT_OF_MEMORY; - void *mark = JS_ARENA_MARK(&cx->tempPool); - jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool); + void *mark; + jsuword *names = JS_GetFunctionLocalNameArray(cx, fun, &mark); if (!names) { NS_Free(ret); return NS_ERROR_OUT_OF_MEMORY; } nsresult rv = NS_OK; - for (uintN i = 0; i < fun->nargs; ++i) { - JSAtom *atom = JS_LOCAL_NAME_TO_ATOM(names[i]); + for (uintN i = 0; i < nargs; ++i) { + JSAtom *atom = JS_LocalNameToAtom(names[i]); if (!atom) { ret[i] = 0; } else { - jsval atomVal = ATOM_KEY(atom); - if (!JSVAL_IS_STRING(atomVal)) { - NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret); - rv = NS_ERROR_UNEXPECTED; - break; - } - JSString *str = JSVAL_TO_STRING(atomVal); + JSString *str = JS_AtomKey(atom); ret[i] = NS_strndup(reinterpret_cast(JS_GetStringChars(str)), JS_GetStringLength(str)); if (!ret[i]) { @@ -1272,10 +1266,10 @@ jsdScript::GetParameterNames(PRUint32* count, PRUnichar*** paramNames) } } } - JS_ARENA_RELEASE(&cx->tempPool, mark); + JS_ReleaseFunctionLocalNameArray(cx, mark); if (NS_FAILED(rv)) return rv; - *count = fun->nargs; + *count = nargs; *paramNames = ret; return NS_OK; } @@ -1484,8 +1478,7 @@ jsdScript::SetBreakpoint(PRUint32 aPC) { ASSERT_VALID_EPHEMERAL; jsuword pc = mFirstPC + aPC; - JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, - reinterpret_cast(PRIVATE_TO_JSVAL(NULL))); + JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL); return NS_OK; } @@ -1990,7 +1983,7 @@ jsdStackFrame::Eval (const nsAString &bytes, const nsACString &fileName, if (JS_IsExceptionPending(cx)) JS_GetPendingException (cx, &jv); else - jv = 0; + jv = JSVAL_NULL; } JS_RestoreExceptionState (cx, estate); @@ -2195,10 +2188,7 @@ NS_IMETHODIMP jsdValue::GetDoubleValue(double *_rval) { ASSERT_VALID_EPHEMERAL; - double *dp = JSD_GetValueDouble (mCx, mValue); - if (!dp) - return NS_ERROR_FAILURE; - *_rval = *dp; + *_rval = JSD_GetValueDouble (mCx, mValue); return NS_OK; } @@ -2907,7 +2897,7 @@ jsdService::WrapValue(jsdIValue **_rval) } NS_IMETHODIMP -jsdService::WrapJSValue(jsval value, jsdIValue** _rval) +jsdService::WrapJSValue(const jsval &value, jsdIValue** _rval) { JSDValue *jsdv = JSD_NewValue(mCx, value); if (!jsdv) diff --git a/js/jsd/jsdebug.c b/js/jsd/jsdebug.c index ed0fb4eb4a92..8f29fef588af 100644 --- a/js/jsd/jsdebug.c +++ b/js/jsd/jsdebug.c @@ -1112,7 +1112,7 @@ JSD_GetValueInt(JSDContext* jsdc, JSDValue* jsdval) return jsd_GetValueInt(jsdc, jsdval); } -JSD_PUBLIC_API(jsdouble*) +JSD_PUBLIC_API(jsdouble) JSD_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval) { JSD_ASSERT_VALID_CONTEXT(jsdc); diff --git a/js/jsd/jsdebug.h b/js/jsd/jsdebug.h index d7ea5a34c167..91e923f1c32b 100644 --- a/js/jsd/jsdebug.h +++ b/js/jsd/jsdebug.h @@ -54,13 +54,11 @@ extern "C" } #endif -JS_BEGIN_EXTERN_C #include "jsapi.h" #include "jsdbgapi.h" #ifdef LIVEWIRE #include "lwdbgapi.h" #endif -JS_END_EXTERN_C JS_BEGIN_EXTERN_C @@ -1270,7 +1268,7 @@ JSD_GetValueInt(JSDContext* jsdc, JSDValue* jsdval); * Return double value (does NOT do conversion). * *** new for version 1.1 **** */ -extern JSD_PUBLIC_API(jsdouble*) +extern JSD_PUBLIC_API(jsdouble) JSD_GetValueDouble(JSDContext* jsdc, JSDValue* jsdval); /* diff --git a/js/src/Makefile.in b/js/src/Makefile.in index f4e155dc5a2f..fc640644505e 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -226,6 +226,7 @@ INSTALLED_HEADERS = \ jsscript.h \ jsscriptinlines.h \ jsstaticcheck.h \ + jsstdint.h \ jsstr.h \ jstask.h \ jstracer.h \ @@ -239,6 +240,8 @@ INSTALLED_HEADERS = \ jswrapper.h \ jsxdrapi.h \ jsxml.h \ + jsval.h \ + jsvalue.h \ prmjtime.h \ $(NULL) diff --git a/js/src/builtins.tbl b/js/src/builtins.tbl deleted file mode 100644 index 0c1c07c000f6..000000000000 --- a/js/src/builtins.tbl +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=0 ft=C: - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (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.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released - * June 22, 2008. - * - * The Initial Developer of the Original Code is - * Andreas Gal - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * This file declares builtin functions that can be called from JITted code. - * Each line starts with "BUILTIN" and an integer, the number of arguments the - * builtin takes. Builtins with no arguments are not supported. - * - * The macro arguments are: - * - * - 'extern' to indicate extern linkage for these functions and the associated - * CallInfo. - * - * - The return type. This identifier must name one of the _JS_TYPEINFO_* - * macros defined in jsbuiltins.h. - * - * - The builtin name. Prefixed with "js_" this gives the native function name. - * - * - The parameter types. - * - * - The cse flag. 1 if the builtin call can be optimized away by common - * subexpression elimination; otherwise 0. This should be 1 only if the - * function is idempotent and the return value is determined solely by the - * arguments. - * - * - The fold flag. Reserved. The same as cse for now. - */ - -/* - * NB: bool FASTCALL is not compatible with Nanojit's calling convention usage. - * Do not use bool FASTCALL, use JSBool only! - */ - -BUILTIN2(extern, JSVAL, js_BoxDouble, CONTEXT, DOUBLE, 1, 1) -BUILTIN2(extern, JSVAL, js_BoxInt32, CONTEXT, INT32, 1, 1) -BUILTIN1(extern, DOUBLE, js_UnboxDouble, JSVAL, 1, 1) -BUILTIN1(extern, INT32, js_UnboxInt32, JSVAL, 1, 1) -BUILTIN2(extern, DOUBLE, js_dmod, DOUBLE, DOUBLE, 1, 1) -BUILTIN2(extern, INT32, js_imod, INT32, INT32, 1, 1) -BUILTIN1(extern, INT32, js_DoubleToInt32, DOUBLE, 1, 1) -BUILTIN1(extern, UINT32, js_DoubleToUint32, DOUBLE, 1, 1) - -BUILTIN2(extern, DOUBLE, js_StringToNumber, CONTEXT, STRING, 1, 1) -BUILTIN2(extern, INT32, js_StringToInt32, CONTEXT, STRING, 1, 1) -BUILTIN2(FRIEND, BOOL, js_CloseIterator, CONTEXT, JSVAL, 0, 0) -BUILTIN2(extern, SIDEEXIT, js_CallTree, INTERPSTATE, FRAGMENT, 0, 0) -BUILTIN3(extern, BOOL, js_AddProperty, CONTEXT, OBJECT, SCOPEPROP, 0, 0) -BUILTIN3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING, 0, 0) -BUILTIN3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32, 0, 0) -BUILTIN3(extern, JSVAL, js_CallGetter, CONTEXT, OBJECT, SCOPEPROP, 0, 0) -BUILTIN2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, 1) -BUILTIN2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32, 1, 1) -BUILTIN2(extern, DOUBLE, js_BooleanOrUndefinedToNumber, CONTEXT, INT32, 1, 1) -BUILTIN2(extern, STRING, js_BooleanOrUndefinedToString, CONTEXT, INT32, 1, 1) -BUILTIN2(extern, OBJECT, js_Arguments, CONTEXT, OBJECT 0, 0) -BUILTIN4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT, 0, 0) diff --git a/js/src/configure.in b/js/src/configure.in index 7c13d356743d..ed29a1206f2e 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -519,7 +519,8 @@ case "$target" in CFLAGS="$CFLAGS -TC -nologo" CXXFLAGS="$CXXFLAGS -TP -nologo" # MSVC warning C4345 warns of newly conformant behavior as of VS2003. - CXXFLAGS="$CXXFLAGS -wd4345" + # MSVC warning C4800 is ubiquitous, useless, and annoying. + CXXFLAGS="$CXXFLAGS -wd4345 -wd4800" AC_LANG_SAVE AC_LANG_C AC_TRY_COMPILE([#include ], diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index 38aae3b07e8a..c2e5a3aec6b6 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -89,17 +89,17 @@ namespace CType { static void Finalize(JSContext* cx, JSObject* obj); static void FinalizeProtoClass(JSContext* cx, JSObject* obj); - static JSBool PrototypeGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool PrototypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool NameGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool NameGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool SizeGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool SizeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool PtrGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); + static JSBool PtrGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool CreateArray(JSContext* cx, uintN argc, jsval* vp); static JSBool ToString(JSContext* cx, uintN argc, jsval* vp); static JSBool ToSource(JSContext* cx, uintN argc, jsval* vp); - static JSBool HasInstance(JSContext* cx, JSObject* obj, jsval v, JSBool* bp); + static JSBool HasInstance(JSContext* cx, JSObject* obj, const jsval *v, JSBool* bp); } namespace PointerType { @@ -107,11 +107,11 @@ namespace PointerType { static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); - static JSBool TargetTypeGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool TargetTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool ContentsGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool ContentsGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool ContentsSetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool ContentsSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool IsNull(JSContext* cx, uintN argc, jsval* vp); } @@ -121,12 +121,12 @@ namespace ArrayType { static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); - static JSBool ElementTypeGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool ElementTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool LengthGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool LengthGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool Getter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); - static JSBool Setter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); + static JSBool Getter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); + static JSBool Setter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool AddressOfElement(JSContext* cx, uintN argc, jsval* vp); } @@ -135,11 +135,11 @@ namespace StructType { static JSBool ConstructData(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); - static JSBool FieldsArrayGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool FieldsArrayGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool FieldGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool FieldGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool FieldSetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool FieldSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool AddressOfField(JSContext* cx, uintN argc, jsval* vp); static JSBool Define(JSContext* cx, uintN argc, jsval* vp); @@ -153,12 +153,12 @@ namespace FunctionType { static JSBool Call(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); - static JSBool ArgTypesGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool ArgTypesGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool ReturnTypeGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool ReturnTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool ABIGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp); - static JSBool IsVariadicGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool ABIGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); + static JSBool IsVariadicGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); } @@ -174,9 +174,9 @@ namespace CClosure { namespace CData { static void Finalize(JSContext* cx, JSObject* obj); - static JSBool ValueGetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool ValueGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); - static JSBool ValueSetter(JSContext* cx, JSObject* obj, jsval idval, + static JSBool ValueSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp); static JSBool Address(JSContext* cx, uintN argc, jsval* vp); static JSBool ReadString(JSContext* cx, uintN argc, jsval* vp); @@ -514,7 +514,7 @@ JSBool TypeError(JSContext* cx, const char* expected, jsval actual) { JSString* str = JS_ValueToSource(cx, actual); - js::AutoValueRooter root(cx, str); + js::AutoStringRooter root(cx, str); const char* src; if (str) { @@ -682,7 +682,7 @@ InitTypeConstructor(JSContext* cx, dataProto = JS_NewObject(cx, &sCDataProtoClass, CDataProto, parent); if (!dataProto) return false; - js::AutoValueRooter protoroot(cx, dataProto); + js::AutoObjectRooter protoroot(cx, dataProto); // Define functions and properties on the 'dataProto' object that are common // to all CData objects created from this type constructor. (These will @@ -816,27 +816,27 @@ InitTypeClasses(JSContext* cx, JSObject* parent) sPointerInstanceFunctions, sPointerInstanceProps, protos[SLOT_POINTERPROTO], protos[SLOT_POINTERDATAPROTO])) return false; - js::AutoValueRooter proot(cx, protos[SLOT_POINTERDATAPROTO]); + js::AutoObjectRooter proot(cx, protos[SLOT_POINTERDATAPROTO]); if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, sArrayFunction, NULL, sArrayProps, sArrayInstanceFunctions, sArrayInstanceProps, protos[SLOT_ARRAYPROTO], protos[SLOT_ARRAYDATAPROTO])) return false; - js::AutoValueRooter aroot(cx, protos[SLOT_ARRAYDATAPROTO]); + js::AutoObjectRooter aroot(cx, protos[SLOT_ARRAYDATAPROTO]); if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, sStructFunction, sStructFunctions, sStructProps, sStructInstanceFunctions, NULL, protos[SLOT_STRUCTPROTO], protos[SLOT_STRUCTDATAPROTO])) return false; - js::AutoValueRooter sroot(cx, protos[SLOT_STRUCTDATAPROTO]); + js::AutoObjectRooter sroot(cx, protos[SLOT_STRUCTDATAPROTO]); if (!InitTypeConstructor(cx, parent, CTypeProto, CDataProto, sFunctionFunction, NULL, sFunctionProps, NULL, NULL, protos[SLOT_FUNCTIONPROTO], protos[SLOT_FUNCTIONDATAPROTO])) return false; - js::AutoValueRooter froot(cx, protos[SLOT_FUNCTIONDATAPROTO]); + js::AutoObjectRooter froot(cx, protos[SLOT_FUNCTIONDATAPROTO]); protos[SLOT_CDATAPROTO] = CDataProto; @@ -1106,7 +1106,7 @@ jsvalToBool(JSContext* cx, jsval val, bool* result) return i == 0 || i == 1; } if (JSVAL_IS_DOUBLE(val)) { - jsdouble d = *JSVAL_TO_DOUBLE(val); + jsdouble d = JSVAL_TO_DOUBLE(val); *result = d != 0; // Allow -0. return d == 1 || d == 0; @@ -1133,7 +1133,7 @@ jsvalToInteger(JSContext* cx, jsval val, IntegerType* result) if (JSVAL_IS_DOUBLE(val)) { // Don't silently lose bits here -- check that val really is an // integer value, and has the right sign. - jsdouble d = *JSVAL_TO_DOUBLE(val); + jsdouble d = JSVAL_TO_DOUBLE(val); return ConvertExact(d, result); } if (!JSVAL_IS_PRIMITIVE(val)) { @@ -1214,7 +1214,7 @@ jsvalToFloat(JSContext *cx, jsval val, FloatType* result) return true; } if (JSVAL_IS_DOUBLE(val)) { - *result = FloatType(*JSVAL_TO_DOUBLE(val)); + *result = FloatType(JSVAL_TO_DOUBLE(val)); return true; } if (!JSVAL_IS_PRIMITIVE(val)) { @@ -1276,7 +1276,7 @@ jsvalToBigInteger(JSContext* cx, if (JSVAL_IS_DOUBLE(val)) { // Don't silently lose bits here -- check that val really is an // integer value, and has the right sign. - jsdouble d = *JSVAL_TO_DOUBLE(val); + jsdouble d = JSVAL_TO_DOUBLE(val); return ConvertExact(d, result); } if (allowString && JSVAL_IS_STRING(val)) { @@ -1317,6 +1317,62 @@ jsvalToSize(JSContext* cx, jsval val, bool allowString, size_t* result) return Convert(jsdouble(*result)) == *result; } +// Implicitly convert val to IntegerType, allowing jsint, jsdouble, +// Int64, UInt64, and optionally a decimal or hexadecimal string argument. +// (This is common code shared by jsvalToSize and the Int64/UInt64 constructors.) +template +static bool +jsidToBigInteger(JSContext* cx, + jsid val, + bool allowString, + IntegerType* result) +{ + JS_STATIC_ASSERT(numeric_limits::is_exact); + + if (JSID_IS_INT(val)) { + // Make sure the integer fits in the alotted precision, and has the right + // sign. + jsint i = JSID_TO_INT(val); + return ConvertExact(i, result); + } + if (allowString && JSID_IS_STRING(val)) { + // Allow conversion from base-10 or base-16 strings, provided the result + // fits in IntegerType. (This allows an Int64 or UInt64 object to be passed + // to the JS array element operator, which will automatically call + // toString() on the object for us.) + return StringToInteger(cx, JSID_TO_STRING(val), result); + } + if (JSID_IS_OBJECT(val)) { + // Allow conversion from an Int64 or UInt64 object directly. + JSObject* obj = JSID_TO_OBJECT(val); + + if (UInt64::IsUInt64(cx, obj)) { + // Make sure the integer fits in IntegerType. + JSUint64 i = Int64Base::GetInt(cx, obj); + return ConvertExact(i, result); + } + + if (Int64::IsInt64(cx, obj)) { + // Make sure the integer fits in IntegerType. + JSInt64 i = Int64Base::GetInt(cx, obj); + return ConvertExact(i, result); + } + } + return false; +} + +// Implicitly convert val to a size value, where the size value is represented +// by size_t but must also fit in a jsdouble. +static bool +jsidToSize(JSContext* cx, jsid val, bool allowString, size_t* result) +{ + if (!jsidToBigInteger(cx, val, allowString, result)) + return false; + + // Also check that the result fits in a jsdouble. + return Convert(jsdouble(*result)) == *result; +} + // Implicitly convert a size value to a jsval, ensuring that the size_t value // fits in a jsdouble. static JSBool @@ -1339,7 +1395,7 @@ jsvalToIntegerExplicit(JSContext* cx, jsval val, IntegerType* result) if (JSVAL_IS_DOUBLE(val)) { // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast. - jsdouble d = *JSVAL_TO_DOUBLE(val); + jsdouble d = JSVAL_TO_DOUBLE(val); *result = FloatIsFinite(d) ? IntegerType(d) : 0; return true; } @@ -1372,7 +1428,7 @@ jsvalToPtrExplicit(JSContext* cx, jsval val, uintptr_t* result) return true; } if (JSVAL_IS_DOUBLE(val)) { - jsdouble d = *JSVAL_TO_DOUBLE(val); + jsdouble d = JSVAL_TO_DOUBLE(val); if (d < 0) { // Cast through an intptr_t intermediate to sign-extend. intptr_t i = Convert(d); @@ -1859,11 +1915,11 @@ ImplicitConvert(JSContext* cx, for (jsuint i = 0; i < sourceLength; ++i) { js::AutoValueRooter item(cx); - if (!JS_GetElement(cx, sourceArray, i, item.addr())) + if (!JS_GetElement(cx, sourceArray, i, item.jsval_addr())) return false; char* data = intermediate.get() + elementSize * i; - if (!ImplicitConvert(cx, item.value(), baseType, data, false, NULL)) + if (!ImplicitConvert(cx, item.jsval_value(), baseType, data, false, NULL)) return false; } @@ -1884,7 +1940,7 @@ ImplicitConvert(JSContext* cx, JSObject* iter = JS_NewPropertyIterator(cx, obj); if (!iter) return false; - js::AutoValueRooter iterroot(cx, iter); + js::AutoObjectRooter iterroot(cx, iter); // Convert into an intermediate, in case of failure. size_t structSize = CType::GetSize(cx, targetType); @@ -1899,30 +1955,29 @@ ImplicitConvert(JSContext* cx, while (1) { if (!JS_NextProperty(cx, iter, &id)) return false; - if (JSVAL_IS_VOID(id)) + if (JSID_IS_VOID(id)) break; js::AutoValueRooter fieldVal(cx); - if (!JS_IdToValue(cx, id, fieldVal.addr())) - return false; - if (!JSVAL_IS_STRING(fieldVal.value())) { + JS_IdToValue(cx, id, fieldVal.jsval_addr()); + if (!JSVAL_IS_STRING(fieldVal.jsval_value())) { JS_ReportError(cx, "property name is not a string"); return false; } const FieldInfo* field = StructType::LookupField(cx, targetType, - fieldVal.value()); + JSVAL_TO_STRING(fieldVal.jsval_value())); if (!field) return false; - JSString* name = JSVAL_TO_STRING(fieldVal.value()); + JSString* name = JSVAL_TO_STRING(fieldVal.jsval_value()); js::AutoValueRooter prop(cx); - if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), prop.addr())) + if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), prop.jsval_addr())) return false; // Convert the field via ImplicitConvert(). char* fieldData = intermediate.get() + field->mOffset; - if (!ImplicitConvert(cx, prop.value(), field->mType, fieldData, false, NULL)) + if (!ImplicitConvert(cx, prop.jsval_value(), field->mType, fieldData, false, NULL)) return false; ++i; @@ -1963,7 +2018,7 @@ ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType, void* buffer) // hard failure (out of memory, or some other similarly serious condition). // We store any pending exception in case we need to re-throw it. js::AutoValueRooter ex(cx); - if (!JS_GetPendingException(cx, ex.addr())) + if (!JS_GetPendingException(cx, ex.jsval_addr())) return false; // Otherwise, assume soft failure. Clear the pending exception so that we @@ -2011,7 +2066,7 @@ ExplicitConvert(JSContext* cx, jsval val, JSObject* targetType, void* buffer) case TYPE_array: case TYPE_struct: // ImplicitConvert is sufficient. Re-throw the exception it generated. - JS_SetPendingException(cx, ex.value()); + JS_SetPendingException(cx, ex.jsval_value()); return false; case TYPE_void_t: case TYPE_function: @@ -2529,7 +2584,7 @@ CType::Create(JSContext* cx, JSObject* typeObj = JS_NewObject(cx, &sCTypeClass, typeProto, parent); if (!typeObj) return NULL; - js::AutoValueRooter root(cx, typeObj); + js::AutoObjectRooter root(cx, typeObj); // Set up the reserved slots. if (!JS_SetReservedSlot(cx, typeObj, SLOT_TYPECODE, INT_TO_JSVAL(type)) || @@ -2544,7 +2599,7 @@ CType::Create(JSContext* cx, JSObject* prototype = JS_NewObject(cx, &sCDataProtoClass, dataProto, parent); if (!prototype) return NULL; - js::AutoValueRooter protoroot(cx, prototype); + js::AutoObjectRooter protoroot(cx, prototype); if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT)) @@ -2582,7 +2637,7 @@ CType::DefineBuiltin(JSContext* cx, JSString* nameStr = JS_NewStringCopyZ(cx, name); if (!nameStr) return NULL; - js::AutoValueRooter nameRoot(cx, nameStr); + js::AutoStringRooter nameRoot(cx, nameStr); // Create a new CType object with the common properties and slots. JSObject* typeObj = Create(cx, typeProto, dataProto, type, nameStr, size, @@ -2808,7 +2863,7 @@ CType::GetSafeSize(JSContext* cx, JSObject* obj, size_t* result) return true; } if (JSVAL_IS_DOUBLE(size)) { - *result = Convert(*JSVAL_TO_DOUBLE(size)); + *result = Convert(JSVAL_TO_DOUBLE(size)); return true; } @@ -2831,7 +2886,7 @@ CType::GetSize(JSContext* cx, JSObject* obj) // For callers who know it can never be JSVAL_VOID, return a size_t directly. if (JSVAL_IS_INT(size)) return JSVAL_TO_INT(size); - return Convert(*JSVAL_TO_DOUBLE(size)); + return Convert(JSVAL_TO_DOUBLE(size)); } bool @@ -2944,7 +2999,7 @@ CType::GetProtoFromType(JSContext* cx, JSObject* obj, CTypeProtoSlot slot) } JSBool -CType::PrototypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +CType::PrototypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CType::IsCType(cx, obj)) { JS_ReportError(cx, "not a CType"); @@ -2957,7 +3012,7 @@ CType::PrototypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) } JSBool -CType::NameGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +CType::NameGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CType::IsCType(cx, obj)) { JS_ReportError(cx, "not a CType"); @@ -2973,7 +3028,7 @@ CType::NameGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) } JSBool -CType::SizeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +CType::SizeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CType::IsCType(cx, obj)) { JS_ReportError(cx, "not a CType"); @@ -2986,7 +3041,7 @@ CType::SizeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) } JSBool -CType::PtrGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +CType::PtrGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CType::IsCType(cx, obj)) { JS_ReportError(cx, "not a CType"); @@ -3079,7 +3134,7 @@ CType::ToSource(JSContext* cx, uintN argc, jsval *vp) } JSBool -CType::HasInstance(JSContext* cx, JSObject* obj, jsval v, JSBool* bp) +CType::HasInstance(JSContext* cx, JSObject* obj, const jsval *v, JSBool* bp) { JS_ASSERT(CType::IsCType(cx, obj)); @@ -3090,10 +3145,10 @@ CType::HasInstance(JSContext* cx, JSObject* obj, jsval v, JSBool* bp) JS_ASSERT(JS_GET_CLASS(cx, prototype) == &sCDataProtoClass); *bp = JS_FALSE; - if (JSVAL_IS_PRIMITIVE(v)) + if (JSVAL_IS_PRIMITIVE(*v)) return JS_TRUE; - JSObject* proto = JSVAL_TO_OBJECT(v); + JSObject* proto = JSVAL_TO_OBJECT(*v); while ((proto = JS_GetPrototype(cx, proto))) { if (proto == prototype) { *bp = JS_TRUE; @@ -3153,7 +3208,7 @@ PointerType::CreateInternal(JSContext* cx, JSObject* baseType) &ffi_type_pointer); if (!typeObj) return NULL; - js::AutoValueRooter root(cx, typeObj); + js::AutoObjectRooter root(cx, typeObj); // Set the target type. (This will be 'null' for an opaque pointer type.) if (!JS_SetReservedSlot(cx, typeObj, SLOT_TARGET_T, OBJECT_TO_JSVAL(baseType))) @@ -3238,7 +3293,7 @@ PointerType::GetBaseType(JSContext* cx, JSObject* obj) JSBool PointerType::TargetTypeGetter(JSContext* cx, JSObject* obj, - jsval idval, + jsid idval, jsval* vp) { if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_pointer) { @@ -3278,7 +3333,7 @@ PointerType::IsNull(JSContext* cx, uintN argc, jsval* vp) JSBool PointerType::ContentsGetter(JSContext* cx, JSObject* obj, - jsval idval, + jsid idval, jsval* vp) { if (!CData::IsCData(cx, obj)) { @@ -3316,7 +3371,7 @@ PointerType::ContentsGetter(JSContext* cx, JSBool PointerType::ContentsSetter(JSContext* cx, JSObject* obj, - jsval idval, + jsid idval, jsval* vp) { if (!CData::IsCData(cx, obj)) { @@ -3423,7 +3478,7 @@ ArrayType::CreateInternal(JSContext* cx, sizeVal, INT_TO_JSVAL(align), NULL); if (!typeObj) return NULL; - js::AutoValueRooter root(cx, typeObj); + js::AutoObjectRooter root(cx, typeObj); // Set the element type. if (!JS_SetReservedSlot(cx, typeObj, SLOT_ELEMENT_T, OBJECT_TO_JSVAL(baseType))) @@ -3478,8 +3533,8 @@ ArrayType::ConstructData(JSContext* cx, // This could be a JS array, or a CData array. JSObject* arg = JSVAL_TO_OBJECT(argv[0]); js::AutoValueRooter lengthVal(cx); - if (!JS_GetProperty(cx, arg, "length", lengthVal.addr()) || - !jsvalToSize(cx, lengthVal.value(), false, &length)) { + if (!JS_GetProperty(cx, arg, "length", lengthVal.jsval_addr()) || + !jsvalToSize(cx, lengthVal.jsval_value(), false, &length)) { JS_ReportError(cx, "argument must be an array object or length"); return JS_FALSE; } @@ -3522,7 +3577,7 @@ ArrayType::ConstructData(JSContext* cx, } // Root the CType object, in case we created one above. - js::AutoValueRooter root(cx, obj); + js::AutoObjectRooter root(cx, obj); JSObject* result = CData::Create(cx, obj, NULL, NULL, true); if (!result) @@ -3566,7 +3621,7 @@ ArrayType::GetSafeLength(JSContext* cx, JSObject* obj, size_t* result) return true; } if (JSVAL_IS_DOUBLE(length)) { - *result = Convert(*JSVAL_TO_DOUBLE(length)); + *result = Convert(JSVAL_TO_DOUBLE(length)); return true; } @@ -3590,7 +3645,7 @@ ArrayType::GetLength(JSContext* cx, JSObject* obj) // For callers who know it can never be JSVAL_VOID, return a size_t directly. if (JSVAL_IS_INT(length)) return JSVAL_TO_INT(length); - return Convert(*JSVAL_TO_DOUBLE(length)); + return Convert(JSVAL_TO_DOUBLE(length)); } ffi_type* @@ -3637,7 +3692,7 @@ ArrayType::BuildFFIType(JSContext* cx, JSObject* obj) } JSBool -ArrayType::ElementTypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +ArrayType::ElementTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_array) { JS_ReportError(cx, "not an ArrayType"); @@ -3650,7 +3705,7 @@ ArrayType::ElementTypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* v } JSBool -ArrayType::LengthGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +ArrayType::LengthGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { // This getter exists for both CTypes and CDatas of the ArrayType persuasion. // If we're dealing with a CData, get the CType from it. @@ -3668,7 +3723,7 @@ ArrayType::LengthGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) } JSBool -ArrayType::Getter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +ArrayType::Getter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { // This should never happen, but we'll check to be safe. if (!CData::IsCData(cx, obj)) { @@ -3685,8 +3740,8 @@ ArrayType::Getter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) // Convert the index to a size_t and bounds-check it. size_t index; size_t length = GetLength(cx, typeObj); - bool ok = jsvalToSize(cx, idval, true, &index); - if (!ok && JSVAL_IS_STRING(idval)) { + bool ok = jsidToSize(cx, idval, true, &index); + if (!ok && JSID_IS_STRING(idval)) { // String either isn't a number, or doesn't fit in size_t. // Chances are it's a regular property lookup, so return. return JS_TRUE; @@ -3703,7 +3758,7 @@ ArrayType::Getter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) } JSBool -ArrayType::Setter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +ArrayType::Setter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { // This should never happen, but we'll check to be safe. if (!CData::IsCData(cx, obj)) { @@ -3720,8 +3775,8 @@ ArrayType::Setter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) // Convert the index to a size_t and bounds-check it. size_t index; size_t length = GetLength(cx, typeObj); - bool ok = jsvalToSize(cx, idval, true, &index); - if (!ok && JSVAL_IS_STRING(idval)) { + bool ok = jsidToSize(cx, idval, true, &index); + if (!ok && JSID_IS_STRING(idval)) { // String either isn't a number, or doesn't fit in size_t. // Chances are it's a regular property lookup, so return. return JS_TRUE; @@ -3763,7 +3818,7 @@ ArrayType::AddressOfElement(JSContext* cx, uintN argc, jsval *vp) JSObject* pointerType = PointerType::CreateInternal(cx, baseType); if (!pointerType) return JS_FALSE; - js::AutoValueRooter root(cx, pointerType); + js::AutoObjectRooter root(cx, pointerType); // Create a PointerType CData object containing null. JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true); @@ -3806,35 +3861,38 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj) JSObject* iter = JS_NewPropertyIterator(cx, obj); if (!iter) return NULL; - js::AutoValueRooter iterroot(cx, iter); + js::AutoObjectRooter iterroot(cx, iter); jsid id; if (!JS_NextProperty(cx, iter, &id)) return NULL; - - js::AutoValueRooter nameVal(cx); - if (!JS_IdToValue(cx, id, nameVal.addr())) - return NULL; - if (!JSVAL_IS_STRING(nameVal.value())) { + if (JSID_IS_VOID(id)) { JS_ReportError(cx, "struct field descriptors require a valid name and type"); return NULL; } - JSString* name = JSVAL_TO_STRING(nameVal.value()); + + js::AutoValueRooter nameVal(cx); + JS_IdToValue(cx, id, nameVal.jsval_addr()); + if (!JSVAL_IS_STRING(nameVal.jsval_value())) { + JS_ReportError(cx, "struct field descriptors require a valid name and type"); + return NULL; + } + JSString* name = JSVAL_TO_STRING(nameVal.jsval_value()); // make sure we have one, and only one, property if (!JS_NextProperty(cx, iter, &id)) return NULL; - if (!JSVAL_IS_VOID(id)) { + if (!JSID_IS_VOID(id)) { JS_ReportError(cx, "struct field descriptors must contain one property"); return NULL; } js::AutoValueRooter propVal(cx); - if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), propVal.addr())) + if (!JS_GetUCProperty(cx, obj, name->chars(), name->length(), propVal.jsval_addr())) return NULL; - if (JSVAL_IS_PRIMITIVE(propVal.value()) || - !CType::IsCType(cx, JSVAL_TO_OBJECT(propVal.value()))) { + if (propVal.value().isPrimitive() || + !CType::IsCType(cx, JSVAL_TO_OBJECT(propVal.jsval_value()))) { JS_ReportError(cx, "struct field descriptors require a valid name and type"); return NULL; } @@ -3842,7 +3900,7 @@ ExtractStructField(JSContext* cx, jsval val, JSObject** typeObj) // Undefined size or zero size struct members are illegal. // (Zero-size arrays are legal as struct members in C++, but libffi will // choke on a zero-size struct, so we disallow them.) - *typeObj = JSVAL_TO_OBJECT(propVal.value()); + *typeObj = JSVAL_TO_OBJECT(propVal.jsval_value()); size_t size; if (!CType::GetSafeSize(cx, *typeObj, &size) || size == 0) { JS_ReportError(cx, "struct field types must have defined and nonzero size"); @@ -3903,7 +3961,7 @@ StructType::Create(JSContext* cx, uintN argc, jsval* vp) JSVAL_TO_STRING(name), JSVAL_VOID, JSVAL_VOID, NULL); if (!result) return JS_FALSE; - js::AutoValueRooter root(cx, result); + js::AutoObjectRooter root(cx, result); if (argc == 2) { if (JSVAL_IS_PRIMITIVE(argv[1]) || @@ -3938,7 +3996,7 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj JSObject* prototype = JS_NewObject(cx, &sCDataProtoClass, dataProto, NULL); if (!prototype) return JS_FALSE; - js::AutoValueRooter protoroot(cx, prototype); + js::AutoObjectRooter protoroot(cx, prototype); if (!JS_DefineProperty(cx, prototype, "constructor", OBJECT_TO_JSVAL(typeObj), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT)) @@ -3968,11 +4026,11 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj for (jsuint i = 0; i < len; ++i) { js::AutoValueRooter item(cx); - if (!JS_GetElement(cx, fieldsObj, i, item.addr())) + if (!JS_GetElement(cx, fieldsObj, i, item.jsval_addr())) return JS_FALSE; JSObject* fieldType; - JSString* name = ExtractStructField(cx, item.value(), &fieldType); + JSString* name = ExtractStructField(cx, item.jsval_value(), &fieldType); if (!name) return JS_FALSE; @@ -4238,12 +4296,11 @@ StructType::GetFieldInfo(JSContext* cx, JSObject* obj) } const FieldInfo* -StructType::LookupField(JSContext* cx, JSObject* obj, jsval idval) +StructType::LookupField(JSContext* cx, JSObject* obj, JSString *name) { JS_ASSERT(CType::IsCType(cx, obj)); JS_ASSERT(CType::GetTypeCode(cx, obj) == TYPE_struct); - JSString* name = JSVAL_TO_STRING(idval); FieldInfoHash::Ptr ptr = GetFieldInfo(cx, obj)->lookup(name); if (ptr) return &ptr->value; @@ -4272,7 +4329,7 @@ StructType::BuildFieldsArray(JSContext* cx, JSObject* obj) js_NewArrayObjectWithCapacity(cx, len, &fieldsVec); if (!fieldsProp) return NULL; - js::AutoValueRooter root(cx, fieldsProp); + js::AutoObjectRooter root(cx, fieldsProp); JS_ASSERT(len == 0 || fieldsVec); for (FieldInfoHash::Range r = fields->all(); !r.empty(); r.popFront()) { @@ -4291,7 +4348,7 @@ StructType::BuildFieldsArray(JSContext* cx, JSObject* obj) } JSBool -StructType::FieldsArrayGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +StructType::FieldsArrayGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CType::IsCType(cx, obj) || CType::GetTypeCode(cx, obj) != TYPE_struct) { JS_ReportError(cx, "not a StructType"); @@ -4321,7 +4378,7 @@ StructType::FieldsArrayGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* } JSBool -StructType::FieldGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +StructType::FieldGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CData::IsCData(cx, obj)) { JS_ReportError(cx, "not a CData"); @@ -4334,7 +4391,7 @@ StructType::FieldGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) return JS_FALSE; } - const FieldInfo* field = LookupField(cx, typeObj, idval); + const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_STRING(idval)); if (!field) return JS_FALSE; @@ -4343,7 +4400,7 @@ StructType::FieldGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) } JSBool -StructType::FieldSetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +StructType::FieldSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CData::IsCData(cx, obj)) { JS_ReportError(cx, "not a CData"); @@ -4356,7 +4413,7 @@ StructType::FieldSetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) return JS_FALSE; } - const FieldInfo* field = LookupField(cx, typeObj, idval); + const FieldInfo* field = LookupField(cx, typeObj, JSID_TO_STRING(idval)); if (!field) return JS_FALSE; @@ -4386,7 +4443,8 @@ StructType::AddressOfField(JSContext* cx, uintN argc, jsval *vp) return JS_FALSE; } - const FieldInfo* field = LookupField(cx, typeObj, JS_ARGV(cx, vp)[0]); + const FieldInfo* field = LookupField(cx, typeObj, + JSVAL_TO_STRING(JS_ARGV(cx, vp)[0])); if (!field) return JS_FALSE; @@ -4394,7 +4452,7 @@ StructType::AddressOfField(JSContext* cx, uintN argc, jsval *vp) JSObject* pointerType = PointerType::CreateInternal(cx, baseType); if (!pointerType) return JS_FALSE; - js::AutoValueRooter root(cx, pointerType); + js::AutoObjectRooter root(cx, pointerType); // Create a PointerType CData object containing null. JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true); @@ -4729,7 +4787,7 @@ FunctionType::CreateInternal(JSContext* cx, NULL, JSVAL_VOID, JSVAL_VOID, NULL); if (!typeObj) return NULL; - js::AutoValueRooter root(cx, typeObj); + js::AutoObjectRooter root(cx, typeObj); // Stash the FunctionInfo in a reserved slot. if (!JS_SetReservedSlot(cx, typeObj, SLOT_FNINFO, @@ -4760,7 +4818,7 @@ FunctionType::ConstructData(JSContext* cx, JSObject* closureObj = CClosure::Create(cx, typeObj, fnObj, thisObj, data); if (!closureObj) return JS_FALSE; - js::AutoValueRooter root(cx, closureObj); + js::AutoObjectRooter root(cx, closureObj); // Set the closure object as the referent of the new CData object. if (!JS_SetReservedSlot(cx, dataObj, SLOT_REFERENT, @@ -4945,7 +5003,7 @@ CheckFunctionType(JSContext* cx, JSObject* obj) } JSBool -FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CheckFunctionType(cx, obj)) return JS_FALSE; @@ -4964,7 +5022,7 @@ FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* v js_NewArrayObjectWithCapacity(cx, len, &vec); if (!argTypes) return JS_FALSE; - js::AutoValueRooter argsroot(cx, argTypes); + js::AutoObjectRooter argsroot(cx, argTypes); JS_ASSERT(len == 0 || vec); for (size_t i = 0; i < len; ++i) @@ -4980,7 +5038,7 @@ FunctionType::ArgTypesGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* v } JSBool -FunctionType::ReturnTypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +FunctionType::ReturnTypeGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CheckFunctionType(cx, obj)) return JS_FALSE; @@ -4991,7 +5049,7 @@ FunctionType::ReturnTypeGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* } JSBool -FunctionType::ABIGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +FunctionType::ABIGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CheckFunctionType(cx, obj)) return JS_FALSE; @@ -5002,7 +5060,7 @@ FunctionType::ABIGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) } JSBool -FunctionType::IsVariadicGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +FunctionType::IsVariadicGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!CheckFunctionType(cx, obj)) return JS_FALSE; @@ -5025,7 +5083,7 @@ CClosure::Create(JSContext* cx, JSObject* result = JS_NewObject(cx, &sCClosureClass, NULL, NULL); if (!result) return NULL; - js::AutoValueRooter root(cx, result); + js::AutoObjectRooter root(cx, result); // Get the FunctionInfo from the FunctionType. FunctionInfo* fninfo = FunctionType::GetFunctionInfo(cx, typeObj); @@ -5125,9 +5183,12 @@ CClosure::Trace(JSTracer* trc, JSObject* obj) // Identify our objects to the tracer. (There's no need to identify // 'closureObj', since that's us.) - JS_CALL_TRACER(trc, cinfo->typeObj, JSTRACE_OBJECT, "typeObj"); - JS_CALL_TRACER(trc, cinfo->thisObj, JSTRACE_OBJECT, "thisObj"); - JS_CALL_TRACER(trc, cinfo->jsfnObj, JSTRACE_OBJECT, "jsfnObj"); + if (cinfo->typeObj) + JS_CALL_OBJECT_TRACER(trc, cinfo->typeObj, "typeObj"); + if (cinfo->thisObj) + JS_CALL_OBJECT_TRACER(trc, cinfo->thisObj, "thisObj"); + if (cinfo->jsfnObj) + JS_CALL_OBJECT_TRACER(trc, cinfo->jsfnObj, "jsfnObj"); } void @@ -5177,7 +5238,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) JS_ASSERT(cif == &fninfo->mCIF); // Get a death grip on 'closureObj'. - js::AutoValueRooter root(cx, cinfo->closureObj); + js::AutoObjectRooter root(cx, cinfo->closureObj); // Set up an array for converted arguments. Array argv; @@ -5189,7 +5250,7 @@ CClosure::ClosureStub(ffi_cif* cif, void* result, void** args, void* userData) for (JSUint32 i = 0; i < cif->nargs; ++i) argv[i] = JSVAL_VOID; - js::AutoArrayRooter roots(cx, argv.length(), argv.begin()); + js::AutoArrayRooter roots(cx, argv.length(), Valueify(argv.begin())); for (JSUint32 i = 0; i < cif->nargs; ++i) { // Convert each argument, and have any CData objects created depend on // the existing buffers. @@ -5263,7 +5324,7 @@ CData::Create(JSContext* cx, JSObject* dataObj = JS_NewObject(cx, &sCDataClass, proto, parent); if (!dataObj) return NULL; - js::AutoValueRooter root(cx, dataObj); + js::AutoObjectRooter root(cx, dataObj); // set the CData's associated type if (!JS_SetReservedSlot(cx, dataObj, SLOT_CTYPE, OBJECT_TO_JSVAL(typeObj))) @@ -5369,7 +5430,7 @@ CData::IsCData(JSContext* cx, JSObject* obj) } JSBool -CData::ValueGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +CData::ValueGetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!IsCData(cx, obj)) { JS_ReportError(cx, "not a CData"); @@ -5384,7 +5445,7 @@ CData::ValueGetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) } JSBool -CData::ValueSetter(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) +CData::ValueSetter(JSContext* cx, JSObject* obj, jsid idval, jsval* vp) { if (!IsCData(cx, obj)) { JS_ReportError(cx, "not a CData"); @@ -5414,7 +5475,7 @@ CData::Address(JSContext* cx, uintN argc, jsval *vp) JSObject* pointerType = PointerType::CreateInternal(cx, typeObj); if (!pointerType) return JS_FALSE; - js::AutoValueRooter root(cx, pointerType); + js::AutoObjectRooter root(cx, pointerType); // Create a PointerType CData object containing null. JSObject* result = CData::Create(cx, pointerType, NULL, NULL, true); @@ -5617,7 +5678,7 @@ Int64Base::Construct(JSContext* cx, JSObject* result = JS_NewObject(cx, clasp, proto, JS_GetParent(cx, proto)); if (!result) return NULL; - js::AutoValueRooter root(cx, result); + js::AutoObjectRooter root(cx, result); // attach the Int64's data JSUint64* buffer = new JSUint64(data); diff --git a/js/src/ctypes/CTypes.h b/js/src/ctypes/CTypes.h index 9db5db2710a7..339347dd10e8 100644 --- a/js/src/ctypes/CTypes.h +++ b/js/src/ctypes/CTypes.h @@ -448,7 +448,7 @@ namespace StructType { JSBool DefineInternal(JSContext* cx, JSObject* typeObj, JSObject* fieldsObj); const FieldInfoHash* GetFieldInfo(JSContext* cx, JSObject* obj); - const FieldInfo* LookupField(JSContext* cx, JSObject* obj, jsval idval); + const FieldInfo* LookupField(JSContext* cx, JSObject* obj, JSString *name); JSObject* BuildFieldsArray(JSContext* cx, JSObject* obj); ffi_type* BuildFFIType(JSContext* cx, JSObject* obj); } diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp index ed86513edb65..8fbf029854bb 100644 --- a/js/src/ctypes/Library.cpp +++ b/js/src/ctypes/Library.cpp @@ -85,7 +85,7 @@ Library::Create(JSContext* cx, jsval aPath) JSObject* libraryObj = JS_NewObject(cx, &sLibraryClass, NULL, NULL); if (!libraryObj) return NULL; - js::AutoValueRooter root(cx, libraryObj); + js::AutoObjectRooter root(cx, libraryObj); // initialize the library if (!JS_SetReservedSlot(cx, libraryObj, SLOT_LIBRARY, PRIVATE_TO_JSVAL(NULL))) @@ -241,7 +241,7 @@ Library::Declare(JSContext* cx, uintN argc, jsval* vp) return JS_FALSE; JSObject* typeObj; - js::AutoValueRooter root(cx); + js::AutoObjectRooter root(cx); bool isFunction = argc > 2; if (isFunction) { // Case 1). diff --git a/js/src/jsapi-tests/testClassGetter.cpp b/js/src/jsapi-tests/testClassGetter.cpp index ef0cc48545ae..6a3b48169be3 100644 --- a/js/src/jsapi-tests/testClassGetter.cpp +++ b/js/src/jsapi-tests/testClassGetter.cpp @@ -9,7 +9,7 @@ int called_test_fn; int called_test_prop_get; -static JSBool test_prop_get( JSContext *cx, JSObject *obj, jsval idval, jsval *vp ) +static JSBool test_prop_get( JSContext *cx, JSObject *obj, jsid id, jsval *vp ) { called_test_prop_get++; return JS_TRUE; diff --git a/js/src/jsapi-tests/testConservativeGC.cpp b/js/src/jsapi-tests/testConservativeGC.cpp index 6c3d0913b715..cf76da578f5c 100644 --- a/js/src/jsapi-tests/testConservativeGC.cpp +++ b/js/src/jsapi-tests/testConservativeGC.cpp @@ -4,11 +4,6 @@ BEGIN_TEST(testConservativeGC) { - jsval v1; - EVAL("Math.sqrt(42);", &v1); - CHECK(JSVAL_IS_DOUBLE(v1)); - double numCopy = *JSVAL_TO_DOUBLE(v1); - jsval v2; EVAL("({foo: 'bar'});", &v2); CHECK(JSVAL_IS_OBJECT(v2)); @@ -20,11 +15,6 @@ BEGIN_TEST(testConservativeGC) JSString strCopy = *JSVAL_TO_STRING(v3); jsval tmp; - EVAL("Math.sqrt(41);", &tmp); - CHECK(JSVAL_IS_DOUBLE(tmp)); - jsdouble *num2 = JSVAL_TO_DOUBLE(tmp); - jsdouble num2Copy = *num2; - EVAL("({foo2: 'bar2'});", &tmp); CHECK(JSVAL_IS_OBJECT(tmp)); JSObject *obj2 = JSVAL_TO_OBJECT(tmp); @@ -46,11 +36,9 @@ BEGIN_TEST(testConservativeGC) JS_GC(cx); - CHECK(numCopy == *JSVAL_TO_DOUBLE(v1)); CHECK(!memcmp(&objCopy, JSVAL_TO_OBJECT(v2), sizeof(objCopy))); CHECK(!memcmp(&strCopy, JSVAL_TO_STRING(v3), sizeof(strCopy))); - CHECK(num2Copy == *num2); CHECK(!memcmp(&obj2Copy, obj2, sizeof(obj2Copy))); CHECK(!memcmp(&str2Copy, str2, sizeof(str2Copy))); diff --git a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp index f4fe786e3c0a..e5009d69288c 100644 --- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp +++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp @@ -23,21 +23,25 @@ BEGIN_TEST(testDefineGetterSetterNonEnumerable) jsvalRoot vget(cx); JSFunction *funGet = JS_NewFunction(cx, native, 0, 0, NULL, "get"); CHECK(funGet); + JSObject *funGetObj = JS_GetFunctionObject(funGet); + vget = OBJECT_TO_JSVAL(funGetObj); jsvalRoot vset(cx); JSFunction *funSet = JS_NewFunction(cx, native, 1, 0, NULL, "set"); CHECK(funSet); + JSObject *funSetObj = JS_GetFunctionObject(funSet); + vset = OBJECT_TO_JSVAL(funSetObj); CHECK(JS_DefineProperty(cx, JSVAL_TO_OBJECT(vobj), PROPERTY_NAME, JSVAL_VOID, - JS_DATA_TO_FUNC_PTR(JSPropertyOp, jsval(vget)), - JS_DATA_TO_FUNC_PTR(JSPropertyOp, jsval(vset)), + JS_DATA_TO_FUNC_PTR(JSPropertyOp, funGetObj), + JS_DATA_TO_FUNC_PTR(JSPropertyOp, funSetObj), JSPROP_GETTER | JSPROP_SETTER | JSPROP_ENUMERATE)); CHECK(JS_DefineProperty(cx, JSVAL_TO_OBJECT(vobj), PROPERTY_NAME, JSVAL_VOID, - JS_DATA_TO_FUNC_PTR(JSPropertyOp, jsval(vget)), - JS_DATA_TO_FUNC_PTR(JSPropertyOp, jsval(vset)), + JS_DATA_TO_FUNC_PTR(JSPropertyOp, funGetObj), + JS_DATA_TO_FUNC_PTR(JSPropertyOp, funSetObj), JSPROP_GETTER | JSPROP_SETTER | JSPROP_PERMANENT)); JSBool found = JS_FALSE; diff --git a/js/src/jsapi-tests/testExtendedEq.cpp b/js/src/jsapi-tests/testExtendedEq.cpp index edca335146ed..c809f563da34 100644 --- a/js/src/jsapi-tests/testExtendedEq.cpp +++ b/js/src/jsapi-tests/testExtendedEq.cpp @@ -8,7 +8,7 @@ #include "tests.h" static JSBool -my_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +my_Equality(JSContext *cx, JSObject *obj, const jsval *, JSBool *bp) { *bp = JS_TRUE; return JS_TRUE; diff --git a/js/src/jsapi-tests/testGCChunkAlloc.cpp b/js/src/jsapi-tests/testGCChunkAlloc.cpp index 14e32bb0a322..a63af4b9241f 100644 --- a/js/src/jsapi-tests/testGCChunkAlloc.cpp +++ b/js/src/jsapi-tests/testGCChunkAlloc.cpp @@ -60,7 +60,7 @@ BEGIN_TEST(testGCChunkAlloc) "var max = 0; (function() {" " var array = [];" " for (; ; ++max)" - " array.push(max + 0.1);" + " array.push({});" "})();"; JSBool ok = JS_EvaluateScript(cx, global, source, strlen(source), "", 1, root.addr()); @@ -76,7 +76,7 @@ BEGIN_TEST(testGCChunkAlloc) " var array = [];" " for (var i = max >> 1; i != 0;) {" " --i;" - " array.push(i + 0.1);" + " array.push({});" " }" "})();", root.addr()); CHECK(errorCount == 1); diff --git a/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp index 7b03adf5d4b1..ef5b646152d8 100644 --- a/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp +++ b/js/src/jsapi-tests/testIsAboutToBeFinalized.cpp @@ -83,7 +83,7 @@ cls_testIsAboutToBeFinalized_bug528645::createAndTestRooted() * Make sure to include unit and numeric strings to the set. */ EVAL("var x = 1.1; " - "[x + 0.1, ''+x, 'a', '42', 'something'.substring(1), " + "[''+x, 'a', '42', 'something'.substring(1), " "{}, [], new Function('return 10;'), ];", root.addr()); diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.cpp index 2bb6dea49f48..161085e1363c 100644 --- a/js/src/jsapi-tests/testLookup.cpp +++ b/js/src/jsapi-tests/testLookup.cpp @@ -33,7 +33,7 @@ BEGIN_TEST(testLookup_bug522590) END_TEST(testLookup_bug522590) JSBool -document_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp) +document_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { // If id is "all", and we're not detecting, resolve document.all=true. jsvalRoot v(cx); diff --git a/js/src/jsapi-tests/testNewObject.cpp b/js/src/jsapi-tests/testNewObject.cpp index 8a293e0d05b8..f8ba4f851564 100644 --- a/js/src/jsapi-tests/testNewObject.cpp +++ b/js/src/jsapi-tests/testNewObject.cpp @@ -67,7 +67,6 @@ BEGIN_TEST(testNewObject_1) CHECK(len == 4); // With N arguments. - JS_ASSERT(INT_FITS_IN_JSVAL(N)); for (size_t i = 0; i < N; i++) argv[i] = INT_TO_JSVAL(i); obj = JS_New(cx, Array, N, argv); diff --git a/js/src/jsapi-tests/testPropCache.cpp b/js/src/jsapi-tests/testPropCache.cpp index 6f20efd0efaf..744d72b0e87e 100644 --- a/js/src/jsapi-tests/testPropCache.cpp +++ b/js/src/jsapi-tests/testPropCache.cpp @@ -7,7 +7,7 @@ static int g_counter; static JSBool -CounterAdd(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +CounterAdd(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { g_counter++; return JS_TRUE; diff --git a/js/src/jsapi-tests/testSameValue.cpp b/js/src/jsapi-tests/testSameValue.cpp index 07fdbfc9e369..52c910dc26f8 100644 --- a/js/src/jsapi-tests/testSameValue.cpp +++ b/js/src/jsapi-tests/testSameValue.cpp @@ -6,8 +6,6 @@ BEGIN_TEST(testSameValue) { - jsvalRoot v1(cx); - jsvalRoot v2(cx); /* * NB: passing a double that fits in an integer jsval is API misuse. As a @@ -16,9 +14,8 @@ BEGIN_TEST(testSameValue) * double, and this is believed to be the only way to make such a * comparison possible. */ - CHECK(JS_NewDoubleValue(cx, 0.0, v1.addr())); - CHECK(JSVAL_IS_DOUBLE(v1)); - CHECK(JS_NewNumberValue(cx, -0.0, v2.addr())); + jsval v1 = DOUBLE_TO_JSVAL(0.0); + jsval v2 = DOUBLE_TO_JSVAL(-0.0); CHECK(!JS_SameValue(cx, v1, v2)); return true; } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index de7e536d9d3d..143968d7b710 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -91,8 +91,9 @@ #include "jsatominlines.h" #include "jscntxtinlines.h" -#include "jsscopeinlines.h" #include "jsobjinlines.h" +#include "jsscopeinlines.h" +#include "jscntxtinlines.h" #if JS_HAS_XML_SUPPORT #include "jsxml.h" @@ -106,13 +107,19 @@ using namespace js; #define JS_ADDRESSOF_VA_LIST(ap) (&(ap)) #endif -/* Check that we can cast JSObject* as jsval without tag bit manipulations. */ -JS_STATIC_ASSERT(JSVAL_OBJECT == 0); +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID = { (size_t)JSID_TYPE_DEFAULT_XML_NAMESPACE }; +JS_PUBLIC_DATA(jsid) JSID_VOID = { (size_t)JSID_TYPE_VOID }; +#endif -/* Check that JSVAL_TRACE_KIND works. */ -JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_OBJECT) == JSTRACE_OBJECT); -JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_DOUBLE) == JSTRACE_DOUBLE); -JS_STATIC_ASSERT(JSVAL_TRACE_KIND(JSVAL_STRING) == JSTRACE_STRING); +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +JS_PUBLIC_DATA(jsval) JSVAL_NULL = { BUILD_JSVAL(JSVAL_TAG_NULL, 0) }; +JS_PUBLIC_DATA(jsval) JSVAL_ZERO = { BUILD_JSVAL(JSVAL_TAG_INT32, 0) }; +JS_PUBLIC_DATA(jsval) JSVAL_ONE = { BUILD_JSVAL(JSVAL_TAG_INT32, 1) }; +JS_PUBLIC_DATA(jsval) JSVAL_FALSE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) }; +JS_PUBLIC_DATA(jsval) JSVAL_TRUE = { BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) }; +JS_PUBLIC_DATA(jsval) JSVAL_VOID = { BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) }; +#endif JS_PUBLIC_API(int64) JS_Now() @@ -123,19 +130,19 @@ JS_Now() JS_PUBLIC_API(jsval) JS_GetNaNValue(JSContext *cx) { - return cx->runtime->NaNValue; + return Jsvalify(cx->runtime->NaNValue); } JS_PUBLIC_API(jsval) JS_GetNegativeInfinityValue(JSContext *cx) { - return cx->runtime->negativeInfinityValue; + return Jsvalify(cx->runtime->negativeInfinityValue); } JS_PUBLIC_API(jsval) JS_GetPositiveInfinityValue(JSContext *cx) { - return cx->runtime->positiveInfinityValue; + return Jsvalify(cx->runtime->positiveInfinityValue); } JS_PUBLIC_API(jsval) @@ -185,7 +192,7 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format JSObject *obj; CHECK_REQUEST(cx); - assertSameCompartment(cx, ValueArray(argv - 2, argc + 2)); + assertSameCompartment(cx, JSValueArray(argv - 2, argc + 2)); sp = argv; required = JS_TRUE; while ((c = *format++) != '\0') { @@ -197,7 +204,7 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format } if (sp == argv + argc) { if (required) { - fun = js_ValueToFunction(cx, &argv[-2], 0); + fun = js_ValueToFunction(cx, Valueify(&argv[-2]), 0); if (fun) { char numBuf[12]; JS_snprintf(numBuf, sizeof numBuf, "%u", argc); @@ -212,7 +219,7 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format } switch (c) { case 'b': - *va_arg(ap, JSBool *) = js_ValueToBoolean(*sp); + *va_arg(ap, JSBool *) = js_ValueToBoolean(Valueify(*sp)); break; case 'c': if (!JS_ValueToUint16(cx, *sp, va_arg(ap, uint16 *))) @@ -242,7 +249,7 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format case 's': case 'S': case 'W': - str = js_ValueToString(cx, *sp); + str = js_ValueToString(cx, Valueify(*sp)); if (!str) return JS_FALSE; *sp = STRING_TO_JSVAL(str); @@ -261,13 +268,13 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv, const char *format } break; case 'o': - if (!js_ValueToObject(cx, *sp, &obj)) + if (!js_ValueToObjectOrNull(cx, Valueify(*sp), &obj)) return JS_FALSE; *sp = OBJECT_TO_JSVAL(obj); *va_arg(ap, JSObject **) = obj; break; case 'f': - obj = js_ValueToFunctionObject(cx, sp, 0); + obj = js_ValueToFunctionObject(cx, Valueify(sp), 0); if (!obj) return JS_FALSE; *sp = OBJECT_TO_JSVAL(obj); @@ -344,7 +351,7 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp) JSBool ok; JSObject *obj; JSString *str; - jsdouble d, *dp; + jsdouble d; CHECK_REQUEST(cx); assertSameCompartment(cx, v); @@ -354,32 +361,28 @@ JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp) ok = JS_TRUE; break; case JSTYPE_OBJECT: - ok = js_ValueToObject(cx, v, &obj); + ok = js_ValueToObjectOrNull(cx, Valueify(v), &obj); if (ok) *vp = OBJECT_TO_JSVAL(obj); break; case JSTYPE_FUNCTION: *vp = v; - obj = js_ValueToFunctionObject(cx, vp, JSV2F_SEARCH_STACK); + obj = js_ValueToFunctionObject(cx, Valueify(vp), JSV2F_SEARCH_STACK); ok = (obj != NULL); break; case JSTYPE_STRING: - str = js_ValueToString(cx, v); + str = js_ValueToString(cx, Valueify(v)); ok = (str != NULL); if (ok) *vp = STRING_TO_JSVAL(str); break; case JSTYPE_NUMBER: ok = JS_ValueToNumber(cx, v, &d); - if (ok) { - dp = js_NewWeaklyRootedDouble(cx, d); - ok = (dp != NULL); - if (ok) - *vp = DOUBLE_TO_JSVAL(dp); - } + if (ok) + *vp = DOUBLE_TO_JSVAL(d); break; case JSTYPE_BOOLEAN: - *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(v)); + *vp = BOOLEAN_TO_JSVAL(js_ValueToBoolean(Valueify(v))); return JS_TRUE; default: { char numBuf[12]; @@ -397,7 +400,7 @@ JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp) { CHECK_REQUEST(cx); assertSameCompartment(cx, v); - return js_ValueToObject(cx, v, objp); + return js_ValueToObjectOrNull(cx, Valueify(v), objp); } JS_PUBLIC_API(JSFunction *) @@ -405,7 +408,7 @@ JS_ValueToFunction(JSContext *cx, jsval v) { CHECK_REQUEST(cx); assertSameCompartment(cx, v); - return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK); + return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK); } JS_PUBLIC_API(JSFunction *) @@ -413,7 +416,7 @@ JS_ValueToConstructor(JSContext *cx, jsval v) { CHECK_REQUEST(cx); assertSameCompartment(cx, v); - return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK); + return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK); } JS_PUBLIC_API(JSString *) @@ -421,7 +424,7 @@ JS_ValueToString(JSContext *cx, jsval v) { CHECK_REQUEST(cx); assertSameCompartment(cx, v); - return js_ValueToString(cx, v); + return js_ValueToString(cx, Valueify(v)); } JS_PUBLIC_API(JSString *) @@ -429,7 +432,7 @@ JS_ValueToSource(JSContext *cx, jsval v) { CHECK_REQUEST(cx); assertSameCompartment(cx, v); - return js_ValueToSource(cx, v); + return js_ValueToSource(cx, Valueify(v)); } JS_PUBLIC_API(JSBool) @@ -438,14 +441,14 @@ JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ValueToNumber(cx, v, dp); + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToNumber(cx, tvr.value(), dp); } JS_PUBLIC_API(JSBool) JS_DoubleIsInt32(jsdouble d, jsint *ip) { - return JSDOUBLE_IS_INT(d, *ip); + return JSDOUBLE_IS_INT32(d, (int32_t *)ip); } JS_PUBLIC_API(JSBool) @@ -454,8 +457,8 @@ JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ValueToECMAInt32(cx, v, (int32_t *)ip); + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToECMAInt32(cx, tvr.value(), (int32_t *)ip); } JS_PUBLIC_API(JSBool) @@ -464,8 +467,8 @@ JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ValueToECMAUint32(cx, v, (uint32_t *)ip); + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)ip); } JS_PUBLIC_API(JSBool) @@ -474,8 +477,8 @@ JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ValueToInt32(cx, v, (int32_t *)ip); + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToInt32(cx, tvr.value(), (int32_t *)ip); } JS_PUBLIC_API(JSBool) @@ -484,8 +487,8 @@ JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip) CHECK_REQUEST(cx); assertSameCompartment(cx, v); - AutoValueRooter tvr(cx, v); - return ValueToUint16(cx, v, (uint16_t *)ip); + AutoValueRooter tvr(cx, Valueify(v)); + return ValueToUint16(cx, tvr.value(), (uint16_t *)ip); } JS_PUBLIC_API(JSBool) @@ -493,33 +496,16 @@ JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp) { CHECK_REQUEST(cx); assertSameCompartment(cx, v); - *bp = js_ValueToBoolean(v); + *bp = js_ValueToBoolean(Valueify(v)); return JS_TRUE; } JS_PUBLIC_API(JSType) JS_TypeOfValue(JSContext *cx, jsval v) { - JSType type; - JSObject *obj; - CHECK_REQUEST(cx); assertSameCompartment(cx, v); - if (JSVAL_IS_OBJECT(v)) { - obj = JSVAL_TO_OBJECT(v); - if (obj) - return obj->map->ops->typeOf(cx, obj); - type = JSTYPE_OBJECT; - } else if (JSVAL_IS_NUMBER(v)) { - type = JSTYPE_NUMBER; - } else if (JSVAL_IS_STRING(v)) { - type = JSTYPE_STRING; - } else if (JSVAL_IS_BOOLEAN(v)) { - type = JSTYPE_BOOLEAN; - } else { - type = JSTYPE_VOID; - } - return type; + return TypeOfValue(cx, Valueify(v)); } JS_PUBLIC_API(const char *) @@ -534,14 +520,14 @@ JS_PUBLIC_API(JSBool) JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2) { assertSameCompartment(cx, v1, v2); - return js_StrictlyEqual(cx, v1, v2); + return StrictlyEqual(cx, Valueify(v1), Valueify(v2)); } JS_PUBLIC_API(JSBool) JS_SameValue(JSContext *cx, jsval v1, jsval v2) { assertSameCompartment(cx, v1, v2); - return js_SameValue(v1, v2, cx); + return SameValue(Valueify(v1), Valueify(v2), cx); } /************************************************************************/ @@ -691,21 +677,6 @@ JS_NewRuntime(uint32 maxbytes) #include "js.msg" #undef MSG_DEF - /* - * If it were possible for pure inline function calls with constant - * arguments to be computed at compile time, these would be static - * assertions, but since it isn't, this is the best we can do. - */ - JS_ASSERT(JSVAL_NULL == OBJECT_TO_JSVAL(NULL)); - JS_ASSERT(JSVAL_ZERO == INT_TO_JSVAL(0)); - JS_ASSERT(JSVAL_ONE == INT_TO_JSVAL(1)); - JS_ASSERT(JSVAL_FALSE == BOOLEAN_TO_JSVAL(JS_FALSE)); - JS_ASSERT(JSVAL_TRUE == BOOLEAN_TO_JSVAL(JS_TRUE)); - - JS_ASSERT(JSVAL_TO_SPECIAL(JSVAL_VOID) == 2); - JS_ASSERT(JSVAL_TO_SPECIAL(JSVAL_HOLE) == (2 | (JSVAL_HOLE_FLAG >> JSVAL_TAGBITS))); - JS_ASSERT(JSVAL_TO_SPECIAL(JSVAL_ARETURN) == 8); - js_NewRuntimeWasCalled = JS_TRUE; } #endif /* DEBUG */ @@ -1108,6 +1079,7 @@ JS_EnterCrossCompartmentCall(JSContext *cx, JSObject *target) { CHECK_REQUEST(cx); + JS_ASSERT(target); AutoCompartment *call = new AutoCompartment(cx, target); if (!call) return NULL; @@ -1142,8 +1114,6 @@ JS_SetGlobalObject(JSContext *cx, JSObject *obj) cx->compartment = obj ? obj->getCompartment(cx) : cx->runtime->defaultCompartment; } -JS_BEGIN_EXTERN_C - JSObject * js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj) { @@ -1214,7 +1184,7 @@ js_InitFunctionAndObjectClasses(JSContext *cx, JSObject *obj) goto out; } obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)), - OBJECT_TO_JSVAL(ctor), 0, 0, 0); + ObjectValue(*ctor), 0, 0, 0); } /* Initialize the object class next so Object.prototype works. */ @@ -1247,8 +1217,6 @@ out: return fun_proto; } -JS_END_EXTERN_C - JS_PUBLIC_API(JSBool) JS_InitStandardClasses(JSContext *cx, JSObject *obj) { @@ -1261,8 +1229,8 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj) /* Define a top-level property 'undefined' with the undefined value. */ JSAtom *atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID]; - if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), JSVAL_VOID, - JS_PropertyStub, JS_PropertyStub, + if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), + PropertyStub, PropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return JS_FALSE; } @@ -1303,7 +1271,7 @@ typedef struct JSStdName { JSObjectOp init; size_t atomOffset; /* offset of atom pointer in JSAtomState */ const char *name; /* null if atom is pre-pinned, else name */ - JSClass *clasp; + Class *clasp; } JSStdName; static JSAtom * @@ -1446,7 +1414,7 @@ static JSStdName object_prototype_names[] = { }; JS_PUBLIC_API(JSBool) -JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id, JSBool *resolved) +JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved) { JSString *idstr; JSRuntime *rt; @@ -1460,17 +1428,17 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id, JSBool *resolved rt = cx->runtime; JS_ASSERT(rt->state != JSRTS_DOWN); - if (rt->state == JSRTS_LANDING || !JSVAL_IS_STRING(id)) + if (rt->state == JSRTS_LANDING || !JSID_IS_ATOM(id)) return JS_TRUE; - idstr = JSVAL_TO_STRING(id); + idstr = JSID_TO_STRING(id); /* Check whether we're resolving 'undefined', and define it if so. */ atom = rt->atomState.typeAtoms[JSTYPE_VOID]; if (idstr == ATOM_TO_STRING(atom)) { *resolved = JS_TRUE; - return obj->defineProperty(cx, ATOM_TO_JSID(atom), JSVAL_VOID, - JS_PropertyStub, JS_PropertyStub, + return obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), + PropertyStub, PropertyStub, JSPROP_PERMANENT | JSPROP_READONLY); } @@ -1527,8 +1495,7 @@ JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id, JSBool *resolved return JS_TRUE; JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(stdnm->clasp); - jsval v = obj->getReservedSlot(key); - if (!JSVAL_IS_PRIMITIVE(v)) + if (obj->getReservedSlot(key).isObject()) return JS_TRUE; if (!stdnm->init(cx, obj)) @@ -1562,8 +1529,8 @@ JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj) /* Check whether we need to bind 'undefined' and define it if so. */ atom = rt->atomState.typeAtoms[JSTYPE_VOID]; if (!AlreadyHasOwnProperty(cx, obj, atom) && - !obj->defineProperty(cx, ATOM_TO_JSID(atom), JSVAL_VOID, - JS_PropertyStub, JS_PropertyStub, + !obj->defineProperty(cx, ATOM_TO_JSID(atom), UndefinedValue(), + PropertyStub, PropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return JS_FALSE; } @@ -1783,8 +1750,8 @@ JS_GetGlobalForScopeChain(JSContext *cx) JS_PUBLIC_API(jsval) JS_ComputeThis(JSContext *cx, jsval *vp) { - assertSameCompartment(cx, ValueArray(vp, 2)); - if (!js_ComputeThis(cx, vp + 2)) + assertSameCompartment(cx, JSValueArray(vp, 2)); + if (!ComputeThisFromVp(cx, Valueify(vp))) return JSVAL_NULL; return vp[1]; } @@ -1826,31 +1793,11 @@ JS_strdup(JSContext *cx, const char *s) return (char *)memcpy(p, s, n); } -JS_PUBLIC_API(jsdouble *) -JS_NewDouble(JSContext *cx, jsdouble d) -{ - CHECK_REQUEST(cx); - return js_NewWeaklyRootedDouble(cx, d); -} - -JS_PUBLIC_API(JSBool) -JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval) -{ - jsdouble *dp; - - CHECK_REQUEST(cx); - dp = js_NewWeaklyRootedDouble(cx, d); - if (!dp) - return JS_FALSE; - *rval = DOUBLE_TO_JSVAL(dp); - return JS_TRUE; -} - JS_PUBLIC_API(JSBool) JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval) { - CHECK_REQUEST(cx); - return js_NewWeaklyRootedNumber(cx, d, rval); + Valueify(rval)->setNumber(d); + return JS_TRUE; } #undef JS_AddRoot @@ -1859,7 +1806,7 @@ JS_PUBLIC_API(JSBool) JS_AddValueRoot(JSContext *cx, jsval *vp) { CHECK_REQUEST(cx); - return js_AddRoot(cx, vp, NULL); + return js_AddRoot(cx, Valueify(vp), NULL); } JS_PUBLIC_API(JSBool) @@ -1876,13 +1823,6 @@ JS_AddObjectRoot(JSContext *cx, JSObject **rp) return js_AddGCThingRoot(cx, (void **)rp, NULL); } -JS_PUBLIC_API(JSBool) -JS_AddDoubleRoot(JSContext *cx, jsdouble **rp) -{ - CHECK_REQUEST(cx); - return js_AddGCThingRoot(cx, (void **)rp, NULL); -} - JS_PUBLIC_API(JSBool) JS_AddGCThingRoot(JSContext *cx, void **rp) { @@ -1894,7 +1834,7 @@ JS_PUBLIC_API(JSBool) JS_AddNamedValueRoot(JSContext *cx, jsval *vp, const char *name) { CHECK_REQUEST(cx); - return js_AddRoot(cx, vp, name); + return js_AddRoot(cx, Valueify(vp), name); } JS_PUBLIC_API(JSBool) @@ -1911,13 +1851,6 @@ JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name) return js_AddGCThingRoot(cx, (void **)rp, name); } -JS_PUBLIC_API(JSBool) -JS_AddNamedDoubleRoot(JSContext *cx, jsdouble **rp, const char *name) -{ - CHECK_REQUEST(cx); - return js_AddGCThingRoot(cx, (void **)rp, name); -} - JS_PUBLIC_API(JSBool) JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name) { @@ -1946,13 +1879,6 @@ JS_RemoveObjectRoot(JSContext *cx, JSObject **rp) return js_RemoveRoot(cx->runtime, (void *)rp); } -JS_PUBLIC_API(JSBool) -JS_RemoveDoubleRoot(JSContext *cx, jsdouble **rp) -{ - CHECK_REQUEST(cx); - return js_RemoveRoot(cx->runtime, (void *)rp); -} - JS_PUBLIC_API(JSBool) JS_RemoveGCThingRoot(JSContext *cx, void **rp) { @@ -1970,7 +1896,7 @@ JS_ClearNewbornRoots(JSContext *cx) JS_PUBLIC_API(void) JS_DumpNamedRoots(JSRuntime *rt, - void (*dump)(const char *name, void *rp, void *data), + void (*dump)(const char *name, void *rp, JSGCRootType type, void *data), void *data) { js_DumpNamedRoots(rt, dump, data); @@ -2034,7 +1960,8 @@ JS_TraceRuntime(JSTracer *trc) JS_PUBLIC_API(void) JS_CallTracer(JSTracer *trc, void *thing, uint32 kind) { - js_CallGCMarker(trc, thing, kind); + JS_ASSERT(thing); + Mark(trc, thing, kind); } #ifdef DEBUG @@ -2057,7 +1984,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui case JSTRACE_OBJECT: { JSObject *obj = (JSObject *)thing; - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); name = clasp->name; #ifdef HAVE_XPCONNECT @@ -2079,10 +2006,6 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui : "string"; break; - case JSTRACE_DOUBLE: - name = "double"; - break; - #if JS_HAS_XML_SUPPORT case JSTRACE_XML: name = "xml"; @@ -2109,7 +2032,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui case JSTRACE_OBJECT: { JSObject *obj = (JSObject *)thing; - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (clasp == &js_FunctionClass) { JSFunction *fun = GET_FUNCTION_PRIVATE(trc->context, obj); if (!fun) { @@ -2117,7 +2040,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui } else if (FUN_OBJECT(fun) != obj) { JS_snprintf(buf, bufsize, "%p", fun); } else { - if (fun->atom && ATOM_IS_STRING(fun->atom)) + if (fun->atom) js_PutEscapedString(buf, bufsize, ATOM_TO_STRING(fun->atom), 0); } @@ -2133,10 +2056,6 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, ui js_PutEscapedString(buf, bufsize, (JSString *)thing, 0); break; - case JSTRACE_DOUBLE: - JS_snprintf(buf, bufsize, "%g", *(jsdouble *)thing); - break; - #if JS_HAS_XML_SUPPORT case JSTRACE_XML: { @@ -2413,7 +2332,7 @@ JS_DumpHeap(JSContext *cx, FILE *fp, void* startThing, uint32 startKind, #endif /* DEBUG */ JS_PUBLIC_API(void) -JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg) +JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg) { JSTracer *trc; @@ -2426,8 +2345,7 @@ JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg) #ifdef JS_THREADSAFE JS_ASSERT(cx->runtime->gcThread == trc->context->thread); #endif - JS_SET_TRACING_NAME(trc, name ? name : "unknown"); - js_CallValueTracerIfGCThing(trc, (jsval)thing); + MarkValue(trc, Valueify(v), name ? name : "unknown"); } extern JS_PUBLIC_API(JSBool) @@ -2706,38 +2624,20 @@ JS_ValueToId(JSContext *cx, jsval v, jsid *idp) { CHECK_REQUEST(cx); assertSameCompartment(cx, v); - - if (JSVAL_IS_INT(v)) { - *idp = INT_JSVAL_TO_JSID(v); - return JS_TRUE; - } - -#if JS_HAS_XML_SUPPORT - if (!JSVAL_IS_PRIMITIVE(v)) { - JSClass *clasp = JSVAL_TO_OBJECT(v)->getClass(); - if (JS_UNLIKELY(clasp == &js_QNameClass.base || - clasp == &js_AttributeNameClass || - clasp == &js_AnyNameClass)) { - *idp = OBJECT_JSVAL_TO_JSID(v); - return JS_TRUE; - } - } -#endif - - return js_ValueToStringId(cx, v, idp); + return ValueToId(cx, Valueify(v), idp); } JS_PUBLIC_API(JSBool) JS_IdToValue(JSContext *cx, jsid id, jsval *vp) { CHECK_REQUEST(cx); - *vp = ID_TO_VALUE(id); + *vp = IdToJsval(id); assertSameCompartment(cx, *vp); return JS_TRUE; } JS_PUBLIC_API(JSBool) -JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return JS_TRUE; } @@ -2749,7 +2649,7 @@ JS_EnumerateStub(JSContext *cx, JSObject *obj) } JS_PUBLIC_API(JSBool) -JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id) +JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id) { return JS_TRUE; } @@ -2758,13 +2658,12 @@ JS_PUBLIC_API(JSBool) JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp) { JS_ASSERT(type != JSTYPE_OBJECT && type != JSTYPE_FUNCTION); - return js_TryValueOf(cx, obj, type, vp); + return js_TryValueOf(cx, obj, type, Valueify(vp)); } JS_PUBLIC_API(void) JS_FinalizeStub(JSContext *cx, JSObject *obj) -{ -} +{} JS_PUBLIC_API(JSObject *) JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, @@ -2774,7 +2673,8 @@ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, { CHECK_REQUEST(cx); assertSameCompartment(cx, obj, parent_proto); - return js_InitClass(cx, obj, parent_proto, clasp, constructor, nargs, + return js_InitClass(cx, obj, parent_proto, Valueify(clasp), + Valueify(constructor), nargs, ps, fs, static_ps, static_fs); } @@ -2782,44 +2682,29 @@ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, JS_PUBLIC_API(JSClass *) JS_GetClass(JSContext *cx, JSObject *obj) { - return obj->getClass(); + return Jsvalify(obj->getClass()); } #else JS_PUBLIC_API(JSClass *) JS_GetClass(JSObject *obj) { - return obj->getClass(); + return Jsvalify(obj->getClass()); } #endif JS_PUBLIC_API(JSBool) JS_InstanceOf(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv) { - JSFunction *fun; - CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - if (obj && obj->getClass() == clasp) - return JS_TRUE; - if (argv) { - fun = js_ValueToFunction(cx, &argv[-2], 0); - if (fun) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_INCOMPATIBLE_PROTO, - clasp->name, JS_GetFunctionName(fun), - obj - ? obj->getClass()->name - : js_null_str); - } - } - return JS_FALSE; + return InstanceOf(cx, obj, Valueify(clasp), Valueify(argv)); } JS_PUBLIC_API(JSBool) JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) { assertSameCompartment(cx, obj, v); - return js_HasInstance(cx, obj, v, bp); + return js_HasInstance(cx, obj, Valueify(&v), bp); } JS_PUBLIC_API(void *) @@ -2840,7 +2725,7 @@ JS_SetPrivate(JSContext *cx, JSObject *obj, void *data) JS_PUBLIC_API(void *) JS_GetInstancePrivate(JSContext *cx, JSObject *obj, JSClass *clasp, jsval *argv) { - if (!JS_InstanceOf(cx, obj, clasp, argv)) + if (!InstanceOf(cx, obj, Valueify(clasp), Valueify(argv))) return NULL; return obj->getPrivate(); } @@ -2888,7 +2773,7 @@ JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent) JS_PUBLIC_API(JSObject *) JS_GetConstructor(JSContext *cx, JSObject *proto) { - jsval cval; + Value cval; CHECK_REQUEST(cx); assertSameCompartment(cx, proto); @@ -2898,19 +2783,19 @@ JS_GetConstructor(JSContext *cx, JSObject *proto) if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval)) return NULL; } - if (!VALUE_IS_FUNCTION(cx, cval)) { + JSObject *funobj; + if (!IsFunctionObject(cval, &funobj)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR, proto->getClass()->name); return NULL; } - return JSVAL_TO_OBJECT(cval); + return &cval.toObject(); } JS_PUBLIC_API(JSBool) JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp) { assertSameCompartment(cx, obj); - JS_ASSERT(JSID_IS_OBJECT(obj)); *idp = OBJECT_TO_JSID(obj); return JS_TRUE; } @@ -2920,9 +2805,9 @@ JS_NewGlobalObject(JSContext *cx, JSClass *clasp) { CHECK_REQUEST(cx); JS_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL); - JSObject *obj = NewObjectWithGivenProto(cx, clasp, NULL, NULL); + JSObject *obj = NewObjectWithGivenProto(cx, Valueify(clasp), NULL, NULL); if (obj && !js_SetReservedSlot(cx, obj, JSRESERVED_GLOBAL_COMPARTMENT, - PRIVATE_TO_JSVAL(cx->compartment))) + PrivateValue(cx->compartment))) return false; return obj; } @@ -2944,10 +2829,11 @@ JS_NewCompartmentAndGlobalObject(JSContext *cx, JSClass *clasp, JSPrincipals *pr } JS_PUBLIC_API(JSObject *) -JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) +JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent) { CHECK_REQUEST(cx); assertSameCompartment(cx, proto, parent); + Class *clasp = Valueify(jsclasp); if (!clasp) clasp = &js_ObjectClass; /* default class is Object */ JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); @@ -2957,10 +2843,11 @@ JS_NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) } JS_PUBLIC_API(JSObject *) -JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) +JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent) { CHECK_REQUEST(cx); assertSameCompartment(cx, proto, parent); + Class *clasp = Valueify(jsclasp); if (!clasp) clasp = &js_ObjectClass; /* default class is Object */ JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); @@ -2976,7 +2863,6 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep) JSScope *scope; JSIdArray *ida; uint32 nslots, i; - jsval v; if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx)) return JS_FALSE; @@ -3026,36 +2912,38 @@ JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep) /* Walk slots in obj and if any value is a non-null object, seal it. */ nslots = scope->freeslot; for (i = 0; i != nslots; ++i) { - v = obj->getSlot(i); + const Value &v = obj->getSlot(i); if (i == JSSLOT_PRIVATE && (obj->getClass()->flags & JSCLASS_HAS_PRIVATE)) continue; - if (JSVAL_IS_PRIMITIVE(v)) + if (v.isPrimitive()) continue; - if (!JS_SealObject(cx, JSVAL_TO_OBJECT(v), deep)) + if (!JS_SealObject(cx, &v.toObject(), deep)) return JS_FALSE; } return JS_TRUE; } JS_PUBLIC_API(JSObject *) -JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) +JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent) { CHECK_REQUEST(cx); assertSameCompartment(cx, proto, parent); + Class *clasp = Valueify(jsclasp); if (!clasp) clasp = &js_ObjectClass; /* default class is Object */ return js_ConstructObject(cx, clasp, proto, parent, 0, NULL); } JS_PUBLIC_API(JSObject *) -JS_ConstructObjectWithArguments(JSContext *cx, JSClass *clasp, JSObject *proto, +JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent, uintN argc, jsval *argv) { CHECK_REQUEST(cx); - assertSameCompartment(cx, proto, parent, ValueArray(argv, argc)); + assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc)); + Class *clasp = Valueify(jsclasp); if (!clasp) clasp = &js_ObjectClass; /* default class is Object */ - return js_ConstructObject(cx, clasp, proto, parent, argc, argv); + return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv)); } static JSBool @@ -3073,11 +2961,12 @@ LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags, #define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n)) static JSBool -LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop, jsval *vp) +LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, jsid id, + JSProperty *prop, Value *vp) { if (!prop) { /* XXX bad API: no way to tell "not defined" from "void value" */ - *vp = JSVAL_VOID; + vp->setUndefined(); return JS_TRUE; } @@ -3087,20 +2976,21 @@ LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop, jsv if (sprop->isMethod()) { AutoScopePropertyRooter root(cx, sprop); JS_UNLOCK_OBJ(cx, obj2); - *vp = sprop->methodValue(); + vp->setObject(sprop->methodObject()); return obj2->scope()->methodReadBarrier(cx, sprop, vp); } /* Peek at the native property's slot value, without doing a Get. */ - *vp = SPROP_HAS_VALID_SLOT(sprop, obj2->scope()) - ? obj2->lockedGetSlot(sprop->slot) - : JSVAL_TRUE; + if (SPROP_HAS_VALID_SLOT(sprop, obj2->scope())) + *vp = obj2->lockedGetSlot(sprop->slot); + else + vp->setBoolean(true); JS_UNLOCK_OBJ(cx, obj2); } else if (obj2->isDenseArray()) { - return js_GetDenseArrayElementValue(cx, obj2, prop, vp); + return js_GetDenseArrayElementValue(cx, obj2, id, vp); } else { /* XXX bad API: no way to return "defined but value unknown" */ - *vp = JSVAL_TRUE; + vp->setBoolean(true); } return true; } @@ -3111,7 +3001,7 @@ JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) JSObject *obj2; JSProperty *prop; return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) && - LookupResult(cx, obj, obj2, prop, vp); + LookupResult(cx, obj, obj2, id, prop, Valueify(vp)); } JS_PUBLIC_API(JSBool) @@ -3146,7 +3036,7 @@ JS_LookupPropertyWithFlagsById(JSContext *cx, JSObject *obj, jsid id, uintN flag ok = obj->isNative() ? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0 : obj->lookupProperty(cx, id, objp, &prop); - return ok && LookupResult(cx, obj, *objp, prop, vp); + return ok && LookupResult(cx, obj, *objp, id, prop, Valueify(vp)); } JS_PUBLIC_API(JSBool) @@ -3245,8 +3135,8 @@ JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj, const jschar *name, siz } static JSBool -DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs, +DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, const Value &value, + PropertyOp getter, PropertyOp setter, uintN attrs, uintN flags, intN tinyid) { CHECK_REQUEST(cx); @@ -3270,19 +3160,21 @@ JS_PUBLIC_API(JSBool) JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs) { - return DefinePropertyById(cx, obj, id, value, getter, setter, attrs, 0, 0); + return DefinePropertyById(cx, obj, id, Valueify(value), Valueify(getter), + Valueify(setter), attrs, 0, 0); } JS_PUBLIC_API(JSBool) JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs) { - return DefinePropertyById(cx, obj, INT_TO_JSID(index), value, getter, setter, attrs, 0, 0); + return DefinePropertyById(cx, obj, INT_TO_JSID(index), Valueify(value), + Valueify(getter), Valueify(setter), attrs, 0, 0); } static JSBool -DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs, +DefineProperty(JSContext *cx, JSObject *obj, const char *name, const Value &value, + PropertyOp getter, PropertyOp setter, uintN attrs, uintN flags, intN tinyid) { jsid id; @@ -3305,20 +3197,21 @@ JS_PUBLIC_API(JSBool) JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs) { - return DefineProperty(cx, obj, name, value, getter, setter, attrs, 0, 0); + return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter), + Valueify(setter), attrs, 0, 0); } JS_PUBLIC_API(JSBool) JS_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name, int8 tinyid, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs) { - return DefineProperty(cx, obj, name, value, getter, setter, attrs, - JSScopeProperty::HAS_SHORTID, tinyid); + return DefineProperty(cx, obj, name, Valueify(value), Valueify(getter), + Valueify(setter), attrs, JSScopeProperty::HAS_SHORTID, tinyid); } static JSBool DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, - jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs, + const Value &value, PropertyOp getter, PropertyOp setter, uintN attrs, uintN flags, intN tinyid) { JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); @@ -3330,7 +3223,8 @@ JS_PUBLIC_API(JSBool) JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs) { - return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0, 0); + return DefineUCProperty(cx, obj, name, namelen, Valueify(value), + Valueify(getter), Valueify(setter), attrs, 0, 0); } JS_PUBLIC_API(JSBool) @@ -3338,8 +3232,8 @@ JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj, const jschar *name, int8 tinyid, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs) { - return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, - attrs, JSScopeProperty::HAS_SHORTID, tinyid); + return DefineUCProperty(cx, obj, name, namelen, Valueify(value), Valueify(getter), + Valueify(setter), attrs, JSScopeProperty::HAS_SHORTID, tinyid); } JS_PUBLIC_API(JSBool) @@ -3347,23 +3241,24 @@ JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JS { CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id, descriptor); - return js_DefineOwnProperty(cx, obj, id, descriptor, bp); + return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp); } JS_PUBLIC_API(JSObject *) -JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *clasp, +JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp, JSObject *proto, uintN attrs) { JSObject *nobj; CHECK_REQUEST(cx); assertSameCompartment(cx, obj, proto); + Class *clasp = Valueify(jsclasp); if (!clasp) clasp = &js_ObjectClass; /* default class is Object */ nobj = NewObject(cx, clasp, proto, obj); if (!nobj) return NULL; - if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs, 0, 0)) + if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0)) return NULL; return nobj; } @@ -3372,14 +3267,11 @@ JS_PUBLIC_API(JSBool) JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds) { JSBool ok; - jsval value; uintN attrs; CHECK_REQUEST(cx); for (ok = JS_TRUE; cds->name; cds++) { - ok = js_NewNumberInRootedValue(cx, cds->dval, &value); - if (!ok) - break; + Value value = DoubleValue(cds->dval); attrs = cds->flags; if (!attrs) attrs = JSPROP_READONLY | JSPROP_PERMANENT; @@ -3396,8 +3288,9 @@ JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps) JSBool ok; for (ok = true; ps->name; ps++) { - ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID, ps->getter, ps->setter, ps->flags, - JSScopeProperty::HAS_SHORTID, ps->tinyid); + ok = DefineProperty(cx, obj, ps->name, UndefinedValue(), + Valueify(ps->getter), Valueify(ps->setter), + ps->flags, JSScopeProperty::HAS_SHORTID, ps->tinyid); if (!ok) break; } @@ -3485,7 +3378,7 @@ JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias) static JSBool GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, - JSBool own, JSPropertyDescriptor *desc) + JSBool own, PropertyDescriptor *desc) { JSObject *obj2; JSProperty *prop; @@ -3498,7 +3391,7 @@ GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, desc->attrs = 0; desc->getter = NULL; desc->setter = NULL; - desc->value = JSVAL_VOID; + desc->value.setUndefined(); if (prop) obj2->dropProperty(cx, prop); return JS_TRUE; @@ -3510,14 +3403,15 @@ GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, desc->attrs = sprop->attributes(); if (sprop->isMethod()) { - desc->getter = desc->setter = JS_PropertyStub; - desc->value = sprop->methodValue(); + desc->getter = desc->setter = PropertyStub; + desc->value.setObject(sprop->methodObject()); } else { desc->getter = sprop->getter(); desc->setter = sprop->setter(); - desc->value = SPROP_HAS_VALID_SLOT(sprop, obj2->scope()) - ? obj2->lockedGetSlot(sprop->slot) - : JSVAL_VOID; + if (SPROP_HAS_VALID_SLOT(sprop, obj2->scope())) + desc->value = obj2->lockedGetSlot(sprop->slot); + else + desc->value.setUndefined(); } JS_UNLOCK_OBJ(cx, obj2); } else if (obj2->isProxy()) { @@ -3532,7 +3426,7 @@ GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, return false; desc->getter = NULL; desc->setter = NULL; - desc->value = JSVAL_VOID; + desc->value.setUndefined(); } return true; } @@ -3541,7 +3435,7 @@ JS_PUBLIC_API(JSBool) JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSPropertyDescriptor *desc) { - return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, desc); + return GetPropertyDescriptorById(cx, obj, id, flags, JS_FALSE, Valueify(desc)); } JS_PUBLIC_API(JSBool) @@ -3549,16 +3443,16 @@ JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp, JSBool *foundp, JSPropertyOp *getterp, JSPropertyOp *setterp) { - JSPropertyDescriptor desc; + PropertyDescriptor desc; if (!GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, JS_FALSE, &desc)) return false; *attrsp = desc.attrs; *foundp = (desc.obj != NULL); if (getterp) - *getterp = desc.getter; + *getterp = Jsvalify(desc.getter); if (setterp) - *setterp = desc.setter; + *setterp = Jsvalify(desc.setter); return true; } @@ -3605,7 +3499,7 @@ JS_PUBLIC_API(JSBool) JS_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { CHECK_REQUEST(cx); - return js_GetOwnPropertyDescriptor(cx, obj, id, vp); + return js_GetOwnPropertyDescriptor(cx, obj, id, Valueify(vp)); } static JSBool @@ -3652,7 +3546,7 @@ JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); - return obj->getProperty(cx, id, vp); + return obj->getProperty(cx, id, Valueify(vp)); } JS_PUBLIC_API(JSBool) @@ -3680,7 +3574,7 @@ JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsval * { CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); - if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, vp)) + if (!js_GetMethod(cx, obj, id, JSGET_METHOD_BARRIER, Valueify(vp))) return JS_FALSE; if (objp) *objp = obj; @@ -3700,7 +3594,7 @@ JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp) CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); - return obj->setProperty(cx, id, vp); + return obj->setProperty(cx, id, Valueify(vp)); } JS_PUBLIC_API(JSBool) @@ -3729,7 +3623,7 @@ JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval) CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); - return obj->deleteProperty(cx, id, rval); + return obj->deleteProperty(cx, id, Valueify(rval)); } JS_PUBLIC_API(JSBool) @@ -3799,7 +3693,7 @@ JS_Enumerate(JSContext *cx, JSObject *obj) CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - AutoValueVector props(cx); + AutoIdVector props(cx); JSIdArray *ida; if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, props) || !VectorToIdArray(cx, props, &ida)) return false; @@ -3825,7 +3719,7 @@ prop_iter_finalize(JSContext *cx, JSObject *obj) if (!pdata) return; - if (JSVAL_TO_INT(obj->fslots[JSSLOT_ITER_INDEX]) >= 0) { + if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() >= 0) { /* Non-native case: destroy the ida enumerated when obj was created. */ JSIdArray *ida = (JSIdArray *) pdata; JS_DestroyIdArray(cx, ida); @@ -3839,23 +3733,22 @@ prop_iter_trace(JSTracer *trc, JSObject *obj) if (!pdata) return; - if (JSVAL_TO_INT(obj->fslots[JSSLOT_ITER_INDEX]) < 0) { + if (obj->fslots[JSSLOT_ITER_INDEX].toInt32() < 0) { /* Native case: just mark the next property to visit. */ ((JSScopeProperty *) pdata)->trace(trc); } else { /* Non-native case: mark each id in the JSIdArray private. */ JSIdArray *ida = (JSIdArray *) pdata; - for (jsint i = 0, n = ida->length; i < n; i++) - js_TraceId(trc, ida->vector[i]); + MarkIdRange(trc, ida->length, ida->vector, "prop iter"); } } -static JSClass prop_iter_class = { +static Class prop_iter_class = { "PropertyIterator", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_MARK_IS_TRACE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iter_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, prop_iter_finalize, NULL, NULL, NULL, NULL, NULL, NULL, JS_CLASS_TRACE(prop_iter_trace), NULL }; @@ -3887,7 +3780,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj) * Note: we have to make sure that we root obj around the call to * JS_Enumerate to protect against multiple allocations under it. */ - AutoValueRooter tvr(cx, iterobj); + AutoObjectRooter tvr(cx, iterobj); ida = JS_Enumerate(cx, obj); if (!ida) return NULL; @@ -3897,7 +3790,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj) /* iterobj cannot escape to other threads here. */ iterobj->setPrivate(pdata); - iterobj->fslots[JSSLOT_ITER_INDEX] = INT_TO_JSVAL(index); + iterobj->fslots[JSSLOT_ITER_INDEX].setInt32(index); return iterobj; } @@ -3911,7 +3804,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp) CHECK_REQUEST(cx); assertSameCompartment(cx, iterobj); - i = JSVAL_TO_INT(iterobj->fslots[JSSLOT_ITER_INDEX]); + i = iterobj->fslots[JSSLOT_ITER_INDEX].toInt32(); if (i < 0) { /* Native case: private data is a property tree node pointer. */ obj = iterobj->getParent(); @@ -3927,7 +3820,7 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp) sprop = sprop->parent; if (!sprop) { - *idp = JSVAL_VOID; + *idp = JSID_VOID; } else { iterobj->setPrivate(sprop->parent); *idp = sprop->id; @@ -3937,10 +3830,10 @@ JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp) ida = (JSIdArray *) iterobj->getPrivate(); JS_ASSERT(i <= ida->length); if (i == 0) { - *idp = JSVAL_VOID; + *idp = JSID_VOID; } else { *idp = ida->vector[--i]; - iterobj->setSlot(JSSLOT_ITER_INDEX, INT_TO_JSVAL(i)); + iterobj->setSlot(JSSLOT_ITER_INDEX, Int32Value(i)); } } return JS_TRUE; @@ -3951,7 +3844,7 @@ JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) { CHECK_REQUEST(cx); assertSameCompartment(cx, obj); - return js_GetReservedSlot(cx, obj, index, vp); + return js_GetReservedSlot(cx, obj, index, Valueify(vp)); } JS_PUBLIC_API(JSBool) @@ -3959,7 +3852,7 @@ JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v) { CHECK_REQUEST(cx); assertSameCompartment(cx, obj, v); - return js_SetReservedSlot(cx, obj, index, v); + return js_SetReservedSlot(cx, obj, index, Valueify(v)); } JS_PUBLIC_API(JSObject *) @@ -3967,8 +3860,8 @@ JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector) { CHECK_REQUEST(cx); /* NB: jsuint cast does ToUint32. */ - assertSameCompartment(cx, ValueArray(vector, vector ? (jsuint)length : 0)); - return js_NewArrayObject(cx, (jsuint)length, vector); + assertSameCompartment(cx, JSValueArray(vector, vector ? (jsuint)length : 0)); + return js_NewArrayObject(cx, (jsuint)length, Valueify(vector)); } JS_PUBLIC_API(JSBool) @@ -4008,7 +3901,7 @@ JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, { CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id); - return CheckAccess(cx, obj, id, mode, vp, attrsp); + return CheckAccess(cx, obj, id, mode, Valueify(vp), attrsp); } #ifdef JS_THREADSAFE @@ -4078,7 +3971,7 @@ JS_NewFunction(JSContext *cx, JSNative native, uintN nargs, uintN flags, if (!atom) return NULL; } - return js_NewFunction(cx, NULL, native, nargs, flags, parent, atom); + return js_NewFunction(cx, NULL, Valueify(native), nargs, flags, parent, atom); } JS_PUBLIC_API(JSObject *) @@ -4099,7 +3992,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent) * We cannot clone this object, so fail (we used to return funobj, bad * idea, but we changed incompatibly to teach any abusers a lesson!). */ - jsval v = OBJECT_TO_JSVAL(funobj); + Value v = ObjectValue(*funobj); js_ReportIsNotFunction(cx, &v, 0); return NULL; } @@ -4129,7 +4022,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent) } JSUpvarArray *uva = fun->u.i.script->upvars(); - JS_ASSERT(uva->length <= size_t(clone->dslots[-1])); + JS_ASSERT(uva->length <= clone->dslots[-1].toPrivateUint32()); void *mark = JS_ARENA_MARK(&cx->tempPool); jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool); @@ -4201,32 +4094,29 @@ JS_ObjectIsFunction(JSContext *cx, JSObject *obj) return obj->getClass() == &js_FunctionClass; } -JS_BEGIN_EXTERN_C static JSBool -js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp) +js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp) { - jsval fsv; JSFunctionSpec *fs; JSObject *tmp; - JSFastNative native; + FastNative native; - fsv = JSVAL_TO_OBJECT(*vp)->getReservedSlot(0); - fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv); + fs = (JSFunctionSpec *) vp->toObject().getReservedSlot(0).toPrivate(); JS_ASSERT((~fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == 0); if (argc < 1) { - js_ReportMissingArg(cx, vp, 0); + js_ReportMissingArg(cx, *vp, 0); return JS_FALSE; } - if (JSVAL_IS_PRIMITIVE(vp[2])) { + if (vp[2].isPrimitive()) { /* * Make sure that this is an object or null, as required by the generic * functions. */ - if (!js_ValueToObject(cx, vp[2], &tmp)) + if (!js_ValueToObjectOrNull(cx, vp[2], &tmp)) return JS_FALSE; - vp[2] = OBJECT_TO_JSVAL(tmp); + vp[2].setObjectOrNull(tmp); } /* @@ -4241,48 +4131,46 @@ js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp) * Follow Function.prototype.apply and .call by using the global object as * the 'this' param if no args. */ - if (!js_ComputeThis(cx, vp + 2)) + if (!ComputeThisFromArgv(cx, vp + 2)) return JS_FALSE; /* Clear the last parameter in case too few arguments were passed. */ - vp[2 + --argc] = JSVAL_VOID; + vp[2 + --argc].setUndefined(); native = #ifdef JS_TRACER (fs->flags & JSFUN_TRCINFO) - ? JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native + ? (FastNative) JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, fs->call)->native : #endif - (JSFastNative) fs->call; + (FastNative) fs->call; return native(cx, argc, vp); } static JSBool js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) + uintN argc, Value *argv, Value *rval) { - jsval fsv; JSFunctionSpec *fs; JSObject *tmp; - fsv = JSVAL_TO_OBJECT(argv[-2])->getReservedSlot(0); - fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv); + fs = (JSFunctionSpec *) argv[-2].toObject().getReservedSlot(0).toPrivate(); JS_ASSERT((fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == JSFUN_GENERIC_NATIVE); if (argc < 1) { - js_ReportMissingArg(cx, argv - 2, 0); + js_ReportMissingArg(cx, *(argv - 2), 0); return JS_FALSE; } - if (JSVAL_IS_PRIMITIVE(argv[0])) { + if (argv[0].isPrimitive()) { /* * Make sure that this is an object or null, as required by the generic * functions. */ - if (!js_ValueToObject(cx, argv[0], &tmp)) + if (!js_ValueToObjectOrNull(cx, argv[0], &tmp)) return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(tmp); + argv[0].setObjectOrNull(tmp); } /* @@ -4297,17 +4185,16 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, * Follow Function.prototype.apply and .call by using the global object as * the 'this' param if no args. */ - if (!js_ComputeThis(cx, argv)) + if (!ComputeThisFromArgv(cx, argv)) return JS_FALSE; js_GetTopStackFrame(cx)->thisv = argv[-1]; JS_ASSERT(cx->fp->argv == argv); /* Clear the last parameter in case too few arguments were passed. */ - argv[--argc] = JSVAL_VOID; + argv[--argc].setUndefined(); - return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc, argv, rval); + return fs->call(cx, &argv[-1].toObject(), argc, Jsvalify(argv), Jsvalify(rval)); } -JS_END_EXTERN_C JS_PUBLIC_API(JSBool) JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) @@ -4336,9 +4223,8 @@ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) flags &= ~JSFUN_GENERIC_NATIVE; fun = JS_DefineFunction(cx, ctor, fs->name, (flags & JSFUN_FAST_NATIVE) - ? (JSNative) - js_generic_fast_native_method_dispatcher - : js_generic_native_method_dispatcher, + ? (JSNative) js_generic_fast_native_method_dispatcher + : Jsvalify(js_generic_native_method_dispatcher), fs->nargs + 1, flags & ~JSFUN_TRCINFO); if (!fun) @@ -4349,7 +4235,8 @@ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) * As jsapi.h notes, fs must point to storage that lives as long * as fun->object lives. */ - if (!JS_SetReservedSlot(cx, FUN_OBJECT(fun), 0, PRIVATE_TO_JSVAL(fs))) + Value priv = PrivateValue(fs); + if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv)) return JS_FALSE; } @@ -4370,7 +4257,7 @@ JS_DefineFunction(JSContext *cx, JSObject *obj, const char *name, JSNative call, CHECK_REQUEST(cx); assertSameCompartment(cx, obj); JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); - return atom ? js_DefineFunction(cx, obj, atom, call, nargs, attrs) : NULL; + return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL; } JS_PUBLIC_API(JSFunction *) @@ -4381,7 +4268,7 @@ JS_DefineUCFunction(JSContext *cx, JSObject *obj, CHECK_REQUEST(cx); assertSameCompartment(cx, obj); JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0); - return atom ? js_DefineFunction(cx, obj, atom, call, nargs, attrs) : NULL; + return atom ? js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs) : NULL; } inline static void @@ -4395,7 +4282,7 @@ inline static void LAST_FRAME_CHECKS(JSContext *cx, bool result) { if (!JS_IsRunning(cx)) { - cx->weakRoots.lastInternalResult = JSVAL_NULL; + cx->weakRoots.lastInternalResult = NULL; LAST_FRAME_EXCEPTION_CHECK(cx, result); } } @@ -4613,7 +4500,7 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, goto out2; { - AutoValueRooter tvr(cx, FUN_OBJECT(fun)); + AutoObjectRooter tvr(cx, FUN_OBJECT(fun)); MUST_FLOW_THROUGH("out"); for (i = 0; i < nargs; i++) { @@ -4635,7 +4522,7 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, } if (obj && funAtom && - !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), + !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), ObjectValue(*fun), NULL, NULL, JSPROP_ENUMERATE)) { fun = NULL; } @@ -4748,7 +4635,7 @@ JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval) CHECK_REQUEST(cx); assertSameCompartment(cx, obj, script); - ok = js_Execute(cx, obj, script, NULL, 0, rval); + ok = Execute(cx, obj, script, NULL, 0, Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); return ok; } @@ -4773,7 +4660,7 @@ JS_EvaluateUCScriptForPrincipals(JSContext *cx, JSObject *obj, LAST_FRAME_CHECKS(cx, script); return JS_FALSE; } - ok = js_Execute(cx, obj, script, NULL, 0, rval); + ok = Execute(cx, obj, script, NULL, 0, Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); JS_DestroyScript(cx, script); return ok; @@ -4816,9 +4703,8 @@ JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc, jsval JSBool ok; CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, fun, ValueArray(argv, argc)); - ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(FUN_OBJECT(fun)), argc, argv, - rval); + assertSameCompartment(cx, obj, fun, JSValueArray(argv, argc)); + ok = InternalCall(cx, obj, ObjectValue(*fun), argc, Valueify(argv), Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); return ok; } @@ -4828,13 +4714,13 @@ JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc, jsval *rval) { CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, ValueArray(argv, argc)); + assertSameCompartment(cx, obj, JSValueArray(argv, argc)); AutoValueRooter tvr(cx); JSAtom *atom = js_Atomize(cx, name, strlen(name), 0); JSBool ok = atom && js_GetMethod(cx, obj, ATOM_TO_JSID(atom), JSGET_NO_METHOD_BARRIER, tvr.addr()) && - js_InternalCall(cx, obj, tvr.value(), argc, argv, rval); + InternalCall(cx, obj, tvr.value(), argc, Valueify(argv), Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); return ok; } @@ -4846,8 +4732,8 @@ JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc, jsval JSBool ok; CHECK_REQUEST(cx); - assertSameCompartment(cx, obj, fval, ValueArray(argv, argc)); - ok = js_InternalCall(cx, obj, fval, argc, argv, rval); + assertSameCompartment(cx, obj, fval, JSValueArray(argv, argc)); + ok = InternalCall(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval)); LAST_FRAME_CHECKS(cx, ok); return ok; } @@ -4856,7 +4742,7 @@ JS_PUBLIC_API(JSObject *) JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv) { CHECK_REQUEST(cx); - assertSameCompartment(cx, ctor, ValueArray(argv, argc)); + assertSameCompartment(cx, ctor, JSValueArray(argv, argc)); // This is not a simple variation of JS_CallFunctionValue because JSOP_NEW // is not a simple variation of JSOP_CALL. We have to determine what class @@ -4866,13 +4752,13 @@ JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv) if (!cx->stack().pushInvokeArgs(cx, argc, args)) return NULL; - jsval *vp = args.getvp(); - vp[0] = OBJECT_TO_JSVAL(ctor); - vp[1] = JSVAL_NULL; + Value *vp = args.getvp(); + vp[0].setObject(*ctor); + vp[1].setNull(); memcpy(vp + 2, argv, argc * sizeof(jsval)); - JSBool ok = js_InvokeConstructor(cx, args); - JSObject *obj = ok ? JSVAL_TO_OBJECT(vp[0]) : NULL; + bool ok = InvokeConstructor(cx, args); + JSObject *obj = ok ? vp[0].toObjectOrNull() : NULL; LAST_FRAME_CHECKS(cx, ok); return obj; @@ -5025,6 +4911,12 @@ JS_NewStringCopyZ(JSContext *cx, const char *s) return str; } +JS_PUBLIC_API(JSBool) +JS_StringHasBeenInterned(JSString *str) +{ + return str->isAtomized(); +} + JS_PUBLIC_API(JSString *) JS_InternString(JSContext *cx, const char *s) { @@ -5228,7 +5120,7 @@ JS_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space, CHECK_REQUEST(cx); assertSameCompartment(cx, replacer, space); JSCharBuffer cb(cx); - if (!js_Stringify(cx, vp, replacer, space, cb)) + if (!js_Stringify(cx, Valueify(vp), replacer, Valueify(space), cb)) return false; return callback(cb.begin(), cb.length(), data); } @@ -5238,14 +5130,14 @@ JS_TryJSON(JSContext *cx, jsval *vp) { CHECK_REQUEST(cx); assertSameCompartment(cx, *vp); - return js_TryJSON(cx, vp); + return js_TryJSON(cx, Valueify(vp)); } JS_PUBLIC_API(JSONParser *) JS_BeginJSONParse(JSContext *cx, jsval *vp) { CHECK_REQUEST(cx); - return js_BeginJSONParse(cx, vp); + return js_BeginJSONParse(cx, Valueify(vp)); } JS_PUBLIC_API(JSBool) @@ -5260,7 +5152,7 @@ JS_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) { CHECK_REQUEST(cx); assertSameCompartment(cx, reviver); - return js_FinishJSONParse(cx, jp, reviver); + return js_FinishJSONParse(cx, jp, Valueify(reviver)); } /* @@ -5474,7 +5366,7 @@ JS_GetPendingException(JSContext *cx, jsval *vp) CHECK_REQUEST(cx); if (!cx->throwing) return JS_FALSE; - *vp = cx->exception; + Valueify(*vp) = cx->exception; return JS_TRUE; } @@ -5483,15 +5375,14 @@ JS_SetPendingException(JSContext *cx, jsval v) { CHECK_REQUEST(cx); assertSameCompartment(cx, v); - cx->throwing = JS_TRUE; - cx->exception = v; + SetPendingException(cx, Valueify(v)); } JS_PUBLIC_API(void) JS_ClearPendingException(JSContext *cx) { cx->throwing = JS_FALSE; - cx->exception = JSVAL_VOID; + cx->exception.setUndefined(); } JS_PUBLIC_API(JSBool) @@ -5530,7 +5421,7 @@ JS_SaveExceptionState(JSContext *cx) if (state) { state->throwing = JS_GetPendingException(cx, &state->exception); if (state->throwing && JSVAL_IS_GCTHING(state->exception)) - js_AddRoot(cx, &state->exception, "JSExceptionState.exception"); + js_AddRoot(cx, Valueify(&state->exception), "JSExceptionState.exception"); } return state; } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index c7d02c1935b6..fe8f79eb0c2e 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -52,172 +52,409 @@ JS_BEGIN_EXTERN_C /* - * Type tags stored in the low bits of a jsval. - */ -typedef enum jsvaltag { - JSVAL_OBJECT = 0x0, /* untagged reference to object */ - JSVAL_INT = 0x1, /* tagged 31-bit integer value */ - JSVAL_DOUBLE = 0x2, /* tagged reference to double */ - JSVAL_STRING = 0x4, /* tagged reference to string */ - JSVAL_SPECIAL = 0x6 /* tagged boolean or private value */ -} jsvaltag; - -/* Type tag bitfield length and derived macros. */ -#define JSVAL_TAGBITS 3 -#define JSVAL_TAGMASK ((jsval) JS_BITMASK(JSVAL_TAGBITS)) -#define JSVAL_ALIGN JS_BIT(JSVAL_TAGBITS) - -/* Not a function, because we have static asserts that use it */ -#define JSVAL_TAG(v) ((jsvaltag)((v) & JSVAL_TAGMASK)) - -/* Not a function, because we have static asserts that use it */ -#define JSVAL_SETTAG(v, t) ((v) | (t)) - -static JS_ALWAYS_INLINE jsval -JSVAL_CLRTAG(jsval v) -{ - return v & ~(jsval)JSVAL_TAGMASK; -} - -/* - * Well-known JS values. The extern'd variables are initialized when the - * first JSContext is created by JS_NewContext (see below). - */ -#define JSVAL_NULL ((jsval) 0) -#define JSVAL_ZERO INT_TO_JSVAL(0) -#define JSVAL_ONE INT_TO_JSVAL(1) -#define JSVAL_FALSE SPECIAL_TO_JSVAL(JS_FALSE) -#define JSVAL_TRUE SPECIAL_TO_JSVAL(JS_TRUE) -#define JSVAL_VOID SPECIAL_TO_JSVAL(2) - -/* - * A "special" value is a 29-bit (for 32-bit jsval) or 61-bit (for 64-bit jsval) - * value whose tag is JSVAL_SPECIAL. These values include the booleans 0 and 1. + * In release builds, jsval and jsid are defined to be integral types. This + * prevents many bugs from being caught at compile time. E.g.: * - * JSVAL_VOID is a non-boolean special value, but embedders MUST NOT rely on - * this. All other possible special values are implementation-reserved - * and MUST NOT be constructed by any embedding of SpiderMonkey. + * jsval v = ... + * if (v == JS_TRUE) // error + * ... + * + * jsid id = v; // error + * + * To catch more errors, jsval and jsid are given struct types in debug builds. + * Struct assignment and (in C++) operator== allow correct code to be mostly + * oblivious to the change. This feature can be explicitly disabled in debug + * builds by defining JS_NO_JSVAL_JSID_STRUCT_TYPES. */ -#define JSVAL_TO_SPECIAL(v) ((JSBool) ((v) >> JSVAL_TAGBITS)) -#define SPECIAL_TO_JSVAL(b) \ - JSVAL_SETTAG((jsval) (b) << JSVAL_TAGBITS, JSVAL_SPECIAL) +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES -/* Predicates for type testing. */ -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_OBJECT(jsval v) -{ - return JSVAL_TAG(v) == JSVAL_OBJECT; -} +/* Well-known JS values. N.B. These constants are initialized at startup. */ +extern JS_PUBLIC_DATA(jsval) JSVAL_NULL; +extern JS_PUBLIC_DATA(jsval) JSVAL_ZERO; +extern JS_PUBLIC_DATA(jsval) JSVAL_ONE; +extern JS_PUBLIC_DATA(jsval) JSVAL_FALSE; +extern JS_PUBLIC_DATA(jsval) JSVAL_TRUE; +extern JS_PUBLIC_DATA(jsval) JSVAL_VOID; -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_INT(jsval v) -{ - return (JSBool)(v & JSVAL_INT); -} +#else -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_DOUBLE(jsval v) -{ - return JSVAL_TAG(v) == JSVAL_DOUBLE; -} +/* Well-known JS values. */ +#define JSVAL_NULL BUILD_JSVAL(JSVAL_TAG_NULL, 0) +#define JSVAL_ZERO BUILD_JSVAL(JSVAL_TAG_INT32, 0) +#define JSVAL_ONE BUILD_JSVAL(JSVAL_TAG_INT32, 1) +#define JSVAL_FALSE BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_FALSE) +#define JSVAL_TRUE BUILD_JSVAL(JSVAL_TAG_BOOLEAN, JS_TRUE) +#define JSVAL_VOID BUILD_JSVAL(JSVAL_TAG_UNDEFINED, 0) -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_NUMBER(jsval v) -{ - return JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v); -} +#endif -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_STRING(jsval v) -{ - return JSVAL_TAG(v) == JSVAL_STRING; -} - -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_SPECIAL(jsval v) -{ - return JSVAL_TAG(v) == JSVAL_SPECIAL; -} - -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_BOOLEAN(jsval v) -{ - return (v & ~((jsval)1 << JSVAL_TAGBITS)) == JSVAL_SPECIAL; -} +/************************************************************************/ static JS_ALWAYS_INLINE JSBool JSVAL_IS_NULL(jsval v) { - return v == JSVAL_NULL; + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_NULL_IMPL(l); } static JS_ALWAYS_INLINE JSBool JSVAL_IS_VOID(jsval v) { - return v == JSVAL_VOID; + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_UNDEFINED_IMPL(l); } static JS_ALWAYS_INLINE JSBool -JSVAL_IS_PRIMITIVE(jsval v) +JSVAL_IS_INT(jsval v) { - return !JSVAL_IS_OBJECT(v) || JSVAL_IS_NULL(v); + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_INT32_IMPL(l); +} + +static JS_ALWAYS_INLINE jsint +JSVAL_TO_INT(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_INT(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_INT32_IMPL(l); +} + +#define JSVAL_INT_BITS 32 +#define JSVAL_INT_MIN ((jsint)0x80000000) +#define JSVAL_INT_MAX ((jsint)0x7fffffff) + +static JS_ALWAYS_INLINE jsval +INT_TO_JSVAL(int32 i) +{ + return IMPL_TO_JSVAL(INT32_TO_JSVAL_IMPL(i)); } -/* Objects, strings, and doubles are GC'ed. */ static JS_ALWAYS_INLINE JSBool -JSVAL_IS_GCTHING(jsval v) +JSVAL_IS_DOUBLE(jsval v) { - return !(v & JSVAL_INT) && JSVAL_TAG(v) != JSVAL_SPECIAL; + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_DOUBLE_IMPL(l); } -static JS_ALWAYS_INLINE void * -JSVAL_TO_GCTHING(jsval v) -{ - JS_ASSERT(JSVAL_IS_GCTHING(v)); - return (void *) JSVAL_CLRTAG(v); -} - -static JS_ALWAYS_INLINE JSObject * -JSVAL_TO_OBJECT(jsval v) -{ - JS_ASSERT(JSVAL_IS_OBJECT(v)); - return (JSObject *) JSVAL_TO_GCTHING(v); -} - -static JS_ALWAYS_INLINE jsdouble * +static JS_ALWAYS_INLINE jsdouble JSVAL_TO_DOUBLE(jsval v) { + jsval_layout l; JS_ASSERT(JSVAL_IS_DOUBLE(v)); - return (jsdouble *) JSVAL_TO_GCTHING(v); + l.asBits = JSVAL_BITS(v); + return l.asDouble; +} + +static JS_ALWAYS_INLINE jsval +DOUBLE_TO_JSVAL(jsdouble d) +{ + return IMPL_TO_JSVAL(DOUBLE_TO_JSVAL_IMPL(d)); +} + +static JS_ALWAYS_INLINE jsval +UINT_TO_JSVAL(uint32 i) +{ + if (i <= JSVAL_INT_MAX) + return INT_TO_JSVAL((int32)i); + return DOUBLE_TO_JSVAL((jsdouble)i); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NUMBER(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_NUMBER_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_STRING(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_STRING_IMPL(l); } static JS_ALWAYS_INLINE JSString * JSVAL_TO_STRING(jsval v) { + jsval_layout l; JS_ASSERT(JSVAL_IS_STRING(v)); - return (JSString *) JSVAL_TO_GCTHING(v); -} - -static JS_ALWAYS_INLINE jsval -OBJECT_TO_JSVAL(JSObject *obj) -{ - JS_ASSERT(((jsval) obj & JSVAL_TAGMASK) == JSVAL_OBJECT); - return (jsval) obj; -} - -static JS_ALWAYS_INLINE jsval -DOUBLE_TO_JSVAL(jsdouble *dp) -{ - JS_ASSERT(((jsword) dp & JSVAL_TAGMASK) == 0); - return JSVAL_SETTAG((jsval) dp, JSVAL_DOUBLE); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_STRING_IMPL(l); } static JS_ALWAYS_INLINE jsval STRING_TO_JSVAL(JSString *str) { - return JSVAL_SETTAG((jsval) str, JSVAL_STRING); + return IMPL_TO_JSVAL(STRING_TO_JSVAL_IMPL(str)); } +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_OBJECT_OR_NULL_IMPL(l); +} + +static JS_ALWAYS_INLINE JSObject * +JSVAL_TO_OBJECT(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_OBJECT(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_OBJECT_IMPL(l); +} + +static JS_ALWAYS_INLINE jsval +OBJECT_TO_JSVAL(JSObject *obj) +{ + if (obj) + return IMPL_TO_JSVAL(OBJECT_TO_JSVAL_IMPL(obj)); + return JSVAL_NULL; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_BOOLEAN(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_BOOLEAN_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_TO_BOOLEAN(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_BOOLEAN_IMPL(l); +} + +static JS_ALWAYS_INLINE jsval +BOOLEAN_TO_JSVAL(JSBool b) +{ + return IMPL_TO_JSVAL(BOOLEAN_TO_JSVAL_IMPL(b)); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_PRIMITIVE(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_PRIMITIVE_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_GCTHING(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_GCTHING_IMPL(l); +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_GCTHING(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_GCTHING(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_GCTHING_IMPL(l); +} + +/* To be GC-safe, privates are tagged as doubles. */ + +static JS_ALWAYS_INLINE jsval +PRIVATE_TO_JSVAL(void *ptr) +{ + return IMPL_TO_JSVAL(PRIVATE_PTR_TO_JSVAL_IMPL(ptr)); +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_PRIVATE(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_DOUBLE(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TO_PRIVATE_PTR_IMPL(l); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(l); +} + +/************************************************************************/ + +/* + * A jsid is an identifier for a property or method of an object which is + * either a 31-bit signed integer, interned string or object. If XML is + * enabled, there is an additional singleton jsid value; see + * JS_DEFAULT_XML_NAMESPACE_ID below. Finally, there is an additional jsid + * value, JSID_VOID, which does not occur in JS scripts but may be used to + * indicate the absence of a valid jsid. + * + * A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or + * JS_IdToValue must be used instead. + */ + +#define JSID_TYPE_STRING 0x0 +#define JSID_TYPE_INT 0x1 +#define JSID_TYPE_VOID 0x2 +#define JSID_TYPE_OBJECT 0x4 +#define JSID_TYPE_DEFAULT_XML_NAMESPACE 0x6 +#define JSID_TYPE_MASK 0x7 + +/* + * Do not use canonical 'id' for jsid parameters since this is a magic word in + * Objective-C++ which, apparently, wants to be able to #include jsapi.h. + */ + +static JS_ALWAYS_INLINE JSBool +JSID_IS_STRING(jsid iden) +{ + return (JSID_BITS(iden) & JSID_TYPE_MASK) == 0; +} + +static JS_ALWAYS_INLINE JSString * +JSID_TO_STRING(jsid iden) +{ + JS_ASSERT(JSID_IS_STRING(iden)); + return (JSString *)(JSID_BITS(iden)); +} + +JS_PUBLIC_API(JSBool) +JS_StringHasBeenInterned(JSString *str); + +/* A jsid may only hold an interned JSString. */ +static JS_ALWAYS_INLINE jsid +INTERNED_STRING_TO_JSID(JSString *str) +{ + jsid iden; + JS_ASSERT(JS_StringHasBeenInterned(str)); + JS_ASSERT(((size_t)str & JSID_TYPE_MASK) == 0); + JSID_BITS(iden) = (size_t)str; + return iden; +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_INT(jsid iden) +{ + return !!(JSID_BITS(iden) & JSID_TYPE_INT); +} + +static JS_ALWAYS_INLINE int32 +JSID_TO_INT(jsid iden) +{ + JS_ASSERT(JSID_IS_INT(iden)); + return ((int32)JSID_BITS(iden)) >> 1; +} + +#define JSID_INT_MIN (-(1 << 30)) +#define JSID_INT_MAX ((1 << 30) - 1) + +static JS_ALWAYS_INLINE JSBool +INT_FITS_IN_JSID(int32 i) +{ + return ((jsuint)(i) - (jsuint)JSID_INT_MIN <= + (jsuint)(JSID_INT_MAX - JSID_INT_MIN)); +} + +static JS_ALWAYS_INLINE jsid +INT_TO_JSID(int32 i) +{ + jsid iden; + JS_ASSERT(INT_FITS_IN_JSID(i)); + JSID_BITS(iden) = ((i << 1) | JSID_TYPE_INT); + return iden; +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_OBJECT(jsid iden) +{ + return (JSID_BITS(iden) & JSID_TYPE_MASK) == JSID_TYPE_OBJECT; +} + +static JS_ALWAYS_INLINE JSObject * +JSID_TO_OBJECT(jsid iden) +{ + JS_ASSERT(JSID_IS_OBJECT(iden)); + return (JSObject *)(JSID_BITS(iden) & ~(size_t)JSID_TYPE_MASK); +} + +static JS_ALWAYS_INLINE jsid +OBJECT_TO_JSID(JSObject *obj) +{ + jsid iden; + JS_ASSERT(obj != NULL); + JS_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0); + JSID_BITS(iden) = ((size_t)obj | JSID_TYPE_OBJECT); + return iden; +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_GCTHING(jsid iden) +{ + return JSID_IS_STRING(iden) || JSID_IS_OBJECT(iden); +} + +static JS_ALWAYS_INLINE void * +JSID_TO_GCTHING(jsid iden) +{ + return (void *)(JSID_BITS(iden) & ~(size_t)JSID_TYPE_MASK); +} + +/* + * The magic XML namespace id is not a valid jsid. Global object classes in + * embeddings that enable JS_HAS_XML_SUPPORT (E4X) should handle this id. + */ + +static JS_ALWAYS_INLINE JSBool +JSID_IS_DEFAULT_XML_NAMESPACE(jsid iden) +{ + JS_ASSERT_IF(((size_t)JSID_BITS(iden) & JSID_TYPE_MASK) == JSID_TYPE_DEFAULT_XML_NAMESPACE, + JSID_BITS(iden) == JSID_TYPE_DEFAULT_XML_NAMESPACE); + return ((size_t)JSID_BITS(iden) == JSID_TYPE_DEFAULT_XML_NAMESPACE); +} + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +extern JS_PUBLIC_DATA(jsid) JS_DEFAULT_XML_NAMESPACE_ID; +#else +#define JS_DEFAULT_XML_NAMESPACE_ID ((jsid)JSID_TYPE_DEFAULT_XML_NAMESPACE) +#endif + +/* + * A void jsid is not a valid id and only arises as an exceptional API return + * value, such as in JS_NextProperty. Embeddings must not pass JSID_VOID into + * JSAPI entry points expecting a jsid and do not need to handle JSID_VOID in + * hooks receiving a jsid except when explicitly noted in the API contract. + */ + +static JS_ALWAYS_INLINE JSBool +JSID_IS_VOID(jsid iden) +{ + JS_ASSERT_IF(((size_t)JSID_BITS(iden) & JSID_TYPE_MASK) == JSID_TYPE_VOID, + JSID_BITS(iden) == JSID_TYPE_VOID); + return ((size_t)JSID_BITS(iden) == JSID_TYPE_VOID); +} + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES +extern JS_PUBLIC_DATA(jsid) JSID_VOID; +#else +#define JSID_VOID ((jsid)JSID_TYPE_VOID) +#endif + +/************************************************************************/ + /* Lock and unlock the GC thing held by a jsval. */ #define JSVAL_LOCK(cx,v) (JSVAL_IS_GCTHING(v) \ ? JS_LockGCThing(cx, JSVAL_TO_GCTHING(v)) \ @@ -226,52 +463,6 @@ STRING_TO_JSVAL(JSString *str) ? JS_UnlockGCThing(cx, JSVAL_TO_GCTHING(v)) \ : JS_TRUE) -/* Domain limits for the jsval int type. */ -#define JSVAL_INT_BITS 31 -#define JSVAL_INT_POW2(n) ((jsval)1 << (n)) -#define JSVAL_INT_MIN (-JSVAL_INT_POW2(30)) -#define JSVAL_INT_MAX (JSVAL_INT_POW2(30) - 1) - -/* Not a function, because we have static asserts that use it */ -#define INT_FITS_IN_JSVAL(i) ((jsuint)(i) - (jsuint)JSVAL_INT_MIN <= \ - (jsuint)(JSVAL_INT_MAX - JSVAL_INT_MIN)) - -static JS_ALWAYS_INLINE jsint -JSVAL_TO_INT(jsval v) -{ - JS_ASSERT(JSVAL_IS_INT(v)); - return (jsint) v >> 1; -} - -/* Not a function, because we have static asserts that use it */ -#define INT_TO_JSVAL_CONSTEXPR(i) (((jsval)(i) << 1) | JSVAL_INT) - -static JS_ALWAYS_INLINE jsval -INT_TO_JSVAL(jsint i) -{ - JS_ASSERT(INT_FITS_IN_JSVAL(i)); - return INT_TO_JSVAL_CONSTEXPR(i); -} - -/* Convert between boolean and jsval, asserting that inputs are valid. */ -static JS_ALWAYS_INLINE JSBool -JSVAL_TO_BOOLEAN(jsval v) -{ - JS_ASSERT(v == JSVAL_TRUE || v == JSVAL_FALSE); - return JSVAL_TO_SPECIAL(v); -} - -static JS_ALWAYS_INLINE jsval -BOOLEAN_TO_JSVAL(JSBool b) -{ - JS_ASSERT(b == JS_TRUE || b == JS_FALSE); - return SPECIAL_TO_JSVAL(b); -} - -/* A private data pointer (2-byte-aligned) can be stored as an int jsval. */ -#define JSVAL_TO_PRIVATE(v) ((void *)((v) & ~JSVAL_INT)) -#define PRIVATE_TO_JSVAL(p) ((jsval)(ptrdiff_t)(p) | JSVAL_INT) - /* Property attributes, set in JSPropertySpec and passed to API functions. */ #define JSPROP_ENUMERATE 0x01 /* property is visible to for/in loop */ #define JSPROP_READONLY 0x02 /* not settable: assignment is no-op */ @@ -833,7 +1024,7 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj); * loops any classes not yet resolved lazily. */ extern JS_PUBLIC_API(JSBool) -JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsval id, +JS_ResolveStandardClass(JSContext *cx, JSObject *obj, jsid id, JSBool *resolved); extern JS_PUBLIC_API(JSBool) @@ -898,7 +1089,7 @@ JS_InitCTypesClass(JSContext *cx, JSObject *global); #define JS_CALLEE(cx,vp) ((vp)[0]) #define JS_ARGV_CALLEE(argv) ((argv)[-2]) #define JS_THIS(cx,vp) JS_ComputeThis(cx, vp) -#define JS_THIS_OBJECT(cx,vp) ((JSObject *) JS_THIS(cx,vp)) +#define JS_THIS_OBJECT(cx,vp) (JSVAL_TO_OBJECT(JS_THIS(cx,vp))) #define JS_ARGV(cx,vp) ((vp) + 2) #define JS_RVAL(cx,vp) (*(vp)) #define JS_SET_RVAL(cx,vp,v) (*(vp) = (v)) @@ -921,12 +1112,6 @@ JS_updateMallocCounter(JSContext *cx, size_t nbytes); extern JS_PUBLIC_API(char *) JS_strdup(JSContext *cx, const char *s); -extern JS_PUBLIC_API(jsdouble *) -JS_NewDouble(JSContext *cx, jsdouble d); - -extern JS_PUBLIC_API(JSBool) -JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval); - extern JS_PUBLIC_API(JSBool) JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval); @@ -964,9 +1149,6 @@ JS_AddStringRoot(JSContext *cx, JSString **rp); extern JS_PUBLIC_API(JSBool) JS_AddObjectRoot(JSContext *cx, JSObject **rp); -extern JS_PUBLIC_API(JSBool) -JS_AddDoubleRoot(JSContext *cx, jsdouble **rp); - extern JS_PUBLIC_API(JSBool) JS_AddGCThingRoot(JSContext *cx, void **rp); @@ -976,7 +1158,6 @@ JS_AddGCThingRoot(JSContext *cx, void **rp); #define JS_AddValueRoot(cx,vp) JS_AddNamedValueRoot((cx), (vp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) #define JS_AddStringRoot(cx,rp) JS_AddNamedStringRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) #define JS_AddObjectRoot(cx,rp) JS_AddNamedObjectRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) -#define JS_AddDoubleRoot(cx,rp) JS_AddNamedDoubleRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) #define JS_AddGCThingRoot(cx,rp) JS_AddNamedGCThingRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__)) #endif @@ -989,9 +1170,6 @@ JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name); extern JS_PUBLIC_API(JSBool) JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name); -extern JS_PUBLIC_API(JSBool) -JS_AddNamedDoubleRoot(JSContext *cx, jsdouble **rp, const char *name); - extern JS_PUBLIC_API(JSBool) JS_AddNamedGCThingRoot(JSContext *cx, void **rp, const char *name); @@ -1004,9 +1182,6 @@ JS_RemoveStringRoot(JSContext *cx, JSString **rp); extern JS_PUBLIC_API(JSBool) JS_RemoveObjectRoot(JSContext *cx, JSObject **rp); -extern JS_PUBLIC_API(JSBool) -JS_RemoveDoubleRoot(JSContext *cx, jsdouble **rp); - extern JS_PUBLIC_API(JSBool) JS_RemoveGCThingRoot(JSContext *cx, void **rp); @@ -1036,10 +1211,15 @@ JS_ClearNewbornRoots(JSContext *cx); #define JS_LeaveLocalRootScopeWithResult(cx, rval) ((void) 0) #define JS_ForgetLocalRoot(cx, thing) ((void) 0) +typedef enum JSGCRootType { + JS_GC_ROOT_VALUE_PTR, + JS_GC_ROOT_GCTHING_PTR +} JSGCRootType; + #ifdef DEBUG extern JS_PUBLIC_API(void) JS_DumpNamedRoots(JSRuntime *rt, - void (*dump)(const char *name, void *rp, void *data), + void (*dump)(const char *name, void *rp, JSGCRootType type, void *data), void *data); #endif @@ -1059,6 +1239,10 @@ JS_DumpNamedRoots(JSRuntime *rt, * or any JS API entry point that acquires locks, without double-tripping or * deadlocking on the GC lock. * + * The JSGCRootType parameter indicates whether rp is a pointer to a Value + * (which is obtained by '(Value *)rp') or a pointer to a GC-thing pointer + * (which is obtained by '(void **)rp'). + * * JS_MapGCRoots returns the count of roots that were successfully mapped. */ #define JS_MAP_GCROOT_NEXT 0 /* continue mapping entries */ @@ -1066,7 +1250,7 @@ JS_DumpNamedRoots(JSRuntime *rt, #define JS_MAP_GCROOT_REMOVE 2 /* remove and free the current entry */ typedef intN -(* JSGCRootMapFun)(void *rp, const char *name, void *data); +(* JSGCRootMapFun)(void *rp, JSGCRootType type, const char *name, void *data); extern JS_PUBLIC_API(uint32) JS_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data); @@ -1098,7 +1282,7 @@ JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data); * instead. */ extern JS_PUBLIC_API(void) -JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg); +JS_MarkGCThing(JSContext *cx, jsval v, const char *name, void *arg); /* * JS_CallTracer API and related macros for implementors of JSTraceOp, to @@ -1114,16 +1298,34 @@ JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg); /* Trace kinds to pass to JS_Tracing. */ #define JSTRACE_OBJECT 0 -#define JSTRACE_DOUBLE 1 -#define JSTRACE_STRING 2 +#define JSTRACE_STRING 1 /* * Use the following macros to check if a particular jsval is a traceable * thing and to extract the thing and its kind to pass to JS_CallTracer. */ -#define JSVAL_IS_TRACEABLE(v) (JSVAL_IS_GCTHING(v) && !JSVAL_IS_NULL(v)) -#define JSVAL_TO_TRACEABLE(v) (JSVAL_TO_GCTHING(v)) -#define JSVAL_TRACE_KIND(v) (JSVAL_TAG(v) >> 1) +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_TRACEABLE(jsval v) +{ + jsval_layout l; + l.asBits = JSVAL_BITS(v); + return JSVAL_IS_TRACEABLE_IMPL(l); +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_TRACEABLE(jsval v) +{ + return JSVAL_TO_GCTHING(v); +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TRACE_KIND(jsval v) +{ + jsval_layout l; + JS_ASSERT(JSVAL_IS_GCTHING(v)); + l.asBits = JSVAL_BITS(v); + return JSVAL_TRACE_KIND_IMPL(l); +} struct JSTracer { JSContext *context; @@ -1220,13 +1422,6 @@ JS_CallTracer(JSTracer *trc, void *thing, uint32 kind); JS_CALL_TRACER((trc), str_, JSTRACE_STRING, name); \ JS_END_MACRO -#define JS_CALL_DOUBLE_TRACER(trc, number, name) \ - JS_BEGIN_MACRO \ - jsdouble *num_ = (number); \ - JS_ASSERT(num_); \ - JS_CALL_TRACER((trc), num_, JSTRACE_DOUBLE, name); \ - JS_END_MACRO - /* * API for JSTraceCallback implementations. */ @@ -1377,7 +1572,7 @@ JS_RemoveExternalStringFinalizer(JSStringFinalizeOp finalizer); /* * Create a new JSString whose chars member refers to external memory, i.e., - * memory requiring special, type-specific finalization. The type code must + * memory requiring spe, type-specific finalization. The type code must * be a nonnegative return value from JS_AddExternalStringFinalizer. */ extern JS_PUBLIC_API(JSString *) @@ -1548,13 +1743,6 @@ JS_ValueToId(JSContext *cx, jsval v, jsid *idp); extern JS_PUBLIC_API(JSBool) JS_IdToValue(JSContext *cx, jsid id, jsval *vp); -/* - * The magic XML namespace id is int-tagged, but not a valid integer jsval. - * Global object classes in embeddings that enable JS_HAS_XML_SUPPORT (E4X) - * should handle this id specially before converting id via JSVAL_TO_INT. - */ -#define JS_DEFAULT_XML_NAMESPACE_ID ((jsid) JSVAL_VOID) - /* * JSNewResolveOp flag bits. */ @@ -1566,13 +1754,13 @@ JS_IdToValue(JSContext *cx, jsid id, jsval *vp); #define JSRESOLVE_WITH 0x20 /* resolve inside a with statement */ extern JS_PUBLIC_API(JSBool) -JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +JS_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp); extern JS_PUBLIC_API(JSBool) JS_EnumerateStub(JSContext *cx, JSObject *obj); extern JS_PUBLIC_API(JSBool) -JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id); +JS_ResolveStub(JSContext *cx, JSObject *obj, jsid id); extern JS_PUBLIC_API(JSBool) JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp); @@ -1829,8 +2017,8 @@ struct JSPropertyDescriptor { uintN attrs; JSPropertyOp getter; JSPropertyOp setter; - uintN shortid; jsval value; + uintN shortid; }; /* @@ -2015,7 +2203,7 @@ JS_NewPropertyIterator(JSContext *cx, JSObject *obj); /* * Return true on success with *idp containing the id of the next enumerable - * property to visit using iterobj, or JSVAL_VOID if there is no such property + * property to visit using iterobj, or JSID_IS_VOID if there is no such property * left to visit. Return false on error. */ extern JS_PUBLIC_API(JSBool) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 568e0ef5432e..44fa8093f9d8 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -60,8 +60,8 @@ * friend. The function isDenseArrayMinLenCapOk() checks that it is set * correctly; a call to it should be put in an assertion at use points. * - * In dense mode, holes in the array are represented by JSVAL_HOLE. The final - * slot in fslots is unused. + * In dense mode, holes in the array are represented by (JS_ARRAY_HOLE) invalid + * values. The final slot in fslots is unused. * * NB: the capacity and length of a dense array are entirely unrelated! The * length may be greater than, less than, or equal to the capacity. See @@ -136,8 +136,6 @@ INDEX_TOO_BIG(jsuint index) ((index) > array->getDenseArrayCapacity() && (index) >= MIN_SPARSE_INDEX && \ (index) > ((array)->getDenseArrayCount() + 1) * 4)) -JS_STATIC_ASSERT(sizeof(JSScopeProperty) > 4 * sizeof(jsval)); - #define ENSURE_SLOW_ARRAY(cx, obj) \ (obj->getClass() == &js_SlowArrayClass || obj->makeDenseArraySlow(cx)) @@ -152,32 +150,18 @@ JS_STATIC_ASSERT(sizeof(JSScopeProperty) > 4 * sizeof(jsval)); * to 2^32-1." * * In our implementation, it would be sufficient to check for JSVAL_IS_INT(id) - * except that by using signed 32-bit integers we miss the top half of the + * except that by using signed 31-bit integers we miss the top half of the * valid range. This function checks the string representation itself; note * that calling a standard conversion routine might allow strings such as * "08" or "4.0" as array indices, which they are not. + * + * 'id' is passed as a jsboxedword since the given id need not necessarily hold + * an atomized string. */ JSBool -js_IdIsIndex(jsval id, jsuint *indexp) +js_StringIsIndex(JSString *str, jsuint *indexp) { - JSString *str; - jschar *cp; - - if (JSVAL_IS_INT(id)) { - jsint i; - i = JSVAL_TO_INT(id); - if (i < 0) - return JS_FALSE; - *indexp = (jsuint)i; - return JS_TRUE; - } - - /* NB: id should be a string, but jsxml.c may call us with an object id. */ - if (!JSVAL_IS_STRING(id)) - return JS_FALSE; - - str = JSVAL_TO_STRING(id); - cp = str->chars(); + jschar *cp = str->chars(); if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) { jsuint index = JS7_UNDEC(*cp++); jsuint oldIndex = 0; @@ -204,13 +188,10 @@ js_IdIsIndex(jsval id, jsuint *indexp) } static jsuint -ValueIsLength(JSContext *cx, jsval* vp) +ValueIsLength(JSContext *cx, Value* vp) { - jsint i; - jsuint length; - - if (JSVAL_IS_INT(*vp)) { - i = JSVAL_TO_INT(*vp); + if (vp->isInt32()) { + int32_t i = vp->toInt32(); if (i < 0) goto error; return (jsuint) i; @@ -222,19 +203,17 @@ ValueIsLength(JSContext *cx, jsval* vp) if (JSDOUBLE_IS_NaN(d)) goto error; + jsuint length; length = (jsuint) d; if (d != (jsdouble) length) goto error; - if (!js_NewNumberInRootedValue(cx, d, vp)) { - *vp = JSVAL_NULL; - return 0; - } + vp->setNumber(length); return length; error: JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); - *vp = JSVAL_NULL; + vp->setNull(); return 0; } @@ -251,12 +230,12 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) return true; } - AutoValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), tvr.addr())) return false; - if (JSVAL_IS_INT(tvr.value())) { - *lengthp = jsuint(jsint(JSVAL_TO_INT(tvr.value()))); /* jsuint cast does ToUint32 */ + if (tvr.value().isInt32()) { + *lengthp = jsuint(jsint(tvr.value().toInt32())); /* jsuint cast does ToUint32 */ return true; } @@ -264,25 +243,19 @@ js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)lengthp); } -static JSBool -IndexToValue(JSContext *cx, jsdouble index, jsval *vp) -{ - return js_NewWeaklyRootedNumber(cx, index, vp); -} - JSBool JS_FASTCALL js_IndexToId(JSContext *cx, jsuint index, jsid *idp) { JSString *str; - if (index <= JSVAL_INT_MAX) { + if (index <= JSID_INT_MAX) { *idp = INT_TO_JSID(index); return JS_TRUE; } str = js_NumberToString(cx, index); if (!str) return JS_FALSE; - return js_ValueToStringId(cx, STRING_TO_JSVAL(str), idp); + return js_ValueToStringId(cx, StringValue(str), idp); } static JSBool @@ -290,11 +263,11 @@ BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom, jsid *idp) { jschar buf[10], *start; - JSClass *clasp; + Class *clasp; JSAtom *atom; JS_STATIC_ASSERT((jsuint)-1 == 4294967295U); - JS_ASSERT(index > JSVAL_INT_MAX); + JS_ASSERT(index > JSID_INT_MAX); start = JS_ARRAY_END(buf); do { @@ -317,7 +290,7 @@ BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom, clasp == &js_ObjectClass)) { atom = js_GetExistingStringAtom(cx, start, JS_ARRAY_END(buf) - start); if (!atom) { - *idp = JSVAL_VOID; + *idp = JSID_VOID; return JS_TRUE; } } else { @@ -346,8 +319,8 @@ JSObject::resizeDenseArrayElements(JSContext *cx, uint32 oldcap, uint32 newcap, return JS_FALSE; } - jsval *slots = dslots ? dslots - 1 : NULL; - jsval *newslots = (jsval *) cx->realloc(slots, (size_t(newcap) + 1) * sizeof(jsval)); + Value *slots = dslots ? dslots - 1 : NULL; + Value *newslots = (Value *) cx->realloc(slots, (size_t(newcap) + 1) * sizeof(Value)); if (!newslots) return false; @@ -355,8 +328,9 @@ JSObject::resizeDenseArrayElements(JSContext *cx, uint32 oldcap, uint32 newcap, setDenseArrayCapacity(newcap); if (initializeAllSlots) { - for (uint32 i = oldcap; i < newcap; i++) - setDenseArrayElement(i, JSVAL_HOLE); + Value *base = addressOfDenseArrayElement(0); + for (Value *vp = base + oldcap, *end = base + newcap; vp < end; ++vp) + vp->setMagic(JS_ARRAY_HOLE); } return true; @@ -378,7 +352,7 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uint32 newcap, bool initialize * Round up all large allocations to a multiple of this (1MB), so as not * to waste space if malloc gives us 1MB-sized chunks (as jemalloc does). */ - static const size_t CAPACITY_CHUNK = 1024 * 1024 / sizeof(jsval); + static const size_t CAPACITY_CHUNK = 1024 * 1024 / sizeof(Value); uint32 oldcap = getDenseArrayCapacity(); @@ -411,7 +385,7 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uint32 newcap, bool initialize * Initialize the slots caller didn't actually ask for. */ for (uint32 i = newcap; i < actualCapacity; i++) { - setDenseArrayElement(i, JSVAL_HOLE); + setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE)); } } } @@ -421,19 +395,14 @@ JSObject::ensureDenseArrayElements(JSContext *cx, uint32 newcap, bool initialize static bool ReallyBigIndexToId(JSContext* cx, jsdouble index, jsid* idp) { - AutoValueRooter dval(cx); - if (!js_NewDoubleInRootedValue(cx, index, dval.addr()) || - !js_ValueToStringId(cx, dval.value(), idp)) { - return JS_FALSE; - } - return JS_TRUE; + return js_ValueToStringId(cx, DoubleValue(index), idp); } static bool IndexToId(JSContext* cx, JSObject* obj, jsdouble index, JSBool* hole, jsid* idp, JSBool createAtom = JS_FALSE) { - if (index <= JSVAL_INT_MAX) { + if (index <= JSID_INT_MAX) { *idp = INT_TO_JSID(int(index)); return JS_TRUE; } @@ -441,7 +410,7 @@ IndexToId(JSContext* cx, JSObject* obj, jsdouble index, JSBool* hole, jsid* idp, if (index <= jsuint(-1)) { if (!BigIndexToId(cx, obj, jsuint(index), createAtom, idp)) return JS_FALSE; - if (hole && JSVAL_IS_VOID(*idp)) + if (hole && JSID_IS_VOID(*idp)) *hole = JS_TRUE; return JS_TRUE; } @@ -457,12 +426,11 @@ IndexToId(JSContext* cx, JSObject* obj, jsdouble index, JSBool* hole, jsid* idp, */ static JSBool GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, - jsval *vp) + Value *vp) { JS_ASSERT(index >= 0); if (obj->isDenseArray() && index < obj->getDenseArrayCapacity() && - (*vp = obj->getDenseArrayElement(jsuint(index))) != JSVAL_HOLE) { - + !(*vp = obj->getDenseArrayElement(uint32(index))).isMagic(JS_ARRAY_HOLE)) { *hole = JS_FALSE; return JS_TRUE; } @@ -473,7 +441,7 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, if (!IndexToId(cx, obj, index, hole, idr.addr())) return JS_FALSE; if (*hole) { - *vp = JSVAL_VOID; + vp->setUndefined(); return JS_TRUE; } @@ -483,7 +451,7 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, return JS_FALSE; if (!prop) { *hole = JS_TRUE; - *vp = JSVAL_VOID; + vp->setUndefined(); } else { obj2->dropProperty(cx, prop); if (!obj->getProperty(cx, idr.id(), vp)) @@ -497,7 +465,7 @@ GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole, * Set the value of the property at the given index to v assuming v is rooted. */ static JSBool -SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v) +SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, const Value &v) { JS_ASSERT(index >= 0); @@ -511,7 +479,7 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v) return JS_FALSE; if (idx >= obj->getArrayLength()) obj->setDenseArrayLength(idx + 1); - if (obj->getDenseArrayElement(idx) == JSVAL_HOLE) + if (obj->getDenseArrayElement(idx).isMagic(JS_ARRAY_HOLE)) obj->incDenseArrayCountBy(1); obj->setDenseArrayElement(idx, v); return JS_TRUE; @@ -526,9 +494,10 @@ SetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, jsval v) if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE)) return JS_FALSE; - JS_ASSERT(!JSVAL_IS_VOID(idr.id())); + JS_ASSERT(!JSID_IS_VOID(idr.id())); - return obj->setProperty(cx, idr.id(), &v); + Value tmp = v; + return obj->setProperty(cx, idr.id(), &tmp); } static JSBool @@ -539,9 +508,9 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index) if (index <= jsuint(-1)) { jsuint idx = jsuint(index); if (!INDEX_TOO_SPARSE(obj, idx) && idx < obj->getDenseArrayCapacity()) { - if (obj->getDenseArrayElement(idx) != JSVAL_HOLE) + if (!obj->getDenseArrayElement(idx).isMagic(JS_ARRAY_HOLE)) obj->decDenseArrayCountBy(1); - obj->setDenseArrayElement(idx, JSVAL_HOLE); + obj->setDenseArrayElement(idx, MagicValue(JS_ARRAY_HOLE)); return JS_TRUE; } } @@ -552,10 +521,10 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index) if (!IndexToId(cx, obj, index, NULL, idr.addr())) return JS_FALSE; - if (JSVAL_IS_VOID(idr.id())) + if (JSID_IS_VOID(idr.id())) return JS_TRUE; - jsval junk; + Value junk; return obj->deleteProperty(cx, idr.id(), &junk); } @@ -565,10 +534,10 @@ DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index) */ static JSBool SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, - JSBool hole, jsval v) + JSBool hole, const Value &v) { if (hole) { - JS_ASSERT(JSVAL_IS_VOID(v)); + JS_ASSERT(v.isUndefined()); return DeleteArrayElement(cx, obj, index); } return SetArrayElement(cx, obj, index, v); @@ -577,11 +546,10 @@ SetOrDeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length) { - jsval v; + Value v; jsid id; - if (!IndexToValue(cx, length, &v)) - return JS_FALSE; + v.setNumber(length); id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); return obj->setProperty(cx, id, &v); } @@ -590,7 +558,7 @@ JSBool js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) { JSErrorReporter older = JS_SetErrorReporter(cx, NULL); - AutoValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); JSBool ok = obj->getProperty(cx, id, tvr.addr()); JS_SetErrorReporter(cx, older); @@ -598,7 +566,7 @@ js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) return false; *lengthp = ValueIsLength(cx, tvr.addr()); - return !JSVAL_IS_NULL(tvr.value()); + return !tvr.value().isNull(); } JSBool @@ -622,20 +590,22 @@ js_IsArrayLike(JSContext *cx, JSObject *obj, JSBool *answerp, jsuint *lengthp) * the JSPROP_SHARED attribute, we must define a shadowing length property. */ static JSBool -array_length_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +array_length_getter(JSContext *cx, JSObject *obj, jsid id, Value *vp) { do { - if (obj->isArray()) - return IndexToValue(cx, obj->getArrayLength(), vp); + if (obj->isArray()) { + vp->setNumber(obj->getArrayLength()); + return JS_TRUE; + } } while ((obj = obj->getProto()) != NULL); return JS_TRUE; } static JSBool -array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +array_length_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp) { jsuint newlen, oldlen, gap, index; - jsval junk; + Value junk; if (!obj->isArray()) { jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); @@ -644,16 +614,14 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } newlen = ValueIsLength(cx, vp); - if (JSVAL_IS_NULL(*vp)) + if (vp->isNull()) return false; oldlen = obj->getArrayLength(); if (oldlen == newlen) return true; - if (!IndexToValue(cx, newlen, vp)) - return false; - + vp->setNumber(newlen); if (oldlen < newlen) { if (obj->isDenseArray()) obj->setDenseArrayLength(newlen); @@ -688,13 +656,13 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return false; /* Protect iter against GC under JSObject::deleteProperty. */ - AutoValueRooter tvr(cx, iter); + AutoObjectRooter tvr(cx, iter); gap = oldlen - newlen; for (;;) { if (!JS_CHECK_OPERATION_LIMIT(cx) || !JS_NextProperty(cx, iter, &id)) return false; - if (JSVAL_IS_VOID(id)) + if (JSID_IS_VOID(id)) break; if (js_IdIsIndex(id, &index) && index - newlen < gap && !obj->deleteProperty(cx, id, &junk)) { @@ -717,11 +685,11 @@ IsDenseArrayId(JSContext *cx, JSObject *obj, jsid id) JS_ASSERT(obj->isDenseArray()); uint32 i; - return id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) || + return JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) || (js_IdIsIndex(id, &i) && obj->getArrayLength() != 0 && i < obj->getDenseArrayCapacity() && - obj->getDenseArrayElement(i) != JSVAL_HOLE); + !obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)); } static JSBool @@ -732,7 +700,7 @@ array_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, return js_LookupProperty(cx, obj, id, objp, propp); if (IsDenseArrayId(cx, obj, id)) { - *propp = (JSProperty *) id; + *propp = (JSProperty *) 1; /* non-null to indicate found */ *objp = obj; return JS_TRUE; } @@ -747,50 +715,51 @@ array_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, } JSBool -js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, JSProperty *prop, - jsval *vp) +js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - jsid id = (jsid) prop; - JS_ASSERT(IsDenseArrayId(cx, obj, id)); + JS_ASSERT(obj->isDenseArray()); uint32 i; if (!js_IdIsIndex(id, &i)) { - JS_ASSERT(id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)); - return IndexToValue(cx, obj->getArrayLength(), vp); + JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)); + vp->setNumber(obj->getArrayLength()); + return JS_TRUE; } *vp = obj->getDenseArrayElement(i); return JS_TRUE; } static JSBool -array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +array_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { uint32 i; - if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) - return IndexToValue(cx, obj->getArrayLength(), vp); + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + vp->setNumber(obj->getArrayLength()); + return JS_TRUE; + } - if (id == ATOM_TO_JSID(cx->runtime->atomState.protoAtom)) { - *vp = OBJECT_TO_JSVAL(obj->getProto()); + if (JSID_IS_ATOM(id, cx->runtime->atomState.protoAtom)) { + vp->setObjectOrNull(obj->getProto()); return JS_TRUE; } if (!obj->isDenseArray()) return js_GetProperty(cx, obj, id, vp); - if (!js_IdIsIndex(ID_TO_VALUE(id), &i) || i >= obj->getDenseArrayCapacity() || - obj->getDenseArrayElement(i) == JSVAL_HOLE) { + if (!js_IdIsIndex(id, &i) || i >= obj->getDenseArrayCapacity() || + obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) { JSObject *obj2; JSProperty *prop; JSScopeProperty *sprop; JSObject *proto = obj->getProto(); if (!proto) { - *vp = JSVAL_VOID; + vp->setUndefined(); return JS_TRUE; } - *vp = JSVAL_VOID; + vp->setUndefined(); if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, &obj2, &prop) < 0) return JS_FALSE; @@ -809,7 +778,7 @@ array_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) } static JSBool -slowarray_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +slowarray_addProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { jsuint index, length; @@ -828,11 +797,11 @@ array_typeOf(JSContext *cx, JSObject *obj) } static JSBool -array_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +array_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { uint32 i; - if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) return array_length_setter(cx, obj, id, vp); if (!obj->isDenseArray()) @@ -849,7 +818,7 @@ array_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) if (i >= obj->getArrayLength()) obj->setDenseArrayLength(i + 1); - if (obj->getDenseArrayElement(i) == JSVAL_HOLE) + if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) obj->incDenseArrayCountBy(1); obj->setDenseArrayElement(i, *vp); return JS_TRUE; @@ -880,12 +849,14 @@ js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj) #ifdef JS_TRACER static JS_ALWAYS_INLINE JSBool FASTCALL -dense_grow(JSContext* cx, JSObject* obj, jsint i, jsval v) +dense_grow(JSContext* cx, JSObject* obj, jsint i, const Value &v) { + JS_ASSERT(obj->isDenseArray()); + /* * Let the interpreter worry about negative array indexes. */ - JS_ASSERT((MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) == (sizeof(jsval) != sizeof(uint32))); + JS_ASSERT((MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) == (sizeof(intptr_t) != sizeof(uint32))); if (MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) { /* * Have to check for negative values bleeding through on 64-bit machines only, @@ -903,7 +874,7 @@ dense_grow(JSContext* cx, JSObject* obj, jsint i, jsval v) if ((u >= capacity) && (INDEX_TOO_SPARSE(obj, u) || !obj->ensureDenseArrayElements(cx, u + 1))) return JS_FALSE; - if (obj->getDenseArrayElement(u) == JSVAL_HOLE) { + if (obj->getDenseArrayElement(u).isMagic()) { if (js_PrototypeHasIndexedProperties(cx, obj)) return JS_FALSE; @@ -916,31 +887,18 @@ dense_grow(JSContext* cx, JSObject* obj, jsint i, jsval v) return JS_TRUE; } - JSBool FASTCALL -js_Array_dense_setelem(JSContext* cx, JSObject* obj, jsint i, jsval v) +js_Array_dense_setelem(JSContext* cx, JSObject* obj, jsint i, ValueArgType v) { - JS_ASSERT(obj->isDenseArray()); - return dense_grow(cx, obj, i, v); + return dense_grow(cx, obj, i, ValueArgToConstRef(v)); } -JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem, CONTEXT, OBJECT, INT32, JSVAL, 0, +JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem, CONTEXT, OBJECT, INT32, VALUE, 0, nanojit::ACC_STORE_ANY) JSBool FASTCALL js_Array_dense_setelem_int(JSContext* cx, JSObject* obj, jsint i, int32 j) { - JS_ASSERT(obj->isDenseArray()); - - jsval v; - if (JS_LIKELY(INT_FITS_IN_JSVAL(j))) { - v = INT_TO_JSVAL(j); - } else { - jsdouble d = (jsdouble)j; - if (!js_NewDoubleInRootedValue(cx, d, &v)) - return JS_FALSE; - } - - return dense_grow(cx, obj, i, v); + return dense_grow(cx, obj, i, Int32Value(j)); } JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem_int, CONTEXT, OBJECT, INT32, INT32, 0, nanojit::ACC_STORE_ANY) @@ -948,48 +906,37 @@ JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem_int, CONTEXT, OBJECT, JSBool FASTCALL js_Array_dense_setelem_double(JSContext* cx, JSObject* obj, jsint i, jsdouble d) { - JS_ASSERT(obj->isDenseArray()); - - jsval v; - jsint j; - - if (JS_LIKELY(JSDOUBLE_IS_INT(d, j) && INT_FITS_IN_JSVAL(j))) { - v = INT_TO_JSVAL(j); - } else { - if (!js_NewDoubleInRootedValue(cx, d, &v)) - return JS_FALSE; - } - - return dense_grow(cx, obj, i, v); + return dense_grow(cx, obj, i, NumberValue(d)); } JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem_double, CONTEXT, OBJECT, INT32, DOUBLE, 0, nanojit::ACC_STORE_ANY) #endif static JSBool -array_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs) +array_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, + PropertyOp getter, PropertyOp setter, uintN attrs) { uint32 i = 0; // init to shut GCC up JSBool isIndex; - if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) return JS_TRUE; - isIndex = js_IdIsIndex(ID_TO_VALUE(id), &i); + isIndex = js_IdIsIndex(id, &i); if (!isIndex || attrs != JSPROP_ENUMERATE || !obj->isDenseArray() || INDEX_TOO_SPARSE(obj, i)) { if (!ENSURE_SLOW_ARRAY(cx, obj)) return JS_FALSE; return js_DefineProperty(cx, obj, id, value, getter, setter, attrs); } - return array_setProperty(cx, obj, id, &value); + Value tmp = *value; + return array_setProperty(cx, obj, id, &tmp); } static JSBool array_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { - *attrsp = id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) + *attrsp = JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ? JSPROP_PERMANENT : JSPROP_ENUMERATE; return JS_TRUE; } @@ -1003,28 +950,28 @@ array_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) } static JSBool -array_deleteProperty(JSContext *cx, JSObject *obj, jsval id, jsval *rval) +array_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval) { uint32 i; if (!obj->isDenseArray()) return js_DeleteProperty(cx, obj, id, rval); - if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { - *rval = JSVAL_FALSE; + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + rval->setBoolean(false); return JS_TRUE; } if (js_IdIsIndex(id, &i) && i < obj->getDenseArrayCapacity() && - obj->getDenseArrayElement(i) != JSVAL_HOLE) { + !obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) { obj->decDenseArrayCountBy(1); - obj->setDenseArrayElement(i, JSVAL_HOLE); + obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE)); } if (!js_SuppressDeletedProperty(cx, obj, id)) return false; - *rval = JSVAL_TRUE; + rval->setBoolean(true); return JS_TRUE; } @@ -1037,21 +984,12 @@ array_finalize(JSContext *cx, JSObject *obj) static void array_trace(JSTracer *trc, JSObject *obj) { - uint32 capacity; - size_t i; - jsval v; - JS_ASSERT(obj->isDenseArray()); obj->traceProtoAndParent(trc); - capacity = obj->getDenseArrayCapacity(); - for (i = 0; i < capacity; i++) { - v = obj->getDenseArrayElement(i); - if (JSVAL_IS_TRACEABLE(v)) { - JS_SET_TRACING_INDEX(trc, "dense_array_elems", i); - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); - } - } + uint32 capacity = obj->getDenseArrayCapacity(); + for (uint32 i = 0; i < capacity; i++) + MarkValue(trc, obj->getDenseArrayElement(i), "dense_array_elems"); } extern JSObjectOps js_ArrayObjectOps; @@ -1078,27 +1016,27 @@ JSObjectOps js_ArrayObjectOps = { }; static JSObjectOps * -array_getObjectOps(JSContext *cx, JSClass *clasp) +array_getObjectOps(JSContext *cx, Class *clasp) { return &js_ArrayObjectOps; } -JSClass js_ArrayClass = { +Class js_ArrayClass = { "Array", JSCLASS_HAS_RESERVED_SLOTS(JSObject::DENSE_ARRAY_FIXED_RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Array), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, js_TryValueOf, array_finalize, - array_getObjectOps, NULL, NULL, NULL, - NULL, NULL, NULL, NULL + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, js_TryValueOf, array_finalize, + array_getObjectOps, NULL, NULL, NULL, + NULL, NULL, NULL, NULL }; -JSClass js_SlowArrayClass = { +Class js_SlowArrayClass = { "Array", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array), - slowarray_addProperty, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, js_TryValueOf, NULL, + slowarray_addProperty, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, js_TryValueOf, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; @@ -1149,11 +1087,11 @@ JSObject::makeDenseArraySlow(JSContext *cx) /* Create new properties pointing to existing elements. */ for (uint32 i = 0; i < capacity; i++) { jsid id; - if (!JS_ValueToId(cx, INT_TO_JSVAL(i), &id)) + if (!ValueToId(cx, Int32Value(i), &id)) goto out_bad; - if (obj->getDenseArrayElement(i) == JSVAL_HOLE) { - obj->setDenseArrayElement(i, JSVAL_VOID); + if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) { + obj->setDenseArrayElement(i, UndefinedValue()); continue; } @@ -1169,11 +1107,7 @@ JSObject::makeDenseArraySlow(JSContext *cx) */ JS_ASSERT(js_SlowArrayClass.flags & JSCLASS_HAS_PRIVATE); obj->voidDenseOnlyArraySlots(); - - /* Make sure we preserve any flags borrowing bits in classword. */ - obj->classword ^= (jsuword) &js_ArrayClass; - obj->classword |= (jsuword) &js_SlowArrayClass; - + obj->clasp = &js_SlowArrayClass; obj->map = scope; return JS_TRUE; @@ -1184,25 +1118,25 @@ JSObject::makeDenseArraySlow(JSContext *cx) /* Transfer ownership of buffer to returned string. */ static inline JSBool -BufferToString(JSContext *cx, JSCharBuffer &cb, jsval *rval) +BufferToString(JSContext *cx, JSCharBuffer &cb, Value *rval) { JSString *str = js_NewStringFromCharBuffer(cx, cb); if (!str) return false; - *rval = STRING_TO_JSVAL(str); + rval->setString(str); return true; } #if JS_HAS_TOSOURCE static JSBool -array_toSource(JSContext *cx, uintN argc, jsval *vp) +array_toSource(JSContext *cx, uintN argc, Value *vp) { JS_CHECK_RECURSION(cx, return false); - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || (obj->getClass() != &js_SlowArrayClass && - !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2))) { + !InstanceOf(cx, obj, &js_ArrayClass, vp + 2))) { return false; } @@ -1266,7 +1200,7 @@ array_toSource(JSContext *cx, uintN argc, jsval *vp) if (!str) goto out; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); const jschar *chars; size_t charlen; str->getCharsAndLength(chars, charlen); @@ -1302,7 +1236,7 @@ array_toSource(JSContext *cx, uintN argc, jsval *vp) static JSBool array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, - JSString *sepstr, jsval *rval) + JSString *sepstr, Value *rval) { JS_CHECK_RECURSION(cx, return false); @@ -1322,11 +1256,11 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, genBefore = cx->busyArrays.generation(); } else { /* Cycle, so return empty string. */ - *rval = ATOM_KEY(cx->runtime->atomState.emptyAtom); + rval->setString(ATOM_TO_STRING(cx->runtime->atomState.emptyAtom)); return true; } - AutoValueRooter tvr(cx, obj); + AutoObjectRooter tvr(cx, obj); /* After this point, all paths exit through the 'out' label. */ MUST_FLOW_THROUGH("out"); @@ -1362,14 +1296,14 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, } /* Get element's character string. */ - if (!(hole || JSVAL_IS_VOID(*rval) || JSVAL_IS_NULL(*rval))) { + if (!(hole || rval->isNullOrUndefined())) { if (locale) { /* Work on obj.toLocalString() instead. */ JSObject *robj; - if (!js_ValueToObject(cx, *rval, &robj)) + if (!js_ValueToObjectOrNull(cx, *rval, &robj)) goto out; - *rval = OBJECT_TO_JSVAL(robj); + rval->setObjectOrNull(robj); JSAtom *atom = cx->runtime->atomState.toLocaleStringAtom; if (!js_TryMethod(cx, robj, atom, 0, NULL, rval)) goto out; @@ -1401,14 +1335,12 @@ array_toString_sub(JSContext *cx, JSObject *obj, JSBool locale, } static JSBool -array_toString(JSContext *cx, uintN argc, jsval *vp) +array_toString(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || (obj->getClass() != &js_SlowArrayClass && - !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2))) { + !InstanceOf(cx, obj, &js_ArrayClass, vp + 2))) { return JS_FALSE; } @@ -1416,14 +1348,12 @@ array_toString(JSContext *cx, uintN argc, jsval *vp) } static JSBool -array_toLocaleString(JSContext *cx, uintN argc, jsval *vp) +array_toLocaleString(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || (obj->getClass() != &js_SlowArrayClass && - !JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2))) { + !InstanceOf(cx, obj, &js_ArrayClass, vp + 2))) { return JS_FALSE; } @@ -1445,7 +1375,7 @@ enum SourceVectorType { }; static JSBool -InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsval *vector, +InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Value *vector, TargetElementsType targetType, SourceVectorType vectorType) { JS_ASSERT(count < MAXINDEX); @@ -1484,11 +1414,11 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva if (newlen > obj->getArrayLength()) obj->setDenseArrayLength(newlen); - JS_ASSERT(count < size_t(-1) / sizeof(jsval)); + JS_ASSERT(count < uint32(-1) / sizeof(Value)); if (targetType == TargetElementsMayContainValues) { jsuint valueCount = 0; for (jsuint i = 0; i < count; i++) { - if (obj->getDenseArrayElement(start + i) != JSVAL_HOLE) + if (!obj->getDenseArrayElement(start + i).isMagic(JS_ARRAY_HOLE)) valueCount++; } JS_ASSERT(obj->getDenseArrayCount() >= valueCount); @@ -1500,16 +1430,16 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva } else { jsuint valueCount = 0; for (jsuint i = 0; i < count; i++) { - if (obj->getDenseArrayElement(start + i) != JSVAL_HOLE) + if (!obj->getDenseArrayElement(start + i).isMagic(JS_ARRAY_HOLE)) valueCount++; } obj->incDenseArrayCountBy(valueCount); } - JS_ASSERT_IF(count != 0, obj->getDenseArrayElement(newlen - 1) != JSVAL_HOLE); + JS_ASSERT_IF(count != 0, !obj->getDenseArrayElement(newlen - 1).isMagic(JS_ARRAY_HOLE)); return JS_TRUE; } - jsval* end = vector + count; + Value* end = vector + count; while (vector != end && start < MAXINDEX) { if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, start++, *vector++)) { @@ -1525,27 +1455,23 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, jsva return JS_FALSE; JS_ASSERT(start == MAXINDEX); - jsval tmp[2] = {JSVAL_NULL, JSVAL_NULL}; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tmp), tmp); - if (!js_NewDoubleInRootedValue(cx, MAXINDEX, &tmp[0])) - return JS_FALSE; - jsdouble *dp = JSVAL_TO_DOUBLE(tmp[0]); - JS_ASSERT(*dp == MAXINDEX); + AutoValueRooter tvr(cx); AutoIdRooter idr(cx); + Value idval = DoubleValue(MAXINDEX); do { - tmp[1] = *vector++; - if (!js_ValueToStringId(cx, tmp[0], idr.addr()) || - !obj->setProperty(cx, idr.id(), &tmp[1])) { + *tvr.addr() = *vector++; + if (!js_ValueToStringId(cx, idval, idr.addr()) || + !obj->setProperty(cx, idr.id(), tvr.addr())) { return JS_FALSE; } - *dp += 1; + idval.getDoubleRef() += 1; } while (vector != end); return JS_TRUE; } static JSBool -InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const jsval *vector, +InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const Value *vector, bool holey = false) { JS_ASSERT(obj->isArray()); @@ -1558,10 +1484,10 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const jsval *vector jsuint count = length; if (!holey) { - memcpy(obj->getDenseArrayElements(), vector, length * sizeof (jsval)); + memcpy(obj->getDenseArrayElements(), vector, length * sizeof(Value)); } else { for (jsuint i = 0; i < length; i++) { - if (vector[i] == JSVAL_HOLE) + if (vector[i].isMagic(JS_ARRAY_HOLE)) --count; obj->setDenseArrayElement(i, vector[i]); } @@ -1582,31 +1508,29 @@ InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, const jsval *vector * Perl-inspired join, reverse, and sort. */ static JSBool -array_join(JSContext *cx, uintN argc, jsval *vp) +array_join(JSContext *cx, uintN argc, Value *vp) { JSString *str; - JSObject *obj; - - if (argc == 0 || JSVAL_IS_VOID(vp[2])) { + if (argc == 0 || vp[2].isUndefined()) { str = NULL; } else { str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - vp[2] = STRING_TO_JSVAL(str); + vp[2].setString(str); } - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); return obj && array_toString_sub(cx, obj, JS_FALSE, str, vp); } static JSBool -array_reverse(JSContext *cx, uintN argc, jsval *vp) +array_reverse(JSContext *cx, uintN argc, Value *vp) { jsuint len; - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &len)) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj)) { /* An empty array or an array with no elements is already reversed. */ @@ -1627,7 +1551,7 @@ array_reverse(JSContext *cx, uintN argc, jsval *vp) uint32 lo = 0, hi = len - 1; for (; lo < hi; lo++, hi--) { - jsval tmp = obj->getDenseArrayElement(lo); + Value tmp = obj->getDenseArrayElement(lo); obj->setDenseArrayElement(lo, obj->getDenseArrayElement(hi)); obj->setDenseArrayElement(hi, tmp); } @@ -1651,7 +1575,7 @@ array_reverse(JSContext *cx, uintN argc, jsval *vp) return false; } } - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); return true; } @@ -1659,7 +1583,7 @@ typedef struct MSortArgs { size_t elsize; JSComparator cmp; void *arg; - JSBool fastcopy; + JSBool isValue; } MSortArgs; /* Helper function for js_MergeSort. */ @@ -1670,14 +1594,14 @@ MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2) size_t elsize, runtotal; int cmp_result; JSComparator cmp; - JSBool fastcopy; + JSBool isValue; runtotal = run1 + run2; elsize = msa->elsize; cmp = msa->cmp; arg = msa->arg; - fastcopy = msa->fastcopy; + isValue = msa->isValue; #define CALL_CMP(a, b) \ if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; @@ -1692,7 +1616,7 @@ MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2) } #define COPY_ONE(p,q,n) \ - (fastcopy ? (void)(*(jsval*)(p) = *(jsval*)(q)) : (void)memcpy(p, q, n)) + (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) a = src; c = dest; @@ -1724,21 +1648,22 @@ MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2) * This sort is stable, i.e. sequence of equal elements is preserved. * See also bug #224128. */ -JSBool +bool js_MergeSort(void *src, size_t nel, size_t elsize, - JSComparator cmp, void *arg, void *tmp) + JSComparator cmp, void *arg, void *tmp, + JSMergeSortElemType elemType) { void *swap, *vec1, *vec2; MSortArgs msa; size_t i, j, lo, hi, run; - JSBool fastcopy; int cmp_result; + JS_ASSERT_IF(JS_SORTING_VALUES, elsize == sizeof(Value)); + bool isValue = elemType == JS_SORTING_VALUES; + /* Avoid memcpy overhead for word-sized and word-aligned elements. */ - fastcopy = (elsize == sizeof(jsval) && - (((jsuword) src | (jsuword) tmp) & JSVAL_ALIGN) == 0); #define COPY_ONE(p,q,n) \ - (fastcopy ? (void)(*(jsval*)(p) = *(jsval*)(q)) : (void)memcpy(p, q, n)) + (isValue ? (void)(*(Value*)p = *(Value*)q) : (void)memcpy(p, q, n)) #define CALL_CMP(a, b) \ if (!cmp(arg, (a), (b), &cmp_result)) return JS_FALSE; #define INS_SORT_INT 4 @@ -1776,7 +1701,7 @@ js_MergeSort(void *src, size_t nel, size_t elsize, msa.elsize = elsize; msa.cmp = cmp; msa.arg = arg; - msa.fastcopy = fastcopy; + msa.isValue = isValue; vec1 = src; vec2 = tmp; @@ -1807,10 +1732,10 @@ js_MergeSort(void *src, size_t nel, size_t elsize, struct CompareArgs { JSContext *context; - jsval fval; + Value fval; InvokeArgsGuard args; - CompareArgs(JSContext *cx, jsval fval) + CompareArgs(JSContext *cx, const Value &fval) : context(cx), fval(fval) {} }; @@ -1818,7 +1743,7 @@ struct CompareArgs static JS_REQUIRES_STACK JSBool sort_compare(void *arg, const void *a, const void *b, int *result) { - jsval av = *(const jsval *)a, bv = *(const jsval *)b; + const Value *av = (const Value *)a, *bv = (const Value *)b; CompareArgs *ca = (CompareArgs *) arg; JSContext *cx = ca->context; @@ -1826,20 +1751,20 @@ sort_compare(void *arg, const void *a, const void *b, int *result) * array_sort deals with holes and undefs on its own and they should not * come here. */ - JS_ASSERT(!JSVAL_IS_VOID(av)); - JS_ASSERT(!JSVAL_IS_VOID(bv)); + JS_ASSERT(!av->isMagic() && !av->isUndefined()); + JS_ASSERT(!av->isMagic() && !bv->isUndefined()); if (!JS_CHECK_OPERATION_LIMIT(cx)) return JS_FALSE; - jsval *invokevp = ca->args.getvp(); - jsval *sp = invokevp; + Value *invokevp = ca->args.getvp(); + Value *sp = invokevp; *sp++ = ca->fval; - *sp++ = JSVAL_NULL; - *sp++ = av; - *sp++ = bv; + *sp++ = NullValue(); + *sp++ = *av; + *sp++ = *bv; - if (!js_Invoke(cx, ca->args, 0)) + if (!Invoke(cx, ca->args, 0)) return JS_FALSE; jsdouble cmp; @@ -1872,59 +1797,52 @@ comparator_stack_cast(JSRedComparator func) static int sort_compare_strings(void *arg, const void *a, const void *b, int *result) { - jsval av = *(const jsval *)a, bv = *(const jsval *)b; + const Value *av = (const Value *)a, *bv = (const Value *)b; - JS_ASSERT(JSVAL_IS_STRING(av)); - JS_ASSERT(JSVAL_IS_STRING(bv)); + JS_ASSERT(av->isString()); + JS_ASSERT(bv->isString()); if (!JS_CHECK_OPERATION_LIMIT((JSContext *)arg)) return JS_FALSE; - *result = (int) js_CompareStrings(JSVAL_TO_STRING(av), JSVAL_TO_STRING(bv)); + *result = (int) js_CompareStrings(av->toString(), bv->toString()); return JS_TRUE; } -/* - * The array_sort function below assumes JSVAL_NULL is zero in order to - * perform initialization using memset. Other parts of SpiderMonkey likewise - * "know" that JSVAL_NULL is zero; this static assertion covers all cases. - */ -JS_STATIC_ASSERT(JSVAL_NULL == 0); - static JSBool -array_sort(JSContext *cx, uintN argc, jsval *vp) +array_sort(JSContext *cx, uintN argc, Value *vp) { - jsval fval; jsuint len, newlen, i, undefs; size_t elemsize; JSString *str; - jsval *argv = JS_ARGV(cx, vp); + Value *argv = JS_ARGV(cx, vp); + Value fval; if (argc > 0) { - if (JSVAL_IS_PRIMITIVE(argv[0])) { + if (argv[0].isPrimitive()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_SORT_ARG); return false; } fval = argv[0]; /* non-default compare function */ } else { - fval = JSVAL_NULL; + fval.setNull(); } - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &len)) return false; if (len == 0) { - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); return true; } /* - * We need a temporary array of 2 * len jsvals to hold the array elements + * We need a temporary array of 2 * len Value to hold the array elements * and the scratch space for merge sort. Check that its size does not * overflow size_t, which would allow for indexing beyond the end of the * malloc'd vector. */ #if JS_BITS_PER_WORD == 32 - if (size_t(len) > size_t(-1) / (2 * sizeof(jsval))) { + if (size_t(len) > size_t(-1) / (2 * sizeof(Value))) { js_ReportAllocationOverflow(cx); return false; } @@ -1938,21 +1856,20 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * In this way when sorting a huge mostly sparse array we will not * access the tail of vec corresponding to properties that do not * exist, allowing OS to avoiding committing RAM. See bug 330812. - * - * After this point control must flow through label out: to exit. */ { - jsval *vec = (jsval *) cx->malloc(2 * size_t(len) * sizeof(jsval)); + Value *vec = (Value *) cx->malloc(2 * size_t(len) * sizeof(Value)); if (!vec) return false; - struct AutoFreeVector { - AutoFreeVector(JSContext *cx, jsval *&vec) : cx(cx), vec(vec) { } + DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(AutoFreeVector) { + JSContext *const cx; + Value *&vec; + public: + AutoFreeVector(JSContext *cx, Value *&vec) : cx(cx), vec(vec) { } ~AutoFreeVector() { cx->free(vec); } - JSContext * const cx; - jsval *&vec; } free(cx, vec); AutoArrayRooter tvr(cx, 0, vec); @@ -1974,7 +1891,7 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) /* Clear vec[newlen] before including it in the rooted set. */ JSBool hole; - vec[newlen] = JSVAL_NULL; + vec[newlen].setNull(); tvr.changeLength(newlen + 1); if (!GetArrayElement(cx, obj, i, &hole, &vec[newlen])) return false; @@ -1982,12 +1899,12 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) if (hole) continue; - if (JSVAL_IS_VOID(vec[newlen])) { + if (vec[newlen].isUndefined()) { ++undefs; continue; } - allStrings = allStrings && JSVAL_IS_STRING(vec[newlen]); + allStrings = allStrings && vec[newlen].isString(); ++newlen; } @@ -1999,21 +1916,20 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * The first newlen elements of vec are copied from the array object * (above). The remaining newlen positions are used as GC-rooted scratch * space for mergesort. We must clear the space before including it to - * the root set covered by tvr.count. We assume JSVAL_NULL==0 to optimize - * initialization using memset. + * the root set covered by tvr.count. */ - jsval *mergesort_tmp = vec + newlen; - PodZero(mergesort_tmp, newlen); + Value *mergesort_tmp = vec + newlen; + MakeValueRangeGCSafe(mergesort_tmp, newlen); tvr.changeLength(newlen * 2); /* Here len == 2 * (newlen + undefs + number_of_holes). */ - if (fval == JSVAL_NULL) { + if (fval.isNull()) { /* * Sort using the default comparator converting all elements to * strings. */ if (allStrings) { - elemsize = sizeof(jsval); + elemsize = sizeof(Value); } else { /* * To avoid string conversion on each compare we do it only once @@ -2021,10 +1937,10 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * values to recover the sorting result. To reuse * sort_compare_strings we move the original values to the odd * indexes in vec, put the string conversion results in the even - * indexes and pass 2 * sizeof(jsval) as an element size to the + * indexes and pass 2 * sizeof(Value) as an element size to the * sorting function. In this way sort_compare_strings will only * see the string values when it casts the compare arguments as - * pointers to jsval. + * pointers to Value. * * This requires doubling the temporary storage including the * scratch space for the merge sort. Since vec already contains @@ -2034,7 +1950,7 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * the elements. */ #if JS_BITS_PER_WORD == 32 - if (size_t(newlen) > size_t(-1) / (4 * sizeof(jsval))) { + if (size_t(newlen) > size_t(-1) / (4 * sizeof(Value))) { js_ReportAllocationOverflow(cx); return false; } @@ -2051,27 +1967,30 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) --i; if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; - jsval v = vec[i]; + const Value &v = vec[i]; str = js_ValueToString(cx, v); if (!str) return false; - vec[2 * i] = STRING_TO_JSVAL(str); + // Copying v must come first, because the following line overwrites v + // when i == 0. vec[2 * i + 1] = v; + vec[2 * i].setString(str); } while (i != 0); JS_ASSERT(tvr.array == vec); - vec = (jsval *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(jsval)); + vec = (Value *) cx->realloc(vec, 4 * size_t(newlen) * sizeof(Value)); if (!vec) { - vec = tvr.array; + vec = tvr.array; /* N.B. AutoFreeVector */ return false; } mergesort_tmp = vec + 2 * newlen; - PodZero(mergesort_tmp, newlen * 2); + MakeValueRangeGCSafe(mergesort_tmp, 2 * newlen); tvr.changeArray(vec, newlen * 4); - elemsize = 2 * sizeof(jsval); + elemsize = 2 * sizeof(Value); } if (!js_MergeSort(vec, size_t(newlen), elemsize, - sort_compare_strings, cx, mergesort_tmp)) { + sort_compare_strings, cx, mergesort_tmp, + JS_SORTING_GENERIC)) { return false; } if (!allStrings) { @@ -2093,9 +2012,10 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) if (!cx->stack().pushInvokeArgs(cx, 2, ca.args)) return false; - if (!js_MergeSort(vec, size_t(newlen), sizeof(jsval), + if (!js_MergeSort(vec, size_t(newlen), sizeof(Value), comparator_stack_cast(sort_compare), - &ca, mergesort_tmp)) { + &ca, mergesort_tmp, + JS_SORTING_VALUES)) { return false; } } @@ -2115,8 +2035,10 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) /* Set undefs that sorted after the rest of elements. */ while (undefs != 0) { --undefs; - if (!JS_CHECK_OPERATION_LIMIT(cx) || !SetArrayElement(cx, obj, newlen++, JSVAL_VOID)) + if (!JS_CHECK_OPERATION_LIMIT(cx) || + !SetArrayElement(cx, obj, newlen++, UndefinedValue())) { return false; + } } /* Re-create any holes that sorted to the end of the array. */ @@ -2124,7 +2046,7 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, --len)) return JS_FALSE; } - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); return true; } @@ -2132,7 +2054,7 @@ array_sort(JSContext *cx, uintN argc, jsval *vp) * Perl-inspired push, pop, shift, unshift, and splice methods. */ static JSBool -array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { jsuint length; @@ -2145,33 +2067,34 @@ array_push_slowly(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval * /* Per ECMA-262, return the new array length. */ jsdouble newlength = length + jsdouble(argc); - if (!IndexToValue(cx, newlength, rval)) - return JS_FALSE; + rval->setNumber(newlength); return js_SetLengthProperty(cx, obj, newlength); } static JSBool -array_push1_dense(JSContext* cx, JSObject* obj, jsval v, jsval *rval) +array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval) { uint32 length = obj->getArrayLength(); if (INDEX_TOO_SPARSE(obj, length)) { if (!obj->makeDenseArraySlow(cx)) return JS_FALSE; - return array_push_slowly(cx, obj, 1, &v, rval); + Value tmp = v; + return array_push_slowly(cx, obj, 1, &tmp, rval); } if (!obj->ensureDenseArrayElements(cx, length + 1)) return JS_FALSE; obj->setDenseArrayLength(length + 1); - JS_ASSERT(obj->getDenseArrayElement(length) == JSVAL_HOLE); + JS_ASSERT(obj->getDenseArrayElement(length).isMagic(JS_ARRAY_HOLE)); obj->incDenseArrayCountBy(1); obj->setDenseArrayElement(length, v); - return IndexToValue(cx, obj->getArrayLength(), rval); + rval->setNumber(obj->getArrayLength()); + return JS_TRUE; } -JSBool JS_FASTCALL -js_ArrayCompPush(JSContext *cx, JSObject *obj, jsval v) +JS_ALWAYS_INLINE JSBool +ArrayCompPushImpl(JSContext *cx, JSObject *obj, const Value &v) { JS_ASSERT(obj->isDenseArray()); uint32_t length = obj->getArrayLength(); @@ -2192,16 +2115,26 @@ js_ArrayCompPush(JSContext *cx, JSObject *obj, jsval v) obj->setDenseArrayElement(length, v); return JS_TRUE; } -JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush, CONTEXT, OBJECT, JSVAL, 0, + +JSBool +js_ArrayCompPush(JSContext *cx, JSObject *obj, const Value &vp) +{ + return ArrayCompPushImpl(cx, obj, vp); +} + +JSBool JS_FASTCALL +js_ArrayCompPush_tn(JSContext *cx, JSObject *obj, ValueArgType v) +{ + return ArrayCompPushImpl(cx, obj, ValueArgToConstRef(v)); +} +JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush_tn, CONTEXT, OBJECT, VALUE, 0, nanojit::ACC_STORE_ANY) static JSBool -array_push(JSContext *cx, uintN argc, jsval *vp) +array_push(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - /* Insist on one argument and obj of the expected class. */ - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return JS_FALSE; if (argc != 1 || !obj->isDenseArray()) @@ -2211,7 +2144,7 @@ array_push(JSContext *cx, uintN argc, jsval *vp) } static JSBool -array_pop_slowly(JSContext *cx, JSObject* obj, jsval *vp) +array_pop_slowly(JSContext *cx, JSObject* obj, Value *vp) { jsuint index; JSBool hole; @@ -2219,7 +2152,7 @@ array_pop_slowly(JSContext *cx, JSObject* obj, jsval *vp) if (!js_GetLengthProperty(cx, obj, &index)) return JS_FALSE; if (index == 0) { - *vp = JSVAL_VOID; + vp->setUndefined(); } else { index--; @@ -2233,14 +2166,14 @@ array_pop_slowly(JSContext *cx, JSObject* obj, jsval *vp) } static JSBool -array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp) +array_pop_dense(JSContext *cx, JSObject* obj, Value *vp) { jsuint index; JSBool hole; index = obj->getArrayLength(); if (index == 0) { - *vp = JSVAL_VOID; + vp->setUndefined(); return JS_TRUE; } index--; @@ -2253,11 +2186,9 @@ array_pop_dense(JSContext *cx, JSObject* obj, jsval *vp) } static JSBool -array_pop(JSContext *cx, uintN argc, jsval *vp) +array_pop(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return JS_FALSE; if (obj->isDenseArray()) @@ -2266,31 +2197,30 @@ array_pop(JSContext *cx, uintN argc, jsval *vp) } static JSBool -array_shift(JSContext *cx, uintN argc, jsval *vp) +array_shift(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; jsuint length, i; JSBool hole; - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; if (length == 0) { - *vp = JSVAL_VOID; + vp->setUndefined(); } else { length--; if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) && length < obj->getDenseArrayCapacity()) { *vp = obj->getDenseArrayElement(0); - if (*vp == JSVAL_HOLE) - *vp = JSVAL_VOID; + if (vp->isMagic(JS_ARRAY_HOLE)) + vp->setUndefined(); else obj->decDenseArrayCountBy(1); - jsval *elems = obj->getDenseArrayElements(); + Value *elems = obj->getDenseArrayElements(); memmove(elems, elems + 1, length * sizeof(jsval)); - obj->setDenseArrayElement(length, JSVAL_HOLE); + obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE)); obj->setDenseArrayLength(length); return JS_TRUE; } @@ -2317,15 +2247,14 @@ array_shift(JSContext *cx, uintN argc, jsval *vp) } static JSBool -array_unshift(JSContext *cx, uintN argc, jsval *vp) +array_unshift(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - jsval *argv; + Value *argv; jsuint length; JSBool hole; jsdouble last, newlen; - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; newlen = length; @@ -2338,10 +2267,10 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp) JS_ASSERT(newlen + argc == length + argc); if (!obj->ensureDenseArrayElements(cx, length + argc)) return JS_FALSE; - jsval *elems = obj->getDenseArrayElements(); + Value *elems = obj->getDenseArrayElements(); memmove(elems + argc, elems, length * sizeof(jsval)); for (uint32 i = 0; i < argc; i++) - obj->setDenseArrayElement(i, JSVAL_HOLE); + obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE)); } else { last = length; jsdouble upperIndex = last + argc; @@ -2367,17 +2296,15 @@ array_unshift(JSContext *cx, uintN argc, jsval *vp) } /* Follow Perl by returning the new array length. */ - return IndexToValue(cx, newlen, vp); + vp->setNumber(newlen); + return JS_TRUE; } static JSBool -array_splice(JSContext *cx, uintN argc, jsval *vp) +array_splice(JSContext *cx, uintN argc, Value *vp) { - jsval *argv; - JSObject *obj; jsuint length, begin, end, count, delta, last; JSBool hole; - JSObject *obj2; /* * Create a new array value to return. Our ECMA v2 proposal specs @@ -2385,16 +2312,16 @@ array_splice(JSContext *cx, uintN argc, jsval *vp) * arguments. We think this is best because it eliminates the need * for callers to do an extra test to handle the empty splice case. */ - obj2 = js_NewArrayObject(cx, 0, NULL); + JSObject *obj2 = js_NewArrayObject(cx, 0, NULL); if (!obj2) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(obj2); + vp->setObject(*obj2); /* Nothing to do if no args. Otherwise get length. */ if (argc == 0) return JS_TRUE; - argv = JS_ARGV(cx, vp); - obj = JS_THIS_OBJECT(cx, vp); + Value *argv = JS_ARGV(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; @@ -2433,7 +2360,7 @@ array_splice(JSContext *cx, uintN argc, jsval *vp) argv++; } - AutoValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); /* If there are elements to remove, put them into the return value. */ if (count > 0) { @@ -2467,14 +2394,14 @@ array_splice(JSContext *cx, uintN argc, jsval *vp) last = length; if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) && length <= obj->getDenseArrayCapacity() && - (length == 0 || obj->getDenseArrayElement(length - 1) != JSVAL_HOLE)) { + (length == 0 || !obj->getDenseArrayElement(length - 1).isMagic(JS_ARRAY_HOLE))) { if (!obj->ensureDenseArrayElements(cx, length + delta)) return JS_FALSE; /* (uint) end could be 0, so we can't use a vanilla >= test. */ while (last-- > end) { - jsval srcval = obj->getDenseArrayElement(last); - jsval dest = obj->getDenseArrayElement(last + delta); - if (dest == JSVAL_HOLE && srcval != JSVAL_HOLE) + const Value &srcval = obj->getDenseArrayElement(last); + const Value &dest = obj->getDenseArrayElement(last + delta); + if (dest.isMagic(JS_ARRAY_HOLE) && !srcval.isMagic(JS_ARRAY_HOLE)) obj->incDenseArrayCountBy(1); obj->setDenseArrayElement(last + delta, srcval); } @@ -2496,9 +2423,9 @@ array_splice(JSContext *cx, uintN argc, jsval *vp) length <= obj->getDenseArrayCapacity()) { /* (uint) end could be 0, so we can't use a vanilla >= test. */ for (last = end; last < length; last++) { - jsval srcval = obj->getDenseArrayElement(last); - jsval dest = obj->getDenseArrayElement(last - delta); - if (dest == JSVAL_HOLE && srcval != JSVAL_HOLE) + const Value &srcval = obj->getDenseArrayElement(last); + const Value &dest = obj->getDenseArrayElement(last - delta); + if (dest.isMagic(JS_ARRAY_HOLE) && !srcval.isMagic(JS_ARRAY_HOLE)) obj->incDenseArrayCountBy(1); obj->setDenseArrayElement(last - delta, srcval); } @@ -2527,20 +2454,15 @@ array_splice(JSContext *cx, uintN argc, jsval *vp) * Python-esque sequence operations. */ static JSBool -array_concat(JSContext *cx, uintN argc, jsval *vp) +array_concat(JSContext *cx, uintN argc, Value *vp) { - jsval *argv, v; - JSObject *aobj, *nobj; - jsuint length, alength, slot; - uintN i; - JSBool hole; - /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */ - argv = JS_ARGV(cx, vp) - 1; - JS_ASSERT(JS_THIS_OBJECT(cx, vp) == JSVAL_TO_OBJECT(argv[0])); + Value *p = JS_ARGV(cx, vp) - 1; /* Create a new Array object and root it using *vp. */ - aobj = JS_THIS_OBJECT(cx, vp); + JSObject *aobj = ComputeThisFromVp(cx, vp); + JSObject *nobj; + jsuint length; if (aobj->isDenseArray()) { /* * Clone aobj but pass the minimum of its length and capacity, to @@ -2557,39 +2479,40 @@ array_concat(JSContext *cx, uintN argc, jsval *vp) if (!nobj) return JS_FALSE; nobj->setDenseArrayLength(length); - *vp = OBJECT_TO_JSVAL(nobj); + vp->setObject(*nobj); if (argc == 0) return JS_TRUE; argc--; - argv++; + p++; } else { nobj = js_NewArrayObject(cx, 0, NULL); if (!nobj) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(nobj); + vp->setObject(*nobj); length = 0; } - AutoValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */ - for (i = 0; i <= argc; i++) { + for (uintN i = 0; i <= argc; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx)) return false; - v = argv[i]; - if (!JSVAL_IS_PRIMITIVE(v)) { + const Value &v = p[i]; + if (v.isObject()) { JSObject *wobj; - aobj = JSVAL_TO_OBJECT(v); + aobj = &v.toObject(); wobj = aobj->wrappedObject(cx); if (wobj->isArray()) { jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); if (!aobj->getProperty(cx, id, tvr.addr())) return false; - alength = ValueIsLength(cx, tvr.addr()); - if (JSVAL_IS_NULL(tvr.value())) + jsuint alength = ValueIsLength(cx, tvr.addr()); + if (tvr.value().isNull()) return false; - for (slot = 0; slot < alength; slot++) { + for (jsuint slot = 0; slot < alength; slot++) { + JSBool hole; if (!JS_CHECK_OPERATION_LIMIT(cx) || !GetArrayElement(cx, aobj, slot, &hole, tvr.addr())) { return false; @@ -2618,16 +2541,16 @@ array_concat(JSContext *cx, uintN argc, jsval *vp) } static JSBool -array_slice(JSContext *cx, uintN argc, jsval *vp) +array_slice(JSContext *cx, uintN argc, Value *vp) { - jsval *argv; - JSObject *nobj, *obj; + Value *argv; + JSObject *nobj; jsuint length, begin, end, slot; JSBool hole; argv = JS_ARGV(cx, vp); - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; begin = 0; @@ -2671,7 +2594,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp) obj->getDenseArrayCount() != obj->getArrayLength()); if (!nobj) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(nobj); + vp->setObject(*nobj); return JS_TRUE; } @@ -2679,7 +2602,7 @@ array_slice(JSContext *cx, uintN argc, jsval *vp) nobj = js_NewArrayObject(cx, 0, NULL); if (!nobj) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(nobj); + vp->setObject(*nobj); AutoValueRooter tvr(cx); for (slot = begin; slot < end; slot++) { @@ -2697,15 +2620,14 @@ array_slice(JSContext *cx, uintN argc, jsval *vp) #if JS_HAS_ARRAY_EXTRAS static JSBool -array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, jsval *vp) +array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, Value *vp) { - JSObject *obj; jsuint length, i, stop; - jsval tosearch; + Value tosearch; jsint direction; JSBool hole; - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj || !js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; if (length == 0) @@ -2713,7 +2635,7 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, jsval *vp) if (argc <= 1) { i = isLast ? length - 1 : 0; - tosearch = (argc != 0) ? vp[2] : JSVAL_VOID; + tosearch = (argc != 0) ? vp[2] : UndefinedValue(); } else { jsdouble start; @@ -2752,26 +2674,28 @@ array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, jsval *vp) !GetArrayElement(cx, obj, (jsuint)i, &hole, vp)) { return JS_FALSE; } - if (!hole && js_StrictlyEqual(cx, *vp, tosearch)) - return js_NewNumberInRootedValue(cx, i, vp); + if (!hole && StrictlyEqual(cx, *vp, tosearch)) { + vp->setNumber(i); + return JS_TRUE; + } if (i == stop) goto not_found; i += direction; } not_found: - *vp = INT_TO_JSVAL(-1); + vp->setInt32(-1); return JS_TRUE; } static JSBool -array_indexOf(JSContext *cx, uintN argc, jsval *vp) +array_indexOf(JSContext *cx, uintN argc, Value *vp) { return array_indexOfHelper(cx, JS_FALSE, argc, vp); } static JSBool -array_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) +array_lastIndexOf(JSContext *cx, uintN argc, Value *vp) { return array_indexOfHelper(cx, JS_TRUE, argc, vp); } @@ -2790,9 +2714,9 @@ typedef enum ArrayExtraMode { #define REDUCE_MODE(mode) ((mode) == REDUCE || (mode) == REDUCE_RIGHT) static JSBool -array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) +array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, Value *vp) { - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); jsuint length; if (!obj || !js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; @@ -2802,10 +2726,10 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) * when passed a non-callable object. */ if (argc == 0) { - js_ReportMissingArg(cx, vp, 0); + js_ReportMissingArg(cx, *vp, 0); return JS_FALSE; } - jsval *argv = vp + 2; + Value *argv = vp + 2; JSObject *callable = js_ValueToCallableObject(cx, &argv[0], JSV2F_SEARCH_STACK); if (!callable) return JS_FALSE; @@ -2855,16 +2779,16 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) newarr = js_NewArrayObject(cx, newlen, NULL); if (!newarr) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(newarr); + vp->setObject(*newarr); break; case SOME: - *vp = JSVAL_FALSE; + vp->setBoolean(false); break; case EVERY: - *vp = JSVAL_TRUE; + vp->setBoolean(true); break; case FOREACH: - *vp = JSVAL_VOID; + vp->setUndefined(); break; } @@ -2873,9 +2797,9 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) JSObject *thisp; if (argc > 1 && !REDUCE_MODE(mode)) { - if (!js_ValueToObject(cx, argv[1], &thisp)) + if (!js_ValueToObjectOrNull(cx, argv[1], &thisp)) return JS_FALSE; - argv[1] = OBJECT_TO_JSVAL(thisp); + argv[1].setObjectOrNull(thisp); } else { thisp = NULL; } @@ -2894,8 +2818,12 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) MUST_FLOW_THROUGH("out"); JSBool ok = JS_TRUE; JSBool cond; - jsval *invokevp = args.getvp(); + Value *invokevp = args.getvp(); + Value calleev, thisv, objv; + calleev.setObject(*callable); + thisv.setObjectOrNull(thisp); + objv.setObject(*obj); AutoValueRooter tvr(cx); for (jsint i = start; i != end; i += step) { JSBool hole; @@ -2912,17 +2840,17 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) * value storage, while some native functions use invokevp[1] for local * rooting. */ - jsval *sp = invokevp; - *sp++ = OBJECT_TO_JSVAL(callable); - *sp++ = OBJECT_TO_JSVAL(thisp); + Value *sp = invokevp; + *sp++ = calleev; + *sp++ = thisv; if (REDUCE_MODE(mode)) *sp++ = *vp; *sp++ = tvr.value(); - *sp++ = INT_TO_JSVAL(i); - *sp++ = OBJECT_TO_JSVAL(obj); + sp++->setInt32(i); + *sp++ = objv; /* Do the call. */ - ok = js_Invoke(cx, args, 0); + ok = Invoke(cx, args, 0); if (!ok) break; @@ -2955,13 +2883,13 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) break; case SOME: if (cond) { - *vp = JSVAL_TRUE; + vp->setBoolean(true); goto out; } break; case EVERY: if (!cond) { - *vp = JSVAL_FALSE; + vp->setBoolean(false); goto out; } break; @@ -2975,43 +2903,43 @@ array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) } static JSBool -array_forEach(JSContext *cx, uintN argc, jsval *vp) +array_forEach(JSContext *cx, uintN argc, Value *vp) { return array_extra(cx, FOREACH, argc, vp); } static JSBool -array_map(JSContext *cx, uintN argc, jsval *vp) +array_map(JSContext *cx, uintN argc, Value *vp) { return array_extra(cx, MAP, argc, vp); } static JSBool -array_reduce(JSContext *cx, uintN argc, jsval *vp) +array_reduce(JSContext *cx, uintN argc, Value *vp) { return array_extra(cx, REDUCE, argc, vp); } static JSBool -array_reduceRight(JSContext *cx, uintN argc, jsval *vp) +array_reduceRight(JSContext *cx, uintN argc, Value *vp) { return array_extra(cx, REDUCE_RIGHT, argc, vp); } static JSBool -array_filter(JSContext *cx, uintN argc, jsval *vp) +array_filter(JSContext *cx, uintN argc, Value *vp) { return array_extra(cx, FILTER, argc, vp); } static JSBool -array_some(JSContext *cx, uintN argc, jsval *vp) +array_some(JSContext *cx, uintN argc, Value *vp) { return array_extra(cx, SOME, argc, vp); } static JSBool -array_every(JSContext *cx, uintN argc, jsval *vp) +array_every(JSContext *cx, uintN argc, Value *vp) { return array_extra(cx, EVERY, argc, vp); } @@ -3074,17 +3002,17 @@ NewDenseArrayObject(JSContext *cx) } JSBool -js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +js_Array(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { jsuint length; - const jsval *vector; + const Value *vector; /* If called without new, replace obj with a new Array object. */ if (!JS_IsConstructing(cx)) { obj = NewDenseArrayObject(cx); if (!obj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); } if (argc == 0) { @@ -3093,12 +3021,12 @@ js_Array(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } else if (argc > 1) { length = (jsuint) argc; vector = argv; - } else if (!JSVAL_IS_NUMBER(argv[0])) { + } else if (!argv[0].isNumber()) { length = 1; vector = argv; } else { length = ValueIsLength(cx, &argv[0]); - if (JSVAL_IS_NULL(argv[0])) + if (argv[0].isNull()) return JS_FALSE; vector = NULL; } @@ -3117,7 +3045,7 @@ js_NewEmptyArray(JSContext* cx, JSObject* proto) /* Initialize all fields of JSObject. */ obj->map = const_cast(&SharedArrayMap); - obj->init(&js_ArrayClass, proto, proto->getParent(), JSVAL_NULL); + obj->init(&js_ArrayClass, proto, proto->getParent(), NullValue()); obj->setDenseArrayLength(0); obj->setDenseArrayCount(0); return obj; @@ -3161,7 +3089,7 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewArrayWithSlots, CONTEXT, OBJECT, UINT JSObject * js_InitArrayClass(JSContext *cx, JSObject *obj) { - JSObject *proto = JS_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1, + JSObject *proto = js_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1, NULL, array_methods, NULL, array_static_methods); /* Initialize the Array prototype object so it gets a length property. */ @@ -3171,7 +3099,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj) } JSObject * -js_NewArrayObject(JSContext *cx, jsuint length, const jsval *vector, bool holey) +js_NewArrayObject(JSContext *cx, jsuint length, const Value *vector, bool holey) { JSObject *obj = NewDenseArrayObject(cx); if (!obj) @@ -3184,7 +3112,7 @@ js_NewArrayObject(JSContext *cx, jsuint length, const jsval *vector, bool holey) JS_ASSERT(obj->getProto()); { - AutoValueRooter tvr(cx, obj); + AutoObjectRooter tvr(cx, obj); if (!InitArrayObject(cx, obj, length, vector, holey)) obj = NULL; } @@ -3205,7 +3133,7 @@ js_NewSlowArrayObject(JSContext *cx) #ifdef DEBUG_ARRAYS JSBool -js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { uintN i; JSObject *array; @@ -3213,8 +3141,7 @@ js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) for (i = 0; i < argc; i++) { char *bytes; - bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, argv[i], - NULL); + bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, argv[i], NULL); if (!bytes) return JS_FALSE; if (JSVAL_IS_PRIMITIVE(argv[i]) || @@ -3253,14 +3180,14 @@ js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count, JSUint8 *dp = dest; for (uintN i = offset; i < offset+count; i++) { - jsval v = obj->getDenseArrayElement(i); - if (JSVAL_IS_INT(v)) { - jsint vi = JSVAL_TO_INT(v); + const Value &v = obj->getDenseArrayElement(i); + if (v.isInt32()) { + jsint vi = v.toInt32(); if (jsuint(vi) > 255) vi = (vi < 0) ? 0 : 255; *dp++ = JSUint8(vi); - } else if (JSVAL_IS_DOUBLE(v)) { - jsdouble vd = *JSVAL_TO_DOUBLE(v); + } else if (v.isDouble()) { + jsdouble vd = v.toDouble(); if (!(vd >= 0)) /* Not < so that NaN coerces to 0 */ *dp++ = 0; else if (vd > 255) @@ -3297,13 +3224,13 @@ js_CoerceArrayToCanvasImageData(JSObject *obj, jsuint offset, jsuint count, } JS_FRIEND_API(JSObject *) -js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector) +js_NewArrayObjectWithCapacity(JSContext *cx, uint32_t capacity, jsval **vector) { JSObject *obj = js_NewArrayObject(cx, capacity, NULL); if (!obj) return NULL; - AutoValueRooter tvr(cx, obj); + AutoObjectRooter tvr(cx, obj); if (!obj->ensureDenseArrayElements(cx, capacity, JS_FALSE)) obj = NULL; @@ -3313,7 +3240,7 @@ js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector) return NULL; obj->setDenseArrayCount(capacity); - *vector = obj->getDenseArrayElements(); + *vector = Jsvalify(obj->getDenseArrayElements()); return obj; } @@ -3325,7 +3252,7 @@ js_IsDensePrimitiveArray(JSObject *obj) jsuint length = obj->getArrayLength(); for (jsuint i = 0; i < length; i++) { - if (!JSVAL_IS_PRIMITIVE(obj->dslots[i])) + if (obj->dslots[i].isObject()) return JS_FALSE; } @@ -3363,15 +3290,15 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone) jsuint holeCount = 0; for (jsuint i = 0; i < jsvalCount; i++) { - jsval &val = obj->dslots[i]; + const Value &val = obj->dslots[i]; - if (JSVAL_IS_STRING(val)) { + if (val.isString()) { // Strings must be made immutable before being copied to a clone. - if (!js_MakeStringImmutable(cx, JSVAL_TO_STRING(val))) + if (!js_MakeStringImmutable(cx, val.toString())) return JS_FALSE; - } else if (val == JSVAL_HOLE) { + } else if (val.isMagic(JS_ARRAY_HOLE)) { holeCount++; - } else if (!JSVAL_IS_PRIMITIVE(val)) { + } else if (val.isObject()) { /* * This wasn't an array of primitives. Return JS_TRUE but a null * clone to signal that no exception was encountered. diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 4c9234d5de9b..6658b61a0692 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -46,14 +46,49 @@ #include "jspubtd.h" #include "jsobj.h" -JS_BEGIN_EXTERN_C - #define ARRAY_CAPACITY_MIN 7 extern JSBool -js_IdIsIndex(jsval id, jsuint *indexp); +js_StringIsIndex(JSString *str, jsuint *indexp); -extern JSClass js_ArrayClass, js_SlowArrayClass; +inline JSBool +js_IdIsIndex(jsid id, jsuint *indexp) +{ + if (JSID_IS_INT(id)) { + jsint i; + i = JSID_TO_INT(id); + if (i < 0) + return JS_FALSE; + *indexp = (jsuint)i; + return JS_TRUE; + } + + if (JS_UNLIKELY(!JSID_IS_STRING(id))) + return JS_FALSE; + + return js_StringIsIndex(JSID_TO_STRING(id), indexp); +} + +/* XML really wants to pretend jsvals are jsids. */ +inline JSBool +js_IdValIsIndex(jsval id, jsuint *indexp) +{ + if (JSVAL_IS_INT(id)) { + jsint i; + i = JSVAL_TO_INT(id); + if (i < 0) + return JS_FALSE; + *indexp = (jsuint)i; + return JS_TRUE; + } + + if (!JSVAL_IS_STRING(id)) + return JS_FALSE; + + return js_StringIsIndex(JSVAL_TO_STRING(id), indexp); +} + +extern js::Class js_ArrayClass, js_SlowArrayClass; inline bool JSObject::isDenseArray() const @@ -112,7 +147,7 @@ extern JSObject * JS_FASTCALL js_NewArrayWithSlots(JSContext* cx, JSObject* proto, uint32 len); extern JSObject * -js_NewArrayObject(JSContext *cx, jsuint length, const jsval *vector, bool holey = false); +js_NewArrayObject(JSContext *cx, jsuint length, const js::Value *vector, bool holey = false); /* Create an array object that starts out already made slow/sparse. */ extern JSObject * @@ -145,25 +180,33 @@ js_IsArrayLike(JSContext *cx, JSObject *obj, JSBool *answerp, jsuint *lengthp); */ typedef JSBool (*JSComparator)(void *arg, const void *a, const void *b, int *result); + +enum JSMergeSortElemType { + JS_SORTING_VALUES, + JS_SORTING_GENERIC +}; + /* * NB: vec is the array to be sorted, tmp is temporary space at least as big * as vec. Both should be GC-rooted if appropriate. * + * isValue should true iff vec points to an array of js::Value + * * The sorted result is in vec. vec may be in an inconsistent state if the * comparator function cmp returns an error inside a comparison, so remember * to check the return value of this function. */ -extern JSBool +extern bool js_MergeSort(void *vec, size_t nel, size_t elsize, JSComparator cmp, - void *arg, void *tmp); + void *arg, void *tmp, JSMergeSortElemType elemType); #ifdef DEBUG_ARRAYS extern JSBool -js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +js_ArrayInfo(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv, js::Value *rval); #endif -extern JSBool JS_FASTCALL -js_ArrayCompPush(JSContext *cx, JSObject *obj, jsval v); +extern JSBool +js_ArrayCompPush(JSContext *cx, JSObject *obj, const js::Value &vp); /* * Fast dense-array-to-buffer conversion for use by canvas. @@ -192,12 +235,12 @@ js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj); * Utility to access the value from the id returned by array_lookupProperty. */ JSBool -js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, JSProperty *prop, - jsval *vp); +js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, jsid id, + js::Value *vp); /* Array constructor native. Exposed only so the JIT can know its address. */ JSBool -js_Array(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); +js_Array(JSContext* cx, JSObject* obj, uintN argc, js::Value* argv, js::Value* rval); /* * Friend api function that allows direct creation of an array object with a @@ -209,9 +252,14 @@ js_Array(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval); * without triggering GC (so this method is allowed to leave those * uninitialized) and to set them to non-JSVAL_HOLE values, so that the * resulting array has length and count both equal to |capacity|. + * + * FIXME: for some strange reason, when this file is included from + * dom/ipc/TabParent.cpp in MSVC, jsuint resolves to a slightly different + * builtin than when mozjs.dll is built, resulting in a link error in xul.dll. + * It would be useful to find out what is causing this insanity. */ JS_FRIEND_API(JSObject *) -js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector); +js_NewArrayObjectWithCapacity(JSContext *cx, uint32_t capacity, jsval **vector); /* * Makes a fast clone of a dense array as long as the array only contains @@ -233,6 +281,4 @@ js_CloneDensePrimitiveArray(JSContext *cx, JSObject *obj, JSObject **clone); JS_FRIEND_API(JSBool) js_IsDensePrimitiveArray(JSObject *obj); -JS_END_EXTERN_C - #endif /* jsarray_h___ */ diff --git a/js/src/jsatom.cpp b/js/src/jsatom.cpp index d3c966022e31..7c3ffb196338 100644 --- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -58,7 +58,13 @@ #include "jsscan.h" #include "jsstr.h" #include "jsversion.h" +#include "jsxml.h" + #include "jsstrinlines.h" +#include "jsatominlines.h" +#include "jsobjinlines.h" + +using namespace js; using namespace js; @@ -87,7 +93,7 @@ JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) == const char * js_AtomToPrintableString(JSContext *cx, JSAtom *atom) { - return js_ValueToPrintableString(cx, ATOM_KEY(atom)); + return js_ValueToPrintableString(cx, StringValue(ATOM_TO_STRING(atom))); } #define JS_PROTO(name,code,init) const char js_##name##_str[] = #name; @@ -292,9 +298,9 @@ const char js_current_str[] = "current"; #endif /* - * JSAtomState.doubleAtoms and JSAtomState.stringAtoms hashtable entry. To - * support pinned and interned string atoms, we use the lowest bits of the - * keyAndFlags field to store ATOM_PINNED and ATOM_INTERNED flags. + * JSAtomState.stringAtoms hashtable entry. To support pinned and interned + * string atoms, we use the lowest bits of the keyAndFlags field to store + * ATOM_PINNED and ATOM_INTERNED flags. */ typedef struct JSAtomHashEntry { JSDHashEntryHdr hdr; @@ -303,14 +309,14 @@ typedef struct JSAtomHashEntry { #define ATOM_ENTRY_FLAG_MASK (ATOM_PINNED | ATOM_INTERNED) -JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JSVAL_ALIGN); +JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JS_GCTHING_ALIGN); /* * Helper macros to access and modify JSAtomHashEntry. */ #define TO_ATOM_ENTRY(hdr) ((JSAtomHashEntry *) hdr) #define ATOM_ENTRY_KEY(entry) \ - ((void *)((entry)->keyAndFlags & ~ATOM_ENTRY_FLAG_MASK)) + ((JSString *)((entry)->keyAndFlags & ~ATOM_ENTRY_FLAG_MASK)) #define ATOM_ENTRY_FLAGS(entry) \ ((uintN)((entry)->keyAndFlags & ATOM_ENTRY_FLAG_MASK)) #define INIT_ATOM_ENTRY(entry, key) \ @@ -320,29 +326,12 @@ JS_STATIC_ASSERT(ATOM_ENTRY_FLAG_MASK < JSVAL_ALIGN); #define CLEAR_ATOM_ENTRY_FLAGS(entry, flags) \ ((void)((entry)->keyAndFlags &= ~(jsuword)(flags))) -static JSDHashNumber -HashDouble(JSDHashTable *table, const void *key); - -static JSBool -MatchDouble(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key); - static JSDHashNumber HashString(JSDHashTable *table, const void *key); static JSBool MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key); -static const JSDHashTableOps DoubleHashOps = { - JS_DHashAllocTable, - JS_DHashFreeTable, - HashDouble, - MatchDouble, - JS_DHashMoveEntryStub, - JS_DHashClearEntryStub, - JS_DHashFinalizeStub, - NULL -}; - static const JSDHashTableOps StringHashOps = { JS_DHashAllocTable, JS_DHashFreeTable, @@ -354,55 +343,19 @@ static const JSDHashTableOps StringHashOps = { NULL }; -#define IS_DOUBLE_TABLE(table) ((table)->ops == &DoubleHashOps) -#define IS_STRING_TABLE(table) ((table)->ops == &StringHashOps) - -#define IS_INITIALIZED_STATE(state) IS_DOUBLE_TABLE(&(state)->doubleAtoms) - -static JSDHashNumber -HashDouble(JSDHashTable *table, const void *key) -{ - JS_ASSERT(IS_DOUBLE_TABLE(table)); - return JS_HASH_DOUBLE(*(jsdouble *)key); -} +#define IS_INITIALIZED_STATE(state) ((state)->stringAtoms.ops != NULL) static JSDHashNumber HashString(JSDHashTable *table, const void *key) { - JS_ASSERT(IS_STRING_TABLE(table)); return js_HashString((JSString *)key); } -static JSBool -MatchDouble(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key) -{ - JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); - jsdouble d1, d2; - - JS_ASSERT(IS_DOUBLE_TABLE(table)); - if (entry->keyAndFlags == 0) { - /* See comments in MatchString. */ - return JS_FALSE; - } - - d1 = *(jsdouble *)ATOM_ENTRY_KEY(entry); - d2 = *(jsdouble *)key; - if (JSDOUBLE_IS_NaN(d1)) - return JSDOUBLE_IS_NaN(d2); -#if defined(XP_WIN) - /* XXX MSVC miscompiles such that (NaN == 0) */ - if (JSDOUBLE_IS_NaN(d2)) - return JS_FALSE; -#endif - return d1 == d2; -} - static JSBool MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key) { JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); - JS_ASSERT(IS_STRING_TABLE(table)); if (entry->keyAndFlags == 0) { /* * This happens when js_AtomizeString adds a new hash entry and @@ -418,7 +371,7 @@ MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key) */ return JS_FALSE; } - return js_EqualStrings((JSString *)ATOM_ENTRY_KEY(entry), (JSString *)key); + return js_EqualStrings(ATOM_ENTRY_KEY(entry), (JSString *)key); } /* @@ -428,7 +381,6 @@ MatchString(JSDHashTable *table, const JSDHashEntryHdr *hdr, const void *key) * atomized strings with just 1K entries. */ #define JS_STRING_HASH_COUNT 1024 -#define JS_DOUBLE_HASH_COUNT 64 JSBool js_InitAtomState(JSRuntime *rt) @@ -439,7 +391,6 @@ js_InitAtomState(JSRuntime *rt) * The caller must zero the state before calling this function. */ JS_ASSERT(!state->stringAtoms.ops); - JS_ASSERT(!state->doubleAtoms.ops); if (!JS_DHashTableInit(&state->stringAtoms, &StringHashOps, NULL, sizeof(JSAtomHashEntry), @@ -447,17 +398,6 @@ js_InitAtomState(JSRuntime *rt) state->stringAtoms.ops = NULL; return JS_FALSE; } - JS_ASSERT(IS_STRING_TABLE(&state->stringAtoms)); - - if (!JS_DHashTableInit(&state->doubleAtoms, &DoubleHashOps, - NULL, sizeof(JSAtomHashEntry), - JS_DHASH_DEFAULT_CAPACITY(JS_DOUBLE_HASH_COUNT))) { - state->doubleAtoms.ops = NULL; - JS_DHashTableFinish(&state->stringAtoms); - state->stringAtoms.ops = NULL; - return JS_FALSE; - } - JS_ASSERT(IS_DOUBLE_TABLE(&state->doubleAtoms)); #ifdef JS_THREADSAFE js_InitLock(&state->lock); @@ -478,9 +418,8 @@ js_string_uninterner(JSDHashTable *table, JSDHashEntryHdr *hdr, * Any string entry that remains at this point must be initialized, as the * last GC should clean any uninitialized ones. */ - JS_ASSERT(IS_STRING_TABLE(table)); JS_ASSERT(entry->keyAndFlags != 0); - str = (JSString *)ATOM_ENTRY_KEY(entry); + str = ATOM_ENTRY_KEY(entry); js_FinalizeStringRT(rt, str); return JS_DHASH_NEXT; @@ -501,7 +440,6 @@ js_FinishAtomState(JSRuntime *rt) JS_DHashTableEnumerate(&state->stringAtoms, js_string_uninterner, rt); JS_DHashTableFinish(&state->stringAtoms); - JS_DHashTableFinish(&state->doubleAtoms); #ifdef JS_THREADSAFE js_FinishLock(&state->lock); @@ -536,7 +474,6 @@ static JSDHashOperator js_atom_unpinner(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, void *arg) { - JS_ASSERT(IS_STRING_TABLE(table)); CLEAR_ATOM_ENTRY_FLAGS(TO_ATOM_ENTRY(hdr), ATOM_PINNED); return JS_DHASH_NEXT; } @@ -565,8 +502,7 @@ js_locked_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr, return JS_DHASH_NEXT; } JS_SET_TRACING_INDEX(trc, "locked_atom", (size_t)number); - js_CallGCMarker(trc, ATOM_ENTRY_KEY(entry), - IS_STRING_TABLE(table) ? JSTRACE_STRING : JSTRACE_DOUBLE); + Mark(trc, ATOM_ENTRY_KEY(entry), JSTRACE_STRING); return JS_DHASH_NEXT; } @@ -578,14 +514,13 @@ js_pinned_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr, JSTracer *trc = (JSTracer *)arg; uintN flags = ATOM_ENTRY_FLAGS(entry); - JS_ASSERT(IS_STRING_TABLE(table)); if (flags & (ATOM_PINNED | ATOM_INTERNED)) { JS_SET_TRACING_INDEX(trc, flags & ATOM_PINNED ? "pinned_atom" : "interned_atom", (size_t)number); - js_CallGCMarker(trc, ATOM_ENTRY_KEY(entry), JSTRACE_STRING); + Mark(trc, ATOM_ENTRY_KEY(entry), JSTRACE_STRING); } return JS_DHASH_NEXT; } @@ -596,12 +531,10 @@ js_TraceAtomState(JSTracer *trc) JSRuntime *rt = trc->context->runtime; JSAtomState *state = &rt->atomState; - if (rt->gcKeepAtoms) { - JS_DHashTableEnumerate(&state->doubleAtoms, js_locked_atom_tracer, trc); + if (rt->gcKeepAtoms) JS_DHashTableEnumerate(&state->stringAtoms, js_locked_atom_tracer, trc); - } else { + else JS_DHashTableEnumerate(&state->stringAtoms, js_pinned_atom_tracer, trc); - } } static JSDHashOperator @@ -629,74 +562,19 @@ js_SweepAtomState(JSContext *cx) { JSAtomState *state = &cx->runtime->atomState; - JS_DHashTableEnumerate(&state->doubleAtoms, js_atom_sweeper, NULL); JS_DHashTableEnumerate(&state->stringAtoms, js_atom_sweeper, NULL); /* * Optimize for simplicity and mutate table generation numbers even if the * sweeper has not removed any entries. */ - state->doubleAtoms.generation++; state->stringAtoms.generation++; } -JSAtom * -js_AtomizeDouble(JSContext *cx, jsdouble d) -{ - JSAtomState *state; - JSDHashTable *table; - JSAtomHashEntry *entry; - uint32 gen; - jsdouble *key; - jsval v; - - state = &cx->runtime->atomState; - table = &state->doubleAtoms; - - JS_LOCK(cx, &state->lock); - entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, &d, JS_DHASH_ADD)); - if (!entry) - goto failed_hash_add; - if (entry->keyAndFlags == 0) { - gen = ++table->generation; - JS_UNLOCK(cx, &state->lock); - - key = js_NewWeaklyRootedDouble(cx, d); - if (!key) - return NULL; - - JS_LOCK(cx, &state->lock); - if (table->generation == gen) { - JS_ASSERT(entry->keyAndFlags == 0); - } else { - entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, key, - JS_DHASH_ADD)); - if (!entry) - goto failed_hash_add; - if (entry->keyAndFlags != 0) - goto finish; - ++table->generation; - } - INIT_ATOM_ENTRY(entry, key); - } - - finish: - v = DOUBLE_TO_JSVAL((jsdouble *)ATOM_ENTRY_KEY(entry)); - cx->weakRoots.lastAtom = v; - JS_UNLOCK(cx, &state->lock); - - return (JSAtom *)v; - - failed_hash_add: - JS_UNLOCK(cx, &state->lock); - JS_ReportOutOfMemory(cx); - return NULL; -} - JSAtom * js_AtomizeString(JSContext *cx, JSString *str, uintN flags) { - jsval v; + JSAtom *atom; JSAtomState *state; JSDHashTable *table; JSAtomHashEntry *entry; @@ -707,13 +585,13 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags) JS_ASSERT_IF(flags & ATOM_NOCOPY, flags & ATOM_TMPSTR); if (str->isAtomized()) - return (JSAtom *) STRING_TO_JSVAL(str); + return STRING_TO_ATOM(str); size_t length = str->length(); if (length == 1) { jschar c = str->chars()[0]; if (c < UNIT_STRING_LIMIT) - return (JSAtom *) STRING_TO_JSVAL(JSString::unitString(c)); + return STRING_TO_ATOM(JSString::unitString(c)); } /* @@ -734,7 +612,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags) if (length == 3) i = i * 10 + chars[2] - '0'; if (jsuint(i) < INT_STRING_LIMIT) - return (JSAtom *) STRING_TO_JSVAL(JSString::intString(i)); + return STRING_TO_ATOM(JSString::intString(i)); } } @@ -746,7 +624,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags) if (!entry) goto failed_hash_add; if (entry->keyAndFlags != 0) { - key = (JSString *)ATOM_ENTRY_KEY(entry); + key = ATOM_ENTRY_KEY(entry); } else { /* * We created a new hashtable entry. Unless str is already allocated @@ -791,7 +669,7 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags) if (!entry) goto failed_hash_add; if (entry->keyAndFlags != 0) { - key = (JSString *)ATOM_ENTRY_KEY(entry); + key = ATOM_ENTRY_KEY(entry); goto finish; } ++table->generation; @@ -804,10 +682,10 @@ js_AtomizeString(JSContext *cx, JSString *str, uintN flags) finish: ADD_ATOM_ENTRY_FLAGS(entry, flags & (ATOM_PINNED | ATOM_INTERNED)); JS_ASSERT(key->isAtomized()); - v = STRING_TO_JSVAL(key); - cx->weakRoots.lastAtom = v; + atom = STRING_TO_ATOM(key); + cx->weakRoots.lastAtom = atom; JS_UNLOCK(cx, &state->lock); - return (JSAtom *)v; + return atom; failed_hash_add: JS_UNLOCK(cx, &state->lock); @@ -874,7 +752,7 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length) if (length == 1) { jschar c = *chars; if (c < UNIT_STRING_LIMIT) - return (JSAtom *) STRING_TO_JSVAL(JSString::unitString(c)); + return STRING_TO_ATOM(JSString::unitString(c)); } str.initFlat((jschar *)chars, length); @@ -883,33 +761,11 @@ js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length) JS_LOCK(cx, &state->lock); hdr = JS_DHashTableOperate(&state->stringAtoms, &str, JS_DHASH_LOOKUP); str2 = JS_DHASH_ENTRY_IS_BUSY(hdr) - ? (JSString *)ATOM_ENTRY_KEY(TO_ATOM_ENTRY(hdr)) + ? ATOM_ENTRY_KEY(TO_ATOM_ENTRY(hdr)) : NULL; JS_UNLOCK(cx, &state->lock); - return str2 ? (JSAtom *)STRING_TO_JSVAL(str2) : NULL; -} - -JSBool -js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp) -{ - JSAtom *atom; - - if (JSVAL_IS_STRING(v)) { - atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0); - if (!atom) - return JS_FALSE; - } else if (JSVAL_IS_DOUBLE(v)) { - atom = js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v)); - if (!atom) - return JS_FALSE; - } else { - JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_BOOLEAN(v) || - JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)); - atom = (JSAtom *)v; - } - *atomp = atom; - return JS_TRUE; + return str2 ? STRING_TO_ATOM(str2) : NULL; } #ifdef DEBUG @@ -920,7 +776,7 @@ atom_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, { JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr); FILE *fp = (FILE *)arg; - void *key; + JSString *key; uintN flags; fprintf(fp, "%3u %08x ", number, (uintN)entry->hdr.keyHash); @@ -928,12 +784,7 @@ atom_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, fputs("", fp); } else { key = ATOM_ENTRY_KEY(entry); - if (IS_DOUBLE_TABLE(table)) { - fprintf(fp, "%.16g", *(jsdouble *)key); - } else { - JS_ASSERT(IS_STRING_TABLE(table)); - js_FileEscapedString(fp, (JSString *)key, '"'); - } + js_FileEscapedString(fp, key, '"'); flags = ATOM_ENTRY_FLAGS(entry); if (flags != 0) { fputs((flags & (ATOM_PINNED | ATOM_INTERNED)) @@ -959,7 +810,6 @@ js_DumpAtoms(JSContext *cx, FILE *fp) putc('\n', fp); fprintf(fp, "doubleAtoms table contents:\n"); - JS_DHashTableEnumerate(&state->doubleAtoms, atom_dumper, fp); #ifdef JS_DHASHMETER JS_DHashTableDumpMeter(&state->doubleAtoms, atom_dumper, fp); #endif @@ -1296,3 +1146,49 @@ js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al) } al->clear(); } + +#if JS_HAS_XML_SUPPORT +bool +js_InternNonIntElementIdSlow(JSContext *cx, JSObject *obj, const Value &idval, + jsid *idp) +{ + JS_ASSERT(idval.isObject()); + if (obj->isXML()) { + *idp = OBJECT_TO_JSID(&idval.toObject()); + return true; + } + + if (!js_IsFunctionQName(cx, &idval.toObject(), idp)) + return JS_FALSE; + if (!JSID_IS_VOID(*idp)) + return true; + + return js_ValueToStringId(cx, idval, idp); +} + +bool +js_InternNonIntElementIdSlow(JSContext *cx, JSObject *obj, const Value &idval, + jsid *idp, Value *vp) +{ + JS_ASSERT(idval.isObject()); + if (obj->isXML()) { + JSObject &idobj = idval.toObject(); + *idp = OBJECT_TO_JSID(&idobj); + vp->setObject(idobj); + return true; + } + + if (!js_IsFunctionQName(cx, &idval.toObject(), idp)) + return JS_FALSE; + if (!JSID_IS_VOID(*idp)) { + *vp = IdToValue(*idp); + return true; + } + + if (js_ValueToStringId(cx, idval, idp)) { + vp->setString(JSID_TO_STRING(*idp)); + return true; + } + return false; +} +#endif diff --git a/js/src/jsatom.h b/js/src/jsatom.h index 1aae4629a92e..e4aa5f17f56b 100644 --- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -51,19 +51,76 @@ #include "jsprvtd.h" #include "jspubtd.h" #include "jslock.h" - -JS_BEGIN_EXTERN_C +#include "jsvalue.h" #define ATOM_PINNED 0x1 /* atom is pinned against GC */ #define ATOM_INTERNED 0x2 /* pinned variant for JS_Intern* API */ #define ATOM_NOCOPY 0x4 /* don't copy atom string bytes */ #define ATOM_TMPSTR 0x8 /* internal, to avoid extra string */ -#define ATOM_KEY(atom) ((jsval)(atom)) -#define ATOM_IS_DOUBLE(atom) JSVAL_IS_DOUBLE(ATOM_KEY(atom)) -#define ATOM_TO_DOUBLE(atom) JSVAL_TO_DOUBLE(ATOM_KEY(atom)) -#define ATOM_IS_STRING(atom) JSVAL_IS_STRING(ATOM_KEY(atom)) -#define ATOM_TO_STRING(atom) JSVAL_TO_STRING(ATOM_KEY(atom)) +#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \ + (JSAtom *)str) +#define ATOM_TO_STRING(atom) ((JSString *)atom) +#define ATOM_TO_JSVAL(atom) STRING_TO_JSVAL(ATOM_TO_STRING(atom)) + +/* Engine-internal extensions of jsid */ + +static JS_ALWAYS_INLINE jsid +JSID_FROM_BITS(size_t bits) +{ + jsid id; + JSID_BITS(id) = bits; + return id; +} + +static JS_ALWAYS_INLINE jsid +ATOM_TO_JSID(JSAtom *atom) +{ + JS_ASSERT(((size_t)atom & 0x7) == 0); + return JSID_FROM_BITS((size_t)atom); +} + +/* All strings stored in jsids are atomized. */ +static JS_ALWAYS_INLINE JSBool +JSID_IS_ATOM(jsid id) +{ + return JSID_IS_STRING(id); +} + +static JS_ALWAYS_INLINE JSBool +JSID_IS_ATOM(jsid id, JSAtom *atom) +{ + return JSID_BITS(id) == JSID_BITS(ATOM_TO_JSID(atom)); +} + +static JS_ALWAYS_INLINE JSAtom * +JSID_TO_ATOM(jsid id) +{ + return (JSAtom *)JSID_TO_STRING(id); +} + +namespace js { + +static JS_ALWAYS_INLINE Value +IdToValue(jsid id) +{ + if (JSID_IS_STRING(id)) + return StringValue(JSID_TO_STRING(id)); + if (JS_LIKELY(JSID_IS_INT(id))) + return Int32Value(JSID_TO_INT(id)); + if (JS_LIKELY(JSID_IS_OBJECT(id))) + return ObjectValue(*JSID_TO_OBJECT(id)); + JS_ASSERT(JSID_IS_DEFAULT_XML_NAMESPACE(id) || JSID_IS_VOID(id)); + return UndefinedValue(); +} + +static JS_ALWAYS_INLINE jsval +IdToJsval(jsid id) +{ + return Jsvalify(IdToValue(id)); +} + +} #if JS_BYTES_PER_WORD == 4 # define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2) @@ -88,7 +145,7 @@ struct JSAtomListElement { #define ALE_ATOM(ale) ((JSAtom *) (ale)->entry.key) #define ALE_INDEX(ale) (jsatomid(uintptr_t((ale)->entry.value))) -#define ALE_VALUE(ale) ((jsval) (ale)->entry.value) +#define ALE_VALUE(ale) ((jsboxedword) (ale)->entry.value) #define ALE_NEXT(ale) ((JSAtomListElement *) (ale)->entry.next) /* @@ -119,8 +176,6 @@ struct JSAtomSet { jsuint count; /* count of indexed literals */ }; -#ifdef __cplusplus - struct JSAtomList : public JSAtomSet { #ifdef DEBUG @@ -198,8 +253,6 @@ class JSAtomListIterator { JSAtomListElement* operator ()(); }; -#endif /* __cplusplus */ - struct JSAtomMap { JSAtom **vector; /* array of ptrs to indexed atoms */ jsatomid length; /* count of (to-be-)indexed atoms */ @@ -207,7 +260,6 @@ struct JSAtomMap { struct JSAtomState { JSDHashTable stringAtoms; /* hash table with shared strings */ - JSDHashTable doubleAtoms; /* hash table with shared doubles */ #ifdef JS_THREADSAFE JSThinLock lock; #endif @@ -483,13 +535,6 @@ js_InitCommonAtoms(JSContext *cx); extern void js_FinishCommonAtoms(JSContext *cx); -/* - * Find or create the atom for a double value. Return null on failure to - * allocate memory. - */ -extern JSAtom * -js_AtomizeDouble(JSContext *cx, jsdouble d); - /* * Find or create the atom for a string. Return null on failure to allocate * memory. @@ -510,12 +555,6 @@ js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, uintN flags); extern JSAtom * js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length); -/* - * This variant handles all primitive values. - */ -JSBool -js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp); - #ifdef DEBUG extern JS_FRIEND_API(void) @@ -523,6 +562,18 @@ js_DumpAtoms(JSContext *cx, FILE *fp); #endif +inline bool +js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp); + +inline bool +js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp); + +inline bool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval, + jsid *idp); +inline bool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval, + jsid *idp, js::Value *vp); /* * For all unmapped atoms recorded in al, add a mapping from the atom's index * to its address. map->length must already be set to the number of atoms in @@ -531,6 +582,4 @@ js_DumpAtoms(JSContext *cx, FILE *fp); extern void js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al); -JS_END_EXTERN_C - #endif /* jsatom_h___ */ diff --git a/js/src/jsatominlines.h b/js/src/jsatominlines.h index fb45543a4b98..d45778025697 100644 --- a/js/src/jsatominlines.h +++ b/js/src/jsatominlines.h @@ -46,8 +46,8 @@ /* * Convert v to an atomized string and wrap it as an id. */ -inline JSBool -js_ValueToStringId(JSContext *cx, jsval v, jsid *idp) +inline bool +js_ValueToAtom(JSContext *cx, const js::Value &v, JSAtom **atomp) { JSString *str; JSAtom *atom; @@ -59,37 +59,87 @@ js_ValueToStringId(JSContext *cx, jsval v, jsid *idp) * done in js_js_AtomizeString) ensures the caller that the resulting id at * is least weakly rooted. */ - if (JSVAL_IS_STRING(v)) { - str = JSVAL_TO_STRING(v); + if (v.isString()) { + str = v.toString(); if (str->isAtomized()) { - cx->weakRoots.lastAtom = v; - *idp = ATOM_TO_JSID((JSAtom *) v); - return JS_TRUE; + cx->weakRoots.lastAtom = *atomp = STRING_TO_ATOM(str); + return true; } } else { str = js_ValueToString(cx, v); if (!str) - return JS_FALSE; + return false; } atom = js_AtomizeString(cx, str, 0); if (!atom) - return JS_FALSE; - *idp = ATOM_TO_JSID(atom); - return JS_TRUE; + return false; + *atomp = atom; + return true; } -inline JSBool +inline bool +js_ValueToStringId(JSContext *cx, const js::Value &v, jsid *idp) +{ + JSAtom *atom; + if (js_ValueToAtom(cx, v, &atom)) { + *idp = ATOM_TO_JSID(atom); + return true; + } + return false; +} + +inline bool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval, + jsid *idp) +{ + JS_ASSERT(!idval.isInt32() || !INT_FITS_IN_JSID(idval.toInt32())); + +#if JS_HAS_XML_SUPPORT + extern bool js_InternNonIntElementIdSlow(JSContext *, JSObject *, + const js::Value &, jsid *); + if (idval.isObject()) + return js_InternNonIntElementIdSlow(cx, obj, idval, idp); +#endif + + return js_ValueToStringId(cx, idval, idp); +} + +inline bool +js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval, + jsid *idp, js::Value *vp) +{ + JS_ASSERT(!idval.isInt32() || !INT_FITS_IN_JSID(idval.toInt32())); + +#if JS_HAS_XML_SUPPORT + extern bool js_InternNonIntElementIdSlow(JSContext *, JSObject *, + const js::Value &, + jsid *, js::Value *); + if (idval.isObject()) + return js_InternNonIntElementIdSlow(cx, obj, idval, idp, vp); +#endif + + JSAtom *atom; + if (js_ValueToAtom(cx, idval, &atom)) { + *idp = ATOM_TO_JSID(atom); + vp->setString(ATOM_TO_STRING(atom)); + return true; + } + return false; +} + +inline bool js_Int32ToId(JSContext* cx, int32 index, jsid* id) { - if (INT_FITS_IN_JSVAL(index)) { + if (INT_FITS_IN_JSID(index)) { *id = INT_TO_JSID(index); - JS_ASSERT(INT_JSID_TO_JSVAL(*id) == INT_TO_JSVAL(index)); - return JS_TRUE; + return true; } + JSString* str = js_NumberToString(cx, index); if (!str) - return JS_FALSE; - return js_ValueToStringId(cx, STRING_TO_JSVAL(str), id); + return false; + + return js_ValueToStringId(cx, js::StringValue(str), id); } #endif /* jsatominlines_h___ */ diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index b292af2f4098..82949bdd025e 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -56,19 +56,14 @@ #include "jsobjinlines.h" -/* Check pseudo-booleans values. */ -JS_STATIC_ASSERT(!(JSVAL_TRUE & JSVAL_HOLE_FLAG)); -JS_STATIC_ASSERT(!(JSVAL_FALSE & JSVAL_HOLE_FLAG)); -JS_STATIC_ASSERT(!(JSVAL_VOID & JSVAL_HOLE_FLAG)); -JS_STATIC_ASSERT((JSVAL_HOLE & JSVAL_HOLE_FLAG)); -JS_STATIC_ASSERT((JSVAL_HOLE & ~JSVAL_HOLE_FLAG) == JSVAL_VOID); -JS_STATIC_ASSERT(!(JSVAL_ARETURN & JSVAL_HOLE_FLAG)); -JSClass js_BooleanClass = { +using namespace js; + +Class js_BooleanClass = { "Boolean", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; @@ -76,48 +71,45 @@ JSClass js_BooleanClass = { #include "jsprf.h" static JSBool -bool_toSource(JSContext *cx, uintN argc, jsval *vp) +bool_toSource(JSContext *cx, uintN argc, Value *vp) { - jsval v; - char buf[32]; - JSString *str; - - if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &v)) + const Value *primp; + if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &primp)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + char buf[32]; JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_BooleanClass.name, - JS_BOOLEAN_STR(JSVAL_TO_BOOLEAN(v))); - str = JS_NewStringCopyZ(cx, buf); + JS_BOOLEAN_STR(primp->toBoolean())); + JSString *str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } #endif static JSBool -bool_toString(JSContext *cx, uintN argc, jsval *vp) +bool_toString(JSContext *cx, uintN argc, Value *vp) { - jsval v; - JSAtom *atom; - JSString *str; - - if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &v)) + const Value *primp; + if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &primp)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_BOOLEAN(v)); - atom = cx->runtime->atomState.booleanAtoms[JSVAL_TO_BOOLEAN(v) ? 1 : 0]; - str = ATOM_TO_STRING(atom); + JSAtom *atom = cx->runtime->atomState.booleanAtoms[primp->toBoolean() ? 1 : 0]; + JSString *str = ATOM_TO_STRING(atom); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -bool_valueOf(JSContext *cx, uintN argc, jsval *vp) +bool_valueOf(JSContext *cx, uintN argc, Value *vp) { - return js_GetPrimitiveThis(cx, vp, &js_BooleanClass, vp); + const Value *primp; + if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &primp)) + return JS_FALSE; + *vp = *primp; + return JS_TRUE; } static JSFunctionSpec boolean_methods[] = { @@ -131,13 +123,14 @@ static JSFunctionSpec boolean_methods[] = { }; static JSBool -Boolean(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Boolean(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { - jsval bval; + Value bval; - bval = (argc != 0) - ? BOOLEAN_TO_JSVAL(js_ValueToBoolean(argv[0])) - : JSVAL_FALSE; + if (argc != 0) + bval.setBoolean(!!js_ValueToBoolean(argv[0])); + else + bval.setBoolean(false); if (!JS_IsConstructing(cx)) *rval = bval; else @@ -150,11 +143,11 @@ js_InitBooleanClass(JSContext *cx, JSObject *obj) { JSObject *proto; - proto = JS_InitClass(cx, obj, NULL, &js_BooleanClass, Boolean, 1, - NULL, boolean_methods, NULL, NULL); + proto = js_InitClass(cx, obj, NULL, &js_BooleanClass, Boolean, 1, + NULL, boolean_methods, NULL, NULL); if (!proto) return NULL; - proto->setPrimitiveThis(JSVAL_FALSE); + proto->setPrimitiveThis(BooleanValue(false)); return proto; } @@ -172,22 +165,22 @@ js_BooleanToCharBuffer(JSContext *cx, JSBool b, JSCharBuffer &cb) } JSBool -js_ValueToBoolean(jsval v) +js_ValueToBoolean(const Value &v) { - if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) + if (v.isNullOrUndefined()) return JS_FALSE; - if (JSVAL_IS_OBJECT(v)) + if (v.isObject()) return JS_TRUE; - if (JSVAL_IS_STRING(v)) - return JSVAL_TO_STRING(v)->length() != 0; - if (JSVAL_IS_INT(v)) - return JSVAL_TO_INT(v) != 0; - if (JSVAL_IS_DOUBLE(v)) { + if (v.isString()) + return v.toString()->length() != 0; + if (v.isInt32()) + return v.toInt32() != 0; + if (v.isDouble()) { jsdouble d; - d = *JSVAL_TO_DOUBLE(v); + d = v.toDouble(); return !JSDOUBLE_IS_NaN(d) && d != 0; } - JS_ASSERT(JSVAL_IS_BOOLEAN(v)); - return JSVAL_TO_BOOLEAN(v); + JS_ASSERT(v.isBoolean()); + return v.toBoolean(); } diff --git a/js/src/jsbool.h b/js/src/jsbool.h index 4722e12433b2..3de8ee33c990 100644 --- a/js/src/jsbool.h +++ b/js/src/jsbool.h @@ -46,27 +46,7 @@ #include "jsapi.h" #include "jsobj.h" -JS_BEGIN_EXTERN_C - -/* - * Special values, not visible to script but used internally by the engine. - * - * JSVAL_HOLE is a useful value for identifying a hole in an array. It's also - * used in the interpreter to represent "no exception pending". In general it - * can be used to represent "no value". - * - * A JSVAL_HOLE can be cheaply converted to undefined without affecting any - * other boolean (or special value) by masking out JSVAL_HOLE_FLAG. - * - * JSVAL_ARETURN is used to throw asynchronous return for generator.close(). - * - * NB: SPECIAL_TO_JSVAL(2) is JSVAL_VOID (see jsapi.h). - */ -#define JSVAL_HOLE_FLAG jsval(4 << JSVAL_TAGBITS) -#define JSVAL_HOLE (JSVAL_VOID | JSVAL_HOLE_FLAG) -#define JSVAL_ARETURN SPECIAL_TO_JSVAL(8) - -extern JSClass js_BooleanClass; +extern js::Class js_BooleanClass; inline bool JSObject::isBoolean() const @@ -84,8 +64,6 @@ extern JSBool js_BooleanToCharBuffer(JSContext *cx, JSBool b, JSCharBuffer &cb); extern JSBool -js_ValueToBoolean(jsval v); - -JS_END_EXTERN_C +js_ValueToBoolean(const js::Value &v); #endif /* jsbool_h___ */ diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index 54b184253c82..da0962a17b2b 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -103,69 +103,55 @@ js_imod(int32 a, int32 b) } JS_DEFINE_CALLINFO_2(extern, INT32, js_imod, INT32, INT32, 1, ACC_NONE) -jsval FASTCALL -js_BoxDouble(JSContext* cx, jsdouble d) -{ - int32 i; - if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) - return INT_TO_JSVAL(i); - JS_ASSERT(JS_ON_TRACE(cx)); - jsval v; /* not rooted but ok here because we know GC won't run */ - if (!js_NewDoubleInRootedValue(cx, d, &v)) - return JSVAL_NULL; - return v; -} -JS_DEFINE_CALLINFO_2(extern, JSVAL, js_BoxDouble, CONTEXT, DOUBLE, 1, ACC_NONE) - -jsval FASTCALL -js_BoxInt32(JSContext* cx, int32 i) -{ - if (JS_LIKELY(INT_FITS_IN_JSVAL(i))) - return INT_TO_JSVAL(i); - JS_ASSERT(JS_ON_TRACE(cx)); - jsval v; /* not rooted but ok here because we know GC won't run */ - jsdouble d = (jsdouble)i; - if (!js_NewDoubleInRootedValue(cx, d, &v)) - return JSVAL_NULL; - return v; -} -JS_DEFINE_CALLINFO_2(extern, JSVAL, js_BoxInt32, CONTEXT, INT32, 1, ACC_NONE) +#if JS_BITS_PER_WORD == 32 jsdouble FASTCALL -js_UnboxDouble(jsval v) +js_UnboxDouble(uint32 tag, uint32 payload) { - if (JS_LIKELY(JSVAL_IS_INT(v))) - return (jsdouble)JSVAL_TO_INT(v); - return *JSVAL_TO_DOUBLE(v); + if (tag == JSVAL_TAG_INT32) + return (double)(int32)payload; + + jsval_layout l; + l.s.tag = (JSValueTag)tag; + l.s.payload.u32 = payload; + return l.asDouble; +} +JS_DEFINE_CALLINFO_2(extern, DOUBLE, js_UnboxDouble, UINT32, UINT32, 1, ACC_NONE) + +int32 FASTCALL +js_UnboxInt32(uint32 tag, uint32 payload) +{ + if (tag == JSVAL_TAG_INT32) + return (int32)payload; + + jsval_layout l; + l.s.tag = (JSValueTag)tag; + l.s.payload.u32 = payload; + return js_DoubleToECMAInt32(l.asDouble); +} +JS_DEFINE_CALLINFO_2(extern, INT32, js_UnboxInt32, UINT32, UINT32, 1, ACC_NONE) + +#elif JS_BITS_PER_WORD == 64 + +jsdouble FASTCALL +js_UnboxDouble(Value v) +{ + if (v.isInt32()) + return (jsdouble)v.toInt32(); + return v.toDouble(); } JS_DEFINE_CALLINFO_1(extern, DOUBLE, js_UnboxDouble, JSVAL, 1, ACC_NONE) int32 FASTCALL -js_UnboxInt32(jsval v) +js_UnboxInt32(Value v) { - if (JS_LIKELY(JSVAL_IS_INT(v))) - return JSVAL_TO_INT(v); - return js_DoubleToECMAInt32(*JSVAL_TO_DOUBLE(v)); + if (v.isInt32()) + return v.toInt32(); + return js_DoubleToECMAInt32(v.toDouble()); } -JS_DEFINE_CALLINFO_1(extern, INT32, js_UnboxInt32, JSVAL, 1, ACC_NONE) +JS_DEFINE_CALLINFO_1(extern, INT32, js_UnboxInt32, VALUE, 1, ACC_NONE) -JSBool FASTCALL -js_TryUnboxInt32(jsval v, int32* i32p) -{ - if (JS_LIKELY(JSVAL_IS_INT(v))) { - *i32p = JSVAL_TO_INT(v); - return JS_TRUE; - } - if (!JSVAL_IS_DOUBLE(v)) - return JS_FALSE; - int32 i; - jsdouble d = *JSVAL_TO_DOUBLE(v); - if (!JSDOUBLE_IS_INT(d, i)) - return JS_FALSE; - *i32p = i; - return JS_TRUE; -} -JS_DEFINE_CALLINFO_2(extern, BOOL, js_TryUnboxInt32, JSVAL, INT32PTR, 1, ACC_NONE) +#endif int32 FASTCALL js_DoubleToInt32(jsdouble d) @@ -217,7 +203,7 @@ AddPropertyHelper(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, bool isD if (!scope->table) { if (slot < obj->numSlots()) { - JS_ASSERT(JSVAL_IS_VOID(obj->getSlot(scope->freeslot))); + JS_ASSERT(obj->getSlot(scope->freeslot).isUndefined()); ++scope->freeslot; } else { if (!js_AllocSlot(cx, obj, &slot)) @@ -270,16 +256,16 @@ HasProperty(JSContext* cx, JSObject* obj, jsid id) // Check that we know how the lookup op will behave. for (JSObject* pobj = obj; pobj; pobj = pobj->getProto()) { if (pobj->map->ops->lookupProperty != js_LookupProperty) - return JSVAL_TO_SPECIAL(JSVAL_VOID); - JSClass* clasp = pobj->getClass(); + return JS_NEITHER; + Class* clasp = pobj->getClass(); if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass) - return JSVAL_TO_SPECIAL(JSVAL_VOID); + return JS_NEITHER; } JSObject* obj2; JSProperty* prop; if (js_LookupPropertyWithFlags(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) < 0) - return JSVAL_TO_SPECIAL(JSVAL_VOID); + return JS_NEITHER; if (prop) obj2->dropProperty(cx, prop); return prop != NULL; @@ -288,11 +274,11 @@ HasProperty(JSContext* cx, JSObject* obj, jsid id) JSBool FASTCALL js_HasNamedProperty(JSContext* cx, JSObject* obj, JSString* idstr) { - jsid id; - if (!js_ValueToStringId(cx, STRING_TO_JSVAL(idstr), &id)) - return JSVAL_TO_BOOLEAN(JSVAL_VOID); + JSAtom *atom = js_AtomizeString(cx, idstr, 0); + if (!atom) + return JS_NEITHER; - return HasProperty(cx, obj, id); + return HasProperty(cx, obj, ATOM_TO_JSID(atom)); } JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedProperty, CONTEXT, OBJECT, STRING, 0, ACC_STORE_ANY) @@ -301,7 +287,7 @@ js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index) { jsid id; if (!js_Int32ToId(cx, index, &id)) - return JSVAL_TO_BOOLEAN(JSVAL_VOID); + return JS_NEITHER; return HasProperty(cx, obj, id); } @@ -311,23 +297,11 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, IN JSString* FASTCALL js_TypeOfObject(JSContext* cx, JSObject* obj) { - if (!obj) - return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_OBJECT]); + JS_ASSERT(obj); return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[obj->typeOf(cx)]); } JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfObject, CONTEXT, OBJECT, 1, ACC_NONE) -JSString* FASTCALL -js_TypeOfBoolean(JSContext* cx, int32 unboxed) -{ - /* Watch out for pseudo-booleans. */ - jsval boxed = SPECIAL_TO_JSVAL(unboxed); - JS_ASSERT(JSVAL_IS_VOID(boxed) || JSVAL_IS_BOOLEAN(boxed)); - JSType type = JS_TypeOfValue(cx, boxed); - return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type]); -} -JS_DEFINE_CALLINFO_2(extern, STRING, js_TypeOfBoolean, CONTEXT, INT32, 1, ACC_NONE) - JSString* FASTCALL js_BooleanIntToString(JSContext *cx, int32 unboxed) { @@ -350,8 +324,7 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa if (!closure) return NULL; - closure->initSharingEmptyScope(&js_FunctionClass, proto, parent, - reinterpret_cast(fun)); + closure->initSharingEmptyScope(&js_FunctionClass, proto, parent, PrivateValue(fun)); return closure; } JS_DEFINE_CALLINFO_4(extern, OBJECT, js_NewNullClosure, CONTEXT, OBJECT, OBJECT, OBJECT, 0, diff --git a/js/src/jsbuiltins.h b/js/src/jsbuiltins.h index 661cd04ea04e..b0cb4aec1e87 100644 --- a/js/src/jsbuiltins.h +++ b/js/src/jsbuiltins.h @@ -48,9 +48,15 @@ #undef THIS #endif -enum JSTNErrType { INFALLIBLE, FAIL_STATUS, FAIL_NULL, FAIL_NEG, FAIL_VOID }; -enum { JSTN_ERRTYPE_MASK = 0x07, JSTN_UNBOX_AFTER = 0x08, JSTN_MORE = 0x10, - JSTN_CONSTRUCTOR = 0x20 }; +enum JSTNErrType { INFALLIBLE, FAIL_STATUS, FAIL_NULL, FAIL_NEG, FAIL_NEITHER }; +enum { + JSTN_ERRTYPE_MASK = 0x07, + JSTN_UNBOX_AFTER = 0x08, + JSTN_MORE = 0x10, + JSTN_CONSTRUCTOR = 0x20, + JSTN_RETURN_NULLABLE_STR = 0x40, + JSTN_RETURN_NULLABLE_OBJ = 0x80 +}; #define JSTN_ERRTYPE(jstn) ((jstn)->flags & JSTN_ERRTYPE_MASK) @@ -80,7 +86,7 @@ enum { JSTN_ERRTYPE_MASK = 0x07, JSTN_UNBOX_AFTER = 0x08, JSTN_MORE = 0x10, * 'o': a JSObject* argument * 'r': a JSObject* argument that is of class js_RegExpClass * 'f': a JSObject* argument that is of class js_FunctionClass - * 'v': a jsval argument (boxing whatever value is actually being passed in) + * 'v': a value argument: on 32-bit, a Value*, on 64-bit, a jsval */ struct JSSpecializedNative { const nanojit::CallInfo *builtin; @@ -110,6 +116,8 @@ struct JSNativeTraceInfo { #define _JS_I32_ARGTYPE nanojit::ARGTYPE_I #define _JS_I32_RETTYPE nanojit::ARGTYPE_I +#define _JS_U64_ARGTYPE nanojit::ARGTYPE_Q +#define _JS_U64_RETTYPE nanojit::ARGTYPE_Q #define _JS_F64_ARGTYPE nanojit::ARGTYPE_D #define _JS_F64_RETTYPE nanojit::ARGTYPE_D #define _JS_PTR_ARGTYPE nanojit::ARGTYPE_P @@ -148,7 +156,7 @@ struct ClosureVarInfo; * _RETRY builtins indicate failure with a special return value that * depends on the return type: * - * BOOL_RETRY: JSVAL_TO_BOOLEAN(JSVAL_VOID) + * BOOL_RETRY: JS_NEITHER * INT32_RETRY: any negative value * STRING_RETRY: NULL * OBJECT_RETRY_NULL: NULL @@ -172,7 +180,6 @@ struct ClosureVarInfo; * effects. */ #define _JS_CTYPE(ctype, size, pch, ach, flags) (ctype, size, pch, ach, flags) -#define _JS_JSVAL_CTYPE(size, pch, ach, flags) (jsval, size, pch, ach, (flags | JSTN_UNBOX_AFTER)) #define _JS_CTYPE_CONTEXT _JS_CTYPE(JSContext *, _JS_PTR,"C", "", INFALLIBLE) #define _JS_CTYPE_RUNTIME _JS_CTYPE(JSRuntime *, _JS_PTR,"R", "", INFALLIBLE) @@ -183,12 +190,12 @@ struct ClosureVarInfo; #define _JS_CTYPE_CALLEE_PROTOTYPE _JS_CTYPE(JSObject *, _JS_PTR,"p","", INFALLIBLE) #define _JS_CTYPE_FUNCTION _JS_CTYPE(JSFunction *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_PC _JS_CTYPE(jsbytecode *, _JS_PTR,"P", "", INFALLIBLE) -#define _JS_CTYPE_JSVALPTR _JS_CTYPE(jsval *, _JS_PTR,"P", "", INFALLIBLE) -#define _JS_CTYPE_JSVAL _JS_JSVAL_CTYPE( _JS_PTR, "","v", INFALLIBLE) -#define _JS_CTYPE_JSVAL_FAIL _JS_JSVAL_CTYPE( _JS_PTR, --, --, FAIL_STATUS) +#define _JS_CTYPE_VALUEPTR _JS_CTYPE(js::Value *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_CVALUEPTR _JS_CTYPE(const js::Value *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_JSID _JS_CTYPE(jsid, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_JSVAL _JS_CTYPE(js::Value, _JS_U64, --, --, INFALLIBLE) #define _JS_CTYPE_BOOL _JS_CTYPE(JSBool, _JS_I32, "","i", INFALLIBLE) -#define _JS_CTYPE_BOOL_RETRY _JS_CTYPE(JSBool, _JS_I32, --, --, FAIL_VOID) +#define _JS_CTYPE_BOOL_RETRY _JS_CTYPE(JSBool, _JS_I32, --, --, FAIL_NEITHER) #define _JS_CTYPE_BOOL_FAIL _JS_CTYPE(JSBool, _JS_I32, --, --, FAIL_STATUS) #define _JS_CTYPE_BOOLPTR _JS_CTYPE(JSBool *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_INT32 _JS_CTYPE(int32, _JS_I32, "","i", INFALLIBLE) @@ -203,10 +210,14 @@ struct ClosureVarInfo; #define _JS_CTYPE_STRING _JS_CTYPE(JSString *, _JS_PTR, "","s", INFALLIBLE) #define _JS_CTYPE_STRING_RETRY _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_NULL) #define _JS_CTYPE_STRING_FAIL _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_STATUS) +#define _JS_CTYPE_STRING_OR_NULL_FAIL _JS_CTYPE(JSString *, _JS_PTR, --, --, FAIL_STATUS | \ + JSTN_RETURN_NULLABLE_STR) #define _JS_CTYPE_STRINGPTR _JS_CTYPE(JSString **, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_OBJECT _JS_CTYPE(JSObject *, _JS_PTR, "","o", INFALLIBLE) #define _JS_CTYPE_OBJECT_RETRY _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_NULL) #define _JS_CTYPE_OBJECT_FAIL _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_STATUS) +#define _JS_CTYPE_OBJECT_OR_NULL_FAIL _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_STATUS | \ + JSTN_RETURN_NULLABLE_OBJ) #define _JS_CTYPE_OBJECTPTR _JS_CTYPE(JSObject **, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_CONSTRUCTOR_RETRY _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_NULL | \ JSTN_CONSTRUCTOR) @@ -214,13 +225,32 @@ struct ClosureVarInfo; #define _JS_CTYPE_SCOPEPROP _JS_CTYPE(JSScopeProperty *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_TRACERSTATE _JS_CTYPE(TracerState *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_FRAGMENT _JS_CTYPE(nanojit::Fragment *, _JS_PTR, --, --, INFALLIBLE) -#define _JS_CTYPE_CLASS _JS_CTYPE(JSClass *, _JS_PTR, --, --, INFALLIBLE) +#define _JS_CTYPE_CLASS _JS_CTYPE(js::Class *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_DOUBLEPTR _JS_CTYPE(double *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_CHARPTR _JS_CTYPE(char *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_APNPTR _JS_CTYPE(ArgsPrivateNative *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_CVIPTR _JS_CTYPE(const ClosureVarInfo *, _JS_PTR, --, --, INFALLIBLE) #define _JS_CTYPE_FRAMEINFO _JS_CTYPE(FrameInfo *, _JS_PTR, --, --, INFALLIBLE) +/* + * The "VALUE" type is used to indicate that a native takes a js::Value + * parameter by value. Unfortunately, for technical reasons, we can't simply + * have the parameter type be js::Value. Furthermore, the right thing to pass + * differs based on word size. Thus, a native that declares a parameter of type + * VALUE should have the corresponding argument type be: + * - on 32-bit: const Value* + * - on 64-bit: jsval (which is a uint64) + * + * To write code that just does the right thing, use the pattern: + * void foo(js::ValueArgType arg) { + * const js::Value &v = js::ValueArgToConstRef(arg); + */ +#if JS_BITS_PER_WORD == 32 +# define _JS_CTYPE_VALUE _JS_CTYPE(js::ValueArgType, _JS_PTR, "","v", INFALLIBLE) +#elif JS_BITS_PER_WORD == 64 +# define _JS_CTYPE_VALUE _JS_CTYPE(js::ValueArgType, _JS_U64, "","v", INFALLIBLE) +#endif + #define _JS_EXPAND(tokens) tokens #define _JS_CTYPE_TYPE2(t,s,p,a,f) t @@ -549,14 +579,11 @@ JS_DECLARE_CALLINFO(js_Array_dense_setelem_double) JS_DECLARE_CALLINFO(js_NewEmptyArray) JS_DECLARE_CALLINFO(js_NewEmptyArrayWithLength) JS_DECLARE_CALLINFO(js_NewArrayWithSlots) -JS_DECLARE_CALLINFO(js_ArrayCompPush) +JS_DECLARE_CALLINFO(js_ArrayCompPush_tn) /* Defined in jsbuiltins.cpp. */ -JS_DECLARE_CALLINFO(js_BoxDouble) -JS_DECLARE_CALLINFO(js_BoxInt32) JS_DECLARE_CALLINFO(js_UnboxDouble) JS_DECLARE_CALLINFO(js_UnboxInt32) -JS_DECLARE_CALLINFO(js_TryUnboxInt32) JS_DECLARE_CALLINFO(js_dmod) JS_DECLARE_CALLINFO(js_imod) JS_DECLARE_CALLINFO(js_DoubleToInt32) @@ -568,7 +595,6 @@ JS_DECLARE_CALLINFO(js_AddAtomProperty) JS_DECLARE_CALLINFO(js_HasNamedProperty) JS_DECLARE_CALLINFO(js_HasNamedPropertyInt32) JS_DECLARE_CALLINFO(js_TypeOfObject) -JS_DECLARE_CALLINFO(js_TypeOfBoolean) JS_DECLARE_CALLINFO(js_BooleanIntToString) JS_DECLARE_CALLINFO(js_NewNullClosure) JS_DECLARE_CALLINFO(js_PopInterpFrame) diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index 1dae6c7f50d4..1c26db2804e1 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -135,21 +135,21 @@ StackSpace::init() void *check = VirtualAlloc(p, COMMIT_BYTES, MEM_COMMIT, PAGE_READWRITE); if (p != check) return false; - base = reinterpret_cast(p); + base = reinterpret_cast(p); commitEnd = base + COMMIT_VALS; end = base + CAPACITY_VALS; #elif defined(XP_OS2) if (DosAllocMem(&p, CAPACITY_BYTES, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY) && DosAllocMem(&p, CAPACITY_BYTES, PAG_COMMIT | PAG_READ | PAG_WRITE)) return false; - base = reinterpret_cast(p); + base = reinterpret_cast(p); end = base + CAPACITY_VALS; #else JS_ASSERT(CAPACITY_BYTES % getpagesize() == 0); p = mmap(NULL, CAPACITY_BYTES, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (p == MAP_FAILED) return false; - base = reinterpret_cast(p); + base = reinterpret_cast(p); end = base + CAPACITY_VALS; #endif return true; @@ -159,22 +159,22 @@ void StackSpace::finish() { #ifdef XP_WIN - VirtualFree(base, (commitEnd - base) * sizeof(jsval), MEM_DECOMMIT); + VirtualFree(base, (commitEnd - base) * sizeof(Value), MEM_DECOMMIT); VirtualFree(base, 0, MEM_RELEASE); #elif defined(XP_OS2) DosFreeMem(base); #else - munmap(base, CAPACITY_BYTES); + munmap((caddr_t)base, CAPACITY_BYTES); #endif } #ifdef XP_WIN JS_FRIEND_API(bool) -StackSpace::bumpCommit(jsval *from, ptrdiff_t nvals) const +StackSpace::bumpCommit(Value *from, ptrdiff_t nvals) const { JS_ASSERT(end - from >= nvals); - jsval *newCommit = commitEnd; - jsval *request = from + nvals; + Value *newCommit = commitEnd; + Value *request = from + nvals; /* Use a dumb loop; will probably execute once. */ JS_ASSERT((end - newCommit) % COMMIT_VALS == 0); @@ -184,7 +184,7 @@ StackSpace::bumpCommit(jsval *from, ptrdiff_t nvals) const } while (newCommit < request); /* The cast is safe because CAPACITY_BYTES is small. */ - int32 size = static_cast(newCommit - commitEnd) * sizeof(jsval); + int32 size = static_cast(newCommit - commitEnd) * sizeof(Value); if (!VirtualAlloc(commitEnd, size, MEM_COMMIT, PAGE_READWRITE)) return false; @@ -200,7 +200,7 @@ StackSpace::mark(JSTracer *trc) * The correctness/completeness of marking depends on the continuity * invariants described by the CallStack and StackSpace definitions. */ - jsval *end = firstUnused(); + Value *end = firstUnused(); for (CallStack *cs = currentCallStack; cs; cs = cs->getPreviousInThread()) { if (cs->inContext()) { /* This may be the only pointer to the initialVarObj. */ @@ -209,22 +209,22 @@ StackSpace::mark(JSTracer *trc) /* Mark slots/args trailing off of the last stack frame. */ JSStackFrame *fp = cs->getCurrentFrame(); - TraceValues(trc, fp->slots(), end, "stack"); + MarkValueRange(trc, fp->slots(), end, "stack"); /* Mark stack frames and slots/args between stack frames. */ JSStackFrame *initialFrame = cs->getInitialFrame(); for (JSStackFrame *f = fp; f != initialFrame; f = f->down) { js_TraceStackFrame(trc, f); - TraceValues(trc, f->down->slots(), f->argEnd(), "stack"); + MarkValueRange(trc, f->down->slots(), f->argEnd(), "stack"); } /* Mark initialFrame stack frame and leading args. */ js_TraceStackFrame(trc, initialFrame); - TraceValues(trc, cs->getInitialArgBegin(), initialFrame->argEnd(), "stack"); + MarkValueRange(trc, cs->getInitialArgBegin(), initialFrame->argEnd(), "stack"); } else { /* Mark slots/args trailing off callstack. */ JS_ASSERT(end == cs->getInitialArgEnd()); - TraceValues(trc, cs->getInitialArgBegin(), cs->getInitialArgEnd(), "stack"); + MarkValueRange(trc, cs->getInitialArgBegin(), cs->getInitialArgEnd(), "stack"); } end = cs->previousCallStackEnd(); } @@ -233,14 +233,14 @@ StackSpace::mark(JSTracer *trc) JS_REQUIRES_STACK bool StackSpace::pushInvokeArgs(JSContext *cx, uintN argc, InvokeArgsGuard &ag) { - jsval *start = firstUnused(); + Value *start = firstUnused(); uintN vplen = 2 + argc; ptrdiff_t nvals = VALUES_PER_CALL_STACK + vplen; if (!ensureSpace(cx, start, nvals)) return false; - jsval *vp = start + VALUES_PER_CALL_STACK; - jsval *vpend = vp + vplen; - memset(vp, 0, vplen * sizeof(jsval)); /* Init so GC-safe on exit. */ + Value *vp = start + VALUES_PER_CALL_STACK; + Value *vpend = vp + vplen; + memset(vp, 0, vplen * sizeof(Value)); /* Init so GC-safe on exit. */ CallStack *cs = new(start) CallStack; cs->setInitialArgEnd(vpend); @@ -278,7 +278,7 @@ StackSpace::getInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag, { if (ag.cs) { JS_ASSERT(ag.cs == currentCallStack && !ag.cs->inContext()); - jsval *start = ag.cs->getInitialArgEnd(); + Value *start = ag.cs->getInitialArgEnd(); ptrdiff_t nvals = nmissing + VALUES_PER_STACK_FRAME + nfixed; if (!ensureSpace(cx, start, nvals)) return false; @@ -288,7 +288,7 @@ StackSpace::getInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag, assertIsCurrent(cx); JS_ASSERT(currentCallStack->isActive()); - jsval *start = cx->regs->sp; + Value *start = cx->regs->sp; ptrdiff_t nvals = nmissing + VALUES_PER_CALL_STACK + VALUES_PER_STACK_FRAME + nfixed; if (!ensureSpace(cx, start, nvals)) return false; @@ -358,7 +358,7 @@ StackSpace::getExecuteFrame(JSContext *cx, JSStackFrame *down, uintN vplen, uintN nfixed, ExecuteFrameGuard &fg) const { - jsval *start = firstUnused(); + Value *start = firstUnused(); ptrdiff_t nvals = VALUES_PER_CALL_STACK + vplen + VALUES_PER_STACK_FRAME + nfixed; if (!ensureSpace(cx, start, nvals)) return false; @@ -395,7 +395,7 @@ StackSpace::popExecuteFrame(JSContext *cx) JS_REQUIRES_STACK void StackSpace::getSynthesizedSlowNativeFrame(JSContext *cx, CallStack *&cs, JSStackFrame *&fp) { - jsval *start = firstUnused(); + Value *start = firstUnused(); JS_ASSERT(size_t(end - start) >= VALUES_PER_CALL_STACK + VALUES_PER_STACK_FRAME); cs = new(start) CallStack; fp = reinterpret_cast(cs + 1); @@ -429,16 +429,16 @@ StackSpace::popSynthesizedSlowNativeFrame(JSContext *cx) * up-frame's address is the top of the down-frame's stack, modulo missing * arguments. */ -static inline jsval * +static inline Value * InlineDownFrameSP(JSStackFrame *up) { JS_ASSERT(up->fun && up->script); - jsval *sp = up->argv + up->argc; + Value *sp = up->argv + up->argc; #ifdef DEBUG uint16 nargs = up->fun->nargs; uintN argc = up->argc; uintN missing = argc < nargs ? nargs - argc : 0; - JS_ASSERT(sp == (jsval *)up - missing); + JS_ASSERT(sp == (Value *)up - missing); #endif return sp; } @@ -488,12 +488,12 @@ FrameRegsIter::operator++() * scan, keeping track of what is immediately after down in memory. */ curcs = curcs->getPreviousInContext(); - cursp = curcs->getSuspendedSP(); + cursp = curcs->getSuspendedRegs()->sp; JSStackFrame *f = curcs->getSuspendedFrame(); while (f != down) { if (f == curcs->getInitialFrame()) { curcs = curcs->getPreviousInContext(); - cursp = curcs->getSuspendedSP(); + cursp = curcs->getSuspendedRegs()->sp; f = curcs->getSuspendedFrame(); } else { cursp = InlineDownFrameSP(f); @@ -1246,7 +1246,7 @@ resolving_HashKey(JSDHashTable *table, const void *ptr) { const JSResolvingKey *key = (const JSResolvingKey *)ptr; - return (JSDHashNumber(uintptr_t(key->obj)) >> JSVAL_TAGBITS) ^ key->id; + return (JSDHashNumber(uintptr_t(key->obj)) >> JS_GCTHING_ALIGN) ^ JSID_BITS(key->id); } static JSBool @@ -1779,13 +1779,13 @@ js_ReportIsNotDefined(JSContext *cx, const char *name) } JSBool -js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, jsval v, +js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, const Value &v, JSString *fallback) { char *bytes; JSBool ok; - bytes = js_DecompileValueGenerator(cx, spindex, v, fallback); + bytes = DecompileValueGenerator(cx, spindex, v, fallback); if (!bytes) return JS_FALSE; @@ -1795,13 +1795,13 @@ js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, jsval v, js_GetErrorMessage, NULL, JSMSG_NO_PROPERTIES, bytes, NULL, NULL); - } else if (JSVAL_IS_VOID(v)) { + } else if (v.isUndefined()) { ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE, bytes, js_undefined_str, NULL); } else { - JS_ASSERT(JSVAL_IS_NULL(v)); + JS_ASSERT(v.isNull()); ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE, bytes, @@ -1813,7 +1813,7 @@ js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, jsval v, } void -js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg) +js_ReportMissingArg(JSContext *cx, const Value &v, uintN arg) { char argbuf[11]; char *bytes; @@ -1821,10 +1821,10 @@ js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg) JS_snprintf(argbuf, sizeof argbuf, "%u", arg); bytes = NULL; - if (VALUE_IS_FUNCTION(cx, *vp)) { - atom = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(*vp))->atom; - bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, *vp, - ATOM_TO_STRING(atom)); + if (IsFunctionObject(v)) { + atom = GET_FUNCTION_PRIVATE(cx, &v.toObject())->atom; + bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, + v, ATOM_TO_STRING(atom)); if (!bytes) return; } @@ -1836,7 +1836,7 @@ js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg) JSBool js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, - intN spindex, jsval v, JSString *fallback, + intN spindex, const Value &v, JSString *fallback, const char *arg1, const char *arg2) { char *bytes; @@ -1844,7 +1844,7 @@ js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1); JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3); - bytes = js_DecompileValueGenerator(cx, spindex, v, fallback); + bytes = DecompileValueGenerator(cx, spindex, v, fallback); if (!bytes) return JS_FALSE; @@ -2230,3 +2230,14 @@ JSContext::purge() FreeOldArenas(runtime, ®expPool); } + +namespace js { + +void +SetPendingException(JSContext *cx, const Value &v) +{ + cx->throwing = JS_TRUE; + cx->exception = v; +} + +} /* namespace js */ diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 9b291eed511e..52ff6dda1ee3 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -207,7 +207,7 @@ struct TracerState // Used when calling natives from trace to root the vp vector. uintN nativeVpLen; - jsval* nativeVp; + js::Value* nativeVp; // The regs pointed to by cx->regs while a deep-bailed slow native // completes execution. @@ -298,14 +298,19 @@ class CallStack /* If this callstack is suspended, the top of the callstack. */ JSStackFrame *suspendedFrame; - /* If this callstack is suspended, |cx->regs| when it was suspended. */ - JSFrameRegs *suspendedRegs; - - /* This callstack was suspended by JS_SaveFrameChain. */ - bool saved; + /* + * To achieve a sizeof(CallStack) that is a multiple of sizeof(Value), we + * compress two fields into one word: + * + * suspendedRegs: If this callstack is suspended, |cx->regs| when it was + * suspended. + * + * saved: Whether this callstack was suspended by JS_SaveFrameChain. + */ + AlignedPtrAndFlag suspendedRegsAndSaved; /* End of arguments before the first frame. See StackSpace comment. */ - jsval *initialArgEnd; + Value *initialArgEnd; /* The varobj on entry to initialFrame. */ JSObject *initialVarObj; @@ -313,18 +318,19 @@ class CallStack public: CallStack() : cx(NULL), previousInContext(NULL), previousInThread(NULL), - initialFrame(NULL), suspendedFrame(NULL), saved(false), - initialArgEnd(NULL), initialVarObj(NULL) + initialFrame(NULL), suspendedFrame(NULL), + suspendedRegsAndSaved(NULL, false), initialArgEnd(NULL), + initialVarObj(NULL) {} /* Safe casts guaranteed by the contiguous-stack layout. */ - jsval *previousCallStackEnd() const { - return (jsval *)this; + Value *previousCallStackEnd() const { + return (Value *)this; } - jsval *getInitialArgBegin() const { - return (jsval *)(this + 1); + Value *getInitialArgBegin() const { + return (Value *)(this + 1); } /* @@ -340,8 +346,8 @@ class CallStack bool inContext() const { JS_ASSERT(!!cx == !!initialFrame); - JS_ASSERT_IF(!initialFrame, !suspendedFrame && !saved); - return cx; + JS_ASSERT_IF(!initialFrame, !suspendedFrame && !suspendedRegsAndSaved.flag()); + return !!cx; } bool isActive() const { @@ -350,15 +356,15 @@ class CallStack } bool isSuspended() const { - JS_ASSERT_IF(!suspendedFrame, !saved); + JS_ASSERT_IF(!suspendedFrame, !suspendedRegsAndSaved.flag()); JS_ASSERT_IF(suspendedFrame, inContext()); - return suspendedFrame; + return !!suspendedFrame; } /* Substate of suspended, queryable in any state. */ bool isSaved() const { - JS_ASSERT_IF(saved, isSuspended()); - return saved; + JS_ASSERT_IF(suspendedRegsAndSaved.flag(), isSuspended()); + return suspendedRegsAndSaved.flag(); } /* Transitioning between inContext <--> isActive */ @@ -388,7 +394,7 @@ class CallStack JS_ASSERT(fp && contains(fp)); suspendedFrame = fp; JS_ASSERT(isSuspended()); - suspendedRegs = regs; + suspendedRegsAndSaved.setPtr(regs); } void resume() { @@ -402,25 +408,25 @@ class CallStack void save(JSStackFrame *fp, JSFrameRegs *regs) { JS_ASSERT(!isSaved()); suspend(fp, regs); - saved = true; + suspendedRegsAndSaved.setFlag(); JS_ASSERT(isSaved()); } void restore() { JS_ASSERT(isSaved()); - saved = false; + suspendedRegsAndSaved.unsetFlag(); resume(); JS_ASSERT(!isSaved()); } /* Data available when !inContext */ - void setInitialArgEnd(jsval *v) { + void setInitialArgEnd(Value *v) { JS_ASSERT(!inContext() && !initialArgEnd); initialArgEnd = v; } - jsval *getInitialArgEnd() const { + Value *getInitialArgEnd() const { JS_ASSERT(!inContext() && initialArgEnd); return initialArgEnd; } @@ -443,12 +449,7 @@ class CallStack JSFrameRegs *getSuspendedRegs() const { JS_ASSERT(isSuspended()); - return suspendedRegs; - } - - jsval *getSuspendedSP() const { - JS_ASSERT(isSuspended()); - return suspendedRegs->sp; + return suspendedRegsAndSaved.ptr(); } /* JSContext / js::StackSpace bookkeeping. */ @@ -485,26 +486,26 @@ class CallStack }; -static const size_t VALUES_PER_CALL_STACK = sizeof(CallStack) / sizeof(jsval); -JS_STATIC_ASSERT(sizeof(CallStack) % sizeof(jsval) == 0); +static const size_t VALUES_PER_CALL_STACK = sizeof(CallStack) / sizeof(Value); +JS_STATIC_ASSERT(sizeof(CallStack) % sizeof(Value) == 0); /* * The ternary constructor is used when arguments are already pushed on the * stack (as the sp of the current frame), which should only happen from within - * js_Interpret. Otherwise, see StackSpace::pushInvokeArgs. + * Interpret. Otherwise, see StackSpace::pushInvokeArgs. */ class InvokeArgsGuard { friend class StackSpace; JSContext *cx; CallStack *cs; /* null implies nothing pushed */ - jsval *vp; + Value *vp; uintN argc; public: inline InvokeArgsGuard(); - inline InvokeArgsGuard(jsval *vp, uintN argc); + inline InvokeArgsGuard(Value *vp, uintN argc); inline ~InvokeArgsGuard(); - jsval *getvp() const { return vp; } + Value *getvp() const { return vp; } uintN getArgc() const { JS_ASSERT(vp != NULL); return argc; } }; @@ -527,13 +528,13 @@ class ExecuteFrameGuard friend class StackSpace; JSContext *cx; /* null implies nothing pushed */ CallStack *cs; - jsval *vp; + Value *vp; JSStackFrame *fp; JSStackFrame *down; public: ExecuteFrameGuard(); JS_REQUIRES_STACK ~ExecuteFrameGuard(); - jsval *getvp() const { return vp; } + Value *getvp() const { return vp; } JSStackFrame *getFrame() const { return fp; } }; @@ -563,11 +564,11 @@ class ExecuteFrameGuard * down down down * * Moreover, the bytes in the following ranges form a contiguous array of - * jsvals that are marked during GC: + * Values that are marked during GC: * 1. between a callstack and its first frame * 2. between two adjacent frames in a callstack * 3. between a callstack's current frame and (if fp->regs) fp->regs->sp - * Thus, the VM must ensure that all such jsvals are safe to be marked. + * Thus, the VM must ensure that all such Values are safe to be marked. * * An empty callstack roots the initial slots before the initial frame is * pushed and after the initial frame has been popped (perhaps to be followed @@ -608,16 +609,16 @@ class ExecuteFrameGuard */ class StackSpace { - jsval *base; + Value *base; #ifdef XP_WIN - mutable jsval *commitEnd; + mutable Value *commitEnd; #endif - jsval *end; + Value *end; CallStack *currentCallStack; /* Although guards are friends, XGuard should only call popX(). */ friend class InvokeArgsGuard; - JS_REQUIRES_STACK inline void popInvokeArgs(JSContext *cx, jsval *vp); + JS_REQUIRES_STACK inline void popInvokeArgs(JSContext *cx, Value *vp); friend class InvokeFrameGuard; JS_REQUIRES_STACK void popInvokeFrame(JSContext *cx, CallStack *maybecs); friend class ExecuteFrameGuard; @@ -625,7 +626,7 @@ class StackSpace /* Return a pointer to the first unused slot. */ JS_REQUIRES_STACK - inline jsval *firstUnused() const; + inline Value *firstUnused() const; inline void assertIsCurrent(JSContext *cx) const; #ifdef DEBUG @@ -636,18 +637,18 @@ class StackSpace * Allocate nvals on the top of the stack, report error on failure. * N.B. the caller must ensure |from == firstUnused()|. */ - inline bool ensureSpace(JSContext *maybecx, jsval *from, ptrdiff_t nvals) const; + inline bool ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const; #ifdef XP_WIN /* Commit more memory from the reserved stack space. */ - JS_FRIEND_API(bool) bumpCommit(jsval *from, ptrdiff_t nvals) const; + JS_FRIEND_API(bool) bumpCommit(Value *from, ptrdiff_t nvals) const; #endif public: static const size_t CAPACITY_VALS = 512 * 1024; - static const size_t CAPACITY_BYTES = CAPACITY_VALS * sizeof(jsval); + static const size_t CAPACITY_BYTES = CAPACITY_VALS * sizeof(Value); static const size_t COMMIT_VALS = 16 * 1024; - static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(jsval); + static const size_t COMMIT_BYTES = COMMIT_VALS * sizeof(Value); /* Kept as a member of JSThreadData; cannot use constructor/destructor. */ bool init(); @@ -730,7 +731,7 @@ class StackSpace * call pushInlineFrame/popInlineFrame. */ JS_REQUIRES_STACK - inline JSStackFrame *getInlineFrame(JSContext *cx, jsval *sp, + inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp, uintN nmissing, uintN nfixed) const; JS_REQUIRES_STACK @@ -775,7 +776,7 @@ class FrameRegsIter { CallStack *curcs; JSStackFrame *curfp; - jsval *cursp; + Value *cursp; jsbytecode *curpc; public: @@ -785,7 +786,7 @@ class FrameRegsIter FrameRegsIter &operator++(); JSStackFrame *fp() const { return curfp; } - jsval *sp() const { return cursp; } + Value *sp() const { return cursp; } jsbytecode *pc() const { return curpc; } }; @@ -1134,7 +1135,7 @@ struct GCPtrHasher typedef void *Lookup; static HashNumber hash(void *key) { - return HashNumber(uintptr_t(key) >> JSVAL_TAGBITS); + return HashNumber(uintptr_t(key) >> JS_GCTHING_ZEROBITS); } static bool match(void *l, void *k) { @@ -1142,25 +1143,41 @@ struct GCPtrHasher } }; -typedef HashMap GCRoots; typedef HashMap GCLocks; +struct RootInfo { + RootInfo() {} + RootInfo(const char *name, JSGCRootType type) : name(name), type(type) {} + const char *name; + JSGCRootType type; +}; + +typedef js::HashMap, + js::SystemAllocPolicy> RootedValueMap; + +/* If HashNumber grows, need to change WrapperHasher. */ +JS_STATIC_ASSERT(sizeof(HashNumber) == 4); + struct WrapperHasher { - typedef jsval Lookup; - - static HashNumber hash(jsval key) { - return GCPtrHasher::hash(JSVAL_TO_GCTHING(key)); + typedef Value Lookup; + + static HashNumber hash(Value key) { + uint64 bits = JSVAL_BITS(Jsvalify(key)); + return (uint32)bits ^ (uint32)(bits >> 32); } - static bool match(jsval l, jsval k) { + static bool match(const Value &l, const Value &k) { return l == k; } }; -typedef HashMap WrapperMap; +typedef HashMap WrapperMap; class AutoValueVector; +class AutoIdVector; } /* namespace js */ @@ -1175,13 +1192,13 @@ struct JSCompartment { bool init(); - bool wrap(JSContext *cx, jsval *vp); + bool wrap(JSContext *cx, js::Value *vp); bool wrap(JSContext *cx, JSString **strp); bool wrap(JSContext *cx, JSObject **objp); bool wrapId(JSContext *cx, jsid *idp); - bool wrap(JSContext *cx, JSPropertyOp *op); - bool wrap(JSContext *cx, JSPropertyDescriptor *desc); - bool wrap(JSContext *cx, js::AutoValueVector &props); + bool wrap(JSContext *cx, js::PropertyOp *op); + bool wrap(JSContext *cx, js::PropertyDescriptor *desc); + bool wrap(JSContext *cx, js::AutoIdVector &props); bool wrapException(JSContext *cx); void sweep(JSContext *cx); @@ -1221,8 +1238,7 @@ struct JSRuntime { JSGCArena *gcEmptyArenaList; #endif JSGCArenaList gcArenaList[FINALIZE_LIMIT]; - JSGCDoubleArenaList gcDoubleArenaList; - js::GCRoots gcRootsHash; + js::RootedValueMap gcRootsHash; js::GCLocks gcLocksHash; jsrefcount gcKeepAtoms; size_t gcBytes; @@ -1296,9 +1312,9 @@ struct JSRuntime { void *gcExtraRootsData; /* Well-known numbers held for use by this runtime's contexts. */ - jsval NaNValue; - jsval negativeInfinityValue; - jsval positiveInfinityValue; + js::Value NaNValue; + js::Value negativeInfinityValue; + js::Value positiveInfinityValue; js::DeflatedStringCache *deflatedStringCache; @@ -1685,7 +1701,7 @@ struct JSContext /* * cx->resolvingTable is non-null and non-empty if we are initializing * standard classes lazily, or if we are otherwise recursing indirectly - * from js_LookupProperty through a JSClass.resolve hook. It is used to + * from js_LookupProperty through a Class.resolve hook. It is used to * limit runaway recursion (see jsapi.c and jsobj.c). */ JSDHashTable *resolvingTable; @@ -1701,7 +1717,7 @@ struct JSContext /* Exception state -- the exception member is a GC root by definition. */ JSPackedBool throwing; /* is there a pending exception? */ - jsval exception; /* most-recently-thrown exception */ + js::Value exception; /* most-recently-thrown exception */ /* Limit pointer for checking native stack consumption during recursion. */ jsuword stackLimit; @@ -1728,7 +1744,7 @@ struct JSContext private: friend class js::StackSpace; - friend JSBool js_Interpret(JSContext *); + friend bool js::Interpret(JSContext *); /* 'fp' and 'regs' must only be changed by calling these functions. */ void setCurrentFrame(JSStackFrame *fp) { @@ -1799,7 +1815,7 @@ struct JSContext /* Return whether this context has an active callstack. */ bool hasActiveCallStack() const { assertCallStacksInSync(); - return fp; + return !!fp; } /* Assuming there is an active callstack, return it. */ @@ -1869,7 +1885,7 @@ struct JSContext int64 rngSeed; /* Location to stash the iteration value between JSOP_MOREITER and JSOP_FOR*. */ - jsval iterValue; + js::Value iterValue; #ifdef JS_TRACER /* @@ -2070,8 +2086,8 @@ struct JSContext #ifdef DEBUG void assertValidStackDepth(uintN depth) { - JS_ASSERT(0 <= regs->sp - StackBase(fp)); - JS_ASSERT(depth <= uintptr_t(regs->sp - StackBase(fp))); + JS_ASSERT(0 <= regs->sp - fp->base()); + JS_ASSERT(depth <= uintptr_t(regs->sp - fp->base())); } #else void assertValidStackDepth(uintN /*depth*/) {} @@ -2116,7 +2132,7 @@ JSStackFrame::pc(JSContext *cx) const namespace js { JS_ALWAYS_INLINE void -StackSpace::popInvokeArgs(JSContext *cx, jsval *vp) +StackSpace::popInvokeArgs(JSContext *cx, Value *vp) { JS_ASSERT(!currentCallStack->inContext()); currentCallStack = currentCallStack->getPreviousInThread(); @@ -2128,7 +2144,7 @@ InvokeArgsGuard::InvokeArgsGuard() {} JS_ALWAYS_INLINE -InvokeArgsGuard::InvokeArgsGuard(jsval *vp, uintN argc) +InvokeArgsGuard::InvokeArgsGuard(Value *vp, uintN argc) : cx(NULL), cs(NULL), vp(vp), argc(argc) {} @@ -2218,7 +2234,7 @@ class AutoGCRooter { /* * Discriminates actual subclass of this being used. If non-negative, the - * subclass roots an array of jsvals of the length stored in this field. + * subclass roots an array of values of the length stored in this field. * If negative, meaning is indicated by the corresponding value in the enum * below. Any other negative value indicates some deeper problem such as * memory corruption. @@ -2235,13 +2251,15 @@ class AutoGCRooter { SCRIPT = -5, /* js::AutoScriptRooter */ ENUMERATOR = -6, /* js::AutoEnumStateRooter */ IDARRAY = -7, /* js::AutoIdArray */ - DESCRIPTORS = -8, /* js::AutoDescriptorArray */ + DESCRIPTORS = -8, /* js::AutoPropDescArrayRooter */ NAMESPACES = -9, /* js::AutoNamespaceArray */ XML = -10, /* js::AutoXMLRooter */ OBJECT = -11, /* js::AutoObjectRooter */ ID = -12, /* js::AutoIdRooter */ - VECTOR = -13, /* js::AutoValueVector */ - DESCRIPTOR = -14 /* js::AutoDescriptor */ + VALVECTOR = -13, /* js::AutoValueVector */ + DESCRIPTOR = -14, /* js::AutoPropertyDescriptorRooter */ + STRING = -15, /* js::AutoStringRooter */ + IDVECTOR = -16 /* js::AutoIdVector */ }; private: @@ -2276,61 +2294,67 @@ class AutoPreserveWeakRoots : private AutoGCRooter class AutoValueRooter : private AutoGCRooter { public: - explicit AutoValueRooter(JSContext *cx, jsval v = JSVAL_NULL + explicit AutoValueRooter(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, JSVAL), val(js::NullValue()) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + AutoValueRooter(JSContext *cx, const Value &v + JS_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, JSVAL), val(v) { JS_GUARD_OBJECT_NOTIFIER_INIT; } - AutoValueRooter(JSContext *cx, JSString *str + + AutoValueRooter(JSContext *cx, jsval v JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, JSVAL), val(STRING_TO_JSVAL(str)) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - } - AutoValueRooter(JSContext *cx, JSObject *obj - JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, JSVAL), val(OBJECT_TO_JSVAL(obj)) + : AutoGCRooter(cx, JSVAL), val(js::Valueify(v)) { JS_GUARD_OBJECT_NOTIFIER_INIT; } - void set(jsval v) { + /* + * If you are looking for Object* overloads, use AutoObjectRooter instead; + * rooting Object*s as a js::Value requires discerning whether or not it is + * a function object. Also, AutoObjectRooter is smaller. + */ + + void set(Value v) { JS_ASSERT(tag == JSVAL); val = v; } - void setObject(JSObject *obj) { + void set(jsval v) { JS_ASSERT(tag == JSVAL); - val = OBJECT_TO_JSVAL(obj); + val = js::Valueify(v); } - void setString(JSString *str) { - JS_ASSERT(tag == JSVAL); - JS_ASSERT(str); - val = STRING_TO_JSVAL(str); - } - - void setDouble(jsdouble *dp) { - JS_ASSERT(tag == JSVAL); - JS_ASSERT(dp); - val = DOUBLE_TO_JSVAL(dp); - } - - jsval value() const { + const Value &value() const { JS_ASSERT(tag == JSVAL); return val; } - jsval *addr() { + Value *addr() { JS_ASSERT(tag == JSVAL); return &val; } + const jsval &jsval_value() const { + JS_ASSERT(tag == JSVAL); + return Jsvalify(val); + } + + jsval *jsval_addr() { + JS_ASSERT(tag == JSVAL); + return Jsvalify(&val); + } + friend void AutoGCRooter::trace(JSTracer *trc); private: - jsval val; + Value val; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; @@ -2362,9 +2386,37 @@ class AutoObjectRooter : private AutoGCRooter { JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; +class AutoStringRooter : private AutoGCRooter { + public: + AutoStringRooter(JSContext *cx, JSString *str = NULL + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, STRING), str(str) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + void setString(JSString *str) { + this->str = str; + } + + JSString * string() const { + return str; + } + + JSString ** addr() { + return &str; + } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + JSString *str; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + class AutoArrayRooter : private AutoGCRooter { public: - AutoArrayRooter(JSContext *cx, size_t len, jsval *vec + AutoArrayRooter(JSContext *cx, size_t len, Value *vec JS_GUARD_OBJECT_NOTIFIER_PARAM) : AutoGCRooter(cx, len), array(vec) { @@ -2372,17 +2424,25 @@ class AutoArrayRooter : private AutoGCRooter { JS_ASSERT(tag >= 0); } + AutoArrayRooter(JSContext *cx, size_t len, jsval *vec + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, len), array(Valueify(vec)) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + JS_ASSERT(tag >= 0); + } + void changeLength(size_t newLength) { tag = ptrdiff_t(newLength); JS_ASSERT(tag >= 0); } - void changeArray(jsval *newArray, size_t newLength) { + void changeArray(Value *newArray, size_t newLength) { changeLength(newLength); array = newArray; } - jsval *array; + Value *array; friend void AutoGCRooter::trace(JSTracer *trc); @@ -2431,23 +2491,23 @@ class AutoIdRooter : private AutoGCRooter public: explicit AutoIdRooter(JSContext *cx, jsid id = INT_TO_JSID(0) JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, ID), idval(id) + : AutoGCRooter(cx, ID), id_(id) { JS_GUARD_OBJECT_NOTIFIER_INIT; } jsid id() { - return idval; + return id_; } jsid * addr() { - return &idval; + return &id_; } friend void AutoGCRooter::trace(JSTracer *trc); private: - jsid idval; + jsid id_; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; @@ -2500,14 +2560,14 @@ class AutoEnumStateRooter : private AutoGCRooter public: AutoEnumStateRooter(JSContext *cx, JSObject *obj JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, ENUMERATOR), obj(obj), stateValue(JSVAL_NULL) + : AutoGCRooter(cx, ENUMERATOR), obj(obj), stateValue() { JS_GUARD_OBJECT_NOTIFIER_INIT; JS_ASSERT(obj); } ~AutoEnumStateRooter() { - if (!JSVAL_IS_NULL(stateValue)) { + if (!stateValue.isNull()) { #ifdef DEBUG JSBool ok = #endif @@ -2518,8 +2578,8 @@ class AutoEnumStateRooter : private AutoGCRooter friend void AutoGCRooter::trace(JSTracer *trc); - jsval state() const { return stateValue; } - jsval * addr() { return &stateValue; } + const Value &state() const { return stateValue; } + Value *addr() { return &stateValue; } protected: void trace(JSTracer *trc) { @@ -2529,7 +2589,7 @@ class AutoEnumStateRooter : private AutoGCRooter JSObject * const obj; private: - jsval stateValue; + Value stateValue; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; @@ -2753,7 +2813,7 @@ extern JS_FRIEND_API(JSContext *) js_NextActiveContext(JSRuntime *, JSContext *); /* - * JSClass.resolve and watchpoint recursion damping machinery. + * Class.resolve and watchpoint recursion damping machinery. */ extern JSBool js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag, @@ -2833,11 +2893,11 @@ js_ReportIsNotDefined(JSContext *cx, const char *name); * Report an attempt to access the property of a null or undefined value (v). */ extern JSBool -js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, jsval v, +js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, const js::Value &v, JSString *fallback); extern void -js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg); +js_ReportMissingArg(JSContext *cx, const js::Value &v, uintN arg); /* * Report error using js_DecompileValueGenerator(cx, spindex, v, fallback) as @@ -2846,7 +2906,7 @@ js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg); */ extern JSBool js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber, - intN spindex, jsval v, JSString *fallback, + intN spindex, const js::Value &v, JSString *fallback, const char *arg1, const char *arg2); #define js_ReportValueError(cx,errorNumber,spindex,v,fallback) \ @@ -2931,7 +2991,7 @@ LeaveTrace(JSContext *cx) static JS_INLINE void LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj) { - if (!obj->fslots[JSSLOT_PARENT]) + if (obj->fslots[JSSLOT_PARENT].isNull()) LeaveTrace(cx); } @@ -2946,7 +3006,10 @@ CanLeaveTrace(JSContext *cx) #endif } -} /* namespace js */ +extern void +SetPendingException(JSContext *cx, const Value &v); + +} /* namespace js */ /* * Get the current cx->fp, first lazily instantiating stack frames if needed. @@ -3015,20 +3078,21 @@ class AutoValueVector : private AutoGCRooter public: explicit AutoValueVector(JSContext *cx JS_GUARD_OBJECT_NOTIFIER_PARAM) - : AutoGCRooter(cx, VECTOR), vector(cx) + : AutoGCRooter(cx, VALVECTOR), vector(cx) { JS_GUARD_OBJECT_NOTIFIER_INIT; } size_t length() const { return vector.length(); } - bool append(jsval v) { return vector.append(v); } - bool append(JSString *str) { return append(STRING_TO_JSVAL(str)); } - bool append(JSObject *obj) { return append(OBJECT_TO_JSVAL(obj)); } - bool append(jsdouble *dp) { return append(DOUBLE_TO_JSVAL(dp)); } + bool append(const Value &v) { return vector.append(v); } void popBack() { vector.popBack(); } + bool growBy(size_t inc) { + return vector.growBy(inc); + } + bool resize(size_t newLength) { return vector.resize(newLength); } @@ -3037,29 +3101,113 @@ class AutoValueVector : private AutoGCRooter return vector.reserve(newLength); } - jsval &operator[](size_t i) { return vector[i]; } - jsval operator[](size_t i) const { return vector[i]; } + Value &operator[](size_t i) { return vector[i]; } + const Value &operator[](size_t i) const { return vector[i]; } - const jsval *begin() const { return vector.begin(); } - jsval *begin() { return vector.begin(); } + const Value *begin() const { return vector.begin(); } + Value *begin() { return vector.begin(); } - const jsval *end() const { return vector.end(); } - jsval *end() { return vector.end(); } + const Value *end() const { return vector.end(); } + Value *end() { return vector.end(); } - jsval back() const { return end()[-1]; } + const Value &back() const { return vector.back(); } friend void AutoGCRooter::trace(JSTracer *trc); - + private: - Vector vector; + Vector vector; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +class AutoIdVector : private AutoGCRooter +{ + public: + explicit AutoIdVector(JSContext *cx + JS_GUARD_OBJECT_NOTIFIER_PARAM) + : AutoGCRooter(cx, IDVECTOR), vector(cx) + { + JS_GUARD_OBJECT_NOTIFIER_INIT; + } + + size_t length() const { return vector.length(); } + + bool append(jsid id) { return vector.append(id); } + + void popBack() { vector.popBack(); } + + bool growBy(size_t inc) { + return vector.growBy(inc); + } + + bool resize(size_t newLength) { + return vector.resize(newLength); + } + + bool reserve(size_t newLength) { + return vector.reserve(newLength); + } + + jsid &operator[](size_t i) { return vector[i]; } + const jsid &operator[](size_t i) const { return vector[i]; } + + const jsid *begin() const { return vector.begin(); } + jsid *begin() { return vector.begin(); } + + const jsid *end() const { return vector.end(); } + jsid *end() { return vector.end(); } + + const jsid &back() const { return vector.back(); } + + friend void AutoGCRooter::trace(JSTracer *trc); + + private: + Vector vector; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; JSIdArray * NewIdArray(JSContext *cx, jsint length); +static JS_ALWAYS_INLINE void +MakeValueRangeGCSafe(Value *vec, uintN len) +{ + PodZero(vec, len); } +static JS_ALWAYS_INLINE void +MakeValueRangeGCSafe(Value *beg, Value *end) +{ + PodZero(beg, end - beg); +} + +static JS_ALWAYS_INLINE void +SetValueRangeToUndefined(Value *beg, Value *end) +{ + for (Value *v = beg; v != end; ++v) + v->setUndefined(); +} + +static JS_ALWAYS_INLINE void +SetValueRangeToUndefined(Value *vec, uintN len) +{ + return SetValueRangeToUndefined(vec, vec + len); +} + +static JS_ALWAYS_INLINE void +SetValueRangeToNull(Value *beg, Value *end) +{ + for (Value *v = beg; v != end; ++v) + v->setNull(); +} + +static JS_ALWAYS_INLINE void +SetValueRangeToNull(Value *vec, uintN len) +{ + return SetValueRangeToNull(vec, vec + len); +} + +} /* namespace js */ + #ifdef _MSC_VER #pragma warning(pop) #pragma warning(pop) diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index fdcc13af9edc..0249dbb5ede0 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -63,7 +63,7 @@ CallStack::getCurrentFrame() const return isSuspended() ? getSuspendedFrame() : cx->fp; } -JS_REQUIRES_STACK inline jsval * +JS_REQUIRES_STACK inline Value * StackSpace::firstUnused() const { CallStack *ccs = currentCallStack; @@ -89,7 +89,7 @@ StackSpace::assertIsCurrent(JSContext *cx) const } JS_ALWAYS_INLINE bool -StackSpace::ensureSpace(JSContext *maybecx, jsval *from, ptrdiff_t nvals) const +StackSpace::ensureSpace(JSContext *maybecx, Value *from, ptrdiff_t nvals) const { JS_ASSERT(from == firstUnused()); #ifdef XP_WIN @@ -127,7 +127,7 @@ StackSpace::ensureEnoughSpaceToEnterTrace() } JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame * -StackSpace::getInlineFrame(JSContext *cx, jsval *sp, +StackSpace::getInlineFrame(JSContext *cx, Value *sp, uintN nmissing, uintN nfixed) const { assertIsCurrent(cx); @@ -178,7 +178,7 @@ StackSpace::popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down) void AutoIdArray::trace(JSTracer *trc) { JS_ASSERT(tag == IDARRAY); - js::TraceValues(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray"); + MarkIdRange(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray"); } class AutoNamespaceArray : protected AutoGCRooter { @@ -239,20 +239,36 @@ class CompartmentChecker check(obj->getCompartment(context)); } + void check(const js::Value &v) { + if (v.isObject()) + check(&v.toObject()); + } + void check(jsval v) { - if (!JSVAL_IS_PRIMITIVE(v)) - check(JSVAL_TO_OBJECT(v)); + check(Valueify(v)); } void check(const ValueArray &arr) { for (size_t i = 0; i < arr.length; i++) check(arr.array[i]); } + + void check(const JSValueArray &arr) { + for (size_t i = 0; i < arr.length; i++) + check(arr.array[i]); + } + + void check(jsid id) { + if (JSID_IS_OBJECT(id)) + check(JSID_TO_OBJECT(id)); + } void check(JSIdArray *ida) { if (ida) { - for (jsint i = 0; i < ida->length; i++) - check(ID_TO_VALUE(ida->vector[i])); + for (jsint i = 0; i < ida->length; i++) { + if (JSID_IS_OBJECT(ida->vector[i])) + check(ida->vector[i]); + } } } @@ -333,7 +349,7 @@ assertSameCompartment(JSContext *cx, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) #undef START_ASSERT_SAME_COMPARTMENT inline JSBool -callJSNative(JSContext *cx, JSNative native, JSObject *thisobj, uintN argc, jsval *argv, jsval *rval) +callJSNative(JSContext *cx, js::Native native, JSObject *thisobj, uintN argc, js::Value *argv, js::Value *rval) { assertSameCompartment(cx, thisobj, ValueArray(argv, argc)); JSBool ok = native(cx, thisobj, argc, argv, rval); @@ -343,7 +359,7 @@ callJSNative(JSContext *cx, JSNative native, JSObject *thisobj, uintN argc, jsva } inline JSBool -callJSFastNative(JSContext *cx, JSFastNative native, uintN argc, jsval *vp) +callJSFastNative(JSContext *cx, js::FastNative native, uintN argc, js::Value *vp) { assertSameCompartment(cx, ValueArray(vp, argc + 2)); JSBool ok = native(cx, argc, vp); @@ -353,22 +369,22 @@ callJSFastNative(JSContext *cx, JSFastNative native, uintN argc, jsval *vp) } inline JSBool -callJSPropertyOp(JSContext *cx, JSPropertyOp op, JSObject *obj, jsval idval, jsval *vp) +callJSPropertyOp(JSContext *cx, js::PropertyOp op, JSObject *obj, jsid id, js::Value *vp) { - assertSameCompartment(cx, obj, idval, *vp); - JSBool ok = op(cx, obj, idval, vp); + assertSameCompartment(cx, obj, id, *vp); + JSBool ok = op(cx, obj, id, vp); if (ok) assertSameCompartment(cx, obj, *vp); return ok; } inline JSBool -callJSPropertyOpSetter(JSContext *cx, JSPropertyOp op, JSObject *obj, jsval idval, jsval *vp) +callJSPropertyOpSetter(JSContext *cx, js::PropertyOp op, JSObject *obj, jsid id, js::Value *vp) { - assertSameCompartment(cx, obj, idval, *vp); - return op(cx, obj, idval, vp); + assertSameCompartment(cx, obj, id, *vp); + return op(cx, obj, id, vp); } -} +} /* namespace js */ #endif /* jscntxtinlines_h___ */ diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 25f64b6f11f7..aa4a790a88e8 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -481,12 +481,12 @@ msFromTime(jsdouble t) * Other Support routines and definitions */ -JSClass js_DateClass = { +Class js_DateClass = { js_Date_str, JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_FIXED_RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Date), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; @@ -565,7 +565,7 @@ date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour, #define MAXARGS 7 static JSBool -date_msecFromArgs(JSContext *cx, uintN argc, jsval *argv, jsdouble *rval) +date_msecFromArgs(JSContext *cx, uintN argc, Value *argv, jsdouble *rval) { uintN loop; jsdouble array[MAXARGS]; @@ -605,7 +605,7 @@ date_msecFromArgs(JSContext *cx, uintN argc, jsval *argv, jsdouble *rval) * See ECMA 15.9.4.[3-10]; */ static JSBool -date_UTC(JSContext *cx, uintN argc, jsval *vp) +date_UTC(JSContext *cx, uintN argc, Value *vp) { jsdouble msec_time; @@ -614,7 +614,8 @@ date_UTC(JSContext *cx, uintN argc, jsval *vp) msec_time = TIMECLIP(msec_time); - return js_NewNumberInRootedValue(cx, msec_time, vp); + vp->setNumber(msec_time); + return JS_TRUE; } /* @@ -1141,26 +1142,27 @@ syntax: } static JSBool -date_parse(JSContext *cx, uintN argc, jsval *vp) +date_parse(JSContext *cx, uintN argc, Value *vp) { JSString *str; jsdouble result; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return true; } str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - vp[2] = STRING_TO_JSVAL(str); + vp[2].setString(str); if (!date_parseString(str, &result, cx)) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return true; } result = TIMECLIP(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return true; } static inline jsdouble @@ -1170,9 +1172,10 @@ NowAsMillis() } static JSBool -date_now(JSContext *cx, uintN argc, jsval *vp) +date_now(JSContext *cx, uintN argc, Value *vp) { - return js_NewDoubleInRootedValue(cx, NowAsMillis(), vp); + vp->setDouble(NowAsMillis()); + return JS_TRUE; } #ifdef JS_TRACER @@ -1188,38 +1191,37 @@ date_now_tn(JSContext*) * Date type. */ static JSBool -GetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) +GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp) { - if (!JS_InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL)) + if (!InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL)) return JS_FALSE; - *dp = *JSVAL_TO_DOUBLE(obj->getDateUTCTime()); + *dp = obj->getDateUTCTime().toNumber(); return JS_TRUE; } static void -SetDateToNaN(JSContext *cx, JSObject *obj, jsval *vp = NULL) +SetDateToNaN(JSContext *cx, JSObject *obj, Value *vp = NULL) { JS_ASSERT(obj->getClass() == &js_DateClass); obj->setDateLocalTime(cx->runtime->NaNValue); obj->setDateUTCTime(cx->runtime->NaNValue); if (vp) - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); } /* * Set UTC time to a given time and invalidate cached local time. */ static JSBool -SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, jsval *vp = NULL) +SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, Value *vp = NULL) { JS_ASSERT(obj->getClass() == &js_DateClass); obj->setDateLocalTime(cx->runtime->NaNValue); - if (!js_NewDoubleInRootedValue(cx, t, obj->addressOfDateUTCTime())) - return false; + obj->setDateUTCTime(DoubleValue(t)); if (vp) - *vp = obj->getDateUTCTime(); + vp->setDouble(t); return true; } @@ -1228,22 +1230,20 @@ SetUTCTime(JSContext *cx, JSObject *obj, jsdouble t, jsval *vp = NULL) * (e.g., NaN), the local time slot is set to the UTC time without conversion. */ static JSBool -GetAndCacheLocalTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) +GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp) { - if (!obj || !JS_InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL)) + if (!obj || !InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL)) return false; - jsval *slotp = obj->addressOfDateLocalTime(); - jsdouble result = *JSVAL_TO_DOUBLE(*slotp); + jsdouble result = obj->getDateLocalTime().toNumber(); if (JSDOUBLE_IS_NaN(result)) { - result = *JSVAL_TO_DOUBLE(obj->getDateUTCTime()); + result = obj->getDateUTCTime().toDouble(); /* if result is NaN, it couldn't be finite. */ if (JSDOUBLE_IS_FINITE(result)) result = LocalTime(result, cx); - if (!js_NewDoubleInRootedValue(cx, result, slotp)) - return false; + obj->setDateLocalTime(DoubleValue(result)); } *dp = result; @@ -1254,20 +1254,22 @@ GetAndCacheLocalTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) * See ECMA 15.9.5.4 thru 15.9.5.23 */ static JSBool -date_getTime(JSContext *cx, uintN argc, jsval *vp) +date_getTime(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - return GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result) && - js_NewNumberInRootedValue(cx, result, vp); + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) + return JS_FALSE; + vp->setNumber(result); + return JS_TRUE; } static JSBool -GetYear(JSContext *cx, JSBool fullyear, jsval *vp) +GetYear(JSContext *cx, JSBool fullyear, Value *vp) { jsdouble result; - if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) { @@ -1278,214 +1280,228 @@ GetYear(JSContext *cx, JSBool fullyear, jsval *vp) result -= 1900; } - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getYear(JSContext *cx, uintN argc, jsval *vp) +date_getYear(JSContext *cx, uintN argc, Value *vp) { return GetYear(cx, JS_FALSE, vp); } static JSBool -date_getFullYear(JSContext *cx, uintN argc, jsval *vp) +date_getFullYear(JSContext *cx, uintN argc, Value *vp) { return GetYear(cx, JS_TRUE, vp); } static JSBool -date_getUTCFullYear(JSContext *cx, uintN argc, jsval *vp) +date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = YearFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getMonth(JSContext *cx, uintN argc, jsval *vp) +date_getMonth(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = MonthFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getUTCMonth(JSContext *cx, uintN argc, jsval *vp) +date_getUTCMonth(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = MonthFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getDate(JSContext *cx, uintN argc, jsval *vp) +date_getDate(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = DateFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getUTCDate(JSContext *cx, uintN argc, jsval *vp) +date_getUTCDate(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = DateFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getDay(JSContext *cx, uintN argc, jsval *vp) +date_getDay(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = WeekDay(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getUTCDay(JSContext *cx, uintN argc, jsval *vp) +date_getUTCDay(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = WeekDay(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getHours(JSContext *cx, uintN argc, jsval *vp) +date_getHours(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = HourFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getUTCHours(JSContext *cx, uintN argc, jsval *vp) +date_getUTCHours(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = HourFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getMinutes(JSContext *cx, uintN argc, jsval *vp) +date_getMinutes(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetAndCacheLocalTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = MinFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getUTCMinutes(JSContext *cx, uintN argc, jsval *vp) +date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = MinFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } /* Date.getSeconds is mapped to getUTCSeconds */ static JSBool -date_getUTCSeconds(JSContext *cx, uintN argc, jsval *vp) +date_getUTCSeconds(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = SecFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } /* Date.getMilliseconds is mapped to getUTCMilliseconds */ static JSBool -date_getUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp) +date_getUTCMilliseconds(JSContext *cx, uintN argc, Value *vp) { jsdouble result; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = msFromTime(result); - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_getTimezoneOffset(JSContext *cx, uintN argc, jsval *vp) +date_getTimezoneOffset(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; jsdouble utctime, localtime, result; - obj = JS_THIS_OBJECT(cx, vp); + obj = ComputeThisFromVp(cx, vp); if (!GetUTCTime(cx, obj, vp, &utctime)) return JS_FALSE; if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime)) @@ -1497,14 +1513,15 @@ date_getTimezoneOffset(JSContext *cx, uintN argc, jsval *vp) * daylight savings time. */ result = (utctime - localtime) / msPerMinute; - return js_NewNumberInRootedValue(cx, result, vp); + vp->setNumber(result); + return JS_TRUE; } static JSBool -date_setTime(JSContext *cx, uintN argc, jsval *vp) +date_setTime(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj = JS_THIS_OBJECT(cx, vp); - if (!JS_InstanceOf(cx, obj, &js_DateClass, vp + 2)) + JSObject *obj = ComputeThisFromVp(cx, vp); + if (!InstanceOf(cx, obj, &js_DateClass, vp + 2)) return false; if (argc == 0) { @@ -1520,10 +1537,10 @@ date_setTime(JSContext *cx, uintN argc, jsval *vp) } static JSBool -date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) +date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp) { JSObject *obj; - jsval *argv; + Value *argv; uintN i; jsdouble args[4], *argp, *stop; jsdouble hour, min, sec, msec; @@ -1532,13 +1549,15 @@ date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) jsdouble msec_time; jsdouble result; - obj = JS_THIS_OBJECT(cx, vp); + obj = ComputeThisFromVp(cx, vp); if (!GetUTCTime(cx, obj, vp, &result)) return false; /* just return NaN if the date is already NaN */ - if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberInRootedValue(cx, result, vp); + if (!JSDOUBLE_IS_FINITE(result)) { + vp->setNumber(result); + return true; + } /* * Satisfy the ECMA rule that if a function is called with @@ -1609,65 +1628,65 @@ date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) } static JSBool -date_setMilliseconds(JSContext *cx, uintN argc, jsval *vp) +date_setMilliseconds(JSContext *cx, uintN argc, Value *vp) { return date_makeTime(cx, 1, JS_TRUE, argc, vp); } static JSBool -date_setUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp) +date_setUTCMilliseconds(JSContext *cx, uintN argc, Value *vp) { return date_makeTime(cx, 1, JS_FALSE, argc, vp); } static JSBool -date_setSeconds(JSContext *cx, uintN argc, jsval *vp) +date_setSeconds(JSContext *cx, uintN argc, Value *vp) { return date_makeTime(cx, 2, JS_TRUE, argc, vp); } static JSBool -date_setUTCSeconds(JSContext *cx, uintN argc, jsval *vp) +date_setUTCSeconds(JSContext *cx, uintN argc, Value *vp) { return date_makeTime(cx, 2, JS_FALSE, argc, vp); } static JSBool -date_setMinutes(JSContext *cx, uintN argc, jsval *vp) +date_setMinutes(JSContext *cx, uintN argc, Value *vp) { return date_makeTime(cx, 3, JS_TRUE, argc, vp); } static JSBool -date_setUTCMinutes(JSContext *cx, uintN argc, jsval *vp) +date_setUTCMinutes(JSContext *cx, uintN argc, Value *vp) { return date_makeTime(cx, 3, JS_FALSE, argc, vp); } static JSBool -date_setHours(JSContext *cx, uintN argc, jsval *vp) +date_setHours(JSContext *cx, uintN argc, Value *vp) { return date_makeTime(cx, 4, JS_TRUE, argc, vp); } static JSBool -date_setUTCHours(JSContext *cx, uintN argc, jsval *vp) +date_setUTCHours(JSContext *cx, uintN argc, Value *vp) { return date_makeTime(cx, 4, JS_FALSE, argc, vp); } static JSBool -date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) +date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp) { JSObject *obj; - jsval *argv; + Value *argv; uintN i; jsdouble lorutime; /* local or UTC version of *date */ jsdouble args[3], *argp, *stop; jsdouble year, month, day; jsdouble result; - obj = JS_THIS_OBJECT(cx, vp); + obj = ComputeThisFromVp(cx, vp); if (!GetUTCTime(cx, obj, vp, &result)) return false; @@ -1694,8 +1713,10 @@ date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) /* return NaN if date is NaN and we're not setting the year, * If we are, use 0 as the time. */ if (!(JSDOUBLE_IS_FINITE(result))) { - if (maxargs < 3) - return js_NewNumberInRootedValue(cx, result, vp); + if (maxargs < 3) { + vp->setDouble(result); + return true; + } lorutime = +0.; } else { lorutime = local ? LocalTime(result, cx) : result; @@ -1728,45 +1749,45 @@ date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) } static JSBool -date_setDate(JSContext *cx, uintN argc, jsval *vp) +date_setDate(JSContext *cx, uintN argc, Value *vp) { return date_makeDate(cx, 1, JS_TRUE, argc, vp); } static JSBool -date_setUTCDate(JSContext *cx, uintN argc, jsval *vp) +date_setUTCDate(JSContext *cx, uintN argc, Value *vp) { return date_makeDate(cx, 1, JS_FALSE, argc, vp); } static JSBool -date_setMonth(JSContext *cx, uintN argc, jsval *vp) +date_setMonth(JSContext *cx, uintN argc, Value *vp) { return date_makeDate(cx, 2, JS_TRUE, argc, vp); } static JSBool -date_setUTCMonth(JSContext *cx, uintN argc, jsval *vp) +date_setUTCMonth(JSContext *cx, uintN argc, Value *vp) { return date_makeDate(cx, 2, JS_FALSE, argc, vp); } static JSBool -date_setFullYear(JSContext *cx, uintN argc, jsval *vp) +date_setFullYear(JSContext *cx, uintN argc, Value *vp) { return date_makeDate(cx, 3, JS_TRUE, argc, vp); } static JSBool -date_setUTCFullYear(JSContext *cx, uintN argc, jsval *vp) +date_setUTCFullYear(JSContext *cx, uintN argc, Value *vp) { return date_makeDate(cx, 3, JS_FALSE, argc, vp); } static JSBool -date_setYear(JSContext *cx, uintN argc, jsval *vp) +date_setYear(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); jsdouble result; if (!GetUTCTime(cx, obj, vp, &result)) @@ -1838,14 +1859,14 @@ print_iso_string(char* buf, size_t size, jsdouble utctime) } static JSBool -date_utc_format(JSContext *cx, jsval *vp, +date_utc_format(JSContext *cx, Value *vp, void (*printFunc)(char*, size_t, jsdouble)) { char buf[100]; JSString *str; jsdouble utctime; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime)) return JS_FALSE; if (!JSDOUBLE_IS_FINITE(utctime)) { @@ -1856,18 +1877,18 @@ date_utc_format(JSContext *cx, jsval *vp, str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -date_toGMTString(JSContext *cx, uintN argc, jsval *vp) +date_toGMTString(JSContext *cx, uintN argc, Value *vp) { return date_utc_format(cx, vp, print_gmt_string); } static JSBool -date_toISOString(JSContext *cx, uintN argc, jsval *vp) +date_toISOString(JSContext *cx, uintN argc, Value *vp) { return date_utc_format(cx, vp, print_iso_string); } @@ -1900,7 +1921,7 @@ typedef enum formatspec { /* helper function */ static JSBool -date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval) +date_format(JSContext *cx, jsdouble date, formatspec format, Value *rval) { char buf[100]; JSString *str; @@ -2008,12 +2029,12 @@ date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval) str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + rval->setString(str); return JS_TRUE; } static JSBool -date_toLocaleHelper(JSContext *cx, const char *format, jsval *vp) +date_toLocaleHelper(JSContext *cx, const char *format, Value *vp) { JSObject *obj; char buf[100]; @@ -2021,7 +2042,7 @@ date_toLocaleHelper(JSContext *cx, const char *format, jsval *vp) PRMJTime split; jsdouble utctime; - obj = JS_THIS_OBJECT(cx, vp); + obj = ComputeThisFromVp(cx, vp); if (!GetUTCTime(cx, obj, vp, &utctime)) return JS_FALSE; @@ -2055,17 +2076,17 @@ date_toLocaleHelper(JSContext *cx, const char *format, jsval *vp) } if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) - return cx->localeCallbacks->localeToUnicode(cx, buf, vp); + return cx->localeCallbacks->localeToUnicode(cx, buf, Jsvalify(vp)); str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -date_toLocaleString(JSContext *cx, uintN argc, jsval *vp) +date_toLocaleString(JSContext *cx, uintN argc, Value *vp) { /* Use '%#c' for windows, because '%c' is * backward-compatible and non-y2k with msvc; '%#c' requests that a @@ -2081,7 +2102,7 @@ date_toLocaleString(JSContext *cx, uintN argc, jsval *vp) } static JSBool -date_toLocaleDateString(JSContext *cx, uintN argc, jsval *vp) +date_toLocaleDateString(JSContext *cx, uintN argc, Value *vp) { /* Use '%#x' for windows, because '%x' is * backward-compatible and non-y2k with msvc; '%#x' requests that a @@ -2097,13 +2118,13 @@ date_toLocaleDateString(JSContext *cx, uintN argc, jsval *vp) } static JSBool -date_toLocaleTimeString(JSContext *cx, uintN argc, jsval *vp) +date_toLocaleTimeString(JSContext *cx, uintN argc, Value *vp) { return date_toLocaleHelper(cx, "%X", vp); } static JSBool -date_toLocaleFormat(JSContext *cx, uintN argc, jsval *vp) +date_toLocaleFormat(JSContext *cx, uintN argc, Value *vp) { JSString *fmt; const char *fmtbytes; @@ -2114,7 +2135,7 @@ date_toLocaleFormat(JSContext *cx, uintN argc, jsval *vp) fmt = js_ValueToString(cx, vp[2]); if (!fmt) return JS_FALSE; - vp[2] = STRING_TO_JSVAL(fmt); + vp[2].setString(fmt); fmtbytes = js_GetStringBytes(cx, fmt); if (!fmtbytes) return JS_FALSE; @@ -2123,21 +2144,21 @@ date_toLocaleFormat(JSContext *cx, uintN argc, jsval *vp) } static JSBool -date_toTimeString(JSContext *cx, uintN argc, jsval *vp) +date_toTimeString(JSContext *cx, uintN argc, Value *vp) { jsdouble utctime; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime)) return JS_FALSE; return date_format(cx, utctime, FORMATSPEC_TIME, vp); } static JSBool -date_toDateString(JSContext *cx, uintN argc, jsval *vp) +date_toDateString(JSContext *cx, uintN argc, Value *vp) { jsdouble utctime; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime)) return JS_FALSE; return date_format(cx, utctime, FORMATSPEC_DATE, vp); } @@ -2147,13 +2168,13 @@ date_toDateString(JSContext *cx, uintN argc, jsval *vp) #include "jsdtoa.h" static JSBool -date_toSource(JSContext *cx, uintN argc, jsval *vp) +date_toSource(JSContext *cx, uintN argc, Value *vp) { jsdouble utctime; char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes; JSString *str; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime)) return JS_FALSE; numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, buf, sizeof buf, DTOSTR_STANDARD, 0, utctime); @@ -2173,23 +2194,23 @@ date_toSource(JSContext *cx, uintN argc, jsval *vp) js_free(bytes); return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } #endif static JSBool -date_toString(JSContext *cx, uintN argc, jsval *vp) +date_toString(JSContext *cx, uintN argc, Value *vp) { jsdouble utctime; - if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime)) + if (!GetUTCTime(cx, ComputeThisFromVp(cx, vp), vp, &utctime)) return JS_FALSE; return date_format(cx, utctime, FORMATSPEC_FULL, vp); } static JSBool -date_valueOf(JSContext *cx, uintN argc, jsval *vp) +date_valueOf(JSContext *cx, uintN argc, Value *vp) { JSString *str, *number_str; @@ -2277,7 +2298,7 @@ static JSFunctionSpec date_methods[] = { }; JSBool -js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +js_Date(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { /* Date called as function. */ if (!JS_IsConstructing(cx)) @@ -2288,7 +2309,7 @@ js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (argc == 0) { d = NowAsMillis(); } else if (argc == 1) { - if (!JSVAL_IS_STRING(argv[0])) { + if (!argv[0].isString()) { /* the argument is a millisecond number */ if (!ValueToNumber(cx, argv[0], &d)) return JS_FALSE; @@ -2298,7 +2319,7 @@ js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JSString *str = js_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); + argv[0].setString(str); if (!date_parseString(str, &d, cx)) d = js_NaN; @@ -2344,8 +2365,8 @@ js_InitDateClass(JSContext *cx, JSObject *obj) jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom); jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom); if (!js_GetProperty(cx, proto, toUTCStringId, toUTCStringFun.addr()) || - !js_DefineProperty(cx, proto, toGMTStringId, toUTCStringFun.value(), - JS_PropertyStub, JS_PropertyStub, 0)) { + !js_DefineProperty(cx, proto, toGMTStringId, toUTCStringFun.addr(), + PropertyStub, PropertyStub, 0)) { return NULL; } diff --git a/js/src/jsdate.h b/js/src/jsdate.h index 0297443ddceb..6a6c9eb198fe 100644 --- a/js/src/jsdate.h +++ b/js/src/jsdate.h @@ -46,9 +46,7 @@ #include "jsobj.h" -JS_BEGIN_EXTERN_C - -extern JSClass js_DateClass; +extern js::Class js_DateClass; inline bool JSObject::isDate() const @@ -134,8 +132,6 @@ js_IntervalNow(); /* Date constructor native. Exposed only so the JIT can know its address. */ JSBool -js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); - -JS_END_EXTERN_C +js_Date(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv, js::Value *rval); #endif /* jsdate_h___ */ diff --git a/js/src/jsdbgapi.cpp b/js/src/jsdbgapi.cpp index 9b9baf03e3d3..6540f5f8750d 100644 --- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -295,8 +295,7 @@ js_MarkTraps(JSTracer *trc) for (JSTrap *trap = (JSTrap *) rt->trapList.next; &trap->links != &rt->trapList; trap = (JSTrap *) trap->links.next) { - JS_SET_TRACING_NAME(trc, "trap->closure"); - js_CallValueTracerIfGCThing(trc, trap->closure); + MarkValue(trc, Valueify(trap->closure), "trap->closure"); } } @@ -415,7 +414,7 @@ typedef struct JSWatchPoint { JSCList links; JSObject *object; /* weak link, see js_FinalizeObject */ JSScopeProperty *sprop; - JSPropertyOp setter; + PropertyOp setter; JSWatchPointHandler handler; JSObject *closure; uintN flags; @@ -436,7 +435,7 @@ DropWatchPointAndUnlock(JSContext *cx, JSWatchPoint *wp, uintN flag) JSBool ok; JSScopeProperty *sprop; JSScope *scope; - JSPropertyOp setter; + PropertyOp setter; ok = JS_TRUE; wp->flags &= ~flag; @@ -506,8 +505,7 @@ js_TraceWatchPoints(JSTracer *trc, JSObject *obj) wp->sprop->trace(trc); if (wp->sprop->hasSetterValue() && wp->setter) JS_CALL_OBJECT_TRACER(trc, CastAsObject(wp->setter), "wp->setter"); - JS_SET_TRACING_NAME(trc, "wp->closure"); - js_CallValueTracerIfGCThing(trc, OBJECT_TO_JSVAL(wp->closure)); + JS_CALL_OBJECT_TRACER(trc, wp->closure, "wp->closure"); } } } @@ -574,11 +572,11 @@ js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id) * Secret handshake with DropWatchPointAndUnlock: if (!scope), we know our * caller has acquired rt->debuggerLock, so we don't have to. */ -JSPropertyOp +PropertyOp js_GetWatchedSetter(JSRuntime *rt, JSScope *scope, const JSScopeProperty *sprop) { - JSPropertyOp setter; + PropertyOp setter; JSWatchPoint *wp; setter = NULL; @@ -598,7 +596,7 @@ js_GetWatchedSetter(JSRuntime *rt, JSScope *scope, } JSBool -js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +js_watch_set(JSContext *cx, JSObject *obj, jsid id, Value *vp) { JSRuntime *rt = cx->runtime; DBG_LOCK(rt); @@ -612,17 +610,17 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) DBG_UNLOCK(rt); JS_LOCK_OBJ(cx, obj); - jsval propid = ID_TO_VALUE(sprop->id); - jsval userid = SPROP_USERID(sprop); + jsid propid = sprop->id; + jsid userid = SPROP_USERID(sprop); JSScope *scope = obj->scope(); JS_UNLOCK_OBJ(cx, obj); /* NB: wp is held, so we can safely dereference it still. */ if (!wp->handler(cx, obj, propid, SPROP_HAS_VALID_SLOT(sprop, scope) - ? obj->getSlotMT(cx, sprop->slot) + ? Jsvalify(obj->getSlotMT(cx, sprop->slot)) : JSVAL_VOID, - vp, wp->closure)) { + Jsvalify(vp), wp->closure)) { DBG_LOCK(rt); DropWatchPointAndUnlock(cx, wp, JSWP_HELD); return JS_FALSE; @@ -640,7 +638,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) * trusted. */ JSObject *closure = wp->closure; - JSClass *clasp = closure->getClass(); + Class *clasp = closure->getClass(); JSFunction *fun; JSScript *script; if (clasp == &js_FunctionClass) { @@ -677,16 +675,18 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } /* Initialize slots/frame. */ - jsval *vp = frame.getvp(); - PodZero(vp, vplen); - vp[0] = OBJECT_TO_JSVAL(closure); + Value *vp = frame.getvp(); + MakeValueRangeGCSafe(vp, vplen); + vp[0].setObject(*closure); + vp[1].setNull(); // satisfy LeaveTree assert JSStackFrame *fp = frame.getFrame(); - PodZero(fp->slots(), nfixed); PodZero(fp); + MakeValueRangeGCSafe(fp->slots(), nfixed); fp->script = script; fp->fun = fun; fp->argv = vp + 2; fp->scopeChain = closure->getParent(); + fp->argsobj = NULL; /* Initialize regs. */ regs.pc = script ? script->code : NULL; @@ -706,9 +706,9 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSBool ok = !wp->setter || (sprop->hasSetterValue() - ? js_InternalCall(cx, obj, - CastAsObjectJSVal(wp->setter), - 1, vp, vp) + ? InternalCall(cx, obj, + ObjectValue(*CastAsObject(wp->setter)), + 1, vp, vp) : callJSPropertyOpSetter(cx, wp->setter, obj, userid, vp)); /* Evil code can cause us to have an arguments object. */ @@ -724,16 +724,16 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } JSBool -js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, Value *argv, + Value *rval) { JSObject *funobj; JSFunction *wrapper; - jsval userid; + jsid userid; - funobj = JSVAL_TO_OBJECT(argv[-2]); + funobj = &argv[-2].toObject(); wrapper = GET_FUNCTION_PRIVATE(cx, funobj); - userid = ATOM_KEY(wrapper->atom); + userid = ATOM_TO_JSID(wrapper->atom); *rval = argv[0]; return js_watch_set(cx, obj, userid, rval); } @@ -752,8 +752,8 @@ IsWatchedProperty(JSContext *cx, JSScopeProperty *sprop) return sprop->setterOp() == js_watch_set; } -JSPropertyOp -js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter) +PropertyOp +js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, PropertyOp setter) { JSAtom *atom; JSFunction *wrapper; @@ -764,7 +764,7 @@ js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter) if (JSID_IS_ATOM(id)) { atom = JSID_TO_ATOM(id); } else if (JSID_IS_INT(id)) { - if (!js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &id)) + if (!js_ValueToStringId(cx, IdToValue(id), &id)) return NULL; atom = JSID_TO_ATOM(id); } else { @@ -779,11 +779,11 @@ js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter) } JS_PUBLIC_API(JSBool) -JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, +JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, JSWatchPointHandler handler, void *closure) { JSObject *origobj; - jsval v; + Value v; uintN attrs; jsid propid; JSObject *pobj; @@ -792,7 +792,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, JSRuntime *rt; JSBool ok; JSWatchPoint *wp; - JSPropertyOp watcher; + PropertyOp watcher; origobj = obj; obj = obj->wrappedObject(cx); @@ -801,13 +801,13 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, return JS_FALSE; AutoValueRooter idroot(cx); - if (JSVAL_IS_INT(idval)) { - propid = INT_JSVAL_TO_JSID(idval); + if (JSID_IS_INT(id)) { + propid = id; } else { - if (!js_ValueToStringId(cx, idval, &propid)) + if (!js_ValueToStringId(cx, IdToValue(id), &propid)) return JS_FALSE; propid = js_CheckForStringIndex(propid); - idroot.set(ID_TO_VALUE(propid)); + idroot.set(IdToValue(propid)); } /* @@ -832,7 +832,7 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, sprop = js_FindWatchPoint(rt, obj->scope(), propid); if (!sprop) { /* Make a new property in obj so we can watch for the first set. */ - if (!js_DefineNativeProperty(cx, obj, propid, JSVAL_VOID, NULL, NULL, + if (!js_DefineNativeProperty(cx, obj, propid, UndefinedValue(), NULL, NULL, JSPROP_ENUMERATE, 0, 0, &prop)) { return JS_FALSE; } @@ -841,14 +841,14 @@ JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval idval, } else if (pobj != obj) { /* Clone the prototype property so we can watch the right object. */ AutoValueRooter valroot(cx); - JSPropertyOp getter, setter; + PropertyOp getter, setter; uintN attrs, flags; intN shortid; if (pobj->isNative()) { valroot.set(SPROP_HAS_VALID_SLOT(sprop, pobj->scope()) ? pobj->lockedGetSlot(sprop->slot) - : JSVAL_VOID); + : UndefinedValue()); getter = sprop->getter(); setter = sprop->setter(); attrs = sprop->attributes(); @@ -933,7 +933,7 @@ out: } JS_PUBLIC_API(JSBool) -JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id, +JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id, JSWatchPointHandler *handlerp, void **closurep) { JSRuntime *rt; @@ -1024,6 +1024,43 @@ JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno) return js_LineNumberToPC(script, lineno); } +JS_PUBLIC_API(uintN) +JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun) +{ + return fun->nargs; +} + +JS_PUBLIC_API(JSBool) +JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun) +{ + return fun->hasLocalNames(); +} + +extern JS_PUBLIC_API(jsuword *) +JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp) +{ + *markp = JS_ARENA_MARK(&cx->tempPool); + return js_GetLocalNameArray(cx, fun, &cx->tempPool); +} + +extern JS_PUBLIC_API(JSAtom *) +JS_LocalNameToAtom(jsuword w) +{ + return JS_LOCAL_NAME_TO_ATOM(w); +} + +extern JS_PUBLIC_API(JSString *) +JS_AtomKey(JSAtom *atom) +{ + return ATOM_TO_STRING(atom); +} + +extern JS_PUBLIC_API(void) +JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark) +{ + JS_ARENA_RELEASE(&cx->tempPool, mark); +} + JS_PUBLIC_API(JSScript *) JS_GetFunctionScript(JSContext *cx, JSFunction *fun) { @@ -1033,13 +1070,13 @@ JS_GetFunctionScript(JSContext *cx, JSFunction *fun) JS_PUBLIC_API(JSNative) JS_GetFunctionNative(JSContext *cx, JSFunction *fun) { - return FUN_NATIVE(fun); + return Jsvalify(FUN_NATIVE(fun)); } JS_PUBLIC_API(JSFastNative) JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun) { - return FUN_FAST_NATIVE(fun); + return Jsvalify(FUN_FAST_NATIVE(fun)); } JS_PUBLIC_API(JSPrincipals *) @@ -1242,13 +1279,13 @@ JS_IsDebuggerFrame(JSContext *cx, JSStackFrame *fp) JS_PUBLIC_API(jsval) JS_GetFrameReturnValue(JSContext *cx, JSStackFrame *fp) { - return fp->rval; + return Jsvalify(fp->rval); } JS_PUBLIC_API(void) JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval) { - fp->rval = rval; + fp->rval = Valueify(rval); } /************************************************************************/ @@ -1362,8 +1399,8 @@ JS_EvaluateUCInStackFrame(JSContext *cx, JSStackFrame *fp, } } - ok = js_Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, - rval); + ok = Execute(cx, scobj, script, fp, JSFRAME_DEBUGGER | JSFRAME_EVAL, + Valueify(rval)); if (cx->fp != fp) memcpy(cx->display, displayCopy, sizeof cx->display); @@ -1415,19 +1452,19 @@ JS_PUBLIC_API(JSBool) JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, JSPropertyDesc *pd) { - pd->id = ID_TO_VALUE(sprop->id); + pd->id = IdToJsval(sprop->id); JSBool wasThrowing = cx->throwing; AutoValueRooter lastException(cx, cx->exception); cx->throwing = JS_FALSE; - if (!js_GetProperty(cx, obj, sprop->id, &pd->value)) { + if (!js_GetProperty(cx, obj, sprop->id, Valueify(&pd->value))) { if (!cx->throwing) { pd->flags = JSPD_ERROR; pd->value = JSVAL_VOID; } else { pd->flags = JSPD_EXCEPTION; - pd->value = cx->exception; + pd->value = Jsvalify(cx->exception); } } else { pd->flags = 0; @@ -1457,7 +1494,7 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, JSScopeProperty *aprop; for (aprop = scope->lastProperty(); aprop; aprop = aprop->parent) { if (aprop != sprop && aprop->slot == sprop->slot) { - pd->alias = ID_TO_VALUE(aprop->id); + pd->alias = IdToJsval(aprop->id); break; } } @@ -1468,13 +1505,12 @@ JS_GetPropertyDesc(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, JS_PUBLIC_API(JSBool) JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda) { - JSClass *clasp; JSScope *scope; uint32 i, n; JSPropertyDesc *pd; JSScopeProperty *sprop; - clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (!obj->isNative() || (clasp->flags & JSCLASS_NEW_ENUMERATE)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_DESCRIBE_PROPS, clasp->name); @@ -1497,13 +1533,13 @@ JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda) return JS_FALSE; i = 0; for (sprop = scope->lastProperty(); sprop; sprop = sprop->parent) { - if (!js_AddRoot(cx, &pd[i].id, NULL)) + if (!js_AddRoot(cx, Valueify(&pd[i].id), NULL)) goto bad; - if (!js_AddRoot(cx, &pd[i].value, NULL)) + if (!js_AddRoot(cx, Valueify(&pd[i].value), NULL)) goto bad; if (!JS_GetPropertyDesc(cx, obj, sprop, &pd[i])) goto bad; - if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, &pd[i].alias, NULL)) + if ((pd[i].flags & JSPD_ALIAS) && !js_AddRoot(cx, Valueify(&pd[i].alias), NULL)) goto bad; if (++i == n) break; @@ -1548,9 +1584,10 @@ SetupFakeFrame(JSContext *cx, ExecuteFrameGuard &frame, JSFrameRegs ®s, JSObj if (!cx->stack().getExecuteFrame(cx, js_GetTopStackFrame(cx), vplen, nfixed, frame)) return false; - jsval *vp = frame.getvp(); + Value *vp = frame.getvp(); PodZero(vp, vplen); - vp[0] = OBJECT_TO_JSVAL(scopeobj); + vp[0].setObject(*scopeobj); + vp[1].setNull(); // satisfy LeaveTree assert JSStackFrame *fp = frame.getFrame(); PodZero(fp); @@ -1700,7 +1737,7 @@ JS_GetObjectTotalSize(JSContext *cx, JSObject *obj) nbytes = sizeof *obj; if (obj->dslots) { - nbytes += ((uint32)obj->dslots[-1] - JS_INITIAL_NSLOTS + 1) + nbytes += (obj->dslots[-1].toPrivateUint32() - JS_INITIAL_NSLOTS + 1) * sizeof obj->dslots[0]; } if (obj->isNative()) { @@ -1719,12 +1756,8 @@ GetAtomTotalSize(JSContext *cx, JSAtom *atom) size_t nbytes; nbytes = sizeof(JSAtom *) + sizeof(JSDHashEntryStub); - if (ATOM_IS_STRING(atom)) { - nbytes += sizeof(JSString); - nbytes += (ATOM_TO_STRING(atom)->flatLength() + 1) * sizeof(jschar); - } else if (ATOM_IS_DOUBLE(atom)) { - nbytes += sizeof(jsdouble); - } + nbytes += sizeof(JSString); + nbytes += (ATOM_TO_STRING(atom)->flatLength() + 1) * sizeof(jschar); return nbytes; } diff --git a/js/src/jsdbgapi.h b/js/src/jsdbgapi.h index 8e5e2e1111c0..03420b4cfa94 100644 --- a/js/src/jsdbgapi.h +++ b/js/src/jsdbgapi.h @@ -87,11 +87,11 @@ JS_ClearInterrupt(JSRuntime *rt, JSInterruptHook *handlerp, void **closurep); /************************************************************************/ extern JS_PUBLIC_API(JSBool) -JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsval id, +JS_SetWatchPoint(JSContext *cx, JSObject *obj, jsid id, JSWatchPointHandler handler, void *closure); extern JS_PUBLIC_API(JSBool) -JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsval id, +JS_ClearWatchPoint(JSContext *cx, JSObject *obj, jsid id, JSWatchPointHandler *handlerp, void **closurep); extern JS_PUBLIC_API(JSBool) @@ -114,22 +114,26 @@ js_SweepWatchPoints(JSContext *cx); extern JSScopeProperty * js_FindWatchPoint(JSRuntime *rt, JSScope *scope, jsid id); +#ifdef __cplusplus + /* * NB: callers outside of jsdbgapi.c must pass non-null scope. */ -extern JSPropertyOp +extern js::PropertyOp js_GetWatchedSetter(JSRuntime *rt, JSScope *scope, const JSScopeProperty *sprop); extern JSBool -js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +js_watch_set(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool -js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv, + js::Value *rval); -extern JSPropertyOp -js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, JSPropertyOp setter); +extern js::PropertyOp +js_WrapWatchedSetter(JSContext *cx, jsid id, uintN attrs, js::PropertyOp setter); + +#endif #endif /* JS_HAS_OBJ_WATCHPOINT */ @@ -141,6 +145,29 @@ JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc); extern JS_PUBLIC_API(jsbytecode *) JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno); +extern JS_PUBLIC_API(uintN) +JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun); + +extern JS_PUBLIC_API(JSBool) +JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun); + +/* + * N.B. The mark is in the context temp pool and thus the caller must take care + * to call JS_ReleaseFunctionLocalNameArray in a LIFO manner (wrt to any other + * call that may use the temp pool. + */ +extern JS_PUBLIC_API(jsuword *) +JS_GetFunctionLocalNameArray(JSContext *cx, JSFunction *fun, void **markp); + +extern JS_PUBLIC_API(JSAtom *) +JS_LocalNameToAtom(jsuword w); + +extern JS_PUBLIC_API(JSString *) +JS_AtomKey(JSAtom *atom); + +extern JS_PUBLIC_API(void) +JS_ReleaseFunctionLocalNameArray(JSContext *cx, void *mark); + extern JS_PUBLIC_API(JSScript *) JS_GetFunctionScript(JSContext *cx, JSFunction *fun); @@ -298,7 +325,7 @@ JS_EvaluateInStackFrame(JSContext *cx, JSStackFrame *fp, /************************************************************************/ typedef struct JSPropertyDesc { - jsval id; /* primary id, a string or int */ + jsval id; /* primary id, atomized string, or int */ jsval value; /* property value */ uint8 flags; /* flags, see below */ uint8 spare; /* unused */ diff --git a/js/src/jsdtoa.cpp b/js/src/jsdtoa.cpp index 5a17141ca50e..d4734fc949d6 100644 --- a/js/src/jsdtoa.cpp +++ b/js/src/jsdtoa.cpp @@ -51,6 +51,8 @@ #include "jslibmath.h" #include "jscntxt.h" +#include "jsobjinlines.h" + #ifdef IS_LITTLE_ENDIAN #define IEEE_8087 #else diff --git a/js/src/jsdtracef.cpp b/js/src/jsdtracef.cpp index 176101e358d6..6880592c6549 100644 --- a/js/src/jsdtracef.cpp +++ b/js/src/jsdtracef.cpp @@ -106,30 +106,28 @@ jsdtrace_frame_linenumber(JSContext *cx, JSStackFrame *fp) * provide raw (unmasked) jsvals should type info be useful from D scripts. */ static void * -jsdtrace_jsvaltovoid(JSContext *cx, const jsval argval) +jsdtrace_jsvaltovoid(JSContext *cx, const js::Value &argval) { - JSType type = TYPEOF(cx, argval); + if (argval.isNull()) + return (void *)JS_TYPE_STR(JSTYPE_NULL); - switch (type) { - case JSTYPE_NULL: - case JSTYPE_VOID: - return (void *)JS_TYPE_STR(type); + if (argval.isUndefined()) + return (void *)JS_TYPE_STR(JSTYPE_VOID); - case JSTYPE_BOOLEAN: - return (void *)JSVAL_TO_BOOLEAN(argval); + if (argval.isBoolean()) + return (void *)argval.toBoolean(); - case JSTYPE_STRING: - return (void *)js_GetStringBytes(cx, JSVAL_TO_STRING(argval)); + if (argval.isString()) + return (void *)js_GetStringBytes(cx, argval.toString()); - case JSTYPE_NUMBER: - if (JSVAL_IS_INT(argval)) - return (void *)JSVAL_TO_INT(argval); - return JSVAL_TO_DOUBLE(argval); - - default: - return JSVAL_TO_GCTHING(argval); + if (argval.isNumber()) { + if (argval.isInt32()) + return (void *)argval.toInt32(); + // FIXME Now what? + //return (void *)argval.toDouble(); } - /* NOTREACHED */ + + return argval.asGCThing(); } static char * @@ -176,7 +174,7 @@ DTrace::handleFunctionInfo(JSContext *cx, JSStackFrame *fp, JSStackFrame *dfp, J void DTrace::handleFunctionArgs(JSContext *cx, JSStackFrame *fp, const JSFunction *fun, jsuint argc, - jsval *argv) + js::Value *argv) { JAVASCRIPT_FUNCTION_ARGS(jsdtrace_filename(fp), jsdtrace_fun_classname(fun), jsdtrace_fun_name(cx, fun), argc, (void *)argv, @@ -188,7 +186,7 @@ DTrace::handleFunctionArgs(JSContext *cx, JSStackFrame *fp, const JSFunction *fu } void -DTrace::handleFunctionRval(JSContext *cx, JSStackFrame *fp, JSFunction *fun, jsval rval) +DTrace::handleFunctionRval(JSContext *cx, JSStackFrame *fp, JSFunction *fun, const js::Value &rval) { JAVASCRIPT_FUNCTION_RVAL(jsdtrace_filename(fp), jsdtrace_fun_classname(fun), jsdtrace_fun_name(cx, fun), jsdtrace_fun_linenumber(cx, fun), @@ -224,7 +222,7 @@ DTrace::ObjectCreationScope::handleCreationImpl(JSObject *obj) void DTrace::finalizeObjectImpl(JSObject *obj) { - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); /* the first arg is NULL - reserved for future use (filename?) */ JAVASCRIPT_OBJECT_FINALIZE(NULL, (char *)clasp->name, (uintptr_t)obj); diff --git a/js/src/jsdtracef.h b/js/src/jsdtracef.h index a7945aa32ec6..c338d580df00 100644 --- a/js/src/jsdtracef.h +++ b/js/src/jsdtracef.h @@ -49,8 +49,9 @@ class DTrace { static void handleFunctionInfo(JSContext *cx, JSStackFrame *fp, JSStackFrame *dfp, JSFunction *fun); static void handleFunctionArgs(JSContext *cx, JSStackFrame *fp, const JSFunction *fun, - jsuint argc, jsval *argv); - static void handleFunctionRval(JSContext *cx, JSStackFrame *fp, JSFunction *fun, jsval rval); + jsuint argc, js::Value *argv); + static void handleFunctionRval(JSContext *cx, JSStackFrame *fp, JSFunction *fun, + const js::Value &rval); static void handleFunctionReturn(JSContext *cx, JSStackFrame *fp, JSFunction *fun); static void finalizeObjectImpl(JSObject *obj); public: @@ -59,9 +60,11 @@ class DTrace { * it is a function as a predicate to the dtrace event emission. */ static void enterJSFun(JSContext *cx, JSStackFrame *fp, JSFunction *fun, - JSStackFrame *dfp, jsuint argc, jsval *argv, jsval *lval = NULL); - static void exitJSFun(JSContext *cx, JSStackFrame *fp, JSFunction *fun, jsval rval, - jsval *lval = NULL); + JSStackFrame *dfp, jsuint argc, js::Value *argv, + js::Value *lval = NULL); + static void exitJSFun(JSContext *cx, JSStackFrame *fp, JSFunction *fun, + const js::Value &rval, + js::Value *lval = NULL); static void finalizeObject(JSObject *obj); @@ -77,12 +80,12 @@ class DTrace { class ObjectCreationScope { JSContext * const cx; JSStackFrame * const fp; - JSClass * const clasp; + js::Class * const clasp; void handleCreationStart(); void handleCreationImpl(JSObject *obj); void handleCreationEnd(); public: - ObjectCreationScope(JSContext *cx, JSStackFrame *fp, JSClass *clasp); + ObjectCreationScope(JSContext *cx, JSStackFrame *fp, js::Class *clasp); void handleCreation(JSObject *obj); ~ObjectCreationScope(); }; @@ -91,10 +94,10 @@ class DTrace { inline void DTrace::enterJSFun(JSContext *cx, JSStackFrame *fp, JSFunction *fun, JSStackFrame *dfp, - jsuint argc, jsval *argv, jsval *lval) + jsuint argc, js::Value *argv, js::Value *lval) { #ifdef INCLUDE_MOZILLA_DTRACE - if (!lval || VALUE_IS_FUNCTION(cx, *lval)) { + if (!lval || lval->isFunObj()) { if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED()) enterJSFunImpl(cx, fp, fun); if (JAVASCRIPT_FUNCTION_INFO_ENABLED()) @@ -106,10 +109,11 @@ DTrace::enterJSFun(JSContext *cx, JSStackFrame *fp, JSFunction *fun, JSStackFram } inline void -DTrace::exitJSFun(JSContext *cx, JSStackFrame *fp, JSFunction *fun, jsval rval, jsval *lval) +DTrace::exitJSFun(JSContext *cx, JSStackFrame *fp, JSFunction *fun, + const js::Value &rval, js::Value *lval) { #ifdef INCLUDE_MOZILLA_DTRACE - if (!lval || VALUE_IS_FUNCTION(cx, *lval)) { + if (!lval || lval->isFunObj()) { if (JAVASCRIPT_FUNCTION_RVAL_ENABLED()) handleFunctionRval(cx, fp, fun, rval); if (JAVASCRIPT_FUNCTION_RETURN_ENABLED()) @@ -151,7 +155,7 @@ DTrace::ExecutionScope::~ExecutionScope() /* Object creation scope. */ inline -DTrace::ObjectCreationScope::ObjectCreationScope(JSContext *cx, JSStackFrame *fp, JSClass *clasp) +DTrace::ObjectCreationScope::ObjectCreationScope(JSContext *cx, JSStackFrame *fp, js::Class *clasp) : cx(cx), fp(fp), clasp(clasp) { #ifdef INCLUDE_MOZILLA_DTRACE diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index 9776cedb49a7..968d0cf03709 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -100,7 +100,8 @@ JSCodeGenerator::JSCodeGenerator(Parser *parser, numSpanDeps(0), numJumpTargets(0), spanDepTodo(0), arrayCompDepth(0), emitLevel(0), - constMap(parser->context) + constMap(parser->context), + constList(parser->context) { flags = TCF_COMPILING; memset(&prolog, 0, sizeof prolog); @@ -214,7 +215,7 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) JS_ASSERT(nuses == 0); blockObj = cg->objectList.lastbox->object; JS_ASSERT(blockObj->getClass() == &js_BlockClass); - JS_ASSERT(JSVAL_IS_VOID(blockObj->fslots[JSSLOT_BLOCK_DEPTH])); + JS_ASSERT(blockObj->fslots[JSSLOT_BLOCK_DEPTH].isUndefined()); OBJ_SET_BLOCK_DEPTH(cx, blockObj, cg->stackDepth); ndefs = OBJ_BLOCK_COUNT(cx, blockObj); @@ -1549,28 +1550,9 @@ JSBool js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, JSParseNode *pn) { - jsdouble dval; - jsint ival; - JSAtom *valueAtom; - jsval v; - /* XXX just do numbers for now */ if (pn->pn_type == TOK_NUMBER) { - dval = pn->pn_dval; - if (JSDOUBLE_IS_INT(dval, ival) && INT_FITS_IN_JSVAL(ival)) { - v = INT_TO_JSVAL(ival); - } else { - /* - * We atomize double to root a jsdouble instance that we wrap as - * jsval and store in cg->constList. This works because atoms are - * protected from GC during compilation. - */ - valueAtom = js_AtomizeDouble(cx, dval); - if (!valueAtom) - return JS_FALSE; - v = ATOM_KEY(valueAtom); - } - if (!cg->constMap.put(atom, v)) + if (!cg->constMap.put(atom, NumberValue(pn->pn_dval))) return JS_FALSE; } return JS_TRUE; @@ -1601,8 +1583,8 @@ js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt JS_ASSERT(sprop->hasShortID()); if (slotp) { - JS_ASSERT(JSVAL_IS_INT(obj->fslots[JSSLOT_BLOCK_DEPTH])); - *slotp = JSVAL_TO_INT(obj->fslots[JSSLOT_BLOCK_DEPTH]) + + JS_ASSERT(obj->fslots[JSSLOT_BLOCK_DEPTH].isInt32()); + *slotp = obj->fslots[JSSLOT_BLOCK_DEPTH].toInt32() + sprop->shortid; } return stmt; @@ -1615,12 +1597,12 @@ js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, JSStmtInfo *stmt } /* - * The function sets vp to JSVAL_HOLE when the atom does not corresponds to a + * The function sets vp to NO_CONSTANT when the atom does not corresponds to a * name defining a constant. */ static JSBool LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, - jsval *vp) + Value *constp) { JSStmtInfo *stmt; JSObject *obj; @@ -1630,7 +1612,7 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, * This enables propagating consts from top-level into switch cases in a * function compiled along with the top-level script. */ - *vp = JSVAL_HOLE; + constp->setMagic(JS_NO_CONSTANT); do { if (cg->inFunction() || cg->compileAndGo()) { /* XXX this will need revising if 'const' becomes block-scoped. */ @@ -1639,8 +1621,8 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, return JS_TRUE; if (JSCodeGenerator::ConstMap::Ptr p = cg->constMap.lookup(atom)) { - JS_ASSERT(p->value != JSVAL_HOLE); - *vp = p->value; + JS_ASSERT(!p->value.isMagic(JS_NO_CONSTANT)); + *constp = p->value; return JS_TRUE; } @@ -1670,7 +1652,7 @@ LookupCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom, */ if (!sprop->writable() && !sprop->configurable() && sprop->hasDefaultGetter() && SPROP_HAS_VALID_SLOT(sprop, scope)) { - *vp = obj->lockedGetSlot(sprop->slot); + *constp = obj->lockedGetSlot(sprop->slot); } } JS_UNLOCK_SCOPE(cx, scope); @@ -1849,15 +1831,15 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg) uintN base = JSSLOT_FREE(&js_BlockClass); for (uintN slot = base, limit = base + OBJ_BLOCK_COUNT(cx, blockObj); slot < limit; slot++) { - jsval v = blockObj->getSlot(slot); + const Value &v = blockObj->getSlot(slot); /* Beware the empty destructuring dummy. */ - if (JSVAL_IS_VOID(v)) { + if (v.isUndefined()) { JS_ASSERT(slot + 1 <= limit); continue; } - JSDefinition *dn = (JSDefinition *) JSVAL_TO_PRIVATE(v); + JSDefinition *dn = (JSDefinition *) v.toPrivate(); JS_ASSERT(dn->pn_defn); JS_ASSERT(uintN(dn->frameSlot() + depth) < JS_BIT(16)); dn->pn_cookie.set(dn->pn_cookie.level(), dn->frameSlot() + depth); @@ -2819,7 +2801,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) { ptrdiff_t top; JSParseNode *left, *right, *next, ltmp, rtmp; - jsint slot; + int32_t slot; top = CG_OFFSET(cg); if (pn->pn_arity == PN_LIST) { @@ -2839,7 +2821,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) if (!BindNameToSlot(cx, cg, left)) return JS_FALSE; if (left->pn_op == JSOP_ARGUMENTS && - JSDOUBLE_IS_INT(next->pn_dval, slot) && + JSDOUBLE_IS_INT32(next->pn_dval, &slot) && (jsuint)slot < JS_BIT(16)) { /* * arguments[i]() requires arguments object as "this". @@ -2894,7 +2876,6 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) } right = &rtmp; right->pn_type = TOK_STRING; - JS_ASSERT(ATOM_IS_STRING(pn->pn_atom)); right->pn_op = js_IsIdentifier(ATOM_TO_STRING(pn->pn_atom)) ? JSOP_QNAMEPART : JSOP_STRING; @@ -2914,7 +2895,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) if (!BindNameToSlot(cx, cg, left)) return JS_FALSE; if (left->pn_op == JSOP_ARGUMENTS && - JSDOUBLE_IS_INT(right->pn_dval, slot) && + JSDOUBLE_IS_INT32(right->pn_dval, &slot) && (jsuint)slot < JS_BIT(16)) { left->pn_offset = right->pn_offset = top; EMIT_UINT16_IMM_OP(JSOP_ARGSUB, (jsatomid)slot); @@ -2939,14 +2920,12 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg) static JSBool EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg) { - jsint ival; + int32_t ival; uint32 u; ptrdiff_t off; jsbytecode *pc; - JSAtom *atom; - JSAtomListElement *ale; - if (JSDOUBLE_IS_INT(dval, ival) && INT_FITS_IN_JSVAL(ival)) { + if (JSDOUBLE_IS_INT32(dval, &ival)) { if (ival == 0) return js_Emit1(cx, cg, JSOP_ZERO) >= 0; if (ival == 1) @@ -2973,14 +2952,26 @@ EmitNumberOp(JSContext *cx, jsdouble dval, JSCodeGenerator *cg) return JS_TRUE; } - atom = js_AtomizeDouble(cx, dval); - if (!atom) + if (!cg->constList.append(DoubleValue(dval))) return JS_FALSE; - ale = cg->atomList.add(cg->parser, atom); - if (!ale) - return JS_FALSE; - return EmitIndexOp(cx, JSOP_DOUBLE, ALE_INDEX(ale), cg); + return EmitIndexOp(cx, JSOP_DOUBLE, cg->constList.length() - 1, cg); +} + +/* + * To avoid bloating all parse nodes for the special case of switch, values are + * allocated in the temp pool and pointed to by the parse node. These values + * are not currently recycled (like parse nodes) and the temp pool is only + * flushed at the end of compiling a script, so these values are technically + * leaked. This would only be a problem for scripts containing a large number + * of large switches, which seems unlikely. + */ +static Value * +AllocateSwitchConstant(JSContext *cx) +{ + Value *pv; + JS_ARENA_ALLOCATE_TYPE(pv, Value, &cx->tempPool); + return pv; } static JSBool @@ -2993,10 +2984,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, JSParseNode *pn2, *pn3, *pn4; uint32 caseCount, tableLength; JSParseNode **table; - jsdouble d; - jsint i, low, high; - jsval v; - JSAtom *atom; + int32_t i, low, high; JSAtomListElement *ale; intN noteIndex; size_t switchSize, tableSize; @@ -3110,30 +3098,22 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, pn4 = pn3->pn_left; while (pn4->pn_type == TOK_RP) pn4 = pn4->pn_kid; + + Value constVal; switch (pn4->pn_type) { case TOK_NUMBER: - d = pn4->pn_dval; - if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) { - pn3->pn_val = INT_TO_JSVAL(i); - } else { - atom = js_AtomizeDouble(cx, d); - if (!atom) { - ok = JS_FALSE; - goto release; - } - pn3->pn_val = ATOM_KEY(atom); - } + constVal.setNumber(pn4->pn_dval); break; case TOK_STRING: - pn3->pn_val = ATOM_KEY(pn4->pn_atom); + constVal.setString(ATOM_TO_STRING(pn4->pn_atom)); break; case TOK_NAME: if (!pn4->maybeExpr()) { - ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &v); + ok = LookupCompileTimeConstant(cx, cg, pn4->pn_atom, &constVal); if (!ok) goto release; - if (v != JSVAL_HOLE) { - if (!JSVAL_IS_PRIMITIVE(v)) { + if (!constVal.isMagic(JS_NO_CONSTANT)) { + if (constVal.isObject()) { /* * XXX JSOP_LOOKUPSWITCH does not support const- * propagated object values, see bug 407186. @@ -3141,7 +3121,6 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, switchOp = JSOP_CONDSWITCH; continue; } - pn3->pn_val = v; constPropagated = JS_TRUE; break; } @@ -3149,15 +3128,15 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, /* FALL THROUGH */ case TOK_PRIMARY: if (pn4->pn_op == JSOP_TRUE) { - pn3->pn_val = JSVAL_TRUE; + constVal.setBoolean(true); break; } if (pn4->pn_op == JSOP_FALSE) { - pn3->pn_val = JSVAL_FALSE; + constVal.setBoolean(false); break; } if (pn4->pn_op == JSOP_NULL) { - pn3->pn_val = JSVAL_NULL; + constVal.setNull(); break; } /* FALL THROUGH */ @@ -3165,16 +3144,23 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, switchOp = JSOP_CONDSWITCH; continue; } + JS_ASSERT(constVal.isPrimitive()); - JS_ASSERT(JSVAL_IS_PRIMITIVE(pn3->pn_val)); + pn3->pn_pval = AllocateSwitchConstant(cx); + if (!pn3->pn_pval) { + ok = JS_FALSE; + goto release; + } + + *pn3->pn_pval = constVal; if (switchOp != JSOP_TABLESWITCH) continue; - if (!JSVAL_IS_INT(pn3->pn_val)) { + if (!pn3->pn_pval->isInt32()) { switchOp = JSOP_LOOKUPSWITCH; continue; } - i = JSVAL_TO_INT(pn3->pn_val); + i = pn3->pn_pval->toInt32(); if ((jsuint)(i + (jsint)JS_BIT(15)) >= (jsuint)JS_BIT(16)) { switchOp = JSOP_LOOKUPSWITCH; continue; @@ -3237,7 +3223,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, * switch generation and use conditional switch if it exceeds * the limit. */ - if (caseCount + cg->atomList.count > JS_BIT(16)) + if (caseCount + cg->constList.length() > JS_BIT(16)) switchOp = JSOP_CONDSWITCH; } } @@ -3369,7 +3355,7 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { if (pn3->pn_type == TOK_DEFAULT) continue; - i = JSVAL_TO_INT(pn3->pn_val); + i = pn3->pn_pval->toInt32(); i -= low; JS_ASSERT((uint32)i < tableLength); table[i] = pn3; @@ -3512,12 +3498,9 @@ EmitSwitch(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { if (pn3->pn_type == TOK_DEFAULT) continue; - if (!js_AtomizePrimitiveValue(cx, pn3->pn_val, &atom)) + if (!cg->constList.append(*pn3->pn_pval)) goto bad; - ale = cg->atomList.add(cg->parser, atom); - if (!ale) - goto bad; - SET_INDEX(pc, ALE_INDEX(ale)); + SET_INDEX(pc, cg->constList.length() - 1); pc += INDEX_LEN; off = pn3->pn_offset - top; @@ -6306,7 +6289,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) * For operator new applied to other expressions than E4X ones, we emit * JSOP_GETPROP instead of JSOP_CALLPROP, etc. This is necessary to * interpose the lambda-initialized method read barrier -- see the code - * in jsops.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP. + * in jsinterp.cpp for JSOP_LAMBDA followed by JSOP_{SET,INIT}PROP. * * Then (or in a call case that has no explicit reference-base object) * we emit JSOP_NULL as a placeholder local GC root to hold the |this| @@ -7404,3 +7387,13 @@ JSCGObjectList::finish(JSObjectArray *array) } while ((objbox = objbox->emitLink) != NULL); JS_ASSERT(cursor == array->vector); } + +void +JSGCConstList::finish(JSConstArray *array) +{ + JS_ASSERT(array->length == list.length()); + Value *src = list.begin(), *srcend = list.end(); + Value *dst = array->vector; + for (; src != srcend; ++src, ++dst) + *dst = *src; +} diff --git a/js/src/jsemit.h b/js/src/jsemit.h index 82706686ad72..9b8f86796311 100644 --- a/js/src/jsemit.h +++ b/js/src/jsemit.h @@ -430,6 +430,16 @@ struct JSCGObjectList { void finish(JSObjectArray *array); }; +class JSGCConstList { + js::Vector list; + public: + JSGCConstList(JSContext *cx) : list(cx) {} + bool append(js::Value v) { return list.append(v); } + size_t length() const { return list.length(); } + void finish(JSConstArray *array); + +}; + struct JSCodeGenerator : public JSTreeContext { JSArenaPool *codePool; /* pointer to thread code arena pool */ @@ -469,9 +479,11 @@ struct JSCodeGenerator : public JSTreeContext uintN emitLevel; /* js_EmitTree recursion level */ - typedef js::HashMap ConstMap; + typedef js::HashMap ConstMap; ConstMap constMap; /* compile time constants */ + JSGCConstList constList; /* constants to be included with the script */ + JSCGObjectList objectList; /* list of emitted objects */ JSCGObjectList regexpList; /* list of emitted regexp that will be cloned during execution */ @@ -487,7 +499,6 @@ struct JSCodeGenerator : public JSTreeContext JSCodeGenerator(js::Parser *parser, JSArenaPool *codePool, JSArenaPool *notePool, uintN lineno); - bool init(); /* diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 587194610a8f..f16e0b28ea5b 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -41,7 +41,6 @@ /* * JS standard exception implementation. */ - #include #include #include "jstypes.h" @@ -63,13 +62,14 @@ #include "jsscript.h" #include "jsstaticcheck.h" +#include "jscntxtinlines.h" #include "jsobjinlines.h" using namespace js; /* Forward declarations for js_ErrorClass's initializer. */ static JSBool -Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +Exception(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval); static void exn_trace(JSTracer *trc, JSObject *obj); @@ -81,15 +81,15 @@ static JSBool exn_enumerate(JSContext *cx, JSObject *obj); static JSBool -exn_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); -JSClass js_ErrorClass = { +Class js_ErrorClass = { js_Error_str, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Error), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - exn_enumerate, (JSResolveOp)exn_resolve, JS_ConvertStub, exn_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + exn_enumerate, (JSResolveOp)exn_resolve, ConvertStub, exn_finalize, NULL, NULL, NULL, Exception, NULL, NULL, JS_CLASS_TRACE(exn_trace), NULL }; @@ -251,10 +251,10 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, JSString *filename, uintN lineno, JSErrorReport *report) { JSSecurityCallbacks *callbacks; - JSCheckAccessOp checkAccess; + CheckAccessOp checkAccess; JSErrorReporter older; JSExceptionState *state; - jsval callerid, v; + jsid callerid; JSStackFrame *fp, *fpstop; size_t stackDepth, valueCount, size; JSBool overflow; @@ -273,17 +273,17 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, */ callbacks = JS_GetSecurityCallbacks(cx); checkAccess = callbacks - ? callbacks->checkObjectAccess + ? Valueify(callbacks->checkObjectAccess) : NULL; older = JS_SetErrorReporter(cx, NULL); state = JS_SaveExceptionState(cx); - callerid = ATOM_KEY(cx->runtime->atomState.callerAtom); + callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom); stackDepth = 0; valueCount = 0; for (fp = js_GetTopStackFrame(cx); fp; fp = fp->down) { if (fp->fun && fp->argv) { - v = JSVAL_NULL; + Value v = NullValue(); if (checkAccess && !checkAccess(cx, fp->callee(), callerid, JSACC_READ, &v)) { break; @@ -446,7 +446,7 @@ exn_enumerate(JSContext *cx, JSObject *obj) } static JSBool -exn_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { JSExnPrivate *priv; @@ -458,8 +458,8 @@ exn_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, *objp = NULL; priv = GetExnPrivate(cx, obj); - if (priv && JSVAL_IS_STRING(id)) { - str = JSVAL_TO_STRING(id); + if (priv && JSID_IS_ATOM(id)) { + str = JSID_TO_STRING(id); atom = cx->runtime->atomState.messageAtom; if (str == ATOM_TO_STRING(atom)) { @@ -528,13 +528,13 @@ ValueToShortSource(JSContext *cx, jsval v) /* Avoid toSource bloat and fallibility for object types. */ if (JSVAL_IS_PRIMITIVE(v)) { - str = js_ValueToSource(cx, v); + str = js_ValueToSource(cx, Valueify(v)); } else if (VALUE_IS_FUNCTION(cx, v)) { /* * XXX Avoid function decompilation bloat for now. */ str = JS_GetFunctionId(JS_ValueToFunction(cx, v)); - if (!str && !(str = js_ValueToSource(cx, v))) { + if (!str && !(str = js_ValueToSource(cx, Valueify(v)))) { /* * Continue to soldier on if the function couldn't be * converted into a string. @@ -685,7 +685,7 @@ StringToFilename(JSContext *cx, JSString *str) } static JSBool -Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Exception(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { JSString *message, *filename; JSStackFrame *fp; @@ -698,17 +698,17 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * NewNativeClassInstance to find the class prototype, we must get the * class prototype ourselves. */ - if (!JSVAL_TO_OBJECT(argv[-2])->getProperty(cx, - ATOM_TO_JSID(cx->runtime->atomState - .classPrototypeAtom), - rval)) { + if (!argv[-2].toObject().getProperty(cx, + ATOM_TO_JSID(cx->runtime->atomState + .classPrototypeAtom), + rval)) { return JS_FALSE; } - JSObject *errProto = JSVAL_TO_OBJECT(*rval); + JSObject *errProto = &rval->toObject(); obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent()); if (!obj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); } /* @@ -723,7 +723,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) message = js_ValueToString(cx, argv[0]); if (!message) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(message); + argv[0].setString(message); } else { message = cx->runtime->emptyString; } @@ -733,7 +733,7 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) filename = js_ValueToString(cx, argv[1]); if (!filename) return JS_FALSE; - argv[1] = STRING_TO_JSVAL(filename); + argv[1].setString(filename); fp = NULL; } else { fp = js_GetScriptedCaller(cx, NULL); @@ -778,7 +778,7 @@ exn_toString(JSContext *cx, uintN argc, jsval *vp) size_t name_length, message_length, length; obj = JS_THIS_OBJECT(cx, vp); - if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), &v)) + if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), Valueify(&v))) return JS_FALSE; name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; *vp = STRING_TO_JSVAL(name); @@ -832,27 +832,27 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) jschar *chars, *cp; obj = JS_THIS_OBJECT(cx, vp); - if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), vp)) + if (!obj || !obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), Valueify(vp))) return false; - name = js_ValueToString(cx, *vp); + name = js_ValueToString(cx, Valueify(*vp)); if (!name) return false; *vp = STRING_TO_JSVAL(name); { - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), localroots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroots), Valueify(localroots)); #ifdef __GNUC__ message = filename = NULL; #endif if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) || - !(message = js_ValueToSource(cx, localroots[0]))) { + !(message = js_ValueToSource(cx, Valueify(localroots[0])))) { return false; } localroots[0] = STRING_TO_JSVAL(message); if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) || - !(filename = js_ValueToSource(cx, localroots[1]))) { + !(filename = js_ValueToSource(cx, Valueify(localroots[1])))) { return false; } localroots[1] = STRING_TO_JSVAL(filename); @@ -860,11 +860,11 @@ exn_toSource(JSContext *cx, uintN argc, jsval *vp) if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2])) return false; uint32_t lineno; - if (!ValueToECMAUint32(cx, localroots[2], &lineno)) + if (!ValueToECMAUint32(cx, Valueify(localroots[2]), &lineno)) return false; if (lineno != 0) { - lineno_as_str = js_ValueToString(cx, localroots[2]); + lineno_as_str = js_ValueToString(cx, Valueify(localroots[2])); if (!lineno_as_str) return false; lineno_length = lineno_as_str->length(); @@ -989,7 +989,7 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) return NULL; PodArrayZero(roots); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots)); #ifdef __GNUC__ error_proto = NULL; /* quell GCC overwarning */ @@ -1034,7 +1034,8 @@ js_InitExceptionClasses(JSContext *cx, JSObject *obj) } /* Add the name property to the prototype. */ - if (!JS_DefineProperty(cx, proto, js_name_str, ATOM_KEY(atom), + if (!JS_DefineProperty(cx, proto, js_name_str, + STRING_TO_JSVAL(ATOM_TO_STRING(atom)), NULL, NULL, JSPROP_ENUMERATE)) { return NULL; } @@ -1139,7 +1140,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, /* Protect the newly-created strings below from nesting GCs. */ PodArrayZero(tv); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), tv); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(tv), Valueify(tv)); /* * Try to get an appropriate prototype by looking up the corresponding @@ -1204,7 +1205,7 @@ js_ReportUncaughtException(JSContext *cx) return false; PodArrayZero(roots); - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots)); /* * Because js_ValueToString below could error and an exception object @@ -1223,7 +1224,7 @@ js_ReportUncaughtException(JSContext *cx) reportp = js_ErrorFromException(cx, exn); /* XXX L10N angels cry once again (see also jsemit.c, /L10N gaffes/) */ - str = js_ValueToString(cx, exn); + str = js_ValueToString(cx, Valueify(exn)); if (!str) { bytes = "unknown (can't convert to string)"; } else { @@ -1246,7 +1247,7 @@ js_ReportUncaughtException(JSContext *cx) if (!JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3])) return false; - str = js_ValueToString(cx, roots[3]); + str = js_ValueToString(cx, Valueify(roots[3])); if (!str) return false; filename = StringToFilename(cx, str); @@ -1256,7 +1257,7 @@ js_ReportUncaughtException(JSContext *cx) if (!JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4])) return false; uint32_t lineno; - if (!ValueToECMAUint32 (cx, roots[4], &lineno)) + if (!ValueToECMAUint32 (cx, Valueify(roots[4]), &lineno)) return false; reportp = &report; diff --git a/js/src/jsexn.h b/js/src/jsexn.h index 0e398aa77827..1d08b34aa4e7 100644 --- a/js/src/jsexn.h +++ b/js/src/jsexn.h @@ -44,9 +44,7 @@ #ifndef jsexn_h___ #define jsexn_h___ -JS_BEGIN_EXTERN_C - -extern JSClass js_ErrorClass; +extern js::Class js_ErrorClass; /* * Initialize the exception constructor/prototype hierarchy. @@ -92,6 +90,4 @@ extern const JSErrorFormatString * js_GetLocalizedErrorMessage(JSContext* cx, void *userRef, const char *locale, const uintN errorNumber); -JS_END_EXTERN_C - #endif /* jsexn_h___ */ diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 48a4324225f7..2feef5e90d4a 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -83,6 +83,7 @@ #include "jsatominlines.h" #include "jscntxtinlines.h" #include "jsobjinlines.h" +#include "jscntxtinlines.h" using namespace js; @@ -95,7 +96,7 @@ SetArgsPrivateNative(JSObject *argsobj, ArgsPrivateNative *apn) } JSBool -js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp) +js_GetArgsValue(JSContext *cx, JSStackFrame *fp, Value *vp) { JSObject *argsobj; @@ -107,40 +108,39 @@ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp) argsobj = js_GetArgsObject(cx, fp); if (!argsobj) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(argsobj); + vp->setObject(*argsobj); return JS_TRUE; } JSBool -js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) +js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, Value *vp) { if (fp->flags & JSFRAME_OVERRIDE_ARGS) { JS_ASSERT(fp->callobj); jsid argumentsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom); - jsval v; + Value v; if (!fp->callobj->getProperty(cx, argumentsid, &v)) return false; JSObject *obj; - if (JSVAL_IS_PRIMITIVE(v)) { + if (v.isPrimitive()) { obj = js_ValueToNonNullObject(cx, v); if (!obj) return false; } else { - obj = JSVAL_TO_OBJECT(v); + obj = &v.toObject(); } return obj->getProperty(cx, id, vp); } - *vp = JSVAL_VOID; + vp->setUndefined(); if (JSID_IS_INT(id)) { uint32 arg = uint32(JSID_TO_INT(id)); - JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); + JSObject *argsobj = fp->argsobj; if (arg < fp->argc) { if (argsobj) { - jsval v = argsobj->getArgsElement(arg); - if (v == JSVAL_HOLE) + if (argsobj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)) return argsobj->getProperty(cx, id, vp); } *vp = fp->argv[arg]; @@ -160,11 +160,11 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) if (argsobj) return argsobj->getProperty(cx, id, vp); } - } else if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { - JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + JSObject *argsobj = fp->argsobj; if (argsobj && argsobj->isArgsLengthOverridden()) return argsobj->getProperty(cx, id, vp); - *vp = INT_TO_JSVAL(jsint(fp->argc)); + vp->setInt32(fp->argc); } return true; } @@ -181,8 +181,8 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee) return NULL; /* Init immediately to avoid GC seeing a half-init'ed object. */ - argsobj->init(&js_ArgumentsClass, proto, parent, JSVAL_NULL); - argsobj->setArgsCallee(OBJECT_TO_JSVAL(callee)); + argsobj->init(&js_ArgumentsClass, proto, parent, PrivateValue(NULL)); + argsobj->setArgsCallee(ObjectOrNullValue(callee)); argsobj->setArgsLength(argc); argsobj->map = cx->runtime->emptyArgumentsScope->hold(); @@ -194,12 +194,11 @@ NewArguments(JSContext *cx, JSObject *parent, uint32 argc, JSObject *callee) } static void -PutArguments(JSContext *cx, JSObject *argsobj, jsval *args) +PutArguments(JSContext *cx, JSObject *argsobj, Value *args) { uint32 argc = argsobj->getArgsLength(); for (uint32 i = 0; i != argc; ++i) { - jsval v = argsobj->getArgsElement(i); - if (v != JSVAL_HOLE) + if (!argsobj->getArgsElement(i).isMagic(JS_ARGS_HOLE)) argsobj->setArgsElement(i, args[i]); } } @@ -220,30 +219,30 @@ js_GetArgsObject(JSContext *cx, JSStackFrame *fp) fp = fp->down; /* Create an arguments object for fp only if it lacks one. */ - JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); + JSObject *argsobj = fp->argsobj; if (argsobj) return argsobj; /* Compute the arguments object's parent slot from fp's scope chain. */ JSObject *global = fp->scopeChain->getGlobal(); - argsobj = NewArguments(cx, global, fp->argc, JSVAL_TO_OBJECT(fp->argv[-2])); + argsobj = NewArguments(cx, global, fp->argc, &fp->argv[-2].toObject()); if (!argsobj) return argsobj; /* Link the new object to fp so it can get actual argument values. */ argsobj->setPrivate(fp); - fp->argsobj = OBJECT_TO_JSVAL(argsobj); + fp->argsobj = argsobj; return argsobj; } void js_PutArgsObject(JSContext *cx, JSStackFrame *fp) { - JSObject *argsobj = JSVAL_TO_OBJECT(fp->argsobj); + JSObject *argsobj = fp->argsobj; JS_ASSERT(argsobj->getPrivate() == fp); PutArguments(cx, argsobj, fp->argv); argsobj->setPrivate(NULL); - fp->argsobj = JSVAL_NULL; + fp->argsobj = NULL; } /* @@ -269,7 +268,7 @@ JS_DEFINE_CALLINFO_6(extern, OBJECT, js_Arguments, CONTEXT, OBJECT, UINT32, OBJE /* FIXME change the return type to void. */ JSBool JS_FASTCALL -js_PutArguments(JSContext *cx, JSObject *argsobj, jsval *args) +js_PutArguments(JSContext *cx, JSObject *argsobj, Value *args) { JS_ASSERT(GetArgsPrivateNative(argsobj)); PutArguments(cx, argsobj, args); @@ -277,22 +276,22 @@ js_PutArguments(JSContext *cx, JSObject *argsobj, jsval *args) return true; } -JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArguments, CONTEXT, OBJECT, JSVALPTR, 0, +JS_DEFINE_CALLINFO_3(extern, BOOL, js_PutArguments, CONTEXT, OBJECT, VALUEPTR, 0, nanojit::ACC_STORE_ANY) static JSBool -args_delProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +args_delProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { JS_ASSERT(obj->isArguments()); - if (JSVAL_IS_INT(idval)) { - uintN arg = uintN(JSVAL_TO_INT(idval)); + if (JSID_IS_INT(id)) { + uintN arg = uintN(JSID_TO_INT(id)); if (arg < obj->getArgsLength()) - obj->setArgsElement(arg, JSVAL_HOLE); - } else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { + obj->setArgsElement(arg, MagicValue(JS_ARGS_HOLE)); + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { obj->setArgsLengthOverridden(); - } else if (idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)) { - obj->setArgsCallee(JSVAL_HOLE); + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) { + obj->setArgsCallee(MagicValue(JS_ARGS_HOLE)); } return true; } @@ -324,7 +323,7 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio funobj, scopeChain); if (!wfunobj) return NULL; - AutoValueRooter tvr(cx, wfunobj); + AutoObjectRooter tvr(cx, wfunobj); JSFunction *wfun = (JSFunction *) wfunobj; wfunobj->setPrivate(wfun); @@ -389,6 +388,9 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio : 0, (script->trynotesOffset != 0) ? script->trynotes()->length + : 0, + (script->constOffset != 0) + ? script->consts()->length : 0); if (!wscript) return NULL; @@ -474,25 +476,23 @@ WrapEscapingClosure(JSContext *cx, JSStackFrame *fp, JSObject *funobj, JSFunctio } static JSBool -ArgGetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +ArgGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - if (!JS_InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) + if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) return true; - if (JSVAL_IS_INT(idval)) { + if (JSID_IS_INT(id)) { /* * arg can exceed the number of arguments if a script changed the * prototype to point to another Arguments object with a bigger argc. */ - uintN arg = uintN(JSVAL_TO_INT(idval)); + uintN arg = uintN(JSID_TO_INT(id)); if (arg < obj->getArgsLength()) { #ifdef JS_TRACER ArgsPrivateNative *argp = GetArgsPrivateNative(obj); if (argp) { - if (NativeToValue(cx, *vp, argp->typemap()[arg], &argp->argv[arg])) - return true; - LeaveTrace(cx); - return false; + ExternNativeToValue(cx, *vp, argp->typemap()[arg], &argp->argv[arg]); + return true; } #endif @@ -500,18 +500,18 @@ ArgGetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) if (fp) { *vp = fp->argv[arg]; } else { - jsval v = obj->getArgsElement(arg); - if (v != JSVAL_HOLE) + const Value &v = obj->getArgsElement(arg); + if (!v.isMagic(JS_ARGS_HOLE)) *vp = v; } } - } else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { if (!obj->isArgsLengthOverridden()) - *vp = INT_TO_JSVAL(obj->getArgsLength()); + vp->setInt32(obj->getArgsLength()); } else { - JS_ASSERT(idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)); - jsval v = obj->getArgsCallee(); - if (v != JSVAL_HOLE) { + JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)); + const Value &v = obj->getArgsCallee(); + if (!v.isMagic(JS_ARGS_HOLE)) { /* * If this function or one in it needs upvars that reach above it * in the scope chain, it must not be a null closure (it could be a @@ -520,7 +520,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) * to reduce code size and tell debugger users the truth instead of * passing off a fibbing wrapper. */ - if (GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))->needsWrapper()) { + if (GET_FUNCTION_PRIVATE(cx, &v.toObject())->needsWrapper()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OPTIMIZED_CLOSURE_LEAK); return false; @@ -532,7 +532,7 @@ ArgGetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) } static JSBool -ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +ArgSetter(JSContext *cx, JSObject *obj, jsid id, Value *vp) { #ifdef JS_TRACER // To be able to set a property here on trace, we would have to make @@ -545,11 +545,11 @@ ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) } #endif - if (!JS_InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) + if (!InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) return true; - if (JSVAL_IS_INT(idval)) { - uintN arg = uintN(JSVAL_TO_INT(idval)); + if (JSID_IS_INT(id)) { + uintN arg = uintN(JSID_TO_INT(id)); if (arg < obj->getArgsLength()) { JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); if (fp) { @@ -558,8 +558,8 @@ ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) } } } else { - JS_ASSERT(idval == ATOM_KEY(cx->runtime->atomState.lengthAtom) || - idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)); + JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) || + JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)); } /* @@ -568,40 +568,38 @@ ArgSetter(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) * args_delete to clear the corresponding reserved slot so the GC can * collect its value. */ - JS_ASSERT_IF(JSVAL_IS_STRING(idval), JSVAL_TO_STRING(idval)->isAtomized()); - jsid id = (jsid)idval; - AutoValueRooter tvr(cx); return js_DeleteProperty(cx, obj, id, tvr.addr()) && js_SetProperty(cx, obj, id, vp); } static JSBool -args_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, +args_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { JS_ASSERT(obj->isArguments()); *objp = NULL; - jsid id = 0; - if (JSVAL_IS_INT(idval)) { - uint32 arg = uint32(JSVAL_TO_INT(idval)); - if (arg < obj->getArgsLength() && obj->getArgsElement(arg) != JSVAL_HOLE) - id = INT_JSVAL_TO_JSID(idval); - } else if (idval == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { + bool valid = false; + if (JSID_IS_INT(id)) { + uint32 arg = uint32(JSID_TO_INT(id)); + if (arg < obj->getArgsLength() && !obj->getArgsElement(arg).isMagic(JS_ARGS_HOLE)) + valid = true; + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { if (!obj->isArgsLengthOverridden()) - id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); - } else if (idval == ATOM_KEY(cx->runtime->atomState.calleeAtom)) { - if (obj->getArgsCallee() != JSVAL_HOLE) - id = ATOM_TO_JSID(cx->runtime->atomState.calleeAtom); + valid = true; + } else if (JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom)) { + if (!obj->getArgsCallee().isMagic(JS_ARGS_HOLE)) + valid = true; } - if (id != 0) { + if (valid) { /* * XXX ECMA specs DontEnum even for indexed properties, contrary to * other array-like objects. */ - if (!js_DefineProperty(cx, obj, id, JSVAL_VOID, ArgGetter, ArgSetter, JSPROP_SHARED)) + Value tmp = UndefinedValue(); + if (!js_DefineProperty(cx, obj, id, &tmp, ArgGetter, ArgSetter, JSPROP_SHARED)) return JS_FALSE; *objp = obj; } @@ -623,7 +621,7 @@ args_enumerate(JSContext *cx, JSObject *obj) ? ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) : (i == -1) ? ATOM_TO_JSID(cx->runtime->atomState.calleeAtom) - : INT_JSVAL_TO_JSID(INT_TO_JSVAL(i)); + : INT_TO_JSID(i); JSObject *pobj; JSProperty *prop; @@ -678,15 +676,15 @@ args_or_call_trace(JSTracer *trc, JSObject *obj) * in a JSStackFrame with their corresponding property values in the frame's * arguments object. */ -JSClass js_ArgumentsClass = { +Class js_ArgumentsClass = { "Arguments", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(JSObject::ARGS_FIXED_RESERVED_SLOTS) | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), - JS_PropertyStub, args_delProperty, - JS_PropertyStub, JS_PropertyStub, + PropertyStub, args_delProperty, + PropertyStub, PropertyStub, args_enumerate, (JSResolveOp) args_resolve, - JS_ConvertStub, NULL, + ConvertStub, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -701,24 +699,24 @@ const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS = 2; * A Declarative Environment object stores its active JSStackFrame pointer in * its private slot, just as Call and Arguments objects do. */ -JSClass js_DeclEnvClass = { +Class js_DeclEnvClass = { js_Object_str, JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; static JSBool -CheckForEscapingClosure(JSContext *cx, JSObject *obj, jsval *vp) +CheckForEscapingClosure(JSContext *cx, JSObject *obj, Value *vp) { JS_ASSERT(obj->getClass() == &js_CallClass || obj->getClass() == &js_DeclEnvClass); - jsval v = *vp; + const Value &v = *vp; - if (VALUE_IS_FUNCTION(cx, v)) { - JSObject *funobj = JSVAL_TO_OBJECT(v); + JSObject *funobj; + if (IsFunctionObject(v, &funobj)) { JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); /* @@ -735,7 +733,7 @@ CheckForEscapingClosure(JSContext *cx, JSObject *obj, jsval *vp) JSObject *wrapper = WrapEscapingClosure(cx, fp, funobj, fun); if (!wrapper) return false; - *vp = OBJECT_TO_JSVAL(wrapper); + vp->setObject(*wrapper); return true; } @@ -748,7 +746,7 @@ CheckForEscapingClosure(JSContext *cx, JSObject *obj, jsval *vp) } static JSBool -CalleeGetter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +CalleeGetter(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CheckForEscapingClosure(cx, obj, vp); } @@ -761,7 +759,7 @@ NewCallObject(JSContext *cx, JSFunction *fun, JSObject *scopeChain) return NULL; /* Init immediately to avoid GC seeing a half-init'ed object. */ - callobj->init(&js_CallClass, NULL, scopeChain, JSVAL_NULL); + callobj->init(&js_CallClass, NULL, scopeChain, PrivateValue(NULL)); callobj->map = cx->runtime->emptyCallScope->hold(); /* This must come after callobj->map has been set. */ @@ -778,7 +776,7 @@ NewDeclEnvObject(JSContext *cx, JSStackFrame *fp) return NULL; /* Init immediately to avoid GC seeing a half-init'ed object. */ - envobj->init(&js_DeclEnvClass, NULL, fp->scopeChain, reinterpret_cast(fp)); + envobj->init(&js_DeclEnvClass, NULL, fp->scopeChain, PrivateValue(fp)); envobj->map = cx->runtime->emptyDeclEnvScope->hold(); return envobj; } @@ -796,7 +794,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp) #ifdef DEBUG /* A call object should be a frame's outermost scope chain element. */ - JSClass *classp = fp->scopeChain->getClass(); + Class *classp = fp->scopeChain->getClass(); if (classp == &js_WithClass || classp == &js_BlockClass) JS_ASSERT(fp->scopeChain->getPrivate() != js_FloatingFrameIfGenerator(cx, fp)); else if (classp == &js_CallClass) @@ -833,7 +831,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp) callobj->setPrivate(fp); JS_ASSERT(fp->argv); - JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->calleeObject())); + JS_ASSERT(fp->fun == GET_FUNCTION_PRIVATE(cx, fp->callee())); callobj->setSlot(JSSLOT_CALLEE, fp->calleeValue()); fp->callobj = callobj; @@ -852,7 +850,7 @@ js_CreateCallObjectOnTrace(JSContext *cx, JSFunction *fun, JSObject *callee, JSO JSObject *callobj = NewCallObject(cx, fun, scopeChain); if (!callobj) return NULL; - callobj->setSlot(JSSLOT_CALLEE, OBJECT_TO_JSVAL(callee)); + callobj->setSlot(JSSLOT_CALLEE, ObjectValue(*callee)); return callobj; } @@ -862,23 +860,21 @@ JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CreateCallObjectOnTrace, CONTEXT, FUNCTI JSFunction * js_GetCallObjectFunction(JSObject *obj) { - jsval v; - JS_ASSERT(obj->getClass() == &js_CallClass); - v = obj->getSlot(JSSLOT_CALLEE); - if (JSVAL_IS_VOID(v)) { + const Value &v = obj->getSlot(JSSLOT_CALLEE); + if (v.isUndefined()) { /* Newborn or prototype object. */ return NULL; } - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); - return GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v)); + JS_ASSERT(v.isObject()); + return GET_FUNCTION_PRIVATE(cx, &v.toObject()); } inline static void -CopyValuesToCallObject(JSObject *callobj, int nargs, jsval *argv, int nvars, jsval *slots) +CopyValuesToCallObject(JSObject *callobj, int nargs, Value *argv, int nvars, Value *slots) { - memcpy(callobj->dslots, argv, nargs * sizeof(jsval)); - memcpy(callobj->dslots + nargs, slots, nvars * sizeof(jsval)); + memcpy(callobj->dslots, argv, nargs * sizeof(Value)); + memcpy(callobj->dslots + nargs, slots, nvars * sizeof(Value)); } void @@ -890,7 +886,7 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp) /* Get the arguments object to snapshot fp's actual argument values. */ if (fp->argsobj) { if (!(fp->flags & JSFRAME_OVERRIDE_ARGS)) - callobj->setSlot(JSSLOT_CALL_ARGUMENTS, fp->argsobj); + callobj->setSlot(JSSLOT_CALL_ARGUMENTS, ObjectOrNullValue(fp->argsobj)); js_PutArgsObject(cx, fp); } @@ -924,8 +920,8 @@ js_PutCallObject(JSContext *cx, JSStackFrame *fp) } JSBool JS_FASTCALL -js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, jsval *argv, - uint32 nvars, jsval *slots) +js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, Value *argv, + uint32 nvars, Value *slots) { JS_ASSERT(scopeChain->hasClass(&js_CallClass)); JS_ASSERT(!scopeChain->getPrivate()); @@ -937,8 +933,8 @@ js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, jsval return true; } -JS_DEFINE_CALLINFO_6(extern, BOOL, js_PutCallObjectOnTrace, CONTEXT, OBJECT, UINT32, JSVALPTR, - UINT32, JSVALPTR, 0, nanojit::ACC_STORE_ANY) +JS_DEFINE_CALLINFO_6(extern, BOOL, js_PutCallObjectOnTrace, CONTEXT, OBJECT, UINT32, VALUEPTR, + UINT32, VALUEPTR, 0, nanojit::ACC_STORE_ANY) static JSBool call_enumerate(JSContext *cx, JSObject *obj) @@ -1003,20 +999,20 @@ enum JSCallPropertyKind { }; static JSBool -CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp, +CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, Value *vp, JSCallPropertyKind kind, JSBool setter = false) { JS_ASSERT(obj->getClass() == &js_CallClass); uintN i = 0; if (kind != JSCPK_ARGUMENTS) { - JS_ASSERT((int16) JSVAL_TO_INT(id) == JSVAL_TO_INT(id)); - i = (uint16) JSVAL_TO_INT(id); + JS_ASSERT((int16) JSID_TO_INT(id) == JSID_TO_INT(id)); + i = (uint16) JSID_TO_INT(id); } - jsval *array; + Value *array; if (kind == JSCPK_UPVAR) { - JSObject *callee = JSVAL_TO_OBJECT(obj->getSlot(JSSLOT_CALLEE)); + JSObject *callee = &obj->getSlot(JSSLOT_CALLEE).toObject(); #ifdef DEBUG JSFunction *callee_fun = (JSFunction *) callee->getPrivate(); @@ -1044,7 +1040,7 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp, argsobj = js_GetArgsObject(cx, fp); if (!argsobj) return false; - *vp = OBJECT_TO_JSVAL(argsobj); + vp->setObject(*argsobj); } else { *vp = obj->getSlot(JSSLOT_CALL_ARGUMENTS); } @@ -1059,8 +1055,8 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp, else JS_ASSERT(kind == JSCPK_ARG); return setter - ? JS_SetReservedSlot(cx, obj, i, *vp) - : JS_GetReservedSlot(cx, obj, i, vp); + ? JS_SetReservedSlot(cx, obj, i, Jsvalify(*vp)) + : JS_GetReservedSlot(cx, obj, i, Jsvalify(vp)); } if (kind == JSCPK_ARG) { @@ -1081,49 +1077,49 @@ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp, } static JSBool -GetCallArguments(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +GetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS); } static JSBool -SetCallArguments(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +SetCallArguments(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS, true); } JSBool -js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG); } JSBool -SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +SetCallArg(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, true); } JSBool -GetFlatUpvar(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +GetFlatUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CallPropertyOp(cx, obj, id, vp, JSCPK_UPVAR); } JSBool -SetFlatUpvar(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +SetFlatUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CallPropertyOp(cx, obj, id, vp, JSCPK_UPVAR, true); } JSBool -js_GetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +js_GetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR); } JSBool -js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, Value *vp) { if (!CallPropertyOp(cx, obj, id, vp, JSCPK_VAR)) return false; @@ -1132,51 +1128,50 @@ js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, jsval *vp) } JSBool -SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +SetCallVar(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, true); } +#if JS_TRACER JSBool JS_FASTCALL -js_SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval v) +js_SetCallArg(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg) { - return CallPropertyOp(cx, obj, id, &v, JSCPK_ARG, true); + Value argcopy = ValueArgToConstRef(arg); + return CallPropertyOp(cx, obj, slotid, &argcopy, JSCPK_ARG, true); } +JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallArg, CONTEXT, OBJECT, JSID, VALUE, 0, + nanojit::ACC_STORE_ANY) JSBool JS_FASTCALL -js_SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval v) +js_SetCallVar(JSContext *cx, JSObject *obj, jsid slotid, ValueArgType arg) { - return CallPropertyOp(cx, obj, id, &v, JSCPK_VAR, true); + Value argcopy = ValueArgToConstRef(arg); + return CallPropertyOp(cx, obj, slotid, &argcopy, JSCPK_VAR, true); } - -JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallArg, CONTEXT, OBJECT, JSID, JSVAL, 0, - nanojit::ACC_STORE_ANY) -JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, JSVAL, 0, +JS_DEFINE_CALLINFO_4(extern, BOOL, js_SetCallVar, CONTEXT, OBJECT, JSID, VALUE, 0, nanojit::ACC_STORE_ANY) +#endif static JSBool -call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, +call_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { - jsval callee; JSFunction *fun; JSLocalKind localKind; - JSPropertyOp getter, setter; + PropertyOp getter, setter; uintN slot, attrs; JS_ASSERT(obj->getClass() == &js_CallClass); JS_ASSERT(!obj->getProto()); - if (!JSVAL_IS_STRING(idval)) + if (!JSID_IS_ATOM(id)) return JS_TRUE; - JS_ASSERT(JSVAL_TO_STRING(idval)->isAtomized()); - jsid id = (jsval)idval; - - callee = obj->getSlot(JSSLOT_CALLEE); - if (JSVAL_IS_VOID(callee)) + const Value &callee = obj->getSlot(JSSLOT_CALLEE); + if (callee.isUndefined()) return JS_TRUE; - fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(callee)); + fun = GET_FUNCTION_PRIVATE(cx, &callee.toObject()); /* * Check whether the id refers to a formal parameter, local variable or @@ -1225,15 +1220,16 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, * This way we penalize performance only slightly on first use of a * null closure, not on every use. */ - jsval v; + Value v; if (!CallPropertyOp(cx, obj, INT_TO_JSID((int16)slot), &v, cpkind)) return JS_FALSE; - if (VALUE_IS_FUNCTION(cx, v) && - GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v))->needsWrapper()) { + JSObject *funobj; + if (IsFunctionObject(v, &funobj) && + GET_FUNCTION_PRIVATE(cx, funobj)->needsWrapper()) { getter = js_GetCallVarChecked; } } - if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, getter, setter, + if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), getter, setter, attrs, JSScopeProperty::HAS_SHORTID, (int16) slot, NULL, JSDNP_DONT_PURGE)) { return JS_FALSE; @@ -1246,8 +1242,8 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, * Resolve arguments so that we never store a particular Call object's * arguments object reference in a Call prototype's |arguments| slot. */ - if (id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) { - if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, + if (JSID_IS_ATOM(id, cx->runtime->atomState.argumentsAtom)) { + if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), GetCallArguments, SetCallArguments, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0, NULL, JSDNP_DONT_PURGE)) { @@ -1261,13 +1257,13 @@ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, return JS_TRUE; } -JS_FRIEND_DATA(JSClass) js_CallClass = { +JS_PUBLIC_DATA(Class) js_CallClass = { "Call", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CALL_CLASS_FIXED_RESERVED_SLOTS) | JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE, - JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, + PropertyStub, PropertyStub, + PropertyStub, PropertyStub, call_enumerate, (JSResolveOp)call_resolve, NULL, NULL, NULL, NULL, @@ -1286,12 +1282,12 @@ enum { }; static JSBool -fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +fun_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - if (!JSVAL_IS_INT(id)) + if (!JSID_IS_INT(id)) return JS_TRUE; - jsint slot = JSVAL_TO_INT(id); + jsint slot = JSID_TO_INT(id); /* * Loop because getter and setter can be delegated from another class, @@ -1315,7 +1311,7 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) */ JSFunction *fun; while (!(fun = (JSFunction *) - JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { + GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) { if (slot != FUN_LENGTH) return JS_TRUE; obj = obj->getProto(); @@ -1345,19 +1341,18 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) if (!js_GetArgsValue(cx, fp, vp)) return JS_FALSE; } else { - *vp = JSVAL_NULL; + vp->setNull(); } break; case FUN_LENGTH: case FUN_ARITY: - *vp = INT_TO_JSVAL((jsint)fun->nargs); + vp->setInt32(fun->nargs); break; case FUN_NAME: - *vp = fun->atom - ? ATOM_KEY(fun->atom) - : STRING_TO_JSVAL(cx->runtime->emptyString); + vp->setString(fun->atom ? ATOM_TO_STRING(fun->atom) + : cx->runtime->emptyString); break; case FUN_CALLER: @@ -1373,20 +1368,20 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSObject *wrapper = WrapEscapingClosure(cx, fp->down, FUN_OBJECT(caller), caller); if (!wrapper) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(wrapper); + vp->setObject(*wrapper); return JS_TRUE; } JS_ASSERT(fp->down->argv); *vp = fp->down->calleeValue(); } else { - *vp = JSVAL_NULL; + vp->setNull(); } /* Censor the caller if it is from another compartment. */ - if (!JSVAL_IS_PRIMITIVE(*vp)) { - if (JSVAL_TO_OBJECT(*vp)->getCompartment(cx) != cx->compartment) - *vp = JSVAL_NULL; + if (vp->isObject()) { + if (vp->toObject().getCompartment(cx) != cx->compartment) + vp->setNull(); } break; @@ -1438,10 +1433,10 @@ fun_enumerate(JSContext *cx, JSObject *obj) } static JSBool -fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +fun_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { - if (!JSVAL_IS_STRING(id)) + if (!JSID_IS_ATOM(id)) return JS_TRUE; JSFunction *fun = GET_FUNCTION_PRIVATE(cx, obj); @@ -1451,7 +1446,7 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, * fun is not a compiler-created function object, which must never leak to * script or embedding code and then be mutated. */ - if ((flags & JSRESOLVE_ASSIGNING) && id != ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { + if ((flags & JSRESOLVE_ASSIGNING) && !JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { JS_ASSERT(!IsInternalFunctionObject(obj)); return JS_TRUE; } @@ -1500,8 +1495,8 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, atom = cx->runtime->atomState.lengthAtom; if (id == ATOM_TO_JSID(atom)) { JS_ASSERT(!IsInternalFunctionObject(obj)); - if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), INT_TO_JSVAL(jsint(fun->nargs)), - JS_PropertyStub, JS_PropertyStub, + if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), Int32Value(fun->nargs), + PropertyStub, PropertyStub, JSPROP_PERMANENT | JSPROP_READONLY, 0, 0, NULL)) { return JS_FALSE; } @@ -1513,12 +1508,12 @@ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, LazyFunctionProp *lfp = &lazy_function_props[i]; atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset); - if (id == ATOM_KEY(atom)) { + if (id == ATOM_TO_JSID(atom)) { JS_ASSERT(!IsInternalFunctionObject(obj)); if (!js_DefineNativeProperty(cx, obj, - ATOM_TO_JSID(atom), JSVAL_VOID, - fun_getProperty, JS_PropertyStub, + ATOM_TO_JSID(atom), UndefinedValue(), + fun_getProperty, PropertyStub, lfp->attrs, JSScopeProperty::HAS_SHORTID, lfp->tinyid, NULL)) { return JS_FALSE; @@ -1579,7 +1574,7 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) #endif } - AutoValueRooter tvr(cx, FUN_OBJECT(fun)); + AutoObjectRooter tvr(cx, FUN_OBJECT(fun)); if (!JS_XDRUint32(xdr, &firstword)) return false; @@ -1729,24 +1724,24 @@ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp) * if v is an object) returning true if .prototype is found. */ static JSBool -fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +fun_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) { - jsval pval; jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); + Value pval; if (!obj->getProperty(cx, id, &pval)) return JS_FALSE; - if (JSVAL_IS_PRIMITIVE(pval)) { + if (pval.isPrimitive()) { /* * Throw a runtime error if instanceof is called on a function that * has a non-object as its .prototype value. */ - js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, - -1, OBJECT_TO_JSVAL(obj), NULL); + js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, ObjectValue(*obj), NULL); return JS_FALSE; } - return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp); + *bp = js_IsDelegate(cx, &pval.toObject(), *v); + return JS_TRUE; } static void @@ -1827,14 +1822,14 @@ JSFunction::countInterpretedReservedSlots() const * does not bloat every instance, only those on which reserved slots are set, * and those on which ad-hoc properties are defined. */ -JS_FRIEND_DATA(JSClass) js_FunctionClass = { +JS_PUBLIC_DATA(Class) js_FunctionClass = { js_Function_str, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function), - JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, + PropertyStub, PropertyStub, + PropertyStub, PropertyStub, fun_enumerate, (JSResolveOp)fun_resolve, - JS_ConvertStub, fun_finalize, + ConvertStub, fun_finalize, NULL, NULL, NULL, NULL, js_XDRFunctionObject, fun_hasInstance, @@ -1862,18 +1857,18 @@ fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent) return JS_DecompileFunction(cx, fun, indent); } -} +} /* namespace js */ static JSBool -fun_toString(JSContext *cx, uintN argc, jsval *vp) +fun_toString(JSContext *cx, uintN argc, Value *vp) { - JS_ASSERT(VALUE_IS_FUNCTION(cx, vp[0])); + JS_ASSERT(IsFunctionObject(vp[0])); uint32_t indent = 0; if (argc != 0 && !ValueToECMAUint32(cx, vp[2], &indent)) return false; - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return false; @@ -1881,17 +1876,17 @@ fun_toString(JSContext *cx, uintN argc, jsval *vp) if (!str) return false; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return true; } #if JS_HAS_TOSOURCE static JSBool -fun_toSource(JSContext *cx, uintN argc, jsval *vp) +fun_toSource(JSContext *cx, uintN argc, Value *vp) { - JS_ASSERT(VALUE_IS_FUNCTION(cx, vp[0])); + JS_ASSERT(IsFunctionObject(vp[0])); - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return false; @@ -1899,28 +1894,23 @@ fun_toSource(JSContext *cx, uintN argc, jsval *vp) if (!str) return false; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return true; } #endif JSBool -js_fun_call(JSContext *cx, uintN argc, jsval *vp) +js_fun_call(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - jsval fval, *argv; - JSString *str; - JSBool ok; - LeaveTrace(cx); - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return JS_FALSE; - fval = vp[1]; + Value fval = vp[1]; if (!js_IsCallable(fval)) { - str = JS_ValueToString(cx, fval); + JSString *str = js_ValueToString(cx, fval); if (str) { const char *bytes = js_GetStringBytes(cx, str); @@ -1934,15 +1924,15 @@ js_fun_call(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - argv = vp + 2; + Value *argv = vp + 2; if (argc == 0) { /* Call fun with its global object as the 'this' param if no args. */ obj = NULL; } else { /* Otherwise convert the first arg to 'this' and skip over it. */ - if (!JSVAL_IS_PRIMITIVE(argv[0])) - obj = JSVAL_TO_OBJECT(argv[0]); - else if (!js_ValueToObject(cx, argv[0], &obj)) + if (argv[0].isObject()) + obj = &argv[0].toObject(); + else if (!js_ValueToObjectOrNull(cx, argv[0], &obj)) return JS_FALSE; argc--; argv++; @@ -1955,24 +1945,17 @@ js_fun_call(JSContext *cx, uintN argc, jsval *vp) /* Push fval, obj, and the args. */ args.getvp()[0] = fval; - args.getvp()[1] = OBJECT_TO_JSVAL(obj); + args.getvp()[1] = ObjectOrNullValue(obj); memcpy(args.getvp() + 2, argv, argc * sizeof *argv); - ok = js_Invoke(cx, args, 0); + bool ok = Invoke(cx, args, 0); *vp = *args.getvp(); return ok; } JSBool -js_fun_apply(JSContext *cx, uintN argc, jsval *vp) +js_fun_apply(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj, *aobj; - jsval fval, *sp; - JSString *str; - jsuint length; - JSBool arraylike; - uintN i; - if (argc == 0) { /* Will get globalObject as 'this' and no other arguments. */ return js_fun_call(cx, argc, vp); @@ -1980,13 +1963,13 @@ js_fun_apply(JSContext *cx, uintN argc, jsval *vp) LeaveTrace(cx); - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return JS_FALSE; - fval = vp[1]; + Value fval = vp[1]; if (!js_IsCallable(fval)) { - str = JS_ValueToString(cx, fval); + JSString *str = js_ValueToString(cx, fval); if (str) { const char *bytes = js_GetStringBytes(cx, str); @@ -2001,18 +1984,18 @@ js_fun_apply(JSContext *cx, uintN argc, jsval *vp) } /* Quell GCC overwarnings. */ - aobj = NULL; - length = 0; + JSObject *aobj = NULL; + jsuint length = 0; if (argc >= 2) { /* If the 2nd arg is null or void, call the function with 0 args. */ - if (JSVAL_IS_NULL(vp[3]) || JSVAL_IS_VOID(vp[3])) { + if (vp[3].isNullOrUndefined()) { argc = 0; } else { /* The second arg must be an array (or arguments object). */ - arraylike = JS_FALSE; - if (!JSVAL_IS_PRIMITIVE(vp[3])) { - aobj = JSVAL_TO_OBJECT(vp[3]); + JSBool arraylike = JS_FALSE; + if (vp[3].isObject()) { + aobj = &vp[3].toObject(); if (!js_IsArrayLike(cx, aobj, &arraylike, &length)) return JS_FALSE; } @@ -2025,9 +2008,9 @@ js_fun_apply(JSContext *cx, uintN argc, jsval *vp) } /* Convert the first arg to 'this' and skip over it. */ - if (!JSVAL_IS_PRIMITIVE(vp[2])) - obj = JSVAL_TO_OBJECT(vp[2]); - else if (!js_ValueToObject(cx, vp[2], &obj)) + if (vp[2].isObject()) + obj = &vp[2].toObject(); + else if (!js_ValueToObjectOrNull(cx, vp[2], &obj)) return JS_FALSE; /* Allocate stack space for fval, obj, and the args. */ @@ -2038,9 +2021,9 @@ js_fun_apply(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; /* Push fval, obj, and aobj's elements as args. */ - sp = args.getvp(); + Value *sp = args.getvp(); *sp++ = fval; - *sp++ = OBJECT_TO_JSVAL(obj); + *sp++ = ObjectOrNullValue(obj); if (aobj && aobj->isArguments() && !aobj->isArgsLengthOverridden()) { /* * Two cases, two loops: note how in the case of an active stack frame @@ -2050,40 +2033,40 @@ js_fun_apply(JSContext *cx, uintN argc, jsval *vp) */ JSStackFrame *fp = (JSStackFrame *) aobj->getPrivate(); if (fp) { - memcpy(sp, fp->argv, argc * sizeof(jsval)); - for (i = 0; i < argc; i++) { - if (aobj->getArgsElement(i) == JSVAL_HOLE) // suppress deleted element - sp[i] = JSVAL_VOID; + memcpy(sp, fp->argv, argc * sizeof(Value)); + for (uintN i = 0; i < argc; i++) { + if (aobj->getArgsElement(i).isMagic(JS_ARGS_HOLE)) // suppress deleted element + sp[i].setUndefined(); } } else { - for (i = 0; i < argc; i++) { + for (uintN i = 0; i < argc; i++) { sp[i] = aobj->getArgsElement(i); - if (sp[i] == JSVAL_HOLE) - sp[i] = JSVAL_VOID; + if (sp[i].isMagic(JS_ARGS_HOLE)) + sp[i].setUndefined(); } } } else { - for (i = 0; i < argc; i++) { + for (uintN i = 0; i < argc; i++) { if (!aobj->getProperty(cx, INT_TO_JSID(jsint(i)), sp)) return JS_FALSE; sp++; } } - JSBool ok = js_Invoke(cx, args, 0); + bool ok = Invoke(cx, args, 0); *vp = *args.getvp(); return ok; } #ifdef NARCISSUS static JS_REQUIRES_STACK JSBool -fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) +fun_applyConstructor(JSContext *cx, uintN argc, Value *vp) { JSObject *aobj; uintN length, i; - if (JSVAL_IS_PRIMITIVE(vp[2]) || - (aobj = JSVAL_TO_OBJECT(vp[2]), + if (vp[2].isPrimitive() || + (aobj = &vp[2].toObject(), !aobj->isArray() && !aobj->isArguments())) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, @@ -2101,16 +2084,16 @@ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) if (!cx->stack().pushInvokeArgs(cx, length, args)) return JS_FALSE; - jsval *sp = args.getvp(); + Value *sp = args.getvp(); *sp++ = vp[1]; - *sp++ = JSVAL_NULL; /* this is filled automagically */ + *sp++ = NullValue(); /* this is filled automagically */ for (i = 0; i < length; i++) { if (!aobj->getProperty(cx, INT_TO_JSID(jsint(i)), sp)) return JS_FALSE; sp++; } - JSBool ok = js_InvokeConstructor(cx, args); + JSBool ok = InvokeConstructor(cx, args); *vp = *args.getvp(); return ok; } @@ -2130,7 +2113,7 @@ static JSFunctionSpec function_methods[] = { }; static JSBool -Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Function(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { JSFunction *fun; JSObject *parent; @@ -2151,7 +2134,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) obj = NewObject(cx, &js_FunctionClass, NULL, NULL); if (!obj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); } else { /* * The constructor is called before the private slot is initialized so @@ -2171,7 +2154,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * its running context's globalObject, which might be different from the * top-level reachable from scopeChain (in HTML frames, e.g.). */ - parent = JSVAL_TO_OBJECT(argv[-2])->getParent(); + parent = argv[-2].toObject().getParent(); fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED, parent, cx->runtime->atomState.anonymousAtom); @@ -2236,7 +2219,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) arg = js_ValueToString(cx, argv[i]); if (!arg) return JS_FALSE; - argv[i] = STRING_TO_JSVAL(arg); + argv[i].setString(arg); /* * Check for overflow. The < test works because the maximum @@ -2277,7 +2260,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Concatenate the arguments into the new string, separated by commas. */ for (i = 0; i < n; i++) { - arg = JSVAL_TO_STRING(argv[i]); + arg = argv[i].toString(); arg_length = arg->length(); (void) js_strncpy(cp, arg->chars(), arg_length); cp += arg_length; @@ -2357,7 +2340,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) str = js_ValueToString(cx, argv[argc-1]); if (!str) return JS_FALSE; - argv[argc-1] = STRING_TO_JSVAL(str); + argv[argc-1].setString(str); } else { str = cx->runtime->emptyString; } @@ -2373,7 +2356,7 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj) JSObject *proto; JSFunction *fun; - proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1, + proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1, NULL, function_methods, NULL, NULL); if (!proto) return NULL; @@ -2385,7 +2368,7 @@ js_InitFunctionClass(JSContext *cx, JSObject *obj) } JSFunction * -js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, +js_NewFunction(JSContext *cx, JSObject *funobj, Native native, uintN nargs, uintN flags, JSObject *parent, JSAtom *atom) { JSFunction *fun; @@ -2423,7 +2406,7 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, #ifdef JS_TRACER JSNativeTraceInfo *trcinfo = JS_FUNC_TO_DATA_PTR(JSNativeTraceInfo *, native); - fun->u.n.native = (JSNative) trcinfo->native; + fun->u.n.native = (js::Native) trcinfo->native; fun->u.n.trcinfo = trcinfo; #else fun->u.n.trcinfo = NULL; @@ -2509,7 +2492,7 @@ js_NewFlatClosure(JSContext *cx, JSFunction *fun) return closure; JSUpvarArray *uva = fun->u.i.script->upvars(); - JS_ASSERT(uva->length <= size_t(closure->dslots[-1])); + JS_ASSERT(uva->length <= closure->dslots[-1].toPrivateUint32()); uintN level = fun->u.i.script->staticLevel; for (uint32 i = 0, n = uva->length; i < n; i++) @@ -2529,10 +2512,10 @@ js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun) } JSFunction * -js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, +js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, Native native, uintN nargs, uintN attrs) { - JSPropertyOp gsop; + PropertyOp gsop; JSFunction *fun; if (attrs & JSFUN_STUB_GSOPS) { @@ -2543,14 +2526,14 @@ js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, * for more on this. */ attrs &= ~JSFUN_STUB_GSOPS; - gsop = JS_PropertyStub; + gsop = PropertyStub; } else { gsop = NULL; } fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom); if (!fun) return NULL; - if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)), + if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ObjectValue(*fun), gsop, gsop, attrs & ~JSFUN_FLAGS_MASK)) { return NULL; } @@ -2562,32 +2545,31 @@ js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, #endif JSFunction * -js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags) +js_ValueToFunction(JSContext *cx, const Value *vp, uintN flags) { - jsval v; - - v = *vp; - if (!VALUE_IS_FUNCTION(cx, v)) { + JSObject *funobj; + if (!IsFunctionObject(*vp, &funobj)) { js_ReportIsNotFunction(cx, vp, flags); return NULL; } - return GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v)); + return GET_FUNCTION_PRIVATE(cx, funobj); } JSObject * -js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags) +js_ValueToFunctionObject(JSContext *cx, Value *vp, uintN flags) { JSFunction *fun; JSStackFrame *caller; JSPrincipals *principals; - if (VALUE_IS_FUNCTION(cx, *vp)) - return JSVAL_TO_OBJECT(*vp); + JSObject *funobj; + if (IsFunctionObject(*vp, &funobj)) + return funobj; fun = js_ValueToFunction(cx, vp, flags); if (!fun) return NULL; - *vp = OBJECT_TO_JSVAL(FUN_OBJECT(fun)); + vp->setObject(*fun); caller = js_GetScriptedCaller(cx, NULL); if (caller) { @@ -2607,19 +2589,18 @@ js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags) } JSObject * -js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags) +js_ValueToCallableObject(JSContext *cx, Value *vp, uintN flags) { - JSObject *callable = JSVAL_IS_OBJECT(*vp) ? JSVAL_TO_OBJECT(*vp) : NULL; - - if (callable && callable->isCallable()) { - *vp = OBJECT_TO_JSVAL(callable); - return callable; + if (vp->isObject()) { + JSObject *callable = &vp->toObject(); + if (callable->isCallable()) + return callable; } return js_ValueToFunctionObject(cx, vp, flags); } void -js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) +js_ReportIsNotFunction(JSContext *cx, const Value *vp, uintN flags) { const char *name = NULL, *source = NULL; AutoValueRooter tvr(cx); @@ -2630,7 +2611,7 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) ++i; ptrdiff_t spindex = - (!i.done() && StackBase(i.fp()) <= vp && vp < i.sp()) + (!i.done() && i.fp()->base() <= vp && vp < i.sp()) ? vp - i.sp() : ((flags & JSV2F_SEARCH_STACK) ? JSDVG_SEARCH_STACK : JSDVG_IGNORE_STACK); @@ -2646,12 +2627,6 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags) JS_STATIC_ASSERT(2 <= MAX_ARRAY_LOCALS); JS_STATIC_ASSERT(MAX_ARRAY_LOCALS < JS_BITMASK(16)); -/* - * We use the lowest bit of the string atom to distinguish const from var - * name when there is only single name or when names are stored as an array. - */ -JS_STATIC_ASSERT((JSVAL_STRING & 1) == 0); - /* * When we use a hash table to store the local names, we use a singly linked * list to record the indexes of duplicated parameter names to preserve the @@ -2705,7 +2680,6 @@ HashLocalName(JSContext *cx, JSLocalNameMap *map, JSAtom *name, return JS_TRUE; } #endif - JS_ASSERT(ATOM_IS_STRING(name)); entry = (JSLocalNameHashEntry *) JS_DHashTableOperate(&map->names, name, JS_DHASH_ADD); if (!entry) { @@ -2938,7 +2912,7 @@ get_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr, return JS_DHASH_NEXT; } -JS_FRIEND_API(jsuword *) +jsuword * js_GetLocalNameArray(JSContext *cx, JSFunction *fun, JSArenaPool *pool) { uintN n; @@ -3001,7 +2975,7 @@ trace_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr, JS_SET_TRACING_INDEX(trc, entry->localKind == JSLOCAL_ARG ? "arg" : "var", entry->index); - js_CallGCMarker(trc, ATOM_TO_STRING(entry->name), JSTRACE_STRING); + Mark(trc, ATOM_TO_STRING(entry->name), JSTRACE_STRING); return JS_DHASH_NEXT; } @@ -3026,7 +3000,7 @@ TraceLocalNames(JSTracer *trc, JSFunction *fun) JS_SET_TRACING_INDEX(trc, i < fun->nargs ? "arg" : "var", i < fun->nargs ? i : i - fun->nargs); - js_CallGCMarker(trc, ATOM_TO_STRING(atom), JSTRACE_STRING); + Mark(trc, ATOM_TO_STRING(atom), JSTRACE_STRING); } } while (i != 0); } else { diff --git a/js/src/jsfun.h b/js/src/jsfun.h index c5539aac8467..b4d7aa15c48f 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -46,8 +46,6 @@ #include "jspubtd.h" #include "jsobj.h" -JS_BEGIN_EXTERN_C - typedef struct JSLocalNameMap JSLocalNameMap; /* @@ -117,7 +115,7 @@ typedef union JSLocalNames { #define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL) #define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL) #define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ - ? (JSFastNative) (fun)->u.n.native \ + ? (js::FastNative) (fun)->u.n.native \ : NULL) #define FUN_MINARGS(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ ? 0 \ @@ -137,8 +135,8 @@ struct JSFunction : public JSObject struct { uint16 extra; /* number of arg slots for local GC roots */ uint16 spare; /* reserved for future use */ - JSNative native; /* native method pointer or null */ - JSClass *clasp; /* class of objects constructed + js::Native native; /* native method pointer or null */ + js::Class *clasp; /* class of objects constructed by this function */ JSNativeTraceInfo *trcinfo; } n; @@ -164,7 +162,7 @@ struct JSFunction : public JSObject bool optimizedClosure() const { return FUN_KIND(this) > JSFUN_INTERPRETED; } bool needsWrapper() const { return FUN_NULL_CLOSURE(this) && u.i.skipmin != 0; } bool isInterpreted() const { return FUN_INTERPRETED(this); } - bool isFastNative() const { return flags & JSFUN_FAST_NATIVE; } + bool isFastNative() const { return !!(flags & JSFUN_FAST_NATIVE); } bool isHeavyweight() const { return JSFUN_HEAVYWEIGHT_TEST(flags); } unsigned minArgs() const { return FUN_MINARGS(this); } @@ -206,9 +204,11 @@ struct JSFunction : public JSObject } }; +JS_STATIC_ASSERT(sizeof(JSFunction) % JS_GCTHING_ALIGN == 0); + /* * Trace-annotated native. This expands to a JSFunctionSpec initializer (like - * JS_FN in jsapi.h). fastcall is a JSFastNative; trcinfo is a + * JS_FN in jsapi.h). fastcall is a FastNative; trcinfo is a * JSNativeTraceInfo*. */ #ifdef JS_TRACER @@ -234,7 +234,7 @@ struct JSFunction : public JSObject * Yes, this is an incompatible change, which prefigures the impending move to * single-threaded objects and GC heaps. */ -extern JSClass js_ArgumentsClass; +extern js::Class js_ArgumentsClass; inline bool JSObject::isArguments() const @@ -242,13 +242,11 @@ JSObject::isArguments() const return getClass() == &js_ArgumentsClass; } -extern JS_FRIEND_DATA(JSClass) js_CallClass; -extern JSClass js_DeclEnvClass; +extern JS_PUBLIC_DATA(js::Class) js_CallClass; +extern JS_PUBLIC_DATA(js::Class) js_FunctionClass; +extern js::Class js_DeclEnvClass; extern const uint32 CALL_CLASS_FIXED_RESERVED_SLOTS; -/* JS_FRIEND_DATA so that VALUE_IS_FUNCTION is callable from the shell. */ -extern JS_FRIEND_DATA(JSClass) js_FunctionClass; - inline bool JSObject::isFunction() const { @@ -265,9 +263,9 @@ JSObject::isCallable() } static inline bool -js_IsCallable(jsval v) +js_IsCallable(const js::Value &v) { - return !JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isCallable(); + return v.isObject() && v.toObject().isCallable(); } /* @@ -276,6 +274,18 @@ js_IsCallable(jsval v) #define VALUE_IS_FUNCTION(cx, v) \ (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isFunction()) +static JS_ALWAYS_INLINE bool +IsFunctionObject(const js::Value &v) +{ + return v.isObject() && v.toObject().isFunction(); +} + +static JS_ALWAYS_INLINE bool +IsFunctionObject(const js::Value &v, JSObject **funobj) +{ + return v.isObject() && (*funobj = &v.toObject())->isFunction(); +} + /* * Macro to access the private slot of the function object after the slot is * initialized. @@ -318,7 +328,7 @@ extern JSObject * js_InitArgumentsClass(JSContext *cx, JSObject *obj); extern JSFunction * -js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, +js_NewFunction(JSContext *cx, JSObject *funobj, js::Native native, uintN nargs, uintN flags, JSObject *parent, JSAtom *atom); extern void @@ -338,7 +348,6 @@ CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent) JSObject *proto; if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto)) return NULL; - JS_ASSERT(proto); return js_CloneFunctionObject(cx, fun, parent, proto); } @@ -349,7 +358,7 @@ extern JS_REQUIRES_STACK JSObject * js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun); extern JSFunction * -js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, +js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, js::Native native, uintN nargs, uintN flags); /* @@ -361,16 +370,16 @@ js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native, #define JSV2F_SEARCH_STACK 0x10000 extern JSFunction * -js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags); +js_ValueToFunction(JSContext *cx, const js::Value *vp, uintN flags); extern JSObject * -js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags); +js_ValueToFunctionObject(JSContext *cx, js::Value *vp, uintN flags); extern JSObject * -js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags); +js_ValueToCallableObject(JSContext *cx, js::Value *vp, uintN flags); extern void -js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags); +js_ReportIsNotFunction(JSContext *cx, const js::Value *vp, uintN flags); extern JSObject * js_GetCallObject(JSContext *cx, JSStackFrame *fp); @@ -382,48 +391,36 @@ extern void js_PutCallObject(JSContext *cx, JSStackFrame *fp); extern JSBool JS_FASTCALL -js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, jsval *argv, - uint32 nvars, jsval *slots); +js_PutCallObjectOnTrace(JSContext *cx, JSObject *scopeChain, uint32 nargs, + js::Value *argv, uint32 nvars, js::Value *slots); extern JSFunction * js_GetCallObjectFunction(JSObject *obj); extern JSBool -js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool -js_GetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +js_GetCallVar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool -SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +SetCallArg(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool -SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp); - -/* - * js_SetCallArg and js_SetCallVar are extern fastcall copies of the setter - * functions. These versions are required in order to set call vars from traces. - * The normal versions must not be fastcall because they are stored in the - * property ops map. - */ -extern JSBool JS_FASTCALL -js_SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval v); - -extern JSBool JS_FASTCALL -js_SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval v); +SetCallVar(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); /* * Slower version of js_GetCallVar used when call_resolve detects an attempt to * leak an optimized closure via indirect or debugger eval. */ extern JSBool -js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool -js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp); +js_GetArgsValue(JSContext *cx, JSStackFrame *fp, js::Value *vp); extern JSBool -js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp); +js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, js::Value *vp); extern JSObject * js_GetArgsObject(JSContext *cx, JSStackFrame *fp); @@ -452,7 +449,7 @@ const uint32 JS_ARGS_LENGTH_MAX = JS_BIT(19) - 1024; * we check first that the shift does not overflow uint32. */ JS_STATIC_ASSERT(JS_ARGS_LENGTH_MAX <= JS_BIT(30)); -JS_STATIC_ASSERT(jsval((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX); +JS_STATIC_ASSERT(((JS_ARGS_LENGTH_MAX << 1) | 1) <= JSVAL_INT_MAX); extern JSBool js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp); @@ -495,7 +492,7 @@ js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp); * If nameWord does not name a formal parameter, use JS_LOCAL_NAME_IS_CONST to * check if nameWord corresponds to the const declaration. */ -extern JS_FRIEND_API(jsuword *) +extern jsuword * js_GetLocalNameArray(JSContext *cx, JSFunction *fun, struct JSArenaPool *pool); #define JS_LOCAL_NAME_TO_ATOM(nameWord) \ @@ -508,19 +505,16 @@ extern void js_FreezeLocalNames(JSContext *cx, JSFunction *fun); extern JSBool -js_fun_apply(JSContext *cx, uintN argc, jsval *vp); +js_fun_apply(JSContext *cx, uintN argc, js::Value *vp); extern JSBool -js_fun_call(JSContext *cx, uintN argc, jsval *vp); +js_fun_call(JSContext *cx, uintN argc, js::Value *vp); -JS_END_EXTERN_C - namespace js { extern JSString * fun_toStringHelper(JSContext *cx, JSObject *obj, uintN indent); } - #endif /* jsfun_h___ */ diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 123c149f7cac..81e49e98975c 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -100,13 +100,11 @@ using namespace js; /* - * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and - * JSTRACE_STRING. + * Check that JSTRACE_XML follows JSTRACE_OBJECT and JSTRACE_STRING. */ JS_STATIC_ASSERT(JSTRACE_OBJECT == 0); -JS_STATIC_ASSERT(JSTRACE_DOUBLE == 1); -JS_STATIC_ASSERT(JSTRACE_STRING == 2); -JS_STATIC_ASSERT(JSTRACE_XML == 3); +JS_STATIC_ASSERT(JSTRACE_STRING == 1); +JS_STATIC_ASSERT(JSTRACE_XML == 2); /* * JS_IS_VALID_TRACE_KIND assumes that JSTRACE_STRING is the last non-xml @@ -114,11 +112,6 @@ JS_STATIC_ASSERT(JSTRACE_XML == 3); */ JS_STATIC_ASSERT(JSTRACE_STRING + 1 == JSTRACE_XML); -/* - * Check that we can use memset(p, 0, ...) to implement JS_CLEAR_WEAK_ROOTS. - */ -JS_STATIC_ASSERT(JSVAL_NULL == 0); - /* * Check consistency of external string constants from JSFinalizeGCThingKind. */ @@ -801,8 +794,6 @@ GetFinalizableArenaTraceKind(JSGCArenaInfo *ainfo) static inline size_t GetArenaTraceKind(JSGCArenaInfo *ainfo) { - if (!ainfo->list) - return JSTRACE_DOUBLE; return GetFinalizableArenaTraceKind(ainfo); } @@ -823,8 +814,6 @@ InitGCArenaLists(JSRuntime *rt) arenaList->thingKind = i; arenaList->thingSize = GetFinalizableThingSize(i); } - rt->gcDoubleArenaList.head = NULL; - rt->gcDoubleArenaList.cursor = NULL; } static void @@ -834,8 +823,6 @@ FinishGCArenaLists(JSRuntime *rt) rt->gcArenaList[i].head = NULL; rt->gcArenaList[i].cursor = NULL; } - rt->gcDoubleArenaList.head = NULL; - rt->gcDoubleArenaList.cursor = NULL; rt->gcBytes = 0; @@ -885,6 +872,11 @@ js_IsAboutToBeFinalized(void *thing) JSBool js_InitGC(JSRuntime *rt, uint32 maxbytes) { +#if defined(XP_WIN) && defined(_M_X64) + if (!InitNtAllocAPIs()) + return JS_FALSE; +#endif + InitGCArenaLists(rt); if (!rt->gcRootsHash.init(256)) @@ -954,15 +946,13 @@ class ConservativeGCStackMarker { #ifdef JS_GCMETER JSConservativeGCStats *total = &trc->context->runtime->gcStats.conservative; total->words += stats.words; - total->oddaddress += stats.oddaddress; - total->special += stats.special; + total->lowbitset += stats.lowbitset; total->notarena += stats.notarena; total->notchunk += stats.notchunk; total->freearena += stats.freearena; total->wrongtag += stats.wrongtag; total->notlive += stats.notlive; total->gcthings += stats.gcthings; - total->raw += stats.raw; total->unmarked += stats.unmarked; #endif } @@ -1032,15 +1022,13 @@ ConservativeGCStackMarker::dumpStats(FILE *fp, JSConservativeGCStats *stats) #define ULSTAT(x) ((unsigned long)(stats->x)) fprintf(fp, "CONSERVATIVE STACK SCANNING:\n"); fprintf(fp, " number of stack words: %lu\n", ULSTAT(words)); - fprintf(fp, " excluded, low bit set: %lu\n", ULSTAT(oddaddress)); - fprintf(fp, " excluded, special: %lu\n", ULSTAT(special)); + fprintf(fp, " excluded, low bit set: %lu\n", ULSTAT(lowbitset)); fprintf(fp, " not withing a chunk: %lu\n", ULSTAT(notchunk)); fprintf(fp, " not within arena range: %lu\n", ULSTAT(notarena)); fprintf(fp, " points to free arena: %lu\n", ULSTAT(freearena)); fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(wrongtag)); fprintf(fp, " excluded, not live: %lu\n", ULSTAT(notlive)); fprintf(fp, " things marked: %lu\n", ULSTAT(gcthings)); - fprintf(fp, " raw pointers marked: %lu\n", ULSTAT(raw)); fprintf(fp, " conservative roots: %lu\n", ULSTAT(unmarked)); #undef ULSTAT } @@ -1088,15 +1076,10 @@ ConservativeGCStackMarker::dumpConservativeRoots() fprintf(fp, "string %s", buf); break; } - case JSTRACE_DOUBLE: { - jsdouble *dp = (jsdouble *) i->thing; - fprintf(fp, "double %e", *dp); - break; - } # if JS_HAS_XML_SUPPORT case JSTRACE_XML: { JSXML *xml = (JSXML *) i->thing; - fprintf(fp, "xml %u", xml->xml_class); + fprintf(fp, "xml %u", (unsigned)xml->xml_class); break; } # endif @@ -1110,6 +1093,8 @@ ConservativeGCStackMarker::dumpConservativeRoots() } #endif /* JS_DUMP_CONSERVATIVE_GC_ROOTS */ +static const jsuword JSID_PAYLOAD_MASK = (jsuword)~(jsuword)JSID_TYPE_MASK; + void ConservativeGCStackMarker::markWord(jsuword w) { @@ -1124,31 +1109,29 @@ ConservativeGCStackMarker::markWord(jsuword w) #endif #define RETURN(x) do { CONSERVATIVE_METER(stats.x++); return; } while (0) + /* * We assume that the compiler never uses sub-word alignment to store - * pointers and does not tag pointers on its own. Thus we exclude words - * with JSVAL_INT (any odd words) or JSVAL_SPECIAL tags as they never - * point to GC things. We also exclude words with a double tag that point - * into a non-double. But, for example, on 32-bit platforms we cannot - * exclude a pointer into an object arena tagged with JSVAL_STRING. The - * latter is 4 and a compiler can store a pointer not to the object but - * rather a pointer to its second field. + * pointers and does not tag pointers on its own. Additionally, the value + * representation for all values and the jsid representation for GC-things + * do not touch the low two bits. Thus any word with the low two bits set + * is not a valid GC-thing. */ - JS_STATIC_ASSERT(JSVAL_INT == 1); - JS_STATIC_ASSERT(JSVAL_DOUBLE == 2); - JS_STATIC_ASSERT(JSVAL_STRING == 4); - JS_STATIC_ASSERT(JSVAL_SPECIAL == 6); + JS_STATIC_ASSERT(JSID_TYPE_STRING == 0 && JSID_TYPE_OBJECT == 4); + if (w & 0x3) + RETURN(lowbitset); - if (w & 1) - RETURN(oddaddress); + /* + * An object jsid has its low bits tagged. In the value representation on + * 64-bit, the high bits are tagged. + */ +#if JS_BITS_PER_WORD == 32 + jsuword payload = w & JSID_PAYLOAD_MASK; +#elif JS_BITS_PER_WORD == 64 + jsuword payload = w & JSID_PAYLOAD_MASK & JSVAL_PAYLOAD_MASK; +#endif - /* Strip off the tag bits. */ - jsuword tag = w & JSVAL_TAGMASK; - - if (tag == JSVAL_SPECIAL) - RETURN(special); - - jsuword chunk = w & ~GC_CHUNK_MASK; + jsuword chunk = payload & ~GC_CHUNK_MASK; JSGCChunkInfo *ci; if (JS_LIKELY(chunkSet.initialized())) { if (!chunkSet.has(chunk)) @@ -1164,10 +1147,10 @@ ConservativeGCStackMarker::markWord(jsuword w) } } - if ((w & GC_CHUNK_MASK) >= GC_MARK_BITMAP_ARRAY_OFFSET) + if ((payload & GC_CHUNK_MASK) >= GC_MARK_BITMAP_ARRAY_OFFSET) RETURN(notarena); - size_t arenaIndex = (w & GC_CHUNK_MASK) >> GC_ARENA_SHIFT; + size_t arenaIndex = (payload & GC_CHUNK_MASK) >> GC_ARENA_SHIFT; if (JS_TEST_BIT(ci->getFreeArenaBitmap(), arenaIndex)) RETURN(freearena); @@ -1176,57 +1159,55 @@ ConservativeGCStackMarker::markWord(jsuword w) JSGCThing *thing; uint32 traceKind; - if (!ainfo->list) { /* doubles */ - if (tag && tag != JSVAL_DOUBLE) - RETURN(wrongtag); - JS_STATIC_ASSERT(JSVAL_TAGMASK == 7 && (sizeof(double) - 1) == 7); - thing = (JSGCThing *) (w & ~JSVAL_TAGMASK); - traceKind = JSTRACE_DOUBLE; - } else { - if (tag == JSVAL_DOUBLE) - RETURN(wrongtag); - traceKind = GetFinalizableArenaTraceKind(ainfo); -#if JS_BYTES_PER_WORD == 8 - if (tag == JSVAL_STRING && traceKind != JSTRACE_STRING) - RETURN(wrongtag); -#endif + traceKind = GetFinalizableArenaTraceKind(ainfo); - jsuword start = a->toPageStart(); - jsuword offset = w - start; - size_t thingSize = ainfo->list->thingSize; - offset -= offset % thingSize; + /* + * On 64-bit we might consider using the tag bits in w to disqualify + * additional false roots, however, the condition would have to look + * something like: + * + * if ((traceKind == JSTRACE_STRING && tag > 0 && tag != JSVAL_TAG_SHIFT) || + * (traceKind == JSTRACE_OBJECT && tag > 0 && tag != JSVAL_TAG_OBJECT)) + * RETURN(wrongtag); + * + * However, it seems like we should measure how often this actually avoids + * false roots. + */ - /* - * If GC_ARENA_SIZE % thingSize != 0 or when thingSize is not a power - * of two, thingSize-aligned pointer may point at the end of the last - * thing yet be inside the arena. - */ - if (offset + thingSize > GC_ARENA_SIZE) { - JS_ASSERT(thingSize & (thingSize - 1)); - RETURN(notarena); - } - thing = (JSGCThing *) (start + offset); + jsuword start = a->toPageStart(); + jsuword offset = payload - start; + size_t thingSize = ainfo->list->thingSize; + offset -= offset % thingSize; - /* Make sure the thing is not on the freelist of the arena. */ - JSGCThing *cursor = ainfo->freeList; - while (cursor) { - JS_ASSERT((((jsuword) cursor) & GC_ARENA_MASK) % thingSize == 0); - JS_ASSERT(!IsMarkedGCThing(cursor)); + /* + * If GC_ARENA_SIZE % thingSize != 0 or when thingSize is not a power + * of two, thingSize-aligned pointer may point at the end of the last + * thing yet be inside the arena. + */ + if (offset + thingSize > GC_ARENA_SIZE) { + JS_ASSERT(thingSize & (thingSize - 1)); + RETURN(notarena); + } + thing = (JSGCThing *) (start + offset); - /* If the cursor moves past the thing, it's not in the freelist. */ - if (thing < cursor) - break; + /* Make sure the thing is not on the freelist of the arena. */ + JSGCThing *cursor = ainfo->freeList; + while (cursor) { + JS_ASSERT((((jsuword) cursor) & GC_ARENA_MASK) % thingSize == 0); + JS_ASSERT(!IsMarkedGCThing(cursor)); - /* If we find it on the freelist, it's dead. */ - if (thing == cursor) - RETURN(notlive); - JS_ASSERT_IF(cursor->link, cursor < cursor->link); - cursor = cursor->link; - } + /* If the cursor moves past the thing, it's not in the freelist. */ + if (thing < cursor) + break; + + /* If we find it on the freelist, it's dead. */ + if (thing == cursor) + RETURN(notlive); + JS_ASSERT_IF(cursor->link, cursor < cursor->link); + cursor = cursor->link; } CONSERVATIVE_METER(stats.gcthings++); - CONSERVATIVE_METER_IF(!tag, stats.raw++); /* * We have now a valid pointer, that is either raw or tagged properly. @@ -1246,8 +1227,7 @@ ConservativeGCStackMarker::markWord(jsuword w) conservativeRoots.append(root); } #endif - JS_SET_TRACING_NAME(trc, "machine stack"); - js_CallGCMarker(trc, thing, traceKind); + Mark(trc, thing, traceKind, "machine stack"); #undef RETURN } @@ -1358,7 +1338,6 @@ JS_FRIEND_API(void) js_DumpGCStats(JSRuntime *rt, FILE *fp) { static const char *const GC_ARENA_NAMES[] = { - "double", "object", "function", #if JS_HAS_XML_SUPPORT @@ -1374,7 +1353,7 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp) "external_string_6", "external_string_7", }; - JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_ARENA_NAMES) == FINALIZE_LIMIT + 1); + JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GC_ARENA_NAMES) == FINALIZE_LIMIT); fprintf(fp, "\nGC allocation statistics:\n\n"); @@ -1394,23 +1373,17 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp) size_t sumLocalAlloc = 0; size_t sumFail = 0; size_t sumRetry = 0; - for (int i = -1; i < (int) FINALIZE_LIMIT; i++) { + for (int i = 0; i < (int) FINALIZE_LIMIT; i++) { size_t thingSize, thingsPerArena; JSGCArenaStats *st; - if (i == -1) { - thingSize = sizeof(jsdouble); - thingsPerArena = DOUBLES_PER_ARENA; - st = &rt->gcStats.doubleArenaStats; - } else { - thingSize = rt->gcArenaList[i].thingSize; - thingsPerArena = ThingsPerArena(thingSize); - st = &rt->gcStats.arenaStats[i]; - } + thingSize = rt->gcArenaList[i].thingSize; + thingsPerArena = ThingsPerArena(thingSize); + st = &rt->gcStats.arenaStats[i]; if (st->maxarenas == 0) continue; fprintf(fp, "%s arenas (thing size %lu, %lu things per arena):", - GC_ARENA_NAMES[i + 1], UL(thingSize), UL(thingsPerArena)); + GC_ARENA_NAMES[i], UL(thingSize), UL(thingsPerArena)); putc('\n', fp); fprintf(fp, " arenas before GC: %lu\n", UL(st->narenas)); fprintf(fp, " new arenas before GC: %lu (%.1f%%)\n", @@ -1443,23 +1416,17 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp) } fputs("Never used arenas:\n", fp); - for (int i = -1; i < (int) FINALIZE_LIMIT; i++) { + for (int i = 0; i < (int) FINALIZE_LIMIT; i++) { size_t thingSize, thingsPerArena; JSGCArenaStats *st; - if (i == -1) { - thingSize = sizeof(jsdouble); - thingsPerArena = DOUBLES_PER_ARENA; - st = &rt->gcStats.doubleArenaStats; - } else { - thingSize = rt->gcArenaList[i].thingSize; - thingsPerArena = ThingsPerArena(thingSize); - st = &rt->gcStats.arenaStats[i]; - } + thingSize = rt->gcArenaList[i].thingSize; + thingsPerArena = ThingsPerArena(thingSize); + st = &rt->gcStats.arenaStats[i]; if (st->maxarenas != 0) continue; fprintf(fp, "%s (thing size %lu, %lu things per arena)\n", - GC_ARENA_NAMES[i + 1], UL(thingSize), UL(thingsPerArena)); + GC_ARENA_NAMES[i], UL(thingSize), UL(thingsPerArena)); } fprintf(fp, "\nTOTAL STATS:\n"); fprintf(fp, " bytes allocated: %lu\n", UL(rt->gcBytes)); @@ -1533,9 +1500,9 @@ js_FinishGC(JSRuntime *rt) } JSBool -js_AddRoot(JSContext *cx, jsval *vp, const char *name) +js_AddRoot(JSContext *cx, Value *vp, const char *name) { - JSBool ok = js_AddRootRT(cx->runtime, vp, name); + JSBool ok = js_AddRootRT(cx->runtime, Jsvalify(vp), name); if (!ok) JS_ReportOutOfMemory(cx); return ok; @@ -1550,11 +1517,9 @@ js_AddGCThingRoot(JSContext *cx, void **rp, const char *name) return ok; } -static JSBool -AddRoot(JSRuntime *rt, void *rp, const char *name) +JS_FRIEND_API(JSBool) +js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name) { - js::GCRoots *roots = &rt->gcRootsHash; - /* * Due to the long-standing, but now removed, use of rt->gcLock across the * bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking @@ -1564,26 +1529,33 @@ AddRoot(JSRuntime *rt, void *rp, const char *name) */ AutoLockGC lock(rt); js_WaitForGC(rt); - return !!roots->put(rp, name); -} -JS_FRIEND_API(JSBool) -js_AddRootRT(JSRuntime *rt, jsval *vp, const char *name) -{ - return AddRoot(rt, vp, name); + return !!rt->gcRootsHash.put((void *)vp, + RootInfo(name, JS_GC_ROOT_VALUE_PTR)); } JS_FRIEND_API(JSBool) js_AddGCThingRootRT(JSRuntime *rt, void **rp, const char *name) { - return AddRoot(rt, rp, name); + /* + * Due to the long-standing, but now removed, use of rt->gcLock across the + * bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking + * properly with a racing GC, without calling JS_AddRoot from a request. + * We have to preserve API compatibility here, now that we avoid holding + * rt->gcLock across the mark phase (including the root hashtable mark). + */ + AutoLockGC lock(rt); + js_WaitForGC(rt); + + return !!rt->gcRootsHash.put((void *)rp, + RootInfo(name, JS_GC_ROOT_GCTHING_PTR)); } JS_FRIEND_API(JSBool) js_RemoveRoot(JSRuntime *rt, void *rp) { /* - * Due to the JS_RemoveRoot API, we may be called outside of a request. + * Due to the JS_RemoveRootRT API, we may be called outside of a request. * Same synchronization drill as above in js_AddRoot. */ AutoLockGC lock(rt); @@ -1593,6 +1565,10 @@ js_RemoveRoot(JSRuntime *rt, void *rp) return JS_TRUE; } +typedef RootedValueMap::Range RootRange; +typedef RootedValueMap::Entry RootEntry; +typedef RootedValueMap::Enum RootEnum; + #ifdef DEBUG static void @@ -1601,12 +1577,14 @@ CheckLeakedRoots(JSRuntime *rt) uint32 leakedroots = 0; /* Warn (but don't assert) debug builds of any remaining roots. */ - for (GCRoots::Range r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) { + for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) { + RootEntry &entry = r.front(); leakedroots++; fprintf(stderr, "JS engine warning: leaking GC root \'%s\' at %p\n", - r.front().value ? r.front().value : "", r.front().key); + entry.value.name ? entry.value.name : "", entry.key); } + if (leakedroots > 0) { if (leakedroots == 1) { fprintf(stderr, @@ -1626,12 +1604,13 @@ CheckLeakedRoots(JSRuntime *rt) void js_DumpNamedRoots(JSRuntime *rt, - void (*dump)(const char *name, void *rp, void *data), + void (*dump)(const char *name, void *rp, JSGCRootType type, void *data), void *data) { - for (GCRoots::Range r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) { - if (r.front().value) - dump(r.front().value, r.front().key, data); + for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) { + RootEntry &entry = r.front(); + if (const char *name = entry.value.name) + dump(name, entry.key, entry.value.type, data); } } @@ -1641,18 +1620,20 @@ uint32 js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data) { AutoLockGC lock(rt); - intN mapflags; - uint32 i = 0; + int ct = 0; + for (RootEnum e(rt->gcRootsHash); !e.empty(); e.popFront()) { + RootEntry &entry = e.front(); + + ct++; + intN mapflags = map(entry.key, entry.value.type, entry.value.name, data); - for (GCRoots::Enum e(rt->gcRootsHash); !e.empty(); e.popFront()) { - mapflags = map(e.front().key, e.front().value, data); - i++; if (mapflags & JS_MAP_GCROOT_REMOVE) e.removeFront(); if (mapflags & JS_MAP_GCROOT_STOP) break; } - return i; + + return ct; } void @@ -1690,14 +1671,12 @@ JSGCFreeLists::purge() *p = NULL; } } - doubles = NULL; } void JSGCFreeLists::moveTo(JSGCFreeLists *another) { *another = *this; - doubles = NULL; PodArrayZero(finalizables); JS_ASSERT(isEmpty()); } @@ -1866,173 +1845,6 @@ js_NewFinalizableGCThing(JSContext *cx, unsigned thingKind) return thing; } -static JSGCThing * -TurnUsedArenaIntoDoubleList(JSGCArena *a) -{ - JSGCThing *head; - JSGCThing **tailp = &head; - jsuword thing = a->toPageStart(); - jsbitmap *markBitmap = a->getMarkBitmap(); - jsbitmap *lastMarkWord = markBitmap + GC_MARK_BITMAP_WORDS - 1; - - for (jsbitmap *m = markBitmap; m <= lastMarkWord; ++m) { - JS_ASSERT(thing < a->toPageStart() + GC_ARENA_SIZE); - JS_ASSERT((thing - a->toPageStart()) % - (JS_BITS_PER_WORD * sizeof(jsdouble)) == 0); - - jsbitmap bits = *m; - if (bits == jsbitmap(-1)) { - thing += JS_BITS_PER_WORD * sizeof(jsdouble); - } else { - /* - * We have some zero bits. Turn corresponding cells into a list - * unrolling the loop for better performance. - */ - const unsigned unroll = 4; - const jsbitmap unrollMask = (jsbitmap(1) << unroll) - 1; - JS_STATIC_ASSERT((JS_BITS_PER_WORD & unrollMask) == 0); - - for (unsigned n = 0; n != JS_BITS_PER_WORD; n += unroll) { - jsbitmap bitsChunk = bits & unrollMask; - bits >>= unroll; - if (bitsChunk == unrollMask) { - thing += unroll * sizeof(jsdouble); - } else { -#define DO_BIT(bit) \ - if (!(bitsChunk & (jsbitmap(1) << (bit)))) { \ - JS_ASSERT(thing - a->toPageStart() <= \ - (DOUBLES_PER_ARENA - 1) * sizeof(jsdouble));\ - JSGCThing *t = reinterpret_cast(thing); \ - *tailp = t; \ - tailp = &t->link; \ - } \ - thing += sizeof(jsdouble); - DO_BIT(0); - DO_BIT(1); - DO_BIT(2); - DO_BIT(3); -#undef DO_BIT - } - } - } - } - *tailp = NULL; - return head; -} - -static JSGCThing * -RefillDoubleFreeList(JSContext *cx) -{ - JS_ASSERT(!JS_THREAD_DATA(cx)->gcFreeLists.doubles); - - JSRuntime *rt = cx->runtime; - JS_ASSERT(!rt->gcRunning); - - JS_LOCK_GC(rt); - - bool canGC = !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota; - bool doGC = canGC && IsGCThresholdReached(rt); - JSGCArena *a; - for (;;) { - if (doGC) { - LastDitchGC(cx); - METER(rt->gcStats.doubleArenaStats.retry++); - canGC = false; - - /* See comments in RefillFinalizableFreeList. */ - JSGCThing *freeList = JS_THREAD_DATA(cx)->gcFreeLists.doubles; - if (freeList) { - JS_UNLOCK_GC(rt); - return freeList; - } - } - - /* - * Loop until we find arena with some free doubles. We turn arenas - * into free lists outside the lock to minimize contention between - * threads. - */ - while (!!(a = rt->gcDoubleArenaList.cursor)) { - rt->gcDoubleArenaList.cursor = a->getInfo()->prev; - JS_UNLOCK_GC(rt); - JSGCThing *list = TurnUsedArenaIntoDoubleList(a); - if (list) - return list; - JS_LOCK_GC(rt); - } - a = NewGCArena(cx); - if (a) - break; - if (!canGC) { - METER(rt->gcStats.doubleArenaStats.fail++); - JS_UNLOCK_GC(rt); - return NULL; - } - doGC = true; - } - - JSGCArenaInfo *ainfo = a->getInfo(); - ainfo->list = NULL; - ainfo->freeList = NULL; - ainfo->prev = rt->gcDoubleArenaList.head; - rt->gcDoubleArenaList.head = a; - JS_UNLOCK_GC(rt); - - return MakeNewArenaFreeList(a, sizeof(jsdouble)); -} - -JSBool -js_NewDoubleInRootedValue(JSContext *cx, jsdouble d, jsval *vp) -{ - /* Updates of metering counters here are not thread-safe. */ - METER(cx->runtime->gcStats.doubleArenaStats.alloc++); - - JSGCThing **freeListp = &JS_THREAD_DATA(cx)->gcFreeLists.doubles; - JSGCThing *thing = *freeListp; - if (thing) { - METER(cx->runtime->gcStats.doubleArenaStats.localalloc++); - CheckGCFreeListLink(thing); - *freeListp = thing->link; - - jsdouble *dp = &thing->asDouble; - *dp = d; - *vp = DOUBLE_TO_JSVAL(dp); - return true; - } - - thing = RefillDoubleFreeList(cx); - if (!thing) { - if (!JS_ON_TRACE(cx)) { - /* Trace code handle this on its own. */ - js_ReportOutOfMemory(cx); - METER(cx->runtime->gcStats.doubleArenaStats.fail++); - } - return false; - } - - JS_ASSERT(!*freeListp || *freeListp == thing); - - CheckGCFreeListLink(thing); - *freeListp = thing->link; - - jsdouble *dp = reinterpret_cast(thing); - *dp = d; - *vp = DOUBLE_TO_JSVAL(dp); - return true; -} - -jsdouble * -js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d) -{ - jsval v; - if (!js_NewDoubleInRootedValue(cx, d, &v)) - return NULL; - - jsdouble *dp = JSVAL_TO_DOUBLE(v); - cx->weakRoots.newbornDouble = dp; - return dp; -} - JSBool js_LockGCThingRT(JSRuntime *rt, void *thing) { @@ -2290,8 +2102,10 @@ MarkDelayedChildren(JSTracer *trc) JS_ASSERT(rt->gcMarkLaterCount == 0); } +namespace js { + void -js_CallGCMarker(JSTracer *trc, void *thing, uint32 kind) +Mark(JSTracer *trc, void *thing, uint32 kind) { JSContext *cx; JSRuntime *rt; @@ -2314,13 +2128,7 @@ js_CallGCMarker(JSTracer *trc, void *thing, uint32 kind) * Optimize for string and double as their size is known and their tracing * is not recursive. */ - switch (kind) { - case JSTRACE_DOUBLE: { - MarkIfUnmarkedGCThing(thing); - goto out; - } - - case JSTRACE_STRING: + if (kind == JSTRACE_STRING) { for (;;) { if (JSString::isStatic(thing)) goto out; @@ -2385,37 +2193,35 @@ js_CallGCMarker(JSTracer *trc, void *thing, uint32 kind) } void -js_CallValueTracerIfGCThing(JSTracer *trc, jsval v) +MarkGCThing(JSTracer *trc, void *thing) { - void *thing; - uint32 kind; - - if (JSVAL_IS_DOUBLE(v) || JSVAL_IS_STRING(v)) { - thing = JSVAL_TO_TRACEABLE(v); - kind = JSVAL_TRACE_KIND(v); - JS_ASSERT(kind == js_GetGCThingTraceKind(thing)); - } else if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) { - /* v can be an arbitrary GC thing reinterpreted as an object. */ - thing = JSVAL_TO_OBJECT(v); - kind = js_GetGCThingTraceKind(thing); - } else { + JS_ASSERT(size_t(thing) % JS_GCTHING_ALIGN == 0); + + if (!thing) return; - } - js_CallGCMarker(trc, thing, kind); + + uint32 kind = js_GetGCThingTraceKind(thing); + Mark(trc, thing, kind); } -static void -gc_root_traversal(const GCRoots::Entry &entry, JSTracer *trc) -{ - jsval *rp = (jsval *)entry.key; - jsval v = *rp; +} /* namespace js */ - /* Ignore null reference, scalar values, and static strings. */ - if (JSVAL_IS_TRACEABLE(v)) { +static void +gc_root_traversal(JSTracer *trc, const RootEntry &entry) +{ #ifdef DEBUG - if (!JSString::isStatic(JSVAL_TO_GCTHING(v))) { + void *ptr; + if (entry.value.type == JS_GC_ROOT_GCTHING_PTR) { + ptr = *reinterpret_cast(entry.key); + } else { + Value *vp = reinterpret_cast(entry.key); + ptr = vp->isGCThing() ? vp->asGCThing() : NULL; + } + + if (ptr) { + if (!JSString::isStatic(ptr)) { bool root_points_to_gcArenaList = false; - jsuword thing = (jsuword) JSVAL_TO_GCTHING(v); + jsuword thing = (jsuword) ptr; JSRuntime *rt = trc->context->runtime; for (unsigned i = 0; i != FINALIZE_LIMIT; i++) { JSGCArenaList *arenaList = &rt->gcArenaList[i]; @@ -2430,30 +2236,22 @@ gc_root_traversal(const GCRoots::Entry &entry, JSTracer *trc) } } } - if (!root_points_to_gcArenaList) { - for (JSGCArena *a = rt->gcDoubleArenaList.head; - a; - a = a->getInfo()->prev) { - if (thing - a->toPageStart() < - DOUBLES_PER_ARENA * sizeof(jsdouble)) { - root_points_to_gcArenaList = true; - break; - } - } - } - if (!root_points_to_gcArenaList && entry.value) { + if (!root_points_to_gcArenaList && entry.value.name) { fprintf(stderr, "JS API usage error: the address passed to JS_AddNamedRoot currently holds an\n" -"invalid jsval. This is usually caused by a missing call to JS_RemoveRoot.\n" +"invalid gcthing. This is usually caused by a missing call to JS_RemoveRoot.\n" "The root's name is \"%s\".\n", - entry.value); + entry.value.name); } JS_ASSERT(root_points_to_gcArenaList); } -#endif - JS_SET_TRACING_NAME(trc, entry.value ? entry.value : "root"); - js_CallValueTracerIfGCThing(trc, v); } +#endif + JS_SET_TRACING_NAME(trc, entry.value.name ? entry.value.name : "root"); + if (entry.value.type == JS_GC_ROOT_GCTHING_PTR) + MarkGCThing(trc, *reinterpret_cast(entry.key)); + else + MarkValueRaw(trc, *reinterpret_cast(entry.key)); } static void @@ -2466,21 +2264,6 @@ gc_lock_traversal(const GCLocks::Entry &entry, JSTracer *trc) JS_CALL_TRACER(trc, entry.key, traceKind, "locked object"); } -namespace js { - -void -TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len) -{ - for (uint32 i = 0; i < len; i++) { - if (JSObject *obj = vec[i]) { - JS_SET_TRACING_INDEX(trc, "vector", i); - js_CallGCMarker(trc, obj, JSTRACE_OBJECT); - } - } -} - -} - void js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) { @@ -2488,14 +2271,13 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) if (fp->callobj) JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call"); if (fp->argsobj) - JS_CALL_OBJECT_TRACER(trc, JSVAL_TO_OBJECT(fp->argsobj), "arguments"); + JS_CALL_OBJECT_TRACER(trc, fp->argsobj, "arguments"); if (fp->script) js_TraceScript(trc, fp->script); /* Allow for primitive this parameter due to JSFUN_THISP_* flags. */ - JS_CALL_VALUE_TRACER(trc, fp->thisv, "this"); - - JS_CALL_VALUE_TRACER(trc, fp->rval, "rval"); + MarkValue(trc, fp->thisv, "this"); + MarkValue(trc, fp->rval, "rval"); if (fp->scopeChain) JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain"); } @@ -2528,11 +2310,9 @@ JSWeakRoots::mark(JSTracer *trc) newbornNames[i]); } } - if (newbornDouble) - JS_CALL_DOUBLE_TRACER(trc, newbornDouble, "newborn_double"); - JS_CALL_VALUE_TRACER(trc, lastAtom, "lastAtom"); - JS_SET_TRACING_NAME(trc, "lastInternalResult"); - js_CallValueTracerIfGCThing(trc, lastInternalResult); + if (lastAtom) + MarkString(trc, ATOM_TO_STRING(lastAtom), "lastAtom"); + MarkGCThing(trc, lastInternalResult, "lastInternalResult"); } inline void @@ -2540,8 +2320,7 @@ AutoGCRooter::trace(JSTracer *trc) { switch (tag) { case JSVAL: - JS_SET_TRACING_NAME(trc, "js::AutoValueRooter.val"); - js_CallValueTracerIfGCThing(trc, static_cast(this)->val); + MarkValue(trc, static_cast(this)->val, "js::AutoValueRooter.val"); return; case SPROP: @@ -2567,40 +2346,40 @@ AutoGCRooter::trace(JSTracer *trc) case IDARRAY: { JSIdArray *ida = static_cast(this)->idArray; - TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray"); + MarkIdRange(trc, ida->length, ida->vector, "js::AutoIdArray.idArray"); return; } case DESCRIPTORS: { - PropertyDescriptorArray &descriptors = - static_cast(this)->descriptors; + PropDescArray &descriptors = + static_cast(this)->descriptors; for (size_t i = 0, len = descriptors.length(); i < len; i++) { - PropertyDescriptor &desc = descriptors[i]; - - JS_CALL_VALUE_TRACER(trc, desc.pd, "PropertyDescriptor::pd"); - JS_CALL_VALUE_TRACER(trc, desc.value, "PropertyDescriptor::value"); - JS_CALL_VALUE_TRACER(trc, desc.get, "PropertyDescriptor::get"); - JS_CALL_VALUE_TRACER(trc, desc.set, "PropertyDescriptor::set"); - js_TraceId(trc, desc.id); + PropDesc &desc = descriptors[i]; + MarkValue(trc, desc.pd, "PropDesc::pd"); + MarkValue(trc, desc.value, "PropDesc::value"); + MarkValue(trc, desc.get, "PropDesc::get"); + MarkValue(trc, desc.set, "PropDesc::set"); + MarkId(trc, desc.id, "PropDesc::id"); } return; } case DESCRIPTOR : { - AutoDescriptor &desc = *static_cast(this); + PropertyDescriptor &desc = *static_cast(this); if (desc.obj) - JS_CALL_OBJECT_TRACER(trc, desc.obj, "Descriptor::obj"); - JS_CALL_VALUE_TRACER(trc, desc.value, "Descriptor::value"); + MarkObject(trc, desc.obj, "Descriptor::obj"); + MarkValue(trc, desc.value, "Descriptor::value"); if (desc.attrs & JSPROP_GETTER) - JS_CALL_VALUE_TRACER(trc, jsval(desc.getter), "Descriptor::get"); + MarkObject(trc, CastAsObject(desc.getter), "Descriptor::get"); if (desc.attrs & JSPROP_SETTER) - JS_CALL_VALUE_TRACER(trc, jsval(desc.setter), "Descriptor::set"); + MarkObject(trc, CastAsObject(desc.setter), "Descriptor::set"); return; } case NAMESPACES: { JSXMLArray &array = static_cast(this)->array; - TraceObjectVector(trc, reinterpret_cast(array.vector), array.length); + MarkObjectRange(trc, array.length, reinterpret_cast(array.vector), + "JSXMLArray.vector"); array.cursors->trace(trc); return; } @@ -2610,26 +2389,34 @@ AutoGCRooter::trace(JSTracer *trc) return; case OBJECT: - if (JSObject *obj = static_cast(this)->obj) { - JS_SET_TRACING_NAME(trc, "js::AutoObjectRooter.obj"); - js_CallGCMarker(trc, obj, JSTRACE_OBJECT); - } + if (JSObject *obj = static_cast(this)->obj) + MarkObject(trc, obj, "js::AutoObjectRooter.obj"); return; case ID: - JS_SET_TRACING_NAME(trc, "js::AutoIdRooter.val"); - js_CallValueTracerIfGCThing(trc, static_cast(this)->idval); + MarkId(trc, static_cast(this)->id_, "js::AutoIdRooter.val"); return; - case VECTOR: { - js::Vector &vector = static_cast(this)->vector; - js::TraceValues(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector"); + case VALVECTOR: { + Vector &vector = static_cast(this)->vector; + MarkValueRange(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector"); + return; + } + + case STRING: + if (JSString *str = static_cast(this)->str) + MarkString(trc, str, "js::AutoStringRooter.str"); + return; + + case IDVECTOR: { + Vector &vector = static_cast(this)->vector; + MarkIdRange(trc, vector.length(), vector.begin(), "js::AutoIdVector.vector"); return; } } JS_ASSERT(tag >= 0); - TraceValues(trc, tag, static_cast(this)->array, "js::AutoArrayRooter.array"); + MarkValueRange(trc, tag, static_cast(this)->array, "js::AutoArrayRooter.array"); } void @@ -2642,10 +2429,10 @@ js_TraceContext(JSTracer *trc, JSContext *acx) JS_CALL_OBJECT_TRACER(trc, acx->globalObject, "global object"); acx->weakRoots.mark(trc); if (acx->throwing) { - JS_CALL_VALUE_TRACER(trc, acx->exception, "exception"); + MarkValue(trc, acx->exception, "exception"); } else { /* Avoid keeping GC-ed junk stored in JSContext.exception. */ - acx->exception = JSVAL_NULL; + acx->exception.setNull(); } for (js::AutoGCRooter *gcr = acx->autoGCRooters; gcr; gcr = gcr->down) @@ -2656,7 +2443,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) js_TraceRegExpStatics(trc, acx); - JS_CALL_VALUE_TRACER(trc, acx->iterValue, "iterValue"); + MarkValue(trc, acx->iterValue, "iterValue"); acx->compartment->marked = true; @@ -2664,7 +2451,7 @@ js_TraceContext(JSTracer *trc, JSContext *acx) TracerState* state = acx->tracerState; while (state) { if (state->nativeVp) - TraceValues(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); + MarkValueRange(trc, state->nativeVpLen, state->nativeVp, "nativeVp"); state = state->prev; } #endif @@ -2675,14 +2462,13 @@ js_TraceRuntime(JSTracer *trc) { JSRuntime *rt = trc->context->runtime; - for (GCRoots::Range r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) - gc_root_traversal(r.front(), trc); + for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) + gc_root_traversal(trc, r.front()); for (GCLocks::Range r = rt->gcLocksHash.all(); !r.empty(); r.popFront()) gc_lock_traversal(r.front(), trc); js_TraceAtomState(trc); - js_TraceRuntimeNumberState(trc); js_MarkTraps(trc); JSContext *iter = NULL; @@ -2750,7 +2536,7 @@ FinalizeObject(JSContext *cx, JSObject *obj, unsigned thingKind) return; /* Finalize obj first, in case it needs map and slots. */ - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (clasp->finalize) clasp->finalize(cx, obj); @@ -3014,7 +2800,6 @@ struct GCTimer { uint64 startSweep; uint64 sweepObjectEnd; uint64 sweepStringEnd; - uint64 sweepDoubleEnd; uint64 sweepDestroyEnd; uint64 end; @@ -3057,8 +2842,7 @@ struct GCTimer { (double)(sweepDestroyEnd - startSweep) / 1e6, (double)(sweepObjectEnd - startSweep) / 1e6, (double)(sweepStringEnd - sweepObjectEnd) / 1e6, - (double)(sweepDoubleEnd - sweepStringEnd) / 1e6, - (double)(sweepDestroyEnd - sweepDoubleEnd) / 1e6); + (double)(sweepDestroyEnd - sweepStringEnd) / 1e6); fprintf(gcFile, "%10d, %10d \n", newChunkCount, destroyChunkCount); fflush(gcFile); @@ -3096,38 +2880,6 @@ HasMarkedDoubles(JSGCArena *a) markBitmap[4] | markBitmap[5] | markBitmap[6] | markBitmap[7]); } -static void -SweepDoubles(JSRuntime *rt) -{ -#ifdef JS_GCMETER - uint32 nlivearenas = 0, nkilledarenas = 0, nthings = 0; -#endif - JSGCArena **ap = &rt->gcDoubleArenaList.head; - while (JSGCArena *a = *ap) { - JSGCArenaInfo *ainfo = a->getInfo(); - if (!HasMarkedDoubles(a)) { - /* No marked double values in the arena. */ - *ap = ainfo->prev; - ReleaseGCArena(rt, a); - METER(nkilledarenas++); - } else { -#ifdef JS_GCMETER - jsdouble *thing = reinterpret_cast(a->toPageStart()); - jsdouble *end = thing + DOUBLES_PER_ARENA; - for (; thing != end; ++thing) { - if (IsMarkedGCThing(thing)) - METER(nthings++); - } - METER(nlivearenas++); -#endif - ap = &ainfo->prev; - } - } - METER(UpdateArenaStats(&rt->gcStats.doubleArenaStats, - nlivearenas, nkilledarenas, nthings)); - rt->gcDoubleArenaList.cursor = rt->gcDoubleArenaList.head; -} - #ifdef JS_THREADSAFE namespace js { @@ -3267,7 +3019,6 @@ GC(JSContext *cx GCTIMER_PARAM) for (JSGCChunkInfo **i = rt->gcChunks.begin(); i != rt->gcChunks.end(); ++i) (*i)->clearMarkBitmap(); - js_TraceRuntime(&trc); js_MarkScriptFilenames(rt); @@ -3357,9 +3108,6 @@ GC(JSContext *cx GCTIMER_PARAM) } TIMESTAMP(sweepStringEnd); - SweepDoubles(rt); - TIMESTAMP(sweepDoubleEnd); - SweepCompartments(cx); /* diff --git a/js/src/jsgc.h b/js/src/jsgc.h index db709eae077b..e86b24901383 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -54,12 +54,12 @@ #include "jsvector.h" #include "jsversion.h" -#define JSTRACE_XML 3 +#define JSTRACE_XML 2 /* * One past the maximum trace kind. */ -#define JSTRACE_LIMIT 4 +#define JSTRACE_LIMIT 3 const uintN JS_EXTERNAL_STRING_LIMIT = 8; @@ -102,7 +102,7 @@ js_ChangeExternalStringFinalizer(JSStringFinalizeOp oldop, JSStringFinalizeOp newop); extern JSBool -js_AddRoot(JSContext *cx, jsval *vp, const char *name); +js_AddRoot(JSContext *cx, js::Value *vp, const char *name); extern JSBool js_AddGCThingRoot(JSContext *cx, void **rp, const char *name); @@ -110,7 +110,7 @@ js_AddGCThingRoot(JSContext *cx, void **rp, const char *name); #ifdef DEBUG extern void js_DumpNamedRoots(JSRuntime *rt, - void (*dump)(const char *name, void *rp, void *data), + void (*dump)(const char *name, void *rp, JSGCRootType type, void *data), void *data); #endif @@ -126,20 +126,6 @@ typedef struct JSPtrTable { extern JSBool js_RegisterCloseableIterator(JSContext *cx, JSObject *obj); -/* - * Allocate a new double jsval and store the result in *vp. vp must be a root. - * The function does not copy the result into any weak root. - */ -extern JSBool -js_NewDoubleInRootedValue(JSContext *cx, jsdouble d, jsval *vp); - -/* - * Return a pointer to a new GC-allocated and weakly-rooted jsdouble number, - * or null when the allocation fails. - */ -extern jsdouble * -js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d); - #ifdef JS_TRACER extern JSBool js_ReserveObjects(JSContext *cx, size_t nobjects); @@ -166,14 +152,6 @@ js_IsAboutToBeFinalized(void *thing); # define JS_IS_VALID_TRACE_KIND(kind) ((uint32)(kind) <= JSTRACE_STRING) #endif -/* - * Trace jsval when JSVAL_IS_OBJECT(v) can be a GC thing pointer tagged as a - * jsval. NB: punning an arbitrary JSString * as an untagged (object-tagged) - * jsval no longer works due to static int and unit strings! - */ -extern void -js_CallValueTracerIfGCThing(JSTracer *trc, jsval v); - extern void js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp); @@ -231,9 +209,6 @@ js_WaitForGC(JSRuntime *rt); #endif -extern void -js_CallGCMarker(JSTracer *trc, void *thing, uint32 kind); - /* * The kind of GC thing with a finalizer. The external strings follow the * ordinary string to simplify js_GetExternalStringGCType. @@ -318,13 +293,7 @@ struct JSGCArenaList { */ }; -struct JSGCDoubleArenaList { - JSGCArena *head; /* list start */ - JSGCArena *cursor; /* next arena with free cells */ -}; - struct JSGCFreeLists { - JSGCThing *doubles; JSGCThing *finalizables[FINALIZE_LIMIT]; void purge(); @@ -332,8 +301,6 @@ struct JSGCFreeLists { #ifdef DEBUG bool isEmpty() const { - if (doubles) - return false; for (size_t i = 0; i != JS_ARRAY_LENGTH(finalizables); ++i) { if (finalizables[i]) return false; @@ -348,14 +315,13 @@ js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data); struct JSWeakRoots { /* Most recently created things by type, members of the GC's root set. */ - void *finalizableNewborns[FINALIZE_LIMIT]; - jsdouble *newbornDouble; + void *finalizableNewborns[FINALIZE_LIMIT]; /* Atom root for the last-looked-up atom on this context. */ - jsval lastAtom; + JSAtom *lastAtom; /* Root for the result of the most recent js_InternalInvoke call. */ - jsval lastInternalResult; + void *lastInternalResult; void mark(JSTracer *trc); }; @@ -448,15 +414,13 @@ const bool JS_WANT_GC_METER_PRINT = false; struct JSConservativeGCStats { uint32 words; /* number of words on native stacks */ - uint32 oddaddress; /* excluded because low bit was set */ - uint32 special; /* excluded because a special value */ + uint32 lowbitset; /* excluded because one of the low bits was set */ uint32 notarena; /* not within arena range in a chunk */ uint32 notchunk; /* not within a valid chunk */ uint32 freearena; /* not within non-free arena */ uint32 wrongtag; /* tagged pointer but wrong type */ uint32 notlive; /* gcthing is not allocated */ uint32 gcthings; /* number of live gcthings */ - uint32 raw; /* number of raw pointers marked */ uint32 unmarked; /* number of unmarked gc things discovered on the stack */ }; @@ -499,7 +463,7 @@ struct JSGCStats { uint32 poke; /* number of potentially useful GC calls */ uint32 afree; /* thing arenas freed so far */ uint32 stackseg; /* total extraordinary stack segments scanned */ - uint32 segslots; /* total stack segment jsval slots scanned */ + uint32 segslots; /* total stack segment value slots scanned */ uint32 nclose; /* number of objects with close hooks */ uint32 maxnclose; /* max number of objects with close hooks */ uint32 closelater; /* number of close hooks scheduled to run */ @@ -510,7 +474,6 @@ struct JSGCStats { uint32 maxnchunks; /* maximum number of allocated chunks */ JSGCArenaStats arenaStats[FINALIZE_LIMIT]; - JSGCArenaStats doubleArenaStats; JSConservativeGCStats conservative; }; @@ -539,25 +502,133 @@ namespace js { extern bool SetProtoCheckingForCycles(JSContext *cx, JSObject *obj, JSObject *proto); +/* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */ void -TraceObjectVector(JSTracer *trc, JSObject **vec, uint32 len); +Mark(JSTracer *trc, void *thing, uint32 kind); -inline void -TraceValues(JSTracer *trc, jsval *beg, jsval *end, const char *name) +static inline void +Mark(JSTracer *trc, void *thing, uint32 kind, const char *name) { - for (jsval *vp = beg; vp < end; ++vp) { - jsval v = *vp; - if (JSVAL_IS_TRACEABLE(v)) { - JS_SET_TRACING_INDEX(trc, name, vp - beg); - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); + JS_ASSERT(thing); + JS_SET_TRACING_NAME(trc, name); + Mark(trc, thing, kind); +} + +static inline void +MarkString(JSTracer *trc, JSString *str, const char *name) +{ + JS_ASSERT(str); + JS_SET_TRACING_NAME(trc, name); + Mark(trc, str, JSTRACE_STRING); +} + +static inline void +MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name) +{ + for (uint32 i = 0; i < len; i++) { + if (JSAtom *atom = vec[i]) { + JS_SET_TRACING_INDEX(trc, name, i); + Mark(trc, ATOM_TO_STRING(atom), JSTRACE_STRING); } } } -inline void -TraceValues(JSTracer *trc, size_t len, jsval *vec, const char *name) +static inline void +MarkObject(JSTracer *trc, JSObject *obj, const char *name) { - TraceValues(trc, vec, vec + len, name); + JS_ASSERT(obj); + JS_SET_TRACING_NAME(trc, name); + Mark(trc, obj, JSTRACE_OBJECT); +} + +static inline void +MarkObjectRange(JSTracer *trc, size_t len, JSObject **vec, const char *name) +{ + for (uint32 i = 0; i < len; i++) { + if (JSObject *obj = vec[i]) { + JS_SET_TRACING_INDEX(trc, name, i); + Mark(trc, obj, JSTRACE_OBJECT); + } + } +} + +/* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */ +static inline void +MarkValueRaw(JSTracer *trc, const js::Value &v) +{ + if (v.isMarkable()) + return Mark(trc, v.asGCThing(), v.gcKind()); +} + +static inline void +MarkValue(JSTracer *trc, const js::Value &v, const char *name) +{ + JS_SET_TRACING_NAME(trc, name); + MarkValueRaw(trc, v); +} + +static inline void +MarkValueRange(JSTracer *trc, Value *beg, Value *end, const char *name) +{ + for (Value *vp = beg; vp < end; ++vp) { + JS_SET_TRACING_INDEX(trc, name, vp - beg); + MarkValueRaw(trc, *vp); + } +} + +static inline void +MarkValueRange(JSTracer *trc, size_t len, Value *vec, const char *name) +{ + MarkValueRange(trc, vec, vec + len, name); +} + +static inline void +MarkId(JSTracer *trc, jsid id) +{ + if (JSID_IS_STRING(id)) + Mark(trc, JSID_TO_STRING(id), JSTRACE_STRING); + else if (JS_UNLIKELY(JSID_IS_OBJECT(id))) + Mark(trc, JSID_TO_OBJECT(id), JSTRACE_OBJECT); +} + +static inline void +MarkId(JSTracer *trc, jsid id, const char *name) +{ + JS_SET_TRACING_NAME(trc, name); + MarkId(trc, id); +} + +static inline void +MarkIdRange(JSTracer *trc, jsid *beg, jsid *end, const char *name) +{ + for (jsid *idp = beg; idp != end; ++idp) { + JS_SET_TRACING_INDEX(trc, name, (idp - beg)); + MarkId(trc, *idp); + } +} + +static inline void +MarkIdRange(JSTracer *trc, size_t len, jsid *vec, const char *name) +{ + MarkIdRange(trc, vec, vec + len, name); +} + +/* N.B. Assumes JS_SET_TRACING_NAME/INDEX has already been called. */ +void +MarkGCThing(JSTracer *trc, void *thing); + +static inline void +MarkGCThing(JSTracer *trc, void *thing, const char *name) +{ + JS_SET_TRACING_NAME(trc, name); + MarkGCThing(trc, thing); +} + +static inline void +MarkGCThing(JSTracer *trc, void *thing, const char *name, size_t index) +{ + JS_SET_TRACING_INDEX(trc, name, index); + MarkGCThing(trc, thing); } JSCompartment * diff --git a/js/src/jsgcchunk.h b/js/src/jsgcchunk.h index 11fe250cc733..0a5962d1862c 100644 --- a/js/src/jsgcchunk.h +++ b/js/src/jsgcchunk.h @@ -40,8 +40,8 @@ #ifndef jsgchunk_h__ #define jsgchunk_h__ +#include "jsapi.h" #include "jsprvtd.h" -#include "jspubtd.h" #include "jsutil.h" namespace js { @@ -55,6 +55,10 @@ const size_t GC_CHUNK_SHIFT = 20; const size_t GC_CHUNK_SIZE = size_t(1) << GC_CHUNK_SHIFT; const size_t GC_CHUNK_MASK = GC_CHUNK_SIZE - 1; +#if defined(XP_WIN) && defined(_M_X64) +bool InitNtAllocAPIs(); +#endif + JS_FRIEND_API(void *) AllocGCChunk(); diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 9e817edae7af..160f446f78c1 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -83,6 +83,7 @@ #include "jsscopeinlines.h" #include "jsscriptinlines.h" #include "jsstrinlines.h" +#include "jscntxtinlines.h" #if JS_HAS_XML_SUPPORT #include "jsxml.h" @@ -182,7 +183,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp) JSObject *innermostNewChild = js_CloneBlockObject(cx, sharedBlock, fp); if (!innermostNewChild) return NULL; - AutoValueRooter tvr(cx, innermostNewChild); + AutoObjectRooter tvr(cx, innermostNewChild); /* * Clone our way towards outer scopes until we reach the innermost @@ -198,8 +199,7 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp) break; /* As in the call above, we don't know the real parent yet. */ - JSObject *clone - = js_CloneBlockObject(cx, sharedBlock, fp); + JSObject *clone = js_CloneBlockObject(cx, sharedBlock, fp); if (!clone) return NULL; @@ -220,34 +220,32 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp) /* Place our newly cloned blocks at the head of the scope chain. */ fp->scopeChain = innermostNewChild; - return fp->scopeChain; + return innermostNewChild; } JSBool -js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp) +js_GetPrimitiveThis(JSContext *cx, Value *vp, Class *clasp, const Value **vpp) { - jsval v; - JSObject *obj; - - v = vp[1]; - if (JSVAL_IS_OBJECT(v)) { - obj = JS_THIS_OBJECT(cx, vp); - if (!JS_InstanceOf(cx, obj, clasp, vp + 2)) + const Value *p = &vp[1]; + if (p->isObject()) { + JSObject *obj = ComputeThisFromVp(cx, vp); + if (!InstanceOf(cx, obj, clasp, vp + 2)) return JS_FALSE; - v = obj->getPrimitiveThis(); + *vpp = &obj->getPrimitiveThis(); + } else { + *vpp = p; } - *thisvp = v; return JS_TRUE; } /* Some objects (e.g., With) delegate 'this' to another object. */ static inline JSObject * -CallThisObjectHook(JSContext *cx, JSObject *obj, jsval *argv) +CallThisObjectHook(JSContext *cx, JSObject *obj, Value *argv) { JSObject *thisp = obj->thisObject(cx); if (!thisp) return NULL; - argv[-1] = OBJECT_TO_JSVAL(thisp); + argv[-1].setObject(*thisp); return thisp; } @@ -267,17 +265,17 @@ CallThisObjectHook(JSContext *cx, JSObject *obj, jsval *argv) * The alert should display "true". */ JS_STATIC_INTERPRET JSObject * -js_ComputeGlobalThis(JSContext *cx, jsval *argv) +ComputeGlobalThis(JSContext *cx, Value *argv) { /* Find the inner global. */ JSObject *inner; - if (JSVAL_IS_PRIMITIVE(argv[-2]) || !JSVAL_TO_OBJECT(argv[-2])->getParent()) { + if (argv[-2].isPrimitive() || !argv[-2].toObject().getParent()) { inner = cx->globalObject; OBJ_TO_INNER_OBJECT(cx, inner); if (!inner) return NULL; } else { - inner = JSVAL_TO_OBJECT(argv[-2])->getGlobal(); + inner = argv[-2].toObject().getGlobal(); } JS_ASSERT(inner->getClass()->flags & JSCLASS_IS_GLOBAL); @@ -287,55 +285,59 @@ js_ComputeGlobalThis(JSContext *cx, jsval *argv) * The outer object has not moved along to a new inner object. * This means we qualify for the cache slot in the global. */ - jsval thisv = inner->getReservedSlot(JSRESERVED_GLOBAL_THIS); - if (!JSVAL_IS_VOID(thisv)) { + const Value &thisv = inner->getReservedSlot(JSRESERVED_GLOBAL_THIS); + if (!thisv.isUndefined()) { argv[-1] = thisv; - return JSVAL_TO_OBJECT(thisv); + return thisv.toObjectOrNull(); } JSObject *stuntThis = CallThisObjectHook(cx, inner, argv); JS_ALWAYS_TRUE(js_SetReservedSlot(cx, inner, JSRESERVED_GLOBAL_THIS, - OBJECT_TO_JSVAL(stuntThis))); + ObjectOrNullValue(stuntThis))); return stuntThis; } return CallThisObjectHook(cx, inner, argv); } +namespace js { + JSObject * -js_ComputeThis(JSContext *cx, jsval *argv) +ComputeThisFromArgv(JSContext *cx, Value *argv) { - JS_ASSERT(argv[-1] != JSVAL_HOLE); // check for SynthesizeFrame poisoning - if (JSVAL_IS_NULL(argv[-1])) - return js_ComputeGlobalThis(cx, argv); + JS_ASSERT(!argv[-1].isMagic(JS_THIS_POISON)); + if (argv[-1].isNull()) + return ComputeGlobalThis(cx, argv); JSObject *thisp; - JS_ASSERT(!JSVAL_IS_NULL(argv[-1])); - if (!JSVAL_IS_OBJECT(argv[-1])) { + JS_ASSERT(!argv[-1].isNull()); + if (argv[-1].isPrimitive()) { if (!js_PrimitiveToObject(cx, &argv[-1])) return NULL; - thisp = JSVAL_TO_OBJECT(argv[-1]); + thisp = argv[-1].toObjectOrNull(); return thisp; - } + } - thisp = JSVAL_TO_OBJECT(argv[-1]); + thisp = &argv[-1].toObject(); if (thisp->getClass() == &js_CallClass || thisp->getClass() == &js_BlockClass) - return js_ComputeGlobalThis(cx, argv); + return ComputeGlobalThis(cx, argv); return CallThisObjectHook(cx, thisp, argv); } +} + #if JS_HAS_NO_SUCH_METHOD const uint32 JSSLOT_FOUND_FUNCTION = JSSLOT_PRIVATE; const uint32 JSSLOT_SAVED_ID = JSSLOT_PRIVATE + 1; -JSClass js_NoSuchMethodClass = { +Class js_NoSuchMethodClass = { "NoSuchMethod", JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -354,26 +356,26 @@ JSClass js_NoSuchMethodClass = { * parameters. */ JS_STATIC_INTERPRET JSBool -js_OnUnknownMethod(JSContext *cx, jsval *vp) +js_OnUnknownMethod(JSContext *cx, Value *vp) { - JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); + JS_ASSERT(!vp[1].isPrimitive()); - JSObject *obj = JSVAL_TO_OBJECT(vp[1]); + JSObject *obj = &vp[1].toObject(); jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom); - AutoValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr())) return false; - if (JSVAL_IS_PRIMITIVE(tvr.value())) { + if (tvr.value().isPrimitive()) { vp[0] = tvr.value(); } else { #if JS_HAS_XML_SUPPORT /* Extract the function name from function::name qname. */ - if (!JSVAL_IS_PRIMITIVE(vp[0])) { - obj = JSVAL_TO_OBJECT(vp[0]); + if (vp[0].isObject()) { + obj = &vp[0].toObject(); if (!js_IsFunctionQName(cx, obj, &id)) return false; - if (id != 0) - vp[0] = ID_TO_VALUE(id); + if (!JSID_IS_VOID(id)) + vp[0] = IdToValue(id); } #endif obj = js_NewGCObject(cx); @@ -389,58 +391,41 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp) obj->map = NULL; obj->init(&js_NoSuchMethodClass, NULL, NULL, tvr.value()); obj->fslots[JSSLOT_SAVED_ID] = vp[0]; - vp[0] = OBJECT_TO_JSVAL(obj); + vp[0].setObject(*obj); } return true; } static JS_REQUIRES_STACK JSBool -NoSuchMethod(JSContext *cx, uintN argc, jsval *vp, uint32 flags) +NoSuchMethod(JSContext *cx, uintN argc, Value *vp, uint32 flags) { InvokeArgsGuard args; if (!cx->stack().pushInvokeArgs(cx, 2, args)) return JS_FALSE; - JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[0])); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); - JSObject *obj = JSVAL_TO_OBJECT(vp[0]); + JS_ASSERT(vp[0].isObject()); + JS_ASSERT(vp[1].isObject()); + JSObject *obj = &vp[0].toObject(); JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass); - jsval *invokevp = args.getvp(); + Value *invokevp = args.getvp(); invokevp[0] = obj->fslots[JSSLOT_FOUND_FUNCTION]; invokevp[1] = vp[1]; invokevp[2] = obj->fslots[JSSLOT_SAVED_ID]; JSObject *argsobj = js_NewArrayObject(cx, argc, vp + 2); if (!argsobj) return JS_FALSE; - invokevp[3] = OBJECT_TO_JSVAL(argsobj); + invokevp[3].setObject(*argsobj); JSBool ok = (flags & JSINVOKE_CONSTRUCT) - ? js_InvokeConstructor(cx, args) - : js_Invoke(cx, args, flags); - *vp = *invokevp; + ? InvokeConstructor(cx, args) + : Invoke(cx, args, flags); + vp[0] = invokevp[0]; return ok; } #endif /* JS_HAS_NO_SUCH_METHOD */ -/* - * We check if the function accepts a primitive value as |this|. For that we - * use a table that maps value's tag into the corresponding function flag. - */ -JS_STATIC_ASSERT(JSVAL_INT == 1); -JS_STATIC_ASSERT(JSVAL_DOUBLE == 2); -JS_STATIC_ASSERT(JSVAL_STRING == 4); -JS_STATIC_ASSERT(JSVAL_SPECIAL == 6); - -const uint16 js_PrimitiveTestFlags[] = { - JSFUN_THISP_NUMBER, /* INT */ - JSFUN_THISP_NUMBER, /* DOUBLE */ - JSFUN_THISP_NUMBER, /* INT */ - JSFUN_THISP_STRING, /* STRING */ - JSFUN_THISP_NUMBER, /* INT */ - JSFUN_THISP_BOOLEAN, /* BOOLEAN */ - JSFUN_THISP_NUMBER /* INT */ -}; +namespace js { class AutoPreserveEnumerators { JSContext *cx; @@ -458,9 +443,9 @@ class AutoPreserveEnumerators { }; static JS_REQUIRES_STACK bool -callJSNative(JSContext *cx, JSCallOp callOp, JSObject *thisp, uintN argc, jsval *argv, jsval *rval) +callJSNative(JSContext *cx, CallOp callOp, JSObject *thisp, uintN argc, Value *argv, Value *rval) { - jsval *vp = argv - 2; + Value *vp = argv - 2; if (callJSFastNative(cx, callOp, argc, vp)) { *rval = JS_RVAL(cx, vp); return true; @@ -470,17 +455,17 @@ callJSNative(JSContext *cx, JSCallOp callOp, JSObject *thisp, uintN argc, jsval template static JS_REQUIRES_STACK bool -Invoke(JSContext *cx, JSFunction *fun, JSScript *script, T native, +InvokeCommon(JSContext *cx, JSFunction *fun, JSScript *script, T native, const InvokeArgsGuard &args, uintN flags) { uintN argc = args.getArgc(); - jsval *vp = args.getvp(); + Value *vp = args.getvp(); if (native && fun && fun->isFastNative()) { #ifdef DEBUG_NOT_THROWING JSBool alreadyThrowing = cx->throwing; #endif - JSBool ok = callJSFastNative(cx, (JSFastNative) native, argc, vp); + JSBool ok = callJSFastNative(cx, (FastNative) native, argc, vp); JS_RUNTIME_METER(cx->runtime, nativeCalls); #ifdef DEBUG_NOT_THROWING if (ok && !alreadyThrowing) @@ -521,11 +506,9 @@ Invoke(JSContext *cx, JSFunction *fun, JSScript *script, T native, JSStackFrame *fp = frame.getFrame(); /* Initialize missing missing arguments and new local variables. */ - jsval *missing = vp + 2 + argc; - for (jsval *v = missing, *end = missing + nmissing; v != end; ++v) - *v = JSVAL_VOID; - for (jsval *v = fp->slots(), *end = v + nvars; v != end; ++v) - *v = JSVAL_VOID; + Value *missing = vp + 2 + argc; + SetValueRangeToUndefined(missing, nmissing); + SetValueRangeToUndefined(fp->slots(), nvars); /* Initialize frame. */ fp->thisv = vp[1]; @@ -535,7 +518,7 @@ Invoke(JSContext *cx, JSFunction *fun, JSScript *script, T native, fp->fun = fun; fp->argc = argc; fp->argv = vp + 2; - fp->rval = (flags & JSINVOKE_CONSTRUCT) ? fp->thisv : JSVAL_VOID; + fp->rval = (flags & JSINVOKE_CONSTRUCT) ? fp->thisv : UndefinedValue(); fp->annotation = NULL; fp->scopeChain = NULL; fp->blockChain = NULL; @@ -556,7 +539,7 @@ Invoke(JSContext *cx, JSFunction *fun, JSScript *script, T native, cx->stack().pushInvokeFrame(cx, args, frame, regs); /* Now that the frame has been pushed, fix up the scope chain. */ - JSObject *parent = JSVAL_TO_OBJECT(vp[0])->getParent(); + JSObject *parent = vp[0].toObject().getParent(); if (native) { /* Slow natives and call ops expect the caller's scopeChain as their scopeChain. */ if (JSStackFrame *down = fp->down) @@ -587,7 +570,7 @@ Invoke(JSContext *cx, JSFunction *fun, JSScript *script, T native, JSBool alreadyThrowing = cx->throwing; #endif - JSObject *thisp = JSVAL_TO_OBJECT(fp->thisv); + JSObject *thisp = fp->thisv.toObjectOrNull(); ok = callJSNative(cx, native, thisp, fp->argc, fp->argv, &fp->rval); JS_ASSERT(cx->fp == fp); @@ -599,7 +582,7 @@ Invoke(JSContext *cx, JSFunction *fun, JSScript *script, T native, } else { JS_ASSERT(script); AutoPreserveEnumerators preserve(cx); - ok = js_Interpret(cx); + ok = Interpret(cx); } DTrace::exitJSFun(cx, fp, fun, fp->rval); @@ -621,26 +604,26 @@ Invoke(JSContext *cx, JSFunction *fun, JSScript *script, T native, * required arguments, allocate declared local variables, and pop everything * when done. Then push the return value. */ -JS_REQUIRES_STACK JS_FRIEND_API(JSBool) -js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags) +JS_REQUIRES_STACK bool +Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags) { - jsval *vp = args.getvp(); + Value *vp = args.getvp(); uintN argc = args.getArgc(); JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); - jsval v = vp[0]; - if (JSVAL_IS_PRIMITIVE(v)) { + const Value &v = vp[0]; + if (v.isPrimitive()) { js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS); return false; } - JSObject *funobj = JSVAL_TO_OBJECT(v); - JSClass *clasp = funobj->getClass(); + JSObject *funobj = &v.toObject(); + Class *clasp = funobj->getClass(); if (clasp == &js_FunctionClass) { /* Get private data and set derived locals from it. */ JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); - JSNative native; + Native native; JSScript *script; if (FUN_INTERPRETED(fun)) { native = NULL; @@ -649,10 +632,10 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags) if (script->isEmpty()) { if (flags & JSINVOKE_CONSTRUCT) { - JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); + JS_ASSERT(vp[1].isObject()); *vp = vp[1]; } else { - *vp = JSVAL_VOID; + vp->setUndefined(); } return true; } @@ -663,15 +646,15 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags) if (JSFUN_BOUND_METHOD_TEST(fun->flags)) { /* Handle bound method special case. */ - vp[1] = OBJECT_TO_JSVAL(funobj->getParent()); - } else if (!JSVAL_IS_OBJECT(vp[1])) { + vp[1].setObject(*funobj->getParent()); + } else if (!vp[1].isObjectOrNull()) { JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT)); - if (PRIMITIVE_THIS_TEST(fun, vp[1])) - return Invoke(cx, fun, script, native, args, flags); + if (PrimitiveThisTest(fun, vp[1])) + return InvokeCommon(cx, fun, script, native, args, flags); } if (flags & JSINVOKE_CONSTRUCT) { - JS_ASSERT(!JSVAL_IS_PRIMITIVE(args.getvp()[1])); + JS_ASSERT(args.getvp()[1].isObject()); } else { /* * We must call js_ComputeThis in case we are not called from the @@ -684,13 +667,13 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags) * the appropriate this-computing bytecode, e.g., JSOP_THIS. */ if (native && (!fun || !(fun->flags & JSFUN_FAST_NATIVE))) { - jsval *vp = args.getvp(); - if (!js_ComputeThis(cx, vp + 2)) + Value *vp = args.getvp(); + if (!ComputeThisFromVp(cx, vp)) return false; flags |= JSFRAME_COMPUTED_THIS; } } - return Invoke(cx, fun, script, native, args, flags); + return InvokeCommon(cx, fun, script, native, args, flags); } #if JS_HAS_NO_SUCH_METHOD @@ -703,28 +686,34 @@ js_Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags) /* Try a call or construct native object op. */ if (flags & JSINVOKE_CONSTRUCT) { - if (!JSVAL_IS_OBJECT(vp[1])) { + if (!vp[1].isObjectOrNull()) { if (!js_PrimitiveToObject(cx, &vp[1])) return false; } - JSNative native = ops->construct; + Native native = ops->construct; if (!native) { js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS); return false; } - return Invoke(cx, NULL, NULL, native, args, flags); + return InvokeCommon(cx, NULL, NULL, native, args, flags); } - JSCallOp callOp = ops->call; + CallOp callOp = ops->call; if (!callOp) { js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS); return false; } - return Invoke(cx, NULL, NULL, callOp, args, flags); + return InvokeCommon(cx, NULL, NULL, callOp, args, flags); +} + +extern JS_REQUIRES_STACK JS_FRIEND_API(bool) +InvokeFriendAPI(JSContext *cx, const InvokeArgsGuard &args, uintN flags) +{ + return Invoke(cx, args, flags); } JSBool -js_InternalInvoke(JSContext *cx, jsval thisv, jsval fval, uintN flags, - uintN argc, jsval *argv, jsval *rval) +InternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, uintN flags, + uintN argc, Value *argv, Value *rval) { LeaveTrace(cx); @@ -734,9 +723,9 @@ js_InternalInvoke(JSContext *cx, jsval thisv, jsval fval, uintN flags, args.getvp()[0] = fval; args.getvp()[1] = thisv; - memcpy(args.getvp() + 2, argv, argc * sizeof(jsval)); + memcpy(args.getvp() + 2, argv, argc * sizeof(Value)); - if (!js_Invoke(cx, args, flags)) + if (!Invoke(cx, args, flags)) return JS_FALSE; /* @@ -746,41 +735,40 @@ js_InternalInvoke(JSContext *cx, jsval thisv, jsval fval, uintN flags, * for local, temporary references to such results. */ *rval = *args.getvp(); - if (JSVAL_IS_GCTHING(*rval) && *rval != JSVAL_NULL) - cx->weakRoots.lastInternalResult = *rval; + if (rval->isMarkable()) + cx->weakRoots.lastInternalResult = rval->asGCThing(); return JS_TRUE; } -JSBool -js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval, - JSAccessMode mode, uintN argc, jsval *argv, jsval *rval) +bool +InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval, + JSAccessMode mode, uintN argc, Value *argv, Value *rval) { LeaveTrace(cx); /* - * js_InternalInvoke could result in another try to get or set the same id + * InternalInvoke could result in another try to get or set the same id * again, see bug 355497. */ JS_CHECK_RECURSION(cx, return JS_FALSE); - return js_InternalCall(cx, obj, fval, argc, argv, rval); + return InternalCall(cx, obj, fval, argc, argv, rval); } -JSBool -js_Execute(JSContext *cx, JSObject *const chain, JSScript *script, - JSStackFrame *down, uintN flags, jsval *result) +bool +Execute(JSContext *cx, JSObject *chain, JSScript *script, + JSStackFrame *down, uintN flags, Value *result) { if (script->isEmpty()) { if (result) - *result = JSVAL_VOID; + result->setUndefined(); return JS_TRUE; } LeaveTrace(cx); DTrace::ExecutionScope executionScope(script); - /* * Get a pointer to new frame/slots. This memory is not "claimed", so the * code before pushExecuteFrame must not reenter the interpreter. @@ -794,14 +782,14 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script, return false; JSStackFrame *fp = frame.getFrame(); - /* Initialize fixed slots. */ - PodZero(fp->slots(), script->nfixed); + /* Initialize fixed slots (GVAR ops expecte NULL). */ + SetValueRangeToNull(fp->slots(), script->nfixed); #if JS_HAS_SHARP_VARS JS_STATIC_ASSERT(SHARP_NSLOTS == 2); if (script->hasSharps) { JS_ASSERT(script->nfixed >= SHARP_NSLOTS); - jsval *sharps = &fp->slots()[script->nfixed - SHARP_NSLOTS]; + Value *sharps = &fp->slots()[script->nfixed - SHARP_NSLOTS]; if (down && down->script && down->script->hasSharps) { JS_ASSERT(down->script->nfixed >= SHARP_NSLOTS); int base = (down->fun && !(down->flags & JSFRAME_SPECIAL)) @@ -812,7 +800,8 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script, sharps[0] = down->slots()[base]; sharps[1] = down->slots()[base + 1]; } else { - sharps[0] = sharps[1] = JSVAL_VOID; + sharps[0].setUndefined(); + sharps[1].setUndefined(); } } #endif @@ -845,7 +834,7 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script, fp->callobj = NULL; fp->argsobj = NULL; fp->fun = NULL; - /* Ininitialize fp->thisv after pushExecuteFrame. */ + fp->thisv.setUndefined(); /* Make GC-safe until initialized below. */ fp->flags = flags | JSFRAME_COMPUTED_THIS; fp->argc = 0; fp->argv = NULL; @@ -865,12 +854,12 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script, fp->script = script; fp->imacpc = NULL; - fp->rval = JSVAL_VOID; + fp->rval.setUndefined(); fp->blockChain = NULL; /* Initialize regs. */ regs.pc = script->code; - regs.sp = StackBase(fp); + regs.sp = fp->base(); /* Officially push |fp|. |frame|'s destructor pops. */ cx->stack().pushExecuteFrame(cx, frame, regs, initialVarObj); @@ -880,7 +869,7 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script, JSObject *thisp = chain->thisObject(cx); if (!thisp) return false; - fp->thisv = OBJECT_TO_JSVAL(thisp); + fp->thisv.setObject(*thisp); } void *hookData = NULL; @@ -888,7 +877,7 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script, hookData = hook(cx, fp, JS_TRUE, 0, cx->debugHooks->executeHookData); AutoPreserveEnumerators preserve(cx); - JSBool ok = js_Interpret(cx); + JSBool ok = Interpret(cx); if (result) *result = fp->rval; @@ -897,18 +886,17 @@ js_Execute(JSContext *cx, JSObject *const chain, JSScript *script, hook(cx, fp, JS_FALSE, &ok, hookData); } - return ok; + return !!ok; } -JSBool -js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, - JSObject **objp, JSProperty **propp) +bool +CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, + JSObject **objp, JSProperty **propp) { JSObject *obj2; JSProperty *prop; uintN oldAttrs, report; bool isFunction; - jsval value; const char *type, *name; /* @@ -991,9 +979,10 @@ js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, report = JSREPORT_ERROR; isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0; if (!isFunction) { + Value value; if (!obj->getProperty(cx, id, &value)) return JS_FALSE; - isFunction = VALUE_IS_FUNCTION(cx, value); + isFunction = IsFunctionObject(value); } } @@ -1008,93 +997,119 @@ js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, : isFunction ? js_function_str : js_var_str; - name = js_ValueToPrintableString(cx, ID_TO_VALUE(id)); + name = js_ValueToPrintableString(cx, IdToValue(id)); if (!name) return JS_FALSE; - return JS_ReportErrorFlagsAndNumber(cx, report, - js_GetErrorMessage, NULL, - JSMSG_REDECLARED_VAR, - type, name); + return !!JS_ReportErrorFlagsAndNumber(cx, report, + js_GetErrorMessage, NULL, + JSMSG_REDECLARED_VAR, + type, name); } -JSBool -js_StrictlyEqual(JSContext *cx, jsval lval, jsval rval) +static JS_ALWAYS_INLINE bool +EqualObjects(JSContext *cx, JSObject *lobj, JSObject *robj) { - jsval ltag = JSVAL_TAG(lval), rtag = JSVAL_TAG(rval); - jsdouble ld, rd; + return lobj == robj || + lobj->wrappedObject(cx) == robj->wrappedObject(cx); +} - if (ltag == rtag) { - if (ltag == JSVAL_STRING) { - JSString *lstr = JSVAL_TO_STRING(lval), - *rstr = JSVAL_TO_STRING(rval); - return js_EqualStrings(lstr, rstr); - } - if (ltag == JSVAL_DOUBLE) { - ld = *JSVAL_TO_DOUBLE(lval); - rd = *JSVAL_TO_DOUBLE(rval); - return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); - } - if (ltag == JSVAL_OBJECT && - lval != rval && - !JSVAL_IS_NULL(lval) && - !JSVAL_IS_NULL(rval)) { - JSObject *lobj, *robj; - - lobj = JSVAL_TO_OBJECT(lval)->wrappedObject(cx); - robj = JSVAL_TO_OBJECT(rval)->wrappedObject(cx); - lval = OBJECT_TO_JSVAL(lobj); - rval = OBJECT_TO_JSVAL(robj); - } - return lval == rval; +bool +StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref) +{ + Value lval = lref, rval = rref; + if (SameType(lval, rval)) { + if (lval.isString()) + return js_EqualStrings(lval.toString(), rval.toString()); + if (lval.isDouble()) + return JSDOUBLE_COMPARE(lval.toDouble(), ==, rval.toDouble(), JS_FALSE); + if (lval.isObject()) + return EqualObjects(cx, &lval.toObject(), &rval.toObject()); + return lval.payloadAsRawUint32() == rval.payloadAsRawUint32(); } - if (ltag == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) { - ld = *JSVAL_TO_DOUBLE(lval); - rd = JSVAL_TO_INT(rval); + + if (lval.isDouble() && rval.isInt32()) { + double ld = lval.toDouble(); + double rd = rval.toInt32(); return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); } - if (JSVAL_IS_INT(lval) && rtag == JSVAL_DOUBLE) { - ld = JSVAL_TO_INT(lval); - rd = *JSVAL_TO_DOUBLE(rval); + if (lval.isInt32() && rval.isDouble()) { + double ld = lval.toInt32(); + double rd = rval.toDouble(); return JSDOUBLE_COMPARE(ld, ==, rd, JS_FALSE); } - return lval == rval; + + return false; } static inline bool -IsNegativeZero(jsval v) +IsNegativeZero(const Value &v) { - return JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v)); + return v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble()); } static inline bool -IsNaN(jsval v) +IsNaN(const Value &v) { - return JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NaN(*JSVAL_TO_DOUBLE(v)); + return v.isDouble() && JSDOUBLE_IS_NaN(v.toDouble()); } -JSBool -js_SameValue(jsval v1, jsval v2, JSContext *cx) +bool +SameValue(const Value &v1, const Value &v2, JSContext *cx) { if (IsNegativeZero(v1)) return IsNegativeZero(v2); if (IsNegativeZero(v2)) - return JS_FALSE; + return false; if (IsNaN(v1) && IsNaN(v2)) - return JS_TRUE; - return js_StrictlyEqual(cx, v1, v2); + return true; + return StrictlyEqual(cx, v1, v2); } -JS_REQUIRES_STACK JSBool -js_InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args) +JSType +TypeOfValue(JSContext *cx, const Value &vref) +{ + Value v = vref; + if (v.isNumber()) + return JSTYPE_NUMBER; + if (v.isString()) + return JSTYPE_STRING; + if (v.isNull()) + return JSTYPE_OBJECT; + if (v.isUndefined()) + return JSTYPE_VOID; + if (v.isObject()) + return v.toObject().map->ops->typeOf(cx, &v.toObject()); + JS_ASSERT(v.isBoolean()); + return JSTYPE_BOOLEAN; +} + +bool +InstanceOfSlow(JSContext *cx, JSObject *obj, Class *clasp, Value *argv) +{ + JS_ASSERT(!obj || obj->getClass() != clasp); + if (argv) { + JSFunction *fun = js_ValueToFunction(cx, &argv[-2], 0); + if (fun) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + clasp->name, JS_GetFunctionName(fun), + obj + ? obj->getClass()->name + : js_null_str); + } + } + return false; +} + +JS_REQUIRES_STACK bool +InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args) { JSFunction *fun = NULL; JSObject *obj2 = NULL; - jsval *vp = args.getvp(); - jsval lval = *vp; - if (!JSVAL_IS_OBJECT(lval) || - (obj2 = JSVAL_TO_OBJECT(lval)) == NULL || - /* XXX clean up to avoid special cases above ObjectOps layer */ - obj2->getClass() == &js_FunctionClass || + Value *vp = args.getvp(); + + /* XXX clean up to avoid special cases above ObjectOps layer */ + if (vp->isPrimitive() || (obj2 = &vp->toObject())->isFunction() || !obj2->map->ops->construct) { fun = js_ValueToFunction(cx, vp, JSV2F_CONSTRUCT); @@ -1103,9 +1118,10 @@ js_InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args) } JSObject *proto, *parent; - JSClass *clasp = &js_ObjectClass; - if (!obj2) { - proto = parent = NULL; + Class *clasp = &js_ObjectClass; + if (vp->isPrimitive()) { + proto = NULL; + parent = NULL; fun = NULL; } else { /* @@ -1114,12 +1130,16 @@ js_InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args) * root to protect this prototype, in case it has no other * strong refs. */ + JSObject *obj2 = &vp->toObject(); if (!obj2->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &vp[1])) { return JS_FALSE; } - jsval v = vp[1]; - proto = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL; + const Value &v = vp[1]; + if (v.isObjectOrNull()) + proto = v.toObjectOrNull(); + else + proto = NULL; parent = obj2->getParent(); if (obj2->getClass() == &js_FunctionClass) { @@ -1136,48 +1156,55 @@ js_InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args) AutoObjectRooter tvr(cx, obj); /* Now we have an object with a constructor method; call it. */ - vp[1] = OBJECT_TO_JSVAL(obj); - if (!js_Invoke(cx, args, JSINVOKE_CONSTRUCT)) + vp[1].setObject(*obj); + if (!Invoke(cx, args, JSINVOKE_CONSTRUCT)) return JS_FALSE; /* Check the return value and if it's primitive, force it to be obj. */ - jsval rval = *vp; - if (JSVAL_IS_PRIMITIVE(rval)) { + const Value &rval = *vp; + if (rval.isPrimitive()) { if (!fun) { /* native [[Construct]] returning primitive is error */ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_NEW_RESULT, - js_ValueToPrintableString(cx, rval)); + js_ValueToPrintableString(cx, *vp)); return JS_FALSE; } - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); } JS_RUNTIME_METER(cx->runtime, constructs); return JS_TRUE; } -JSBool -js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp) +bool +ValueToId(JSContext *cx, const Value &v, jsid *idp) { - JS_ASSERT(!JSVAL_IS_INT(idval)); + int32_t i; + if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) { + *idp = INT_TO_JSID(i); + return true; + } #if JS_HAS_XML_SUPPORT - if (!JSVAL_IS_PRIMITIVE(idval)) { + if (v.isObject()) { + JSObject *obj = &v.toObject(); if (obj->isXML()) { - *idp = OBJECT_JSVAL_TO_JSID(idval); + *idp = OBJECT_TO_JSID(obj); return JS_TRUE; } - if (!js_IsFunctionQName(cx, JSVAL_TO_OBJECT(idval), idp)) + if (!js_IsFunctionQName(cx, obj, idp)) return JS_FALSE; - if (*idp != 0) + if (!JSID_IS_VOID(*idp)) return JS_TRUE; } #endif - return js_ValueToStringId(cx, idval, idp); + return js_ValueToStringId(cx, v, idp); } +} /* namespace js */ + /* * Enter the new with scope using an object at sp[-1] and associate the depth * of the with block with sp + stackIndex. @@ -1185,25 +1212,22 @@ js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp) JS_STATIC_INTERPRET JS_REQUIRES_STACK JSBool js_EnterWith(JSContext *cx, jsint stackIndex) { - JSStackFrame *fp; - jsval *sp; - JSObject *obj, *parent, *withobj; - - fp = cx->fp; - sp = cx->regs->sp; + JSStackFrame *fp = cx->fp; + Value *sp = cx->regs->sp; JS_ASSERT(stackIndex < 0); - JS_ASSERT(StackBase(fp) <= sp + stackIndex); + JS_ASSERT(fp->base() <= sp + stackIndex); - if (!JSVAL_IS_PRIMITIVE(sp[-1])) { - obj = JSVAL_TO_OBJECT(sp[-1]); + JSObject *obj; + if (sp[-1].isObject()) { + obj = &sp[-1].toObject(); } else { obj = js_ValueToNonNullObject(cx, sp[-1]); if (!obj) return JS_FALSE; - sp[-1] = OBJECT_TO_JSVAL(obj); + sp[-1].setObject(*obj); } - parent = js_GetScopeChain(cx, fp); + JSObject *parent = js_GetScopeChain(cx, fp); if (!parent) return JS_FALSE; @@ -1211,8 +1235,8 @@ js_EnterWith(JSContext *cx, jsint stackIndex) if (!obj) return JS_FALSE; - withobj = js_NewWithObject(cx, obj, parent, - sp + stackIndex - StackBase(fp)); + JSObject *withobj = js_NewWithObject(cx, obj, parent, + sp + stackIndex - fp->base()); if (!withobj) return JS_FALSE; @@ -1233,10 +1257,10 @@ js_LeaveWith(JSContext *cx) withobj->setPrivate(NULL); } -JS_REQUIRES_STACK JSClass * +JS_REQUIRES_STACK Class * js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth) { - JSClass *clasp; + Class *clasp; clasp = obj->getClass(); if ((clasp == &js_WithClass || clasp == &js_BlockClass) && @@ -1255,10 +1279,10 @@ JS_STATIC_INTERPRET JS_REQUIRES_STACK JSBool js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind) { JSObject *obj; - JSClass *clasp; + Class *clasp; JS_ASSERT(stackDepth >= 0); - JS_ASSERT(StackBase(cx->fp) + stackDepth <= cx->regs->sp); + JS_ASSERT(cx->fp->base() + stackDepth <= cx->regs->sp); JSStackFrame *fp = cx->fp; for (obj = fp->blockChain; obj; obj = obj->getParent()) { @@ -1281,32 +1305,33 @@ js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind) } } - cx->regs->sp = StackBase(fp) + stackDepth; + cx->regs->sp = fp->base() + stackDepth; return normalUnwind; } JS_STATIC_INTERPRET JSBool -js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2) +js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, Value *vp, Value *vp2) { if (cs->format & JOF_POST) { double d; - if (!ValueToNumberValue(cx, vp, &d)) + if (!ValueToNumber(cx, *vp, &d)) return JS_FALSE; + vp->setNumber(d); (cs->format & JOF_INC) ? ++d : --d; - return js_NewNumberInRootedValue(cx, d, vp2); + vp2->setNumber(d); + return JS_TRUE; } double d; if (!ValueToNumber(cx, *vp, &d)) return JS_FALSE; (cs->format & JOF_INC) ? ++d : --d; - if (!js_NewNumberInRootedValue(cx, d, vp2)) - return JS_FALSE; - *vp = *vp2; + vp->setNumber(d); + *vp2 = *vp; return JS_TRUE; } -jsval & +const Value & js_GetUpvar(JSContext *cx, uintN level, UpvarCookie cookie) { level -= cookie.level(); @@ -1316,7 +1341,7 @@ js_GetUpvar(JSContext *cx, uintN level, UpvarCookie cookie) JS_ASSERT(fp->script); uintN slot = cookie.slot(); - jsval *vp; + Value *vp; if (!fp->fun || (fp->flags & JSFRAME_EVAL)) { vp = fp->slots() + fp->script->nfixed; @@ -1343,7 +1368,6 @@ js_TraceOpcode(JSContext *cx) JSStackFrame *fp; JSFrameRegs *regs; intN ndefs, n, nuses; - jsval *siter; JSString *str; JSOp op; @@ -1369,8 +1393,7 @@ js_TraceOpcode(JSContext *cx) if (ndefs != 0 && ndefs < regs->sp - fp->slots()) { for (n = -ndefs; n < 0; n++) { - char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n], - NULL); + char *bytes = DecompileValueGenerator(cx, n, regs->sp[n], NULL); if (bytes) { fprintf(tracefp, "%s %s", (n == -ndefs) ? " output:" : ",", @@ -1380,10 +1403,10 @@ js_TraceOpcode(JSContext *cx) JS_ClearPendingException(cx); } } - fprintf(tracefp, " @ %u\n", (uintN) (regs->sp - StackBase(fp))); + fprintf(tracefp, " @ %u\n", (uintN) (regs->sp - fp->base())); } fprintf(tracefp, " stack: "); - for (siter = StackBase(fp); siter < regs->sp; siter++) { + for (Value *siter = fp->base(); siter < regs->sp; siter++) { str = js_ValueToString(cx, *siter); if (!str) { fputs("", tracefp); @@ -1405,8 +1428,7 @@ js_TraceOpcode(JSContext *cx) nuses = js_GetStackUses(&js_CodeSpec[op], op, regs->pc); if (nuses != 0) { for (n = -nuses; n < 0; n++) { - char *bytes = js_DecompileValueGenerator(cx, n, regs->sp[n], - NULL); + char *bytes = DecompileValueGenerator(cx, n, regs->sp[n], NULL); if (bytes) { fprintf(tracefp, "%s %s", (n == -nuses) ? " inputs:" : ",", @@ -1416,7 +1438,7 @@ js_TraceOpcode(JSContext *cx) JS_ClearPendingException(cx); } } - fprintf(tracefp, " @ %u\n", (uintN) (regs->sp - StackBase(fp))); + fprintf(tracefp, " @ %u\n", (uintN) (regs->sp - fp->base())); } cx->tracePrevPc = regs->pc; @@ -1629,7 +1651,7 @@ namespace reprmeter { } static const char *reprName[] = { "invalid", "int", "double", "bool", "special", - "string", "null", "object", + "string", "null", "object", "fun:interp", "fun:fast", "fun:slow", "array:slow", "array:dense" }; @@ -1730,121 +1752,64 @@ namespace reprmeter { } #endif /* JS_REPRMETER */ -#define PUSH(v) (*regs.sp++ = (v)) -#define PUSH_OPND(v) PUSH(v) -#define STORE_OPND(n,v) (regs.sp[n] = (v)) -#define POP() (*--regs.sp) -#define POP_OPND() POP() -#define FETCH_OPND(n) (regs.sp[n]) +#define PUSH_COPY(v) *regs.sp++ = v +#define PUSH_NULL() regs.sp++->setNull() +#define PUSH_UNDEFINED() regs.sp++->setUndefined() +#define PUSH_BOOLEAN(b) regs.sp++->setBoolean(b) +#define PUSH_DOUBLE(d) regs.sp++->setDouble(d) +#define PUSH_INT32(i) regs.sp++->setInt32(i) +#define PUSH_STRING(s) regs.sp++->setString(s) +#define PUSH_OBJECT(obj) regs.sp++->setObject(obj) +#define PUSH_OBJECT_OR_NULL(obj) regs.sp++->setObject(obj) +#define PUSH_HOLE() regs.sp++->setMagic(JS_ARRAY_HOLE) +#define POP_COPY_TO(v) v = *--regs.sp -/* - * Push the jsdouble d using sp from the lexical environment. Try to convert d - * to a jsint that fits in a jsval, otherwise GC-alloc space for it and push a - * reference. - */ -#define STORE_NUMBER(cx, n, d) \ +#define POP_BOOLEAN(cx, vp, b) \ JS_BEGIN_MACRO \ - jsint i_; \ - \ - if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) \ - regs.sp[n] = INT_TO_JSVAL(i_); \ - else if (!js_NewDoubleInRootedValue(cx, d, ®s.sp[n])) \ - goto error; \ - JS_END_MACRO - -#define STORE_INT(cx, n, i) \ - JS_BEGIN_MACRO \ - if (INT_FITS_IN_JSVAL(i)) \ - regs.sp[n] = INT_TO_JSVAL(i); \ - else if (!js_NewDoubleInRootedValue(cx, (jsdouble) (i), ®s.sp[n])) \ - goto error; \ - JS_END_MACRO - -#define STORE_UINT(cx, n, u) \ - JS_BEGIN_MACRO \ - if ((u) <= JSVAL_INT_MAX) \ - regs.sp[n] = INT_TO_JSVAL(u); \ - else if (!js_NewDoubleInRootedValue(cx, (jsdouble) (u), ®s.sp[n])) \ - goto error; \ - JS_END_MACRO - -#define FETCH_NUMBER(cx, n, d) \ - JS_BEGIN_MACRO \ - jsval v_; \ - \ - v_ = FETCH_OPND(n); \ - VALUE_TO_NUMBER(cx, v_, d); \ - JS_END_MACRO - -#define FETCH_INT(cx, n, i) \ - JS_BEGIN_MACRO \ - if (!ValueToECMAInt32(cx, regs.sp[n], &i)) \ - goto error; \ - JS_END_MACRO - -#define FETCH_UINT(cx, n, ui) \ - JS_BEGIN_MACRO \ - if (!ValueToECMAUint32(cx, regs.sp[n], &ui)) \ - goto error; \ - JS_END_MACRO - -#define VALUE_TO_NUMBER(cx, v, d) \ - JS_BEGIN_MACRO \ - if (!ValueToNumber(cx, v, &d)) \ - goto error; \ - JS_END_MACRO - -#define POP_BOOLEAN(cx, v, b) \ - JS_BEGIN_MACRO \ - v = FETCH_OPND(-1); \ - if (v == JSVAL_NULL) { \ - b = JS_FALSE; \ - } else if (JSVAL_IS_BOOLEAN(v)) { \ - b = JSVAL_TO_BOOLEAN(v); \ + vp = ®s.sp[-1]; \ + if (vp->isNull()) { \ + b = false; \ + } else if (vp->isBoolean()) { \ + b = vp->toBoolean(); \ } else { \ - b = js_ValueToBoolean(v); \ + b = !!js_ValueToBoolean(*vp); \ } \ regs.sp--; \ JS_END_MACRO -#define VALUE_TO_OBJECT(cx, n, v, obj) \ +#define VALUE_TO_OBJECT(cx, vp, obj) \ JS_BEGIN_MACRO \ - if (!JSVAL_IS_PRIMITIVE(v)) { \ - obj = JSVAL_TO_OBJECT(v); \ + if ((vp)->isObject()) { \ + obj = &(vp)->toObject(); \ } else { \ - obj = js_ValueToNonNullObject(cx, v); \ + obj = js_ValueToNonNullObject(cx, *(vp)); \ if (!obj) \ goto error; \ - STORE_OPND(n, OBJECT_TO_JSVAL(obj)); \ + (vp)->setObject(*obj); \ } \ JS_END_MACRO -#define FETCH_OBJECT(cx, n, v, obj) \ +#define FETCH_OBJECT(cx, n, obj) \ JS_BEGIN_MACRO \ - v = FETCH_OPND(n); \ - VALUE_TO_OBJECT(cx, n, v, obj); \ + Value *vp_ = ®s.sp[n]; \ + VALUE_TO_OBJECT(cx, vp_, obj); \ JS_END_MACRO #define DEFAULT_VALUE(cx, n, hint, v) \ JS_BEGIN_MACRO \ - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); \ + JS_ASSERT(v.isObject()); \ JS_ASSERT(v == regs.sp[n]); \ - if (!DefaultValue(cx, JSVAL_TO_OBJECT(v), hint, ®s.sp[n])) \ + if (!DefaultValue(cx, &v.toObject(), hint, ®s.sp[n])) \ goto error; \ v = regs.sp[n]; \ JS_END_MACRO -/* - * Quickly test if v is an int from the [-2**29, 2**29) range, that is, when - * the lowest bit of v is 1 and the bits 30 and 31 are both either 0 or 1. For - * such v we can do increment or decrement via adding or subtracting two - * without checking that the result overflows JSVAL_INT_MIN or JSVAL_INT_MAX. - */ -#define CAN_DO_FAST_INC_DEC(v) (((((v) << 1) ^ v) & 0x80000001) == 1) - -JS_STATIC_ASSERT(JSVAL_INT == 1); -JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(INT_TO_JSVAL_CONSTEXPR(JSVAL_INT_MIN))); -JS_STATIC_ASSERT(!CAN_DO_FAST_INC_DEC(INT_TO_JSVAL_CONSTEXPR(JSVAL_INT_MAX))); +/* Test whether v is an int in the range [-2^31 + 1, 2^31 - 2] */ +static JS_ALWAYS_INLINE bool +CanIncDecWithoutOverflow(int32_t i) +{ + return (i > JSVAL_INT_MIN) && (i < JSVAL_INT_MAX); +} /* * Conditional assert to detect failure to clear a pending exception that is @@ -1964,21 +1929,20 @@ AssertValidPropertyCacheHit(JSContext *cx, JSScript *script, JSFrameRegs& regs, } else if (entry->vword.isSprop()) { JS_ASSERT(entry->vword.toSprop() == sprop); JS_ASSERT_IF(sprop->isMethod(), - sprop->methodValue() == pobj->lockedGetSlot(sprop->slot)); + &sprop->methodObject() == &pobj->lockedGetSlot(sprop->slot).toObject()); } else { - jsval v; - JS_ASSERT(entry->vword.isObject()); + Value v; + JS_ASSERT(entry->vword.isFunObj()); JS_ASSERT(!entry->vword.isNull()); JS_ASSERT(pobj->scope()->brandedOrHasMethodBarrier()); JS_ASSERT(sprop->hasDefaultGetterOrIsMethod()); JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, pobj->scope())); v = pobj->lockedGetSlot(sprop->slot); - JS_ASSERT(VALUE_IS_FUNCTION(cx, v)); - JS_ASSERT(entry->vword.toObject() == JSVAL_TO_OBJECT(v)); + JS_ASSERT(&entry->vword.toFunObj() == &v.toObject()); if (sprop->isMethod()) { JS_ASSERT(js_CodeSpec[*regs.pc].format & JOF_CALLOP); - JS_ASSERT(sprop->methodValue() == v); + JS_ASSERT(&sprop->methodObject() == &v.toObject()); } } @@ -2042,7 +2006,7 @@ JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH); * all cases, but we inline the most frequently taken paths here. */ static inline bool -IteratorMore(JSContext *cx, JSObject *iterobj, JSBool *cond, jsval *rval) +IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval) { if (iterobj->getClass() == &js_IteratorClass.base) { NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); @@ -2050,63 +2014,43 @@ IteratorMore(JSContext *cx, JSObject *iterobj, JSBool *cond, jsval *rval) } else { if (!js_IteratorMore(cx, iterobj, rval)) return false; - *cond = (*rval == JSVAL_TRUE); + *cond = rval->isTrue(); } return true; } static inline bool -IteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval) +IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval) { if (iterobj->getClass() == &js_IteratorClass.base) { NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); JS_ASSERT(ni->props_cursor < ni->props_end); - *rval = *ni->props_cursor; - if (JSVAL_IS_STRING(*rval) || (ni->flags & JSITER_FOREACH)) { - ni->props_cursor++; + if (ni->isKeyIter()) { + jsid id = *ni->currentKey(); + if (JSID_IS_ATOM(id)) { + rval->setString(JSID_TO_STRING(id)); + ni->incKeyCursor(); + return true; + } + /* Take the slow path if we have to stringify a numeric property name. */ + } else { + *rval = *ni->currentValue(); + ni->incValueCursor(); return true; } - /* Take the slow path if we have to stringify a numeric property name. */ } return js_IteratorNext(cx, iterobj, rval); } -JS_REQUIRES_STACK JSBool -js_Interpret(JSContext *cx) + +namespace js { + +JS_REQUIRES_STACK bool +Interpret(JSContext *cx) { #ifdef MOZ_TRACEVIS TraceVisStateObj tvso(cx, S_INTERP); #endif - - JSRuntime *rt; - JSStackFrame *fp; - JSScript *script; - uintN inlineCallCount; - JSAtom **atoms; - JSVersion currentVersion, originalVersion; - JSFrameRegs regs, *prevContextRegs; - JSObject *obj, *obj2, *parent; - JSBool ok, cond; - jsint len; - jsbytecode *endpc, *pc2; - JSOp op, op2; - jsatomid index; - JSAtom *atom; - uintN argc, attrs, flags; - uint32 slot; - jsval *vp, lval, rval, ltmp, rtmp; - jsid id; - JSProperty *prop; - JSScopeProperty *sprop; - JSString *str, *str2; - int32_t i, j; - jsdouble d, d2; - JSClass *clasp; - JSFunction *fun; - JSType type; - jsint low, high, off, npairs; - JSBool match; - JSPropertyOp getter, setter; JSAutoResolveFlags rf(cx, JSRESOLVE_INFER); # ifdef DEBUG @@ -2133,6 +2077,9 @@ js_Interpret(JSContext *cx) # define TRACE_OPCODE(OP) ((void) 0) # endif + /* + * Macros for threaded interpreter loop + */ #if JS_THREADED_INTERP static void *const normalJumpTable[] = { # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) \ @@ -2225,16 +2172,16 @@ js_Interpret(JSContext *cx) /* Check for too deep of a native thread stack. */ JS_CHECK_RECURSION(cx, return JS_FALSE); - rt = cx->runtime; + JSRuntime *const rt = cx->runtime; /* Set registerized frame pointer and derived script pointer. */ - fp = cx->fp; - script = fp->script; + JSStackFrame *fp = cx->fp; + JSScript *script = fp->script; JS_ASSERT(!script->isEmpty()); JS_ASSERT(script->length > 1); - /* Count of JS function calls that nest in this C js_Interpret frame. */ - inlineCallCount = 0; + /* Count of JS function calls that nest in this C Interpret frame. */ + uintN inlineCallCount = 0; /* * Initialize the index segment register used by LOAD_ATOM and @@ -2243,9 +2190,9 @@ js_Interpret(JSContext *cx) * access. For less frequent object and regexp loads we have to recover * the segment from atoms pointer first. */ - atoms = script->atomMap.vector; + JSAtom **atoms = script->atomMap.vector; -#define LOAD_ATOM(PCOFF) \ +#define LOAD_ATOM(PCOFF, atom) \ JS_BEGIN_MACRO \ JS_ASSERT(fp->imacpc \ ? atoms == COMMON_ATOMS_START(&rt->atomState) && \ @@ -2259,12 +2206,15 @@ js_Interpret(JSContext *cx) #define GET_FULL_INDEX(PCOFF) \ (atoms - script->atomMap.vector + GET_INDEX(regs.pc + PCOFF)) -#define LOAD_OBJECT(PCOFF) \ +#define LOAD_OBJECT(PCOFF, obj) \ (obj = script->getObject(GET_FULL_INDEX(PCOFF))) #define LOAD_FUNCTION(PCOFF) \ (fun = script->getFunction(GET_FULL_INDEX(PCOFF))) +#define LOAD_DOUBLE(PCOFF, dbl) \ + (dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble()) + #ifdef JS_TRACER #ifdef MOZ_TRACEVIS @@ -2291,6 +2241,8 @@ js_Interpret(JSContext *cx) atoms = FrameAtomBase(cx, fp); \ currentVersion = (JSVersion) script->version; \ JS_ASSERT(cx->regs == ®s); \ + if (cx->throwing) \ + goto error; \ JS_END_MACRO #define MONITOR_BRANCH(reason) \ @@ -2356,14 +2308,14 @@ js_Interpret(JSContext *cx) /* * Optimized Get and SetVersion for proper script language versioning. * - * If any native method or JSClass/JSObjectOps hook calls js_SetVersion + * If any native method or Class/JSObjectOps hook calls js_SetVersion * and changes cx->version, the effect will "stick" and we will stop * maintaining currentVersion. This is relied upon by testsuites, for * the most part -- web browsers select version before compiling and not * at run-time. */ - currentVersion = (JSVersion) script->version; - originalVersion = (JSVersion) cx->version; + JSVersion currentVersion = (JSVersion) script->version; + JSVersion originalVersion = (JSVersion) cx->version; if (currentVersion != originalVersion) js_SetVersion(cx, currentVersion); @@ -2374,7 +2326,7 @@ js_Interpret(JSContext *cx) *disp = fp; } -# define CHECK_INTERRUPT_HANDLER() \ +#define CHECK_INTERRUPT_HANDLER() \ JS_BEGIN_MACRO \ if (cx->debugHooks->interruptHook) \ ENABLE_INTERRUPTS(); \ @@ -2393,15 +2345,15 @@ js_Interpret(JSContext *cx) * local variable, and copy out on exit. */ JS_ASSERT(cx->regs); - prevContextRegs = cx->regs; - regs = *cx->regs; + JSFrameRegs *const prevContextRegs = cx->regs; + JSFrameRegs regs = *cx->regs; cx->setCurrentRegs(®s); #if JS_HAS_GENERATORS if (JS_UNLIKELY(fp->isGenerator())) { JS_ASSERT(prevContextRegs == &cx->generatorFor(fp)->savedRegs); JS_ASSERT((size_t) (regs.pc - script->code) <= script->length); - JS_ASSERT((size_t) (regs.sp - StackBase(fp)) <= StackDepth(script)); + JS_ASSERT((size_t) (regs.sp - fp->base()) <= StackDepth(script)); /* * To support generator_throw and to catch ignored exceptions, @@ -2425,14 +2377,24 @@ js_Interpret(JSContext *cx) AbortRecording(cx, "attempt to reenter interpreter while recording"); #endif + /* State communicated between non-local jumps: */ + JSBool interpReturnOK; + JSAtom *atomNotDefined; + /* * It is important that "op" be initialized before calling DO_OP because * it is possible for "op" to be specially assigned during the normal * processing of an opcode while looping. We rely on DO_NEXT_OP to manage * "op" correctly in all other cases. */ + JSOp op; + jsint len; len = 0; +#if JS_THREADED_INTERP DO_NEXT_OP(len); +#else + DO_NEXT_OP(len); +#endif #if JS_THREADED_INTERP /* @@ -2461,15 +2423,4383 @@ js_Interpret(JSContext *cx) switch (switchOp) { #endif -/********************** Here we include the operations ***********************/ -#include "jsops.cpp" -/*****************************************************************************/ +#if JS_THREADED_INTERP + interrupt: +#else /* !JS_THREADED_INTERP */ + case -1: + JS_ASSERT(switchMask == -1); +#endif /* !JS_THREADED_INTERP */ + { + bool moreInterrupts = false; + JSInterruptHook hook = cx->debugHooks->interruptHook; + if (hook) { +#ifdef JS_TRACER + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "interrupt hook"); +#endif + Value rval; + switch (hook(cx, script, regs.pc, Jsvalify(&rval), + cx->debugHooks->interruptHookData)) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + fp->rval = rval; + interpReturnOK = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->throwing = JS_TRUE; + cx->exception = rval; + goto error; + default:; + } + moreInterrupts = true; + } +#ifdef JS_TRACER + if (TraceRecorder* tr = TRACE_RECORDER(cx)) { + AbortableRecordingStatus status = tr->monitorRecording(op); + JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR); + switch (status) { + case ARECORD_CONTINUE: + moreInterrupts = true; + break; + case ARECORD_IMACRO: + case ARECORD_IMACRO_ABORTED: + atoms = COMMON_ATOMS_START(&rt->atomState); + op = JSOp(*regs.pc); + if (status == ARECORD_IMACRO) + DO_OP(); /* keep interrupting for op. */ + break; + case ARECORD_ERROR: + // The code at 'error:' aborts the recording. + goto error; + case ARECORD_ABORTED: + case ARECORD_COMPLETED: + break; + case ARECORD_STOP: + /* A 'stop' error should have already aborted recording. */ + default: + JS_NOT_REACHED("Bad recording status"); + } + } +#endif /* !JS_TRACER */ + +#if JS_THREADED_INTERP +#ifdef MOZ_TRACEVIS + if (!moreInterrupts) + ExitTraceVisState(cx, R_ABORT); +#endif + jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable; + JS_EXTENSION_(goto *normalJumpTable[op]); +#else + switchMask = moreInterrupts ? -1 : 0; + switchOp = intN(op); + goto do_switch; +#endif + } + +/* No-ops for ease of decompilation. */ +ADD_EMPTY_CASE(JSOP_NOP) +ADD_EMPTY_CASE(JSOP_CONDSWITCH) +ADD_EMPTY_CASE(JSOP_TRY) +ADD_EMPTY_CASE(JSOP_TRACE) +#if JS_HAS_XML_SUPPORT +ADD_EMPTY_CASE(JSOP_STARTXML) +ADD_EMPTY_CASE(JSOP_STARTXMLEXPR) +#endif +END_EMPTY_CASES + +/* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */ +BEGIN_CASE(JSOP_LINENO) +END_CASE(JSOP_LINENO) + +BEGIN_CASE(JSOP_PUSH) + PUSH_UNDEFINED(); +END_CASE(JSOP_PUSH) + +BEGIN_CASE(JSOP_POP) + regs.sp--; +END_CASE(JSOP_POP) + +BEGIN_CASE(JSOP_POPN) +{ + regs.sp -= GET_UINT16(regs.pc); +#ifdef DEBUG + JS_ASSERT(fp->base() <= regs.sp); + JSObject *obj = fp->blockChain; + JS_ASSERT_IF(obj, + OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj) + <= (size_t) (regs.sp - fp->base())); + for (obj = fp->scopeChain; obj; obj = obj->getParent()) { + Class *clasp = obj->getClass(); + if (clasp != &js_BlockClass && clasp != &js_WithClass) + continue; + if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, fp)) + break; + JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) + + ((clasp == &js_BlockClass) + ? OBJ_BLOCK_COUNT(cx, obj) + : 1) + <= regs.sp); + } +#endif +} +END_CASE(JSOP_POPN) + +BEGIN_CASE(JSOP_SETRVAL) +BEGIN_CASE(JSOP_POPV) + ASSERT_NOT_THROWING(cx); + POP_COPY_TO(fp->rval); +END_CASE(JSOP_POPV) + +BEGIN_CASE(JSOP_ENTERWITH) + if (!js_EnterWith(cx, -1)) + goto error; + + /* + * We must ensure that different "with" blocks have different stack depth + * associated with them. This allows the try handler search to properly + * recover the scope chain. Thus we must keep the stack at least at the + * current level. + * + * We set sp[-1] to the current "with" object to help asserting the + * enter/leave balance in [leavewith]. + */ + regs.sp[-1].setObject(*fp->scopeChain); +END_CASE(JSOP_ENTERWITH) + +BEGIN_CASE(JSOP_LEAVEWITH) + JS_ASSERT(®s.sp[-1].toObject() == fp->scopeChain); + regs.sp--; + js_LeaveWith(cx); +END_CASE(JSOP_LEAVEWITH) + +BEGIN_CASE(JSOP_RETURN) + POP_COPY_TO(fp->rval); + /* FALL THROUGH */ + +BEGIN_CASE(JSOP_RETRVAL) /* fp->rval already set */ +BEGIN_CASE(JSOP_STOP) +{ + /* + * When the inlined frame exits with an exception or an error, ok will be + * false after the inline_return label. + */ + ASSERT_NOT_THROWING(cx); + CHECK_BRANCH(); + + if (fp->imacpc) { + /* + * If we are at the end of an imacro, return to its caller in the + * current frame. + */ + JS_ASSERT(op == JSOP_STOP); + JS_ASSERT((uintN)(regs.sp - fp->slots()) <= script->nslots); + regs.pc = fp->imacpc + js_CodeSpec[*fp->imacpc].length; + fp->imacpc = NULL; + atoms = script->atomMap.vector; + op = JSOp(*regs.pc); + DO_OP(); + } + + JS_ASSERT(regs.sp == fp->base()); + if ((fp->flags & JSFRAME_CONSTRUCTING) && fp->rval.isPrimitive()) + fp->rval = fp->thisv; + + interpReturnOK = true; + if (inlineCallCount) + inline_return: + { + JS_ASSERT(!fp->blockChain); + JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0)); + + if (JS_LIKELY(script->staticLevel < JS_DISPLAY_SIZE)) + cx->display[script->staticLevel] = fp->displaySave; + + void *hookData = fp->hookData; + if (JS_UNLIKELY(hookData != NULL)) { + if (JSInterpreterHook hook = cx->debugHooks->callHook) { + hook(cx, fp, JS_FALSE, &interpReturnOK, hookData); + CHECK_INTERRUPT_HANDLER(); + } + } + + /* + * If fp has a call object, sync values and clear the back- + * pointer. This can happen for a lightweight function if it calls eval + * unexpectedly (in a way that is hidden from the compiler). See bug + * 325540. + */ + fp->putActivationObjects(cx); + + DTrace::exitJSFun(cx, fp, fp->fun, fp->rval); + + /* Restore context version only if callee hasn't set version. */ + if (JS_LIKELY(cx->version == currentVersion)) { + currentVersion = fp->callerVersion; + if (currentVersion != cx->version) + js_SetVersion(cx, currentVersion); + } + + /* + * If inline-constructing, replace primitive rval with the new object + * passed in via |this|, and instrument this constructor invocation. + */ + if (fp->flags & JSFRAME_CONSTRUCTING) { + if (fp->rval.isPrimitive()) + fp->rval = fp->thisv; + JS_RUNTIME_METER(cx->runtime, constructs); + } + + JSStackFrame *down = fp->down; + bool recursive = fp->script == down->script; + + /* Pop the frame. */ + cx->stack().popInlineFrame(cx, fp, down); + + /* Propagate return value before fp is lost. */ + regs.sp[-1] = fp->rval; + + /* Sync interpreter registers. */ + fp = cx->fp; + script = fp->script; + atoms = FrameAtomBase(cx, fp); + + /* Resume execution in the calling frame. */ + inlineCallCount--; + if (JS_LIKELY(interpReturnOK)) { + JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length + == JSOP_CALL_LENGTH); + TRACE_0(LeaveFrame); + if (!TRACE_RECORDER(cx) && recursive) { + if (*(regs.pc + JSOP_CALL_LENGTH) == JSOP_TRACE) { + regs.pc += JSOP_CALL_LENGTH; + MONITOR_BRANCH(Record_LeaveFrame); + op = (JSOp)*regs.pc; + DO_OP(); + } + } + if (*(regs.pc + JSOP_CALL_LENGTH) == JSOP_TRACE || + *(regs.pc + JSOP_CALL_LENGTH) == JSOP_NOP) { + JS_STATIC_ASSERT(JSOP_TRACE_LENGTH == JSOP_NOP_LENGTH); + regs.pc += JSOP_CALL_LENGTH; + len = JSOP_TRACE_LENGTH; + } else { + len = JSOP_CALL_LENGTH; + } + DO_NEXT_OP(len); + } + goto error; + } + interpReturnOK = true; + goto exit; +} + +BEGIN_CASE(JSOP_DEFAULT) + regs.sp--; + /* FALL THROUGH */ +BEGIN_CASE(JSOP_GOTO) +{ + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); +} +END_CASE(JSOP_GOTO) + +BEGIN_CASE(JSOP_IFEQ) +{ + bool cond; + Value *_; + POP_BOOLEAN(cx, _, cond); + if (cond == false) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_IFEQ) + +BEGIN_CASE(JSOP_IFNE) +{ + bool cond; + Value *_; + POP_BOOLEAN(cx, _, cond); + if (cond != false) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_IFNE) + +BEGIN_CASE(JSOP_OR) +{ + bool cond; + Value *vp; + POP_BOOLEAN(cx, vp, cond); + if (cond == true) { + len = GET_JUMP_OFFSET(regs.pc); + PUSH_COPY(*vp); + DO_NEXT_OP(len); + } +} +END_CASE(JSOP_OR) + +BEGIN_CASE(JSOP_AND) +{ + bool cond; + Value *vp; + POP_BOOLEAN(cx, vp, cond); + if (cond == false) { + len = GET_JUMP_OFFSET(regs.pc); + PUSH_COPY(*vp); + DO_NEXT_OP(len); + } +} +END_CASE(JSOP_AND) + +BEGIN_CASE(JSOP_DEFAULTX) + regs.sp--; + /* FALL THROUGH */ +BEGIN_CASE(JSOP_GOTOX) +{ + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); +} +END_CASE(JSOP_GOTOX); + +BEGIN_CASE(JSOP_IFEQX) +{ + bool cond; + Value *_; + POP_BOOLEAN(cx, _, cond); + if (cond == false) { + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_IFEQX) + +BEGIN_CASE(JSOP_IFNEX) +{ + bool cond; + Value *_; + POP_BOOLEAN(cx, _, cond); + if (cond != false) { + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_IFNEX) + +BEGIN_CASE(JSOP_ORX) +{ + bool cond; + Value *vp; + POP_BOOLEAN(cx, vp, cond); + if (cond == true) { + len = GET_JUMPX_OFFSET(regs.pc); + PUSH_COPY(*vp); + DO_NEXT_OP(len); + } +} +END_CASE(JSOP_ORX) + +BEGIN_CASE(JSOP_ANDX) +{ + bool cond; + Value *vp; + POP_BOOLEAN(cx, vp, cond); + if (cond == JS_FALSE) { + len = GET_JUMPX_OFFSET(regs.pc); + PUSH_COPY(*vp); + DO_NEXT_OP(len); + } +} +END_CASE(JSOP_ANDX) + +/* + * If the index value at sp[n] is not an int that fits in a jsval, it could + * be an object (an XML QName, AttributeName, or AnyName), but only if we are + * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a + * string atom id. + */ +#define FETCH_ELEMENT_ID(obj, n, id) \ + JS_BEGIN_MACRO \ + const Value &idval_ = regs.sp[n]; \ + int32_t i_; \ + if (ValueFitsInInt32(idval_, &i_) && INT_FITS_IN_JSID(i_)) { \ + id = INT_TO_JSID(i_); \ + } else { \ + if (!js_InternNonIntElementId(cx, obj, idval_, &id, ®s.sp[n])) \ + goto error; \ + } \ + JS_END_MACRO + +#define TRY_BRANCH_AFTER_COND(cond,spdec) \ + JS_BEGIN_MACRO \ + JS_ASSERT(js_CodeSpec[op].length == 1); \ + uintN diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \ + if (diff_ <= 1) { \ + regs.sp -= spdec; \ + if (cond == (diff_ != 0)) { \ + ++regs.pc; \ + len = GET_JUMP_OFFSET(regs.pc); \ + BRANCH(len); \ + } \ + len = 1 + JSOP_IFEQ_LENGTH; \ + DO_NEXT_OP(len); \ + } \ + JS_END_MACRO + +BEGIN_CASE(JSOP_IN) +{ + const Value &rref = regs.sp[-1]; + if (!rref.isObject()) { + js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NULL); + goto error; + } + JSObject *obj = &rref.toObject(); + jsid id; + FETCH_ELEMENT_ID(obj, -2, id); + JSObject *obj2; + JSProperty *prop; + if (!obj->lookupProperty(cx, id, &obj2, &prop)) + goto error; + bool cond = prop != NULL; + if (prop) + obj2->dropProperty(cx, prop); + TRY_BRANCH_AFTER_COND(cond, 2); + regs.sp--; + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_IN) + +BEGIN_CASE(JSOP_ITER) +{ + JS_ASSERT(regs.sp > fp->base()); + uintN flags = regs.pc[1]; + if (!js_ValueToIterator(cx, flags, ®s.sp[-1])) + goto error; + CHECK_INTERRUPT_HANDLER(); + JS_ASSERT(!regs.sp[-1].isPrimitive()); +} +END_CASE(JSOP_ITER) + +BEGIN_CASE(JSOP_MOREITER) +{ + JS_ASSERT(regs.sp - 1 >= fp->base()); + JS_ASSERT(regs.sp[-1].isObject()); + PUSH_NULL(); + bool cond; + if (!IteratorMore(cx, ®s.sp[-2].toObject(), &cond, ®s.sp[-1])) + goto error; + CHECK_INTERRUPT_HANDLER(); + TRY_BRANCH_AFTER_COND(cond, 1); + JS_ASSERT(regs.pc[1] == JSOP_IFNEX); + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_MOREITER) + +BEGIN_CASE(JSOP_ENDITER) +{ + JS_ASSERT(regs.sp - 1 >= fp->base()); + bool ok = !!js_CloseIterator(cx, ®s.sp[-1].toObject()); + regs.sp--; + if (!ok) + goto error; +} +END_CASE(JSOP_ENDITER) + +BEGIN_CASE(JSOP_FORARG) +{ + JS_ASSERT(regs.sp - 1 >= fp->base()); + uintN slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + JS_ASSERT(regs.sp[-1].isObject()); + if (!IteratorNext(cx, ®s.sp[-1].toObject(), &fp->argv[slot])) + goto error; +} +END_CASE(JSOP_FORARG) + +BEGIN_CASE(JSOP_FORLOCAL) +{ + JS_ASSERT(regs.sp - 1 >= fp->base()); + uintN slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < fp->script->nslots); + JS_ASSERT(regs.sp[-1].isObject()); + if (!IteratorNext(cx, ®s.sp[-1].toObject(), &fp->slots()[slot])) + goto error; +} +END_CASE(JSOP_FORLOCAL) + +BEGIN_CASE(JSOP_FORNAME) +{ + JS_ASSERT(regs.sp - 1 >= fp->base()); + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + JSObject *obj, *obj2; + JSProperty *prop; + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) + goto error; + if (prop) + obj2->dropProperty(cx, prop); + { + AutoValueRooter tvr(cx); + JS_ASSERT(regs.sp[-1].isObject()); + if (!IteratorNext(cx, ®s.sp[-1].toObject(), tvr.addr())) + goto error; + if (!obj->setProperty(cx, id, tvr.addr())) + goto error; + } +} +END_CASE(JSOP_FORNAME) + +BEGIN_CASE(JSOP_FORPROP) +{ + JS_ASSERT(regs.sp - 2 >= fp->base()); + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + JSObject *obj; + FETCH_OBJECT(cx, -1, obj); + { + AutoValueRooter tvr(cx); + JS_ASSERT(regs.sp[-2].isObject()); + if (!IteratorNext(cx, ®s.sp[-2].toObject(), tvr.addr())) + goto error; + if (!obj->setProperty(cx, id, tvr.addr())) + goto error; + } + regs.sp--; +} +END_CASE(JSOP_FORPROP) + +BEGIN_CASE(JSOP_FORELEM) + /* + * JSOP_FORELEM simply dups the property identifier at top of stack and + * lets the subsequent JSOP_ENUMELEM opcode sequence handle the left-hand + * side expression evaluation and assignment. This opcode exists solely to + * help the decompiler. + */ + JS_ASSERT(regs.sp - 1 >= fp->base()); + JS_ASSERT(regs.sp[-1].isObject()); + PUSH_NULL(); + if (!IteratorNext(cx, ®s.sp[-2].toObject(), ®s.sp[-1])) + goto error; +END_CASE(JSOP_FORELEM) + +BEGIN_CASE(JSOP_DUP) +{ + JS_ASSERT(regs.sp > fp->base()); + const Value &rref = regs.sp[-1]; + PUSH_COPY(rref); +} +END_CASE(JSOP_DUP) + +BEGIN_CASE(JSOP_DUP2) +{ + JS_ASSERT(regs.sp - 2 >= fp->base()); + const Value &lref = regs.sp[-2]; + const Value &rref = regs.sp[-1]; + PUSH_COPY(lref); + PUSH_COPY(rref); +} +END_CASE(JSOP_DUP2) + +BEGIN_CASE(JSOP_SWAP) +{ + JS_ASSERT(regs.sp - 2 >= fp->base()); + Value &lref = regs.sp[-2]; + Value &rref = regs.sp[-1]; + lref.swap(rref); +} +END_CASE(JSOP_SWAP) + +BEGIN_CASE(JSOP_PICK) +{ + jsint i = regs.pc[1]; + JS_ASSERT(regs.sp - (i+1) >= fp->base()); + Value lval = regs.sp[-(i+1)]; + memmove(regs.sp - (i+1), regs.sp - i, sizeof(Value)*i); + regs.sp[-1] = lval; +} +END_CASE(JSOP_PICK) + +#define NATIVE_GET(cx,obj,pobj,sprop,getHow,vp) \ + JS_BEGIN_MACRO \ + if (sprop->hasDefaultGetter()) { \ + /* Fast path for Object instance properties. */ \ + JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT || \ + !sprop->hasDefaultSetter()); \ + if (((sprop)->slot != SPROP_INVALID_SLOT)) \ + *(vp) = (pobj)->lockedGetSlot((sprop)->slot); \ + else \ + (vp)->setUndefined(); \ + } else { \ + if (!js_NativeGet(cx, obj, pobj, sprop, getHow, vp)) \ + goto error; \ + } \ + JS_END_MACRO + +#define NATIVE_SET(cx,obj,sprop,entry,vp) \ + JS_BEGIN_MACRO \ + TRACE_2(SetPropHit, entry, sprop); \ + if (sprop->hasDefaultSetter() && \ + (sprop)->slot != SPROP_INVALID_SLOT && \ + !(obj)->scope()->brandedOrHasMethodBarrier()) { \ + /* Fast path for, e.g., plain Object instance properties. */ \ + (obj)->lockedSetSlot((sprop)->slot, *vp); \ + } else { \ + if (!js_NativeSet(cx, obj, sprop, false, vp)) \ + goto error; \ + } \ + JS_END_MACRO + +/* + * Skip the JSOP_POP typically found after a JSOP_SET* opcode, where oplen is + * the constant length of the SET opcode sequence, and spdec is the constant + * by which to decrease the stack pointer to pop all of the SET op's operands. + * + * NB: unlike macros that could conceivably be replaced by functions (ignoring + * goto error), where a call should not have to be braced in order to expand + * correctly (e.g., in if (cond) FOO(); else BAR()), these three macros lack + * JS_{BEGIN,END}_MACRO brackets. They are also indented so as to align with + * nearby opcode code. + */ +#define SKIP_POP_AFTER_SET(oplen,spdec) \ + if (regs.pc[oplen] == JSOP_POP) { \ + regs.sp -= spdec; \ + regs.pc += oplen + JSOP_POP_LENGTH; \ + op = (JSOp) *regs.pc; \ + DO_OP(); \ + } + +#define END_SET_CASE(OP) \ + SKIP_POP_AFTER_SET(OP##_LENGTH, 1); \ + END_CASE(OP) + +#define END_SET_CASE_STORE_RVAL(OP,spdec) \ + SKIP_POP_AFTER_SET(OP##_LENGTH, spdec); \ + { \ + Value *newsp = regs.sp - ((spdec) - 1); \ + newsp[-1] = regs.sp[-1]; \ + regs.sp = newsp; \ + } \ + END_CASE(OP) + +BEGIN_CASE(JSOP_SETCONST) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + JSObject *obj = fp->varobj(cx); + const Value &ref = regs.sp[-1]; + if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), ref, + PropertyStub, PropertyStub, + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { + goto error; + } +} +END_SET_CASE(JSOP_SETCONST); + +#if JS_HAS_DESTRUCTURING +BEGIN_CASE(JSOP_ENUMCONSTELEM) +{ + const Value &ref = regs.sp[-3]; + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + jsid id; + FETCH_ELEMENT_ID(obj, -1, id); + if (!obj->defineProperty(cx, id, ref, + PropertyStub, PropertyStub, + JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { + goto error; + } + regs.sp -= 3; +} +END_CASE(JSOP_ENUMCONSTELEM) +#endif + +BEGIN_CASE(JSOP_BINDNAME) +{ + JSObject *obj; + do { + /* + * We can skip the property lookup for the global object. If the + * property does not exist anywhere on the scope chain, JSOP_SETNAME + * adds the property to the global. + * + * As a consequence of this optimization for the global object we run + * its JSRESOLVE_ASSIGNING-tolerant resolve hooks only in JSOP_SETNAME, + * after the interpreter evaluates the right- hand-side of the + * assignment, and not here. + * + * This should be transparent to the hooks because the script, instead + * of name = rhs, could have used global.name = rhs given a global + * object reference, which also calls the hooks only after evaluating + * the rhs. We desire such resolve hook equivalence between the two + * forms. + */ + obj = fp->scopeChain; + if (!obj->getParent()) + break; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + break; + } + + jsid id = ATOM_TO_JSID(atom); + obj = js_FindIdentifierBase(cx, fp->scopeChain, id); + if (!obj) + goto error; + } while (0); + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_BINDNAME) + +BEGIN_CASE(JSOP_IMACOP) + JS_ASSERT(JS_UPTRDIFF(fp->imacpc, script->code) < script->length); + op = JSOp(*fp->imacpc); + DO_OP(); + +#define BITWISE_OP(OP) \ + JS_BEGIN_MACRO \ + int32_t i, j; \ + if (!ValueToECMAInt32(cx, regs.sp[-2], &i)) \ + goto error; \ + if (!ValueToECMAInt32(cx, regs.sp[-1], &j)) \ + goto error; \ + i = i OP j; \ + regs.sp--; \ + regs.sp[-1].setInt32(i); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_BITOR) + BITWISE_OP(|); +END_CASE(JSOP_BITOR) + +BEGIN_CASE(JSOP_BITXOR) + BITWISE_OP(^); +END_CASE(JSOP_BITXOR) + +BEGIN_CASE(JSOP_BITAND) + BITWISE_OP(&); +END_CASE(JSOP_BITAND) + +#undef BITWISE_OP + +/* + * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies + * because they begin if/else chains, so callers must not put semicolons after + * the call expressions! + */ +#if JS_HAS_XML_SUPPORT +#define XML_EQUALITY_OP(OP) \ + if ((lval.isObject() && lval.toObject().isXML()) || \ + (rval.isObject() && rval.toObject().isXML())) { \ + if (!js_TestXMLEquality(cx, lval, rval, &cond)) \ + goto error; \ + cond = cond OP JS_TRUE; \ + } else + +#define EXTENDED_EQUALITY_OP(OP) \ + if (((clasp = l->getClass())->flags & JSCLASS_IS_EXTENDED) && \ + ((ExtendedClass *)clasp)->equality) { \ + if (!((ExtendedClass *)clasp)->equality(cx, l, &rval, &cond)) \ + goto error; \ + cond = cond OP JS_TRUE; \ + } else +#else +#define XML_EQUALITY_OP(OP) /* nothing */ +#define EXTENDED_EQUALITY_OP(OP) /* nothing */ +#endif + +#define EQUALITY_OP(OP, IFNAN) \ + JS_BEGIN_MACRO \ + Class *clasp; \ + JSBool cond; \ + Value rval = regs.sp[-1]; \ + Value lval = regs.sp[-2]; \ + XML_EQUALITY_OP(OP) \ + if (SameType(lval, rval)) { \ + if (lval.isString()) { \ + JSString *l = lval.toString(), *r = rval.toString(); \ + cond = js_EqualStrings(l, r) OP JS_TRUE; \ + } else if (lval.isDouble()) { \ + double l = lval.toDouble(), r = rval.toDouble(); \ + cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \ + } else if (lval.isObject()) { \ + JSObject *l = &lval.toObject(), *r = &rval.toObject(); \ + EXTENDED_EQUALITY_OP(OP) \ + cond = l OP r; \ + } else { \ + cond = lval.payloadAsRawUint32() OP rval.payloadAsRawUint32();\ + } \ + } else { \ + if (lval.isNullOrUndefined()) { \ + cond = rval.isNullOrUndefined() OP true; \ + } else if (rval.isNullOrUndefined()) { \ + cond = true OP false; \ + } else { \ + if (lval.isObject()) \ + DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); \ + if (rval.isObject()) \ + DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \ + if (lval.isString() && rval.isString()) { \ + JSString *l = lval.toString(), *r = rval.toString(); \ + cond = js_EqualStrings(l, r) OP JS_TRUE; \ + } else { \ + double l, r; \ + if (!ValueToNumber(cx, lval, &l) || \ + !ValueToNumber(cx, rval, &r)) { \ + goto error; \ + } \ + cond = JSDOUBLE_COMPARE(l, OP, r, IFNAN); \ + } \ + } \ + } \ + TRY_BRANCH_AFTER_COND(cond, 2); \ + regs.sp--; \ + regs.sp[-1].setBoolean(cond); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_EQ) + EQUALITY_OP(==, false); +END_CASE(JSOP_EQ) + +BEGIN_CASE(JSOP_NE) + EQUALITY_OP(!=, true); +END_CASE(JSOP_NE) + +#undef EQUALITY_OP +#undef XML_EQUALITY_OP +#undef EXTENDED_EQUALITY_OP + +#define STRICT_EQUALITY_OP(OP, COND) \ + JS_BEGIN_MACRO \ + const Value &rref = regs.sp[-1]; \ + const Value &lref = regs.sp[-2]; \ + COND = StrictlyEqual(cx, lref, rref) OP true; \ + regs.sp--; \ + JS_END_MACRO + +BEGIN_CASE(JSOP_STRICTEQ) +{ + bool cond; + STRICT_EQUALITY_OP(==, cond); + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_STRICTEQ) + +BEGIN_CASE(JSOP_STRICTNE) +{ + bool cond; + STRICT_EQUALITY_OP(!=, cond); + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_STRICTNE) + +BEGIN_CASE(JSOP_CASE) +{ + bool cond; + STRICT_EQUALITY_OP(==, cond); + if (cond) { + regs.sp--; + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_CASE) + +BEGIN_CASE(JSOP_CASEX) +{ + bool cond; + STRICT_EQUALITY_OP(==, cond); + if (cond) { + regs.sp--; + len = GET_JUMPX_OFFSET(regs.pc); + BRANCH(len); + } +} +END_CASE(JSOP_CASEX) + +#undef STRICT_EQUALITY_OP + +#define RELATIONAL_OP(OP) \ + JS_BEGIN_MACRO \ + Value rval = regs.sp[-1]; \ + Value lval = regs.sp[-2]; \ + bool cond; \ + /* Optimize for two int-tagged operands (typical loop control). */ \ + if (lval.isInt32() && rval.isInt32()) { \ + cond = lval.toInt32() OP rval.toInt32(); \ + } else { \ + if (lval.isObject()) \ + DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \ + if (rval.isObject()) \ + DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \ + if (lval.isString() && rval.isString()) { \ + JSString *l = lval.toString(), *r = rval.toString(); \ + cond = js_CompareStrings(l, r) OP 0; \ + } else { \ + double l, r; \ + if (!ValueToNumber(cx, lval, &l) || \ + !ValueToNumber(cx, rval, &r)) { \ + goto error; \ + } \ + cond = JSDOUBLE_COMPARE(l, OP, r, false); \ + } \ + } \ + TRY_BRANCH_AFTER_COND(cond, 2); \ + regs.sp--; \ + regs.sp[-1].setBoolean(cond); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_LT) + RELATIONAL_OP(<); +END_CASE(JSOP_LT) + +BEGIN_CASE(JSOP_LE) + RELATIONAL_OP(<=); +END_CASE(JSOP_LE) + +BEGIN_CASE(JSOP_GT) + RELATIONAL_OP(>); +END_CASE(JSOP_GT) + +BEGIN_CASE(JSOP_GE) + RELATIONAL_OP(>=); +END_CASE(JSOP_GE) + +#undef RELATIONAL_OP + +#define SIGNED_SHIFT_OP(OP) \ + JS_BEGIN_MACRO \ + int32_t i, j; \ + if (!ValueToECMAInt32(cx, regs.sp[-2], &i)) \ + goto error; \ + if (!ValueToECMAInt32(cx, regs.sp[-1], &j)) \ + goto error; \ + i = i OP (j & 31); \ + regs.sp--; \ + regs.sp[-1].setInt32(i); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_LSH) + SIGNED_SHIFT_OP(<<); +END_CASE(JSOP_LSH) + +BEGIN_CASE(JSOP_RSH) + SIGNED_SHIFT_OP(>>); +END_CASE(JSOP_RSH) + +#undef SIGNED_SHIFT_OP + +BEGIN_CASE(JSOP_URSH) +{ + uint32_t u; + if (!ValueToECMAUint32(cx, regs.sp[-2], &u)) + goto error; + int32_t j; + if (!ValueToECMAInt32(cx, regs.sp[-1], &j)) + goto error; + + u >>= (j & 31); + + regs.sp--; + regs.sp[-1].setNumber(uint32(u)); +} +END_CASE(JSOP_URSH) + +BEGIN_CASE(JSOP_ADD) +{ + Value rval = regs.sp[-1]; + Value lval = regs.sp[-2]; + + if (lval.isInt32() && rval.isInt32()) { + int32_t l = lval.toInt32(), r = rval.toInt32(); + int32_t sum = l + r; + regs.sp--; + if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) + regs.sp[-1].setDouble(double(l) + double(r)); + else + regs.sp[-1].setInt32(sum); + } else +#if JS_HAS_XML_SUPPORT + if (IsXML(lval) && IsXML(rval)) { + if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval)) + goto error; + regs.sp--; + regs.sp[-1] = rval; + } else +#endif + { + if (lval.isObject()) + DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); + if (rval.isObject()) + DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); + bool lIsString, rIsString; + if ((lIsString = lval.isString()) | (rIsString = rval.isString())) { + JSString *lstr, *rstr; + if (lIsString) { + lstr = lval.toString(); + } else { + lstr = js_ValueToString(cx, lval); + if (!lstr) + goto error; + regs.sp[-2].setString(lstr); + } + if (rIsString) { + rstr = rval.toString(); + } else { + rstr = js_ValueToString(cx, rval); + if (!rstr) + goto error; + regs.sp[-1].setString(rstr); + } + JSString *str = js_ConcatStrings(cx, lstr, rstr); + if (!str) + goto error; + regs.sp--; + regs.sp[-1].setString(str); + } else { + double l, r; + if (!ValueToNumber(cx, lval, &l) || !ValueToNumber(cx, rval, &r)) + goto error; + l += r; + regs.sp--; + regs.sp[-1].setNumber(l); + } + } +} +END_CASE(JSOP_ADD) + +BEGIN_CASE(JSOP_OBJTOSTR) +{ + const Value &ref = regs.sp[-1]; + if (ref.isObject()) { + JSString *str = js_ValueToString(cx, ref); + if (!str) + goto error; + regs.sp[-1].setString(str); + } +} +END_CASE(JSOP_OBJTOSTR) + +BEGIN_CASE(JSOP_CONCATN) +{ + JSCharBuffer buf(cx); + uintN argc = GET_ARGC(regs.pc); + for (Value *vp = regs.sp - argc; vp < regs.sp; vp++) { + JS_ASSERT(vp->isPrimitive()); + if (!js_ValueToCharBuffer(cx, *vp, buf)) + goto error; + } + JSString *str = js_NewStringFromCharBuffer(cx, buf); + if (!str) + goto error; + regs.sp -= argc - 1; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_CONCATN) + +#define BINARY_OP(OP) \ + JS_BEGIN_MACRO \ + double d1, d2; \ + if (!ValueToNumber(cx, regs.sp[-2], &d1) || \ + !ValueToNumber(cx, regs.sp[-1], &d2)) { \ + goto error; \ + } \ + double d = d1 OP d2; \ + regs.sp--; \ + regs.sp[-1].setNumber(d); \ + JS_END_MACRO + +BEGIN_CASE(JSOP_SUB) + BINARY_OP(-); +END_CASE(JSOP_SUB) + +BEGIN_CASE(JSOP_MUL) + BINARY_OP(*); +END_CASE(JSOP_MUL) + +#undef BINARY_OP + +BEGIN_CASE(JSOP_DIV) +{ + double d1, d2; + if (!ValueToNumber(cx, regs.sp[-2], &d1) || + !ValueToNumber(cx, regs.sp[-1], &d2)) { + goto error; + } + regs.sp--; + if (d2 == 0) { + const Value *vp; +#ifdef XP_WIN + /* XXX MSVC miscompiles such that (NaN == 0) */ + if (JSDOUBLE_IS_NaN(d2)) + vp = &rt->NaNValue; + else +#endif + if (d1 == 0 || JSDOUBLE_IS_NaN(d1)) + vp = &rt->NaNValue; + else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2)) + vp = &rt->negativeInfinityValue; + else + vp = &rt->positiveInfinityValue; + regs.sp[-1] = *vp; + } else { + d1 /= d2; + regs.sp[-1].setNumber(d1); + } +} +END_CASE(JSOP_DIV) + +BEGIN_CASE(JSOP_MOD) +{ + Value &lref = regs.sp[-2]; + Value &rref = regs.sp[-1]; + int32_t l, r; + if (lref.isInt32() && rref.isInt32() && + (l = lref.toInt32()) >= 0 && (r = rref.toInt32()) > 0) { + int32_t mod = l % r; + regs.sp--; + regs.sp[-1].setInt32(mod); + } else { + double d1, d2; + if (!ValueToNumber(cx, regs.sp[-2], &d1) || + !ValueToNumber(cx, regs.sp[-1], &d2)) { + goto error; + } + regs.sp--; + if (d2 == 0) { + regs.sp[-1].setDouble(js_NaN); + } else { + d1 = js_fmod(d1, d2); + regs.sp[-1].setDouble(d1); + } + } +} +END_CASE(JSOP_MOD) + +BEGIN_CASE(JSOP_NOT) +{ + Value *_; + bool cond; + POP_BOOLEAN(cx, _, cond); + PUSH_BOOLEAN(!cond); +} +END_CASE(JSOP_NOT) + +BEGIN_CASE(JSOP_BITNOT) +{ + int32_t i; + if (!ValueToECMAInt32(cx, regs.sp[-1], &i)) + goto error; + i = ~i; + regs.sp[-1].setInt32(i); +} +END_CASE(JSOP_BITNOT) + +BEGIN_CASE(JSOP_NEG) +{ + /* + * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies + * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the + * results, -0.0 or INT32_MAX + 1, are jsdouble values. + */ + const Value &ref = regs.sp[-1]; + int32_t i; + if (ref.isInt32() && (i = ref.toInt32()) != 0 && i != INT32_MIN) { + i = -i; + regs.sp[-1].setInt32(i); + } else { + double d; + if (!ValueToNumber(cx, regs.sp[-1], &d)) + goto error; + d = -d; + regs.sp[-1].setDouble(d); + } +} +END_CASE(JSOP_NEG) + +BEGIN_CASE(JSOP_POS) + if (!ValueToNumber(cx, ®s.sp[-1])) + goto error; +END_CASE(JSOP_POS) + +BEGIN_CASE(JSOP_DELNAME) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + JSObject *obj, *obj2; + JSProperty *prop; + if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) + goto error; + + /* ECMA says to return true if name is undefined or inherited. */ + PUSH_BOOLEAN(true); + if (prop) { + obj2->dropProperty(cx, prop); + if (!obj->deleteProperty(cx, id, ®s.sp[-1])) + goto error; + } +} +END_CASE(JSOP_DELNAME) + +BEGIN_CASE(JSOP_DELPROP) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + + JSObject *obj; + FETCH_OBJECT(cx, -1, obj); + + Value rval; + if (!obj->deleteProperty(cx, id, &rval)) + goto error; + + regs.sp[-1] = rval; +} +END_CASE(JSOP_DELPROP) + +BEGIN_CASE(JSOP_DELELEM) +{ + /* Fetch the left part and resolve it to a non-null object. */ + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + + /* Fetch index and convert it to id suitable for use with obj. */ + jsid id; + FETCH_ELEMENT_ID(obj, -1, id); + + /* Get or set the element. */ + if (!obj->deleteProperty(cx, id, ®s.sp[-2])) + goto error; + + regs.sp--; +} +END_CASE(JSOP_DELELEM) + +BEGIN_CASE(JSOP_TYPEOFEXPR) +BEGIN_CASE(JSOP_TYPEOF) +{ + const Value &ref = regs.sp[-1]; + JSType type = JS_TypeOfValue(cx, Jsvalify(ref)); + JSAtom *atom = rt->atomState.typeAtoms[type]; + regs.sp[-1].setString(ATOM_TO_STRING(atom)); +} +END_CASE(JSOP_TYPEOF) + +BEGIN_CASE(JSOP_VOID) + regs.sp[-1].setUndefined(); +END_CASE(JSOP_VOID) + +{ + JSObject *obj; + JSAtom *atom; + jsid id; + jsint i; + +BEGIN_CASE(JSOP_INCELEM) +BEGIN_CASE(JSOP_DECELEM) +BEGIN_CASE(JSOP_ELEMINC) +BEGIN_CASE(JSOP_ELEMDEC) + + /* + * Delay fetching of id until we have the object to ensure the proper + * evaluation order. See bug 372331. + */ + id = JSID_VOID; + i = -2; + goto fetch_incop_obj; + +BEGIN_CASE(JSOP_INCPROP) +BEGIN_CASE(JSOP_DECPROP) +BEGIN_CASE(JSOP_PROPINC) +BEGIN_CASE(JSOP_PROPDEC) + LOAD_ATOM(0, atom); + id = ATOM_TO_JSID(atom); + i = -1; + + fetch_incop_obj: + FETCH_OBJECT(cx, i, obj); + if (JSID_IS_VOID(id)) + FETCH_ELEMENT_ID(obj, -1, id); + goto do_incop; + +BEGIN_CASE(JSOP_INCNAME) +BEGIN_CASE(JSOP_DECNAME) +BEGIN_CASE(JSOP_NAMEINC) +BEGIN_CASE(JSOP_NAMEDEC) +{ + obj = fp->scopeChain; + + JSObject *obj2; + PropertyCacheEntry *entry; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + if (obj == obj2 && entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + JS_ASSERT(slot < obj->scope()->freeslot); + Value &rref = obj->getSlotRef(slot); + int32_t tmp; + if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) { + int32_t inc = tmp + ((js_CodeSpec[op].format & JOF_INC) ? 1 : -1); + if (!(js_CodeSpec[op].format & JOF_POST)) + tmp = inc; + rref.getInt32Ref() = inc; + PUSH_INT32(tmp); + len = JSOP_INCNAME_LENGTH; + DO_NEXT_OP(len); + } + } + LOAD_ATOM(0, atom); + } + + id = ATOM_TO_JSID(atom); + JSProperty *prop; + if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) + goto error; + if (!prop) { + atomNotDefined = atom; + goto atom_not_defined; + } + obj2->dropProperty(cx, prop); +} + +do_incop: +{ + /* + * We need a root to store the value to leave on the stack until + * we have done with obj->setProperty. + */ + PUSH_NULL(); + if (!obj->getProperty(cx, id, ®s.sp[-1])) + goto error; + + const JSCodeSpec *cs = &js_CodeSpec[op]; + JS_ASSERT(cs->ndefs == 1); + JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) == JOF_TMPSLOT2); + Value &ref = regs.sp[-1]; + int32_t tmp; + if (JS_LIKELY(ref.isInt32() && CanIncDecWithoutOverflow(tmp = ref.toInt32()))) { + int incr = (cs->format & JOF_INC) ? 1 : -1; + if (cs->format & JOF_POST) + ref.getInt32Ref() = tmp + incr; + else + ref.getInt32Ref() = tmp += incr; + fp->flags |= JSFRAME_ASSIGNING; + JSBool ok = obj->setProperty(cx, id, &ref); + fp->flags &= ~JSFRAME_ASSIGNING; + if (!ok) + goto error; + + /* + * We must set regs.sp[-1] to tmp for both post and pre increments + * as the setter overwrites regs.sp[-1]. + */ + ref.setInt32(tmp); + } else { + /* We need an extra root for the result. */ + PUSH_NULL(); + if (!js_DoIncDec(cx, cs, ®s.sp[-2], ®s.sp[-1])) + goto error; + fp->flags |= JSFRAME_ASSIGNING; + JSBool ok = obj->setProperty(cx, id, ®s.sp[-1]); + fp->flags &= ~JSFRAME_ASSIGNING; + if (!ok) + goto error; + regs.sp--; + } + + if (cs->nuses == 0) { + /* regs.sp[-1] already contains the result of name increment. */ + } else { + regs.sp[-1 - cs->nuses] = regs.sp[-1]; + regs.sp -= cs->nuses; + } + len = cs->length; + DO_NEXT_OP(len); +} +} + +{ + int incr, incr2; + Value *vp; + + /* Position cases so the most frequent i++ does not need a jump. */ +BEGIN_CASE(JSOP_DECARG) + incr = -1; incr2 = -1; goto do_arg_incop; +BEGIN_CASE(JSOP_ARGDEC) + incr = -1; incr2 = 0; goto do_arg_incop; +BEGIN_CASE(JSOP_INCARG) + incr = 1; incr2 = 1; goto do_arg_incop; +BEGIN_CASE(JSOP_ARGINC) + incr = 1; incr2 = 0; + + do_arg_incop: + // If we initialize in the declaration, MSVC complains that the labels skip init. + uint32 slot; + slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + METER_SLOT_OP(op, slot); + vp = fp->argv + slot; + goto do_int_fast_incop; + +BEGIN_CASE(JSOP_DECLOCAL) + incr = -1; incr2 = -1; goto do_local_incop; +BEGIN_CASE(JSOP_LOCALDEC) + incr = -1; incr2 = 0; goto do_local_incop; +BEGIN_CASE(JSOP_INCLOCAL) + incr = 1; incr2 = 1; goto do_local_incop; +BEGIN_CASE(JSOP_LOCALINC) + incr = 1; incr2 = 0; + + /* + * do_local_incop comes right before do_int_fast_incop as we want to + * avoid an extra jump for variable cases as local++ is more frequent + * than arg++. + */ + do_local_incop: + slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < fp->script->nslots); + vp = fp->slots() + slot; + METER_SLOT_OP(op, slot); + vp = fp->slots() + slot; + + do_int_fast_incop: + int32_t tmp; + if (JS_LIKELY(vp->isInt32() && CanIncDecWithoutOverflow(tmp = vp->toInt32()))) { + vp->getInt32Ref() = tmp + incr; + JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length); + SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0); + PUSH_INT32(tmp + incr2); + } else { + PUSH_COPY(*vp); + if (!js_DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-1], vp)) + goto error; + } + len = JSOP_INCARG_LENGTH; + JS_ASSERT(len == js_CodeSpec[op].length); + DO_NEXT_OP(len); +} + +/* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */ +#define FAST_GLOBAL_INCREMENT_OP(SLOWOP,INCR,INCR2) \ + op2 = SLOWOP; \ + incr = INCR; \ + incr2 = INCR2; \ + goto do_global_incop + +{ + JSOp op2; + int incr, incr2; + +BEGIN_CASE(JSOP_DECGVAR) + FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, -1, -1); +BEGIN_CASE(JSOP_GVARDEC) + FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, -1, 0); +BEGIN_CASE(JSOP_INCGVAR) + FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME, 1, 1); +BEGIN_CASE(JSOP_GVARINC) + FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC, 1, 0); + +#undef FAST_GLOBAL_INCREMENT_OP + + do_global_incop: + JS_ASSERT((js_CodeSpec[op].format & JOF_TMPSLOT_MASK) == + JOF_TMPSLOT2); + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < GlobalVarCount(fp)); + METER_SLOT_OP(op, slot); + const Value &lref = fp->slots()[slot]; + if (lref.isNull()) { + op = op2; + DO_OP(); + } + slot = (uint32)lref.toInt32(); + JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); + JSObject *varobj = cx->activeCallStack()->getInitialVarObj(); + + /* XXX all this code assumes that varobj is either a callobj or global and + * that it cannot be accessed in a MT way. This is either true now or + * coming soon. */ + + Value &rref = varobj->getSlotRef(slot); + int32_t tmp; + if (JS_LIKELY(rref.isInt32() && CanIncDecWithoutOverflow(tmp = rref.toInt32()))) { + PUSH_INT32(tmp + incr2); + rref.getInt32Ref() = tmp + incr; + } else { + PUSH_COPY(rref); + if (!js_DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-1], &rref)) + goto error; + } + len = JSOP_INCGVAR_LENGTH; /* all gvar incops are same length */ + JS_ASSERT(len == js_CodeSpec[op].length); + DO_NEXT_OP(len); +} + +BEGIN_CASE(JSOP_THIS) + if (!fp->getThisObject(cx)) + goto error; + PUSH_COPY(fp->thisv); +END_CASE(JSOP_THIS) + +BEGIN_CASE(JSOP_UNBRANDTHIS) +{ + JSObject *obj = fp->getThisObject(cx); + if (!obj) + goto error; + if (!obj->unbrand(cx)) + goto error; +} +END_CASE(JSOP_UNBRANDTHIS) + +{ + JSObject *obj; + Value *vp; + jsint i; + +BEGIN_CASE(JSOP_GETTHISPROP) + obj = fp->getThisObject(cx); + if (!obj) + goto error; + i = 0; + PUSH_NULL(); + goto do_getprop_with_obj; + +BEGIN_CASE(JSOP_GETARGPROP) +{ + i = ARGNO_LEN; + uint32 slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + PUSH_COPY(fp->argv[slot]); + goto do_getprop_body; +} + +BEGIN_CASE(JSOP_GETLOCALPROP) +{ + i = SLOTNO_LEN; + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_COPY(fp->slots()[slot]); + goto do_getprop_body; +} + +BEGIN_CASE(JSOP_GETPROP) +BEGIN_CASE(JSOP_GETXPROP) + i = 0; + + do_getprop_body: + vp = ®s.sp[-1]; + + do_getprop_with_lval: + VALUE_TO_OBJECT(cx, vp, obj); + + do_getprop_with_obj: + { + Value rval; + do { + /* + * We do not impose the method read barrier if in an imacro, + * assuming any property gets it does (e.g., for 'toString' + * from JSOP_NEW) will not be leaked to the calling script. + */ + JSObject *aobj = js_GetProtoIfDenseArray(obj); + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry); + if (entry->vword.isFunObj()) { + rval.setObject(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + JS_ASSERT(slot < obj2->scope()->freeslot); + rval = obj2->lockedGetSlot(slot); + } else { + JS_ASSERT(entry->vword.isSprop()); + JSScopeProperty *sprop = entry->vword.toSprop(); + NATIVE_GET(cx, obj, obj2, sprop, + fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER, + &rval); + } + break; + } + + jsid id = ATOM_TO_JSID(atom); + if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty) + ? !js_GetPropertyHelper(cx, obj, id, + fp->imacpc + ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER + : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER, + &rval) + : !obj->getProperty(cx, id, &rval)) { + goto error; + } + } while (0); + + regs.sp[-1] = rval; + JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length); + len = JSOP_GETPROP_LENGTH + i; + } +END_VARLEN_CASE + +BEGIN_CASE(JSOP_LENGTH) + vp = ®s.sp[-1]; + if (vp->isString()) { + vp->setInt32(vp->toString()->length()); + } else if (vp->isObject()) { + JSObject *obj = &vp->toObject(); + if (obj->isArray()) { + jsuint length = obj->getArrayLength(); + regs.sp[-1].setNumber(length); + } else if (obj->isArguments() && !obj->isArgsLengthOverridden()) { + uint32 length = obj->getArgsLength(); + JS_ASSERT(length < INT32_MAX); + regs.sp[-1].setInt32(int32_t(length)); + } else { + i = -2; + goto do_getprop_with_lval; + } + } else { + i = -2; + goto do_getprop_with_lval; + } +END_CASE(JSOP_LENGTH) + +} + +BEGIN_CASE(JSOP_CALLPROP) +{ + Value lval = regs.sp[-1]; + + Value objv; + if (lval.isObject()) { + objv = lval; + } else { + JSProtoKey protoKey; + if (lval.isString()) { + protoKey = JSProto_String; + } else if (lval.isNumber()) { + protoKey = JSProto_Number; + } else if (lval.isBoolean()) { + protoKey = JSProto_Boolean; + } else { + JS_ASSERT(lval.isNull() || lval.isUndefined()); + js_ReportIsNullOrUndefined(cx, -1, lval, NULL); + goto error; + } + JSObject *pobj; + if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj)) + goto error; + objv.setObject(*pobj); + } + + JSObject *aobj = js_GetProtoIfDenseArray(&objv.toObject()); + Value rval; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry); + if (entry->vword.isFunObj()) { + rval.setObject(entry->vword.toFunObj()); + } else if (entry->vword.isSlot()) { + uint32 slot = entry->vword.toSlot(); + JS_ASSERT(slot < obj2->scope()->freeslot); + rval = obj2->lockedGetSlot(slot); + } else { + JS_ASSERT(entry->vword.isSprop()); + JSScopeProperty *sprop = entry->vword.toSprop(); + NATIVE_GET(cx, &objv.toObject(), obj2, sprop, JSGET_NO_METHOD_BARRIER, &rval); + } + regs.sp[-1] = rval; + PUSH_COPY(lval); + goto end_callprop; + } + + /* + * Cache miss: use the immediate atom that was loaded for us under + * PropertyCache::test. + */ + jsid id; + id = ATOM_TO_JSID(atom); + + PUSH_NULL(); + if (lval.isObject()) { + if (!js_GetMethod(cx, &objv.toObject(), id, + JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty) + ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER + : JSGET_NO_METHOD_BARRIER, + &rval)) { + goto error; + } + regs.sp[-1] = objv; + regs.sp[-2] = rval; + } else { + JS_ASSERT(objv.toObject().map->ops->getProperty == js_GetProperty); + if (!js_GetPropertyHelper(cx, &objv.toObject(), id, + JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER, + &rval)) { + goto error; + } + regs.sp[-1] = lval; + regs.sp[-2] = rval; + } + + end_callprop: + /* Wrap primitive lval in object clothing if necessary. */ + if (lval.isPrimitive()) { + /* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */ + JSObject *funobj; + if (!IsFunctionObject(rval, &funobj) || + !PrimitiveThisTest(GET_FUNCTION_PRIVATE(cx, funobj), lval)) { + if (!js_PrimitiveToObject(cx, ®s.sp[-1])) + goto error; + } + } +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(rval.isUndefined())) { + LOAD_ATOM(0, atom); + regs.sp[-2].setString(ATOM_TO_STRING(atom)); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + goto error; + } +#endif +} +END_CASE(JSOP_CALLPROP) + +BEGIN_CASE(JSOP_UNBRAND) + JS_ASSERT(regs.sp - fp->slots() >= 1); + if (!regs.sp[-1].toObject().unbrand(cx)) + goto error; +END_CASE(JSOP_UNBRAND) + +BEGIN_CASE(JSOP_SETNAME) +BEGIN_CASE(JSOP_SETPROP) +BEGIN_CASE(JSOP_SETMETHOD) +{ + Value &rref = regs.sp[-1]; + JS_ASSERT_IF(op == JSOP_SETMETHOD, IsFunctionObject(rref)); + Value &lref = regs.sp[-2]; + JS_ASSERT_IF(op == JSOP_SETNAME, lref.isObject()); + JSObject *obj; + VALUE_TO_OBJECT(cx, &lref, obj); + + do { + PropertyCache *cache = &JS_PROPERTY_CACHE(cx); + + /* + * Probe the property cache, specializing for two important + * set-property cases. First: + * + * function f(a, b, c) { + * var o = {p:a, q:b, r:c}; + * return o; + * } + * + * or similar real-world cases, which evolve a newborn native + * object predicatably through some bounded number of property + * additions. And second: + * + * o.p = x; + * + * in a frequently executed method or loop body, where p will + * (possibly after the first iteration) always exist in native + * object o. + */ + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + if (cache->testForSet(cx, regs.pc, obj, &entry, &obj2, &atom)) { + /* + * Fast property cache hit, only partially confirmed by + * testForSet. We know that the entry applies to regs.pc and + * that obj's shape matches. + * + * The entry predicts either a new property to be added + * directly to obj by this set, or on an existing "own" + * property, or on a prototype property that has a setter. + */ + JS_ASSERT(entry->vword.isSprop()); + JSScopeProperty *sprop = entry->vword.toSprop(); + JS_ASSERT_IF(sprop->isDataDescriptor(), sprop->writable()); + JS_ASSERT_IF(sprop->hasSlot(), entry->vcapTag() == 0); + + JSScope *scope = obj->scope(); + JS_ASSERT(!scope->sealed()); + + /* + * Fastest path: check whether the cached sprop is already + * in scope and call NATIVE_SET and break to get out of the + * do-while(0). But we can call NATIVE_SET only if obj owns + * scope or sprop is shared. + */ + bool checkForAdd; + if (!sprop->hasSlot()) { + if (entry->vcapTag() == 0 || + ((obj2 = obj->getProto()) && + obj2->isNative() && + obj2->shape() == entry->vshape())) { + goto fast_set_propcache_hit; + } + + /* The cache entry doesn't apply. vshape mismatch. */ + checkForAdd = false; + } else if (!scope->isSharedEmpty()) { + if (sprop == scope->lastProperty() || scope->hasProperty(sprop)) { + fast_set_propcache_hit: + PCMETER(cache->pchits++); + PCMETER(cache->setpchits++); + NATIVE_SET(cx, obj, sprop, entry, &rref); + break; + } + checkForAdd = sprop->hasSlot() && sprop->parent == scope->lastProperty(); + } else { + /* + * We check that cx own obj here and will continue to + * own it after js_GetMutableScope returns so we can + * continue to skip JS_UNLOCK_OBJ calls. + */ + JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); + scope = js_GetMutableScope(cx, obj); + JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); + if (!scope) + goto error; + checkForAdd = !sprop->parent; + } + + uint32 slot; + if (checkForAdd && + entry->vshape() == rt->protoHazardShape && + sprop->hasDefaultSetter() && + (slot = sprop->slot) == scope->freeslot) { + /* + * Fast path: adding a plain old property that was once + * at the frontier of the property tree, whose slot is + * next to claim among the allocated slots in obj, + * where scope->table has not been created yet. + * + * We may want to remove hazard conditions above and + * inline compensation code here, depending on + * real-world workloads. + */ + PCMETER(cache->pchits++); + PCMETER(cache->addpchits++); + + if (slot < obj->numSlots()) { + ++scope->freeslot; + } else { + if (!js_AllocSlot(cx, obj, &slot)) + goto error; + JS_ASSERT(slot + 1 == scope->freeslot); + } + + /* + * If this obj's number of reserved slots differed, or + * if something created a hash table for scope, we must + * pay the price of JSScope::putProperty. + * + * (A built-in object with a pre-allocated but not fixed + * population of reserved slots hook can cause scopes of the + * same shape to have different freeslot values. Arguments, + * Block, Call, and certain Function objects pre-allocate + * reserveds lots this way. This is what causes the slot != + * sprop->slot case. See js_GetMutableScope. FIXME 558451) + */ + if (slot == sprop->slot && !scope->table) { + scope->extend(cx, sprop); + } else { + JSScopeProperty *sprop2 = + scope->putProperty(cx, sprop->id, + sprop->getter(), sprop->setter(), + slot, sprop->attributes(), + sprop->getFlags(), sprop->shortid); + if (!sprop2) { + js_FreeSlot(cx, obj, slot); + goto error; + } + sprop = sprop2; + } + + /* + * No method change check here because here we are + * adding a new property, not updating an existing + * slot's value that might contain a method of a + * branded scope. + */ + TRACE_2(SetPropHit, entry, sprop); + obj->lockedSetSlot(slot, rref); + + /* + * Purge the property cache of the id we may have just + * shadowed in obj's scope and proto chains. We do this + * after unlocking obj's scope to avoid lock nesting. + */ + js_PurgeScopeChain(cx, obj, sprop->id); + break; + } + PCMETER(cache->setpcmisses++); + atom = NULL; + } else if (!atom) { + /* + * Slower property cache hit, fully confirmed by testForSet (in + * the slow path, via fullTest). + */ + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + JSScopeProperty *sprop = NULL; + if (obj == obj2) { + sprop = entry->vword.toSprop(); + JS_ASSERT(sprop->writable()); + JS_ASSERT(!obj2->scope()->sealed()); + NATIVE_SET(cx, obj, sprop, entry, &rref); + } + if (sprop) + break; + } + + if (!atom) + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + if (entry && JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) { + uintN defineHow; + if (op == JSOP_SETMETHOD) + defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD; + else if (op == JSOP_SETNAME) + defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED; + else + defineHow = JSDNP_CACHE_RESULT; + if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rref)) + goto error; + } else { + if (!obj->setProperty(cx, id, &rref)) + goto error; + ABORT_RECORDING(cx, "Non-native set"); + } + } while (0); +} +END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2); + +BEGIN_CASE(JSOP_GETELEM) +{ + Value &lref = regs.sp[-2]; + Value &rref = regs.sp[-1]; + if (lref.isString() && rref.isInt32()) { + JSString *str = lref.toString(); + int32_t i = rref.toInt32(); + if (size_t(i) < str->length()) { + str = JSString::getUnitString(cx, str, size_t(i)); + if (!str) + goto error; + regs.sp--; + regs.sp[-1].setString(str); + len = JSOP_GETELEM_LENGTH; + DO_NEXT_OP(len); + } + } + + JSObject *obj; + VALUE_TO_OBJECT(cx, &lref, obj); + + const Value *copyFrom; + Value rval; + jsid id; + if (rref.isInt32()) { + int32_t i = rref.toInt32(); + if (obj->isDenseArray()) { + jsuint idx = jsuint(i); + + if (idx < obj->getArrayLength() && + idx < obj->getDenseArrayCapacity()) { + copyFrom = obj->addressOfDenseArrayElement(idx); + if (!copyFrom->isMagic()) + goto end_getelem; + + /* Reload retval from the stack in the rare hole case. */ + copyFrom = ®s.sp[-1]; + } + } else if (obj->isArguments() +#ifdef JS_TRACER + && !GetArgsPrivateNative(obj) +#endif + ) { + uint32 arg = uint32(i); + + if (arg < obj->getArgsLength()) { + JSStackFrame *afp = (JSStackFrame *) obj->getPrivate(); + if (afp) { + copyFrom = &afp->argv[arg]; + goto end_getelem; + } + + copyFrom = obj->addressOfArgsElement(arg); + if (!copyFrom->isMagic()) + goto end_getelem; + copyFrom = ®s.sp[-1]; + } + } + if (JS_LIKELY(INT_FITS_IN_JSID(i))) + id = INT_TO_JSID(i); + else + goto intern_big_int; + } else { + intern_big_int: + if (!js_InternNonIntElementId(cx, obj, rref, &id)) + goto error; + } + + if (!obj->getProperty(cx, id, &rval)) + goto error; + copyFrom = &rval; + + end_getelem: + regs.sp--; + regs.sp[-1] = *copyFrom; +} +END_CASE(JSOP_GETELEM) + +BEGIN_CASE(JSOP_CALLELEM) +{ + /* Fetch the left part and resolve it to a non-null object. */ + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + + /* Fetch index and convert it to id suitable for use with obj. */ + jsid id; + FETCH_ELEMENT_ID(obj, -1, id); + + /* Get or set the element. */ + if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, ®s.sp[-2])) + goto error; + +#if JS_HAS_NO_SUCH_METHOD + if (JS_UNLIKELY(regs.sp[-2].isUndefined())) { + regs.sp[-2] = regs.sp[-1]; + regs.sp[-1].setObject(*obj); + if (!js_OnUnknownMethod(cx, regs.sp - 2)) + goto error; + } else +#endif + { + regs.sp[-1].setObject(*obj); + } +} +END_CASE(JSOP_CALLELEM) + +BEGIN_CASE(JSOP_SETELEM) +{ + JSObject *obj; + FETCH_OBJECT(cx, -3, obj); + jsid id; + FETCH_ELEMENT_ID(obj, -2, id); + do { + if (obj->isDenseArray() && JSID_IS_INT(id)) { + jsuint length = obj->getDenseArrayCapacity(); + jsint i = JSID_TO_INT(id); + if ((jsuint)i < length) { + if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) { + if (js_PrototypeHasIndexedProperties(cx, obj)) + break; + if ((jsuint)i >= obj->getArrayLength()) + obj->setDenseArrayLength(i + 1); + obj->incDenseArrayCountBy(1); + } + obj->setDenseArrayElement(i, regs.sp[-1]); + goto end_setelem; + } + } + } while (0); + if (!obj->setProperty(cx, id, ®s.sp[-1])) + goto error; + end_setelem:; +} +END_SET_CASE_STORE_RVAL(JSOP_SETELEM, 3) + +BEGIN_CASE(JSOP_ENUMELEM) +{ + /* Funky: the value to set is under the [obj, id] pair. */ + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + jsid id; + FETCH_ELEMENT_ID(obj, -1, id); + if (!obj->setProperty(cx, id, ®s.sp[-3])) + goto error; + regs.sp -= 3; +} +END_CASE(JSOP_ENUMELEM) + +{ + JSFunction *fun; + JSObject *obj; + uintN flags; + uintN argc; + Value *vp; + +BEGIN_CASE(JSOP_NEW) +{ + /* Get immediate argc and find the constructor function. */ + argc = GET_ARGC(regs.pc); + vp = regs.sp - (2 + argc); + JS_ASSERT(vp >= fp->base()); + + /* + * Assign lval, obj, and fun exactly as the code at inline_call: expects to + * find them, to avoid nesting a js_Interpret call via js_InvokeConstructor. + */ + if (IsFunctionObject(vp[0], &obj)) { + fun = GET_FUNCTION_PRIVATE(cx, obj); + if (fun->isInterpreted()) { + /* Root as we go using vp[1]. */ + if (!obj->getProperty(cx, + ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), + &vp[1])) { + goto error; + } + JSObject *proto = vp[1].isObject() ? &vp[1].toObject() : NULL; + JSObject *obj2 = NewObject(cx, &js_ObjectClass, proto, obj->getParent()); + if (!obj2) + goto error; + + if (fun->u.i.script->isEmpty()) { + vp[0].setObject(*obj2); + regs.sp = vp + 1; + goto end_new; + } + + vp[1].setObject(*obj2); + flags = JSFRAME_CONSTRUCTING; + goto inline_call; + } + } + + if (!InvokeConstructor(cx, InvokeArgsGuard(vp, argc))) + goto error; + regs.sp = vp + 1; + CHECK_INTERRUPT_HANDLER(); + TRACE_0(NativeCallComplete); + + end_new:; +} +END_CASE(JSOP_NEW) + +BEGIN_CASE(JSOP_CALL) +BEGIN_CASE(JSOP_EVAL) +BEGIN_CASE(JSOP_APPLY) +{ + argc = GET_ARGC(regs.pc); + vp = regs.sp - (argc + 2); + + if (IsFunctionObject(*vp, &obj)) { + fun = GET_FUNCTION_PRIVATE(cx, obj); + + /* Clear frame flags since this is not a constructor call. */ + flags = 0; + if (FUN_INTERPRETED(fun)) + inline_call: + { + JSScript *newscript = fun->u.i.script; + if (JS_UNLIKELY(newscript->isEmpty())) { + vp->setUndefined(); + regs.sp = vp + 1; + goto end_call; + } + + /* Restrict recursion of lightweight functions. */ + if (JS_UNLIKELY(inlineCallCount >= JS_MAX_INLINE_CALL_COUNT)) { + js_ReportOverRecursed(cx); + goto error; + } + + /* + * Get pointer to new frame/slots, without changing global state. + * Initialize missing args if there are any. + */ + StackSpace &stack = cx->stack(); + uintN nfixed = newscript->nslots; + uintN funargs = fun->nargs; + JSStackFrame *newfp; + if (argc < funargs) { + uintN missing = funargs - argc; + newfp = stack.getInlineFrame(cx, regs.sp, missing, nfixed); + if (!newfp) + goto error; + SetValueRangeToUndefined(regs.sp, missing); + } else { + newfp = stack.getInlineFrame(cx, regs.sp, 0, nfixed); + if (!newfp) + goto error; + } + + /* Initialize stack frame. */ + newfp->callobj = NULL; + newfp->argsobj = NULL; + newfp->script = newscript; + newfp->fun = fun; + newfp->argc = argc; + newfp->argv = vp + 2; + newfp->rval.setUndefined(); + newfp->annotation = NULL; + newfp->scopeChain = obj->getParent(); + newfp->flags = flags; + newfp->blockChain = NULL; + if (JS_LIKELY(newscript->staticLevel < JS_DISPLAY_SIZE)) { + JSStackFrame **disp = &cx->display[newscript->staticLevel]; + newfp->displaySave = *disp; + *disp = newfp; + } + JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags)); + newfp->thisv = vp[1]; + newfp->imacpc = NULL; + + /* Push void to initialize local variables. */ + Value *newsp = newfp->base(); + SetValueRangeToUndefined(newfp->slots(), newsp); + + /* Switch version if currentVersion wasn't overridden. */ + newfp->callerVersion = (JSVersion) cx->version; + if (JS_LIKELY(cx->version == currentVersion)) { + currentVersion = (JSVersion) newscript->version; + if (JS_UNLIKELY(currentVersion != cx->version)) + js_SetVersion(cx, currentVersion); + } + + /* Push the frame. */ + stack.pushInlineFrame(cx, fp, regs.pc, newfp); + + /* Initializer regs after pushInlineFrame snapshots pc. */ + regs.pc = newscript->code; + regs.sp = newsp; + + /* Import into locals. */ + JS_ASSERT(newfp == cx->fp); + fp = newfp; + script = newscript; + atoms = script->atomMap.vector; + + /* Now that the new frame is rooted, maybe create a call object. */ + if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) + goto error; + + /* Call the debugger hook if present. */ + if (JSInterpreterHook hook = cx->debugHooks->callHook) { + fp->hookData = hook(cx, fp, JS_TRUE, 0, + cx->debugHooks->callHookData); + CHECK_INTERRUPT_HANDLER(); + } else { + fp->hookData = NULL; + } + + inlineCallCount++; + JS_RUNTIME_METER(rt, inlineCalls); + + DTrace::enterJSFun(cx, fp, fun, fp->down, fp->argc, fp->argv); + +#ifdef JS_TRACER + if (TraceRecorder *tr = TRACE_RECORDER(cx)) { + AbortableRecordingStatus status = tr->record_EnterFrame(inlineCallCount); + RESTORE_INTERP_VARS(); + if (StatusAbortsRecorderIfActive(status)) { + if (TRACE_RECORDER(cx)) { + JS_ASSERT(TRACE_RECORDER(cx) == tr); + AbortRecording(cx, "record_EnterFrame failed"); + } + if (status == ARECORD_ERROR) + goto error; + } + } else if (fp->script == fp->down->script && + *fp->down->savedPC == JSOP_CALL && + *regs.pc == JSOP_TRACE) { + MONITOR_BRANCH(Record_EnterFrame); + } +#endif + + /* Load first op and dispatch it (safe since JSOP_STOP). */ + op = (JSOp) *regs.pc; + DO_OP(); + } + + if (fun->flags & JSFUN_FAST_NATIVE) { + DTrace::enterJSFun(cx, NULL, fun, fp, argc, vp + 2, vp); + + JS_ASSERT(fun->u.n.extra == 0); + JS_ASSERT(vp[1].isObjectOrNull() || PrimitiveThisTest(fun, vp[1])); + JSBool ok = ((FastNative) fun->u.n.native)(cx, argc, vp); + DTrace::exitJSFun(cx, NULL, fun, *vp, vp); + regs.sp = vp + 1; + if (!ok) + goto error; + TRACE_0(NativeCallComplete); + goto end_call; + } + } + + bool ok; + ok = Invoke(cx, InvokeArgsGuard(vp, argc), 0); + regs.sp = vp + 1; + CHECK_INTERRUPT_HANDLER(); + if (!ok) + goto error; + JS_RUNTIME_METER(rt, nonInlineCalls); + TRACE_0(NativeCallComplete); + + end_call:; +} +END_CASE(JSOP_CALL) +} + +BEGIN_CASE(JSOP_SETCALL) +{ + uintN argc = GET_ARGC(regs.pc); + Value *vp = regs.sp - argc - 2; + JSBool ok = Invoke(cx, InvokeArgsGuard(vp, argc), 0); + if (ok) + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS); + goto error; +} +END_CASE(JSOP_SETCALL) + +BEGIN_CASE(JSOP_NAME) +BEGIN_CASE(JSOP_CALLNAME) +{ + JSObject *obj = fp->scopeChain; + + JSScopeProperty *sprop; + Value rval; + + PropertyCacheEntry *entry; + JSObject *obj2; + JSAtom *atom; + JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); + if (!atom) { + ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); + if (entry->vword.isFunObj()) { + PUSH_OBJECT(entry->vword.toFunObj()); + goto do_push_obj_if_call; + } + + if (entry->vword.isSlot()) { + uintN slot = entry->vword.toSlot(); + JS_ASSERT(slot < obj2->scope()->freeslot); + PUSH_COPY(obj2->lockedGetSlot(slot)); + goto do_push_obj_if_call; + } + + JS_ASSERT(entry->vword.isSprop()); + sprop = entry->vword.toSprop(); + goto do_native_get; + } + + jsid id; + id = ATOM_TO_JSID(atom); + JSProperty *prop; + if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) + goto error; + if (!prop) { + /* Kludge to allow (typeof foo == "undefined") tests. */ + JSOp op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH); + if (op2 == JSOP_TYPEOF) { + PUSH_UNDEFINED(); + len = JSOP_NAME_LENGTH; + DO_NEXT_OP(len); + } + atomNotDefined = atom; + goto atom_not_defined; + } + + /* Take the slow path if prop was not found in a native object. */ + if (!obj->isNative() || !obj2->isNative()) { + obj2->dropProperty(cx, prop); + if (!obj->getProperty(cx, id, &rval)) + goto error; + } else { + sprop = (JSScopeProperty *)prop; + do_native_get: + NATIVE_GET(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, &rval); + JS_UNLOCK_OBJ(cx, obj2); + } + + PUSH_COPY(rval); + + do_push_obj_if_call: + /* obj must be on the scope chain, thus not a function. */ + if (op == JSOP_CALLNAME) + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_NAME) + +BEGIN_CASE(JSOP_UINT16) + PUSH_INT32((int32_t) GET_UINT16(regs.pc)); +END_CASE(JSOP_UINT16) + +BEGIN_CASE(JSOP_UINT24) + PUSH_INT32((int32_t) GET_UINT24(regs.pc)); +END_CASE(JSOP_UINT24) + +BEGIN_CASE(JSOP_INT8) + PUSH_INT32(GET_INT8(regs.pc)); +END_CASE(JSOP_INT8) + +BEGIN_CASE(JSOP_INT32) + PUSH_INT32(GET_INT32(regs.pc)); +END_CASE(JSOP_INT32) + +BEGIN_CASE(JSOP_INDEXBASE) + /* + * Here atoms can exceed script->atomMap.length as we use atoms as a + * segment register for object literals as well. + */ + atoms += GET_INDEXBASE(regs.pc); +END_CASE(JSOP_INDEXBASE) + +BEGIN_CASE(JSOP_INDEXBASE1) +BEGIN_CASE(JSOP_INDEXBASE2) +BEGIN_CASE(JSOP_INDEXBASE3) + atoms += (op - JSOP_INDEXBASE1 + 1) << 16; +END_CASE(JSOP_INDEXBASE3) + +BEGIN_CASE(JSOP_RESETBASE0) +BEGIN_CASE(JSOP_RESETBASE) + atoms = script->atomMap.vector; +END_CASE(JSOP_RESETBASE) + +BEGIN_CASE(JSOP_DOUBLE) +{ + JS_ASSERT(!fp->imacpc); + JS_ASSERT(size_t(atoms - script->atomMap.vector) <= script->atomMap.length); + double dbl; + LOAD_DOUBLE(0, dbl); + PUSH_DOUBLE(dbl); +} +END_CASE(JSOP_DOUBLE) + +BEGIN_CASE(JSOP_STRING) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + PUSH_STRING(ATOM_TO_STRING(atom)); +} +END_CASE(JSOP_STRING) + +BEGIN_CASE(JSOP_OBJECT) +{ + JSObject *obj; + LOAD_OBJECT(0, obj); + /* Only XML and RegExp objects are emitted. */ + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_OBJECT) + +BEGIN_CASE(JSOP_REGEXP) +{ + /* + * Push a regexp object cloned from the regexp literal object mapped by the + * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was + * flouted by many browser-based implementations. + * + * We avoid the js_GetScopeChain call here and pass fp->scopeChain as + * js_GetClassPrototype uses the latter only to locate the global. + */ + jsatomid index = GET_FULL_INDEX(0); + JSObject *proto; + if (!js_GetClassPrototype(cx, fp->scopeChain, JSProto_RegExp, &proto)) + goto error; + JS_ASSERT(proto); + JSObject *obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto); + if (!obj) + goto error; + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_REGEXP) + +BEGIN_CASE(JSOP_ZERO) + PUSH_INT32(0); +END_CASE(JSOP_ZERO) + +BEGIN_CASE(JSOP_ONE) + PUSH_INT32(1); +END_CASE(JSOP_ONE) + +BEGIN_CASE(JSOP_NULL) + PUSH_NULL(); +END_CASE(JSOP_NULL) + +BEGIN_CASE(JSOP_FALSE) + PUSH_BOOLEAN(false); +END_CASE(JSOP_FALSE) + +BEGIN_CASE(JSOP_TRUE) + PUSH_BOOLEAN(true); +END_CASE(JSOP_TRUE) + +{ +BEGIN_CASE(JSOP_TABLESWITCH) +{ + jsbytecode *pc2 = regs.pc; + len = GET_JUMP_OFFSET(pc2); + + /* + * ECMAv2+ forbids conversion of discriminant, so we will skip to the + * default case if the discriminant isn't already an int jsval. (This + * opcode is emitted only for dense jsint-domain switches.) + */ + const Value &rref = *--regs.sp; + int32_t i; + if (rref.isInt32()) { + i = rref.toInt32(); + } else if (rref.isDouble() && rref.toDouble() == 0) { + /* Treat -0 (double) as 0. */ + i = 0; + } else { + DO_NEXT_OP(len); + } + + pc2 += JUMP_OFFSET_LEN; + jsint low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + jsint high = GET_JUMP_OFFSET(pc2); + + i -= low; + if ((jsuint)i < (jsuint)(high - low + 1)) { + pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i; + jsint off = (jsint) GET_JUMP_OFFSET(pc2); + if (off) + len = off; + } +} +END_VARLEN_CASE +} + +{ +BEGIN_CASE(JSOP_TABLESWITCHX) +{ + jsbytecode *pc2 = regs.pc; + len = GET_JUMPX_OFFSET(pc2); + + /* + * ECMAv2+ forbids conversion of discriminant, so we will skip to the + * default case if the discriminant isn't already an int jsval. (This + * opcode is emitted only for dense jsint-domain switches.) + */ + const Value &rref = *--regs.sp; + int32_t i; + if (rref.isInt32()) { + i = rref.toInt32(); + } else if (rref.isDouble() && rref.toDouble() == 0) { + /* Treat -0 (double) as 0. */ + i = 0; + } else { + DO_NEXT_OP(len); + } + + pc2 += JUMPX_OFFSET_LEN; + jsint low = GET_JUMP_OFFSET(pc2); + pc2 += JUMP_OFFSET_LEN; + jsint high = GET_JUMP_OFFSET(pc2); + + i -= low; + if ((jsuint)i < (jsuint)(high - low + 1)) { + pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i; + jsint off = (jsint) GET_JUMPX_OFFSET(pc2); + if (off) + len = off; + } +} +END_VARLEN_CASE +} + +{ +BEGIN_CASE(JSOP_LOOKUPSWITCHX) +{ + jsint off; + off = JUMPX_OFFSET_LEN; + goto do_lookup_switch; + +BEGIN_CASE(JSOP_LOOKUPSWITCH) + off = JUMP_OFFSET_LEN; + + do_lookup_switch: + /* + * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if any atom + * index in it would exceed 64K limit. + */ + JS_ASSERT(!fp->imacpc); + JS_ASSERT(atoms == script->atomMap.vector); + jsbytecode *pc2 = regs.pc; + + Value lval = regs.sp[-1]; + regs.sp--; + + if (!lval.isPrimitive()) + goto end_lookup_switch; + + pc2 += off; + jsint npairs; + npairs = (jsint) GET_UINT16(pc2); + pc2 += UINT16_LEN; + JS_ASSERT(npairs); /* empty switch uses JSOP_TABLESWITCH */ + + bool match; +#define SEARCH_PAIRS(MATCH_CODE) \ + for (;;) { \ + Value rval = script->getConst(GET_INDEX(pc2)); \ + MATCH_CODE \ + pc2 += INDEX_LEN; \ + if (match) \ + break; \ + pc2 += off; \ + if (--npairs == 0) { \ + pc2 = regs.pc; \ + break; \ + } \ + } + + if (lval.isString()) { + JSString *str = lval.toString(); + JSString *str2; + SEARCH_PAIRS( + match = (rval.isString() && + ((str2 = rval.toString()) == str || + js_EqualStrings(str2, str))); + ) + } else if (lval.isNumber()) { + double ldbl = lval.toNumber(); + SEARCH_PAIRS( + match = rval.isNumber() && ldbl == rval.toNumber(); + ) + } else { + SEARCH_PAIRS( + match = (lval == rval); + ) + } +#undef SEARCH_PAIRS + + end_lookup_switch: + len = (op == JSOP_LOOKUPSWITCH) + ? GET_JUMP_OFFSET(pc2) + : GET_JUMPX_OFFSET(pc2); +} +END_VARLEN_CASE +} + +BEGIN_CASE(JSOP_TRAP) +{ + Value rval; + JSTrapStatus status = JS_HandleTrap(cx, script, regs.pc, Jsvalify(&rval)); + switch (status) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_RETURN: + fp->rval = rval; + interpReturnOK = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->throwing = JS_TRUE; + cx->exception = rval; + goto error; + default: + break; + } + JS_ASSERT(status == JSTRAP_CONTINUE); + CHECK_INTERRUPT_HANDLER(); + JS_ASSERT(rval.isInt32()); + op = (JSOp) rval.toInt32(); + JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT); + DO_OP(); +} + +BEGIN_CASE(JSOP_ARGUMENTS) +{ + Value rval; + if (!js_GetArgsValue(cx, fp, &rval)) + goto error; + PUSH_COPY(rval); +} +END_CASE(JSOP_ARGUMENTS) + +BEGIN_CASE(JSOP_ARGSUB) +{ + jsid id = INT_TO_JSID(GET_ARGNO(regs.pc)); + Value rval; + if (!js_GetArgsProperty(cx, fp, id, &rval)) + goto error; + PUSH_COPY(rval); +} +END_CASE(JSOP_ARGSUB) + +BEGIN_CASE(JSOP_ARGCNT) +{ + jsid id = ATOM_TO_JSID(rt->atomState.lengthAtom); + Value rval; + if (!js_GetArgsProperty(cx, fp, id, &rval)) + goto error; + PUSH_COPY(rval); +} +END_CASE(JSOP_ARGCNT) + +BEGIN_CASE(JSOP_GETARG) +BEGIN_CASE(JSOP_CALLARG) +{ + uint32 slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + METER_SLOT_OP(op, slot); + PUSH_COPY(fp->argv[slot]); + if (op == JSOP_CALLARG) + PUSH_NULL(); +} +END_CASE(JSOP_GETARG) + +BEGIN_CASE(JSOP_SETARG) +{ + uint32 slot = GET_ARGNO(regs.pc); + JS_ASSERT(slot < fp->fun->nargs); + METER_SLOT_OP(op, slot); + fp->argv[slot] = regs.sp[-1]; +} +END_SET_CASE(JSOP_SETARG) + +BEGIN_CASE(JSOP_GETLOCAL) +{ + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_COPY(fp->slots()[slot]); +} +END_CASE(JSOP_GETLOCAL) + +BEGIN_CASE(JSOP_CALLLOCAL) +{ + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + PUSH_COPY(fp->slots()[slot]); + PUSH_NULL(); +} +END_CASE(JSOP_CALLLOCAL) + +BEGIN_CASE(JSOP_SETLOCAL) +{ + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < script->nslots); + fp->slots()[slot] = regs.sp[-1]; +} +END_SET_CASE(JSOP_SETLOCAL) + +BEGIN_CASE(JSOP_GETUPVAR) +BEGIN_CASE(JSOP_CALLUPVAR) +{ + JSUpvarArray *uva = script->upvars(); + + uintN index = GET_UINT16(regs.pc); + JS_ASSERT(index < uva->length); + + const Value &rval = js_GetUpvar(cx, script->staticLevel, uva->vector[index]); + PUSH_COPY(rval); + + if (op == JSOP_CALLUPVAR) + PUSH_NULL(); +} +END_CASE(JSOP_GETUPVAR) + +BEGIN_CASE(JSOP_GETUPVAR_DBG) +BEGIN_CASE(JSOP_CALLUPVAR_DBG) +{ + JSFunction *fun = fp->fun; + JS_ASSERT(FUN_KIND(fun) == JSFUN_INTERPRETED); + JS_ASSERT(fun->u.i.wrapper); + + /* Scope for tempPool mark and local names allocation in it. */ + JSObject *obj, *obj2; + JSProperty *prop; + jsid id; + JSAtom *atom; + { + void *mark = JS_ARENA_MARK(&cx->tempPool); + jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool); + if (!names) + goto error; + + uintN index = fun->countArgsAndVars() + GET_UINT16(regs.pc); + atom = JS_LOCAL_NAME_TO_ATOM(names[index]); + id = ATOM_TO_JSID(atom); + + JSBool ok = js_FindProperty(cx, id, &obj, &obj2, &prop); + JS_ARENA_RELEASE(&cx->tempPool, mark); + if (!ok) + goto error; + } + + if (!prop) { + atomNotDefined = atom; + goto atom_not_defined; + } + + /* Minimize footprint with generic code instead of NATIVE_GET. */ + obj2->dropProperty(cx, prop); + Value *vp = regs.sp; + PUSH_NULL(); + if (!obj->getProperty(cx, id, vp)) + goto error; + + if (op == JSOP_CALLUPVAR_DBG) + PUSH_NULL(); +} +END_CASE(JSOP_GETUPVAR_DBG) + +BEGIN_CASE(JSOP_GETDSLOT) +BEGIN_CASE(JSOP_CALLDSLOT) +{ + JS_ASSERT(fp->argv); + JSObject *obj = &fp->argv[-2].toObject(); + JS_ASSERT(obj); + JS_ASSERT(obj->dslots); + + uintN index = GET_UINT16(regs.pc); + JS_ASSERT(JS_INITIAL_NSLOTS + index < obj->dslots[-1].toPrivateUint32()); + JS_ASSERT_IF(obj->scope()->object == obj, + JS_INITIAL_NSLOTS + index < obj->scope()->freeslot); + + PUSH_COPY(obj->dslots[index]); + if (op == JSOP_CALLDSLOT) + PUSH_NULL(); +} +END_CASE(JSOP_GETDSLOT) + +BEGIN_CASE(JSOP_GETGVAR) +BEGIN_CASE(JSOP_CALLGVAR) +{ + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < GlobalVarCount(fp)); + METER_SLOT_OP(op, slot); + const Value &lval = fp->slots()[slot]; + if (lval.isNull()) { + op = (op == JSOP_GETGVAR) ? JSOP_NAME : JSOP_CALLNAME; + DO_OP(); + } + JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); + JSObject *varobj = cx->activeCallStack()->getInitialVarObj(); + + /* XXX all this code assumes that varobj is either a callobj or global and + * that it cannot be accessed in a MT way. This is either true now or + * coming soon. */ + + slot = (uint32)lval.toInt32(); + const Value &rref = varobj->lockedGetSlot(slot); + PUSH_COPY(rref); + if (op == JSOP_CALLGVAR) + PUSH_NULL(); +} +END_CASE(JSOP_GETGVAR) + +BEGIN_CASE(JSOP_SETGVAR) +{ + uint32 slot = GET_SLOTNO(regs.pc); + JS_ASSERT(slot < GlobalVarCount(fp)); + METER_SLOT_OP(op, slot); + const Value &rref = regs.sp[-1]; + JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); + JSObject *obj = cx->activeCallStack()->getInitialVarObj(); + const Value &lref = fp->slots()[slot]; + if (lref.isNull()) { + /* + * Inline-clone and deoptimize JSOP_SETNAME code here because + * JSOP_SETGVAR has arity 1: [rref], not arity 2: [obj, rref] + * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME. + */ +#ifdef JS_TRACER + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "SETGVAR with NULL slot"); +#endif + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + Value rval = rref; + if (!obj->setProperty(cx, id, &rval)) + goto error; + } else { + uint32 slot = (uint32)lref.toInt32(); + JS_LOCK_OBJ(cx, obj); + JSScope *scope = obj->scope(); + if (!scope->methodWriteBarrier(cx, slot, rref)) { + JS_UNLOCK_SCOPE(cx, scope); + goto error; + } + obj->lockedSetSlot(slot, rref); + JS_UNLOCK_SCOPE(cx, scope); + } +} +END_SET_CASE(JSOP_SETGVAR) + +BEGIN_CASE(JSOP_DEFCONST) +BEGIN_CASE(JSOP_DEFVAR) +{ + uint32 index = GET_INDEX(regs.pc); + JSAtom *atom = atoms[index]; + + /* + * index is relative to atoms at this point but for global var + * code below we need the absolute value. + */ + index += atoms - script->atomMap.vector; + JSObject *obj = fp->varobj(cx); + JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty); + uintN attrs = JSPROP_ENUMERATE; + if (!(fp->flags & JSFRAME_EVAL)) + attrs |= JSPROP_PERMANENT; + if (op == JSOP_DEFCONST) + attrs |= JSPROP_READONLY; + + /* Lookup id in order to check for redeclaration problems. */ + jsid id = ATOM_TO_JSID(atom); + JSProperty *prop = NULL; + JSObject *obj2; + if (op == JSOP_DEFVAR) { + /* + * Redundant declaration of a |var|, even one for a non-writable + * property like |undefined| in ES5, does nothing. + */ + if (!obj->lookupProperty(cx, id, &obj2, &prop)) + goto error; + } else { + if (!CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop)) + goto error; + } + + /* Bind a variable only if it's not yet defined. */ + if (!prop) { + if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), PropertyStub, PropertyStub, + attrs, 0, 0, &prop)) { + goto error; + } + JS_ASSERT(prop); + obj2 = obj; + } + + /* + * Try to optimize a property we either just created, or found + * directly in the global object, that is permanent, has a slot, + * and has stub getter and setter, into a "fast global" accessed + * by the JSOP_*GVAR opcodes. + */ + if (!fp->fun && + index < GlobalVarCount(fp) && + obj2 == obj && + obj->isNative()) { + JSScopeProperty *sprop = (JSScopeProperty *) prop; + if (!sprop->configurable() && + SPROP_HAS_VALID_SLOT(sprop, obj->scope()) && + sprop->hasDefaultGetterOrIsMethod() && + sprop->hasDefaultSetter()) { + /* + * Fast globals use frame variables to map the global name's atom + * index to the permanent varobj slot number, tagged as a jsval. + * The atom index for the global's name literal is identical to its + * variable index. + */ + fp->slots()[index].setInt32(sprop->slot); + } + } + + obj2->dropProperty(cx, prop); +} +END_CASE(JSOP_DEFVAR) + +BEGIN_CASE(JSOP_DEFFUN) +{ + PropertyOp getter, setter; + bool doSet; + JSObject *pobj; + JSProperty *prop; + uint32 old; + + /* + * A top-level function defined in Global or Eval code (see ECMA-262 + * Ed. 3), or else a SpiderMonkey extension: a named function statement in + * a compound statement (not at the top statement level of global code, or + * at the top level of a function body). + */ + JSFunction *fun; + LOAD_FUNCTION(0); + JSObject *obj = FUN_OBJECT(fun); + + JSObject *obj2; + if (FUN_NULL_CLOSURE(fun)) { + /* + * Even a null closure needs a parent for principals finding. + * FIXME: bug 476950, although debugger users may also demand some kind + * of scope link for debugger-assisted eval-in-frame. + */ + obj2 = fp->scopeChain; + } else { + JS_ASSERT(!FUN_FLAT_CLOSURE(fun)); + + /* + * Inline js_GetScopeChain a bit to optimize for the case of a + * top-level function. + */ + if (!fp->blockChain) { + obj2 = fp->scopeChain; + } else { + obj2 = js_GetScopeChain(cx, fp); + if (!obj2) + goto error; + } + } + + /* + * If static link is not current scope, clone fun's object to link to the + * current scope via parent. We do this to enable sharing of compiled + * functions among multiple equivalent scopes, amortizing the cost of + * compilation over a number of executions. Examples include XUL scripts + * and event handlers shared among Firefox or other Mozilla app chrome + * windows, and user-defined JS functions precompiled and then shared among + * requests in server-side JS. + */ + if (obj->getParent() != obj2) { + obj = CloneFunctionObject(cx, fun, obj2); + if (!obj) + goto error; + } + + /* + * Protect obj from any GC hiding below JSObject::setProperty or + * JSObject::defineProperty. All paths from here must flow through the + * fp->scopeChain code below the parent->defineProperty call. + */ + MUST_FLOW_THROUGH("restore_scope"); + fp->scopeChain = obj; + + Value rval = ObjectValue(*obj); + + /* + * ECMA requires functions defined when entering Eval code to be + * impermanent. + */ + uintN attrs = (fp->flags & JSFRAME_EVAL) + ? JSPROP_ENUMERATE + : JSPROP_ENUMERATE | JSPROP_PERMANENT; + + /* + * Load function flags that are also property attributes. Getters and + * setters do not need a slot, their value is stored elsewhere in the + * property itself, not in obj slots. + */ + getter = setter = PropertyStub; + uintN flags = JSFUN_GSFLAG2ATTR(fun->flags); + if (flags) { + /* Function cannot be both getter a setter. */ + JS_ASSERT(flags == JSPROP_GETTER || flags == JSPROP_SETTER); + attrs |= flags | JSPROP_SHARED; + rval.setUndefined(); + if (flags == JSPROP_GETTER) + getter = CastAsPropertyOp(obj); + else + setter = CastAsPropertyOp(obj); + } + + /* + * We define the function as a property of the variable object and not the + * current scope chain even for the case of function expression statements + * and functions defined by eval inside let or with blocks. + */ + JSObject *parent = fp->varobj(cx); + JS_ASSERT(parent); + + /* + * Check for a const property of the same name -- or any kind of property + * if executing with the strict option. We check here at runtime as well + * as at compile-time, to handle eval as well as multiple HTML script tags. + */ + jsid id = ATOM_TO_JSID(fun->atom); + prop = NULL; + JSBool ok = CheckRedeclaration(cx, parent, id, attrs, &pobj, &prop); + if (!ok) + goto restore_scope; + + /* + * We deviate from 10.1.2 in ECMA 262 v3 and under eval use for function + * declarations JSObject::setProperty, not JSObject::defineProperty, to + * preserve the JSOP_PERMANENT attribute of existing properties and make + * sure that such properties cannot be deleted. + * + * We also use JSObject::setProperty for the existing properties of Call + * objects with matching attributes to preserve the native getters and + * setters that store the value of the property in the interpreter frame, + * see bug 467495. + */ + doSet = (attrs == JSPROP_ENUMERATE); + JS_ASSERT_IF(doSet, fp->flags & JSFRAME_EVAL); + if (prop) { + if (parent == pobj && + parent->getClass() == &js_CallClass && + (old = ((JSScopeProperty *) prop)->attributes(), + !(old & (JSPROP_GETTER|JSPROP_SETTER)) && + (old & (JSPROP_ENUMERATE|JSPROP_PERMANENT)) == attrs)) { + /* + * js_CheckRedeclaration must reject attempts to add a getter or + * setter to an existing property without a getter or setter. + */ + JS_ASSERT(!(attrs & ~(JSPROP_ENUMERATE|JSPROP_PERMANENT))); + JS_ASSERT(!(old & JSPROP_READONLY)); + doSet = JS_TRUE; + } + pobj->dropProperty(cx, prop); + } + ok = doSet + ? parent->setProperty(cx, id, &rval) + : parent->defineProperty(cx, id, rval, getter, setter, attrs); + + restore_scope: + /* Restore fp->scopeChain now that obj is defined in fp->callobj. */ + fp->scopeChain = obj2; + if (!ok) + goto error; +} +END_CASE(JSOP_DEFFUN) + +BEGIN_CASE(JSOP_DEFFUN_FC) +BEGIN_CASE(JSOP_DEFFUN_DBGFC) +{ + JSFunction *fun; + LOAD_FUNCTION(0); + + JSObject *obj = (op == JSOP_DEFFUN_FC) + ? js_NewFlatClosure(cx, fun) + : js_NewDebuggableFlatClosure(cx, fun); + if (!obj) + goto error; + + Value rval = ObjectValue(*obj); + + uintN attrs = (fp->flags & JSFRAME_EVAL) + ? JSPROP_ENUMERATE + : JSPROP_ENUMERATE | JSPROP_PERMANENT; + + uintN flags = JSFUN_GSFLAG2ATTR(fun->flags); + if (flags) { + attrs |= flags | JSPROP_SHARED; + rval.setUndefined(); + } + + JSObject *parent = fp->varobj(cx); + JS_ASSERT(parent); + + jsid id = ATOM_TO_JSID(fun->atom); + JSBool ok = CheckRedeclaration(cx, parent, id, attrs, NULL, NULL); + if (ok) { + if (attrs == JSPROP_ENUMERATE) { + JS_ASSERT(fp->flags & JSFRAME_EVAL); + ok = parent->setProperty(cx, id, &rval); + } else { + JS_ASSERT(attrs & JSPROP_PERMANENT); + + ok = parent->defineProperty(cx, id, rval, + (flags & JSPROP_GETTER) + ? CastAsPropertyOp(obj) + : PropertyStub, + (flags & JSPROP_SETTER) + ? CastAsPropertyOp(obj) + : PropertyStub, + attrs); + } + } + + if (!ok) + goto error; +} +END_CASE(JSOP_DEFFUN_FC) + +BEGIN_CASE(JSOP_DEFLOCALFUN) +{ + /* + * Define a local function (i.e., one nested at the top level of another + * function), parented by the current scope chain, stored in a local + * variable slot that the compiler allocated. This is an optimization over + * JSOP_DEFFUN that avoids requiring a call object for the outer function's + * activation. + */ + JSFunction *fun; + LOAD_FUNCTION(SLOTNO_LEN); + JS_ASSERT(fun->isInterpreted()); + JS_ASSERT(!FUN_FLAT_CLOSURE(fun)); + JSObject *obj = FUN_OBJECT(fun); + + if (FUN_NULL_CLOSURE(fun)) { + obj = CloneFunctionObject(cx, fun, fp->scopeChain); + if (!obj) + goto error; + } else { + JSObject *parent = js_GetScopeChain(cx, fp); + if (!parent) + goto error; + + if (obj->getParent() != parent) { +#ifdef JS_TRACER + if (TRACE_RECORDER(cx)) + AbortRecording(cx, "DEFLOCALFUN for closure"); +#endif + obj = CloneFunctionObject(cx, fun, parent); + if (!obj) + goto error; + } + } + + uint32 slot = GET_SLOTNO(regs.pc); + TRACE_2(DefLocalFunSetSlot, slot, obj); + + fp->slots()[slot].setObject(*obj); +} +END_CASE(JSOP_DEFLOCALFUN) + +BEGIN_CASE(JSOP_DEFLOCALFUN_FC) +{ + JSFunction *fun; + LOAD_FUNCTION(SLOTNO_LEN); + + JSObject *obj = js_NewFlatClosure(cx, fun); + if (!obj) + goto error; + + uint32 slot = GET_SLOTNO(regs.pc); + TRACE_2(DefLocalFunSetSlot, slot, obj); + + fp->slots()[slot].setObject(*obj); +} +END_CASE(JSOP_DEFLOCALFUN_FC) + +BEGIN_CASE(JSOP_DEFLOCALFUN_DBGFC) +{ + JSFunction *fun; + LOAD_FUNCTION(SLOTNO_LEN); + + JSObject *obj = js_NewDebuggableFlatClosure(cx, fun); + if (!obj) + goto error; + + uint32 slot = GET_SLOTNO(regs.pc); + fp->slots()[slot].setObject(*obj); +} +END_CASE(JSOP_DEFLOCALFUN_DBGFC) + +BEGIN_CASE(JSOP_LAMBDA) +{ + /* Load the specified function object literal. */ + JSFunction *fun; + LOAD_FUNCTION(0); + JSObject *obj = FUN_OBJECT(fun); + + /* do-while(0) so we can break instead of using a goto. */ + do { + JSObject *parent; + if (FUN_NULL_CLOSURE(fun)) { + parent = fp->scopeChain; + + if (obj->getParent() == parent) { + op = JSOp(regs.pc[JSOP_LAMBDA_LENGTH]); + + /* + * Optimize ({method: function () { ... }, ...}) and + * this.method = function () { ... }; bytecode sequences. + */ + if (op == JSOP_SETMETHOD) { +#ifdef DEBUG + JSOp op2 = JSOp(regs.pc[JSOP_LAMBDA_LENGTH + JSOP_SETMETHOD_LENGTH]); + JS_ASSERT(op2 == JSOP_POP || op2 == JSOP_POPV); +#endif + + const Value &lref = regs.sp[-1]; + if (lref.isObject() && + lref.toObject().getClass() == &js_ObjectClass) { + break; + } + } else if (op == JSOP_INITMETHOD) { +#ifdef DEBUG + const Value &lref = regs.sp[-1]; + JS_ASSERT(lref.isObject()); + JSObject *obj2 = &lref.toObject(); + JS_ASSERT(obj2->getClass() == &js_ObjectClass); + JS_ASSERT(obj2->scope()->object == obj2); +#endif + break; + } + } + } else { + parent = js_GetScopeChain(cx, fp); + if (!parent) + goto error; + } + + obj = CloneFunctionObject(cx, fun, parent); + if (!obj) + goto error; + } while (0); + + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_LAMBDA) + +BEGIN_CASE(JSOP_LAMBDA_FC) +{ + JSFunction *fun; + LOAD_FUNCTION(0); + + JSObject *obj = js_NewFlatClosure(cx, fun); + if (!obj) + goto error; + + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_LAMBDA_FC) + +BEGIN_CASE(JSOP_LAMBDA_DBGFC) +{ + JSFunction *fun; + LOAD_FUNCTION(0); + + JSObject *obj = js_NewDebuggableFlatClosure(cx, fun); + if (!obj) + goto error; + + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_LAMBDA_DBGFC) + +BEGIN_CASE(JSOP_CALLEE) + PUSH_COPY(fp->argv[-2]); +END_CASE(JSOP_CALLEE) + +BEGIN_CASE(JSOP_GETTER) +BEGIN_CASE(JSOP_SETTER) +{ + do_getter_setter: + JSOp op2 = (JSOp) *++regs.pc; + jsid id; + Value rval; + jsint i; + JSObject *obj; + switch (op2) { + case JSOP_INDEXBASE: + atoms += GET_INDEXBASE(regs.pc); + regs.pc += JSOP_INDEXBASE_LENGTH - 1; + goto do_getter_setter; + case JSOP_INDEXBASE1: + case JSOP_INDEXBASE2: + case JSOP_INDEXBASE3: + atoms += (op2 - JSOP_INDEXBASE1 + 1) << 16; + goto do_getter_setter; + + case JSOP_SETNAME: + case JSOP_SETPROP: + { + JSAtom *atom; + LOAD_ATOM(0, atom); + id = ATOM_TO_JSID(atom); + rval = regs.sp[-1]; + i = -1; + goto gs_pop_lval; + } + case JSOP_SETELEM: + rval = regs.sp[-1]; + id = JSID_VOID; + i = -2; + gs_pop_lval: + FETCH_OBJECT(cx, i - 1, obj); + break; + + case JSOP_INITPROP: + { + JS_ASSERT(regs.sp - fp->base() >= 2); + rval = regs.sp[-1]; + i = -1; + JSAtom *atom; + LOAD_ATOM(0, atom); + id = ATOM_TO_JSID(atom); + goto gs_get_lval; + } + default: + JS_ASSERT(op2 == JSOP_INITELEM); + + JS_ASSERT(regs.sp - fp->base() >= 3); + rval = regs.sp[-1]; + id = JSID_VOID; + i = -2; + gs_get_lval: + { + const Value &lref = regs.sp[i-1]; + JS_ASSERT(lref.isObject()); + obj = &lref.toObject(); + break; + } + } + + /* Ensure that id has a type suitable for use with obj. */ + if (JSID_IS_VOID(id)) + FETCH_ELEMENT_ID(obj, i, id); + + if (!js_IsCallable(rval)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_GETTER_OR_SETTER, + (op == JSOP_GETTER) + ? js_getter_str + : js_setter_str); + goto error; + } + + /* + * Getters and setters are just like watchpoints from an access control + * point of view. + */ + Value rtmp; + uintN attrs; + if (!CheckAccess(cx, obj, id, JSACC_WATCH, &rtmp, &attrs)) + goto error; + + PropertyOp getter, setter; + if (op == JSOP_GETTER) { + getter = CastAsPropertyOp(&rval.toObject()); + setter = PropertyStub; + attrs = JSPROP_GETTER; + } else { + getter = PropertyStub; + setter = CastAsPropertyOp(&rval.toObject()); + attrs = JSPROP_SETTER; + } + attrs |= JSPROP_ENUMERATE | JSPROP_SHARED; + + /* Check for a readonly or permanent property of the same name. */ + if (!CheckRedeclaration(cx, obj, id, attrs, NULL, NULL)) + goto error; + + if (!obj->defineProperty(cx, id, UndefinedValue(), getter, setter, attrs)) + goto error; + + regs.sp += i; + if (js_CodeSpec[op2].ndefs > js_CodeSpec[op2].nuses) { + JS_ASSERT(js_CodeSpec[op2].ndefs == js_CodeSpec[op2].nuses + 1); + regs.sp[-1] = rval; + } + len = js_CodeSpec[op2].length; + DO_NEXT_OP(len); +} + +BEGIN_CASE(JSOP_HOLE) + PUSH_HOLE(); +END_CASE(JSOP_HOLE) + +BEGIN_CASE(JSOP_NEWARRAY) +{ + len = GET_UINT16(regs.pc); + cx->assertValidStackDepth(len); + JSObject *obj = js_NewArrayObject(cx, len, regs.sp - len, JS_TRUE); + if (!obj) + goto error; + regs.sp -= len - 1; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_NEWARRAY) + +BEGIN_CASE(JSOP_NEWINIT) +{ + jsint i = GET_INT8(regs.pc); + JS_ASSERT(i == JSProto_Array || i == JSProto_Object); + JSObject *obj; + if (i == JSProto_Array) { + obj = js_NewArrayObject(cx, 0, NULL); + if (!obj) + goto error; + } else { + obj = NewBuiltinClassInstance(cx, &js_ObjectClass); + if (!obj) + goto error; + + if (regs.pc[JSOP_NEWINIT_LENGTH] != JSOP_ENDINIT) { + JS_LOCK_OBJ(cx, obj); + JSScope *scope = js_GetMutableScope(cx, obj); + if (!scope) { + JS_UNLOCK_OBJ(cx, obj); + goto error; + } + + /* + * We cannot assume that js_GetMutableScope above creates a scope + * owned by cx and skip JS_UNLOCK_SCOPE. A new object debugger + * hook may add properties to the newly created object, suspend + * the current request and share the object with other threads. + */ + JS_UNLOCK_SCOPE(cx, scope); + } + } + + PUSH_OBJECT(*obj); + CHECK_INTERRUPT_HANDLER(); +} +END_CASE(JSOP_NEWINIT) + +BEGIN_CASE(JSOP_ENDINIT) +{ + /* Re-set the newborn root to the top of this object tree. */ + JS_ASSERT(regs.sp - fp->base() >= 1); + const Value &lref = regs.sp[-1]; + JS_ASSERT(lref.isObject()); + cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = &lref.toObject(); +} +END_CASE(JSOP_ENDINIT) + +BEGIN_CASE(JSOP_INITPROP) +BEGIN_CASE(JSOP_INITMETHOD) +{ + /* Load the property's initial value into rval. */ + JS_ASSERT(regs.sp - fp->base() >= 2); + Value rval = regs.sp[-1]; + + /* Load the object being initialized into lval/obj. */ + JSObject *obj = ®s.sp[-2].toObject(); + JS_ASSERT(obj->isNative()); + + JSScope *scope = obj->scope(); + + /* + * Probe the property cache. + * + * We can not assume that the object created by JSOP_NEWINIT is still + * single-threaded as the debugger can access it from other threads. + * So check first. + * + * On a hit, if the cached sprop has a non-default setter, it must be + * __proto__. If sprop->parent != scope->lastProperty(), there is a + * repeated property name. The fast path does not handle these two cases. + */ + PropertyCacheEntry *entry; + JSScopeProperty *sprop; + if (CX_OWNS_OBJECT_TITLE(cx, obj) && + JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, scope, &sprop, &entry) && + sprop->hasDefaultSetter() && + sprop->parent == scope->lastProperty()) + { + /* Fast path. Property cache hit. */ + uint32 slot = sprop->slot; + JS_ASSERT(slot == scope->freeslot); + if (slot < obj->numSlots()) { + ++scope->freeslot; + } else { + if (!js_AllocSlot(cx, obj, &slot)) + goto error; + JS_ASSERT(slot == sprop->slot); + } + + JS_ASSERT(!scope->lastProperty() || + scope->shape == scope->lastProperty()->shape); + if (scope->table) { + JSScopeProperty *sprop2 = + scope->addProperty(cx, sprop->id, sprop->getter(), sprop->setter(), slot, + sprop->attributes(), sprop->getFlags(), sprop->shortid); + if (!sprop2) { + js_FreeSlot(cx, obj, slot); + goto error; + } + JS_ASSERT(sprop2 == sprop); + } else { + JS_ASSERT(!scope->isSharedEmpty()); + scope->extend(cx, sprop); + } + + /* + * No method change check here because here we are adding a new + * property, not updating an existing slot's value that might + * contain a method of a branded scope. + */ + TRACE_2(SetPropHit, entry, sprop); + obj->lockedSetSlot(slot, rval); + } else { + PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++); + + /* Get the immediate property name into id. */ + JSAtom *atom; + LOAD_ATOM(0, atom); + jsid id = ATOM_TO_JSID(atom); + + /* Set the property named by obj[id] to rval. */ + if (!CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL, NULL)) + goto error; + + uintN defineHow = (op == JSOP_INITMETHOD) + ? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD + : JSDNP_CACHE_RESULT; + if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom) + ? js_SetPropertyHelper(cx, obj, id, defineHow, &rval) + : js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL, + JSPROP_ENUMERATE, 0, 0, NULL, + defineHow))) { + goto error; + } + } + + /* Common tail for property cache hit and miss cases. */ + regs.sp--; +} +END_CASE(JSOP_INITPROP); + +BEGIN_CASE(JSOP_INITELEM) +{ + /* Pop the element's value into rval. */ + JS_ASSERT(regs.sp - fp->base() >= 3); + const Value &rref = regs.sp[-1]; + + /* Find the object being initialized at top of stack. */ + const Value &lref = regs.sp[-3]; + JS_ASSERT(lref.isObject()); + JSObject *obj = &lref.toObject(); + + /* Fetch id now that we have obj. */ + jsid id; + FETCH_ELEMENT_ID(obj, -2, id); + + /* + * Check for property redeclaration strict warning (we may be in an object + * initialiser, not an array initialiser). + */ + if (!CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL, NULL)) + goto error; + + /* + * If rref is a hole, do not call JSObject::defineProperty. In this case, + * obj must be an array, so if the current op is the last element + * initialiser, set the array length to one greater than id. + */ + if (rref.isMagic(JS_ARRAY_HOLE)) { + JS_ASSERT(obj->isArray()); + JS_ASSERT(JSID_IS_INT(id)); + JS_ASSERT(jsuint(JSID_TO_INT(id)) < JS_ARGS_LENGTH_MAX); + if (js_GetOpcode(cx, script, regs.pc + JSOP_INITELEM_LENGTH) == JSOP_ENDINIT && + !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) { + goto error; + } + } else { + if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) + goto error; + } + regs.sp -= 2; +} +END_CASE(JSOP_INITELEM) + +#if JS_HAS_SHARP_VARS + +BEGIN_CASE(JSOP_DEFSHARP) +{ + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < fp->script->nfixed); + const Value &lref = fp->slots()[slot]; + JSObject *obj; + if (lref.isObject()) { + obj = &lref.toObject(); + } else { + JS_ASSERT(lref.isUndefined()); + obj = js_NewArrayObject(cx, 0, NULL); + if (!obj) + goto error; + fp->slots()[slot].setObject(*obj); + } + jsint i = (jsint) GET_UINT16(regs.pc + UINT16_LEN); + jsid id = INT_TO_JSID(i); + const Value &rref = regs.sp[-1]; + if (rref.isPrimitive()) { + char numBuf[12]; + JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SHARP_DEF, numBuf); + goto error; + } + if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE)) + goto error; +} +END_CASE(JSOP_DEFSHARP) + +BEGIN_CASE(JSOP_USESHARP) +{ + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < fp->script->nfixed); + const Value &lref = fp->slots()[slot]; + jsint i = (jsint) GET_UINT16(regs.pc + UINT16_LEN); + Value rval; + if (lref.isUndefined()) { + rval.setUndefined(); + } else { + JSObject *obj = &fp->slots()[slot].toObject(); + jsid id = INT_TO_JSID(i); + if (!obj->getProperty(cx, id, &rval)) + goto error; + } + if (!rval.isObjectOrNull()) { + char numBuf[12]; + + JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_BAD_SHARP_USE, numBuf); + goto error; + } + PUSH_COPY(rval); +} +END_CASE(JSOP_USESHARP) + +BEGIN_CASE(JSOP_SHARPINIT) +{ + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < fp->script->nfixed); + Value *vp = &fp->slots()[slot]; + Value rval = vp[1]; + + /* + * We peek ahead safely here because empty initialisers get zero + * JSOP_SHARPINIT ops, and non-empty ones get two: the first comes + * immediately after JSOP_NEWINIT followed by one or more property + * initialisers; and the second comes directly before JSOP_ENDINIT. + */ + if (regs.pc[JSOP_SHARPINIT_LENGTH] != JSOP_ENDINIT) { + rval.setInt32(rval.isUndefined() ? 1 : rval.toInt32() + 1); + } else { + JS_ASSERT(rval.isInt32()); + rval.getInt32Ref() -= 1; + if (rval.toInt32() == 0) + vp[0].setUndefined(); + } + vp[1] = rval; +} +END_CASE(JSOP_SHARPINIT) + +#endif /* JS_HAS_SHARP_VARS */ + +{ +BEGIN_CASE(JSOP_GOSUB) + PUSH_BOOLEAN(false); + jsint i = (regs.pc - script->main) + JSOP_GOSUB_LENGTH; + PUSH_INT32(i); + len = GET_JUMP_OFFSET(regs.pc); +END_VARLEN_CASE +} + +{ +BEGIN_CASE(JSOP_GOSUBX) + PUSH_BOOLEAN(false); + jsint i = (regs.pc - script->main) + JSOP_GOSUBX_LENGTH; + len = GET_JUMPX_OFFSET(regs.pc); + PUSH_INT32(i); +END_VARLEN_CASE +} + +{ +BEGIN_CASE(JSOP_RETSUB) + /* Pop [exception or hole, retsub pc-index]. */ + Value rval, lval; + POP_COPY_TO(rval); + POP_COPY_TO(lval); + JS_ASSERT(lval.isBoolean()); + if (lval.toBoolean()) { + /* + * Exception was pending during finally, throw it *before* we adjust + * pc, because pc indexes into script->trynotes. This turns out not to + * be necessary, but it seems clearer. And it points out a FIXME: + * 350509, due to Igor Bukanov. + */ + cx->throwing = JS_TRUE; + cx->exception = rval; + goto error; + } + JS_ASSERT(rval.isInt32()); + len = rval.toInt32(); + regs.pc = script->main; +END_VARLEN_CASE +} + +BEGIN_CASE(JSOP_EXCEPTION) + JS_ASSERT(cx->throwing); + PUSH_COPY(cx->exception); + cx->throwing = JS_FALSE; + CHECK_BRANCH(); +END_CASE(JSOP_EXCEPTION) + +BEGIN_CASE(JSOP_FINALLY) + CHECK_BRANCH(); +END_CASE(JSOP_FINALLY) + +BEGIN_CASE(JSOP_THROWING) + JS_ASSERT(!cx->throwing); + cx->throwing = JS_TRUE; + POP_COPY_TO(cx->exception); +END_CASE(JSOP_THROWING) + +BEGIN_CASE(JSOP_THROW) + JS_ASSERT(!cx->throwing); + CHECK_BRANCH(); + cx->throwing = JS_TRUE; + POP_COPY_TO(cx->exception); + /* let the code at error try to catch the exception. */ + goto error; + +BEGIN_CASE(JSOP_SETLOCALPOP) +{ + /* + * The stack must have a block with at least one local slot below the + * exception object. + */ + JS_ASSERT((size_t) (regs.sp - fp->base()) >= 2); + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(slot + 1 < script->nslots); + POP_COPY_TO(fp->slots()[slot]); +} +END_CASE(JSOP_SETLOCALPOP) + +BEGIN_CASE(JSOP_IFPRIMTOP) + /* + * If the top of stack is of primitive type, jump to our target. Otherwise + * advance to the next opcode. + */ + JS_ASSERT(regs.sp > fp->base()); + if (regs.sp[-1].isPrimitive()) { + len = GET_JUMP_OFFSET(regs.pc); + BRANCH(len); + } +END_CASE(JSOP_IFPRIMTOP) + +BEGIN_CASE(JSOP_PRIMTOP) + JS_ASSERT(regs.sp > fp->base()); + if (regs.sp[-1].isObject()) { + jsint i = GET_INT8(regs.pc); + js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, -2, regs.sp[-2], NULL, + (i == JSTYPE_VOID) ? "primitive type" : JS_TYPE_STR(i)); + goto error; + } +END_CASE(JSOP_PRIMTOP) + +BEGIN_CASE(JSOP_OBJTOP) + if (regs.sp[-1].isPrimitive()) { + js_ReportValueError(cx, GET_UINT16(regs.pc), -1, regs.sp[-1], NULL); + goto error; + } +END_CASE(JSOP_OBJTOP) + +BEGIN_CASE(JSOP_INSTANCEOF) +{ + const Value &rref = regs.sp[-1]; + JSObject *obj; + if (rref.isPrimitive() || + !(obj = &rref.toObject())->map->ops->hasInstance) { + js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, + -1, rref, NULL); + goto error; + } + const Value &lref = regs.sp[-2]; + JSBool cond = JS_FALSE; + if (!obj->map->ops->hasInstance(cx, obj, &lref, &cond)) + goto error; + regs.sp--; + regs.sp[-1].setBoolean(cond); +} +END_CASE(JSOP_INSTANCEOF) + +#if JS_HAS_DEBUGGER_KEYWORD +BEGIN_CASE(JSOP_DEBUGGER) +{ + JSDebuggerHandler handler = cx->debugHooks->debuggerHandler; + if (handler) { + Value rval; + switch (handler(cx, script, regs.pc, Jsvalify(&rval), cx->debugHooks->debuggerHandlerData)) { + case JSTRAP_ERROR: + goto error; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + fp->rval = rval; + interpReturnOK = JS_TRUE; + goto forced_return; + case JSTRAP_THROW: + cx->throwing = JS_TRUE; + cx->exception = rval; + goto error; + default:; + } + CHECK_INTERRUPT_HANDLER(); + } +} +END_CASE(JSOP_DEBUGGER) +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + +#if JS_HAS_XML_SUPPORT +BEGIN_CASE(JSOP_DEFXMLNS) +{ + Value rval; + POP_COPY_TO(rval); + if (!js_SetDefaultXMLNamespace(cx, rval)) + goto error; +} +END_CASE(JSOP_DEFXMLNS) + +BEGIN_CASE(JSOP_ANYNAME) +{ + jsid id; + if (!js_GetAnyName(cx, &id)) + goto error; + PUSH_COPY(IdToValue(id)); +} +END_CASE(JSOP_ANYNAME) + +BEGIN_CASE(JSOP_QNAMEPART) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + PUSH_STRING(ATOM_TO_STRING(atom)); +} +END_CASE(JSOP_QNAMEPART) + +BEGIN_CASE(JSOP_QNAMECONST) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + Value rval = StringValue(ATOM_TO_STRING(atom)); + Value lval = regs.sp[-1]; + JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval); + if (!obj) + goto error; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_QNAMECONST) + +BEGIN_CASE(JSOP_QNAME) +{ + Value rval = regs.sp[-1]; + Value lval = regs.sp[-2]; + JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval); + if (!obj) + goto error; + regs.sp--; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_QNAME) + +BEGIN_CASE(JSOP_TOATTRNAME) +{ + Value rval; + rval = regs.sp[-1]; + if (!js_ToAttributeName(cx, &rval)) + goto error; + regs.sp[-1] = rval; +} +END_CASE(JSOP_TOATTRNAME) + +BEGIN_CASE(JSOP_TOATTRVAL) +{ + Value rval; + rval = regs.sp[-1]; + JS_ASSERT(rval.isString()); + JSString *str = js_EscapeAttributeValue(cx, rval.toString(), JS_FALSE); + if (!str) + goto error; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_TOATTRVAL) + +BEGIN_CASE(JSOP_ADDATTRNAME) +BEGIN_CASE(JSOP_ADDATTRVAL) +{ + Value rval = regs.sp[-1]; + Value lval = regs.sp[-2]; + JSString *str = lval.toString(); + JSString *str2 = rval.toString(); + str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2); + if (!str) + goto error; + regs.sp--; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_ADDATTRNAME) + +BEGIN_CASE(JSOP_BINDXMLNAME) +{ + Value lval; + lval = regs.sp[-1]; + JSObject *obj; + jsid id; + if (!js_FindXMLProperty(cx, lval, &obj, &id)) + goto error; + regs.sp[-1].setObjectOrNull(obj); + PUSH_COPY(IdToValue(id)); +} +END_CASE(JSOP_BINDXMLNAME) + +BEGIN_CASE(JSOP_SETXMLNAME) +{ + JSObject *obj = ®s.sp[-3].toObject(); + Value rval = regs.sp[-1]; + jsid id; + FETCH_ELEMENT_ID(obj, -2, id); + if (!obj->setProperty(cx, id, &rval)) + goto error; + rval = regs.sp[-1]; + regs.sp -= 2; + regs.sp[-1] = rval; +} +END_CASE(JSOP_SETXMLNAME) + +BEGIN_CASE(JSOP_CALLXMLNAME) +BEGIN_CASE(JSOP_XMLNAME) +{ + Value lval = regs.sp[-1]; + JSObject *obj; + jsid id; + if (!js_FindXMLProperty(cx, lval, &obj, &id)) + goto error; + Value rval; + if (!obj->getProperty(cx, id, &rval)) + goto error; + regs.sp[-1] = rval; + if (op == JSOP_CALLXMLNAME) + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_XMLNAME) + +BEGIN_CASE(JSOP_DESCENDANTS) +BEGIN_CASE(JSOP_DELDESC) +{ + JSObject *obj; + FETCH_OBJECT(cx, -2, obj); + jsval rval = Jsvalify(regs.sp[-1]); + if (!js_GetXMLDescendants(cx, obj, rval, &rval)) + goto error; + + if (op == JSOP_DELDESC) { + regs.sp[-1] = Valueify(rval); /* set local root */ + if (!js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval))) + goto error; + rval = JSVAL_TRUE; /* always succeed */ + } + + regs.sp--; + regs.sp[-1] = Valueify(rval); +} +END_CASE(JSOP_DESCENDANTS) + +{ +BEGIN_CASE(JSOP_FILTER) + /* + * We push the hole value before jumping to [enditer] so we can detect the + * first iteration and direct js_StepXMLListFilter to initialize filter's + * state. + */ + PUSH_HOLE(); + len = GET_JUMP_OFFSET(regs.pc); + JS_ASSERT(len > 0); +END_VARLEN_CASE +} + +BEGIN_CASE(JSOP_ENDFILTER) +{ + bool cond = !regs.sp[-1].isMagic(); + if (cond) { + /* Exit the "with" block left from the previous iteration. */ + js_LeaveWith(cx); + } + if (!js_StepXMLListFilter(cx, cond)) + goto error; + if (!regs.sp[-1].isNull()) { + /* + * Decrease sp after EnterWith returns as we use sp[-1] there to root + * temporaries. + */ + JS_ASSERT(IsXML(regs.sp[-1])); + if (!js_EnterWith(cx, -2)) + goto error; + regs.sp--; + len = GET_JUMP_OFFSET(regs.pc); + JS_ASSERT(len < 0); + BRANCH(len); + } + regs.sp--; +} +END_CASE(JSOP_ENDFILTER); + +BEGIN_CASE(JSOP_TOXML) +{ + Value rval = regs.sp[-1]; + JSObject *obj = js_ValueToXMLObject(cx, rval); + if (!obj) + goto error; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_TOXML) + +BEGIN_CASE(JSOP_TOXMLLIST) +{ + Value rval = regs.sp[-1]; + JSObject *obj = js_ValueToXMLListObject(cx, rval); + if (!obj) + goto error; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_TOXMLLIST) + +BEGIN_CASE(JSOP_XMLTAGEXPR) +{ + Value rval = regs.sp[-1]; + JSString *str = js_ValueToString(cx, rval); + if (!str) + goto error; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_XMLTAGEXPR) + +BEGIN_CASE(JSOP_XMLELTEXPR) +{ + Value rval = regs.sp[-1]; + JSString *str; + if (IsXML(rval)) { + str = js_ValueToXMLString(cx, rval); + } else { + str = js_ValueToString(cx, rval); + if (str) + str = js_EscapeElementValue(cx, str); + } + if (!str) + goto error; + regs.sp[-1].setString(str); +} +END_CASE(JSOP_XMLELTEXPR) + +BEGIN_CASE(JSOP_XMLCDATA) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + JSString *str = ATOM_TO_STRING(atom); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str); + if (!obj) + goto error; + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_XMLCDATA) + +BEGIN_CASE(JSOP_XMLCOMMENT) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + JSString *str = ATOM_TO_STRING(atom); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str); + if (!obj) + goto error; + PUSH_OBJECT(*obj); +} +END_CASE(JSOP_XMLCOMMENT) + +BEGIN_CASE(JSOP_XMLPI) +{ + JSAtom *atom; + LOAD_ATOM(0, atom); + JSString *str = ATOM_TO_STRING(atom); + Value rval = regs.sp[-1]; + JSString *str2 = rval.toString(); + JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, str, str2); + if (!obj) + goto error; + regs.sp[-1].setObject(*obj); +} +END_CASE(JSOP_XMLPI) + +BEGIN_CASE(JSOP_GETFUNNS) +{ + Value rval; + if (!js_GetFunctionNamespace(cx, &rval)) + goto error; + PUSH_COPY(rval); +} +END_CASE(JSOP_GETFUNNS) +#endif /* JS_HAS_XML_SUPPORT */ + +BEGIN_CASE(JSOP_ENTERBLOCK) +{ + JSObject *obj; + LOAD_OBJECT(0, obj); + JS_ASSERT(!OBJ_IS_CLONED_BLOCK(obj)); + JS_ASSERT(fp->base() + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp); + Value *vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj); + JS_ASSERT(regs.sp < vp); + JS_ASSERT(vp <= fp->slots() + script->nslots); + SetValueRangeToUndefined(regs.sp, vp); + regs.sp = vp; + +#ifdef DEBUG + JS_ASSERT(fp->blockChain == obj->getParent()); + + /* + * The young end of fp->scopeChain may omit blocks if we haven't closed + * over them, but if there are any closure blocks on fp->scopeChain, they'd + * better be (clones of) ancestors of the block we're entering now; + * anything else we should have popped off fp->scopeChain when we left its + * static scope. + */ + JSObject *obj2 = fp->scopeChain; + Class *clasp; + while ((clasp = obj2->getClass()) == &js_WithClass) + obj2 = obj2->getParent(); + if (clasp == &js_BlockClass && + obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) { + JSObject *youngestProto = obj2->getProto(); + JS_ASSERT(!OBJ_IS_CLONED_BLOCK(youngestProto)); + JSObject *parent = obj; + while ((parent = parent->getParent()) != youngestProto) + JS_ASSERT(parent); + } +#endif + + fp->blockChain = obj; +} +END_CASE(JSOP_ENTERBLOCK) + +BEGIN_CASE(JSOP_LEAVEBLOCKEXPR) +BEGIN_CASE(JSOP_LEAVEBLOCK) +{ +#ifdef DEBUG + JS_ASSERT(fp->blockChain->getClass() == &js_BlockClass); + uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain); + + JS_ASSERT(blockDepth <= StackDepth(script)); +#endif + /* + * If we're about to leave the dynamic scope of a block that has been + * cloned onto fp->scopeChain, clear its private data, move its locals from + * the stack into the clone, and pop it off the chain. + */ + JSObject *obj = fp->scopeChain; + if (obj->getProto() == fp->blockChain) { + JS_ASSERT(obj->getClass() == &js_BlockClass); + if (!js_PutBlockObject(cx, JS_TRUE)) + goto error; + } + + /* Pop the block chain, too. */ + fp->blockChain = fp->blockChain->getParent(); + + /* Move the result of the expression to the new topmost stack slot. */ + Value *vp = NULL; /* silence GCC warnings */ + if (op == JSOP_LEAVEBLOCKEXPR) + vp = ®s.sp[-1]; + regs.sp -= GET_UINT16(regs.pc); + if (op == JSOP_LEAVEBLOCKEXPR) { + JS_ASSERT(fp->base() + blockDepth == regs.sp - 1); + regs.sp[-1] = *vp; + } else { + JS_ASSERT(fp->base() + blockDepth == regs.sp); + } +} +END_CASE(JSOP_LEAVEBLOCK) + +#if JS_HAS_GENERATORS +BEGIN_CASE(JSOP_GENERATOR) +{ + ASSERT_NOT_THROWING(cx); + regs.pc += JSOP_GENERATOR_LENGTH; + JSObject *obj = js_NewGenerator(cx); + if (!obj) + goto error; + JS_ASSERT(!fp->callobj && !fp->argsobj); + fp->rval.setObject(*obj); + interpReturnOK = true; + if (inlineCallCount != 0) + goto inline_return; + goto exit; +} + +BEGIN_CASE(JSOP_YIELD) + ASSERT_NOT_THROWING(cx); + if (cx->generatorFor(fp)->state == JSGEN_CLOSING) { + js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, + JSDVG_SEARCH_STACK, fp->argv[-2], NULL); + goto error; + } + fp->rval = regs.sp[-1]; + fp->flags |= JSFRAME_YIELDING; + regs.pc += JSOP_YIELD_LENGTH; + interpReturnOK = JS_TRUE; + goto exit; + +BEGIN_CASE(JSOP_ARRAYPUSH) +{ + uint32 slot = GET_UINT16(regs.pc); + JS_ASSERT(script->nfixed <= slot); + JS_ASSERT(slot < script->nslots); + JSObject *obj = &fp->slots()[slot].toObject(); + if (!js_ArrayCompPush(cx, obj, regs.sp[-1])) + goto error; + regs.sp--; +} +END_CASE(JSOP_ARRAYPUSH) +#endif /* JS_HAS_GENERATORS */ + + L_JSOP_UNUSED180: + +#if JS_THREADED_INTERP + L_JSOP_BACKPATCH: + L_JSOP_BACKPATCH_POP: + +# if !JS_HAS_GENERATORS + L_JSOP_GENERATOR: + L_JSOP_YIELD: + L_JSOP_ARRAYPUSH: +# endif + +# if !JS_HAS_SHARP_VARS + L_JSOP_DEFSHARP: + L_JSOP_USESHARP: + L_JSOP_SHARPINIT: +# endif + +# if !JS_HAS_DESTRUCTURING + L_JSOP_ENUMCONSTELEM: +# endif + +# if !JS_HAS_XML_SUPPORT + L_JSOP_CALLXMLNAME: + L_JSOP_STARTXMLEXPR: + L_JSOP_STARTXML: + L_JSOP_DELDESC: + L_JSOP_GETFUNNS: + L_JSOP_XMLPI: + L_JSOP_XMLCOMMENT: + L_JSOP_XMLCDATA: + L_JSOP_XMLELTEXPR: + L_JSOP_XMLTAGEXPR: + L_JSOP_TOXMLLIST: + L_JSOP_TOXML: + L_JSOP_ENDFILTER: + L_JSOP_FILTER: + L_JSOP_DESCENDANTS: + L_JSOP_XMLNAME: + L_JSOP_SETXMLNAME: + L_JSOP_BINDXMLNAME: + L_JSOP_ADDATTRVAL: + L_JSOP_ADDATTRNAME: + L_JSOP_TOATTRVAL: + L_JSOP_TOATTRNAME: + L_JSOP_QNAME: + L_JSOP_QNAMECONST: + L_JSOP_QNAMEPART: + L_JSOP_ANYNAME: + L_JSOP_DEFXMLNS: +# endif + + L_JSOP_UNUSED218: + +#endif /* !JS_THREADED_INTERP */ #if !JS_THREADED_INTERP default: -#endif -#ifndef JS_TRACER - bad_opcode: #endif { char numBuf[12]; @@ -2509,7 +6839,7 @@ js_Interpret(JSContext *cx) if (!cx->throwing) { /* This is an error, not a catchable exception, quit the frame ASAP. */ - ok = JS_FALSE; + interpReturnOK = JS_FALSE; } else { JSThrowHook handler; JSTryNote *tn, *tnlimit; @@ -2518,7 +6848,8 @@ js_Interpret(JSContext *cx) /* Call debugger throw hook if set. */ handler = cx->debugHooks->throwHook; if (handler) { - switch (handler(cx, script, regs.pc, &rval, + Value rval; + switch (handler(cx, script, regs.pc, Jsvalify(&rval), cx->debugHooks->throwHookData)) { case JSTRAP_ERROR: cx->throwing = JS_FALSE; @@ -2526,7 +6857,7 @@ js_Interpret(JSContext *cx) case JSTRAP_RETURN: cx->throwing = JS_FALSE; fp->rval = rval; - ok = JS_TRUE; + interpReturnOK = JS_TRUE; goto forced_return; case JSTRAP_THROW: cx->exception = rval; @@ -2568,7 +6899,7 @@ js_Interpret(JSContext *cx) * with the stack depth exceeding the current one and this * condition is what we use to filter them out. */ - if (tn->stackDepth > regs.sp - StackBase(fp)) + if (tn->stackDepth > regs.sp - fp->base()) continue; /* @@ -2578,8 +6909,8 @@ js_Interpret(JSContext *cx) */ regs.pc = (script)->main + tn->start + tn->length; - ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE); - JS_ASSERT(regs.sp == StackBase(fp) + tn->stackDepth); + JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE); + JS_ASSERT(regs.sp == fp->base() + tn->stackDepth); if (!ok) { /* * Restart the handler search with updated pc and stack depth @@ -2594,7 +6925,7 @@ js_Interpret(JSContext *cx) #if JS_HAS_GENERATORS /* Catch cannot intercept the closing of a generator. */ - if (JS_UNLIKELY(cx->exception == JSVAL_ARETURN)) + if (JS_UNLIKELY(cx->exception.isMagic(JS_GENERATOR_CLOSING))) break; #endif @@ -2611,8 +6942,8 @@ js_Interpret(JSContext *cx) * Push (true, exception) pair for finally to indicate that * [retsub] should rethrow the exception. */ - PUSH(JSVAL_TRUE); - PUSH(cx->exception); + PUSH_BOOLEAN(true); + PUSH_COPY(cx->exception); cx->throwing = JS_FALSE; len = 0; DO_NEXT_OP(len); @@ -2622,7 +6953,7 @@ js_Interpret(JSContext *cx) JS_ASSERT(js_GetOpcode(cx, fp->script, regs.pc) == JSOP_ENDITER); AutoValueRooter tvr(cx, cx->exception); cx->throwing = false; - ok = js_CloseIterator(cx, regs.sp[-1]); + ok = js_CloseIterator(cx, ®s.sp[-1].toObject()); regs.sp -= 1; if (!ok) goto error; @@ -2637,26 +6968,27 @@ js_Interpret(JSContext *cx) * Propagate the exception or error to the caller unless the exception * is an asynchronous return from a generator. */ - ok = JS_FALSE; + interpReturnOK = JS_FALSE; #if JS_HAS_GENERATORS - if (JS_UNLIKELY(cx->throwing && cx->exception == JSVAL_ARETURN)) { + if (JS_UNLIKELY(cx->throwing && + cx->exception.isMagic(JS_GENERATOR_CLOSING))) { cx->throwing = JS_FALSE; - ok = JS_TRUE; - fp->rval = JSVAL_VOID; + interpReturnOK = JS_TRUE; + fp->rval.setUndefined(); } #endif } forced_return: /* - * Unwind the scope making sure that ok stays false even when js_UnwindScope - * returns true. + * Unwind the scope making sure that interpReturnOK stays false even when + * js_UnwindScope returns true. * - * When a trap handler returns JSTRAP_RETURN, we jump here with ok set to - * true bypassing any finally blocks. + * When a trap handler returns JSTRAP_RETURN, we jump here with + * interpReturnOK set to true bypassing any finally blocks. */ - ok &= js_UnwindScope(cx, 0, ok || cx->throwing); - JS_ASSERT(regs.sp == StackBase(fp)); + interpReturnOK &= js_UnwindScope(cx, 0, interpReturnOK || cx->throwing); + JS_ASSERT(regs.sp == fp->base()); #ifdef DEBUG cx->tracePrevPc = NULL; @@ -2684,30 +7016,32 @@ js_Interpret(JSContext *cx) #ifdef JS_TRACER if (TRACE_RECORDER(cx)) - AbortRecording(cx, "recording out of js_Interpret"); + AbortRecording(cx, "recording out of Interpret"); #endif JS_ASSERT_IF(!fp->isGenerator(), !fp->blockChain); JS_ASSERT_IF(!fp->isGenerator(), !js_IsActiveWithOrBlock(cx, fp->scopeChain, 0)); - /* Undo the remaining effects committed on entry to js_Interpret. */ + /* Undo the remaining effects committed on entry to Interpret. */ if (script->staticLevel < JS_DISPLAY_SIZE) cx->display[script->staticLevel] = fp->displaySave; if (cx->version == currentVersion && currentVersion != originalVersion) js_SetVersion(cx, originalVersion); --cx->interpLevel; - return ok; + return interpReturnOK; atom_not_defined: { const char *printable; - printable = js_AtomToPrintableString(cx, atom); + printable = js_AtomToPrintableString(cx, atomNotDefined); if (printable) js_ReportIsNotDefined(cx, printable); goto error; } } +} /* namespace js */ + #endif /* !defined jsinvoke_cpp___ */ diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 1749c734fee9..495bcafe488a 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -48,12 +48,11 @@ #include "jsfun.h" #include "jsopcode.h" #include "jsscript.h" - -JS_BEGIN_EXTERN_C +#include "jsvalue.h" typedef struct JSFrameRegs { jsbytecode *pc; /* program counter */ - jsval *sp; /* stack pointer */ + js::Value *sp; /* stack pointer */ } JSFrameRegs; /* JS stack frame flags. */ @@ -85,14 +84,13 @@ struct JSStackFrame { jsbytecode *imacpc; /* null or interpreter macro call pc */ JSObject *callobj; /* lazily created Call object */ - jsval argsobj; /* lazily created arguments object, must be - JSVAL_OBJECT */ + JSObject *argsobj; /* lazily created arguments object */ JSScript *script; /* script being interpreted */ JSFunction *fun; /* function being called or null */ - jsval thisv; /* "this" pointer if in method */ + js::Value thisv; /* "this" pointer if in method */ uintN argc; /* actual argument count */ - jsval *argv; /* base of argument stack slots */ - jsval rval; /* function return value */ + js::Value *argv; /* base of argument stack slots */ + js::Value rval; /* function return value */ void *annotation; /* used by Java security */ /* Maintained by StackSpace operations */ @@ -139,10 +137,7 @@ struct JSStackFrame * also used in some other cases --- entering 'with' blocks, for * example. */ - union { - JSObject *scopeChain; - jsval scopeChainVal; - }; + JSObject *scopeChain; JSObject *blockChain; uint32 flags; /* frame flags -- see below */ @@ -169,26 +164,25 @@ struct JSStackFrame /* Get the frame's current bytecode, assuming |this| is in |cx|. */ jsbytecode *pc(JSContext *cx) const; - jsval *argEnd() const { - return (jsval *)this; + js::Value *argEnd() const { + return (js::Value *)this; } - jsval *slots() const { - return (jsval *)(this + 1); + js::Value *slots() const { + return (js::Value *)(this + 1); } - jsval calleeValue() { + js::Value *base() const { + return slots() + script->nfixed; + } + + const js::Value &calleeValue() { JS_ASSERT(argv); return argv[-2]; } - JSObject *calleeObject() { - JS_ASSERT(argv); - return JSVAL_TO_OBJECT(argv[-2]); - } - JSObject *callee() { - return argv ? JSVAL_TO_OBJECT(argv[-2]) : NULL; + return argv ? &argv[-2].toObject() : NULL; } /* @@ -203,13 +197,10 @@ struct JSStackFrame inline JSObject *getThisObject(JSContext *cx); - bool isGenerator() const { return flags & JSFRAME_GENERATOR; } + bool isGenerator() const { return !!(flags & JSFRAME_GENERATOR); } bool isFloatingGenerator() const { - if (flags & JSFRAME_FLOATING_GENERATOR) { - JS_ASSERT(isGenerator()); - return true; - } - return false; + JS_ASSERT_IF(flags & JSFRAME_FLOATING_GENERATOR, isGenerator()); + return !!(flags & JSFRAME_FLOATING_GENERATOR); } bool isDummyFrame() const { return !script && !fun; } @@ -217,16 +208,13 @@ struct JSStackFrame namespace js { -static const size_t VALUES_PER_STACK_FRAME = sizeof(JSStackFrame) / sizeof(jsval); -JS_STATIC_ASSERT(sizeof(JSStackFrame) % sizeof(jsval) == 0); +JS_STATIC_ASSERT(sizeof(JSStackFrame) % sizeof(Value) == 0); +static const size_t VALUES_PER_STACK_FRAME = sizeof(JSStackFrame) / sizeof(Value); -} +JS_STATIC_ASSERT(offsetof(JSStackFrame, rval) % sizeof(Value) == 0); +JS_STATIC_ASSERT(offsetof(JSStackFrame, thisv) % sizeof(Value) == 0); -static JS_INLINE jsval * -StackBase(JSStackFrame *fp) -{ - return fp->slots() + fp->script->nfixed; -} +} /* namespace js */ static JS_INLINE uintN GlobalVarCount(JSStackFrame *fp) @@ -252,10 +240,13 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp); * instance of clasp and extract its private slot value to return via *thisvp. * * NB: this function loads and uses *vp before storing *thisvp, so the two may - * alias the same jsval. + * alias the same Value. */ extern JSBool -js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp); +js_GetPrimitiveThis(JSContext *cx, js::Value *vp, js::Class *clasp, + const js::Value **vpp); + +namespace js { /* * For a call with arguments argv including argv[-1] (nominal |this|) and @@ -265,14 +256,22 @@ js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp); * must not be a JSVAL_VOID. */ extern JSObject * -js_ComputeThis(JSContext *cx, jsval *argv); +ComputeThisFromArgv(JSContext *cx, js::Value *argv); -extern const uint16 js_PrimitiveTestFlags[]; +JS_ALWAYS_INLINE JSObject * +ComputeThisFromVp(JSContext *cx, js::Value *vp) +{ + return ComputeThisFromArgv(cx, vp + 2); +} -#define PRIMITIVE_THIS_TEST(fun,thisv) \ - (JS_ASSERT(!JSVAL_IS_VOID(thisv)), \ - JSFUN_THISP_TEST(JSFUN_THISP_FLAGS((fun)->flags), \ - js_PrimitiveTestFlags[JSVAL_TAG(thisv) - 1])) +JS_ALWAYS_INLINE bool +PrimitiveThisTest(JSFunction *fun, const Value &v) +{ + uint16 flags = fun->flags; + return (v.isString() && !!(flags & JSFUN_THISP_STRING)) || + (v.isNumber() && !!(flags & JSFUN_THISP_NUMBER)) || + (v.isBoolean() && !!(flags & JSFUN_THISP_BOOLEAN)); +} /* * The js::InvokeArgumentsGuard passed to js_Invoke must come from an @@ -282,8 +281,11 @@ extern const uint16 js_PrimitiveTestFlags[]; * and the range [args.getvp() + 2, args.getvp() + 2 + args.getArgc()) should * be initialized actual arguments. */ -extern JS_REQUIRES_STACK JS_FRIEND_API(JSBool) -js_Invoke(JSContext *cx, const js::InvokeArgsGuard &args, uintN flags); +extern JS_REQUIRES_STACK bool +Invoke(JSContext *cx, const InvokeArgsGuard &args, uintN flags); + +extern JS_REQUIRES_STACK JS_FRIEND_API(bool) +InvokeFriendAPI(JSContext *cx, const InvokeArgsGuard &args, uintN flags); /* * Consolidated js_Invoke flags simply rename certain JSFRAME_* flags, so that @@ -309,51 +311,81 @@ js_Invoke(JSContext *cx, const js::InvokeArgsGuard &args, uintN flags); * "Internal" calls may come from C or C++ code using a JSContext on which no * JS is running (!cx->fp), so they may need to push a dummy JSStackFrame. */ -#define js_InternalCall(cx,obj,fval,argc,argv,rval) \ - js_InternalInvoke(cx, OBJECT_TO_JSVAL(obj), fval, 0, argc, argv, rval) - -#define js_InternalConstruct(cx,obj,fval,argc,argv,rval) \ - js_InternalInvoke(cx, OBJECT_TO_JSVAL(obj), fval, JSINVOKE_CONSTRUCT, argc, argv, rval) - extern JSBool -js_InternalInvoke(JSContext *cx, jsval thisv, jsval fval, uintN flags, - uintN argc, jsval *argv, jsval *rval); +InternalInvoke(JSContext *cx, const Value &thisv, const Value &fval, uintN flags, + uintN argc, Value *argv, Value *rval); -extern JSBool -js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval, - JSAccessMode mode, uintN argc, jsval *argv, jsval *rval); +static JS_ALWAYS_INLINE bool +InternalCall(JSContext *cx, JSObject *obj, const Value &fval, + uintN argc, Value *argv, Value *rval) +{ + return InternalInvoke(cx, ObjectOrNullValue(obj), fval, 0, argc, argv, rval); +} -extern JS_FORCES_STACK JSBool -js_Execute(JSContext *cx, JSObject *chain, JSScript *script, - JSStackFrame *down, uintN flags, jsval *result); +static JS_ALWAYS_INLINE bool +InternalConstruct(JSContext *cx, JSObject *obj, const Value &fval, + uintN argc, Value *argv, Value *rval) +{ + return InternalInvoke(cx, ObjectOrNullValue(obj), fval, JSINVOKE_CONSTRUCT, argc, argv, rval); +} -extern JS_REQUIRES_STACK JSBool -js_InvokeConstructor(JSContext *cx, const js::InvokeArgsGuard &args); +extern bool +InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, const Value &fval, + JSAccessMode mode, uintN argc, Value *argv, Value *rval); -extern JS_REQUIRES_STACK JSBool -js_Interpret(JSContext *cx); +extern JS_FORCES_STACK bool +Execute(JSContext *cx, JSObject *chain, JSScript *script, + JSStackFrame *down, uintN flags, Value *result); + +extern JS_REQUIRES_STACK bool +InvokeConstructor(JSContext *cx, const InvokeArgsGuard &args); + +extern JS_REQUIRES_STACK bool +Interpret(JSContext *cx); #define JSPROP_INITIALIZER 0x100 /* NB: Not a valid property attribute. */ -extern JSBool -js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, - JSObject **objp, JSProperty **propp); +extern bool +CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, + JSObject **objp, JSProperty **propp); -extern JSBool -js_StrictlyEqual(JSContext *cx, jsval lval, jsval rval); +extern bool +StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval); /* === except that NaN is the same as NaN and -0 is not the same as +0. */ -extern JSBool -js_SameValue(jsval v1, jsval v2, JSContext *cx); +extern bool +SameValue(const Value &v1, const Value &v2, JSContext *cx); -extern JSBool -js_InternNonIntElementId(JSContext *cx, JSObject *obj, jsval idval, jsid *idp); +extern JSType +TypeOfValue(JSContext *cx, const Value &v); + +inline bool +InstanceOf(JSContext *cx, JSObject *obj, Class *clasp, Value *argv) +{ + if (obj && obj->getClass() == clasp) + return true; + extern bool InstanceOfSlow(JSContext *, JSObject *, Class *, Value *); + return InstanceOfSlow(cx, obj, clasp, argv); +} + +inline void * +GetInstancePrivate(JSContext *cx, JSObject *obj, Class *clasp, Value *argv) +{ + if (!InstanceOf(cx, obj, clasp, argv)) + return NULL; + return obj->getPrivate(); +} + +extern bool +ValueToId(JSContext *cx, const Value &v, jsid *idp); + +} /* namespace js */ /* * Given an active context, a static scope level, and an upvar cookie, return * the value of the upvar. */ -extern jsval & +extern const js::Value & js_GetUpvar(JSContext *cx, uintN level, js::UpvarCookie cookie); /* @@ -382,31 +414,13 @@ js_GetUpvar(JSContext *cx, uintN level, js::UpvarCookie cookie); #else # define JS_STATIC_INTERPRET -/* - * ECMA requires "the global object", but in embeddings such as the browser, - * which have multiple top-level objects (windows, frames, etc. in the DOM), - * we prefer fun's parent. An example that causes this code to run: - * - * // in window w1 - * function f() { return this } - * function g() { return f } - * - * // in window w2 - * var h = w1.g() - * alert(h() == w1) - * - * The alert should display "true". - */ -extern JSObject * -js_ComputeGlobalThis(JSContext *cx, jsval *argv); - extern JS_REQUIRES_STACK JSBool js_EnterWith(JSContext *cx, jsint stackIndex); extern JS_REQUIRES_STACK void js_LeaveWith(JSContext *cx); -extern JS_REQUIRES_STACK JSClass * +extern JS_REQUIRES_STACK js::Class * js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth); /* @@ -417,7 +431,7 @@ extern JS_REQUIRES_STACK JSBool js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind); extern JSBool -js_OnUnknownMethod(JSContext *cx, jsval *vp); +js_OnUnknownMethod(JSContext *cx, js::Value *vp); /* * Find the results of incrementing or decrementing *vp. For pre-increments, @@ -426,7 +440,7 @@ js_OnUnknownMethod(JSContext *cx, jsval *vp); * the result. Both vp and vp2 must be roots. */ extern JSBool -js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, jsval *vp, jsval *vp2); +js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, js::Value *vp, js::Value *vp2); /* * Opcode tracing helper. When len is not 0, cx->fp->regs->pc[-len] gives the @@ -446,19 +460,16 @@ js_MeterSlotOpcode(JSOp op, uint32 slot); #endif /* JS_LONE_INTERPRET */ -JS_END_EXTERN_C - inline JSObject * JSStackFrame::getThisObject(JSContext *cx) { if (flags & JSFRAME_COMPUTED_THIS) - return JSVAL_TO_OBJECT(thisv); /* JSVAL_COMPUTED_THIS invariant */ - JSObject* obj = js_ComputeThis(cx, argv); - if (!obj) + return &thisv.toObject(); + if (!js::ComputeThisFromArgv(cx, argv)) return NULL; - thisv = OBJECT_TO_JSVAL(obj); + thisv = argv[-1]; flags |= JSFRAME_COMPUTED_THIS; - return obj; + return &thisv.toObject(); } #endif /* jsinterp_h___ */ diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 55c7f0555970..3cfd0c3d876b 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -85,14 +85,14 @@ static void iterator_finalize(JSContext *cx, JSObject *obj); static void iterator_trace(JSTracer *trc, JSObject *obj); static JSObject *iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly); -JSExtendedClass js_IteratorClass = { +ExtendedClass js_IteratorClass = { { "Iterator", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) | JSCLASS_MARK_IS_TRACE | JSCLASS_IS_EXTENDED, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, iterator_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, iterator_finalize, NULL, NULL, NULL, NULL, NULL, NULL, JS_CLASS_TRACE(iterator_trace), NULL }, NULL, NULL, NULL, iterator_iterator, @@ -103,11 +103,12 @@ JSExtendedClass js_IteratorClass = { void NativeIterator::mark(JSTracer *trc) { - for (jsval *vp = props_array; vp < props_end; ++vp) { - JS_SET_TRACING_INDEX(trc, "props", (vp - props_array)); - js_CallValueTracerIfGCThing(trc, *vp); - } - JS_CALL_OBJECT_TRACER(trc, obj, "obj"); + if (isKeyIter()) + MarkIdRange(trc, beginKey(), endKey(), "props"); + else + MarkValueRange(trc, beginValue(), endValue(), "props"); + if (obj) + MarkObject(trc, obj, "obj"); } /* @@ -136,43 +137,75 @@ iterator_trace(JSTracer *trc, JSObject *obj) ni->mark(trc); } -static bool -NewKeyValuePair(JSContext *cx, jsid key, jsval val, jsval *rval) +struct IdHashPolicy { + typedef jsid Lookup; + static HashNumber hash(jsid id) { + return JSID_BITS(id); + } + static bool match(jsid id1, jsid id2) { + return id1 == id2; + } +}; + +typedef HashSet IdSet; + +static inline bool +NewKeyValuePair(JSContext *cx, jsid id, const Value &val, Value *rval) { - jsval vec[2] = { ID_TO_VALUE(key), val }; + Value vec[2] = { IdToValue(id), val }; AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); JSObject *aobj = js_NewArrayObject(cx, 2, vec); if (!aobj) return false; - *rval = OBJECT_TO_JSVAL(aobj); + rval->setObject(*aobj); return true; } -static bool -IdToIteratorValue(JSContext *cx, JSObject *obj, jsid id, uintN flags, jsval *vp) +struct KeyEnumeration { - if (!(flags & JSITER_FOREACH)) { - *vp = ID_TO_VALUE(id); + typedef AutoIdVector ResultVector; + + static JS_ALWAYS_INLINE bool + append(JSContext *, AutoIdVector &keys, JSObject *, jsid id, uintN flags) + { + JS_ASSERT((flags & JSITER_FOREACH) == 0); + return keys.append(id); + } +}; + +struct ValueEnumeration +{ + typedef AutoValueVector ResultVector; + + static JS_ALWAYS_INLINE bool + append(JSContext *cx, AutoValueVector &vals, JSObject *obj, jsid id, uintN flags) + { + JS_ASSERT(flags & JSITER_FOREACH); + + if (!vals.growBy(1)) + return false; + + /* Do the lookup on the original object instead of the prototype. */ + Value *vp = vals.end() - 1; + if (!obj->getProperty(cx, id, vp)) + return false; + if ((flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, *vp, vp)) + return false; + return true; } +}; - /* Do the lookup on the original object instead of the prototype. */ - if (!obj->getProperty(cx, id, vp)) - return false; - if ((flags & JSITER_KEYVALUE) && !NewKeyValuePair(cx, id, *vp, vp)) - return false; - return true; -} - +template static inline bool Enumerate(JSContext *cx, JSObject *obj, JSObject *pobj, jsid id, - bool enumerable, bool sharedPermanent, uintN flags, HashSet& ht, - AutoValueVector& vec) + bool enumerable, bool sharedPermanent, uintN flags, IdSet& ht, + typename EnumPolicy::ResultVector &props) { - JS_ASSERT(JSVAL_IS_INT(id) || JSVAL_IS_STRING(id)); + JS_ASSERT(JSID_IS_INT(id) || JSID_IS_ATOM(id)); - HashSet::AddPtr p = ht.lookupForAdd(id); + IdSet::AddPtr p = ht.lookupForAdd(id); JS_ASSERT_IF(obj == pobj, !p); /* If we've already seen this, we definitely won't add it. */ @@ -201,62 +234,56 @@ Enumerate(JSContext *cx, JSObject *obj, JSObject *pobj, jsid id, return true; } - if (enumerable || (flags & JSITER_HIDDEN)) { - if (!vec.append(JSVAL_VOID)) - return false; - if (!IdToIteratorValue(cx, obj, id, flags, vec.end() - 1)) - return false; - } + if (enumerable || (flags & JSITER_HIDDEN)) + return EnumPolicy::append(cx, props, obj, id, flags); + return true; } +template static bool -EnumerateNativeProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags, - HashSet &ht, AutoValueVector& props) +EnumerateNativeProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags, IdSet &ht, + typename EnumPolicy::ResultVector &props) { - AutoValueVector sprops(cx); - JS_LOCK_OBJ(cx, pobj); + size_t initialLength = props.length(); + /* Collect all unique properties from this object's scope. */ JSScope *scope = pobj->scope(); for (JSScopeProperty *sprop = scope->lastProperty(); sprop; sprop = sprop->parent) { - if (sprop->id != JSVAL_VOID && + if (!JSID_IS_DEFAULT_XML_NAMESPACE(sprop->id) && !sprop->isAlias() && - !Enumerate(cx, obj, pobj, sprop->id, sprop->enumerable(), sprop->isSharedPermanent(), - flags, ht, sprops)) + !Enumerate(cx, obj, pobj, sprop->id, sprop->enumerable(), sprop->isSharedPermanent(), + flags, ht, props)) { return false; } } - while (sprops.length() > 0) { - if (!props.append(sprops.back())) - return false; - sprops.popBack(); - } + Reverse(props.begin() + initialLength, props.end()); JS_UNLOCK_SCOPE(cx, scope); - return true; } +template static bool EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uintN flags, - HashSet &ht, AutoValueVector& props) + IdSet &ht, typename EnumPolicy::ResultVector &props) { - if (!Enumerate(cx, obj, pobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), false, true, - flags, ht, props)) { + if (!Enumerate(cx, obj, pobj, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), false, true, + flags, ht, props)) { return false; } if (pobj->getDenseArrayCount() > 0) { size_t capacity = pobj->getDenseArrayCapacity(); - jsval *vp = pobj->dslots; + Value *vp = pobj->dslots; for (size_t i = 0; i < capacity; ++i, ++vp) { - if (*vp != JSVAL_HOLE) { + if (!vp->isMagic(JS_ARRAY_HOLE)) { /* Dense arrays never get so large that i would not fit into an integer id. */ - if (!Enumerate(cx, obj, pobj, INT_TO_JSVAL(i), true, false, flags, ht, props)) + if (!Enumerate(cx, obj, pobj, INT_TO_JSID(i), true, false, flags, ht, props)) return false; } } @@ -265,57 +292,35 @@ EnumerateDenseArrayProperties(JSContext *cx, JSObject *obj, JSObject *pobj, uint return true; } -NativeIterator * -NativeIterator::allocate(JSContext *cx, JSObject *obj, uintN flags, uint32 *sarray, uint32 slength, - uint32 key, AutoValueVector &props) -{ - size_t plength = props.length(); - NativeIterator *ni = (NativeIterator *) - cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsval) + slength * sizeof(uint32)); - if (!ni) - return NULL; - ni->obj = obj; - ni->props_array = ni->props_cursor = (jsval *) (ni + 1); - ni->props_end = ni->props_array + plength; - if (plength) - memcpy(ni->props_array, props.begin(), plength * sizeof(jsval)); - ni->shapes_array = (uint32 *) ni->props_end; - ni->shapes_length = slength; - ni->shapes_key = key; - ni->flags = flags; - if (slength) - memcpy(ni->shapes_array, sarray, slength * sizeof(uint32)); - return ni; -} - +template static bool -Snapshot(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &props) +Snapshot(JSContext *cx, JSObject *obj, uintN flags, typename EnumPolicy::ResultVector &props) { /* * FIXME: Bug 575997 - We won't need to initialize this hash table if * (flags & JSITER_OWNONLY) when we eliminate inheritance of * shared-permanent properties as own properties. */ - HashSet ht(cx); + IdSet ht(cx); if (!ht.init(32)) - return false; + return NULL; JSObject *pobj = obj; do { - JSClass *clasp = pobj->getClass(); + Class *clasp = pobj->getClass(); if (pobj->isNative() && pobj->map->ops->enumerate == js_Enumerate && !(clasp->flags & JSCLASS_NEW_ENUMERATE)) { if (!clasp->enumerate(cx, pobj)) return false; - if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) + if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) return false; } else if (pobj->isDenseArray()) { - if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props)) + if (!EnumerateDenseArrayProperties(cx, obj, pobj, flags, ht, props)) return false; } else { if (pobj->isProxy()) { - AutoValueVector proxyProps(cx); + AutoIdVector proxyProps(cx); if (flags & JSITER_OWNONLY) { if (!JSProxy::enumerateOwn(cx, pobj, proxyProps)) return false; @@ -324,27 +329,27 @@ Snapshot(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &props) return false; } for (size_t n = 0, len = proxyProps.length(); n < len; n++) { - if (!Enumerate(cx, obj, pobj, (jsid) proxyProps[n], true, false, flags, ht, props)) + if (!Enumerate(cx, obj, pobj, proxyProps[n], true, false, flags, ht, props)) return false; } /* Proxy objects enumerate the prototype on their own, so we are done here. */ break; } - jsval state; + Value state; JSIterateOp op = (flags & JSITER_HIDDEN) ? JSENUMERATE_INIT_ALL : JSENUMERATE_INIT; if (!pobj->enumerate(cx, op, &state, NULL)) return false; - if (state == JSVAL_NATIVE_ENUMERATE_COOKIE) { - if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) + if (state.isMagic(JS_NATIVE_ENUMERATE)) { + if (!EnumerateNativeProperties(cx, obj, pobj, flags, ht, props)) return false; } else { while (true) { jsid id; if (!pobj->enumerate(cx, JSENUMERATE_NEXT, &state, &id)) return false; - if (state == JSVAL_NULL) + if (state.isNull()) break; - if (!Enumerate(cx, obj, pobj, id, true, false, flags, ht, props)) + if (!Enumerate(cx, obj, pobj, id, true, false, flags, ht, props)) return false; } } @@ -358,7 +363,7 @@ Snapshot(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &props) } bool -VectorToIdArray(JSContext *cx, AutoValueVector &props, JSIdArray **idap) +VectorToIdArray(JSContext *cx, AutoIdVector &props, JSIdArray **idap) { JS_STATIC_ASSERT(sizeof(JSIdArray) > sizeof(jsid)); size_t len = props.length(); @@ -375,13 +380,13 @@ VectorToIdArray(JSContext *cx, AutoValueVector &props, JSIdArray **idap) } bool -GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &props) +GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &props) { - return Snapshot(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), props); + return Snapshot(cx, obj, flags & (JSITER_OWNONLY | JSITER_HIDDEN), props); } static inline bool -GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) +GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp) { /* Check whether we have a valid __iterator__ method. */ JSAtom *atom = cx->runtime->atomState.iteratorAtom; @@ -389,21 +394,21 @@ GetCustomIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) return false; /* If there is no custom __iterator__ method, we are done here. */ - if (*vp == JSVAL_VOID) + if (vp->isUndefined()) return true; /* Otherwise call it and return that object. */ LeaveTrace(cx); - jsval arg = BOOLEAN_TO_JSVAL((flags & JSITER_FOREACH) == 0); - if (!js_InternalCall(cx, obj, *vp, 1, &arg, vp)) + Value arg = BooleanValue((flags & JSITER_FOREACH) == 0); + if (!InternalCall(cx, obj, *vp, 1, &arg, vp)) return false; - if (JSVAL_IS_PRIMITIVE(*vp)) { + if (vp->isPrimitive()) { /* * We are always coming from js_ValueToIterator, and we are no longer on * trace, so the object we are iterating over is on top of the stack (-1). */ js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE, - -1, OBJECT_TO_JSVAL(obj), NULL, + -1, ObjectValue(*obj), NULL, js_AtomToPrintableString(cx, atom)); return false; } @@ -445,13 +450,55 @@ NewIteratorObject(JSContext *cx, uintN flags) if (!obj) return false; obj->map = cx->runtime->emptyEnumeratorScope->hold(); - obj->init(&js_IteratorClass.base, NULL, NULL, JSVAL_NULL); + obj->init(&js_IteratorClass.base, NULL, NULL, NullValue()); return obj; } return NewBuiltinClassInstance(cx, &js_IteratorClass.base); } +NativeIterator * +NativeIterator::allocateKeyIterator(JSContext *cx, uint32 slength, const AutoIdVector &props) +{ + size_t plength = props.length(); + NativeIterator *ni = (NativeIterator *) + cx->malloc(sizeof(NativeIterator) + plength * sizeof(jsid) + slength * sizeof(uint32)); + if (!ni) + return NULL; + ni->props_array = ni->props_cursor = (jsid *) (ni + 1); + ni->props_end = (jsid *)ni->props_array + plength; + if (plength) + memcpy(ni->props_array, props.begin(), plength * sizeof(jsid)); + return ni; +} + +NativeIterator * +NativeIterator::allocateValueIterator(JSContext *cx, uint32 slength, const AutoValueVector &props) +{ + size_t plength = props.length(); + NativeIterator *ni = (NativeIterator *) + cx->malloc(sizeof(NativeIterator) + plength * sizeof(Value) + slength * sizeof(uint32)); + if (!ni) + return NULL; + ni->props_array = ni->props_cursor = (Value *) (ni + 1); + ni->props_end = (Value *)ni->props_array + plength; + if (plength) + memcpy(ni->props_array, props.begin(), plength * sizeof(Value)); + return ni; +} + +inline void +NativeIterator::init(JSObject *obj, uintN flags, const uint32 *sarray, uint32 slength, uint32 key) +{ + this->obj = obj; + this->flags = flags; + this->shapes_array = (uint32 *) this->props_end; + this->shapes_length = slength; + this->shapes_key = key; + if (slength) + memcpy(this->shapes_array, sarray, slength * sizeof(uint32)); +} + static inline void RegisterEnumerator(JSContext *cx, JSObject *iterobj, NativeIterator *ni) { @@ -462,37 +509,89 @@ RegisterEnumerator(JSContext *cx, JSObject *iterobj, NativeIterator *ni) } } -bool -IdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &props, jsval *vp) +static inline bool +VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &keys, + const uint32 *sarray, uint32 slength, uint32 key, Value *vp) { + JS_ASSERT(!(flags & JSITER_FOREACH)); + JSObject *iterobj = NewIteratorObject(cx, flags); if (!iterobj) return false; - *vp = OBJECT_TO_JSVAL(iterobj); - NativeIterator *ni = NativeIterator::allocate(cx, obj, flags, NULL, 0, 0, props); + NativeIterator *ni = NativeIterator::allocateKeyIterator(cx, slength, keys); if (!ni) - return false; - - /* If this is a for-each iteration, fetch the values or key/value pairs. */ - if (flags & JSITER_FOREACH) { - size_t length = props.length(); - for (size_t n = 0; n < length; ++n) { - jsval *vp = &ni->begin()[n]; - if (!IdToIteratorValue(cx, obj, *vp, flags, vp)) - return false; - } - } + return NULL; + ni->init(obj, flags, sarray, slength, key); iterobj->setNativeIterator(ni); + vp->setObject(*iterobj); RegisterEnumerator(cx, iterobj, ni); return true; } bool -GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) +VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &props, Value *vp) +{ + return VectorToKeyIterator(cx, obj, flags, props, NULL, 0, 0, vp); +} + +static inline bool +VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &vals, + const uint32 *sarray, uint32 slength, uint32 key, Value *vp) +{ + JS_ASSERT(flags & JSITER_FOREACH); + + JSObject *iterobj = NewIteratorObject(cx, flags); + if (!iterobj) + return false; + + NativeIterator *ni = NativeIterator::allocateValueIterator(cx, slength, vals); + if (!ni) + return NULL; + ni->init(obj, flags, sarray, slength, key); + + iterobj->setNativeIterator(ni); + vp->setObject(*iterobj); + + RegisterEnumerator(cx, iterobj, ni); + return true; +} + +bool +VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, AutoValueVector &props, Value *vp) +{ + return VectorToValueIterator(cx, obj, flags, props, NULL, 0, 0, vp); +} + +bool +EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, AutoIdVector &props, Value *vp) +{ + if (!(flags & JSITER_FOREACH)) + return VectorToKeyIterator(cx, obj, flags, props, vp); + + /* For for-each iteration, we need to look up the value of each id. */ + + size_t plength = props.length(); + + AutoValueVector vals(cx); + if (!vals.reserve(plength)) + return NULL; + + for (size_t i = 0; i < plength; ++i) { + if (!ValueEnumeration::append(cx, vals, obj, props[i], flags)) + return false; + } + + return VectorToValueIterator(cx, obj, flags, vals, vp); +} + +typedef Vector ShapeVector; + +bool +GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp) { uint32 hash; JSObject **hp; @@ -532,7 +631,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) if (ni->shapes_key == key && ni->shapes_length == shapes.length() && Compare(ni->shapes_array, shapes.begin(), ni->shapes_length)) { - *vp = OBJECT_TO_JSVAL(iterobj); + vp->setObject(*iterobj); *hp = ni->next; RegisterEnumerator(cx, iterobj, ni); @@ -546,31 +645,23 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp) return JSProxy::iterate(cx, obj, flags, vp); if (!GetCustomIterator(cx, obj, flags, vp)) return false; - if (*vp != JSVAL_VOID) + if (!vp->isUndefined()) return true; } - JSObject *iterobj = NewIteratorObject(cx, flags); - if (!iterobj) - return false; - - /* Store in *vp to protect it from GC (callers must root vp). */ - *vp = OBJECT_TO_JSVAL(iterobj); - /* NB: for (var p in null) succeeds by iterating over no properties. */ - AutoValueVector props(cx); - if (JS_LIKELY(obj != NULL) && !Snapshot(cx, obj, flags, props)) + + if (flags & JSITER_FOREACH) { + AutoValueVector vals(cx); + if (JS_LIKELY(obj != NULL) && !Snapshot(cx, obj, flags, vals)) + return false; + return VectorToValueIterator(cx, obj, flags, vals, shapes.begin(), shapes.length(), key, vp); + } + + AutoIdVector keys(cx); + if (JS_LIKELY(obj != NULL) && !Snapshot(cx, obj, flags, keys)) return false; - - NativeIterator *ni = - NativeIterator::allocate(cx, obj, flags, shapes.begin(), shapes.length(), key, props); - if (!ni) - return false; - - iterobj->setNativeIterator(ni); - - RegisterEnumerator(cx, iterobj, ni); - return true; + return VectorToKeyIterator(cx, obj, flags, keys, shapes.begin(), shapes.length(), key, vp); } static JSObject * @@ -580,7 +671,7 @@ iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly) } static JSBool -Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval) +Iterator(JSContext *cx, JSObject *iterobj, uintN argc, Value *argv, Value *rval) { JSBool keyonly; uintN flags; @@ -594,30 +685,29 @@ Iterator(JSContext *cx, JSObject *iterobj, uintN argc, jsval *argv, jsval *rval) JSBool js_ThrowStopIteration(JSContext *cx) { - jsval v; + Value v; JS_ASSERT(!JS_IsExceptionPending(cx)); if (js_FindClassObject(cx, NULL, JSProto_StopIteration, &v)) - JS_SetPendingException(cx, v); + SetPendingException(cx, v); return JS_FALSE; } static JSBool -iterator_next(JSContext *cx, uintN argc, jsval *vp) +iterator_next(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; - obj = JS_THIS_OBJECT(cx, vp); - if (!JS_InstanceOf(cx, obj, &js_IteratorClass.base, vp + 2)) + obj = ComputeThisFromVp(cx, vp); + if (!InstanceOf(cx, obj, &js_IteratorClass.base, vp + 2)) return false; if (!js_IteratorMore(cx, obj, vp)) return false; - if (*vp == JSVAL_FALSE) { + if (!vp->toBoolean()) { js_ThrowStopIteration(cx); return false; } - JS_ASSERT(*vp == JSVAL_TRUE); return js_IteratorNext(cx, obj, vp); } @@ -633,13 +723,8 @@ static JSFunctionSpec iterator_methods[] = { * Otherwise construct the default iterator. */ JS_FRIEND_API(JSBool) -js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) +js_ValueToIterator(JSContext *cx, uintN flags, Value *vp) { - JSObject *obj; - JSClass *clasp; - JSExtendedClass *xclasp; - JSObject *iterobj; - /* JSITER_KEYVALUE must always come with JSITER_FOREACH */ JS_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH); @@ -648,13 +733,12 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) * left in iterValue when a trace is left due to an operation time-out after * JSOP_MOREITER but before the value is picked up by FOR*. */ - cx->iterValue = JSVAL_HOLE; + cx->iterValue.setMagic(JS_NO_ITER_VALUE); - AutoValueRooter tvr(cx); - - if (!JSVAL_IS_PRIMITIVE(*vp)) { + JSObject *obj; + if (vp->isObject()) { /* Common case. */ - obj = JSVAL_TO_OBJECT(*vp); + obj = &vp->toObject(); } else { /* * Enumerating over null and undefined gives an empty enumerator. @@ -664,10 +748,10 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) * standard. */ if ((flags & JSITER_ENUMERATE)) { - if (!js_ValueToObject(cx, *vp, &obj)) + if (!js_ValueToObjectOrNull(cx, *vp, &obj)) return false; if (!obj) - return GetIterator(cx, obj, flags, vp); + return GetIterator(cx, NULL, flags, vp); } else { obj = js_ValueToNonNullObject(cx, *vp); if (!obj) @@ -675,17 +759,18 @@ js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp) } } - tvr.setObject(obj); + AutoObjectRooter tvr(cx, obj); - clasp = obj->getClass(); + Class *clasp = obj->getClass(); + ExtendedClass *xclasp; if ((clasp->flags & JSCLASS_IS_EXTENDED) && - (xclasp = (JSExtendedClass *) clasp)->iteratorObject) { + (xclasp = (ExtendedClass *) clasp)->iteratorObject) { /* Enumerate Iterator.prototype directly. */ if (clasp != &js_IteratorClass.base || obj->getNativeIterator()) { - iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH)); + JSObject *iterobj = xclasp->iteratorObject(cx, obj, !(flags & JSITER_FOREACH)); if (!iterobj) return false; - *vp = OBJECT_TO_JSVAL(iterobj); + vp->setObject(*iterobj); return true; } } @@ -699,17 +784,11 @@ CloseGenerator(JSContext *cx, JSObject *genobj); #endif JS_FRIEND_API(JSBool) -js_CloseIterator(JSContext *cx, jsval v) +js_CloseIterator(JSContext *cx, JSObject *obj) { - JSObject *obj; - JSClass *clasp; - - cx->iterValue = JSVAL_HOLE; - - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); - obj = JSVAL_TO_OBJECT(v); - clasp = obj->getClass(); + cx->iterValue.setMagic(JS_NO_ITER_VALUE); + Class *clasp = obj->getClass(); if (clasp == &js_IteratorClass.base) { /* Remove enumerators from the active list, which is a stack. */ NativeIterator *ni = obj->getNativeIterator(); @@ -754,10 +833,11 @@ js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id) while (iterobj) { again: NativeIterator *ni = iterobj->getNativeIterator(); - if (ni->obj == obj && ni->props_cursor < ni->props_end) { + /* This only works for identified surpressed keys, not values. */ + if (ni->isKeyIter() && ni->obj == obj && ni->props_cursor < ni->props_end) { /* Check whether id is still to come. */ - jsid *props_cursor = ni->props_cursor; - jsid *props_end = ni->props_end; + jsid *props_cursor = ni->currentKey(); + jsid *props_end = ni->endKey(); for (jsid *idp = props_cursor; idp < props_end; ++idp) { if (*idp == id) { /* @@ -796,10 +876,10 @@ js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id) * If it is the next property to be enumerated, just skip it. */ if (idp == props_cursor) { - ni->props_cursor++; + ni->incKeyCursor(); } else { memmove(idp, idp + 1, (props_end - (idp + 1)) * sizeof(jsid)); - ni->props_end--; + ni->props_end = ni->endKey() - 1; } break; } @@ -811,7 +891,7 @@ js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id) } JSBool -js_IteratorMore(JSContext *cx, JSObject *iterobj, jsval *rval) +js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval) { /* Fast path for native iterators */ if (iterobj->getClass() == &js_IteratorClass.base) { @@ -820,42 +900,42 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, jsval *rval) * read-only and permanent. */ NativeIterator *ni = iterobj->getNativeIterator(); - *rval = BOOLEAN_TO_JSVAL(ni->props_cursor < ni->props_end); + rval->setBoolean(ni->props_cursor < ni->props_end); return true; } /* We might still have a pending value. */ - if (cx->iterValue != JSVAL_HOLE) { - *rval = JSVAL_TRUE; + if (!cx->iterValue.isMagic(JS_NO_ITER_VALUE)) { + rval->setBoolean(true); return true; } /* Fetch and cache the next value from the iterator. */ jsid id = ATOM_TO_JSID(cx->runtime->atomState.nextAtom); - if (!JS_GetMethodById(cx, iterobj, id, &iterobj, rval)) + if (!js_GetMethod(cx, iterobj, id, JSGET_METHOD_BARRIER, rval)) return false; - if (!js_InternalCall(cx, iterobj, *rval, 0, NULL, rval)) { + if (!InternalCall(cx, iterobj, *rval, 0, NULL, rval)) { /* Check for StopIteration. */ if (!cx->throwing || !js_ValueIsStopIteration(cx->exception)) return false; /* Inline JS_ClearPendingException(cx). */ cx->throwing = JS_FALSE; - cx->exception = JSVAL_VOID; - cx->iterValue = JSVAL_HOLE; - *rval = JSVAL_FALSE; + cx->exception.setUndefined(); + cx->iterValue.setMagic(JS_NO_ITER_VALUE); + rval->setBoolean(false); return true; } /* Cache the value returned by iterobj.next() so js_IteratorNext() can find it. */ - JS_ASSERT(*rval != JSVAL_HOLE); + JS_ASSERT(!rval->isMagic(JS_NO_ITER_VALUE)); cx->iterValue = *rval; - *rval = JSVAL_TRUE; + rval->setBoolean(true); return true; } JSBool -js_IteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval) +js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval) { /* Fast path for native iterators */ if (iterobj->getClass() == &js_IteratorClass.base) { @@ -865,14 +945,20 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval) */ NativeIterator *ni = iterobj->getNativeIterator(); JS_ASSERT(ni->props_cursor < ni->props_end); - *rval = *ni->props_cursor++; + if (ni->isKeyIter()) { + *rval = IdToValue(*ni->currentKey()); + ni->incKeyCursor(); + } else { + *rval = *ni->currentValue(); + ni->incValueCursor(); + } - if (JSVAL_IS_STRING(*rval) || (ni->flags & JSITER_FOREACH)) + if (rval->isString() || !ni->isKeyIter()) return true; JSString *str; jsint i; - if (JSVAL_IS_INT(*rval) && (jsuint(i = JSVAL_TO_INT(*rval)) < INT_STRING_LIMIT)) { + if (rval->isInt32() && (jsuint(i = rval->toInt32()) < INT_STRING_LIMIT)) { str = JSString::intString(i); } else { str = js_ValueToString(cx, *rval); @@ -880,31 +966,31 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval) return false; } - *rval = STRING_TO_JSVAL(str); + rval->setString(str); return true; } - JS_ASSERT(cx->iterValue != JSVAL_HOLE); + JS_ASSERT(!cx->iterValue.isMagic(JS_NO_ITER_VALUE)); *rval = cx->iterValue; - cx->iterValue = JSVAL_HOLE; + cx->iterValue.setMagic(JS_NO_ITER_VALUE); return true; } static JSBool -stopiter_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +stopiter_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) { - *bp = js_ValueIsStopIteration(v); + *bp = js_ValueIsStopIteration(*v); return JS_TRUE; } -JSClass js_StopIterationClass = { +Class js_StopIterationClass = { js_StopIteration_str, JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration), - JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, - JS_ConvertStub, NULL, + PropertyStub, PropertyStub, + PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, + ConvertStub, NULL, NULL, NULL, NULL, NULL, NULL, stopiter_hasInstance, @@ -946,20 +1032,20 @@ generator_trace(JSTracer *trc, JSObject *obj) JSStackFrame *fp = gen->getFloatingFrame(); JS_ASSERT(gen->getLiveFrame() == fp); - TraceValues(trc, gen->floatingStack, fp->argEnd(), "generator slots"); + MarkValueRange(trc, gen->floatingStack, fp->argEnd(), "generator slots"); js_TraceStackFrame(trc, fp); - TraceValues(trc, fp->slots(), gen->savedRegs.sp, "generator slots"); + MarkValueRange(trc, fp->slots(), gen->savedRegs.sp, "generator slots"); } -JSExtendedClass js_GeneratorClass = { +ExtendedClass js_GeneratorClass = { { js_Generator_str, JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE | JSCLASS_IS_EXTENDED, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, generator_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, generator_finalize, NULL, NULL, NULL, NULL, NULL, NULL, JS_CLASS_TRACE(generator_trace), NULL }, NULL, NULL, NULL, iterator_iterator, @@ -990,19 +1076,19 @@ js_NewGenerator(JSContext *cx) /* Compute JSGenerator size. */ uintN nbytes = sizeof(JSGenerator) + - (-1 + /* one jsval included in JSGenerator */ + (-1 + /* one Value included in JSGenerator */ vplen + VALUES_PER_STACK_FRAME + - fp->script->nslots) * sizeof(jsval); + fp->script->nslots) * sizeof(Value); JSGenerator *gen = (JSGenerator *) cx->malloc(nbytes); if (!gen) return NULL; /* Cut up floatingStack space. */ - jsval *vp = gen->floatingStack; + Value *vp = gen->floatingStack; JSStackFrame *newfp = reinterpret_cast(vp + vplen); - jsval *slots = newfp->slots(); + Value *slots = newfp->slots(); /* Initialize JSGenerator. */ gen->obj = obj; @@ -1023,7 +1109,7 @@ js_NewGenerator(JSContext *cx) } newfp->argsobj = fp->argsobj; if (fp->argsobj) { /* Steal args object. */ - JSVAL_TO_OBJECT(fp->argsobj)->setPrivate(newfp); + fp->argsobj->setPrivate(newfp); fp->argsobj = NULL; } newfp->script = fp->script; @@ -1039,8 +1125,8 @@ js_NewGenerator(JSContext *cx) newfp->flags = fp->flags | JSFRAME_GENERATOR | JSFRAME_FLOATING_GENERATOR; /* Copy in arguments and slots. */ - memcpy(vp, fp->argv - 2, vplen * sizeof(jsval)); - memcpy(slots, fp->slots(), fp->script->nfixed * sizeof(jsval)); + memcpy(vp, fp->argv - 2, vplen * sizeof(Value)); + memcpy(slots, fp->slots(), fp->script->nfixed * sizeof(Value)); obj->setPrivate(gen); return obj; @@ -1068,11 +1154,11 @@ typedef enum JSGeneratorOp { */ static JS_REQUIRES_STACK JSBool SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, - JSGenerator *gen, jsval arg) + JSGenerator *gen, const Value &arg) { if (gen->state == JSGEN_RUNNING || gen->state == JSGEN_CLOSING) { js_ReportValueError(cx, JSMSG_NESTING_GENERATOR, - JSDVG_SEARCH_STACK, OBJECT_TO_JSVAL(obj), + JSDVG_SEARCH_STACK, ObjectOrNullValue(obj), JS_GetFunctionId(gen->getFloatingFrame()->fun)); return JS_FALSE; } @@ -1096,13 +1182,13 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, break; case JSGENOP_THROW: - JS_SetPendingException(cx, arg); + SetPendingException(cx, arg); gen->state = JSGEN_RUNNING; break; default: JS_ASSERT(op == JSGENOP_CLOSE); - JS_SetPendingException(cx, JSVAL_ARETURN); + SetPendingException(cx, MagicValue(JS_GENERATOR_CLOSING)); gen->state = JSGEN_CLOSING; break; } @@ -1110,7 +1196,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, JSStackFrame *genfp = gen->getFloatingFrame(); JSBool ok; { - jsval *genVp = gen->floatingStack; + Value *genVp = gen->floatingStack; uintN vplen = gen->vplen; uintN nfixed = genfp->script->nslots; @@ -1124,7 +1210,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, return JS_FALSE; } - jsval *vp = frame.getvp(); + Value *vp = frame.getvp(); JSStackFrame *fp = frame.getFrame(); /* @@ -1132,7 +1218,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, * only be set on the generator's frame. See args_or_call_trace. */ uintN usedBefore = gen->savedRegs.sp - genVp; - memcpy(vp, genVp, usedBefore * sizeof(jsval)); + memcpy(vp, genVp, usedBefore * sizeof(Value)); fp->flags &= ~JSFRAME_FLOATING_GENERATOR; fp->argv = vp + 2; gen->savedRegs.sp = fp->slots() + (gen->savedRegs.sp - genfp->slots()); @@ -1140,7 +1226,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, #ifdef DEBUG JSObject *callobjBefore = fp->callobj; - jsval argsobjBefore = fp->argsobj; + JSObject *argsobjBefore = fp->argsobj; #endif /* @@ -1152,7 +1238,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, if (genfp->callobj) fp->callobj->setPrivate(fp); if (genfp->argsobj) - JSVAL_TO_OBJECT(fp->argsobj)->setPrivate(fp); + fp->argsobj->setPrivate(fp); gen->liveFrame = fp; (void)cx->enterGenerator(gen); /* OOM check above. */ @@ -1163,7 +1249,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, JSObject *enumerators = cx->enumerators; cx->enumerators = gen->enumerators; - ok = js_Interpret(cx); + ok = Interpret(cx); /* Restore the original enumerators stack. */ gen->enumerators = cx->enumerators; @@ -1173,7 +1259,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, cx->leaveGenerator(gen); gen->liveFrame = genfp; if (fp->argsobj) - JSVAL_TO_OBJECT(fp->argsobj)->setPrivate(genfp); + fp->argsobj->setPrivate(genfp); if (fp->callobj) fp->callobj->setPrivate(genfp); @@ -1183,7 +1269,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, /* Copy and rebase stack frame/args/slots. Restore "floating" flag. */ JS_ASSERT(uintN(gen->savedRegs.sp - fp->slots()) <= fp->script->nslots); uintN usedAfter = gen->savedRegs.sp - vp; - memcpy(genVp, vp, usedAfter * sizeof(jsval)); + memcpy(genVp, vp, usedAfter * sizeof(Value)); genfp->flags |= JSFRAME_FLOATING_GENERATOR; genfp->argv = genVp + 2; gen->savedRegs.sp = genfp->slots() + (gen->savedRegs.sp - fp->slots()); @@ -1201,7 +1287,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, return JS_TRUE; } - genfp->rval = JSVAL_VOID; + genfp->rval.setUndefined(); gen->state = JSGEN_CLOSED; if (ok) { /* Returned, explicitly or by falling off the end. */ @@ -1231,22 +1317,20 @@ CloseGenerator(JSContext *cx, JSObject *obj) if (gen->state == JSGEN_CLOSED) return JS_TRUE; - return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JSVAL_VOID); + return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, UndefinedValue()); } /* * Common subroutine of generator_(next|send|throw|close) methods. */ static JSBool -generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp, uintN argc) +generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc) { JSObject *obj; - jsval arg; - LeaveTrace(cx); - obj = JS_THIS_OBJECT(cx, vp); - if (!JS_InstanceOf(cx, obj, &js_GeneratorClass.base, vp + 2)) + obj = ComputeThisFromVp(cx, vp); + if (!InstanceOf(cx, obj, &js_GeneratorClass.base, vp + 2)) return JS_FALSE; JSGenerator *gen = (JSGenerator *) obj->getPrivate(); @@ -1262,7 +1346,7 @@ generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp, uintN argc) break; case JSGENOP_SEND: - if (argc >= 1 && !JSVAL_IS_VOID(vp[2])) { + if (argc >= 1 && !vp[2].isUndefined()) { js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND, JSDVG_SEARCH_STACK, vp[2], NULL); return JS_FALSE; @@ -1281,7 +1365,7 @@ generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp, uintN argc) case JSGENOP_SEND: return js_ThrowStopIteration(cx); case JSGENOP_THROW: - JS_SetPendingException(cx, argc >= 1 ? vp[2] : JSVAL_VOID); + SetPendingException(cx, argc >= 1 ? vp[2] : UndefinedValue()); return JS_FALSE; default: JS_ASSERT(op == JSGENOP_CLOSE); @@ -1289,35 +1373,33 @@ generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp, uintN argc) } } - arg = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0) - ? vp[2] - : JSVAL_VOID; - if (!SendToGenerator(cx, op, obj, gen, arg)) + bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0); + if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue())) return JS_FALSE; *vp = gen->getFloatingFrame()->rval; return JS_TRUE; } static JSBool -generator_send(JSContext *cx, uintN argc, jsval *vp) +generator_send(JSContext *cx, uintN argc, Value *vp) { return generator_op(cx, JSGENOP_SEND, vp, argc); } static JSBool -generator_next(JSContext *cx, uintN argc, jsval *vp) +generator_next(JSContext *cx, uintN argc, Value *vp) { return generator_op(cx, JSGENOP_NEXT, vp, argc); } static JSBool -generator_throw(JSContext *cx, uintN argc, jsval *vp) +generator_throw(JSContext *cx, uintN argc, Value *vp) { return generator_op(cx, JSGENOP_THROW, vp, argc); } static JSBool -generator_close(JSContext *cx, uintN argc, jsval *vp) +generator_close(JSContext *cx, uintN argc, Value *vp) { return generator_op(cx, JSGENOP_CLOSE, vp, argc); } @@ -1343,19 +1425,19 @@ js_InitIteratorClasses(JSContext *cx, JSObject *obj) if (stop) return stop; - proto = JS_InitClass(cx, obj, NULL, &js_IteratorClass.base, Iterator, 2, + proto = js_InitClass(cx, obj, NULL, &js_IteratorClass.base, Iterator, 2, NULL, iterator_methods, NULL, NULL); if (!proto) return NULL; #if JS_HAS_GENERATORS /* Initialize the generator internals if configured. */ - if (!JS_InitClass(cx, obj, NULL, &js_GeneratorClass.base, NULL, 0, + if (!js_InitClass(cx, obj, NULL, &js_GeneratorClass.base, NULL, 0, NULL, generator_methods, NULL, NULL)) { return NULL; } #endif - return JS_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0, + return js_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0, NULL, NULL, NULL, NULL); } diff --git a/js/src/jsiter.h b/js/src/jsiter.h index 83bfe5ef0e4c..f6a478d3278a 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -47,8 +47,6 @@ #include "jspubtd.h" #include "jsversion.h" -JS_BEGIN_EXTERN_C - /* * NB: these flag bits are encoded into the bytecode stream in the immediate * operand of JSOP_ITER, so don't change them without advancing jsxdrapi.h's @@ -62,48 +60,95 @@ JS_BEGIN_EXTERN_C struct NativeIterator { JSObject *obj; - jsval *props_array; - jsval *props_cursor; - jsval *props_end; + void *props_array; + void *props_cursor; + void *props_end; uint32 *shapes_array; uint32 shapes_length; uint32 shapes_key; uintN flags; JSObject *next; - static NativeIterator *allocate(JSContext *cx, JSObject *obj, uintN flags, - uint32 *sarray, uint32 slength, uint32 key, - js::AutoValueVector &props); + bool isKeyIter() const { return (flags & JSITER_FOREACH) == 0; } - inline size_t length() const { - return props_end - props_array; + inline jsid *beginKey() const { + JS_ASSERT(isKeyIter()); + return (jsid *)props_array; } - inline jsval *begin() const { - return props_array; + inline jsid *endKey() const { + JS_ASSERT(isKeyIter()); + return (jsid *)props_end; } + size_t numKeys() const { + return endKey() - beginKey(); + } + + jsid *currentKey() const { + JS_ASSERT(isKeyIter()); + return reinterpret_cast(props_cursor); + } + + void incKeyCursor() { + JS_ASSERT(isKeyIter()); + props_cursor = reinterpret_cast(props_cursor) + 1; + } + + inline js::Value *beginValue() const { + JS_ASSERT(!isKeyIter()); + return (js::Value *)props_array; + } + + inline js::Value *endValue() const { + JS_ASSERT(!isKeyIter()); + return (js::Value *)props_end; + } + + size_t numValues() const { + return endValue() - beginValue(); + } + + js::Value *currentValue() const { + JS_ASSERT(!isKeyIter()); + return reinterpret_cast(props_cursor); + } + + void incValueCursor() { + JS_ASSERT(!isKeyIter()); + props_cursor = reinterpret_cast(props_cursor) + 1; + } + + static NativeIterator *allocateKeyIterator(JSContext *cx, uint32 slength, + const js::AutoIdVector &props); + static NativeIterator *allocateValueIterator(JSContext *cx, uint32 slength, + const js::AutoValueVector &props); + void init(JSObject *obj, uintN flags, const uint32 *sarray, uint32 slength, uint32 key); + void mark(JSTracer *trc); }; +bool +VectorToIdArray(JSContext *cx, js::AutoIdVector &props, JSIdArray **idap); + +bool +GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props); + +bool +GetIterator(JSContext *cx, JSObject *obj, uintN flags, js::Value *vp); + +bool +VectorToKeyIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp); + +bool +VectorToValueIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoValueVector &props, js::Value *vp); + /* - * Magic jsval that indicates that a custom enumerate hook forwarded - * to js_Enumerate, which really means the object can be enumerated like - * a native object. + * Creates either a key or value iterator, depending on flags. For a value + * iterator, performs value-lookup to convert the given list of jsids. */ -static const jsval JSVAL_NATIVE_ENUMERATE_COOKIE = SPECIAL_TO_JSVAL(0x220576); - bool -VectorToIdArray(JSContext *cx, js::AutoValueVector &props, JSIdArray **idap); - -bool -GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, js::AutoValueVector &props); - -bool -GetIterator(JSContext *cx, JSObject *obj, uintN flags, jsval *vp); - -bool -IdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoValueVector &props, jsval *vp); +EnumeratedIdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector &props, js::Value *vp); /* * Convert the value stored in *vp to its iteration object. The flags should @@ -112,10 +157,10 @@ IdVectorToIterator(JSContext *cx, JSObject *obj, uintN flags, js::AutoValueVecto * iterator will never be exposed to scripts. */ extern JS_FRIEND_API(JSBool) -js_ValueToIterator(JSContext *cx, uintN flags, jsval *vp); +js_ValueToIterator(JSContext *cx, uintN flags, js::Value *vp); extern JS_FRIEND_API(JSBool) -js_CloseIterator(JSContext *cx, jsval v); +js_CloseIterator(JSContext *cx, JSObject *iterObj); bool js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id); @@ -126,10 +171,10 @@ js_SuppressDeletedProperty(JSContext *cx, JSObject *obj, jsid id); * picked up by IteratorNext(). The value is cached in the current context. */ extern JSBool -js_IteratorMore(JSContext *cx, JSObject *iterobj, jsval *rval); +js_IteratorMore(JSContext *cx, JSObject *iterobj, js::Value *rval); extern JSBool -js_IteratorNext(JSContext *cx, JSObject *iterobj, jsval *rval); +js_IteratorNext(JSContext *cx, JSObject *iterobj, js::Value *rval); extern JSBool js_ThrowStopIteration(JSContext *cx); @@ -154,7 +199,7 @@ struct JSGenerator { uintN vplen; JSStackFrame *liveFrame; JSObject *enumerators; - jsval floatingStack[1]; + js::Value floatingStack[1]; JSStackFrame *getFloatingFrame() { return reinterpret_cast(floatingStack + vplen); @@ -204,20 +249,17 @@ js_LiveFrameIfGenerator(JSStackFrame *fp) #endif -extern JSExtendedClass js_GeneratorClass; -extern JSExtendedClass js_IteratorClass; -extern JSClass js_StopIterationClass; +extern js::ExtendedClass js_GeneratorClass; +extern js::ExtendedClass js_IteratorClass; +extern js::Class js_StopIterationClass; static inline bool -js_ValueIsStopIteration(jsval v) +js_ValueIsStopIteration(const js::Value &v) { - return !JSVAL_IS_PRIMITIVE(v) && - JSVAL_TO_OBJECT(v)->getClass() == &js_StopIterationClass; + return v.isObject() && v.toObject().getClass() == &js_StopIterationClass; } extern JSObject * js_InitIteratorClasses(JSContext *cx, JSObject *obj); -JS_END_EXTERN_C - #endif /* jsiter_h___ */ diff --git a/js/src/jslock.cpp b/js/src/jslock.cpp index f924922b7751..94c26429b90e 100644 --- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -500,16 +500,16 @@ FinishSharingTitle(JSContext *cx, JSTitle *title) uint32 nslots = scope->freeslot; JS_ASSERT(nslots >= JSSLOT_START(obj->getClass())); for (uint32 i = JSSLOT_START(obj->getClass()); i != nslots; ++i) { - jsval v = obj->getSlot(i); - if (JSVAL_IS_STRING(v) && - !js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) { + Value v = obj->getSlot(i); + if (v.isString() && + !js_MakeStringImmutable(cx, v.toString())) { /* * FIXME bug 363059: The following error recovery changes * runtime execution semantics, arbitrarily and silently * ignoring errors except out-of-memory, which should have been * reported through JS_ReportOutOfMemory at this point. */ - obj->setSlot(i, JSVAL_VOID); + obj->setSlot(i, UndefinedValue()); } } } @@ -717,7 +717,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot) if (CX_THREAD_IS_RUNNING_GC(cx) || scope->sealed() || (title->ownercx && ClaimTitle(title, cx))) { - return obj->getSlot(slot); + return Jsvalify(obj->getSlot(slot)); } #ifndef NSPR_LOCK @@ -732,7 +732,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot) * lock release followed by fat lock acquisition. */ if (scope == obj->scope()) { - v = obj->getSlot(slot); + v = Jsvalify(obj->getSlot(slot)); if (!NativeCompareAndSwap(&tl->owner, me, 0)) { /* Assert that scope locks never revert to flyweight. */ JS_ASSERT(title->ownercx != cx); @@ -746,12 +746,12 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot) js_Dequeue(tl); } else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) { - return obj->getSlot(slot); + return Jsvalify(obj->getSlot(slot)); } #endif js_LockObj(cx, obj); - v = obj->getSlot(slot); + v = Jsvalify(obj->getSlot(slot)); /* * Test whether cx took ownership of obj's scope during js_LockObj. @@ -805,7 +805,7 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v) if (CX_THREAD_IS_RUNNING_GC(cx) || scope->sealed() || (title->ownercx && ClaimTitle(title, cx))) { - obj->lockedSetSlot(slot, v); + obj->lockedSetSlot(slot, Valueify(v)); return; } @@ -815,7 +815,7 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v) JS_ASSERT(CURRENT_THREAD_IS_ME(me)); if (NativeCompareAndSwap(&tl->owner, 0, me)) { if (scope == obj->scope()) { - obj->lockedSetSlot(slot, v); + obj->lockedSetSlot(slot, Valueify(v)); if (!NativeCompareAndSwap(&tl->owner, me, 0)) { /* Assert that scope locks never revert to flyweight. */ JS_ASSERT(title->ownercx != cx); @@ -828,13 +828,13 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v) if (!NativeCompareAndSwap(&tl->owner, me, 0)) js_Dequeue(tl); } else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) { - obj->lockedSetSlot(slot, v); + obj->lockedSetSlot(slot, Valueify(v)); return; } #endif js_LockObj(cx, obj); - obj->lockedSetSlot(slot, v); + obj->lockedSetSlot(slot, Valueify(v)); /* * Same drill as above, in js_GetSlotThreadSafe. diff --git a/js/src/jslock.h b/js/src/jslock.h index 6297a1e750b7..3be65498cdb1 100644 --- a/js/src/jslock.h +++ b/js/src/jslock.h @@ -40,8 +40,8 @@ #define jslock_h__ #include "jstypes.h" -#include "jsprvtd.h" /* for JSScope, etc. */ -#include "jspubtd.h" /* for JSRuntime, etc. */ +#include "jsapi.h" +#include "jsprvtd.h" #ifdef JS_THREADSAFE # include "pratom.h" diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index a2e7abd286ed..1864ca9dc63d 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -54,7 +54,6 @@ #include "jsmath.h" #include "jsnum.h" #include "jslibmath.h" -#include "jsobj.h" using namespace js; @@ -95,84 +94,88 @@ static JSConstDoubleSpec math_constants[] = { {0,0,0,{0,0,0}} }; -JSClass js_MathClass = { +Class js_MathClass = { js_Math_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Math), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; static JSBool -math_abs(JSContext *cx, uintN argc, jsval *vp) +math_abs(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = fabs(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } static JSBool -math_acos(JSContext *cx, uintN argc, jsval *vp) +math_acos(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; #if defined(SOLARIS) && defined(__GNUC__) if (x < -1 || 1 < x) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } #endif z = acos(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setDouble(z); + return JS_TRUE; } static JSBool -math_asin(JSContext *cx, uintN argc, jsval *vp) +math_asin(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; #if defined(SOLARIS) && defined(__GNUC__) if (x < -1 || 1 < x) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } #endif z = asin(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setDouble(z); + return JS_TRUE; } static JSBool -math_atan(JSContext *cx, uintN argc, jsval *vp) +math_atan(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = atan(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setDouble(z); + return JS_TRUE; } static inline jsdouble JS_FASTCALL @@ -206,19 +209,21 @@ math_atan2_kernel(jsdouble x, jsdouble y) } static JSBool -math_atan2(JSContext *cx, uintN argc, jsval *vp) +math_atan2(JSContext *cx, uintN argc, Value *vp) { - jsdouble x, y; + jsdouble x, y, z; if (argc <= 1) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; if (!ValueToNumber(cx, vp[3], &y)) return JS_FALSE; - return js_NewNumberInRootedValue(cx, math_atan2_kernel (x, y), vp); + z = math_atan2_kernel(x, y); + vp->setDouble(z); + return JS_TRUE; } static inline jsdouble JS_FASTCALL @@ -232,42 +237,44 @@ math_ceil_kernel(jsdouble x) } JSBool -js_math_ceil(JSContext *cx, uintN argc, jsval *vp) +js_math_ceil(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = math_ceil_kernel(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } static JSBool -math_cos(JSContext *cx, uintN argc, jsval *vp) +math_cos(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = cos(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setDouble(z); + return JS_TRUE; } static JSBool -math_exp(JSContext *cx, uintN argc, jsval *vp) +math_exp(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) @@ -275,64 +282,67 @@ math_exp(JSContext *cx, uintN argc, jsval *vp) #ifdef _WIN32 if (!JSDOUBLE_IS_NaN(x)) { if (x == js_PositiveInfinity) { - *vp = cx->runtime->positiveInfinityValue; + vp->setDouble(js_PositiveInfinity); return JS_TRUE; } if (x == js_NegativeInfinity) { - *vp = JSVAL_ZERO; + vp->setInt32(0); return JS_TRUE; } } #endif z = exp(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } JSBool -js_math_floor(JSContext *cx, uintN argc, jsval *vp) +js_math_floor(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = floor(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } static JSBool -math_log(JSContext *cx, uintN argc, jsval *vp) +math_log(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; #if defined(SOLARIS) && defined(__GNUC__) if (x < 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } #endif z = log(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } JSBool -js_math_max(JSContext *cx, uintN argc, jsval *vp) +js_math_max(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z = js_NegativeInfinity; - jsval *argv; + Value *argv; uintN i; if (argc == 0) { - *vp = cx->runtime->negativeInfinityValue; + vp->setDouble(js_NegativeInfinity); return JS_TRUE; } argv = vp + 2; @@ -340,7 +350,7 @@ js_math_max(JSContext *cx, uintN argc, jsval *vp) if (!ValueToNumber(cx, argv[i], &x)) return JS_FALSE; if (JSDOUBLE_IS_NaN(x)) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (x == 0 && x == z) { @@ -350,18 +360,19 @@ js_math_max(JSContext *cx, uintN argc, jsval *vp) z = (x > z) ? x : z; } } - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } JSBool -js_math_min(JSContext *cx, uintN argc, jsval *vp) +js_math_min(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z = js_PositiveInfinity; - jsval *argv; + Value *argv; uintN i; if (argc == 0) { - *vp = cx->runtime->positiveInfinityValue; + vp->setDouble(js_PositiveInfinity); return JS_TRUE; } argv = vp + 2; @@ -369,7 +380,7 @@ js_math_min(JSContext *cx, uintN argc, jsval *vp) if (!ValueToNumber(cx, argv[i], &x)) return JS_FALSE; if (JSDOUBLE_IS_NaN(x)) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (x == 0 && x == z) { @@ -379,16 +390,17 @@ js_math_min(JSContext *cx, uintN argc, jsval *vp) z = (x < z) ? x : z; } } - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } static JSBool -math_pow(JSContext *cx, uintN argc, jsval *vp) +math_pow(JSContext *cx, uintN argc, Value *vp) { jsdouble x, y, z; if (argc <= 1) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) @@ -400,16 +412,17 @@ math_pow(JSContext *cx, uintN argc, jsval *vp) * we need to wrap the libm call to make it ECMA compliant. */ if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } /* pow(x, +-0) is always 1, even for x = NaN. */ if (y == 0) { - *vp = JSVAL_ONE; + vp->setInt32(1); return JS_TRUE; } z = pow(x, y); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } static const int64 RNG_MULTIPLIER = 0x5DEECE66DLL; @@ -458,10 +471,11 @@ random_nextDouble(JSContext *cx) } static JSBool -math_random(JSContext *cx, uintN argc, jsval *vp) +math_random(JSContext *cx, uintN argc, Value *vp) { jsdouble z = random_nextDouble(cx); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setDouble(z); + return JS_TRUE; } #if defined _WIN32 && !defined WINCE && _MSC_VER < 1400 @@ -480,70 +494,74 @@ js_copysign(double x, double y) #endif JSBool -js_math_round(JSContext *cx, uintN argc, jsval *vp) +js_math_round(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = js_copysign(floor(x + 0.5), x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setNumber(z); + return JS_TRUE; } static JSBool -math_sin(JSContext *cx, uintN argc, jsval *vp) +math_sin(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = sin(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setDouble(z); + return JS_TRUE; } static JSBool -math_sqrt(JSContext *cx, uintN argc, jsval *vp) +math_sqrt(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = sqrt(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setDouble(z); + return JS_TRUE; } static JSBool -math_tan(JSContext *cx, uintN argc, jsval *vp) +math_tan(JSContext *cx, uintN argc, Value *vp) { jsdouble x, z; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; z = tan(x); - return js_NewNumberInRootedValue(cx, z, vp); + vp->setDouble(z); + return JS_TRUE; } #if JS_HAS_TOSOURCE static JSBool -math_toSource(JSContext *cx, uintN argc, jsval *vp) +math_toSource(JSContext *cx, uintN argc, Value *vp) { - *vp = ATOM_KEY(CLASS_ATOM(cx, Math)); + vp->setString(ATOM_TO_STRING(CLASS_ATOM(cx, Math))); return JS_TRUE; } #endif @@ -737,7 +755,7 @@ js_InitMathClass(JSContext *cx, JSObject *obj) { JSObject *Math; - Math = JS_NewObject(cx, &js_MathClass, NULL, obj); + Math = JS_NewObject(cx, Jsvalify(&js_MathClass), NULL, obj); if (!Math) return NULL; if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math), diff --git a/js/src/jsmath.h b/js/src/jsmath.h index 0eab6dfb0657..ec5a5386bdda 100644 --- a/js/src/jsmath.h +++ b/js/src/jsmath.h @@ -43,9 +43,7 @@ * JS math functions. */ -JS_BEGIN_EXTERN_C - -extern JSClass js_MathClass; +extern js::Class js_MathClass; extern JSObject * js_InitMathClass(JSContext *cx, JSObject *obj); @@ -54,20 +52,18 @@ extern void js_InitRandom(JSContext *cx); extern JSBool -js_math_ceil(JSContext *cx, uintN argc, jsval *vp); +js_math_ceil(JSContext *cx, uintN argc, js::Value *vp); extern JSBool -js_math_floor(JSContext *cx, uintN argc, jsval *vp); +js_math_floor(JSContext *cx, uintN argc, js::Value *vp); extern JSBool -js_math_max(JSContext *cx, uintN argc, jsval *vp); +js_math_max(JSContext *cx, uintN argc, js::Value *vp); extern JSBool -js_math_min(JSContext *cx, uintN argc, jsval *vp); +js_math_min(JSContext *cx, uintN argc, js::Value *vp); extern JSBool -js_math_round(JSContext *cx, uintN argc, jsval *vp); - -JS_END_EXTERN_C +js_math_round(JSContext *cx, uintN argc, js::Value *vp); #endif /* jsmath_h___ */ diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index 91ae35df3f92..0a215271053e 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -103,42 +103,42 @@ JS_STATIC_ASSERT(uintptr_t(PTRDIFF_MAX) + uintptr_t(1) == uintptr_t(PTRDIFF_MIN) #endif /* JS_HAVE_STDINT_H */ static JSBool -num_isNaN(JSContext *cx, uintN argc, jsval *vp) +num_isNaN(JSContext *cx, uintN argc, Value *vp) { if (argc == 0) { - *vp = JSVAL_TRUE; + vp->setBoolean(true); return JS_TRUE; } jsdouble x; if (!ValueToNumber(cx, vp[2], &x)) return false; - *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x)); + vp->setBoolean(JSDOUBLE_IS_NaN(x)); return JS_TRUE; } static JSBool -num_isFinite(JSContext *cx, uintN argc, jsval *vp) +num_isFinite(JSContext *cx, uintN argc, Value *vp) { if (argc == 0) { - *vp = JSVAL_FALSE; + vp->setBoolean(false); return JS_TRUE; } jsdouble x; if (!ValueToNumber(cx, vp[2], &x)) return JS_FALSE; - *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x)); + vp->setBoolean(JSDOUBLE_IS_FINITE(x)); return JS_TRUE; } static JSBool -num_parseFloat(JSContext *cx, uintN argc, jsval *vp) +num_parseFloat(JSContext *cx, uintN argc, Value *vp) { JSString *str; jsdouble d; const jschar *bp, *end, *ep; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } str = js_ValueToString(cx, vp[2]); @@ -148,10 +148,11 @@ num_parseFloat(JSContext *cx, uintN argc, jsval *vp) if (!js_strtod(cx, bp, end, &ep, &d)) return JS_FALSE; if (ep == bp) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } - return js_NewNumberInRootedValue(cx, d, vp); + vp->setNumber(d); + return JS_TRUE; } #ifdef JS_TRACER @@ -172,14 +173,14 @@ ParseFloat(JSContext* cx, JSString* str) /* See ECMA 15.1.2.2. */ static JSBool -num_parseInt(JSContext *cx, uintN argc, jsval *vp) +num_parseInt(JSContext *cx, uintN argc, Value *vp) { JSString *str; jsdouble d; const jschar *bp, *end, *ep; if (argc == 0) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } int32_t radix; @@ -190,11 +191,11 @@ num_parseInt(JSContext *cx, uintN argc, jsval *vp) radix = 0; } if (radix != 0 && (radix < 2 || radix > 36)) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } - if (JSVAL_IS_INT(vp[2]) && (radix == 0 || radix == 10)) { + if (vp[2].isInt32() && (radix == 0 || radix == 10)) { *vp = vp[2]; return JS_TRUE; } @@ -206,10 +207,11 @@ num_parseInt(JSContext *cx, uintN argc, jsval *vp) if (!js_strtointeger(cx, bp, end, &ep, radix, &d)) return JS_FALSE; if (ep == bp) { - *vp = cx->runtime->NaNValue; + vp->setDouble(js_NaN); return JS_TRUE; } - return js_NewNumberInRootedValue(cx, d, vp); + vp->setNumber(d); + return JS_TRUE; } #ifdef JS_TRACER @@ -266,46 +268,43 @@ static JSFunctionSpec number_functions[] = { JS_FS_END }; -JSClass js_NumberClass = { +Class js_NumberClass = { js_Number_str, JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; static JSBool -Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Number(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { - jsval v; + Value v; if (argc != 0) { - if (!ValueToNumberValue(cx, &argv[0])) + if (!ValueToNumber(cx, &argv[0])) return JS_FALSE; - v = argv[0]; } else { - v = JSVAL_ZERO; + argv[0].setInt32(0); } if (!JS_IsConstructing(cx)) - *rval = v; + *rval = argv[0]; else - obj->setPrimitiveThis(v); + obj->setPrimitiveThis(argv[0]); return true; } #if JS_HAS_TOSOURCE static JSBool -num_toSource(JSContext *cx, uintN argc, jsval *vp) +num_toSource(JSContext *cx, uintN argc, Value *vp) { - jsval v; - jsdouble d; char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr; char buf[64]; JSString *str; - if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + const Value *primp; + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &primp)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_NUMBER(v)); - d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); + double d = primp->toNumber(); numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d); if (!numStr) { @@ -316,7 +315,7 @@ num_toSource(JSContext *cx, uintN argc, jsval *vp) str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } #endif @@ -372,18 +371,14 @@ static JSString * JS_FASTCALL js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base); static JSBool -num_toString(JSContext *cx, uintN argc, jsval *vp) +num_toString(JSContext *cx, uintN argc, Value *vp) { - jsval v; - jsdouble d; - JSString *str; - - if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + const Value *primp; + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &primp)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_NUMBER(v)); - d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); + double d = primp->toNumber(); int32_t base = 10; - if (argc != 0 && !JSVAL_IS_VOID(vp[2])) { + if (argc != 0 && !vp[2].isUndefined()) { if (!ValueToECMAInt32(cx, vp[2], &base)) return JS_FALSE; @@ -395,22 +390,22 @@ num_toString(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } } - str = js_NumberToStringWithBase(cx, d, base); + JSString *str = js_NumberToStringWithBase(cx, d, base); if (!str) { JS_ReportOutOfMemory(cx); return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -num_toLocaleString(JSContext *cx, uintN argc, jsval *vp) +num_toLocaleString(JSContext *cx, uintN argc, Value *vp) { size_t thousandsLength, decimalLength; const char *numGrouping, *tmpGroup; JSRuntime *rt; - JSString *numStr, *str; + JSString *str; const char *num, *end, *tmpSrc; char *buf, *tmpDest; const char *nint; @@ -422,9 +417,8 @@ num_toLocaleString(JSContext *cx, uintN argc, jsval *vp) */ if (!num_toString(cx, 0, vp)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_STRING(*vp)); - numStr = JSVAL_TO_STRING(*vp); - num = js_GetStringBytes(cx, numStr); + JS_ASSERT(vp->isString()); + num = js_GetStringBytes(cx, vp->toString()); if (!num) return JS_FALSE; @@ -500,7 +494,7 @@ num_toLocaleString(JSContext *cx, uintN argc, jsval *vp) } if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) - return cx->localeCallbacks->localeToUnicode(cx, buf, vp); + return cx->localeCallbacks->localeToUnicode(cx, buf, Jsvalify(vp)); str = JS_NewString(cx, buf, size); if (!str) { @@ -508,23 +502,19 @@ num_toLocaleString(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -num_valueOf(JSContext *cx, uintN argc, jsval *vp) +num_valueOf(JSContext *cx, uintN argc, Value *vp) { - jsval v; - JSObject *obj; - - v = vp[1]; - if (JSVAL_IS_NUMBER(v)) { - *vp = v; + if (vp[1].isNumber()) { + *vp = vp[1]; return JS_TRUE; } - obj = JS_THIS_OBJECT(cx, vp); - if (!JS_InstanceOf(cx, obj, &js_NumberClass, vp + 2)) + JSObject *obj = ComputeThisFromVp(cx, vp); + if (!InstanceOf(cx, obj, &js_NumberClass, vp + 2)) return JS_FALSE; *vp = obj->getPrimitiveThis(); return JS_TRUE; @@ -536,21 +526,18 @@ num_valueOf(JSContext *cx, uintN argc, jsval *vp) static JSBool num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, jsint precisionMin, jsint precisionMax, jsint precisionOffset, - uintN argc, jsval *vp) + uintN argc, Value *vp) { - jsval v; - jsdouble d, precision; - JSString *str; - /* Use MAX_PRECISION+1 because precisionOffset can be 1. */ char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)]; char *numStr; - if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + const Value *primp; + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &primp)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_NUMBER(v)); - d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); + double d = primp->toNumber(); + double precision; if (argc == 0) { precision = 0.0; oneArgMode = zeroArgMode; @@ -575,10 +562,10 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, JS_ReportOutOfMemory(cx); return JS_FALSE; } - str = JS_NewStringCopyZ(cx, numStr); + JSString *str = JS_NewStringCopyZ(cx, numStr); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } @@ -587,23 +574,23 @@ num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, * than ECMA requires; this is permitted by ECMA-262. */ static JSBool -num_toFixed(JSContext *cx, uintN argc, jsval *vp) +num_toFixed(JSContext *cx, uintN argc, Value *vp) { return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0, argc, vp); } static JSBool -num_toExponential(JSContext *cx, uintN argc, jsval *vp) +num_toExponential(JSContext *cx, uintN argc, Value *vp) { return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1, argc, vp); } static JSBool -num_toPrecision(JSContext *cx, uintN argc, jsval *vp) +num_toPrecision(JSContext *cx, uintN argc, Value *vp) { - if (argc == 0 || JSVAL_IS_VOID(vp[2])) + if (argc == 0 || vp[2].isUndefined()) return num_toString(cx, 0, vp); return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0, argc, vp); @@ -685,31 +672,25 @@ inline void FIX_FPU() { JSBool js_InitRuntimeNumberState(JSContext *cx) { - JS_STATIC_ASSERT(JSVAL_NULL == jsval(0)); - JSRuntime *rt = cx->runtime; - JS_ASSERT(JSVAL_IS_NULL(rt->NaNValue)); FIX_FPU(); jsdpun u; - u.s.hi = JSDOUBLE_HI32_EXPMASK | JSDOUBLE_HI32_MANTMASK; - u.s.lo = 0xffffffff; + u.s.hi = 0x7ff80000; + u.s.lo = 0x00000000; number_constants[NC_NaN].dval = js_NaN = u.d; - if (!js_NewDoubleInRootedValue(cx, u.d, &rt->NaNValue)) - return false; + rt->NaNValue.setDouble(u.d); u.s.hi = JSDOUBLE_HI32_EXPMASK; u.s.lo = 0x00000000; number_constants[NC_POSITIVE_INFINITY].dval = js_PositiveInfinity = u.d; - if (!js_NewDoubleInRootedValue(cx, u.d, &rt->positiveInfinityValue)) - return false; + rt->positiveInfinityValue.setDouble(u.d); u.s.hi = JSDOUBLE_HI32_SIGNBIT | JSDOUBLE_HI32_EXPMASK; u.s.lo = 0x00000000; number_constants[NC_NEGATIVE_INFINITY].dval = js_NegativeInfinity = u.d; - if (!js_NewDoubleInRootedValue(cx, u.d, &rt->negativeInfinityValue)) - return false; + rt->negativeInfinityValue.setDouble(u.d); u.s.hi = 0; u.s.lo = 1; @@ -732,32 +713,11 @@ js_InitRuntimeNumberState(JSContext *cx) return rt->thousandsSeparator && rt->decimalSeparator && rt->numGrouping; } -void -js_TraceRuntimeNumberState(JSTracer *trc) -{ - JSRuntime *rt = trc->context->runtime; - - if (!JSVAL_IS_NULL(rt->NaNValue)) - JS_CALL_DOUBLE_TRACER(trc, JSVAL_TO_DOUBLE(rt->NaNValue), "NaN"); - if (!JSVAL_IS_NULL(rt->positiveInfinityValue)) { - JS_CALL_DOUBLE_TRACER(trc, JSVAL_TO_DOUBLE(rt->positiveInfinityValue), - "+Infinity"); - } - if (!JSVAL_IS_NULL(rt->negativeInfinityValue)) { - JS_CALL_DOUBLE_TRACER(trc, JSVAL_TO_DOUBLE(rt->negativeInfinityValue), - "-Infinity"); - } -} - void js_FinishRuntimeNumberState(JSContext *cx) { JSRuntime *rt = cx->runtime; - rt->NaNValue = JSVAL_NULL; - rt->negativeInfinityValue = JSVAL_NULL; - rt->positiveInfinityValue = JSVAL_NULL; - cx->free((void *) rt->thousandsSeparator); cx->free((void *) rt->decimalSeparator); cx->free((void *) rt->numGrouping); @@ -776,23 +736,24 @@ js_InitNumberClass(JSContext *cx, JSObject *obj) if (!JS_DefineFunctions(cx, obj, number_functions)) return NULL; - proto = JS_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1, + proto = js_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1, NULL, number_methods, NULL, NULL); if (!proto || !(ctor = JS_GetConstructor(cx, proto))) return NULL; - proto->setPrimitiveThis(JSVAL_ZERO); + proto->setPrimitiveThis(Int32Value(0)); if (!JS_DefineConstDoubles(cx, ctor, number_constants)) return NULL; /* ECMA 15.1.1.1 */ rt = cx->runtime; - if (!JS_DefineProperty(cx, obj, js_NaN_str, rt->NaNValue, JS_PropertyStub, JS_PropertyStub, + if (!JS_DefineProperty(cx, obj, js_NaN_str, Jsvalify(rt->NaNValue), + JS_PropertyStub, JS_PropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return NULL; } /* ECMA 15.1.1.2 */ - if (!JS_DefineProperty(cx, obj, js_Infinity_str, rt->positiveInfinityValue, + if (!JS_DefineProperty(cx, obj, js_Infinity_str, Jsvalify(rt->positiveInfinityValue), JS_PropertyStub, JS_PropertyStub, JSPROP_PERMANENT | JSPROP_READONLY)) { return NULL; @@ -800,29 +761,6 @@ js_InitNumberClass(JSContext *cx, JSObject *obj) return proto; } -JSBool -js_NewNumberInRootedValue(JSContext *cx, jsdouble d, jsval *vp) -{ - jsint i; - - if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) { - *vp = INT_TO_JSVAL(i); - return JS_TRUE; - } - return js_NewDoubleInRootedValue(cx, d, vp); -} - -JSBool -js_NewWeaklyRootedNumber(JSContext *cx, jsdouble d, jsval *rval) -{ - jsint i; - if (JSDOUBLE_IS_INT(d, i) && INT_FITS_IN_JSVAL(i)) { - *rval = INT_TO_JSVAL(i); - return JS_TRUE; - } - return JS_NewDoubleValue(cx, d, rval); -} - /* * Convert a number to C string. The buf must be large enough to accommodate * the result, including '-' and '\0', if base == 10 or d is an integer that @@ -832,11 +770,11 @@ js_NewWeaklyRootedNumber(JSContext *cx, jsdouble d, jsval *rval) static char * NumberToCString(JSContext *cx, jsdouble d, jsint base, char *buf, size_t bufSize) { - jsint i; + int32_t i; char *numStr; JS_ASSERT(bufSize >= DTOSTR_STANDARD_BUFFER_SIZE); - if (JSDOUBLE_IS_INT(d, i)) { + if (JSDOUBLE_IS_INT32(d, &i)) { numStr = IntToCString(i, base, buf, bufSize); } else { if (base == 10) @@ -883,8 +821,8 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base) if (base < 2 || base > 36) return NULL; - jsint i; - if (JSDOUBLE_IS_INT(d, i)) { + int32_t i; + if (JSDOUBLE_IS_INT32(d, &i)) { if (base == 10 && jsuint(i) < INT_STRING_LIMIT) return JSString::intString(i); if (jsuint(i) < jsuint(base)) { @@ -915,18 +853,17 @@ js_NumberToString(JSContext *cx, jsdouble d) } JSBool JS_FASTCALL -js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb) +js_NumberValueToCharBuffer(JSContext *cx, const Value &v, JSCharBuffer &cb) { /* Convert to C-string. */ static const size_t arrSize = DTOSTR_STANDARD_BUFFER_SIZE; char arr[arrSize]; const char *cstr; - if (JSVAL_IS_INT(v)) { - cstr = IntToCString(JSVAL_TO_INT(v), 10, arr, arrSize); + if (v.isInt32()) { + cstr = IntToCString(v.toInt32(), 10, arr, arrSize); } else { - JS_ASSERT(JSVAL_IS_DOUBLE(v)); cstr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, arr, arrSize, - DTOSTR_STANDARD, 0, *JSVAL_TO_DOUBLE(v)); + DTOSTR_STANDARD, 0, v.toDouble()); } if (!cstr) return JS_FALSE; @@ -938,7 +875,7 @@ js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb) size_t cstrlen = strlen(cstr); JS_ASSERT(cstrlen < arrSize); size_t sizeBefore = cb.length(); - if (!cb.growBy(cstrlen)) + if (!cb.growByUninitialized(cstrlen)) return JS_FALSE; jschar *appendBegin = cb.begin() + sizeBefore; #ifdef DEBUG @@ -952,87 +889,59 @@ js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb) namespace js { -jsval -ValueToNumberSlow(JSContext *cx, jsval v, double *out) +bool +ValueToNumberSlow(JSContext *cx, Value v, double *out) { - JS_ASSERT(!JSVAL_IS_INT(v) && !JSVAL_IS_DOUBLE(v)); + JS_ASSERT(!v.isNumber()); goto skip_int_double; for (;;) { - if (JSVAL_IS_INT(v)) { - *out = (double)JSVAL_TO_INT(v); - return v; - } - if (JSVAL_IS_DOUBLE(v)) { - *out = *JSVAL_TO_DOUBLE(v); - return v; + if (v.isNumber()) { + *out = v.toNumber(); + return true; } skip_int_double: - if (JSVAL_IS_STRING(v)) { - JSString *str = JSVAL_TO_STRING(v); - - jsdouble d = StringToNumberType(cx, str); + if (v.isString()) { + jsdouble d = StringToNumberType(cx, v.toString()); if (JSDOUBLE_IS_NaN(d)) break; - - /* - * JSVAL_TRUE indicates that double jsval was never constructed - * for the result. - */ *out = d; - return JSVAL_TRUE; + return true; } - if (JSVAL_IS_BOOLEAN(v)) { - if (JSVAL_TO_BOOLEAN(v)) { + if (v.isBoolean()) { + if (v.toBoolean()) { *out = 1.0; - return JSVAL_ONE; + return true; } *out = 0.0; - return JSVAL_ZERO; + return true; } - if (JSVAL_IS_NULL(v)) { + if (v.isNull()) { *out = 0.0; - return JSVAL_ZERO; + return true; } - if (JSVAL_IS_VOID(v)) + if (v.isUndefined()) break; - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); - if (!DefaultValue(cx, JSVAL_TO_OBJECT(v), JSTYPE_NUMBER, &v)) - return JSVAL_NULL; - if (!JSVAL_IS_PRIMITIVE(v)) + JS_ASSERT(v.isObject()); + if (!DefaultValue(cx, &v.toObject(), JSTYPE_NUMBER, &v)) + return false; + if (v.isObject()) break; } *out = js_NaN; - return cx->runtime->NaNValue; + return true; } bool -ValueToNumberValueSlow(JSContext *cx, jsval *vp, double *out) +ValueToECMAInt32Slow(JSContext *cx, const Value &v, int32_t *out) { - jsval v = *vp = ValueToNumberSlow(cx, *vp, out); - return !JSVAL_IS_NULL(v) && - (v != JSVAL_TRUE || js_NewNumberInRootedValue(cx, *out, vp)); -} - -bool -ValueToNumberValueSlow(JSContext *cx, jsval *vp) -{ - double d; - jsval v = *vp = ValueToNumberSlow(cx, *vp, &d); - return !JSVAL_IS_NULL(v) && - (v != JSVAL_TRUE || js_NewNumberInRootedValue(cx, d, vp)); -} - -bool -ValueToECMAInt32Slow(JSContext *cx, jsval v, int32_t *out) -{ - JS_ASSERT(!JSVAL_IS_INT(v)); + JS_ASSERT(!v.isInt32()); jsdouble d; - if (JSVAL_IS_DOUBLE(v)) { - d = *JSVAL_TO_DOUBLE(v); + if (v.isDouble()) { + d = v.toDouble(); } else { - if (JSVAL_IS_NULL(ValueToNumberSlow(cx, v, &d))) + if (!ValueToNumberSlow(cx, v, &d)) return false; } *out = js_DoubleToECMAInt32(d); @@ -1040,14 +949,14 @@ ValueToECMAInt32Slow(JSContext *cx, jsval v, int32_t *out) } bool -ValueToECMAUint32Slow(JSContext *cx, jsval v, uint32_t *out) +ValueToECMAUint32Slow(JSContext *cx, const Value &v, uint32_t *out) { - JS_ASSERT(!JSVAL_IS_INT(v)); + JS_ASSERT(!v.isInt32()); jsdouble d; - if (JSVAL_IS_DOUBLE(v)) { - d = *JSVAL_TO_DOUBLE(v); + if (v.isDouble()) { + d = v.toDouble(); } else { - if (JSVAL_IS_NULL(ValueToNumberSlow(cx, v, &d))) + if (!ValueToNumberSlow(cx, v, &d)) return false; } *out = js_DoubleToECMAUint32(d); @@ -1069,7 +978,7 @@ js_DoubleToECMAUint32(jsdouble d) /* * We check whether d fits int32, not uint32, as all but the ">>>" bit * manipulation bytecode stores the result as int, not uint. When the - * result does not fit int jsval, it will be stored as a negative double. + * result does not fit int Value, it will be stored as a negative double. */ i = (int32) d; if ((jsdouble) i == d) @@ -1088,20 +997,14 @@ js_DoubleToECMAUint32(jsdouble d) namespace js { bool -ValueToInt32Slow(JSContext *cx, jsval v, int32_t *out) +ValueToInt32Slow(JSContext *cx, const Value &v, int32_t *out) { - JS_ASSERT(!JSVAL_IS_INT(v)); + JS_ASSERT(!v.isInt32()); jsdouble d; - if (JSVAL_IS_DOUBLE(v)) { - d = *JSVAL_TO_DOUBLE(v); - } else { - jsval v2 = ValueToNumberSlow(cx, v, &d); - if (JSVAL_IS_NULL(v2)) - return false; - if (JSVAL_IS_INT(v2)) { - *out = JSVAL_TO_INT(v2); - return true; - } + if (v.isDouble()) { + d = v.toDouble(); + } else if (!ValueToNumberSlow(cx, v, &d)) { + return false; } if (JSDOUBLE_IS_NaN(d) || d <= -2147483649.0 || 2147483648.0 <= d) { @@ -1114,20 +1017,14 @@ ValueToInt32Slow(JSContext *cx, jsval v, int32_t *out) } bool -ValueToUint16Slow(JSContext *cx, jsval v, uint16_t *out) +ValueToUint16Slow(JSContext *cx, const Value &v, uint16_t *out) { - JS_ASSERT(!JSVAL_IS_INT(v)); + JS_ASSERT(!v.isInt32()); jsdouble d; - if (JSVAL_IS_DOUBLE(v)) { - d = *JSVAL_TO_DOUBLE(v); - } else { - jsval v2 = ValueToNumberSlow(cx, v, &d); - if (JSVAL_IS_NULL(v2)) - return false; - if (JSVAL_IS_INT(v2)) { - *out = (uint16_t) JSVAL_TO_INT(v2); - return true; - } + if (v.isDouble()) { + d = v.toDouble(); + } else if (!ValueToNumberSlow(cx, v, &d)) { + return false; } if (d == 0 || !JSDOUBLE_IS_FINITE(d)) { diff --git a/js/src/jsnum.h b/js/src/jsnum.h index d09f82f82552..aae674b0eaa9 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -47,6 +47,7 @@ #ifdef SOLARIS #include #endif +#include "jsvalue.h" #include "jsstdint.h" #include "jsstr.h" @@ -117,31 +118,11 @@ JSDOUBLE_IS_INFINITE(jsdouble d) #endif } -static inline int -JSDOUBLE_IS_NEGZERO(jsdouble d) -{ -#ifdef WIN32 - return (d == 0 && (_fpclass(d) & _FPCLASS_NZ)); -#elif defined(SOLARIS) - return (d == 0 && copysign(1, d) < 0); -#else - return (d == 0 && signbit(d)); -#endif -} - #define JSDOUBLE_HI32_SIGNBIT 0x80000000 #define JSDOUBLE_HI32_EXPMASK 0x7ff00000 #define JSDOUBLE_HI32_MANTMASK 0x000fffff -static inline int -JSDOUBLE_IS_INT(jsdouble d, jsint& i) -{ - if (JSDOUBLE_IS_NEGZERO(d)) - return false; - return d == (i = jsint(d)); -} - -static inline int +static inline bool JSDOUBLE_IS_NEG(jsdouble d) { #ifdef WIN32 @@ -178,14 +159,11 @@ extern jsdouble js_NegativeInfinity; extern JSBool js_InitRuntimeNumberState(JSContext *cx); -extern void -js_TraceRuntimeNumberState(JSTracer *trc); - extern void js_FinishRuntimeNumberState(JSContext *cx); /* Initialize the Number class, returning its prototype object. */ -extern JSClass js_NumberClass; +extern js::Class js_NumberClass; inline bool JSObject::isNumber() const @@ -193,7 +171,7 @@ JSObject::isNumber() const return getClass() == &js_NumberClass; } -extern "C" JSObject * +extern JSObject * js_InitNumberClass(JSContext *cx, JSObject *obj); /* @@ -206,19 +184,6 @@ extern const char js_isFinite_str[]; extern const char js_parseFloat_str[]; extern const char js_parseInt_str[]; -/* - * vp must be a root. - */ -extern JSBool -js_NewNumberInRootedValue(JSContext *cx, jsdouble d, jsval *vp); - -/* - * Create a weakly rooted integer or double jsval as appropriate for the given - * jsdouble. - */ -extern JSBool -js_NewWeaklyRootedNumber(JSContext *cx, jsdouble d, jsval *vp); - extern JSString * JS_FASTCALL js_IntToString(JSContext *cx, jsint i); @@ -226,131 +191,99 @@ extern JSString * JS_FASTCALL js_NumberToString(JSContext *cx, jsdouble d); /* - * Convert an integer or double (contained in the given jsval) to a string and + * Convert an integer or double (contained in the given value) to a string and * append to the given buffer. */ extern JSBool JS_FASTCALL -js_NumberValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb); +js_NumberValueToCharBuffer(JSContext *cx, const js::Value &v, JSCharBuffer &cb); namespace js { /* * Convert a value to a number, returning the converted value in 'out' if the - * conversion succeeds. v most be a copy of a rooted jsval. + * conversion succeeds. */ JS_ALWAYS_INLINE bool -ValueToNumber(JSContext *cx, jsval v, double *out) +ValueToNumber(JSContext *cx, const js::Value &v, double *out) { - if (JSVAL_IS_INT(v)) { - *out = JSVAL_TO_INT(v); + if (v.isNumber()) { + *out = v.toNumber(); return true; } - if (JSVAL_IS_DOUBLE(v)) { - *out = *JSVAL_TO_DOUBLE(v); - return true; - } - extern jsval ValueToNumberSlow(JSContext *, jsval, double *); - return !JSVAL_IS_NULL(ValueToNumberSlow(cx, v, out)); + extern bool ValueToNumberSlow(JSContext *, js::Value, double *); + return ValueToNumberSlow(cx, v, out); } -/* - * Convert a value to a number, replacing 'vp' with the converted value and - * returning the value as a double in 'out'. vp must point to a rooted jsval. - * - * N.B. this function will allocate a new double if needed; callers needing - * only a double, not a value, should use ValueToNumber instead. - */ +/* Convert a value to a number, replacing 'vp' with the converted value. */ JS_ALWAYS_INLINE bool -ValueToNumberValue(JSContext *cx, jsval *vp, double *out) +ValueToNumber(JSContext *cx, js::Value *vp) { - jsval v = *vp; - if (JSVAL_IS_INT(v)) { - *out = JSVAL_TO_INT(v); + if (vp->isNumber()) return true; - } - if (JSVAL_IS_DOUBLE(v)) { - *out = *JSVAL_TO_DOUBLE(v); - return true; - } - extern bool ValueToNumberValueSlow(JSContext *, jsval *, double *); - return ValueToNumberValueSlow(cx, vp, out); -} - -/* - * Convert a value to a number, replacing 'vp' with the converted value. vp - * must point to a rooted jsval. - * - * N.B. this function will allocate a new double if needed; callers needing - * only a double, not a value, should use ValueToNumber instead. - */ -JS_ALWAYS_INLINE bool -ValueToNumberValue(JSContext *cx, jsval *vp) -{ - jsval v = *vp; - if (JSVAL_IS_INT(v)) - return true; - if (JSVAL_IS_DOUBLE(v)) - return true; - extern bool ValueToNumberValueSlow(JSContext *, jsval *); - return ValueToNumberValueSlow(cx, vp); + double d; + extern bool ValueToNumberSlow(JSContext *, js::Value, double *); + if (!ValueToNumberSlow(cx, *vp, &d)) + return false; + vp->setNumber(d); + return true; } /* * Convert a value to an int32 or uint32, according to the ECMA rules for - * ToInt32 and ToUint32. Return converted value on success, !ok on failure. v - * must be a copy of a rooted jsval. + * ToInt32 and ToUint32. Return converted value in *out on success, !ok on + * failure. */ JS_ALWAYS_INLINE bool -ValueToECMAInt32(JSContext *cx, jsval v, int32_t *out) +ValueToECMAInt32(JSContext *cx, const js::Value &v, int32_t *out) { - if (JSVAL_IS_INT(v)) { - *out = JSVAL_TO_INT(v); + if (v.isInt32()) { + *out = v.toInt32(); return true; } - extern bool ValueToECMAInt32Slow(JSContext *, jsval, int32_t *); + extern bool ValueToECMAInt32Slow(JSContext *, const js::Value &, int32_t *); return ValueToECMAInt32Slow(cx, v, out); } JS_ALWAYS_INLINE bool -ValueToECMAUint32(JSContext *cx, jsval v, uint32_t *out) +ValueToECMAUint32(JSContext *cx, const js::Value &v, uint32_t *out) { - if (JSVAL_IS_INT(v)) { - *out = (uint32_t)JSVAL_TO_INT(v); + if (v.isInt32()) { + *out = (uint32_t)v.toInt32(); return true; } - extern bool ValueToECMAUint32Slow(JSContext *, jsval, uint32_t *); + extern bool ValueToECMAUint32Slow(JSContext *, const js::Value &, uint32_t *); return ValueToECMAUint32Slow(cx, v, out); } /* * Convert a value to a number, then to an int32 if it fits by rounding to - * nearest. Return converted value on success, !ok on failure. v must be a copy - * of a rooted jsval. + * nearest. Return converted value in *out on success, !ok on failure. As a + * side effect, *vp will be mutated to match *out. */ JS_ALWAYS_INLINE bool -ValueToInt32(JSContext *cx, jsval v, int32_t *out) +ValueToInt32(JSContext *cx, const js::Value &v, int32_t *out) { - if (JSVAL_IS_INT(v)) { - *out = JSVAL_TO_INT(v); + if (v.isInt32()) { + *out = v.toInt32(); return true; } - extern bool ValueToInt32Slow(JSContext *, jsval, int32_t *); + extern bool ValueToInt32Slow(JSContext *, const js::Value &, int32_t *); return ValueToInt32Slow(cx, v, out); } /* * Convert a value to a number, then to a uint16 according to the ECMA rules * for ToUint16. Return converted value on success, !ok on failure. v must be a - * copy of a rooted jsval. + * copy of a rooted value. */ JS_ALWAYS_INLINE bool -ValueToUint16(JSContext *cx, jsval v, uint16_t *out) +ValueToUint16(JSContext *cx, const js::Value &v, uint16_t *out) { - if (JSVAL_IS_INT(v)) { - *out = (uint16_t)JSVAL_TO_INT(v); + if (v.isInt32()) { + *out = (uint16_t)v.toInt32(); return true; } - extern bool ValueToUint16Slow(JSContext *, jsval, uint16_t *); + extern bool ValueToUint16Slow(JSContext *, const js::Value &, uint16_t *); return ValueToUint16Slow(cx, v, out); } @@ -638,6 +571,16 @@ js_strtointeger(JSContext *cx, const jschar *s, const jschar *send, namespace js { +static JS_ALWAYS_INLINE bool +ValueFitsInInt32(const Value &v, int32_t *pi) +{ + if (v.isInt32()) { + *pi = v.toInt32(); + return true; + } + return v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), pi); +} + template struct NumberTraits { }; template<> struct NumberTraits { static JS_ALWAYS_INLINE int32 NaN() { return 0; } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 3311cb2d5ab7..91550eefd19e 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -121,29 +121,29 @@ JS_FRIEND_DATA(JSObjectOps) js_ObjectOps = { js_Clear }; -JSClass js_ObjectClass = { +Class js_ObjectClass = { js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Object), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; #if JS_HAS_OBJ_PROTO_PROP static JSBool -obj_getProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp); static JSBool -obj_setProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +obj_setProto(JSContext *cx, JSObject *obj, jsid id, Value *vp); static JSPropertySpec object_props[] = { - {js_proto_str, 0, JSPROP_PERMANENT|JSPROP_SHARED, obj_getProto, obj_setProto}, + {js_proto_str, 0, JSPROP_PERMANENT|JSPROP_SHARED, Jsvalify(obj_getProto), Jsvalify(obj_setProto)}, {0,0,0,0,0} }; static JSBool -obj_getProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +obj_getProto(JSContext *cx, JSObject *obj, jsid id, Value *vp) { /* Let CheckAccess get the slot's value, based on the access mode. */ uintN attrs; @@ -152,12 +152,12 @@ obj_getProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp) } static JSBool -obj_setProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +obj_setProto(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - if (!JSVAL_IS_OBJECT(*vp)) + if (!vp->isObjectOrNull()) return JS_TRUE; - JSObject *pobj = JSVAL_TO_OBJECT(*vp); + JSObject *pobj = vp->toObjectOrNull(); if (pobj) { /* * Innerize pobj here to avoid sticking unwanted properties on the @@ -186,7 +186,7 @@ obj_setProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp) static JSHashNumber js_hash_object(const void *key) { - return JSHashNumber(uintptr_t(key) >> JSVAL_TAGBITS); + return JSHashNumber(uintptr_t(key) >> JS_GCTHING_ALIGN); } static JSHashEntry * @@ -227,14 +227,15 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) ok = JS_TRUE; for (i = 0, length = ida->length; i < length; i++) { id = ida->vector[i]; + js::Value val; ok = obj->lookupProperty(cx, id, &obj2, &prop); if (!ok) break; if (!prop) continue; bool hasGetter, hasSetter; - AutoValueRooter v(cx, JSVAL_VOID); - AutoValueRooter setter(cx, JSVAL_VOID); + AutoValueRooter v(cx); + AutoValueRooter setter(cx); if (obj2->isNative()) { JSScopeProperty *sprop = (JSScopeProperty *) prop; hasGetter = sprop->hasGetterValue(); @@ -249,8 +250,8 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) } if (hasSetter) { /* Mark the getter, then set val to setter. */ - if (hasGetter && !JSVAL_IS_PRIMITIVE(v.value())) { - ok = !!MarkSharpObjects(cx, JSVAL_TO_OBJECT(v.value()), NULL); + if (hasGetter && v.value().isObject()) { + ok = !!MarkSharpObjects(cx, &v.value().toObject(), NULL); if (!ok) break; } @@ -260,8 +261,8 @@ MarkSharpObjects(JSContext *cx, JSObject *obj, JSIdArray **idap) if (!ok) break; } - if (!JSVAL_IS_PRIMITIVE(v.value()) && - !MarkSharpObjects(cx, JSVAL_TO_OBJECT(v.value()), NULL)) { + if (v.value().isObject() && + !MarkSharpObjects(cx, &v.value().toObject(), NULL)) { ok = JS_FALSE; break; } @@ -468,7 +469,7 @@ js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map) #if JS_HAS_TOSOURCE static JSBool -obj_toSource(JSContext *cx, uintN argc, jsval *vp) +obj_toSource(JSContext *cx, uintN argc, Value *vp) { JSBool ok, outermost; JSObject *obj; @@ -480,18 +481,19 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) const char *comma; JSObject *obj2; JSProperty *prop; - jsval *val; + Value *val; JSString *gsop[2]; JSString *idstr, *valstr, *str; JS_CHECK_RECURSION(cx, return JS_FALSE); - jsval localroot[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + Value localroot[4]; + PodArrayZero(localroot); AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(localroot), localroot); /* If outermost, we need parentheses to be an expression, not a block. */ outermost = (cx->sharpObjectMap.depth == 0); - obj = JS_THIS_OBJECT(cx, vp); + obj = ComputeThisFromVp(cx, vp); if (!obj || !(he = js_EnterSharpObject(cx, obj, &ida, &chars))) { ok = JS_FALSE; goto out; @@ -564,16 +566,16 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) goto error; /* - * Convert id to a jsval and then to a string. Decide early whether we + * Convert id to a value and then to a string. Decide early whether we * prefer get/set or old getter/setter syntax. */ - idstr = js_ValueToString(cx, ID_TO_VALUE(id)); + idstr = js_ValueToString(cx, IdToValue(id)); if (!idstr) { ok = JS_FALSE; obj2->dropProperty(cx, prop); goto error; } - *vp = STRING_TO_JSVAL(idstr); /* local root */ + vp->setString(idstr); /* local root */ jsint valcnt = 0; if (prop) { @@ -617,7 +619,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) ok = JS_FALSE; goto error; } - *vp = STRING_TO_JSVAL(idstr); /* local root */ + vp->setString(idstr); /* local root */ } idstr->getCharsAndLength(idstrchars, idstrlength); @@ -626,7 +628,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) * Censor an accessor descriptor getter or setter part if it's * undefined. */ - if (gsop[j] && JSVAL_IS_VOID(val[j])) + if (gsop[j] && val[j].isUndefined()) continue; /* Convert val[j] to its canonical source form. */ @@ -635,7 +637,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) ok = JS_FALSE; goto error; } - localroot[j] = STRING_TO_JSVAL(valstr); /* local root */ + localroot[j].setString(valstr); /* local root */ valstr->getCharsAndLength(vchars, vlength); /* @@ -646,8 +648,8 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) vsharp = NULL; vsharplength = 0; #if JS_HAS_SHARP_VARS - if (!gsop[j] && !JSVAL_IS_PRIMITIVE(val[j]) && vchars[0] != '#') { - he = js_EnterSharpObject(cx, JSVAL_TO_OBJECT(val[j]), NULL, &vsharp); + if (!gsop[j] && val[j].isObject() && vchars[0] != '#') { + he = js_EnterSharpObject(cx, &val[j].toObject(), NULL, &vsharp); if (!he) { ok = JS_FALSE; goto error; @@ -669,8 +671,8 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) * Remove '(function ' from the beginning of valstr and ')' from the * end so that we can put "get" in front of the function definition. */ - if (gsop[j] && VALUE_IS_FUNCTION(cx, val[j])) { - JSFunction *fun = JS_ValueToFunction(cx, val[j]); + if (gsop[j] && IsFunctionObject(val[j])) { + JSFunction *fun = js_ValueToFunction(cx, &val[j], JSV2F_SEARCH_STACK); const jschar *start = vchars; const jschar *end = vchars + vlength; @@ -801,7 +803,7 @@ obj_toSource(JSContext *cx, uintN argc, jsval *vp) ok = JS_FALSE; goto out; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); ok = JS_TRUE; out: return ok; @@ -846,9 +848,9 @@ obj_toStringHelper(JSContext *cx, JSObject *obj) } static JSBool -obj_toString(JSContext *cx, uintN argc, jsval *vp) +obj_toString(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return false; @@ -856,33 +858,31 @@ obj_toString(JSContext *cx, uintN argc, jsval *vp) if (!str) return false; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return true; } static JSBool -obj_toLocaleString(JSContext *cx, uintN argc, jsval *vp) +obj_toLocaleString(JSContext *cx, uintN argc, Value *vp) { - jsval thisv; - JSString *str; - - thisv = JS_THIS(cx, vp); - if (JSVAL_IS_NULL(thisv)) + if (!ComputeThisFromVp(cx, vp)) return JS_FALSE; - str = js_ValueToString(cx, thisv); + JSString *str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -obj_valueOf(JSContext *cx, uintN argc, jsval *vp) +obj_valueOf(JSContext *cx, uintN argc, Value *vp) { - *vp = JS_THIS(cx, vp); - return !JSVAL_IS_NULL(*vp); + if (!ComputeThisFromVp(cx, vp)) + return JS_FALSE; + *vp = vp[1]; + return JS_TRUE; } /* @@ -934,7 +934,7 @@ js_CheckPrincipalsAccess(JSContext *cx, JSObject *scopeobj, JSObject * js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller) { - JSClass *clasp; + Class *clasp; JSExtendedClass *xclasp; JSObject *inner; @@ -1020,10 +1020,10 @@ EvalCacheHash(JSContext *cx, JSString *str) } static JSBool -obj_eval(JSContext *cx, uintN argc, jsval *vp) +obj_eval(JSContext *cx, uintN argc, Value *vp) { if (argc < 1) { - *vp = JSVAL_VOID; + vp->setUndefined(); return JS_TRUE; } @@ -1046,8 +1046,8 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) * we're guaranteed to be allowed to access) then we do a security * check. */ - jsval *argv = JS_ARGV(cx, vp); - JSObject *obj = JS_THIS_OBJECT(cx, vp); + Value *argv = JS_ARGV(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return JS_FALSE; obj = obj->wrappedObject(cx); @@ -1071,7 +1071,7 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) } } - if (!JSVAL_IS_STRING(argv[0])) { + if (!argv[0].isString()) { *vp = argv[0]; return JS_TRUE; } @@ -1079,9 +1079,9 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) /* Accept an optional trailing argument that overrides the scope object. */ JSObject *scopeobj = NULL; if (argc >= 2) { - if (!js_ValueToObject(cx, argv[1], &scopeobj)) + if (!js_ValueToObjectOrNull(cx, argv[1], &scopeobj)) return JS_FALSE; - argv[1] = OBJECT_TO_JSVAL(scopeobj); + argv[1].setObjectOrNull(scopeobj); JSObject *obj = scopeobj; while (obj) { if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx)) @@ -1136,7 +1136,7 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - /* NB: We know obj is a global object here. */ + /* NB: We know inner is a global object here. */ JS_ASSERT(!obj->getParent()); scopeobj = obj; } else { @@ -1173,7 +1173,7 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) scopeobj = withGuard.obj; JS_ASSERT(argc >= 2); - argv[1] = OBJECT_TO_JSVAL(withGuard.obj); + argv[1].setObject(*withGuard.obj); } /* We're pretending that we're in global code. */ @@ -1193,12 +1193,12 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - JSObject *callee = JSVAL_TO_OBJECT(vp[0]); + JSObject *callee = &vp[0].toObject(); JSPrincipals *principals = js_EvalFramePrincipals(cx, callee, caller); uintN line; const char *file = js_ComputeFilename(cx, caller, principals, &line); - JSString *str = JSVAL_TO_STRING(argv[0]); + JSString *str = argv[0].toString(); JSScript *script = NULL; /* @@ -1299,7 +1299,7 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) */ JSBool ok = js_CheckPrincipalsAccess(cx, scopeobj, principals, cx->runtime->atomState.evalAtom) && - js_Execute(cx, scopeobj, script, callerFrame, JSFRAME_EVAL, vp); + Execute(cx, scopeobj, script, callerFrame, JSFRAME_EVAL, vp); script->u.nextToGC = *bucket; *bucket = script; @@ -1313,8 +1313,8 @@ obj_eval(JSContext *cx, uintN argc, jsval *vp) #if JS_HAS_OBJ_WATCHPOINT static JSBool -obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp, - void *closure) +obj_watch_handler(JSContext *cx, JSObject *obj, jsid id, jsval old, + jsval *nvp, void *closure) { JSObject *callable; JSSecurityCallbacks *callbacks; @@ -1323,7 +1323,7 @@ obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp, JSResolvingKey key; JSResolvingEntry *entry; uint32 generation; - jsval argv[3]; + Value argv[3]; JSBool ok; callable = (JSObject *) closure; @@ -1356,61 +1356,61 @@ obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp, return JS_TRUE; generation = cx->resolvingTable->generation; - argv[0] = id; - argv[1] = old; - argv[2] = *nvp; - ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(callable), 3, argv, nvp); + argv[0] = IdToValue(id); + argv[1] = Valueify(old); + argv[2] = Valueify(*nvp); + ok = InternalCall(cx, obj, ObjectOrNullValue(callable), 3, argv, Valueify(nvp)); js_StopResolving(cx, &key, JSRESFLAG_WATCH, entry, generation); return ok; } static JSBool -obj_watch(JSContext *cx, uintN argc, jsval *vp) +obj_watch(JSContext *cx, uintN argc, Value *vp) { - JSObject *callable; - jsval userid, value; - jsid propid; - JSObject *obj; - uintN attrs; - if (argc <= 1) { - js_ReportMissingArg(cx, vp, 1); + js_ReportMissingArg(cx, *vp, 1); return JS_FALSE; } - callable = js_ValueToCallableObject(cx, &vp[3], 0); + JSObject *callable = js_ValueToCallableObject(cx, &vp[3], 0); if (!callable) return JS_FALSE; /* Compute the unique int/atom symbol id needed by js_LookupProperty. */ - userid = vp[2]; - if (!JS_ValueToId(cx, userid, &propid)) + jsid propid; + if (!ValueToId(cx, vp[2], &propid)) return JS_FALSE; - obj = JS_THIS_OBJECT(cx, vp); - if (!obj || !CheckAccess(cx, obj, propid, JSACC_WATCH, &value, &attrs)) + JSObject *obj = ComputeThisFromVp(cx, vp); + Value tmp; + uintN attrs; + if (!obj || !CheckAccess(cx, obj, propid, JSACC_WATCH, &tmp, &attrs)) return JS_FALSE; - *vp = JSVAL_VOID; + vp->setUndefined(); if (attrs & JSPROP_READONLY) return JS_TRUE; if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx)) return JS_FALSE; - return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, callable); + return JS_SetWatchPoint(cx, obj, propid, obj_watch_handler, callable); } static JSBool -obj_unwatch(JSContext *cx, uintN argc, jsval *vp) +obj_unwatch(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return JS_FALSE; - *vp = JSVAL_VOID; - return JS_ClearWatchPoint(cx, obj, argc != 0 ? vp[2] : JSVAL_VOID, - NULL, NULL); + vp->setUndefined(); + jsid id; + if (argc != 0) { + if (!ValueToId(cx, vp[2], &id)) + return JS_FALSE; + } else { + id = JSID_VOID; + } + return JS_ClearWatchPoint(cx, obj, id, NULL, NULL); } #endif /* JS_HAS_OBJ_WATCHPOINT */ @@ -1422,24 +1422,22 @@ obj_unwatch(JSContext *cx, uintN argc, jsval *vp) /* Proposed ECMA 15.2.4.5. */ static JSBool -obj_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) +obj_hasOwnProperty(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); return obj && js_HasOwnPropertyHelper(cx, obj->map->ops->lookupProperty, argc, vp); } JSBool js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc, - jsval *vp) + Value *vp) { jsid id; - if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id)) + if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id)) return JS_FALSE; - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); JSObject *obj2; JSProperty *prop; if (!obj) @@ -1448,16 +1446,16 @@ js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc, bool has; if (!JSProxy::hasOwn(cx, obj, id, &has)) return false; - *vp = BOOLEAN_TO_JSVAL(has); + vp->setBoolean(has); return true; } if (!js_HasOwnProperty(cx, lookup, obj, id, &obj2, &prop)) return JS_FALSE; if (prop) { - *vp = JSVAL_TRUE; + vp->setBoolean(true); obj2->dropProperty(cx, prop); } else { - *vp = JSVAL_FALSE; + vp->setBoolean(false); } return JS_TRUE; } @@ -1477,7 +1475,7 @@ js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, JSExtendedClass *xclasp; JSObject *outer; - JSClass *clasp = (*objp)->getClass(); + Class *clasp = (*objp)->getClass(); if (!(clasp->flags & JSCLASS_IS_EXTENDED) || !(xclasp = (JSExtendedClass *) clasp)->outerObject) { outer = NULL; @@ -1517,34 +1515,30 @@ js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, /* Proposed ECMA 15.2.4.6. */ static JSBool -obj_isPrototypeOf(JSContext *cx, uintN argc, jsval *vp) +obj_isPrototypeOf(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); if (!obj) return JS_FALSE; - JSBool b; - if (!js_IsDelegate(cx, obj, argc != 0 ? vp[2] : JSVAL_VOID, &b)) - return JS_FALSE; - *vp = BOOLEAN_TO_JSVAL(b); + const Value &v = argc != 0 ? vp[2] : UndefinedValue(); + vp->setBoolean(js_IsDelegate(cx, obj, v)); return JS_TRUE; } /* Proposed ECMA 15.2.4.7. */ static JSBool -obj_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp) +obj_propertyIsEnumerable(JSContext *cx, uintN argc, Value *vp) { jsid id; - JSObject *obj; - - if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id)) + if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id)) return JS_FALSE; - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); return obj && js_PropertyIsEnumerable(cx, obj, id, vp); } JSBool -js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, Value *vp) { JSObject *pobj; JSProperty *prop; @@ -1552,7 +1546,7 @@ js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp) return JS_FALSE; if (!prop) { - *vp = JSVAL_FALSE; + vp->setBoolean(false); return JS_TRUE; } @@ -1580,10 +1574,10 @@ js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp) return false; } if (pobj != obj && !shared) { - *vp = JSVAL_FALSE; + vp->setBoolean(false); return true; } - *vp = BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0); + vp->setBoolean((attrs & JSPROP_ENUMERATE) != 0); return true; } @@ -1595,88 +1589,80 @@ const char js_lookupGetter_str[] = "__lookupGetter__"; const char js_lookupSetter_str[] = "__lookupSetter__"; JS_FRIEND_API(JSBool) -js_obj_defineGetter(JSContext *cx, uintN argc, jsval *vp) +js_obj_defineGetter(JSContext *cx, uintN argc, Value *vp) { - jsval fval, junk; - jsid id; - JSObject *obj; - uintN attrs; - if (argc <= 1 || !js_IsCallable(vp[3])) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GETTER_OR_SETTER, js_getter_str); return JS_FALSE; } - fval = vp[3]; + PropertyOp getter = CastAsPropertyOp(&vp[3].toObject()); - if (!JS_ValueToId(cx, vp[2], &id)) + jsid id; + if (!ValueToId(cx, vp[2], &id)) return JS_FALSE; - obj = JS_THIS_OBJECT(cx, vp); - if (!obj || !js_CheckRedeclaration(cx, obj, id, JSPROP_GETTER, NULL, NULL)) + JSObject *obj = ComputeThisFromVp(cx, vp); + if (!obj || !CheckRedeclaration(cx, obj, id, JSPROP_GETTER, NULL, NULL)) return JS_FALSE; /* * Getters and setters are just like watchpoints from an access * control point of view. */ + Value junk; + uintN attrs; if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs)) return JS_FALSE; - *vp = JSVAL_VOID; - return obj->defineProperty(cx, id, JSVAL_VOID, - CastAsPropertyOp(JSVAL_TO_OBJECT(fval)), JS_PropertyStub, + vp->setUndefined(); + return obj->defineProperty(cx, id, UndefinedValue(), getter, PropertyStub, JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED); } JS_FRIEND_API(JSBool) -js_obj_defineSetter(JSContext *cx, uintN argc, jsval *vp) +js_obj_defineSetter(JSContext *cx, uintN argc, Value *vp) { - jsval fval, junk; - jsid id; - JSObject *obj; - uintN attrs; - if (argc <= 1 || !js_IsCallable(vp[3])) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GETTER_OR_SETTER, js_setter_str); return JS_FALSE; } - fval = vp[3]; + PropertyOp setter = CastAsPropertyOp(&vp[3].toObject()); - if (!JS_ValueToId(cx, vp[2], &id)) + jsid id; + if (!ValueToId(cx, vp[2], &id)) return JS_FALSE; - obj = JS_THIS_OBJECT(cx, vp); - if (!obj || !js_CheckRedeclaration(cx, obj, id, JSPROP_SETTER, NULL, NULL)) + JSObject *obj = ComputeThisFromVp(cx, vp); + if (!obj || !CheckRedeclaration(cx, obj, id, JSPROP_SETTER, NULL, NULL)) return JS_FALSE; /* * Getters and setters are just like watchpoints from an access * control point of view. */ + Value junk; + uintN attrs; if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs)) return JS_FALSE; - *vp = JSVAL_VOID; - return obj->defineProperty(cx, id, JSVAL_VOID, - JS_PropertyStub, CastAsPropertyOp(JSVAL_TO_OBJECT(fval)), + vp->setUndefined(); + return obj->defineProperty(cx, id, UndefinedValue(), PropertyStub, setter, JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED); } static JSBool -obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp) +obj_lookupGetter(JSContext *cx, uintN argc, Value *vp) { jsid id; - JSObject *obj, *pobj; - JSProperty *prop; - JSScopeProperty *sprop; - - if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id)) + if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id)) return JS_FALSE; - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); + JSObject *pobj; + JSProperty *prop; if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop)) return JS_FALSE; - *vp = JSVAL_VOID; + vp->setUndefined(); if (prop) { if (pobj->isNative()) { - sprop = (JSScopeProperty *) prop; + JSScopeProperty *sprop = (JSScopeProperty *) prop; if (sprop->hasGetterValue()) *vp = sprop->getterValue(); JS_UNLOCK_OBJ(cx, pobj); @@ -1686,22 +1672,20 @@ obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp) } static JSBool -obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp) +obj_lookupSetter(JSContext *cx, uintN argc, Value *vp) { jsid id; - JSObject *obj, *pobj; - JSProperty *prop; - JSScopeProperty *sprop; - - if (!JS_ValueToId(cx, argc != 0 ? vp[2] : JSVAL_VOID, &id)) + if (!ValueToId(cx, argc != 0 ? vp[2] : UndefinedValue(), &id)) return JS_FALSE; - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); + JSObject *pobj; + JSProperty *prop; if (!obj || !obj->lookupProperty(cx, id, &pobj, &prop)) return JS_FALSE; - *vp = JSVAL_VOID; + vp->setUndefined(); if (prop) { if (pobj->isNative()) { - sprop = (JSScopeProperty *) prop; + JSScopeProperty *sprop = (JSScopeProperty *) prop; if (sprop->hasSetterValue()) *vp = sprop->setterValue(); JS_UNLOCK_OBJ(cx, pobj); @@ -1712,18 +1696,15 @@ obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp) #endif /* OLD_GETTER_SETTER_METHODS */ JSBool -obj_getPrototypeOf(JSContext *cx, uintN argc, jsval *vp) +obj_getPrototypeOf(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - uintN attrs; - if (argc == 0) { - js_ReportMissingArg(cx, vp, 0); + js_ReportMissingArg(cx, *vp, 0); return JS_FALSE; } - if (JSVAL_IS_PRIMITIVE(vp[2])) { - char *bytes = js_DecompileValueGenerator(cx, 0 - argc, vp[2], NULL); + if (vp[2].isPrimitive()) { + char *bytes = DecompileValueGenerator(cx, 0 - argc, vp[2], NULL); if (!bytes) return JS_FALSE; JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, @@ -1732,49 +1713,51 @@ obj_getPrototypeOf(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - obj = JSVAL_TO_OBJECT(vp[2]); + JSObject *obj = &vp[2].toObject(); + uintN attrs; return CheckAccess(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.protoAtom), JSACC_PROTO, vp, &attrs); } extern JSBool -js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, jsval getter, jsval setter, - jsval value, jsval *vp) +js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, + const Value &getter, const Value &setter, + const Value &value, Value *vp) { /* We have our own property, so start creating the descriptor. */ JSObject *desc = NewBuiltinClassInstance(cx, &js_ObjectClass); if (!desc) return false; - *vp = OBJECT_TO_JSVAL(desc); /* Root and return. */ + vp->setObject(*desc); /* Root and return. */ const JSAtomState &atomState = cx->runtime->atomState; if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.getAtom), getter, - JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) || + PropertyStub, PropertyStub, JSPROP_ENUMERATE) || !desc->defineProperty(cx, ATOM_TO_JSID(atomState.setAtom), setter, - JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE)) { + PropertyStub, PropertyStub, JSPROP_ENUMERATE)) { return false; } } else { if (!desc->defineProperty(cx, ATOM_TO_JSID(atomState.valueAtom), value, - JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) || + PropertyStub, PropertyStub, JSPROP_ENUMERATE) || !desc->defineProperty(cx, ATOM_TO_JSID(atomState.writableAtom), - BOOLEAN_TO_JSVAL((attrs & JSPROP_READONLY) == 0), - JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE)) { + BooleanValue((attrs & JSPROP_READONLY) == 0), + PropertyStub, PropertyStub, JSPROP_ENUMERATE)) { return false; } } return desc->defineProperty(cx, ATOM_TO_JSID(atomState.enumerableAtom), - BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0), - JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE) && + BooleanValue((attrs & JSPROP_ENUMERATE) != 0), + PropertyStub, PropertyStub, JSPROP_ENUMERATE) && desc->defineProperty(cx, ATOM_TO_JSID(atomState.configurableAtom), - BOOLEAN_TO_JSVAL((attrs & JSPROP_PERMANENT) == 0), - JS_PropertyStub, JS_PropertyStub, JSPROP_ENUMERATE); + BooleanValue((attrs & JSPROP_PERMANENT) == 0), + PropertyStub, PropertyStub, JSPROP_ENUMERATE); } JSBool -js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, Value *vp) { if (obj->isProxy()) { if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, vp)) @@ -1786,11 +1769,11 @@ js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp) if (!js_HasOwnProperty(cx, obj->map->ops->lookupProperty, obj, id, &pobj, &prop)) return false; if (!prop) { - *vp = JSVAL_VOID; + vp->setUndefined(); return true; } - jsval roots[] = { JSVAL_VOID, JSVAL_VOID, JSVAL_VOID }; + Value roots[] = { UndefinedValue(), UndefinedValue(), UndefinedValue() }; AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); unsigned attrs; bool doGet = true; @@ -1821,7 +1804,7 @@ js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp) } static bool -GetFirstArgumentAsObject(JSContext *cx, uintN argc, jsval *vp, const char *method, JSObject **objp) +GetFirstArgumentAsObject(JSContext *cx, uintN argc, Value *vp, const char *method, JSObject **objp) { if (argc == 0) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -1829,9 +1812,9 @@ GetFirstArgumentAsObject(JSContext *cx, uintN argc, jsval *vp, const char *metho return false; } - jsval v = vp[2]; - if (JSVAL_IS_PRIMITIVE(v)) { - char *bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL); + const Value &v = vp[2]; + if (v.isPrimitive()) { + char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL); if (!bytes) return false; JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE, @@ -1840,66 +1823,75 @@ GetFirstArgumentAsObject(JSContext *cx, uintN argc, jsval *vp, const char *metho return false; } - *objp = JSVAL_TO_OBJECT(v); + *objp = &v.toObject(); return true; } static JSBool -obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, jsval *vp) +obj_getOwnPropertyDescriptor(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyDescriptor", &obj)) return JS_FALSE; AutoIdRooter nameidr(cx); - if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) + if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), nameidr.addr())) return JS_FALSE; return js_GetOwnPropertyDescriptor(cx, obj, nameidr.id(), vp); } static JSBool -obj_keys(JSContext *cx, uintN argc, jsval *vp) +obj_keys(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.keys", &obj)) return JS_FALSE; - AutoValueVector props(cx); + AutoIdVector props(cx); if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, props)) return JS_FALSE; + AutoValueVector vals(cx); + vals.resize(props.length()); for (size_t i = 0, len = props.length(); i < len; i++) { - jsid id = jsid(props[i]); - if (JSID_IS_INT(id) && !js_ValueToStringId(cx, INT_JSID_TO_JSVAL(id), &props[i])) - return JS_FALSE; + jsid id = props[i]; + if (JSID_IS_STRING(id)) { + vals[i].setString(JSID_TO_STRING(id)); + } else { + JS_ASSERT(JSID_IS_INT(id)); + JSString *str = js_IntToString(cx, JSID_TO_INT(id)); + if (!str) + return JS_FALSE; + vals[i].setString(str); + } } JS_ASSERT(props.length() <= UINT32_MAX); - JSObject *aobj = js_NewArrayObject(cx, jsuint(props.length()), props.begin(), false); + JSObject *aobj = js_NewArrayObject(cx, jsuint(vals.length()), vals.begin(), false); if (!aobj) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(aobj); + vp->setObject(*aobj); return JS_TRUE; } static JSBool -HasProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp, JSBool* answerp) +HasProperty(JSContext* cx, JSObject* obj, jsid id, Value* vp, JSBool* answerp) { if (!JS_HasPropertyById(cx, obj, id, answerp)) return JS_FALSE; if (!*answerp) { - *vp = JSVAL_VOID; + vp->setUndefined(); return JS_TRUE; } - return JS_GetPropertyById(cx, obj, id, vp); + return JS_GetPropertyById(cx, obj, id, Jsvalify(vp)); } -PropertyDescriptor::PropertyDescriptor() - : pd(JSVAL_VOID), - id(INT_JSVAL_TO_JSID(JSVAL_ZERO)), - value(JSVAL_VOID), - get(JSVAL_VOID), - set(JSVAL_VOID), +PropDesc::PropDesc() + : pd(UndefinedValue()), + id(INT_TO_JSID(0)), + value(UndefinedValue()), + get(UndefinedValue()), + set(UndefinedValue()), attrs(0), hasGet(false), hasSet(false), @@ -1911,16 +1903,17 @@ PropertyDescriptor::PropertyDescriptor() } bool -PropertyDescriptor::initialize(JSContext* cx, jsid id, jsval v) +PropDesc::initialize(JSContext* cx, jsid id, const Value &origval) { + Value v = origval; this->id = id; /* 8.10.5 step 1 */ - if (JSVAL_IS_PRIMITIVE(v)) { + if (v.isPrimitive()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT); return false; } - JSObject* desc = JSVAL_TO_OBJECT(v); + JSObject* desc = &v.toObject(); /* Make a copy of the descriptor. We might need it later. */ pd = v; @@ -1973,7 +1966,7 @@ PropertyDescriptor::initialize(JSContext* cx, jsid id, jsval v) if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.getAtom), &v, &hasProperty)) return false; if (hasProperty) { - if ((JSVAL_IS_PRIMITIVE(v) || !js_IsCallable(v)) && v != JSVAL_VOID) { + if ((v.isPrimitive() || !js_IsCallable(v)) && !v.isUndefined()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD, js_getter_str); return false; @@ -1987,7 +1980,7 @@ PropertyDescriptor::initialize(JSContext* cx, jsid id, jsval v) if (!HasProperty(cx, desc, ATOM_TO_JSID(cx->runtime->atomState.setAtom), &v, &hasProperty)) return false; if (hasProperty) { - if ((JSVAL_IS_PRIMITIVE(v) || !js_IsCallable(v)) && v != JSVAL_VOID) { + if ((v.isPrimitive() || !js_IsCallable(v)) && !v.isUndefined()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GET_SET_FIELD, js_setter_str); return false; @@ -2011,10 +2004,10 @@ Reject(JSContext *cx, uintN errorNumber, bool throwError, jsid id, bool *rval) { if (throwError) { jsid idstr; - if (!js_ValueToStringId(cx, ID_TO_VALUE(id), &idstr)) + if (!js_ValueToStringId(cx, IdToValue(id), &idstr)) return JS_FALSE; JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, errorNumber, - JS_GetStringBytes(JSVAL_TO_STRING(ID_TO_VALUE(idstr)))); + JS_GetStringBytes(JSID_TO_STRING(idstr))); return JS_FALSE; } @@ -2043,7 +2036,7 @@ Reject(JSContext *cx, JSObject *obj, JSProperty *prop, uintN errorNumber, bool t } static JSBool -DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc, +DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwError, bool *rval) { /* 8.12.9 step 1. */ @@ -2065,8 +2058,8 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d if (desc.isGenericDescriptor() || desc.isDataDescriptor()) { JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty); - return js_DefineProperty(cx, obj, desc.id, desc.value, - JS_PropertyStub, JS_PropertyStub, desc.attrs); + return js_DefineProperty(cx, obj, desc.id, &desc.value, + PropertyStub, PropertyStub, desc.attrs); } JS_ASSERT(desc.isAccessorDescriptor()); @@ -2075,17 +2068,18 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d * Getters and setters are just like watchpoints from an access * control point of view. */ - jsval dummy; + Value dummy; uintN dummyAttrs; if (!CheckAccess(cx, obj, desc.id, JSACC_WATCH, &dummy, &dummyAttrs)) return JS_FALSE; - return js_DefineProperty(cx, obj, desc.id, JSVAL_VOID, + Value tmp = UndefinedValue(); + return js_DefineProperty(cx, obj, desc.id, &tmp, desc.getter(), desc.setter(), desc.attrs); } /* 8.12.9 steps 5-6 (note 5 is merely a special case of 6). */ - jsval v = JSVAL_VOID; + Value v = UndefinedValue(); /* * In the special case of shared permanent properties, the "own" property @@ -2104,16 +2098,12 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d break; if (desc.hasGet && - !js_SameValue(desc.getterValue(), - sprop->hasGetterValue() ? sprop->getterValue() : JSVAL_VOID, - cx)) { + !SameValue(desc.getterValue(), sprop->getterOrUndefined(), cx)) { break; } if (desc.hasSet && - !js_SameValue(desc.setterValue(), - sprop->hasSetterValue() ? sprop->setterValue() : JSVAL_VOID, - cx)) { + !SameValue(desc.setterValue(), sprop->setterOrUndefined(), cx)) { break; } } else { @@ -2164,7 +2154,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d if (!sprop->isDataDescriptor()) break; - if (desc.hasValue && !js_SameValue(desc.value, v, cx)) + if (desc.hasValue && !SameValue(desc.value, v, cx)) break; if (desc.hasWritable && desc.writable() != sprop->writable()) break; @@ -2215,7 +2205,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d JS_ASSERT(sprop->isDataDescriptor()); if (!sprop->configurable() && !sprop->writable()) { if ((desc.hasWritable && desc.writable()) || - (desc.hasValue && !js_SameValue(desc.value, v, cx))) { + (desc.hasValue && !SameValue(desc.value, v, cx))) { return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_UNCONFIGURABLE_PROP, throwError, desc.id, rval); } @@ -2225,14 +2215,9 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d JS_ASSERT(desc.isAccessorDescriptor() && sprop->isAccessorDescriptor()); if (!sprop->configurable()) { if ((desc.hasSet && - !js_SameValue(desc.setterValue(), - sprop->hasSetterValue() ? sprop->setterValue() : JSVAL_VOID, - cx)) || + !SameValue(desc.setterValue(), sprop->setterOrUndefined(), cx)) || (desc.hasGet && - !js_SameValue(desc.getterValue(), - sprop->hasGetterValue() ? sprop->getterValue() : JSVAL_VOID, - cx))) - { + !SameValue(desc.getterValue(), sprop->getterOrUndefined(), cx))) { return Reject(cx, obj2, current, JSMSG_CANT_REDEFINE_UNCONFIGURABLE_PROP, throwError, desc.id, rval); } @@ -2241,7 +2226,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d /* 8.12.9 step 12. */ uintN attrs; - JSPropertyOp getter, setter; + PropertyOp getter, setter; if (desc.isGenericDescriptor()) { uintN changed = 0; if (desc.hasConfigurable) @@ -2252,7 +2237,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d attrs = (sprop->attributes() & ~changed) | (desc.attrs & changed); if (sprop->isMethod()) { JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); - getter = setter = JS_PropertyStub; + getter = setter = PropertyStub; } else { getter = sprop->getter(); setter = sprop->setter(); @@ -2269,7 +2254,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d if (desc.hasValue) v = desc.value; attrs = (desc.attrs & ~unchanged) | (sprop->attributes() & unchanged); - getter = setter = JS_PropertyStub; + getter = setter = PropertyStub; } else { JS_ASSERT(desc.isAccessorDescriptor()); @@ -2277,7 +2262,7 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d * Getters and setters are just like watchpoints from an access * control point of view. */ - jsval dummy; + Value dummy; if (!CheckAccess(cx, obj2, desc.id, JSACC_WATCH, &dummy, &attrs)) { obj2->dropProperty(cx, current); return JS_FALSE; @@ -2300,25 +2285,25 @@ DefinePropertyOnObject(JSContext *cx, JSObject *obj, const PropertyDescriptor &d getter = desc.getter(); } else { getter = (sprop->isMethod() || (sprop->hasDefaultGetter() && !sprop->hasGetterValue())) - ? JS_PropertyStub + ? PropertyStub : sprop->getter(); } if (desc.hasSet) { setter = desc.setter(); } else { setter = (sprop->hasDefaultSetter() && !sprop->hasSetterValue()) - ? JS_PropertyStub + ? PropertyStub : sprop->setter(); } } *rval = true; obj2->dropProperty(cx, current); - return js_DefineProperty(cx, obj, desc.id, v, getter, setter, attrs); + return js_DefineProperty(cx, obj, desc.id, &v, getter, setter, attrs); } static JSBool -DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc, +DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwError, bool *rval) { /* @@ -2333,7 +2318,7 @@ DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropertyDescriptor &de jsuint oldLen = obj->getArrayLength(); - if (desc.id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { + if (JSID_IS_ATOM(desc.id, cx->runtime->atomState.lengthAtom)) { /* * Our optimization of storage of the length property of arrays makes * it very difficult to properly implement defining the property. For @@ -2370,7 +2355,7 @@ DefinePropertyOnArray(JSContext *cx, JSObject *obj, const PropertyDescriptor &de } static JSBool -DefineProperty(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc, bool throwError, +DefineProperty(JSContext *cx, JSObject *obj, const PropDesc &desc, bool throwError, bool *rval) { if (obj->isArray()) @@ -2386,10 +2371,11 @@ DefineProperty(JSContext *cx, JSObject *obj, const PropertyDescriptor &desc, boo } JSBool -js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp) +js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, + const Value &descriptor, JSBool *bp) { - AutoDescriptorArray descs(cx); - PropertyDescriptor *desc = descs.append(); + AutoPropDescArrayRooter descs(cx); + PropDesc *desc = descs.append(); if (!desc || !desc->initialize(cx, id, descriptor)) return false; @@ -2402,21 +2388,21 @@ js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JS /* ES5 15.2.3.6: Object.defineProperty(O, P, Attributes) */ static JSBool -obj_defineProperty(JSContext* cx, uintN argc, jsval* vp) +obj_defineProperty(JSContext* cx, uintN argc, Value* vp) { /* 15.2.3.6 steps 1 and 5. */ JSObject *obj; if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperty", &obj)) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); /* 15.2.3.6 step 2. */ AutoIdRooter nameidr(cx); - if (!JS_ValueToId(cx, argc >= 2 ? vp[3] : JSVAL_VOID, nameidr.addr())) + if (!ValueToId(cx, argc >= 2 ? vp[3] : UndefinedValue(), nameidr.addr())) return JS_FALSE; /* 15.2.3.6 step 3. */ - jsval descval = argc >= 3 ? vp[4] : JSVAL_VOID; + const Value &descval = argc >= 3 ? vp[4] : UndefinedValue(); /* 15.2.3.6 step 4 */ JSBool junk; @@ -2430,14 +2416,14 @@ DefineProperties(JSContext *cx, JSObject *obj, JSObject *props) if (!ida) return false; - AutoDescriptorArray descs(cx); + AutoPropDescArrayRooter descs(cx); size_t len = ida.length(); for (size_t i = 0; i < len; i++) { jsid id = ida[i]; - PropertyDescriptor* desc = descs.append(); + PropDesc* desc = descs.append(); AutoValueRooter tvr(cx); if (!desc || - !JS_GetPropertyById(cx, props, id, tvr.addr()) || + !JS_GetPropertyById(cx, props, id, tvr.jsval_addr()) || !desc->initialize(cx, id, tvr.value())) { return false; } @@ -2460,13 +2446,13 @@ js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props) /* ES5 15.2.3.7: Object.defineProperties(O, Properties) */ static JSBool -obj_defineProperties(JSContext* cx, uintN argc, jsval* vp) +obj_defineProperties(JSContext* cx, uintN argc, Value* vp) { /* 15.2.3.6 steps 1 and 5. */ JSObject *obj; if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.defineProperties", &obj)) return false; - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); if (argc < 2) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -2477,14 +2463,14 @@ obj_defineProperties(JSContext* cx, uintN argc, jsval* vp) JSObject* props = js_ValueToNonNullObject(cx, vp[3]); if (!props) return false; - vp[3] = OBJECT_TO_JSVAL(props); + vp[3].setObject(*props); return DefineProperties(cx, obj, props); } /* ES5 15.2.3.5: Object.create(O [, Properties]) */ static JSBool -obj_create(JSContext *cx, uintN argc, jsval *vp) +obj_create(JSContext *cx, uintN argc, Value *vp) { if (argc == 0) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -2492,9 +2478,9 @@ obj_create(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; } - jsval v = vp[2]; - if (!JSVAL_IS_OBJECT(v)) { - char *bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL); + const Value &v = vp[2]; + if (!v.isObjectOrNull()) { + char *bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NULL); if (!bytes) return JS_FALSE; JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE, @@ -2507,30 +2493,30 @@ obj_create(JSContext *cx, uintN argc, jsval *vp) * Use the callee's global as the parent of the new object to avoid dynamic * scoping (i.e., using the caller's global). */ - JSObject *obj = NewObjectWithGivenProto(cx, &js_ObjectClass, JSVAL_TO_OBJECT(v), - JSVAL_TO_OBJECT(*vp)->getGlobal()); + JSObject *obj = NewObjectWithGivenProto(cx, &js_ObjectClass, v.toObjectOrNull(), + vp->toObject().getGlobal()); if (!obj) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(obj); /* Root and prepare for eventual return. */ + vp->setObject(*obj); /* Root and prepare for eventual return. */ /* 15.2.3.5 step 4. */ - if (argc > 1 && vp[3] != JSVAL_VOID) { - if (JSVAL_IS_PRIMITIVE(vp[3])) { + if (argc > 1 && !vp[3].isUndefined()) { + if (vp[3].isPrimitive()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT); return JS_FALSE; } - JSObject *props = JSVAL_TO_OBJECT(vp[3]); + JSObject *props = &vp[3].toObject(); AutoIdArray ida(cx, JS_Enumerate(cx, props)); if (!ida) return JS_FALSE; - AutoDescriptorArray descs(cx); + AutoPropDescArrayRooter descs(cx); size_t len = ida.length(); for (size_t i = 0; i < len; i++) { jsid id = ida[i]; - PropertyDescriptor *desc = descs.append(); - if (!desc || !JS_GetPropertyById(cx, props, id, &vp[1]) || + PropDesc *desc = descs.append(); + if (!desc || !JS_GetPropertyById(cx, props, id, Jsvalify(&vp[1])) || !desc->initialize(cx, id, vp[1])) { return JS_FALSE; } @@ -2548,31 +2534,39 @@ obj_create(JSContext *cx, uintN argc, jsval *vp) } static JSBool -obj_getOwnPropertyNames(JSContext *cx, uintN argc, jsval *vp) +obj_getOwnPropertyNames(JSContext *cx, uintN argc, Value *vp) { JSObject *obj; if (!GetFirstArgumentAsObject(cx, argc, vp, "Object.getOwnPropertyNames", &obj)) return false; - AutoValueVector props(cx); - if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, props)) + AutoIdVector keys(cx); + if (!GetPropertyNames(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, keys)) return false; - for (size_t i = 0, len = props.length(); i < len; i++) { - jsval v = props[i]; - if (JSVAL_IS_INT(v)) { - JSString *str = js_ValueToString(cx, v); + AutoValueVector vals(cx); + if (!vals.resize(keys.length())) + return false; + + for (size_t i = 0, len = keys.length(); i < len; i++) { + jsid id = keys[i]; + if (JSID_IS_INT(id)) { + JSString *str = js_ValueToString(cx, Int32Value(JSID_TO_INT(id))); if (!str) return false; - props[i] = STRING_TO_JSVAL(str); + vals[i].setString(str); + } else if (JSID_IS_ATOM(id)) { + vals[i].setString(JSID_TO_STRING(id)); + } else { + vals[i].setObject(*JSID_TO_OBJECT(id)); } } - JSObject *aobj = js_NewArrayObject(cx, props.length(), props.begin()); + JSObject *aobj = js_NewArrayObject(cx, vals.length(), vals.begin()); if (!aobj) return false; - *vp = OBJECT_TO_JSVAL(aobj); + vp->setObject(*aobj); return true; } @@ -2620,33 +2614,33 @@ static JSFunctionSpec object_static_methods[] = { }; JSBool -js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +js_Object(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { if (argc == 0) { /* Trigger logic below to construct a blank object. */ obj = NULL; } else { /* If argv[0] is null or undefined, obj comes back null. */ - if (!js_ValueToObject(cx, argv[0], &obj)) + if (!js_ValueToObjectOrNull(cx, argv[0], &obj)) return JS_FALSE; } if (!obj) { - JS_ASSERT(!argc || JSVAL_IS_NULL(argv[0]) || JSVAL_IS_VOID(argv[0])); + JS_ASSERT(!argc || argv[0].isNull() || argv[0].isUndefined()); if (JS_IsConstructing(cx)) return JS_TRUE; obj = NewBuiltinClassInstance(cx, &js_ObjectClass); if (!obj) return JS_FALSE; } - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); return JS_TRUE; } #ifdef JS_TRACER JSObject* -js_NewObjectWithClassProto(JSContext *cx, JSClass *clasp, JSObject *proto, - jsval privateSlotValue) +js_NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto, + const Value &privateSlotValue) { JS_ASSERT(!clasp->getObjectOps); JS_ASSERT(proto->map->ops == &js_ObjectOps); @@ -2663,7 +2657,7 @@ JSObject* FASTCALL js_Object_tn(JSContext* cx, JSObject* proto) { JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE)); - return js_NewObjectWithClassProto(cx, &js_ObjectClass, proto, JSVAL_VOID); + return js_NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue()); } JS_DEFINE_TRCINFO_1(js_Object, @@ -2674,7 +2668,7 @@ JSObject* FASTCALL js_NonEmptyObject(JSContext* cx, JSObject* proto) { JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE)); - JSObject *obj = js_NewObjectWithClassProto(cx, &js_ObjectClass, proto, JSVAL_VOID); + JSObject *obj = js_NewObjectWithClassProto(cx, &js_ObjectClass, proto, UndefinedValue()); if (!obj) return NULL; JS_LOCK_OBJ(cx, obj); @@ -2685,7 +2679,7 @@ js_NonEmptyObject(JSContext* cx, JSObject* proto) } /* - * See comments in the JSOP_NEWINIT case of jsops.cpp why we cannot + * See comments in the JSOP_NEWINIT case of jsinterp.cpp why we cannot * assume that cx owns the scope and skip the unlock call. */ JS_UNLOCK_SCOPE(cx, scope); @@ -2696,7 +2690,7 @@ JS_DEFINE_CALLINFO_2(extern, CONSTRUCTOR_RETRY, js_NonEmptyObject, CONTEXT, CALL nanojit::ACC_STORE_ANY) JSObject* FASTCALL -js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor) +js_NewInstance(JSContext *cx, Class *clasp, JSObject *ctor) { JS_ASSERT(JS_ON_TRACE(cx)); JS_ASSERT(ctor->isFunction()); @@ -2715,19 +2709,19 @@ js_NewInstance(JSContext *cx, JSClass *clasp, JSObject *ctor) } JSScopeProperty *sprop = scope->lookup(ATOM_TO_JSID(atom)); - jsval pval = sprop ? ctor->getSlot(sprop->slot) : JSVAL_HOLE; + Value pval = sprop ? ctor->getSlot(sprop->slot) : MagicValue(JS_GENERIC_MAGIC); JSObject *parent = ctor->getParent(); JSObject *proto; - if (!JSVAL_IS_PRIMITIVE(pval)) { + if (pval.isObject()) { /* An object in ctor.prototype, let's use it as the new instance's proto. */ - proto = JSVAL_TO_OBJECT(pval); + proto = &pval.toObject(); } else { /* A hole or a primitive: either way, we need to get Object.prototype. */ if (!js_GetClassPrototype(cx, parent, JSProto_Object, &proto)) return NULL; - if (pval == JSVAL_HOLE) { + if (pval.isMagic(JS_GENERIC_MAGIC)) { /* * No ctor.prototype was set, so we inline-expand and optimize * fun_resolve's prototype creation code. @@ -2881,13 +2875,13 @@ with_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, } static JSBool -with_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +with_GetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return obj->getProto()->getProperty(cx, id, vp); } static JSBool -with_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +with_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return obj->getProto()->setProperty(cx, id, vp); } @@ -2905,14 +2899,14 @@ with_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) } static JSBool -with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) +with_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval) { return obj->getProto()->deleteProperty(cx, id, rval); } static JSBool with_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, - jsval *statep, jsid *idp) + Value *statep, jsid *idp) { return obj->getProto()->enumerate(cx, enum_op, statep, idp); } @@ -2949,16 +2943,16 @@ JS_FRIEND_DATA(JSObjectOps) js_WithObjectOps = { }; static JSObjectOps * -with_getObjectOps(JSContext *cx, JSClass *clasp) +with_getObjectOps(JSContext *cx, Class *clasp) { return &js_WithObjectOps; } -JSClass js_WithClass = { +Class js_WithClass = { "With", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, with_getObjectOps, 0,0,0,0,0,0,0 }; @@ -2972,7 +2966,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth) if (!obj) return NULL; obj->init(&js_WithClass, proto, parent, - reinterpret_cast(js_FloatingFrameIfGenerator(cx, cx->fp))); + PrivateValue(js_FloatingFrameIfGenerator(cx, cx->fp))); OBJ_SET_BLOCK_DEPTH(cx, obj, depth); obj->map = cx->runtime->emptyWithScope->hold(); @@ -2995,7 +2989,7 @@ js_NewBlockObject(JSContext *cx) JSObject *blockObj = js_NewGCObject(cx); if (!blockObj) return NULL; - blockObj->init(&js_BlockClass, NULL, NULL, JSVAL_NULL); + blockObj->init(&js_BlockClass, NULL, NULL, NullValue()); blockObj->map = cx->runtime->emptyBlockScope->hold(); return blockObj; } @@ -3010,9 +3004,10 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSStackFrame *fp) if (!clone) return NULL; + Value privateValue = PrivateValue(js_FloatingFrameIfGenerator(cx, fp)); + /* The caller sets parent on its own. */ - jsval priv = (jsval)js_FloatingFrameIfGenerator(cx, fp); - clone->init(&js_BlockClass, proto, NULL, priv); + clone->init(&js_BlockClass, proto, NULL, privateValue); clone->fslots[JSSLOT_BLOCK_DEPTH] = proto->fslots[JSSLOT_BLOCK_DEPTH]; JS_ASSERT(cx->runtime->emptyBlockScope->freeslot == JSSLOT_BLOCK_DEPTH + 1); @@ -3050,8 +3045,8 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind) /* The block and its locals must be on the current stack for GC safety. */ uintN depth = OBJ_BLOCK_DEPTH(cx, obj); - JS_ASSERT(depth <= (size_t) (cx->regs->sp - StackBase(fp))); - JS_ASSERT(count <= (size_t) (cx->regs->sp - StackBase(fp) - depth)); + JS_ASSERT(depth <= (size_t) (cx->regs->sp - fp->base())); + JS_ASSERT(count <= (size_t) (cx->regs->sp - fp->base() - depth)); /* See comments in CheckDestructuring from jsparse.cpp. */ JS_ASSERT(count >= 1); @@ -3060,7 +3055,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind) obj->fslots[JSSLOT_BLOCK_DEPTH + 1] = fp->slots()[depth]; if (normalUnwind && count > 1) { --count; - memcpy(obj->dslots, fp->slots() + depth + 1, count * sizeof(jsval)); + memcpy(obj->dslots, fp->slots() + depth + 1, count * sizeof(Value)); } /* We must clear the private slot even with errors. */ @@ -3070,7 +3065,7 @@ js_PutBlockObject(JSContext *cx, JSBool normalUnwind) } static JSBool -block_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { /* * Block objects are never exposed to script, and the engine handles them @@ -3079,7 +3074,7 @@ block_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) */ JS_ASSERT(obj->getClass() == &js_BlockClass); JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj)); - uintN index = (uintN) JSVAL_TO_INT(id); + uintN index = (uintN) JSID_TO_INT(id); JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj)); JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); @@ -3101,11 +3096,11 @@ block_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -block_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +block_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { JS_ASSERT(obj->getClass() == &js_BlockClass); JS_ASSERT(OBJ_IS_CLONED_BLOCK(obj)); - uintN index = (uintN) JSVAL_TO_INT(id); + uintN index = (uintN) JSID_TO_INT(id); JS_ASSERT(index < OBJ_BLOCK_COUNT(cx, obj)); JSStackFrame *fp = (JSStackFrame *) obj->getPrivate(); @@ -3133,8 +3128,9 @@ js_DefineBlockVariable(JSContext *cx, JSObject *obj, jsid id, intN index) JS_ASSERT(!OBJ_IS_CLONED_BLOCK(obj)); /* Use JSPROP_ENUMERATE to aid the disassembler. */ - return js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, - block_getProperty, block_setProperty, + return js_DefineNativeProperty(cx, obj, id, UndefinedValue(), + block_getProperty, + block_setProperty, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, JSScopeProperty::HAS_SHORTID, index, NULL); } @@ -3164,13 +3160,10 @@ JSObject::swap(JSObject *other) JS_ASSERT(size == GetObjectSize(other)); /* Trade the guts of the objects. */ - union { - JSFunction fun; - JSObject obj; - } tmp; - memcpy(&tmp, this, size); + char tmp[tl::Max::result]; + memcpy(tmp, this, size); memcpy(this, other, size); - memcpy(other, &tmp, size); + memcpy(other, tmp, size); /* Fixup scope ownerships. */ if (otherOwns) @@ -3255,7 +3248,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) obj->setParent(parent); } - AutoValueRooter tvr(cx, obj); + AutoObjectRooter tvr(cx, obj); if (!JS_XDRUint32(xdr, &tmp)) return false; @@ -3263,7 +3256,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) if (xdr->mode == JSXDR_DECODE) { depth = (uint16)(tmp >> 16); count = (uint16)tmp; - obj->setSlot(JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)); + obj->setSlot(JSSLOT_BLOCK_DEPTH, Value(Int32Value(depth))); } /* @@ -3305,11 +3298,11 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) #endif -JSClass js_BlockClass = { +Class js_BlockClass = { "Block", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; @@ -3323,7 +3316,7 @@ js_InitObjectClass(JSContext *cx, JSObject *obj) /* ECMA (15.1.2.1) says 'eval' is a property of the global object. */ if (!js_DefineFunction(cx, obj, cx->runtime->atomState.evalAtom, - (JSNative)obj_eval, 1, + (Native)obj_eval, 1, JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS)) { return NULL; } @@ -3333,7 +3326,7 @@ js_InitObjectClass(JSContext *cx, JSObject *obj) static bool DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom, - jsval v, uint32 attrs, bool &named) + const Value &v, uint32 attrs, bool &named) { jsid id = ATOM_TO_JSID(atom); @@ -3363,7 +3356,7 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom, } uint32 slot = JSSLOT_START(obj->getClass()) + index; - sprop = scope->addProperty(cx, id, JS_PropertyStub, JS_PropertyStub, + sprop = scope->addProperty(cx, id, PropertyStub, PropertyStub, slot, attrs, 0, 0); JS_UNLOCK_SCOPE(cx, scope); @@ -3376,20 +3369,18 @@ DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom, JS_UNLOCK_SCOPE(cx, scope); } - named = obj->defineProperty(cx, id, v, JS_PropertyStub, JS_PropertyStub, attrs); + named = obj->defineProperty(cx, id, v, PropertyStub, PropertyStub, attrs); return named; } JSObject * js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, - JSClass *clasp, JSNative constructor, uintN nargs, + Class *clasp, Native constructor, uintN nargs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs) { JSAtom *atom; JSProtoKey key; - JSObject *proto, *ctor; - jsval cval, rval; JSFunction *fun; bool named = false; @@ -3439,13 +3430,14 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, * (3) is not enough without addressing the bootstrapping dependency on (1) * and (2). */ - proto = NewObject(cx, clasp, parent_proto, obj); + JSObject *proto = NewObject(cx, clasp, parent_proto, obj); if (!proto) return NULL; /* After this point, control must exit via label bad or out. */ - AutoValueRooter tvr(cx, proto); + AutoObjectRooter tvr(cx, proto); + JSObject *ctor; if (!constructor) { /* * Lacking a constructor, name the prototype (e.g., Math) unless this @@ -3460,7 +3452,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, uint32 attrs = (clasp->flags & JSCLASS_IS_ANONYMOUS) ? JSPROP_READONLY | JSPROP_PERMANENT : 0; - if (!DefineStandardSlot(cx, obj, key, atom, tvr.value(), attrs, named)) + if (!DefineStandardSlot(cx, obj, key, atom, ObjectValue(*proto), attrs, named)) goto bad; } @@ -3470,7 +3462,7 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, if (!fun) goto bad; - AutoValueRooter tvr2(cx, OBJECT_TO_JSVAL(fun)); + AutoValueRooter tvr2(cx, ObjectValue(*fun)); if (!DefineStandardSlot(cx, obj, key, atom, tvr2.value(), 0, named)) goto bad; @@ -3489,11 +3481,11 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, */ ctor = FUN_OBJECT(fun); if (clasp->flags & JSCLASS_CONSTRUCT_PROTOTYPE) { - cval = OBJECT_TO_JSVAL(ctor); - if (!js_InternalConstruct(cx, proto, cval, 0, NULL, &rval)) + Value rval; + if (!InternalConstruct(cx, proto, ObjectOrNullValue(ctor), 0, NULL, &rval)) goto bad; - if (!JSVAL_IS_PRIMITIVE(rval) && JSVAL_TO_OBJECT(rval) != proto) - proto = JSVAL_TO_OBJECT(rval); + if (rval.isObject() && &rval.toObject() != proto) + proto = &rval.toObject(); } /* Connect constructor and prototype by named properties. */ @@ -3530,14 +3522,14 @@ js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, if (key != JSProto_Null && !js_SetClassObject(cx, obj, key, ctor, proto)) goto bad; -out: return proto; bad: - if (named) - (void) obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval); - proto = NULL; - goto out; + if (named) { + Value rval; + obj->deleteProperty(cx, ATOM_TO_JSID(atom), &rval); + } + return NULL; } bool @@ -3547,16 +3539,13 @@ JSObject::allocSlots(JSContext *cx, size_t nslots) JS_ASSERT(nslots > JS_INITIAL_NSLOTS); size_t nwords = slotsToDynamicWords(nslots); - dslots = (jsval*) cx->malloc(nwords * sizeof(jsval)); + dslots = (Value*) cx->malloc(nwords * sizeof(Value)); if (!dslots) return false; dslots++; - dslots[-1] = nslots; - /* clear the newly allocated cells. */ - for (jsuint i = JS_INITIAL_NSLOTS; i < nslots; i++) - dslots[i - JS_INITIAL_NSLOTS] = JSVAL_VOID; - + dslots[-1].setPrivateUint32(nslots); + SetValueRangeToUndefined(dslots, nslots - JS_INITIAL_NSLOTS); return true; } @@ -3602,20 +3591,21 @@ JSObject::growSlots(JSContext *cx, size_t nslots) if (!dslots) return allocSlots(cx, nslots); - size_t oldnslots = size_t(dslots[-1]); + size_t oldnslots = dslots[-1].toPrivateUint32(); - jsval *tmpdslots = (jsval*) cx->realloc(dslots - 1, nwords * sizeof(jsval)); + Value *tmpdslots = (Value*) cx->realloc(dslots - 1, nwords * sizeof(Value)); if (!tmpdslots) return false; /* Leave dslots at its old size. */ dslots = tmpdslots; dslots++; - dslots[-1] = nslots; + dslots[-1].setPrivateUint32(nslots); /* Initialize the additional slots we added. */ JS_ASSERT(nslots > oldnslots); - for (size_t i = oldnslots; i < nslots; i++) - dslots[i - JS_INITIAL_NSLOTS] = JSVAL_VOID; + Value *beg = dslots + (oldnslots - JS_INITIAL_NSLOTS); + Value *end = dslots + (nslots - JS_INITIAL_NSLOTS); + SetValueRangeToUndefined(beg, end); return true; } @@ -3627,21 +3617,21 @@ JSObject::shrinkSlots(JSContext *cx, size_t nslots) if (!dslots) return; - JS_ASSERT(size_t(dslots[-1]) > JS_INITIAL_NSLOTS); - JS_ASSERT(nslots <= size_t(dslots[-1])); + JS_ASSERT(dslots[-1].toPrivateUint32() > JS_INITIAL_NSLOTS); + JS_ASSERT(nslots <= dslots[-1].toPrivateUint32()); if (nslots <= JS_INITIAL_NSLOTS) { freeSlotsArray(cx); dslots = NULL; } else { size_t nwords = slotsToDynamicWords(nslots); - jsval *tmpdslots = (jsval*) cx->realloc(dslots - 1, nwords * sizeof(jsval)); + Value *tmpdslots = (Value*) cx->realloc(dslots - 1, nwords * sizeof(Value)); if (!tmpdslots) return; /* Leave dslots at its old size. */ dslots = tmpdslots; dslots++; - dslots[-1] = nslots; + dslots[-1].setPrivateUint32(nslots); } } @@ -3666,8 +3656,6 @@ js_EnsureReservedSlots(JSContext *cx, JSObject *obj, size_t nreserved) return true; } -JS_BEGIN_EXTERN_C - static JSObject * js_InitNullClass(JSContext *cx, JSObject *obj) { @@ -3685,8 +3673,6 @@ static JSObjectOp lazy_prototype_init[JSProto_LIMIT] = { #undef JS_PROTO }; -JS_END_EXTERN_C - namespace js { bool @@ -3737,7 +3723,7 @@ js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSResolvingEntry *rentry; uint32 generation; JSObjectOp init; - jsval v; + Value v; while ((tmp = obj->getParent()) != NULL) obj = tmp; @@ -3747,8 +3733,8 @@ js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, } v = obj->getReservedSlot(key); - if (!JSVAL_IS_PRIMITIVE(v)) { - *objp = JSVAL_TO_OBJECT(v); + if (v.isObject()) { + *objp = &v.toObject(); return JS_TRUE; } @@ -3771,8 +3757,8 @@ js_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, ok = JS_FALSE; } else { v = obj->getReservedSlot(key); - if (!JSVAL_IS_PRIMITIVE(v)) - cobj = JSVAL_TO_OBJECT(v); + if (v.isObject()) + cobj = &v.toObject(); } } @@ -3788,19 +3774,18 @@ js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject *cobj, if (!(obj->getClass()->flags & JSCLASS_IS_GLOBAL)) return JS_TRUE; - return js_SetReservedSlot(cx, obj, key, OBJECT_TO_JSVAL(cobj)) && - js_SetReservedSlot(cx, obj, JSProto_LIMIT + key, OBJECT_TO_JSVAL(proto)); + return js_SetReservedSlot(cx, obj, key, ObjectOrNullValue(cobj)) && + js_SetReservedSlot(cx, obj, JSProto_LIMIT + key, ObjectOrNullValue(proto)); } JSBool js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey, - jsval *vp, JSClass *clasp) + Value *vp, Class *clasp) { JSStackFrame *fp; JSObject *obj, *cobj, *pobj; jsid id; JSProperty *prop; - jsval v; JSScopeProperty *sprop; /* @@ -3821,7 +3806,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey, } else { obj = cx->globalObject; if (!obj) { - *vp = JSVAL_VOID; + vp->setUndefined(); return JS_TRUE; } } @@ -3836,7 +3821,7 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey, if (!js_GetClassObject(cx, obj, protoKey, &cobj)) return JS_FALSE; if (cobj) { - *vp = OBJECT_TO_JSVAL(cobj); + vp->setObject(*cobj); return JS_TRUE; } id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[protoKey]); @@ -3852,13 +3837,13 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey, &pobj, &prop) < 0) { return JS_FALSE; } - v = JSVAL_VOID; + Value v = UndefinedValue(); if (prop && pobj->isNative()) { sprop = (JSScopeProperty *) prop; if (SPROP_HAS_VALID_SLOT(sprop, pobj->scope())) { v = pobj->lockedGetSlot(sprop->slot); - if (JSVAL_IS_PRIMITIVE(v)) - v = JSVAL_VOID; + if (v.isPrimitive()) + v.setUndefined(); } JS_UNLOCK_OBJ(cx, pobj); } @@ -3867,50 +3852,50 @@ js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey protoKey, } JSObject * -js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, - JSObject *parent, uintN argc, jsval *argv) +js_ConstructObject(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent, + uintN argc, Value *argv) { - jsval cval, rval; - JSObject *obj, *ctor; - AutoArrayRooter argtvr(cx, argc, argv); JSProtoKey protoKey = GetClassProtoKey(clasp); - if (!js_FindClassObject(cx, parent, protoKey, &cval, clasp)) + + /* Protect constructor in case a crazy getter for .prototype uproots it. */ + AutoValueRooter tvr(cx); + if (!js_FindClassObject(cx, parent, protoKey, tvr.addr(), clasp)) return NULL; - if (JSVAL_IS_PRIMITIVE(cval)) { - js_ReportIsNotFunction(cx, &cval, JSV2F_CONSTRUCT | JSV2F_SEARCH_STACK); + const Value &cval = tvr.value(); + if (tvr.value().isPrimitive()) { + js_ReportIsNotFunction(cx, tvr.addr(), JSV2F_CONSTRUCT | JSV2F_SEARCH_STACK); return NULL; } - /* Protect cval in case a crazy getter for .prototype uproots it. */ - AutoValueRooter tvr(cx, cval); - /* * If proto is NULL, set it to Constructor.prototype, just like JSOP_NEW * does, likewise for the new object's parent. */ - ctor = JSVAL_TO_OBJECT(cval); + JSObject *ctor = &cval.toObject(); if (!parent) parent = ctor->getParent(); if (!proto) { + Value rval; if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &rval)) { return NULL; } - if (JSVAL_IS_OBJECT(rval)) - proto = JSVAL_TO_OBJECT(rval); + if (rval.isObjectOrNull()) + proto = rval.toObjectOrNull(); } - obj = NewObject(cx, clasp, proto, parent); + JSObject *obj = NewObject(cx, clasp, proto, parent); if (!obj) return NULL; - if (!js_InternalConstruct(cx, obj, cval, argc, argv, &rval)) + Value rval; + if (!InternalConstruct(cx, obj, cval, argc, argv, &rval)) return NULL; - if (JSVAL_IS_PRIMITIVE(rval)) + if (rval.isPrimitive()) return obj; /* @@ -3920,7 +3905,7 @@ js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, * private data set at this point, then the constructor was replaced and * we should throw a type error. */ - obj = JSVAL_TO_OBJECT(rval); + obj = &rval.toObject(); if (obj->getClass() != clasp || (!(~clasp->flags & (JSCLASS_HAS_PRIVATE | JSCLASS_CONSTRUCT_PROTOTYPE)) && @@ -3948,7 +3933,7 @@ js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp) } /* js_ReallocSlots or js_FreeSlot should set the free slots to void. */ - JS_ASSERT(JSVAL_IS_VOID(obj->getSlot(scope->freeslot))); + JS_ASSERT(obj->getSlot(scope->freeslot).isUndefined()); *slotp = scope->freeslot++; return JS_TRUE; } @@ -3958,14 +3943,14 @@ js_FreeSlot(JSContext *cx, JSObject *obj, uint32 slot) { JSScope *scope = obj->scope(); JS_ASSERT(scope->object == obj); - obj->lockedSetSlot(slot, JSVAL_VOID); + obj->lockedSetSlot(slot, UndefinedValue()); if (scope->freeslot == slot + 1) scope->freeslot = slot; } -/* JSVAL_INT_MAX as a string */ -#define JSVAL_INT_MAX_STRING "1073741823" +/* JSBOXEDWORD_INT_MAX as a string */ +#define JSBOXEDWORD_INT_MAX_STRING "1073741823" /* * Convert string indexes that convert to int jsvals as ints to save memory. @@ -3992,7 +3977,7 @@ js_CheckForStringIndex(jsid id) return id; size_t n = str->flatLength() - negative; - if (n > sizeof(JSVAL_INT_MAX_STRING) - 1) + if (n > sizeof(JSBOXEDWORD_INT_MAX_STRING) - 1) return id; const jschar *cp = s; @@ -4013,13 +3998,13 @@ js_CheckForStringIndex(jsid id) /* * Non-integer indexes can't be represented as integers. Also, distinguish - * index "-0" from "0", because JSVAL_INT cannot. + * index "-0" from "0", because JSBOXEDWORD_INT cannot. */ if (cp != end || (negative && index == 0)) return id; - if (oldIndex < JSVAL_INT_MAX / 10 || - (oldIndex == JSVAL_INT_MAX / 10 && c <= (JSVAL_INT_MAX % 10))) { + if (oldIndex < JSID_INT_MAX / 10 || + (oldIndex == JSID_INT_MAX / 10 && c <= (JSID_INT_MAX % 10))) { if (negative) index = 0 - index; id = INT_TO_JSID((jsint)index); @@ -4085,7 +4070,7 @@ js_PurgeScopeChainHelper(JSContext *cx, JSObject *obj, jsid id) JSScopeProperty * js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, - JSPropertyOp getter, JSPropertyOp setter, uint32 slot, + PropertyOp getter, PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid) { JSScope *scope; @@ -4116,7 +4101,7 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, JSScopeProperty * js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, uintN attrs, uintN mask, - JSPropertyOp getter, JSPropertyOp setter) + PropertyOp getter, PropertyOp setter) { JSScope *scope; @@ -4132,10 +4117,10 @@ js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, } JSBool -js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs) +js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, + PropertyOp getter, PropertyOp setter, uintN attrs) { - return js_DefineNativeProperty(cx, obj, id, value, getter, setter, attrs, + return js_DefineNativeProperty(cx, obj, id, *value, getter, setter, attrs, 0, 0, NULL); } @@ -4146,11 +4131,11 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, * both while saving cycles for classes that stub their addProperty hook. */ static inline bool -AddPropertyHelper(JSContext *cx, JSClass *clasp, JSObject *obj, JSScope *scope, - JSScopeProperty *sprop, jsval *vp) +AddPropertyHelper(JSContext *cx, Class *clasp, JSObject *obj, JSScope *scope, + JSScopeProperty *sprop, Value *vp) { - if (clasp->addProperty != JS_PropertyStub) { - jsval nominal = *vp; + if (clasp->addProperty != PropertyStub) { + Value nominal = *vp; if (!callJSPropertyOp(cx, clasp->addProperty, obj, SPROP_USERID(sprop), vp)) return false; @@ -4163,15 +4148,16 @@ AddPropertyHelper(JSContext *cx, JSClass *clasp, JSObject *obj, JSScope *scope, } JSBool -js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs, +js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value, + PropertyOp getter, PropertyOp setter, uintN attrs, uintN flags, intN shortid, JSProperty **propp, uintN defineHow /* = 0 */) { - JSClass *clasp; + Class *clasp; JSScope *scope; JSScopeProperty *sprop; JSBool added; + Value valueCopy; JS_ASSERT((defineHow & ~(JSDNP_CACHE_RESULT | JSDNP_DONT_PURGE | JSDNP_SET_METHOD)) == 0); LeaveTraceIfGlobalObject(cx, obj); @@ -4258,11 +4244,11 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, /* Add a new property, or replace an existing one of the same id. */ if (defineHow & JSDNP_SET_METHOD) { JS_ASSERT(clasp == &js_ObjectClass); - JS_ASSERT(VALUE_IS_FUNCTION(cx, value)); + JS_ASSERT(IsFunctionObject(value)); JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); JS_ASSERT(!getter && !setter); - JSObject *funobj = JSVAL_TO_OBJECT(value); + JSObject *funobj = &value.toObject(); if (FUN_OBJECT(GET_FUNCTION_PRIVATE(cx, funobj)) == funobj) { flags |= JSScopeProperty::METHOD; getter = CastAsPropertyOp(funobj); @@ -4291,14 +4277,17 @@ js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, obj->lockedSetSlot(sprop->slot, value); /* XXXbe called with lock held */ - if (!AddPropertyHelper(cx, clasp, obj, scope, sprop, &value)) { + valueCopy = value; + if (!AddPropertyHelper(cx, clasp, obj, scope, sprop, &valueCopy)) { scope->removeProperty(cx, id); goto error; } if (defineHow & JSDNP_CACHE_RESULT) { +#ifdef JS_TRACER JS_ASSERT_NOT_ON_TRACE(cx); PropertyCacheEntry *entry = +#endif JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, sprop, added); TRACE_2(SetPropHit, entry, sprop); } @@ -4350,7 +4339,7 @@ static JSBool CallResolveOp(JSContext *cx, JSObject *start, JSObject *obj, jsid id, uintN flags, JSObject **objp, JSProperty **propp, bool *recursedp) { - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); JSResolveOp resolve = clasp->resolve; JSScope *scope = obj->scope(); @@ -4391,7 +4380,7 @@ CallResolveOp(JSContext *cx, JSObject *start, JSObject *obj, jsid id, uintN flag { /* Protect id and all atoms from a GC nested in resolve. */ AutoKeepAtoms keep(cx->runtime); - ok = newresolve(cx, obj, ID_TO_VALUE(id), flags, &obj2); + ok = newresolve(cx, obj, id, flags, &obj2); } if (!ok) goto cleanup; @@ -4440,7 +4429,7 @@ CallResolveOp(JSContext *cx, JSObject *start, JSObject *obj, jsid id, uintN flag * its scope after resolve returns. */ JS_UNLOCK_OBJ(cx, obj); - ok = resolve(cx, obj, ID_TO_VALUE(id)); + ok = resolve(cx, obj, id); if (!ok) goto cleanup; JS_LOCK_OBJ(cx, obj); @@ -4545,7 +4534,7 @@ js_FindPropertyHelper(JSContext *cx, jsid id, JSBool cacheResult, if (prop) { #ifdef DEBUG if (parent) { - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); JS_ASSERT(pobj->isNative()); JS_ASSERT(pobj->getClass() == clasp); if (clasp == &js_BlockClass) { @@ -4699,7 +4688,7 @@ js_FindIdentifierBase(JSContext *cx, JSObject *scopeChain, jsid id) JSBool js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, - JSScopeProperty *sprop, uintN getHow, jsval *vp) + JSScopeProperty *sprop, uintN getHow, Value *vp) { LeaveTraceIfGlobalObject(cx, pobj); @@ -4712,14 +4701,15 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, scope = pobj->scope(); slot = sprop->slot; - *vp = (slot != SPROP_INVALID_SLOT) - ? pobj->lockedGetSlot(slot) - : JSVAL_VOID; + if (slot != SPROP_INVALID_SLOT) + *vp = pobj->lockedGetSlot(slot); + else + vp->setUndefined(); if (sprop->hasDefaultGetter()) return true; if (JS_UNLIKELY(sprop->isMethod()) && (getHow & JSGET_NO_METHOD_BARRIER)) { - JS_ASSERT(sprop->methodValue() == *vp); + JS_ASSERT(&sprop->methodObject() == &vp->toObject()); return true; } @@ -4727,7 +4717,7 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, JS_UNLOCK_SCOPE(cx, scope); { AutoScopePropertyRooter tvr(cx, sprop); - AutoValueRooter tvr2(cx, pobj); + AutoObjectRooter tvr2(cx, pobj); if (!sprop->get(cx, obj, pobj, vp)) return false; } @@ -4736,12 +4726,11 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, if (SLOT_IN_SCOPE(slot, scope) && (JS_LIKELY(cx->runtime->propertyRemovals == sample) || scope->hasProperty(sprop))) { - jsval v = *vp; - if (!scope->methodWriteBarrier(cx, sprop, v)) { + if (!scope->methodWriteBarrier(cx, sprop, *vp)) { JS_UNLOCK_SCOPE(cx, scope); return false; } - pobj->lockedSetSlot(slot, v); + pobj->lockedSetSlot(slot, *vp); } return true; @@ -4749,7 +4738,7 @@ js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, JSBool js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, - jsval *vp) + Value *vp) { LeaveTraceIfGlobalObject(cx, obj); @@ -4797,12 +4786,11 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, if (SLOT_IN_SCOPE(slot, scope) && (JS_LIKELY(cx->runtime->propertyRemovals == sample) || scope->hasProperty(sprop))) { - jsval v = *vp; - if (!added && !scope->methodWriteBarrier(cx, sprop, v)) { + if (!added && !scope->methodWriteBarrier(cx, sprop, *vp)) { JS_UNLOCK_SCOPE(cx, scope); return false; } - obj->lockedSetSlot(slot, v); + obj->lockedSetSlot(slot, *vp); } return true; @@ -4810,7 +4798,7 @@ js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, JSBool js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, - jsval *vp) + Value *vp) { JSObject *aobj, *obj2; int protoIndex; @@ -4828,9 +4816,9 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, if (protoIndex < 0) return JS_FALSE; if (!prop) { - *vp = JSVAL_VOID; + vp->setUndefined(); - if (!callJSPropertyOp(cx, obj->getClass()->getProperty, obj, ID_TO_VALUE(id), vp)) + if (!callJSPropertyOp(cx, obj->getClass()->getProperty, obj, id, vp)) return JS_FALSE; PCMETER(getHow & JSGET_CACHE_RESULT && JS_PROPERTY_CACHE(cx).nofills++); @@ -4840,7 +4828,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, * object foo with no property named 'bar'. */ jsbytecode *pc; - if (JSVAL_IS_VOID(*vp) && ((pc = js_GetCurrentBytecodePC(cx)) != NULL)) { + if (vp->isUndefined() && ((pc = js_GetCurrentBytecodePC(cx)) != NULL)) { JSOp op; uintN flags; @@ -4862,7 +4850,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, * XXX do not warn about missing __iterator__ as the function * may be called from JS_GetMethodById. See bug 355145. */ - if (id == ATOM_TO_JSID(cx->runtime->atomState.iteratorAtom)) + if (JSID_IS_ATOM(id, cx->runtime->atomState.iteratorAtom)) return JS_TRUE; /* Do not warn about tests like (obj[prop] == undefined). */ @@ -4880,7 +4868,7 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, /* Ok, bad undefined property reference: whine about it. */ if (!js_ReportValueErrorFlags(cx, flags, JSMSG_UNDEFINED_PROP, - JSDVG_IGNORE_STACK, ID_TO_VALUE(id), + JSDVG_IGNORE_STACK, IdToValue(id), NULL, NULL, NULL)) { return JS_FALSE; } @@ -4906,13 +4894,13 @@ js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, } JSBool -js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +js_GetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return js_GetPropertyHelper(cx, obj, id, JSGET_METHOD_BARRIER, vp); } JSBool -js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, jsval *vp) +js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, Value *vp) { JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); @@ -4929,7 +4917,7 @@ js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, jsval *vp) } JS_FRIEND_API(bool) -js_CheckUndeclaredVarAssignment(JSContext *cx, jsval propname) +js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname) { JSStackFrame *const fp = js_GetTopStackFrame(cx); if (!fp) @@ -4941,7 +4929,7 @@ js_CheckUndeclaredVarAssignment(JSContext *cx, jsval propname) return true; } - const char *bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(propname)); + const char *bytes = js_GetStringBytes(cx, propname); return bytes && JS_ReportErrorFlagsAndNumber(cx, (JSREPORT_WARNING | JSREPORT_STRICT @@ -4956,7 +4944,7 @@ JSBool ReportReadOnly(JSContext* cx, jsid id, uintN flags) { return js_ReportValueErrorFlags(cx, flags, JSMSG_READ_ONLY, - JSDVG_IGNORE_STACK, ID_TO_VALUE(id), NULL, + JSDVG_IGNORE_STACK, IdToValue(id), NULL, NULL, NULL); } @@ -4969,7 +4957,7 @@ ReportReadOnly(JSContext* cx, jsid id, uintN flags) */ JSBool js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, - jsval *vp) + Value *vp) { int protoIndex; JSObject *pobj; @@ -4978,8 +4966,8 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, JSScope *scope; uintN attrs, flags; intN shortid; - JSClass *clasp; - JSPropertyOp getter, setter; + Class *clasp; + PropertyOp getter, setter; bool added; JS_ASSERT((defineHow & @@ -5010,7 +4998,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, if (!obj->getParent() && (defineHow & JSDNP_UNQUALIFIED) && - !js_CheckUndeclaredVarAssignment(cx, ID_TO_VALUE(id))) { + !js_CheckUndeclaredVarAssignment(cx, JSID_TO_STRING(id))) { return JS_FALSE; } } @@ -5089,8 +5077,10 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, /* Don't clone a prototype property that doesn't have a slot. */ if (!sprop->hasSlot()) { if (defineHow & JSDNP_CACHE_RESULT) { +#ifdef JS_TRACER JS_ASSERT_NOT_ON_TRACE(cx); PropertyCacheEntry *entry = +#endif JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, protoIndex, pobj, sprop); TRACE_2(SetPropHit, entry, sprop); } @@ -5152,10 +5142,10 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, */ if ((defineHow & JSDNP_SET_METHOD) && obj->getClass() == &js_ObjectClass) { - JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp)); + JS_ASSERT(IsFunctionObject(*vp)); JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); - JSObject *funobj = JSVAL_TO_OBJECT(*vp); + JSObject *funobj = &vp->toObject(); if (FUN_OBJECT(GET_FUNCTION_PRIVATE(cx, funobj)) == funobj) { flags |= JSScopeProperty::METHOD; getter = CastAsPropertyOp(funobj); @@ -5175,7 +5165,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, * in js_DefineNativeProperty. */ if (SPROP_HAS_VALID_SLOT(sprop, scope)) - obj->lockedSetSlot(sprop->slot, JSVAL_VOID); + obj->lockedSetSlot(sprop->slot, UndefinedValue()); /* XXXbe called with obj locked */ if (!AddPropertyHelper(cx, clasp, obj, scope, sprop, vp)) { @@ -5187,8 +5177,11 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, } if (defineHow & JSDNP_CACHE_RESULT) { +#ifdef JS_TRACER JS_ASSERT_NOT_ON_TRACE(cx); - PropertyCacheEntry *entry = JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, sprop, added); + PropertyCacheEntry *entry = +#endif + JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, 0, obj, sprop, added); TRACE_2(SetPropHit, entry, sprop); } @@ -5200,7 +5193,7 @@ js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, } JSBool -js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +js_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return js_SetPropertyHelper(cx, obj, id, 0, vp); } @@ -5249,7 +5242,7 @@ js_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) } JSBool -js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) +js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval) { JSObject *proto; JSProperty *prop; @@ -5257,7 +5250,7 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) JSScope *scope; JSBool ok; - *rval = JSVAL_TRUE; + rval->setBoolean(true); /* Convert string indices to integers if appropriate. */ id = js_CheckForStringIndex(id); @@ -5275,10 +5268,10 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) if (proto->isNative()) { sprop = (JSScopeProperty *)prop; if (sprop->isSharedPermanent()) - *rval = JSVAL_FALSE; + rval->setBoolean(false); JS_UNLOCK_OBJ(cx, proto); } - if (*rval == JSVAL_FALSE) + if (rval->isBoolean() && rval->toBoolean() == false) return JS_TRUE; } @@ -5287,13 +5280,13 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) * a prototype, call the class's delProperty hook, passing rval as the * result parameter. */ - return callJSPropertyOp(cx, obj->getClass()->delProperty, obj, ID_TO_VALUE(id), rval); + return callJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval); } sprop = (JSScopeProperty *)prop; if (!sprop->configurable()) { JS_UNLOCK_OBJ(cx, obj); - *rval = JSVAL_FALSE; + rval->setBoolean(false); return JS_TRUE; } @@ -5316,16 +5309,12 @@ js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) namespace js { JSBool -DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) +DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp) { - jsval v, save; - JSString *str; - JS_ASSERT(hint != JSTYPE_OBJECT && hint != JSTYPE_FUNCTION); - v = save = OBJECT_TO_JSVAL(obj); - switch (hint) { - case JSTYPE_STRING: + Value v = ObjectValue(*obj); + if (hint == JSTYPE_STRING) { /* * Optimize for String objects with standard toString methods. Support * new String(...) instances whether mutated to have their own scope or @@ -5351,10 +5340,10 @@ DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) } if (sprop && sprop->hasDefaultGetter() && SPROP_HAS_VALID_SLOT(sprop, scope)) { - jsval fval = pobj->lockedGetSlot(sprop->slot); + const Value &fval = pobj->lockedGetSlot(sprop->slot); - if (VALUE_IS_FUNCTION(cx, fval)) { - JSObject *funobj = JSVAL_TO_OBJECT(fval); + JSObject *funobj; + if (IsFunctionObject(fval, &funobj)) { JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); if (FUN_FAST_NATIVE(fun) == js_str_toString) { @@ -5371,29 +5360,27 @@ DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) * Propagate the exception if js_TryMethod finds an appropriate * method, and calling that method returned failure. */ - if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, - &v)) { + if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, + 0, NULL, &v)) { return JS_FALSE; } - if (!JSVAL_IS_PRIMITIVE(v)) { + if (!v.isPrimitive()) { if (!obj->getClass()->convert(cx, obj, hint, &v)) return JS_FALSE; } - break; - - default: + } else { if (!obj->getClass()->convert(cx, obj, hint, &v)) return JS_FALSE; - if (!JSVAL_IS_PRIMITIVE(v)) { - JS_ASSERT(hint != JS_TypeOfValue(cx, v)); + if (v.isObject()) { + JS_ASSERT(hint != TypeOfValue(cx, v)); if (!js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, &v)) return JS_FALSE; } - break; } - if (!JSVAL_IS_PRIMITIVE(v)) { + if (v.isObject()) { /* Avoid recursive death when decompiling in js_ReportValueError. */ + JSString *str; if (hint == JSTYPE_STRING) { str = JS_InternString(cx, obj->getClass()->name); if (!str) @@ -5401,9 +5388,9 @@ DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) } else { str = NULL; } - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, - JSDVG_SEARCH_STACK, save, str, + JSDVG_SEARCH_STACK, *vp, str, (hint == JSTYPE_VOID) ? "primitive type" : JS_TYPE_STR(hint)); @@ -5416,14 +5403,14 @@ DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp) } /* namespace js */ JSBool -js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp) +js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, Value *statep, jsid *idp) { /* If the class has a custom JSCLASS_NEW_ENUMERATE hook, call it. */ - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); JSEnumerateOp enumerate = clasp->enumerate; if (clasp->flags & JSCLASS_NEW_ENUMERATE) { JS_ASSERT(enumerate != JS_EnumerateStub); - return ((JSNewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp); + return ((NewEnumerateOp) enumerate)(cx, obj, enum_op, statep, idp); } if (!enumerate(cx, obj)) @@ -5431,7 +5418,7 @@ js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, j /* Tell InitNativeIterator to treat us like a native object. */ JS_ASSERT(enum_op == JSENUMERATE_INIT || enum_op == JSENUMERATE_INIT_ALL); - *statep = JSVAL_NATIVE_ENUMERATE_COOKIE; + statep->setMagic(JS_NATIVE_ENUMERATE); return true; } @@ -5439,15 +5426,15 @@ namespace js { JSBool CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, - jsval *vp, uintN *attrsp) + Value *vp, uintN *attrsp) { JSBool writing; JSObject *pobj; JSProperty *prop; - JSClass *clasp; + Class *clasp; JSScopeProperty *sprop; JSSecurityCallbacks *callbacks; - JSCheckAccessOp check; + CheckAccessOp check; while (JS_UNLIKELY(obj->getClass() == &js_WithClass)) obj = obj->getProto(); @@ -5457,14 +5444,14 @@ CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, case JSACC_PROTO: pobj = obj; if (!writing) - *vp = OBJECT_TO_JSVAL(obj->getProto()); + vp->setObjectOrNull(obj->getProto()); *attrsp = JSPROP_PERMANENT; break; case JSACC_PARENT: JS_ASSERT(!writing); pobj = obj; - *vp = OBJECT_TO_JSVAL(obj->getParent()); + vp->setObject(*obj->getParent()); *attrsp = JSPROP_READONLY | JSPROP_PERMANENT; break; @@ -5473,7 +5460,7 @@ CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, return JS_FALSE; if (!prop) { if (!writing) - *vp = JSVAL_VOID; + vp->setUndefined(); *attrsp = 0; pobj = obj; break; @@ -5481,7 +5468,7 @@ CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, if (!pobj->isNative()) { if (!writing) { - *vp = JSVAL_VOID; + vp->setUndefined(); *attrsp = 0; } break; @@ -5490,9 +5477,10 @@ CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, sprop = (JSScopeProperty *)prop; *attrsp = sprop->attributes(); if (!writing) { - *vp = (SPROP_HAS_VALID_SLOT(sprop, pobj->scope())) - ? pobj->lockedGetSlot(sprop->slot) - : JSVAL_VOID; + if (SPROP_HAS_VALID_SLOT(sprop, pobj->scope())) + *vp = pobj->lockedGetSlot(sprop->slot); + else + vp->setUndefined(); } JS_UNLOCK_OBJ(cx, pobj); } @@ -5513,9 +5501,9 @@ CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, check = clasp->checkAccess; if (!check) { callbacks = JS_GetSecurityCallbacks(cx); - check = callbacks ? callbacks->checkObjectAccess : NULL; + check = callbacks ? Valueify(callbacks->checkObjectAccess) : NULL; } - return !check || check(cx, pobj, ID_TO_VALUE(id), mode, vp); + return !check || check(cx, pobj, id, mode, vp); } } @@ -5543,12 +5531,12 @@ js_TypeOf(JSContext *cx, JSObject *obj) #ifdef NARCISSUS JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED); - jsval v; + Value v; if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.__call__Atom), &v)) { JS_ClearPendingException(cx); } else { - if (VALUE_IS_FUNCTION(cx, v)) + if (IsFunctionObject(v)) return JSTYPE_FUNCTION; } #endif @@ -5566,21 +5554,21 @@ js_DropProperty(JSContext *cx, JSObject *obj, JSProperty *prop) #ifdef NARCISSUS static JSBool -GetCurrentExecutionContext(JSContext *cx, JSObject *obj, jsval *rval) +GetCurrentExecutionContext(JSContext *cx, JSObject *obj, Value *rval) { JSObject *tmp; - jsval xcval; + Value xcval; while ((tmp = obj->getParent()) != NULL) obj = tmp; if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.ExecutionContextAtom), &xcval)) return JS_FALSE; - if (JSVAL_IS_PRIMITIVE(xcval)) { + if (xcval.isPrimitive()) { JS_ReportError(cx, "invalid ExecutionContext in global object"); return JS_FALSE; } - if (!JSVAL_TO_OBJECT(xcval)->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.currentAtom), - rval)) { + if (!xcval.toObject().getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.currentAtom), + rval)) { return JS_FALSE; } return JS_TRUE; @@ -5588,38 +5576,38 @@ GetCurrentExecutionContext(JSContext *cx, JSObject *obj, jsval *rval) #endif JSBool -js_Call(JSContext *cx, uintN argc, jsval *vp) +js_Call(JSContext *cx, uintN argc, Value *vp) { JSStackFrame *fp = cx->fp; JSObject *obj = fp->getThisObject(cx); if (!obj) return false; - JS_ASSERT(OBJECT_TO_JSVAL(obj) == fp->thisv); + JS_ASSERT(ObjectValue(*obj) == fp->thisv); - JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); - JSClass *clasp = callee->getClass(); + JSObject *callee = &JS_CALLEE(cx, vp).toObject(); + Class *clasp = callee->getClass(); if (!clasp->call) { #ifdef NARCISSUS JSObject *args; - jsval fval, nargv[3]; + Value fval, nargv[3]; JSBool ok; if (!callee->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.__call__Atom), &fval)) return JS_FALSE; - if (VALUE_IS_FUNCTION(cx, fval)) { + if (IsFunctionObject(fval)) { if (!GetCurrentExecutionContext(cx, obj, &nargv[2])) return JS_FALSE; args = js_GetArgsObject(cx, js_GetTopStackFrame(cx)); if (!args) return JS_FALSE; - nargv[0] = OBJECT_TO_JSVAL(obj); - nargv[1] = OBJECT_TO_JSVAL(args); - return js_InternalCall(cx, callee, fval, 3, nargv, rval); + nargv[0].setObject(*obj); + nargv[1].setObject(*args); + return InternalCall(cx, callee, fval, 3, nargv, rval); } - if (JSVAL_IS_OBJECT(fval) && JSVAL_TO_OBJECT(fval) != callee) { + if (fval.isObjectOrNull() && fval.toObjectOrNull() != callee) { vp[0] = fval; ok = js_Call(cx, argc, vp); - vp[0] = OBJECT_TO_JSVAL(callee); + vp[0].setObject(*callee); return ok; } #endif @@ -5634,32 +5622,31 @@ js_Call(JSContext *cx, uintN argc, jsval *vp) } JSBool -js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +js_Construct(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { - JSClass *clasp; - clasp = JSVAL_TO_OBJECT(argv[-2])->getClass(); + Class *clasp = argv[-2].toObject().getClass(); if (!clasp->construct) { #ifdef NARCISSUS JSObject *callee, *args; - jsval cval, nargv[2]; + Value cval, nargv[2]; JSBool ok; - callee = JSVAL_TO_OBJECT(argv[-2]); + callee = &argv[-2].toObject(); if (!callee->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.__construct__Atom), &cval)) { return JS_FALSE; } - if (VALUE_IS_FUNCTION(cx, cval)) { + if (IsFunctionObject(cval)) { if (!GetCurrentExecutionContext(cx, obj, &nargv[1])) return JS_FALSE; args = js_GetArgsObject(cx, js_GetTopStackFrame(cx)); if (!args) return JS_FALSE; - nargv[0] = OBJECT_TO_JSVAL(args); - return js_InternalCall(cx, callee, cval, 2, nargv, rval); + nargv[0].setObject(*args); + return InternalCall(cx, callee, cval, 2, nargv, rval); } - if (JSVAL_IS_OBJECT(cval) && JSVAL_TO_OBJECT(cval) != callee) { + if (cval.isObjectOrNull() && cval.toObjectOrNull() != callee) { argv[-2] = cval; ok = js_Call(cx, argc, argv - 2); if (ok) @@ -5675,21 +5662,19 @@ js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } JSBool -js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +js_HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) { - JSClass *clasp; - - clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (clasp->hasInstance) return clasp->hasInstance(cx, obj, v, bp); #ifdef NARCISSUS { - jsval fval, rval; + Value fval, rval; if (!obj->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.__hasInstance__Atom), &fval)) return JS_FALSE; - if (VALUE_IS_FUNCTION(cx, fval)) { - if (!js_InternalCall(cx, obj, fval, 1, &v, &rval)) + if (IsFunctionObject(fval)) { + if (!InternalCall(cx, obj, fval, 1, v, &rval)) return JS_FALSE; *bp = js_ValueToBoolean(rval); return JS_TRUE; @@ -5697,43 +5682,38 @@ js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) } #endif js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, - JSDVG_SEARCH_STACK, OBJECT_TO_JSVAL(obj), NULL); + JSDVG_SEARCH_STACK, ObjectValue(*obj), NULL); return JS_FALSE; } -JSBool -js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +bool +js_IsDelegate(JSContext *cx, JSObject *obj, const Value &v) { - JSObject *obj2; - - *bp = JS_FALSE; - if (JSVAL_IS_PRIMITIVE(v)) - return JS_TRUE; - obj2 = JSVAL_TO_OBJECT(v)->wrappedObject(cx); + if (v.isPrimitive()) + return false; + JSObject *obj2 = v.toObject().wrappedObject(cx); while ((obj2 = obj2->getProto()) != NULL) { - if (obj2 == obj) { - *bp = JS_TRUE; - break; - } + if (obj2 == obj) + return true; } - return JS_TRUE; + return false; } bool js::FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop, - JSClass *clasp) + Class *clasp) { - jsval v; + Value v; if (!js_FindClassObject(cx, scope, protoKey, &v, clasp)) return false; - if (VALUE_IS_FUNCTION(cx, v)) { - JSObject *ctor = JSVAL_TO_OBJECT(v); + if (IsFunctionObject(v)) { + JSObject *ctor = &v.toObject(); if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &v)) return false; } - *protop = JSVAL_IS_OBJECT(v) ? JSVAL_TO_OBJECT(v) : NULL; + *protop = v.isObject() ? &v.toObject() : NULL; return true; } @@ -5743,7 +5723,7 @@ js::FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSOb */ JSBool js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, - JSObject **protop, JSClass *clasp) + JSObject **protop, Class *clasp) { VOUCH_DOES_NOT_REQUIRE_STACK(); JS_ASSERT(JSProto_Null <= protoKey); @@ -5763,9 +5743,9 @@ js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, } scope = scope->getGlobal(); if (scope->getClass()->flags & JSCLASS_IS_GLOBAL) { - jsval v = scope->getReservedSlot(JSProto_LIMIT + protoKey); - if (!JSVAL_IS_PRIMITIVE(v)) { - *protop = JSVAL_TO_OBJECT(v); + const Value &v = scope->getReservedSlot(JSProto_LIMIT + protoKey); + if (v.isObject()) { + *protop = &v.toObject(); return true; } } @@ -5790,30 +5770,25 @@ js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, * 'constructor' in f.prototype for all function objects f. */ static JSBool -CheckCtorGetAccess(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +CheckCtorGetAccess(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - JSAtom *atom; - uintN attrs; - - atom = cx->runtime->atomState.constructorAtom; + JSAtom *atom = cx->runtime->atomState.constructorAtom; JS_ASSERT(id == ATOM_TO_JSID(atom)); + uintN attrs; return CheckAccess(cx, obj, ATOM_TO_JSID(atom), JSACC_READ, vp, &attrs); } static JSBool -CheckCtorSetAccess(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +CheckCtorSetAccess(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - JSAtom *atom; - uintN attrs; - - atom = cx->runtime->atomState.constructorAtom; + JSAtom *atom = cx->runtime->atomState.constructorAtom; JS_ASSERT(id == ATOM_TO_JSID(atom)); + uintN attrs; return CheckAccess(cx, obj, ATOM_TO_JSID(atom), JSACC_WRITE, vp, &attrs); } JSBool -js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, - uintN attrs) +js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs) { /* * Use the given attributes for the prototype property of the constructor, @@ -5822,8 +5797,7 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, * DontDelete. */ if (!ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), - OBJECT_TO_JSVAL(proto), JS_PropertyStub, JS_PropertyStub, - attrs)) { + ObjectOrNullValue(proto), PropertyStub, PropertyStub, attrs)) { return JS_FALSE; } @@ -5832,65 +5806,57 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, * for a user-defined function f, is DontEnum. */ return proto->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), - OBJECT_TO_JSVAL(ctor), CheckCtorGetAccess, CheckCtorSetAccess, 0); + ObjectOrNullValue(ctor), CheckCtorGetAccess, CheckCtorSetAccess, 0); } JSBool -js_PrimitiveToObject(JSContext *cx, jsval *vp) +js_PrimitiveToObject(JSContext *cx, Value *vp) { - JSClass *clasp; - JSObject *obj; + Value v = *vp; + JS_ASSERT(v.isPrimitive()); - /* Table to map primitive value's tag into the corresponding class. */ - JS_STATIC_ASSERT(JSVAL_INT == 1); - JS_STATIC_ASSERT(JSVAL_DOUBLE == 2); - JS_STATIC_ASSERT(JSVAL_STRING == 4); - JS_STATIC_ASSERT(JSVAL_SPECIAL == 6); - static JSClass *const PrimitiveClasses[] = { - &js_NumberClass, /* INT */ - &js_NumberClass, /* DOUBLE */ - &js_NumberClass, /* INT */ - &js_StringClass, /* STRING */ - &js_NumberClass, /* INT */ - &js_BooleanClass, /* BOOLEAN */ - &js_NumberClass /* INT */ - }; + Class *clasp; + if (v.isNumber()) + clasp = &js_NumberClass; + else if (v.isString()) + clasp = &js_StringClass; + else + clasp = &js_BooleanClass; - JS_ASSERT(!JSVAL_IS_OBJECT(*vp)); - JS_ASSERT(!JSVAL_IS_VOID(*vp)); - clasp = PrimitiveClasses[JSVAL_TAG(*vp) - 1]; - obj = NewBuiltinClassInstance(cx, clasp); + JSObject *obj = NewBuiltinClassInstance(cx, clasp); if (!obj) return JS_FALSE; - obj->setPrimitiveThis(*vp); - *vp = OBJECT_TO_JSVAL(obj); + + obj->setPrimitiveThis(v); + vp->setObject(*obj); return JS_TRUE; } JSBool -js_ValueToObject(JSContext *cx, jsval v, JSObject **objp) +js_ValueToObjectOrNull(JSContext *cx, const Value &v, JSObject **objp) { JSObject *obj; - if (JSVAL_IS_OBJECT(v)) { - obj = JSVAL_TO_OBJECT(v); - } else if (JSVAL_IS_VOID(v)) { + if (v.isObjectOrNull()) { + obj = v.toObjectOrNull(); + } else if (v.isUndefined()) { obj = NULL; } else { - if (!js_PrimitiveToObject(cx, &v)) + Value tmp = v; + if (!js_PrimitiveToObject(cx, &tmp)) return JS_FALSE; - obj = JSVAL_TO_OBJECT(v); + obj = &tmp.toObject(); } *objp = obj; return JS_TRUE; } JSObject * -js_ValueToNonNullObject(JSContext *cx, jsval v) +js_ValueToNonNullObject(JSContext *cx, const Value &v) { JSObject *obj; - if (!js_ValueToObject(cx, v, &obj)) + if (!js_ValueToObjectOrNull(cx, v, &obj)) return NULL; if (!obj) js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, v, NULL); @@ -5898,24 +5864,19 @@ js_ValueToNonNullObject(JSContext *cx, jsval v) } JSBool -js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, jsval *rval) +js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, Value *rval) { - jsval argv[1]; + Value argv[1]; - argv[0] = ATOM_KEY(cx->runtime->atomState.typeAtoms[type]); - return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, 1, argv, - rval); + argv[0].setString(ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[type])); + return js_TryMethod(cx, obj, cx->runtime->atomState.valueOfAtom, + 1, argv, rval); } JSBool js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, - uintN argc, jsval *argv, jsval *rval) + uintN argc, Value *argv, Value *rval) { - JSErrorReporter older; - jsid id; - jsval fval; - JSBool ok; - JS_CHECK_RECURSION(cx, return JS_FALSE); /* @@ -5923,17 +5884,17 @@ js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, * returned failure. We propagate failure in this case to make exceptions * behave properly. */ - older = JS_SetErrorReporter(cx, NULL); - id = ATOM_TO_JSID(atom); - fval = JSVAL_VOID; - ok = js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval); + JSErrorReporter older = JS_SetErrorReporter(cx, NULL); + jsid id = ATOM_TO_JSID(atom); + Value fval; + JSBool ok = js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &fval); JS_SetErrorReporter(cx, older); if (!ok) return false; - if (JSVAL_IS_PRIMITIVE(fval)) + if (fval.isPrimitive()) return JS_TRUE; - return js_InternalCall(cx, obj, fval, argc, argv, rval); + return InternalCall(cx, obj, fval, argc, argv, rval); } #if JS_HAS_XDR @@ -5943,7 +5904,7 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp) { JSContext *cx; JSAtom *atom; - JSClass *clasp; + Class *clasp; uint32 classId, classDef; JSProtoKey protoKey; JSObject *proto; @@ -5955,7 +5916,7 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp) classId = JS_XDRFindClassIdByName(xdr, clasp->name); classDef = !classId; if (classDef) { - if (!JS_XDRRegisterClass(xdr, clasp, &classId)) + if (!JS_XDRRegisterClass(xdr, Jsvalify(clasp), &classId)) return JS_FALSE; protoKey = JSCLASS_CACHED_PROTO_KEY(clasp); if (protoKey != JSProto_Null) { @@ -5994,10 +5955,10 @@ js_XDRObject(JSXDRState *xdr, JSObject **objp) if (!js_GetClassPrototype(cx, NULL, protoKey, &proto, clasp)) return JS_FALSE; clasp = proto->getClass(); - if (!JS_XDRRegisterClass(xdr, clasp, &classId)) + if (!JS_XDRRegisterClass(xdr, Jsvalify(clasp), &classId)) return JS_FALSE; } else { - clasp = JS_XDRFindClassById(xdr, classId); + clasp = Valueify(JS_XDRFindClassById(xdr, classId)); if (!clasp) { char numBuf[12]; JS_snprintf(numBuf, sizeof numBuf, "%ld", (long)classId); @@ -6075,7 +6036,7 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize) if (!sprop) { const char *slotname = NULL; - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (clasp->flags & JSCLASS_IS_GLOBAL) { uint32 key = slot - JSSLOT_START(clasp); #define JS_PROTO(name,code,init) \ @@ -6089,11 +6050,11 @@ js_PrintObjectSlotName(JSTracer *trc, char *buf, size_t bufsize) else JS_snprintf(buf, bufsize, "**UNKNOWN SLOT %ld**", (long)slot); } else { - jsval nval = ID_TO_VALUE(sprop->id); - if (JSVAL_IS_INT(nval)) { - JS_snprintf(buf, bufsize, "%ld", (long)JSVAL_TO_INT(nval)); - } else if (JSVAL_IS_STRING(nval)) { - js_PutEscapedString(buf, bufsize, JSVAL_TO_STRING(nval), 0); + jsid id = sprop->id; + if (JSID_IS_INT(id)) { + JS_snprintf(buf, bufsize, "%ld", (long)JSID_TO_INT(id)); + } else if (JSID_IS_ATOM(id)) { + js_PutEscapedString(buf, bufsize, JSID_TO_STRING(id), 0); } else { JS_snprintf(buf, bufsize, "**FINALIZED ATOM KEY**"); } @@ -6129,7 +6090,7 @@ js_TraceObject(JSTracer *trc, JSObject *obj) js_TraceWatchPoints(trc, obj); /* No one runs while the GC is running, so we can use LOCKED_... here. */ - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (clasp->mark) { if (clasp->flags & JSCLASS_MARK_IS_TRACE) ((JSTraceOp) clasp->mark)(trc, obj); @@ -6158,11 +6119,9 @@ js_TraceObject(JSTracer *trc, JSObject *obj) JS_ASSERT(nslots >= JSSLOT_START(clasp)); for (uint32 i = JSSLOT_START(clasp); i != nslots; ++i) { - jsval v = obj->getSlot(i); - if (JSVAL_IS_TRACEABLE(v)) { - JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i); - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); - } + const Value &v = obj->getSlot(i); + JS_SET_TRACING_DETAILS(trc, js_PrintObjectSlotName, obj, i); + MarkValueRaw(trc, v); } } @@ -6187,34 +6146,37 @@ js_Clear(JSContext *cx, JSObject *obj) i = obj->numSlots(); n = JSSLOT_FREE(obj->getClass()); while (--i >= n) - obj->setSlot(i, JSVAL_VOID); + obj->setSlot(i, UndefinedValue()); scope->freeslot = n; } JS_UNLOCK_OBJ(cx, obj); } bool -js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp) +js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, Value *vp) { if (!obj->isNative()) { - *vp = JSVAL_VOID; + vp->setUndefined(); return true; } uint32 slot = JSSLOT_START(obj->getClass()) + index; JS_LOCK_OBJ(cx, obj); - *vp = (slot < obj->numSlots()) ? obj->getSlot(slot) : JSVAL_VOID; + if (slot < obj->numSlots()) + *vp = obj->getSlot(slot); + else + vp->setUndefined(); JS_UNLOCK_OBJ(cx, obj); return true; } bool -js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v) +js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, const Value &v) { if (!obj->isNative()) return true; - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); uint32 slot = JSSLOT_START(clasp) + index; JS_LOCK_OBJ(cx, obj); @@ -6253,7 +6215,7 @@ js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v) JSObject * JSObject::wrappedObject(JSContext *cx) const { - JSClass *clasp = getClass(); + Class *clasp = getClass(); if (clasp->flags & JSCLASS_IS_EXTENDED) { if (JSObjectOp wrappedObject = reinterpret_cast(clasp)->wrappedObject) { if (JSObject *obj = wrappedObject(cx, const_cast(this))) @@ -6287,7 +6249,7 @@ JSObject::getCompartment(JSContext *cx) { JSObject *obj = getGlobal(); - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (!(clasp->flags & JSCLASS_IS_GLOBAL)) { // The magic AnyName object is runtime-wide. if (clasp == &js_AnyNameClass) @@ -6295,7 +6257,7 @@ JSObject::getCompartment(JSContext *cx) // The magic function namespace object is runtime-wide. if (clasp == &js_NamespaceClass.base && - obj->getNameURI() == ATOM_KEY(cx->runtime->atomState.lazy.functionNamespaceURIAtom)) { + obj->getNameURI() == ATOM_TO_JSVAL(cx->runtime->atomState.lazy.functionNamespaceURIAtom)) { return cx->runtime->defaultCompartment; } @@ -6306,12 +6268,12 @@ JSObject::getCompartment(JSContext *cx) } JS_NOT_REACHED("non-global object at end of scope chain"); } - jsval v = obj->getReservedSlot(JSRESERVED_GLOBAL_COMPARTMENT); - return (JSCompartment *) JSVAL_TO_PRIVATE(v); + const Value &v = obj->getReservedSlot(JSRESERVED_GLOBAL_COMPARTMENT); + return (JSCompartment *)v.toPrivate(); } JS_FRIEND_API(JSBool) -js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_GETTER_ONLY); return JS_FALSE; @@ -6377,53 +6339,63 @@ JS_FRIEND_API(void) js_DumpAtom(JSAtom *atom) { fprintf(stderr, "JSAtom* (%p) = ", (void *) atom); - js_DumpValue(ATOM_KEY(atom)); + js_DumpString(ATOM_TO_STRING(atom)); } void -dumpValue(jsval val) +dumpValue(const Value &v) { - if (JSVAL_IS_NULL(val)) { + if (v.isNull()) fprintf(stderr, "null"); - } else if (JSVAL_IS_VOID(val)) { + else if (v.isUndefined()) fprintf(stderr, "undefined"); - } else if (JSVAL_IS_OBJECT(val) && JSVAL_TO_OBJECT(val)->isFunction()) { - JSObject *funobj = JSVAL_TO_OBJECT(val); + else if (v.isInt32()) + fprintf(stderr, "%d", v.toInt32()); + else if (v.isDouble()) + fprintf(stderr, "%g", v.toDouble()); + else if (v.isString()) + dumpString(v.toString()); + else if (v.isObject() && v.toObject().isFunction()) { + JSObject *funobj = &v.toObject(); JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); fprintf(stderr, "<%s %s at %p (JSFunction at %p)>", fun->atom ? "function" : "unnamed", fun->atom ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom)) : "function", (void *) funobj, (void *) fun); - } else if (JSVAL_IS_OBJECT(val)) { - JSObject *obj = JSVAL_TO_OBJECT(val); - JSClass *clasp = obj->getClass(); + } else if (v.isObject()) { + JSObject *obj = &v.toObject(); + Class *clasp = obj->getClass(); fprintf(stderr, "<%s%s at %p>", clasp->name, clasp == &js_ObjectClass ? "" : " object", (void *) obj); - } else if (JSVAL_IS_INT(val)) { - fprintf(stderr, "%d", JSVAL_TO_INT(val)); - } else if (JSVAL_IS_STRING(val)) { - dumpString(JSVAL_TO_STRING(val)); - } else if (JSVAL_IS_DOUBLE(val)) { - fprintf(stderr, "%g", *JSVAL_TO_DOUBLE(val)); - } else if (val == JSVAL_TRUE) { - fprintf(stderr, "true"); - } else if (val == JSVAL_FALSE) { - fprintf(stderr, "false"); - } else if (val == JSVAL_HOLE) { - fprintf(stderr, "hole"); + } else if (v.isBoolean()) { + if (v.toBoolean()) + fprintf(stderr, "true"); + else + fprintf(stderr, "false"); + } else if (v.isMagic()) { + fprintf(stderr, ""); } else { - /* jsvals are pointer-sized, and %p is portable */ - fprintf(stderr, "unrecognized jsval %p", (void *) val); + fprintf(stderr, "unexpected value"); } } JS_FRIEND_API(void) -js_DumpValue(jsval val) +js_DumpValue(const Value &val) { - fprintf(stderr, "jsval %p = ", (void *) val); dumpValue(val); fputc('\n', stderr); } @@ -6431,8 +6403,8 @@ js_DumpValue(jsval val) JS_FRIEND_API(void) js_DumpId(jsid id) { - fprintf(stderr, "jsid %p = ", (void *) id); - dumpValue(ID_TO_VALUE(id)); + fprintf(stderr, "jsid %p = ", (void *) JSID_BITS(id)); + dumpValue(IdToValue(id)); fputc('\n', stderr); } @@ -6451,11 +6423,11 @@ dumpScopeProp(JSScopeProperty *sprop) if (attrs & JSPROP_SHARED) fprintf(stderr, "shared "); if (sprop->isAlias()) fprintf(stderr, "alias "); if (JSID_IS_ATOM(id)) - dumpString(JSVAL_TO_STRING(ID_TO_VALUE(id))); + dumpString(JSID_TO_STRING(id)); else if (JSID_IS_INT(id)) fprintf(stderr, "%d", (int) JSID_TO_INT(id)); else - fprintf(stderr, "unknown jsid %p", (void *) id); + fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id)); fprintf(stderr, ": slot %d", sprop->slot); fprintf(stderr, "\n"); } @@ -6464,7 +6436,7 @@ JS_FRIEND_API(void) js_DumpObject(JSObject *obj) { uint32 i, slots; - JSClass *clasp; + Class *clasp; jsuint reservedEnd; fprintf(stderr, "object %p\n", (void *) obj); @@ -6499,11 +6471,11 @@ js_DumpObject(JSObject *obj) } fprintf(stderr, "proto "); - dumpValue(OBJECT_TO_JSVAL(obj->getProto())); + dumpValue(ObjectOrNullValue(obj->getProto())); fputc('\n', stderr); fprintf(stderr, "parent "); - dumpValue(OBJECT_TO_JSVAL(obj->getParent())); + dumpValue(ObjectOrNullValue(obj->getParent())); fputc('\n', stderr); i = JSSLOT_PRIVATE; @@ -6533,15 +6505,15 @@ MaybeDumpObject(const char *name, JSObject *obj) { if (obj) { fprintf(stderr, " %s: ", name); - dumpValue(OBJECT_TO_JSVAL(obj)); + dumpValue(ObjectValue(*obj)); fputc('\n', stderr); } } static void -MaybeDumpValue(const char *name, jsval v) +MaybeDumpValue(const char *name, const Value &v) { - if (!JSVAL_IS_NULL(v)) { + if (!v.isNull()) { fprintf(stderr, " %s: ", name); dumpValue(v); fputc('\n', stderr); @@ -6594,11 +6566,11 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start) fprintf(stderr, "pc = %p\n", pc); fprintf(stderr, " current op: %s\n", js_CodeName[*pc]); } - jsval *sp = i.sp(); + Value *sp = i.sp(); fprintf(stderr, " slots: %p\n", (void *) fp->slots()); fprintf(stderr, " sp: %p = slots + %u\n", (void *) sp, (unsigned) (sp - fp->slots())); if (sp - fp->slots() < 10000) { // sanity - for (jsval *p = fp->slots(); p < sp; p++) { + for (Value *p = fp->slots(); p < sp; p++) { fprintf(stderr, " %p: ", (void *) p); dumpValue(*p); fputc('\n', stderr); @@ -6606,7 +6578,7 @@ js_DumpStackFrame(JSContext *cx, JSStackFrame *start) } fprintf(stderr, " argv: %p (argc: %u)\n", (void *) fp->argv, (unsigned) fp->argc); MaybeDumpObject("callobj", fp->callobj); - MaybeDumpObject("argsobj", JSVAL_TO_OBJECT(fp->argsobj)); + MaybeDumpObject("argsobj", fp->argsobj); MaybeDumpValue("this", fp->thisv); fprintf(stderr, " rval: "); dumpValue(fp->rval); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 4aee6c2d6ebc..bb56435b5655 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -52,22 +52,52 @@ #include "jshash.h" /* Added by JSIFY */ #include "jspubtd.h" #include "jsprvtd.h" +#include "jsvalue.h" #include "jsvector.h" -namespace js { class AutoDescriptorArray; class JSProxyHandler; } +namespace js { + +class JSProxyHandler; +class AutoPropDescArrayRooter; + +static inline PropertyOp +CastAsPropertyOp(JSObject *object) +{ + return JS_DATA_TO_FUNC_PTR(PropertyOp, object); +} + +static inline JSPropertyOp +CastAsJSPropertyOp(JSObject *object) +{ + return JS_DATA_TO_FUNC_PTR(JSPropertyOp, object); +} + +inline JSObject * +CastAsObject(PropertyOp op) +{ + return JS_FUNC_TO_DATA_PTR(JSObject *, op); +} + +inline Value +CastAsObjectJsval(PropertyOp op) +{ + return ObjectValue(*CastAsObject(op)); +} + +} /* namespace js */ /* * A representation of ECMA-262 ed. 5's internal property descriptor data * structure. */ -struct PropertyDescriptor { - friend class js::AutoDescriptorArray; +struct PropDesc { + friend class js::AutoPropDescArrayRooter; - PropertyDescriptor(); + PropDesc(); public: /* 8.10.5 ToPropertyDescriptor(Obj) */ - bool initialize(JSContext* cx, jsid id, jsval v); + bool initialize(JSContext* cx, jsid id, const js::Value &v); /* 8.10.1 IsAccessorDescriptor(desc) */ bool isAccessorDescriptor() const { @@ -97,32 +127,32 @@ struct PropertyDescriptor { } JSObject* getterObject() const { - return (get != JSVAL_VOID) ? JSVAL_TO_OBJECT(get) : NULL; + return get.isUndefined() ? NULL : &get.toObject(); } JSObject* setterObject() const { - return (set != JSVAL_VOID) ? JSVAL_TO_OBJECT(set) : NULL; + return set.isUndefined() ? NULL : &set.toObject(); } - jsval getterValue() const { + const js::Value &getterValue() const { return get; } - jsval setterValue() const { + const js::Value &setterValue() const { return set; } - JSPropertyOp getter() const { + js::PropertyOp getter() const { return js::CastAsPropertyOp(getterObject()); } - JSPropertyOp setter() const { + js::PropertyOp setter() const { return js::CastAsPropertyOp(setterObject()); } static void traceDescriptorArray(JSTracer* trc, JSObject* obj); static void finalizeDescriptorArray(JSContext* cx, JSObject* obj); - jsval pd; + js::Value pd; jsid id; - jsval value, get, set; + js::Value value, get, set; /* Property descriptor boolean fields. */ uint8 attrs; @@ -137,11 +167,9 @@ struct PropertyDescriptor { }; namespace js { - typedef Vector PropertyDescriptorArray; + typedef Vector PropDescArray; } -JS_BEGIN_EXTERN_C - /* For detailed comments on these function pointer types, see jsprvtd.h. */ struct JSObjectOps { /* @@ -153,21 +181,21 @@ struct JSObjectOps { /* Mandatory non-null function pointer members. */ JSLookupPropOp lookupProperty; - JSDefinePropOp defineProperty; - JSPropertyIdOp getProperty; - JSPropertyIdOp setProperty; + js::DefinePropOp defineProperty; + js::PropertyIdOp getProperty; + js::PropertyIdOp setProperty; JSAttributesOp getAttributes; JSAttributesOp setAttributes; - JSPropertyIdOp deleteProperty; - JSNewEnumerateOp enumerate; + js::PropertyIdOp deleteProperty; + js::NewEnumerateOp enumerate; JSTypeOfOp typeOf; JSTraceOp trace; /* Optionally non-null members start here. */ JSObjectOp thisObject; - JSCallOp call; - JSNative construct; - JSHasInstanceOp hasInstance; + js::CallOp call; + js::Native construct; + js::HasInstanceOp hasInstance; JSFinalizeOp clear; bool inline isNative() const; @@ -208,25 +236,18 @@ const uint32 JSSLOT_PARENT = 0; /* * The first available slot to store generic value. For JSCLASS_HAS_PRIVATE - * classes the slot stores a pointer to private data reinterpreted as jsval. + * classes the slot stores a pointer to private data stuffed in a Value. * Such pointer is stored as is without an overhead of PRIVATE_TO_JSVAL * tagging and should be accessed using the (get|set)Private methods of * JSObject. */ const uint32 JSSLOT_PRIVATE = 1; -const uintptr_t JSSLOT_CLASS_MASK_BITS = 3; - /* * JSObject struct, with members sized to fit in 32 bytes on 32-bit targets, * 64 bytes on 64-bit systems. The JSFunction struct is an extension of this * struct allocated from a larger GC size-class. * - * The classword member stores the JSClass pointer for this object, with the - * least two bits encoding whether this object is a "delegate" or a "system" - * object. We do *not* synchronize updates of classword -- API clients must - * take care. - * * An object is a delegate if it is on another object's prototype (linked by * JSSLOT_PROTO) or scope (JSSLOT_PARENT) chain, and therefore the delegate * might be asked implicitly to get or set a property on behalf of another @@ -242,11 +263,11 @@ const uintptr_t JSSLOT_CLASS_MASK_BITS = 3; * to be complementary to this bit, but it is up to the API client to implement * any such association. * - * Both these classword tag bits are initially zero; they may be set or queried - * using the (is|set)(Delegate|System) inline methods. + * Both these flags are initially zero; they may be set or queried using the + * (is|set)(Delegate|System) inline methods. * * The dslots member is null or a pointer into a dynamically allocated vector - * of jsvals for reserved and dynamic slots. If dslots is not null, dslots[-1] + * of Values for reserved and dynamic slots. If dslots is not null, dslots[-1] * records the number of available slots. */ struct JSObject { @@ -257,30 +278,42 @@ struct JSObject { friend class js::TraceRecorder; JSObjectMap *map; /* property map, see jsscope.h */ - jsuword classword; /* JSClass ptr | bits, see above */ + js::Class *clasp; /* class pointer */ + jsuword flags; /* see above */ JSObject *proto; /* object's prototype */ - jsval fslots[JS_INITIAL_NSLOTS]; /* small number of fixed slots */ - jsval *dslots; /* dynamically allocated slots */ + js::Value *dslots; /* dynamically allocated slots */ +#if JS_BITS_PER_WORD == 32 + // TODO: this is needed to pad out fslots. alternatively, clasp could be + // merged by with flags and the padding removed, but I think the upcoming + // removal of JSScope will change this all anyway so I will leave this + // here for now. + uint32 padding; +#endif + js::Value fslots[JS_INITIAL_NSLOTS]; /* small number of fixed slots */ bool isNative() const { return map->ops->isNative(); } - JSClass *getClass() const { - return (JSClass *) (classword & ~JSSLOT_CLASS_MASK_BITS); + js::Class *getClass() const { + return clasp; } - bool hasClass(const JSClass *clasp) const { - return clasp == getClass(); + JSClass *getJSClass() const { + return Jsvalify(clasp); + } + + bool hasClass(const js::Class *c) const { + return c == clasp; } inline JSScope *scope() const; inline uint32 shape() const; bool isDelegate() const { - return (classword & jsuword(1)) != jsuword(0); + return (flags & jsuword(1)) != jsuword(0); } void setDelegate() { - classword |= jsuword(1); + flags |= jsuword(1); } static void setDelegateNullSafe(JSObject *obj) { @@ -289,15 +322,15 @@ struct JSObject { } bool isSystem() const { - return (classword & jsuword(2)) != jsuword(0); + return (flags & jsuword(2)) != jsuword(0); } void setSystem() { - classword |= jsuword(2); + flags |= jsuword(2); } uint32 numSlots(void) const { - return dslots ? (uint32)dslots[-1] : (uint32)JS_INITIAL_NSLOTS; + return dslots ? dslots[-1].toPrivateUint32() : (uint32)JS_INITIAL_NSLOTS; } private: @@ -316,31 +349,31 @@ struct JSObject { bool growSlots(JSContext *cx, size_t nslots); void shrinkSlots(JSContext *cx, size_t nslots); - jsval& getSlotRef(uintN slot) { + js::Value& getSlotRef(uintN slot) { return (slot < JS_INITIAL_NSLOTS) ? fslots[slot] - : (JS_ASSERT(slot < (uint32)dslots[-1]), + : (JS_ASSERT(slot < dslots[-1].toPrivateUint32()), dslots[slot - JS_INITIAL_NSLOTS]); } - jsval getSlot(uintN slot) const { + const js::Value &getSlot(uintN slot) const { return (slot < JS_INITIAL_NSLOTS) ? fslots[slot] - : (JS_ASSERT(slot < (uint32)dslots[-1]), + : (JS_ASSERT(slot < dslots[-1].toPrivateUint32()), dslots[slot - JS_INITIAL_NSLOTS]); } - void setSlot(uintN slot, jsval value) { + void setSlot(uintN slot, const js::Value &value) { if (slot < JS_INITIAL_NSLOTS) { fslots[slot] = value; } else { - JS_ASSERT(slot < (uint32)dslots[-1]); + JS_ASSERT(slot < dslots[-1].toPrivateUint32()); dslots[slot - JS_INITIAL_NSLOTS] = value; } } - inline jsval lockedGetSlot(uintN slot) const; - inline void lockedSetSlot(uintN slot, jsval value); + inline const js::Value &lockedGetSlot(uintN slot) const; + inline void lockedSetSlot(uintN slot, const js::Value &value); /* * These ones are for multi-threaded ("MT") objects. Use getSlot(), @@ -348,10 +381,10 @@ struct JSObject { * one thread can access obj, or when accessing read-only slots within * JS_INITIAL_NSLOTS. */ - inline jsval getSlotMT(JSContext *cx, uintN slot); - inline void setSlotMT(JSContext *cx, uintN slot, jsval value); + inline js::Value getSlotMT(JSContext *cx, uintN slot); + inline void setSlotMT(JSContext *cx, uintN slot, const js::Value &value); - inline jsval getReservedSlot(uintN index) const; + inline js::Value getReservedSlot(uintN index) const; JSObject *getProto() const { return proto; @@ -371,11 +404,11 @@ struct JSObject { } JSObject *getParent() const { - return JSVAL_TO_OBJECT(fslots[JSSLOT_PARENT]); + return fslots[JSSLOT_PARENT].toObjectOrNull(); } void clearParent() { - fslots[JSSLOT_PARENT] = JSVAL_NULL; + fslots[JSSLOT_PARENT].setNull(); } void setParent(JSObject *newParent) { @@ -384,7 +417,7 @@ struct JSObject { JS_ASSERT(obj != this); #endif setDelegateNullSafe(newParent); - fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(newParent); + fslots[JSSLOT_PARENT].setObjectOrNull(newParent); } void traceProtoAndParent(JSTracer *trc) const { @@ -398,22 +431,20 @@ struct JSObject { void *getPrivate() const { JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE); - jsval v = fslots[JSSLOT_PRIVATE]; - JS_ASSERT((v & jsval(1)) == jsval(0)); - return reinterpret_cast(v); + void *priv = fslots[JSSLOT_PRIVATE].toPrivate(); + return priv; } void setPrivate(void *data) { JS_ASSERT(getClass()->flags & JSCLASS_HAS_PRIVATE); - jsval v = reinterpret_cast(data); - JS_ASSERT((v & jsval(1)) == jsval(0)); - fslots[JSSLOT_PRIVATE] = v; + JS_ASSERT((size_t(data) & 1) == 0); + fslots[JSSLOT_PRIVATE].setPrivate(data); } - static jsval defaultPrivate(JSClass *clasp) { - return (clasp->flags & JSCLASS_HAS_PRIVATE) - ? JSVAL_NULL - : JSVAL_VOID; + static js::Value defaultPrivate(js::Class *clasp) { + if (clasp->flags & JSCLASS_HAS_PRIVATE) + return js::PrivateValue(NULL); + return js::UndefinedValue(); } /* @@ -424,8 +455,8 @@ struct JSObject { static const uint32 JSSLOT_PRIMITIVE_THIS = JSSLOT_PRIVATE; public: - inline jsval getPrimitiveThis() const; - inline void setPrimitiveThis(jsval pthis); + inline const js::Value &getPrimitiveThis() const; + inline void setPrimitiveThis(const js::Value &pthis); /* * Array-specific getters and setters (for both dense and slow arrays). @@ -464,11 +495,11 @@ struct JSObject { inline bool isDenseArrayMinLenCapOk(bool strictAboutLength = true) const; - inline jsval getDenseArrayElement(uint32 i) const; - inline jsval *addressOfDenseArrayElement(uint32 i); - inline void setDenseArrayElement(uint32 i, jsval v); + inline const js::Value &getDenseArrayElement(uint32 i) const; + inline js::Value *addressOfDenseArrayElement(uint32 i); + inline void setDenseArrayElement(uint32 i, const js::Value &v); - inline jsval *getDenseArrayElements() const; // returns pointer to the Array's elements array + inline js::Value *getDenseArrayElements() const; // returns pointer to the Array's elements array bool resizeDenseArrayElements(JSContext *cx, uint32 oldcap, uint32 newcap, bool initializeAllSlots = true); bool ensureDenseArrayElements(JSContext *cx, uint32 newcap, @@ -509,11 +540,12 @@ struct JSObject { inline void setArgsLengthOverridden(); inline bool isArgsLengthOverridden() const; - inline jsval getArgsCallee() const; - inline void setArgsCallee(jsval callee); + inline const js::Value &getArgsCallee() const; + inline void setArgsCallee(const js::Value &callee); - inline jsval getArgsElement(uint32 i) const; - inline void setArgsElement(uint32 i, jsval v); + inline const js::Value &getArgsElement(uint32 i) const; + inline js::Value *addressOfArgsElement(uint32 i) const; + inline void setArgsElement(uint32 i, const js::Value &v); /* * Date-specific getters and setters. @@ -527,13 +559,11 @@ struct JSObject { public: static const uint32 DATE_FIXED_RESERVED_SLOTS = 2; - inline jsval getDateLocalTime() const; - inline jsval *addressOfDateLocalTime(); - inline void setDateLocalTime(jsval pthis); + inline const js::Value &getDateLocalTime() const; + inline void setDateLocalTime(const js::Value &pthis); - inline jsval getDateUTCTime() const; - inline jsval *addressOfDateUTCTime(); - inline void setDateUTCTime(jsval pthis); + inline const js::Value &getDateUTCTime() const; + inline void setDateUTCTime(const js::Value &pthis); /* * RegExp-specific getters and setters. @@ -545,8 +575,8 @@ struct JSObject { public: static const uint32 REGEXP_FIXED_RESERVED_SLOTS = 1; - inline jsval getRegExpLastIndex() const; - inline jsval *addressOfRegExpLastIndex(); + inline const js::Value &getRegExpLastIndex() const; + inline void setRegExpLastIndex(const js::Value &v); inline void zeroRegExpLastIndex(); /* @@ -596,8 +626,8 @@ struct JSObject { */ inline js::JSProxyHandler *getProxyHandler() const; - inline jsval getProxyPrivate() const; - inline void setProxyPrivate(jsval priv); + inline const js::Value &getProxyPrivate() const; + inline void setProxyPrivate(const js::Value &priv); /* * With object-specific getters and setters. @@ -612,22 +642,20 @@ struct JSObject { inline bool isCallable(); /* The map field is not initialized here and should be set separately. */ - void init(JSClass *clasp, JSObject *proto, JSObject *parent, - jsval privateSlotValue) { - JS_ASSERT(((jsuword) clasp & 3) == 0); + void init(js::Class *aclasp, JSObject *proto, JSObject *parent, + const js::Value &privateSlotValue) { JS_STATIC_ASSERT(JSSLOT_PRIVATE + 3 == JS_INITIAL_NSLOTS); - JS_ASSERT_IF(clasp->flags & JSCLASS_HAS_PRIVATE, - (privateSlotValue & jsval(1)) == jsval(0)); - classword = jsuword(clasp); + clasp = aclasp; + flags = 0; JS_ASSERT(!isDelegate()); JS_ASSERT(!isSystem()); setProto(proto); setParent(parent); fslots[JSSLOT_PRIVATE] = privateSlotValue; - fslots[JSSLOT_PRIVATE + 1] = JSVAL_VOID; - fslots[JSSLOT_PRIVATE + 2] = JSVAL_VOID; + fslots[JSSLOT_PRIVATE + 1].setUndefined(); + fslots[JSSLOT_PRIVATE + 2].setUndefined(); dslots = NULL; } @@ -635,8 +663,10 @@ struct JSObject { * Like init, but also initializes map. The catch: proto must be the result * of a call to js_InitClass(...clasp, ...). */ - inline void initSharingEmptyScope(JSClass *clasp, JSObject *proto, JSObject *parent, - jsval privateSlotValue); + inline void initSharingEmptyScope(js::Class *clasp, + JSObject *proto, + JSObject *parent, + const js::Value &privateSlotValue); inline bool hasSlotsArray() const { return !!dslots; } @@ -648,18 +678,18 @@ struct JSObject { return map->ops->lookupProperty(cx, this, id, objp, propp); } - JSBool defineProperty(JSContext *cx, jsid id, jsval value, - JSPropertyOp getter = JS_PropertyStub, - JSPropertyOp setter = JS_PropertyStub, + JSBool defineProperty(JSContext *cx, jsid id, const js::Value &value, + js::PropertyOp getter = js::PropertyStub, + js::PropertyOp setter = js::PropertyStub, uintN attrs = JSPROP_ENUMERATE) { - return map->ops->defineProperty(cx, this, id, value, getter, setter, attrs); + return map->ops->defineProperty(cx, this, id, &value, getter, setter, attrs); } - JSBool getProperty(JSContext *cx, jsid id, jsval *vp) { + JSBool getProperty(JSContext *cx, jsid id, js::Value *vp) { return map->ops->getProperty(cx, this, id, vp); } - JSBool setProperty(JSContext *cx, jsid id, jsval *vp) { + JSBool setProperty(JSContext *cx, jsid id, js::Value *vp) { return map->ops->setProperty(cx, this, id, vp); } @@ -671,11 +701,11 @@ struct JSObject { return map->ops->setAttributes(cx, this, id, attrsp); } - JSBool deleteProperty(JSContext *cx, jsid id, jsval *rval) { + JSBool deleteProperty(JSContext *cx, jsid id, js::Value *rval) { return map->ops->deleteProperty(cx, this, id, rval); } - JSBool enumerate(JSContext *cx, JSIterateOp op, jsval *statep, + JSBool enumerate(JSContext *cx, JSIterateOp op, js::Value *statep, jsid *idp) { return map->ops->enumerate(cx, this, op, statep, idp); } @@ -690,6 +720,7 @@ struct JSObject { JSObject *thisObject(JSContext *cx) { return map->ops->thisObject ? map->ops->thisObject(cx, this) : this; } + static bool thisObject(JSContext *cx, const js::Value &v, js::Value *vp); inline void dropProperty(JSContext *cx, JSProperty *prop); @@ -720,8 +751,13 @@ struct JSObject { JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL); inline bool unbrand(JSContext *cx); + + inline void initArrayClass(); }; +JS_STATIC_ASSERT(offsetof(JSObject, fslots) % sizeof(js::Value) == 0); +JS_STATIC_ASSERT(sizeof(JSObject) % JS_GCTHING_ALIGN == 0); + #define JSSLOT_START(clasp) (((clasp)->flags & JSCLASS_HAS_PRIVATE) \ ? JSSLOT_PRIVATE + 1 \ : JSSLOT_PRIVATE) @@ -734,8 +770,8 @@ struct JSObject { * obj->dslots[-1] that is used to store the length of the vector biased by * JS_INITIAL_NSLOTS (and again net of the slot at index -1). */ -#define MAX_DSLOTS_LENGTH (~size_t(0) / sizeof(jsval) - 1) -#define MAX_DSLOTS_LENGTH32 (~uint32(0) / sizeof(jsval) - 1) +#define MAX_DSLOTS_LENGTH (~size_t(0) / sizeof(js::Value) - 1) +#define MAX_DSLOTS_LENGTH32 (~uint32(0) / sizeof(js::Value) - 1) #define OBJ_CHECK_SLOT(obj,slot) \ (JS_ASSERT((obj)->isNative()), JS_ASSERT(slot < (obj)->scope()->freeslot)) @@ -758,9 +794,9 @@ struct JSObject { inline void OBJ_TO_INNER_OBJECT(JSContext *cx, JSObject *&obj) { - JSClass *clasp = obj->getClass(); + js::Class *clasp = obj->getClass(); if (clasp->flags & JSCLASS_IS_EXTENDED) { - JSExtendedClass *xclasp = (JSExtendedClass *) clasp; + js::ExtendedClass *xclasp = (js::ExtendedClass *) clasp; if (xclasp->innerObject) obj = xclasp->innerObject(cx, obj); } @@ -773,25 +809,33 @@ OBJ_TO_INNER_OBJECT(JSContext *cx, JSObject *&obj) inline void OBJ_TO_OUTER_OBJECT(JSContext *cx, JSObject *&obj) { - JSClass *clasp = obj->getClass(); + js::Class *clasp = obj->getClass(); if (clasp->flags & JSCLASS_IS_EXTENDED) { - JSExtendedClass *xclasp = (JSExtendedClass *) clasp; + js::ExtendedClass *xclasp = (js::ExtendedClass *) clasp; if (xclasp->outerObject) obj = xclasp->outerObject(cx, obj); } } -class ValueArray { +class JSValueArray { public: jsval *array; size_t length; - ValueArray(jsval *v, size_t c) : array(v), length(c) {} + JSValueArray(jsval *v, size_t c) : array(v), length(c) {} }; -extern JSClass js_ObjectClass; -extern JSClass js_WithClass; -extern JSClass js_BlockClass; +class ValueArray { + public: + js::Value *array; + size_t length; + + ValueArray(js::Value *v, size_t c) : array(v), length(c) {} +}; + +extern js::Class js_ObjectClass; +extern js::Class js_WithClass; +extern js::Class js_BlockClass; /* * Block scope object macros. The slots reserved by js_BlockClass are: @@ -824,9 +868,9 @@ js_DefineBlockVariable(JSContext *cx, JSObject *obj, jsid id, intN index); #define OBJ_BLOCK_COUNT(cx,obj) \ ((OBJ_IS_CLONED_BLOCK(obj) ? obj->getProto() : obj)->scope()->entryCount) #define OBJ_BLOCK_DEPTH(cx,obj) \ - JSVAL_TO_INT(obj->getSlot(JSSLOT_BLOCK_DEPTH)) + obj->getSlot(JSSLOT_BLOCK_DEPTH).toInt32() #define OBJ_SET_BLOCK_DEPTH(cx,obj,depth) \ - obj->setSlot(JSSLOT_BLOCK_DEPTH, INT_TO_JSVAL(depth)) + obj->setSlot(JSSLOT_BLOCK_DEPTH, Value(Int32Value(depth))) /* * To make sure this slot is well-defined, always call js_NewWithObject to @@ -895,21 +939,23 @@ js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map); extern JSBool js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, uintN argc, - jsval *vp); + js::Value *vp); extern JSBool js_HasOwnProperty(JSContext *cx, JSLookupPropOp lookup, JSObject *obj, jsid id, JSObject **objp, JSProperty **propp); extern JSBool -js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, jsval getter, jsval setter, jsval value, jsval *vp); +js_NewPropertyDescriptorObject(JSContext *cx, jsid id, uintN attrs, + const js::Value &getter, const js::Value &setter, + const js::Value &value, js::Value *vp); extern JSBool -js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +js_PropertyIsEnumerable(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); #ifdef OLD_GETTER_SETTER_METHODS -JS_FRIEND_API(JSBool) js_obj_defineGetter(JSContext *cx, uintN argc, jsval *vp); -JS_FRIEND_API(JSBool) js_obj_defineSetter(JSContext *cx, uintN argc, jsval *vp); +JS_FRIEND_API(JSBool) js_obj_defineGetter(JSContext *cx, uintN argc, js::Value *vp); +JS_FRIEND_API(JSBool) js_obj_defineSetter(JSContext *cx, uintN argc, js::Value *vp); #endif extern JSObject * @@ -917,7 +963,7 @@ js_InitObjectClass(JSContext *cx, JSObject *obj); extern JSObject * js_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, - JSClass *clasp, JSNative constructor, uintN nargs, + js::Class *clasp, js::Native constructor, uintN nargs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs); @@ -950,8 +996,8 @@ extern const char js_lookupSetter_str[]; * object, not by the parent of its .prototype object value. */ extern JSObject* -js_NewObjectWithClassProto(JSContext *cx, JSClass *clasp, JSObject *proto, - jsval privateSlotValue); +js_NewObjectWithClassProto(JSContext *cx, js::Class *clasp, JSObject *proto, + const js::Value &privateSlotValue); extern JSBool js_PopulateObject(JSContext *cx, JSObject *newborn, JSObject *props); @@ -972,12 +1018,12 @@ js_SetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, * JSProto_Null, clasp must non-null. */ extern JSBool -js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey key, jsval *vp, - JSClass *clasp = NULL); +js_FindClassObject(JSContext *cx, JSObject *start, JSProtoKey key, + js::Value *vp, js::Class *clasp = NULL); extern JSObject * -js_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto, - JSObject *parent, uintN argc, jsval *argv); +js_ConstructObject(JSContext *cx, js::Class *clasp, JSObject *proto, + JSObject *parent, uintN argc, js::Value *argv); extern JSBool js_AllocSlot(JSContext *cx, JSObject *obj, uint32 *slotp); @@ -1021,7 +1067,7 @@ js_PurgeScopeChain(JSContext *cx, JSObject *obj, jsid id) */ extern JSScopeProperty * js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, - JSPropertyOp getter, JSPropertyOp setter, uint32 slot, + js::PropertyOp getter, js::PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid); /* @@ -1032,14 +1078,15 @@ js_AddNativeProperty(JSContext *cx, JSObject *obj, jsid id, extern JSScopeProperty * js_ChangeNativePropertyAttrs(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, uintN attrs, uintN mask, - JSPropertyOp getter, JSPropertyOp setter); + js::PropertyOp getter, js::PropertyOp setter); extern JSBool -js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs); +js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value *value, + js::PropertyOp getter, js::PropertyOp setter, uintN attrs); extern JSBool -js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp); +js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, + const js::Value &descriptor, JSBool *bp); /* * Flags for the defineHow parameter of js_DefineNativeProperty. @@ -1061,8 +1108,8 @@ const uintN JSDNP_UNQUALIFIED = 8; /* Unqualified property set. Only used in * the held property, and to release the lock on obj. */ extern JSBool -js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs, +js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value &value, + js::PropertyOp getter, js::PropertyOp setter, uintN attrs, uintN flags, intN shortid, JSProperty **propp, uintN defineHow = 0); @@ -1095,11 +1142,11 @@ js_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, jsid id, uintN flags, static inline bool js_IsCacheableNonGlobalScope(JSObject *obj) { - extern JS_FRIEND_DATA(JSClass) js_CallClass; - extern JS_FRIEND_DATA(JSClass) js_DeclEnvClass; + extern JS_FRIEND_DATA(js::Class) js_CallClass; + extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass; JS_ASSERT(obj->getParent()); - JSClass *clasp = obj->getClass(); + js::Class *clasp = obj->getClass(); bool cacheable = (clasp == &js_CallClass || clasp == &js_BlockClass || clasp == &js_DeclEnvClass); @@ -1154,24 +1201,24 @@ const uintN JSGET_NO_METHOD_BARRIER = 2; // call to joined function can't leak */ extern JSBool js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, - JSScopeProperty *sprop, uintN getHow, jsval *vp); + JSScopeProperty *sprop, uintN getHow, js::Value *vp); extern JSBool js_NativeSet(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, bool added, - jsval *vp); + js::Value *vp); extern JSBool js_GetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN getHow, - jsval *vp); + js::Value *vp); extern JSBool -js_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +js_GetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool -js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +js_GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool -js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, jsval *vp); +js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, js::Value *vp); /* * Check whether it is OK to assign an undeclared property with name @@ -1180,14 +1227,14 @@ js_GetMethod(JSContext *cx, JSObject *obj, jsid id, uintN getHow, jsval *vp); * when it returns false). */ extern JS_FRIEND_API(bool) -js_CheckUndeclaredVarAssignment(JSContext *cx, jsval propname); +js_CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname); extern JSBool js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow, - jsval *vp); + js::Value *vp); extern JSBool -js_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +js_SetProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool js_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp); @@ -1204,24 +1251,24 @@ js_SetNativeAttributes(JSContext *cx, JSObject *obj, JSScopeProperty *sprop, uintN attrs); extern JSBool -js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval); +js_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, js::Value *rval); namespace js { extern JSBool -DefaultValue(JSContext *cx, JSObject *obj, JSType hint, jsval *vp); +DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp); } extern JSBool js_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, - jsval *statep, jsid *idp); + js::Value *statep, jsid *idp); namespace js { extern JSBool CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, - jsval *vp, uintN *attrsp); + js::Value *vp, uintN *attrsp); } @@ -1229,17 +1276,17 @@ extern JSType js_TypeOf(JSContext *cx, JSObject *obj); extern JSBool -js_Call(JSContext *cx, uintN argc, jsval *vp); +js_Call(JSContext *cx, uintN argc, js::Value *vp); extern JSBool -js_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_Construct(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv, + js::Value *rval); extern JSBool -js_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +js_HasInstance(JSContext *cx, JSObject *obj, const js::Value *v, JSBool *bp); -extern JSBool -js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +extern bool +js_IsDelegate(JSContext *cx, JSObject *obj, const js::Value &v); /* * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is @@ -1247,7 +1294,7 @@ js_IsDelegate(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); */ extern JS_FRIEND_API(JSBool) js_GetClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, - JSObject **protop, JSClass *clasp = NULL); + JSObject **protop, js::Class *clasp = NULL); extern JSBool js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, @@ -1258,20 +1305,28 @@ js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, * *vp must not be an object, null or undefined. */ extern JSBool -js_PrimitiveToObject(JSContext *cx, jsval *vp); +js_PrimitiveToObject(JSContext *cx, js::Value *vp); +/* + * v and vp may alias. On successful return, vp->isObjectOrNull(). If vp is not + * rooted, the caller must root vp before the next possible GC. + */ extern JSBool -js_ValueToObject(JSContext *cx, jsval v, JSObject **objp); +js_ValueToObjectOrNull(JSContext *cx, const js::Value &v, JSObject **objp); +/* + * v and vp may alias. On successful return, vp->isObject(). If vp is not + * rooted, the caller must root vp before the next possible GC. + */ extern JSObject * -js_ValueToNonNullObject(JSContext *cx, jsval v); +js_ValueToNonNullObject(JSContext *cx, const js::Value &v); extern JSBool -js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, jsval *rval); +js_TryValueOf(JSContext *cx, JSObject *obj, JSType type, js::Value *rval); extern JSBool js_TryMethod(JSContext *cx, JSObject *obj, JSAtom *atom, - uintN argc, jsval *argv, jsval *rval); + uintN argc, js::Value *argv, js::Value *rval); extern JSBool js_XDRObject(JSXDRState *xdr, JSObject **objp); @@ -1286,18 +1341,14 @@ extern void js_Clear(JSContext *cx, JSObject *obj); extern bool -js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp); +js_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, js::Value *vp); extern bool -js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v); +js_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, const js::Value &v); /* * Precondition: obj must be locked. */ -extern JSBool -js_ReallocSlots(JSContext *cx, JSObject *obj, uint32 nslots, - JSBool exactAllocation); - extern JSObject * js_CheckScopeChainValidity(JSContext *cx, JSObject *scopeobj, const char *caller); @@ -1322,15 +1373,15 @@ extern JSBool js_ReportGetterOnlyAssignment(JSContext *cx); extern JS_FRIEND_API(JSBool) -js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +js_GetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp); #ifdef DEBUG JS_FRIEND_API(void) js_DumpChars(const jschar *s, size_t n); JS_FRIEND_API(void) js_DumpString(JSString *str); JS_FRIEND_API(void) js_DumpAtom(JSAtom *atom); -JS_FRIEND_API(void) js_DumpValue(jsval val); -JS_FRIEND_API(void) js_DumpId(jsid id); JS_FRIEND_API(void) js_DumpObject(JSObject *obj); +JS_FRIEND_API(void) js_DumpValue(const js::Value &val); +JS_FRIEND_API(void) js_DumpId(jsid id); JS_FRIEND_API(void) js_DumpStackFrame(JSContext *cx, JSStackFrame *start = NULL); #endif @@ -1339,9 +1390,8 @@ js_InferFlags(JSContext *cx, uintN defaultFlags); /* Object constructor native. Exposed only so the JIT can know its address. */ JSBool -js_Object(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +js_Object(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv, js::Value *rval); -JS_END_EXTERN_C namespace js { @@ -1356,5 +1406,4 @@ extern JSString * obj_toStringHelper(JSContext *cx, JSObject *obj); } - #endif /* jsobj_h___ */ diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index bb33d38513cb..d0d278566e2e 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -62,7 +62,7 @@ JSObject::dropProperty(JSContext *cx, JSProperty *prop) JS_UNLOCK_OBJ(cx, this); } -inline jsval +inline js::Value JSObject::getSlotMT(JSContext *cx, uintN slot) { #ifdef JS_THREADSAFE @@ -72,20 +72,20 @@ JSObject::getSlotMT(JSContext *cx, uintN slot) * (obj->scope()->ownercx == cx), to avoid needlessly switching from * lock-free to lock-full scope when doing GC on a different context * from the last one to own the scope. The caller in this case is - * probably a JSClass.mark function, e.g., fun_mark, or maybe a + * probably a Class.mark function, e.g., fun_mark, or maybe a * finalizer. */ OBJ_CHECK_SLOT(this, slot); return (scope()->title.ownercx == cx) - ? this->lockedGetSlot(slot) - : js_GetSlotThreadSafe(cx, this, slot); + ? this->lockedGetSlot(slot) + : js::Valueify(js_GetSlotThreadSafe(cx, this, slot)); #else return this->lockedGetSlot(slot); #endif } inline void -JSObject::setSlotMT(JSContext *cx, uintN slot, jsval value) +JSObject::setSlotMT(JSContext *cx, uintN slot, const js::Value &value) { #ifdef JS_THREADSAFE /* Thread-safe way to set a slot. */ @@ -93,17 +93,17 @@ JSObject::setSlotMT(JSContext *cx, uintN slot, jsval value) if (scope()->title.ownercx == cx) this->lockedSetSlot(slot, value); else - js_SetSlotThreadSafe(cx, this, slot, value); + js_SetSlotThreadSafe(cx, this, slot, js::Jsvalify(value)); #else this->lockedSetSlot(slot, value); #endif } -inline jsval +inline js::Value JSObject::getReservedSlot(uintN index) const { uint32 slot = JSSLOT_START(getClass()) + index; - return (slot < numSlots()) ? getSlot(slot) : JSVAL_VOID; + return (slot < numSlots()) ? getSlot(slot) : js::UndefinedValue(); } inline bool @@ -112,7 +112,7 @@ JSObject::isPrimitive() const return isNumber() || isString() || isBoolean(); } -inline jsval +inline const js::Value & JSObject::getPrimitiveThis() const { JS_ASSERT(isPrimitive()); @@ -120,7 +120,7 @@ JSObject::getPrimitiveThis() const } inline void -JSObject::setPrimitiveThis(jsval pthis) +JSObject::setPrimitiveThis(const js::Value &pthis) { JS_ASSERT(isPrimitive()); fslots[JSSLOT_PRIMITIVE_THIS] = pthis; @@ -136,22 +136,26 @@ inline bool JSObject::isDenseArrayMinLenCapOk(bool strictAboutLength) const { JS_ASSERT(isDenseArray()); - uint32 length = uncheckedGetArrayLength(); - uint32 capacity = uncheckedGetDenseArrayCapacity(); - uint32 minLenCap = uint32(fslots[JSSLOT_DENSE_ARRAY_MINLENCAP]); // This function can be called while the LENGTH and MINLENCAP slots are // still set to JSVAL_VOID and there are no dslots (ie. the capacity is // zero). If 'strictAboutLength' is false we allow this. - return minLenCap == JS_MIN(length, capacity) || - (!strictAboutLength && minLenCap == uint32(JSVAL_VOID) && - length == uint32(JSVAL_VOID) && capacity == 0); + if (!strictAboutLength && + fslots[JSSLOT_ARRAY_LENGTH].isUndefined() && + uncheckedGetDenseArrayCapacity() == 0) { + return true; + } + + uint32 length = uncheckedGetArrayLength(); + uint32 capacity = uncheckedGetDenseArrayCapacity(); + uint32 minLenCap = fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].toPrivateUint32(); + return minLenCap == JS_MIN(length, capacity); } inline uint32 JSObject::uncheckedGetArrayLength() const { - return uint32(fslots[JSSLOT_ARRAY_LENGTH]); + return fslots[JSSLOT_ARRAY_LENGTH].toPrivateUint32(); } inline uint32 @@ -166,50 +170,50 @@ inline void JSObject::setDenseArrayLength(uint32 length) { JS_ASSERT(isDenseArray()); - fslots[JSSLOT_ARRAY_LENGTH] = length; + fslots[JSSLOT_ARRAY_LENGTH].setPrivateUint32(length); uint32 capacity = uncheckedGetDenseArrayCapacity(); - fslots[JSSLOT_DENSE_ARRAY_MINLENCAP] = JS_MIN(length, capacity); + fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].setPrivateUint32(JS_MIN(length, capacity)); } inline void JSObject::setSlowArrayLength(uint32 length) { JS_ASSERT(isSlowArray()); - fslots[JSSLOT_ARRAY_LENGTH] = length; + fslots[JSSLOT_ARRAY_LENGTH].setPrivateUint32(length); } inline uint32 JSObject::getDenseArrayCount() const { JS_ASSERT(isDenseArray()); - return uint32(fslots[JSSLOT_DENSE_ARRAY_COUNT]); + return fslots[JSSLOT_DENSE_ARRAY_COUNT].toPrivateUint32(); } inline void JSObject::setDenseArrayCount(uint32 count) { JS_ASSERT(isDenseArray()); - fslots[JSSLOT_DENSE_ARRAY_COUNT] = count; + fslots[JSSLOT_DENSE_ARRAY_COUNT].setPrivateUint32(count); } inline void JSObject::incDenseArrayCountBy(uint32 posDelta) { JS_ASSERT(isDenseArray()); - fslots[JSSLOT_DENSE_ARRAY_COUNT] += posDelta; + fslots[JSSLOT_DENSE_ARRAY_COUNT].getPrivateUint32Ref() += posDelta; } inline void JSObject::decDenseArrayCountBy(uint32 negDelta) { JS_ASSERT(isDenseArray()); - fslots[JSSLOT_DENSE_ARRAY_COUNT] -= negDelta; + fslots[JSSLOT_DENSE_ARRAY_COUNT].getPrivateUint32Ref() -= negDelta; } inline uint32 JSObject::uncheckedGetDenseArrayCapacity() const { - return dslots ? uint32(dslots[-1]) : 0; + return dslots ? dslots[-1].toPrivateUint32() : 0; } inline uint32 @@ -225,12 +229,12 @@ JSObject::setDenseArrayCapacity(uint32 capacity) { JS_ASSERT(isDenseArray()); JS_ASSERT(dslots); - dslots[-1] = capacity; + dslots[-1].setPrivateUint32(capacity); uint32 length = uncheckedGetArrayLength(); - fslots[JSSLOT_DENSE_ARRAY_MINLENCAP] = JS_MIN(length, capacity); + fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].setPrivateUint32(JS_MIN(length, capacity)); } -inline jsval +inline const js::Value & JSObject::getDenseArrayElement(uint32 i) const { JS_ASSERT(isDenseArray()); @@ -238,7 +242,7 @@ JSObject::getDenseArrayElement(uint32 i) const return dslots[i]; } -inline jsval * +inline js::Value * JSObject::addressOfDenseArrayElement(uint32 i) { JS_ASSERT(isDenseArray()); @@ -247,14 +251,14 @@ JSObject::addressOfDenseArrayElement(uint32 i) } inline void -JSObject::setDenseArrayElement(uint32 i, jsval v) +JSObject::setDenseArrayElement(uint32 i, const js::Value &v) { JS_ASSERT(isDenseArray()); JS_ASSERT(i < getDenseArrayCapacity()); dslots[i] = v; } -inline jsval * +inline js::Value * JSObject::getDenseArrayElements() const { JS_ASSERT(isDenseArray()); @@ -269,16 +273,16 @@ JSObject::freeDenseArrayElements(JSContext *cx) cx->free(dslots - 1); dslots = NULL; } - fslots[JSSLOT_DENSE_ARRAY_MINLENCAP] = 0; - JS_ASSERT(isDenseArrayMinLenCapOk()); + fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].setPrivateUint32(0); + JS_ASSERT(isDenseArrayMinLenCapOk(/* strictAboutLength = */false)); } inline void JSObject::voidDenseOnlyArraySlots() { JS_ASSERT(isDenseArray()); - fslots[JSSLOT_DENSE_ARRAY_COUNT] = JSVAL_VOID; - fslots[JSSLOT_DENSE_ARRAY_MINLENCAP] = JSVAL_VOID; + fslots[JSSLOT_DENSE_ARRAY_COUNT].setUndefined(); + fslots[JSSLOT_DENSE_ARRAY_MINLENCAP].setUndefined(); } inline void @@ -286,7 +290,7 @@ JSObject::setArgsLength(uint32 argc) { JS_ASSERT(isArguments()); JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); - fslots[JSSLOT_ARGS_LENGTH] = INT_TO_JSVAL(argc << 1); + fslots[JSSLOT_ARGS_LENGTH].setInt32(argc << 1); JS_ASSERT(!isArgsLengthOverridden()); } @@ -294,7 +298,7 @@ inline uint32 JSObject::getArgsLength() const { JS_ASSERT(isArguments()); - uint32 argc = uint32(JSVAL_TO_INT(fslots[JSSLOT_ARGS_LENGTH])) >> 1; + uint32 argc = uint32(fslots[JSSLOT_ARGS_LENGTH].toInt32()) >> 1; JS_ASSERT(argc <= JS_ARGS_LENGTH_MAX); return argc; } @@ -303,21 +307,18 @@ inline void JSObject::setArgsLengthOverridden() { JS_ASSERT(isArguments()); - jsval v = fslots[JSSLOT_ARGS_LENGTH]; - v = INT_TO_JSVAL(JSVAL_TO_INT(v) | 1); - JS_ASSERT(JSVAL_IS_INT(v)); - fslots[JSSLOT_ARGS_LENGTH] = v; + fslots[JSSLOT_ARGS_LENGTH].getInt32Ref() |= 1; } inline bool JSObject::isArgsLengthOverridden() const { JS_ASSERT(isArguments()); - jsval v = fslots[JSSLOT_ARGS_LENGTH]; - return (JSVAL_TO_INT(v) & 1) != 0; + const js::Value &v = fslots[JSSLOT_ARGS_LENGTH]; + return (v.toInt32() & 1) != 0; } -inline jsval +inline const js::Value & JSObject::getArgsCallee() const { JS_ASSERT(isArguments()); @@ -325,13 +326,13 @@ JSObject::getArgsCallee() const } inline void -JSObject::setArgsCallee(jsval callee) +JSObject::setArgsCallee(const js::Value &callee) { JS_ASSERT(isArguments()); fslots[JSSLOT_ARGS_CALLEE] = callee; } -inline jsval +inline const js::Value & JSObject::getArgsElement(uint32 i) const { JS_ASSERT(isArguments()); @@ -339,75 +340,69 @@ JSObject::getArgsElement(uint32 i) const return dslots[i]; } +inline js::Value * +JSObject::addressOfArgsElement(uint32 i) const +{ + JS_ASSERT(isArguments()); + JS_ASSERT(i < numSlots() - JS_INITIAL_NSLOTS); + return &dslots[i]; +} + inline void -JSObject::setArgsElement(uint32 i, jsval v) +JSObject::setArgsElement(uint32 i, const js::Value &v) { JS_ASSERT(isArguments()); JS_ASSERT(i < numSlots() - JS_INITIAL_NSLOTS); dslots[i] = v; } -inline jsval +inline const js::Value & JSObject::getDateLocalTime() const { JS_ASSERT(isDate()); return fslots[JSSLOT_DATE_LOCAL_TIME]; } -inline jsval * -JSObject::addressOfDateLocalTime() -{ - JS_ASSERT(isDate()); - return &fslots[JSSLOT_DATE_LOCAL_TIME]; -} - inline void -JSObject::setDateLocalTime(jsval time) +JSObject::setDateLocalTime(const js::Value &time) { JS_ASSERT(isDate()); fslots[JSSLOT_DATE_LOCAL_TIME] = time; } -inline jsval +inline const js::Value & JSObject::getDateUTCTime() const { JS_ASSERT(isDate()); return fslots[JSSLOT_DATE_UTC_TIME]; } -inline jsval * -JSObject::addressOfDateUTCTime() -{ - JS_ASSERT(isDate()); - return &fslots[JSSLOT_DATE_UTC_TIME]; -} - inline void -JSObject::setDateUTCTime(jsval time) +JSObject::setDateUTCTime(const js::Value &time) { JS_ASSERT(isDate()); fslots[JSSLOT_DATE_UTC_TIME] = time; } -inline jsval +inline const js::Value & JSObject::getRegExpLastIndex() const { JS_ASSERT(isRegExp()); return fslots[JSSLOT_REGEXP_LAST_INDEX]; } -inline jsval * -JSObject::addressOfRegExpLastIndex() +inline void +JSObject::setRegExpLastIndex(const js::Value &v) { JS_ASSERT(isRegExp()); - return &fslots[JSSLOT_REGEXP_LAST_INDEX]; + fslots[JSSLOT_REGEXP_LAST_INDEX] = v; } inline void JSObject::zeroRegExpLastIndex() { JS_ASSERT(isRegExp()); - fslots[JSSLOT_REGEXP_LAST_INDEX] = JSVAL_ZERO; + fslots[JSSLOT_REGEXP_LAST_INDEX].setInt32(0); } inline NativeIterator * @@ -426,73 +421,73 @@ inline jsval JSObject::getNamePrefix() const { JS_ASSERT(isNamespace() || isQName()); - return fslots[JSSLOT_NAME_PREFIX]; + return js::Jsvalify(fslots[JSSLOT_NAME_PREFIX]); } inline void JSObject::setNamePrefix(jsval prefix) { JS_ASSERT(isNamespace() || isQName()); - fslots[JSSLOT_NAME_PREFIX] = prefix; + fslots[JSSLOT_NAME_PREFIX] = js::Valueify(prefix); } inline jsval JSObject::getNameURI() const { JS_ASSERT(isNamespace() || isQName()); - return fslots[JSSLOT_NAME_URI]; + return js::Jsvalify(fslots[JSSLOT_NAME_URI]); } inline void JSObject::setNameURI(jsval uri) { JS_ASSERT(isNamespace() || isQName()); - fslots[JSSLOT_NAME_URI] = uri; + fslots[JSSLOT_NAME_URI] = js::Valueify(uri); } inline jsval JSObject::getNamespaceDeclared() const { JS_ASSERT(isNamespace()); - return fslots[JSSLOT_NAMESPACE_DECLARED]; + return js::Jsvalify(fslots[JSSLOT_NAMESPACE_DECLARED]); } inline void JSObject::setNamespaceDeclared(jsval decl) { JS_ASSERT(isNamespace()); - fslots[JSSLOT_NAMESPACE_DECLARED] = decl; + fslots[JSSLOT_NAMESPACE_DECLARED] = js::Valueify(decl); } inline jsval JSObject::getQNameLocalName() const { JS_ASSERT(isQName()); - return fslots[JSSLOT_QNAME_LOCAL_NAME]; + return js::Jsvalify(fslots[JSSLOT_QNAME_LOCAL_NAME]); } inline void JSObject::setQNameLocalName(jsval name) { JS_ASSERT(isQName()); - fslots[JSSLOT_QNAME_LOCAL_NAME] = name; + fslots[JSSLOT_QNAME_LOCAL_NAME] = js::Valueify(name); } inline JSObject * JSObject::getWithThis() const { - return JSVAL_TO_OBJECT(fslots[JSSLOT_WITH_THIS]); + return &fslots[JSSLOT_WITH_THIS].toObject(); } inline void JSObject::setWithThis(JSObject *thisp) { - fslots[JSSLOT_WITH_THIS] = OBJECT_TO_JSVAL(thisp); + fslots[JSSLOT_WITH_THIS].setObject(*thisp); } inline void -JSObject::initSharingEmptyScope(JSClass *clasp, JSObject *proto, JSObject *parent, - jsval privateSlotValue) +JSObject::initSharingEmptyScope(js::Class *clasp, JSObject *proto, JSObject *parent, + const js::Value &privateSlotValue) { init(clasp, proto, parent, privateSlotValue); @@ -505,7 +500,7 @@ inline void JSObject::freeSlotsArray(JSContext *cx) { JS_ASSERT(hasSlotsArray()); - JS_ASSERT(size_t(dslots[-1]) > JS_INITIAL_NSLOTS); + JS_ASSERT(dslots[-1].toPrivateUint32() > JS_INITIAL_NSLOTS); cx->free(dslots - 1); } @@ -530,20 +525,20 @@ JSObject::unbrand(JSContext *cx) namespace js { -class AutoDescriptorArray : private AutoGCRooter +class AutoPropDescArrayRooter : private AutoGCRooter { public: - AutoDescriptorArray(JSContext *cx) + AutoPropDescArrayRooter(JSContext *cx) : AutoGCRooter(cx, DESCRIPTORS), descriptors(cx) { } - PropertyDescriptor *append() { - if (!descriptors.append(PropertyDescriptor())) + PropDesc *append() { + if (!descriptors.append(PropDesc())) return NULL; return &descriptors.back(); } - PropertyDescriptor& operator[](size_t i) { + PropDesc& operator[](size_t i) { JS_ASSERT(i < descriptors.length()); return descriptors[i]; } @@ -551,20 +546,20 @@ class AutoDescriptorArray : private AutoGCRooter friend void AutoGCRooter::trace(JSTracer *trc); private: - PropertyDescriptorArray descriptors; + PropDescArray descriptors; }; -class AutoDescriptor : private AutoGCRooter, public JSPropertyDescriptor +class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescriptor { public: - AutoDescriptor(JSContext *cx) : AutoGCRooter(cx, DESCRIPTOR) { + AutoPropertyDescriptorRooter(JSContext *cx) : AutoGCRooter(cx, DESCRIPTOR) { obj = NULL; attrs = 0; - getter = setter = (JSPropertyOp) NULL; - value = JSVAL_VOID; + getter = setter = (PropertyOp) NULL; + value.setUndefined(); } - AutoDescriptor(JSContext *cx, JSPropertyDescriptor *desc) : AutoGCRooter(cx, DESCRIPTOR) { + AutoPropertyDescriptorRooter(JSContext *cx, PropertyDescriptor *desc) : AutoGCRooter(cx, DESCRIPTOR) { obj = desc->obj; attrs = desc->attrs; getter = desc->getter; @@ -576,7 +571,7 @@ class AutoDescriptor : private AutoGCRooter, public JSPropertyDescriptor }; static inline bool -InitScopeForObject(JSContext* cx, JSObject* obj, JSClass *clasp, JSObject* proto, JSObjectOps* ops) +InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, JSObject* proto, JSObjectOps* ops) { JS_ASSERT(ops->isNative()); JS_ASSERT(proto == obj->getProto()); @@ -610,7 +605,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSClass *clasp, JSObject* proto scope->freeslot = freeslot; #ifdef DEBUG if (freeslot < obj->numSlots()) - obj->setSlot(freeslot, JSVAL_VOID); + obj->setSlot(freeslot, UndefinedValue()); #endif } @@ -630,7 +625,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, JSClass *clasp, JSObject* proto * prototype as proto, and its parent global as parent. */ static inline JSObject * -NewNativeClassInstance(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) +NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent) { JS_ASSERT(proto); JS_ASSERT(proto->isNative()); @@ -667,7 +662,7 @@ NewNativeClassInstance(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject * builtin. See bug 481444. */ if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) { - AutoValueRooter tvr(cx, obj); + AutoObjectRooter tvr(cx, obj); AutoKeepAtoms keep(cx->runtime); cx->debugHooks->objectHook(cx, obj, JS_TRUE, cx->debugHooks->objectHookData); @@ -682,16 +677,16 @@ NewNativeClassInstance(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject bool FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject **protop, - JSClass *clasp); + Class *clasp); /* * Helper used to create Boolean, Date, RegExp, etc. instances of built-in - * classes with class prototypes of the same JSClass. See, e.g., jsdate.cpp, + * classes with class prototypes of the same Class. See, e.g., jsdate.cpp, * jsregexp.cpp, and js_PrimitiveToObject in jsobj.cpp. Use this to get the * right default proto and parent for clasp in cx. */ static inline JSObject * -NewBuiltinClassInstance(JSContext *cx, JSClass *clasp) +NewBuiltinClassInstance(JSContext *cx, Class *clasp) { VOUCH_DOES_NOT_REQUIRE_STACK(); @@ -710,10 +705,10 @@ NewBuiltinClassInstance(JSContext *cx, JSClass *clasp) } JS_ASSERT(global->getClass()->flags & JSCLASS_IS_GLOBAL); - jsval v = global->getReservedSlot(JSProto_LIMIT + protoKey); + const Value &v = global->getReservedSlot(JSProto_LIMIT + protoKey); JSObject *proto; - if (!JSVAL_IS_PRIMITIVE(v)) { - proto = JSVAL_TO_OBJECT(v); + if (v.isObject()) { + proto = &v.toObject(); JS_ASSERT(proto->getParent() == global); } else { if (!FindClassPrototype(cx, global, protoKey, &proto, clasp)) @@ -729,7 +724,7 @@ NewBuiltinClassInstance(JSContext *cx, JSClass *clasp) * and NewObject can be used to construct full-sized JSFunction instances. */ static inline JSObject * -NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) +NewObjectWithGivenProto(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent) { DTrace::ObjectCreationScope objectCreationScope(cx, cx->fp, clasp); @@ -782,7 +777,7 @@ NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject * builtin. See bug 481444. */ if (cx->debugHooks->objectHook && !JS_ON_TRACE(cx)) { - AutoValueRooter tvr(cx, obj); + AutoObjectRooter tvr(cx, obj); AutoKeepAtoms keep(cx->runtime); cx->debugHooks->objectHook(cx, obj, JS_TRUE, cx->debugHooks->objectHookData); @@ -795,7 +790,7 @@ out: } static inline JSProtoKey -GetClassProtoKey(JSClass *clasp) +GetClassProtoKey(js::Class *clasp) { JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp); if (key != JSProto_Null) @@ -815,7 +810,7 @@ GetClassProtoKey(JSClass *clasp) * Default parent is null to proto's parent (null if proto is null too). */ static inline JSObject * -NewObject(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent) +NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent) { /* Bootstrap the ur-object, and make it the default prototype object. */ if (!proto) { diff --git a/js/src/json.cpp b/js/src/json.cpp index faaf9b46aeef..61821a5da128 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -86,7 +86,7 @@ struct JSONParser JSONParserState *statep; JSONParserState stateStack[JSON_MAX_DEPTH]; - jsval *rootVal; + Value *rootVal; JSObject *objectStack; js::Vector objectKey; js::Vector buffer; @@ -96,22 +96,22 @@ struct JSONParser #pragma warning(pop) #endif -JSClass js_JSONClass = { +Class js_JSONClass = { js_JSON_str, JSCLASS_HAS_CACHED_PROTO(JSProto_JSON), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; JSBool -js_json_parse(JSContext *cx, uintN argc, jsval *vp) +js_json_parse(JSContext *cx, uintN argc, Value *vp) { JSString *s = NULL; - jsval *argv = vp + 2; - AutoValueRooter reviver(cx, JSVAL_NULL); + Value *argv = vp + 2; + AutoValueRooter reviver(cx); - if (!JS_ConvertArguments(cx, argc, argv, "S / v", &s, reviver.addr())) + if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "S / v", &s, reviver.addr())) return JS_FALSE; JSONParser *jp = js_BeginJSONParse(cx, vp); @@ -128,14 +128,14 @@ js_json_parse(JSContext *cx, uintN argc, jsval *vp) } JSBool -js_json_stringify(JSContext *cx, uintN argc, jsval *vp) +js_json_stringify(JSContext *cx, uintN argc, Value *vp) { - jsval *argv = vp + 2; - AutoValueRooter space(cx, JSVAL_NULL); + Value *argv = vp + 2; + AutoValueRooter space(cx); AutoObjectRooter replacer(cx); // Must throw an Error if there isn't a first arg - if (!JS_ConvertArguments(cx, argc, argv, "v / o v", vp, replacer.addr(), space.addr())) + if (!JS_ConvertArguments(cx, argc, Jsvalify(argv), "v / o v", vp, replacer.addr(), space.addr())) return JS_FALSE; JSCharBuffer cb(cx); @@ -150,22 +150,22 @@ js_json_stringify(JSContext *cx, uintN argc, jsval *vp) JSString *str = js_NewStringFromCharBuffer(cx, cb); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); } else { - *vp = JSVAL_VOID; + vp->setUndefined(); } return JS_TRUE; } JSBool -js_TryJSON(JSContext *cx, jsval *vp) +js_TryJSON(JSContext *cx, Value *vp) { // Checks whether the return value implements toJSON() JSBool ok = JS_TRUE; - if (!JSVAL_IS_PRIMITIVE(*vp)) { - JSObject *obj = JSVAL_TO_OBJECT(*vp); + if (vp->isObject()) { + JSObject *obj = &vp->toObject(); ok = js_TryMethod(cx, obj, cx->runtime->atomState.toJSONAtom, 0, NULL, vp); } @@ -230,9 +230,9 @@ public: }; static JSBool CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder, - StringifyContext *scx, jsval *vp); + StringifyContext *scx, Value *vp); static JSBool Str(JSContext *cx, jsid id, JSObject *holder, - StringifyContext *scx, jsval *vp, bool callReplacer = true); + StringifyContext *scx, Value *vp, bool callReplacer = true); static JSBool WriteIndent(JSContext *cx, StringifyContext *scx, uint32 limit) @@ -250,47 +250,48 @@ WriteIndent(JSContext *cx, StringifyContext *scx, uint32 limit) } static JSBool -JO(JSContext *cx, jsval *vp, StringifyContext *scx) +JO(JSContext *cx, Value *vp, StringifyContext *scx) { - JSObject *obj = JSVAL_TO_OBJECT(*vp); + JSObject *obj = &vp->toObject(); if (!scx->cb.append('{')) return JS_FALSE; - jsval vec[4] = {JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL}; + Value vec[3] = { NullValue(), NullValue(), NullValue() }; AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vec), vec); - jsval& outputValue = vec[0]; - jsval& whitelistElement = vec[1]; - jsid& id = vec[2]; + Value& outputValue = vec[0]; + Value& whitelistElement = vec[1]; + AutoIdRooter idr(cx); + jsid& id = *idr.addr(); - jsval *keySource = vp; + Value *keySource = vp; bool usingWhitelist = false; // if the replacer is an array, we use the keys from it if (scx->replacer && JS_IsArrayObject(cx, scx->replacer)) { usingWhitelist = true; - vec[3] = OBJECT_TO_JSVAL(scx->replacer); - keySource = &vec[3]; + vec[2].setObject(*scx->replacer); + keySource = &vec[2]; } JSBool memberWritten = JS_FALSE; - AutoIdArray ida(cx, JS_Enumerate(cx, JSVAL_TO_OBJECT(*keySource))); + AutoIdArray ida(cx, JS_Enumerate(cx, &keySource->toObject())); if (!ida) return JS_FALSE; for (jsint i = 0, len = ida.length(); i < len; i++) { - outputValue = JSVAL_VOID; + outputValue.setUndefined(); if (!usingWhitelist) { - if (!js_ValueToStringId(cx, ida[i], &id)) + if (!js_ValueToStringId(cx, IdToValue(ida[i]), &id)) return JS_FALSE; } else { // skip non-index properties jsuint index = 0; - if (!js_IdIsIndex(ID_TO_VALUE(ida[i]), &index)) + if (!js_IdIsIndex(ida[i], &index)) continue; - if (!scx->replacer->getProperty(cx, ID_TO_VALUE(ida[i]), &whitelistElement)) + if (!scx->replacer->getProperty(cx, ida[i], &whitelistElement)) return JS_FALSE; if (!js_ValueToStringId(cx, whitelistElement, &id)) @@ -300,12 +301,12 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) // We should have a string id by this point. Either from // JS_Enumerate's id array, or by converting an element // of the whitelist. - JS_ASSERT(JSVAL_IS_STRING(ID_TO_VALUE(id))); + JS_ASSERT(JSID_IS_ATOM(id)); - if (!JS_GetPropertyById(cx, obj, id, &outputValue)) + if (!JS_GetPropertyById(cx, obj, id, Jsvalify(&outputValue))) return JS_FALSE; - if (JSVAL_IS_OBJECT(outputValue) && !js_TryJSON(cx, &outputValue)) + if (outputValue.isObjectOrNull() && !js_TryJSON(cx, &outputValue)) return JS_FALSE; // call this here, so we don't write out keys if the replacer function @@ -313,10 +314,10 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) if (!CallReplacerFunction(cx, id, obj, scx, &outputValue)) return JS_FALSE; - JSType type = JS_TypeOfValue(cx, outputValue); + JSType type = JS_TypeOfValue(cx, Jsvalify(outputValue)); // elide undefined values and functions and XML - if (outputValue == JSVAL_VOID || type == JSTYPE_FUNCTION || type == JSTYPE_XML) + if (outputValue.isUndefined() || type == JSTYPE_FUNCTION || type == JSTYPE_XML) continue; // output a comma unless this is the first member to write @@ -328,7 +329,7 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) return JS_FALSE; // Be careful below, this string is weakly rooted - JSString *s = js_ValueToString(cx, ID_TO_VALUE(id)); + JSString *s = js_ValueToString(cx, IdToValue(id)); if (!s) return JS_FALSE; @@ -349,9 +350,9 @@ JO(JSContext *cx, jsval *vp, StringifyContext *scx) } static JSBool -JA(JSContext *cx, jsval *vp, StringifyContext *scx) +JA(JSContext *cx, Value *vp, StringifyContext *scx) { - JSObject *obj = JSVAL_TO_OBJECT(*vp); + JSObject *obj = &vp->toObject(); if (!scx->cb.append('[')) return JS_FALSE; @@ -363,7 +364,7 @@ JA(JSContext *cx, jsval *vp, StringifyContext *scx) if (length != 0 && !WriteIndent(cx, scx, scx->depth)) return JS_FALSE; - AutoValueRooter outputValue(cx, JSVAL_NULL); + AutoValueRooter outputValue(cx); jsid id; jsuint i; @@ -376,7 +377,7 @@ JA(JSContext *cx, jsval *vp, StringifyContext *scx) if (!Str(cx, id, obj, scx, outputValue.addr())) return JS_FALSE; - if (outputValue.value() == JSVAL_VOID) { + if (outputValue.value().isUndefined()) { if (!js_AppendLiteral(scx->cb, "null")) return JS_FALSE; } @@ -396,60 +397,63 @@ JA(JSContext *cx, jsval *vp, StringifyContext *scx) } static JSBool -CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp) +CallReplacerFunction(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, Value *vp) { if (scx->replacer && scx->replacer->isCallable()) { - jsval vec[2] = {ID_TO_VALUE(id), *vp}; - if (!JS_CallFunctionValue(cx, holder, OBJECT_TO_JSVAL(scx->replacer), 2, vec, vp)) + Value vec[2] = { IdToValue(id), *vp}; + if (!JS_CallFunctionValue(cx, holder, OBJECT_TO_JSVAL(scx->replacer), + 2, Jsvalify(vec), Jsvalify(vp))) { return JS_FALSE; + } } return JS_TRUE; } static JSBool -Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp, bool callReplacer) +Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, Value *vp, bool callReplacer) { JS_CHECK_RECURSION(cx, return JS_FALSE); - if (!JSVAL_IS_PRIMITIVE(*vp) && !js_TryJSON(cx, vp)) + if (vp->isObject() && !js_TryJSON(cx, vp)) return JS_FALSE; if (callReplacer && !CallReplacerFunction(cx, id, holder, scx, vp)) return JS_FALSE; // catches string and number objects with no toJSON - if (!JSVAL_IS_PRIMITIVE(*vp)) { - JSClass *clasp = JSVAL_TO_OBJECT(*vp)->getClass(); + if (vp->isObject()) { + JSObject *obj = &vp->toObject(); + Class *clasp = obj->getClass(); if (clasp == &js_StringClass || clasp == &js_NumberClass) - *vp = JSVAL_TO_OBJECT(*vp)->getPrimitiveThis(); + *vp = obj->getPrimitiveThis(); } - if (JSVAL_IS_STRING(*vp)) { + if (vp->isString()) { const jschar *chars; size_t length; - JSVAL_TO_STRING(*vp)->getCharsAndLength(chars, length); + vp->toString()->getCharsAndLength(chars, length); return write_string(cx, scx->cb, chars, length); } - if (JSVAL_IS_NULL(*vp)) { + if (vp->isNull()) { return js_AppendLiteral(scx->cb, "null"); } - if (JSVAL_IS_BOOLEAN(*vp)) { - return JSVAL_TO_BOOLEAN(*vp) ? js_AppendLiteral(scx->cb, "true") - : js_AppendLiteral(scx->cb, "false"); + if (vp->isBoolean()) { + return vp->toBoolean() ? js_AppendLiteral(scx->cb, "true") + : js_AppendLiteral(scx->cb, "false"); } - if (JSVAL_IS_NUMBER(*vp)) { - if (JSVAL_IS_DOUBLE(*vp)) { - jsdouble d = *JSVAL_TO_DOUBLE(*vp); + if (vp->isNumber()) { + if (vp->isDouble()) { + jsdouble d = vp->toDouble(); if (!JSDOUBLE_IS_FINITE(d)) return js_AppendLiteral(scx->cb, "null"); } char numBuf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr; - jsdouble d = JSVAL_IS_INT(*vp) ? jsdouble(JSVAL_TO_INT(*vp)) : *JSVAL_TO_DOUBLE(*vp); + jsdouble d = vp->isInt32() ? jsdouble(vp->toInt32()) : vp->toDouble(); numStr = js_dtostr(JS_THREAD_DATA(cx)->dtoaState, numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d); if (!numStr) { @@ -465,43 +469,43 @@ Str(JSContext *cx, jsid id, JSObject *holder, StringifyContext *scx, jsval *vp, return scx->cb.append(dstr, dbufSize); } - if (JSVAL_IS_OBJECT(*vp) && !VALUE_IS_FUNCTION(cx, *vp) && !VALUE_IS_XML(*vp)) { + if (vp->isObject() && !IsFunctionObject(*vp) && !IsXML(*vp)) { JSBool ok; scx->depth++; - ok = (JS_IsArrayObject(cx, JSVAL_TO_OBJECT(*vp)) ? JA : JO)(cx, vp, scx); + ok = (JS_IsArrayObject(cx, &vp->toObject()) ? JA : JO)(cx, vp, scx); scx->depth--; return ok; } - *vp = JSVAL_VOID; + vp->setUndefined(); return JS_TRUE; } static JSBool -InitializeGap(JSContext *cx, jsval space, JSCharBuffer &cb) +InitializeGap(JSContext *cx, const Value &space, JSCharBuffer &cb) { AutoValueRooter gap(cx, space); - if (!JSVAL_IS_PRIMITIVE(space)) { - JSObject *obj = JSVAL_TO_OBJECT(space); - JSClass *clasp = obj->getClass(); + if (space.isObject()) { + JSObject *obj = &space.toObject(); + Class *clasp = obj->getClass(); if (clasp == &js_NumberClass || clasp == &js_StringClass) *gap.addr() = obj->getPrimitiveThis(); } - if (JSVAL_IS_STRING(gap.value())) { + if (gap.value().isString()) { if (!js_ValueToCharBuffer(cx, gap.value(), cb)) return JS_FALSE; if (cb.length() > 10) cb.resize(10); } - if (JSVAL_IS_NUMBER(gap.value())) { - jsdouble d = JSVAL_IS_INT(gap.value()) - ? JSVAL_TO_INT(gap.value()) - : js_DoubleToInteger(*JSVAL_TO_DOUBLE(gap.value())); + if (gap.value().isNumber()) { + jsdouble d = gap.value().isInt32() + ? gap.value().toInt32() + : js_DoubleToInteger(gap.value().toDouble()); d = JS_MIN(10, d); if (d >= 1 && !cb.appendN(' ', uint32(d))) return JS_FALSE; @@ -511,7 +515,7 @@ InitializeGap(JSContext *cx, jsval space, JSCharBuffer &cb) } JSBool -js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space, +js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, const Value &space, JSCharBuffer &cb) { StringifyContext scx(cx, cb, replacer); @@ -541,7 +545,7 @@ static JSBool HandleData(JSContext *cx, JSONParser *jp, JSONDataType type); static JSBool PopState(JSContext *cx, JSONParser *jp); static bool -Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) +Walk(JSContext *cx, jsid id, JSObject *holder, const Value &reviver, Value *vp) { JS_CHECK_RECURSION(cx, return false); @@ -550,8 +554,8 @@ Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) JSObject *obj; - if (!JSVAL_IS_PRIMITIVE(*vp) && !(obj = JSVAL_TO_OBJECT(*vp))->isCallable()) { - AutoValueRooter propValue(cx, JSVAL_NULL); + if (vp->isObject() && !(obj = &vp->toObject())->isCallable()) { + AutoValueRooter propValue(cx); if(obj->isArray()) { jsuint length = 0; @@ -578,7 +582,7 @@ Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) jsid idName = ida[i]; if (!Walk(cx, idName, obj, reviver, propValue.addr())) return false; - if (propValue.value() == JSVAL_VOID) { + if (propValue.value().isUndefined()) { if (!js_DeleteProperty(cx, obj, idName, propValue.addr())) return false; } else { @@ -592,29 +596,31 @@ Walk(JSContext *cx, jsid id, JSObject *holder, jsval reviver, jsval *vp) } // return reviver.call(holder, key, value); - jsval value = *vp; - JSString *key = js_ValueToString(cx, ID_TO_VALUE(id)); + const Value &value = *vp; + JSString *key = js_ValueToString(cx, IdToValue(id)); if (!key) return false; - jsval vec[2] = {STRING_TO_JSVAL(key), value}; - jsval reviverResult; - if (!JS_CallFunctionValue(cx, holder, reviver, 2, vec, &reviverResult)) + Value vec[2] = { StringValue(key), value }; + Value reviverResult; + if (!JS_CallFunctionValue(cx, holder, Jsvalify(reviver), + 2, Jsvalify(vec), Jsvalify(&reviverResult))) { return false; + } *vp = reviverResult; return true; } static bool -Revive(JSContext *cx, jsval reviver, jsval *vp) +Revive(JSContext *cx, const Value &reviver, Value *vp) { JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass); if (!obj) return false; - AutoValueRooter tvr(cx, obj); + AutoObjectRooter tvr(cx, obj); if (!obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.emptyAtom), *vp, NULL, NULL, JSPROP_ENUMERATE)) { return false; @@ -624,7 +630,7 @@ Revive(JSContext *cx, jsval reviver, jsval *vp) } JSONParser * -js_BeginJSONParse(JSContext *cx, jsval *rootVal) +js_BeginJSONParse(JSContext *cx, Value *rootVal) { if (!cx) return NULL; @@ -648,12 +654,12 @@ js_BeginJSONParse(JSContext *cx, jsval *rootVal) return jp; bad: - js_FinishJSONParse(cx, jp, JSVAL_NULL); + js_FinishJSONParse(cx, jp, NullValue()); return NULL; } bool -js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) +js_FinishJSONParse(JSContext *cx, JSONParser *jp, const Value &reviver) { if (!jp) return true; @@ -678,7 +684,7 @@ js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) js_RemoveRoot(cx->runtime, &jp->objectStack); bool ok = *jp->statep == JSON_PARSE_STATE_FINISHED; - jsval *vp = jp->rootVal; + Value *vp = jp->rootVal; cx->destroy(jp); @@ -690,7 +696,7 @@ js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver) return false; } - if (!JSVAL_IS_PRIMITIVE(reviver) && JSVAL_TO_OBJECT(reviver)->isCallable()) + if (reviver.isObject() && reviver.toObject().isCallable()) ok = Revive(cx, reviver, vp); return ok; @@ -734,7 +740,7 @@ PopState(JSContext *cx, JSONParser *jp) } static JSBool -PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, jsval value) +PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, const Value &value) { JSBool ok; if (parent->isArray()) { @@ -748,7 +754,7 @@ PushValue(JSContext *cx, JSONParser *jp, JSObject *parent, jsval value) } } else { ok = JS_DefineUCProperty(cx, parent, jp->objectKey.begin(), - jp->objectKey.length(), value, + jp->objectKey.length(), Jsvalify(value), NULL, NULL, JSPROP_ENUMERATE); jp->objectKey.clear(); } @@ -767,8 +773,8 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj) return JS_FALSE; } - jsval v = OBJECT_TO_JSVAL(obj); - AutoValueRooter tvr(cx, v); + AutoObjectRooter tvr(cx, obj); + Value v = ObjectOrNullValue(obj); // Check if this is the root object if (len == 0) { @@ -781,12 +787,11 @@ PushObject(JSContext *cx, JSONParser *jp, JSObject *obj) return JS_TRUE; } - jsval p; + Value p; if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &p)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_OBJECT(p)); - JSObject *parent = JSVAL_TO_OBJECT(p); + JSObject *parent = &p.toObject(); if (!PushValue(cx, jp, parent, v)) return JS_FALSE; @@ -839,7 +844,7 @@ CloseArray(JSContext *cx, JSONParser *jp) } static JSBool -PushPrimitive(JSContext *cx, JSONParser *jp, jsval value) +PushPrimitive(JSContext *cx, JSONParser *jp, const Value &value) { AutoValueRooter tvr(cx, value); @@ -848,12 +853,11 @@ PushPrimitive(JSContext *cx, JSONParser *jp, jsval value) return JS_FALSE; if (len > 0) { - jsval o; + Value o; if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &o)) return JS_FALSE; - JS_ASSERT(!JSVAL_IS_PRIMITIVE(o)); - return PushValue(cx, jp, JSVAL_TO_OBJECT(o), value); + return PushValue(cx, jp, &o.toObject(), value); } // root value must be primitive @@ -874,11 +878,7 @@ HandleNumber(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) return JS_FALSE; } - jsval numVal; - if (!JS_NewNumberValue(cx, val, &numVal)) - return JS_FALSE; - - return PushPrimitive(cx, jp, numVal); + return PushPrimitive(cx, jp, DoubleValue(val)); } static JSBool @@ -888,13 +888,13 @@ HandleString(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) if (!str) return JS_FALSE; - return PushPrimitive(cx, jp, STRING_TO_JSVAL(str)); + return PushPrimitive(cx, jp, StringValue(str)); } static JSBool HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) { - jsval keyword; + Value keyword; TokenKind tt = js_CheckKeyword(buf, len); if (tt != TOK_PRIMARY) { // bad keyword @@ -903,11 +903,11 @@ HandleKeyword(JSContext *cx, JSONParser *jp, const jschar *buf, uint32 len) } if (buf[0] == 'n') { - keyword = JSVAL_NULL; + keyword.setNull(); } else if (buf[0] == 't') { - keyword = JSVAL_TRUE; + keyword.setBoolean(true); } else if (buf[0] == 'f') { - keyword = JSVAL_FALSE; + keyword.setBoolean(false); } else { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_JSON_BAD_PARSE); return JS_FALSE; @@ -1187,9 +1187,9 @@ js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len #if JS_HAS_TOSOURCE static JSBool -json_toSource(JSContext *cx, uintN argc, jsval *vp) +json_toSource(JSContext *cx, uintN argc, Value *vp) { - *vp = ATOM_KEY(CLASS_ATOM(cx, JSON)); + vp->setString(ATOM_TO_STRING(CLASS_ATOM(cx, JSON))); return JS_TRUE; } #endif @@ -1208,7 +1208,7 @@ js_InitJSONClass(JSContext *cx, JSObject *obj) { JSObject *JSON; - JSON = JS_NewObject(cx, &js_JSONClass, NULL, obj); + JSON = NewObject(cx, &js_JSONClass, NULL, obj); if (!JSON) return NULL; if (!JS_DefineProperty(cx, obj, js_JSON_str, OBJECT_TO_JSVAL(JSON), diff --git a/js/src/json.h b/js/src/json.h index f6030f2f61fb..0e6a996691f0 100644 --- a/js/src/json.h +++ b/js/src/json.h @@ -45,18 +45,16 @@ #define JSON_MAX_DEPTH 2048 #define JSON_PARSER_BUFSIZE 1024 -JS_BEGIN_EXTERN_C - -extern JSClass js_JSONClass; +extern js::Class js_JSONClass; extern JSObject * js_InitJSONClass(JSContext *cx, JSObject *obj); extern JSBool -js_Stringify(JSContext *cx, jsval *vp, JSObject *replacer, jsval space, - JSCharBuffer &cb); +js_Stringify(JSContext *cx, js::Value *vp, JSObject *replacer, + const js::Value &space, JSCharBuffer &cb); -extern JSBool js_TryJSON(JSContext *cx, jsval *vp); +extern JSBool js_TryJSON(JSContext *cx, js::Value *vp); /* JSON parsing states; most permit leading whitespace. */ enum JSONParserState { @@ -113,14 +111,12 @@ enum JSONDataType { struct JSONParser; extern JSONParser * -js_BeginJSONParse(JSContext *cx, jsval *rootVal); +js_BeginJSONParse(JSContext *cx, js::Value *rootVal); extern JSBool js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len); extern bool -js_FinishJSONParse(JSContext *cx, JSONParser *jp, jsval reviver); - -JS_END_EXTERN_C +js_FinishJSONParse(JSContext *cx, JSONParser *jp, const js::Value &reviver); #endif /* json_h___ */ diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index ee045c9fe310..2e3806edb866 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -294,7 +294,7 @@ ToDisassemblySource(JSContext *cx, jsval v) { if (!JSVAL_IS_PRIMITIVE(v)) { JSObject *obj = JSVAL_TO_OBJECT(v); - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (clasp == &js_BlockClass) { char *source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj)); @@ -331,11 +331,11 @@ ToDisassemblySource(JSContext *cx, jsval v) AutoValueRooter tvr(cx); if (!js_regexp_toString(cx, obj, tvr.addr())) return NULL; - return js_GetStringBytes(cx, JSVAL_TO_STRING(tvr.value())); + return js_GetStringBytes(cx, JSVAL_TO_STRING(Jsvalify(tvr.value()))); } } - return js_ValueToPrintableSource(cx, v); + return js_ValueToPrintableSource(cx, Valueify(v)); } JS_FRIEND_API(uintN) @@ -388,8 +388,12 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, case JOF_REGEXP: index = js_GetIndexFromBytecode(cx, script, pc, 0); if (type == JOF_ATOM) { - JS_GET_SCRIPT_ATOM(script, pc, index, atom); - v = ATOM_KEY(atom); + if (op == JSOP_DOUBLE) { + v = Jsvalify(script->getConst(index)); + } else { + JS_GET_SCRIPT_ATOM(script, pc, index, atom); + v = ATOM_TO_JSVAL(atom); + } } else { if (type == JOF_OBJECT) obj = script->getObject(index); @@ -452,12 +456,12 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, pc2 += UINT16_LEN; fprintf(fp, " offset %d npairs %u", (intN) off, (uintN) npairs); while (npairs) { - JS_GET_SCRIPT_ATOM(script, pc, GET_INDEX(pc2), atom); + uint16 constIndex = GET_INDEX(pc2); pc2 += INDEX_LEN; off = GetJumpOffset(pc, pc2); pc2 += jmplen; - bytes = ToDisassemblySource(cx, ATOM_KEY(atom)); + bytes = ToDisassemblySource(cx, Jsvalify(script->getConst(constIndex))); if (!bytes) return 0; fprintf(fp, "\n\t%s: %d", bytes, (intN) off); @@ -481,7 +485,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, index = js_GetIndexFromBytecode(cx, script, pc, SLOTNO_LEN); if (type == JOF_SLOTATOM) { JS_GET_SCRIPT_ATOM(script, pc, index, atom); - v = ATOM_KEY(atom); + v = ATOM_TO_JSVAL(atom); } else { obj = script->getObject(index); v = OBJECT_TO_JSVAL(obj); @@ -1112,7 +1116,7 @@ SprintDoubleValue(Sprinter *sp, jsval v, JSOp *opp) char *s, buf[DTOSTR_STANDARD_BUFFER_SIZE]; JS_ASSERT(JSVAL_IS_DOUBLE(v)); - d = *JSVAL_TO_DOUBLE(v); + d = JSVAL_TO_DOUBLE(v); if (JSDOUBLE_IS_NEGZERO(d)) { todo = SprintCString(sp, "-0"); *opp = JSOP_NEG; @@ -1222,7 +1226,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength, todo = SprintDoubleValue(&ss->sprinter, key, &junk); str = NULL; } else { - str = js_ValueToString(cx, key); + str = js_ValueToString(cx, Valueify(key)); if (!str) return JS_FALSE; } @@ -1575,8 +1579,7 @@ DecompileDestructuring(SprintStack *ss, jsbytecode *pc, jsbytecode *endpc) case JSOP_INT32: d = i = GET_INT32(pc); goto do_getelem; case JSOP_DOUBLE: - GET_DOUBLE_FROM_BYTECODE(jp->script, pc, 0, atom); - d = *ATOM_TO_DOUBLE(atom); + GET_DOUBLE_FROM_BYTECODE(jp->script, pc, 0, d); LOCAL_ASSERT(JSDOUBLE_IS_FINITE(d) && !JSDOUBLE_IS_NEGZERO(d)); i = (jsint)d; @@ -3874,7 +3877,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) do_getarg_prop: atom = GetArgOrVarAtom(ss->printer, i); LOCAL_ASSERT(atom); - LOCAL_ASSERT(ATOM_IS_STRING(atom)); lval = QuoteString(&ss->sprinter, ATOM_TO_STRING(atom), 0); if (!lval || !PushOff(ss, STR2OFF(&ss->sprinter, lval), op)) return NULL; @@ -4034,11 +4036,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) break; case JSOP_DOUBLE: - GET_DOUBLE_FROM_BYTECODE(jp->script, pc, 0, atom); - val = ATOM_KEY(atom); - LOCAL_ASSERT(JSVAL_IS_DOUBLE(val)); + { + double d; + GET_DOUBLE_FROM_BYTECODE(jp->script, pc, 0, d); + val = DOUBLE_TO_JSVAL(d); todo = SprintDoubleValue(&ss->sprinter, val, &saveop); break; + } case JSOP_STRING: LOAD_ATOM(0); @@ -4212,7 +4216,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) case JSOP_REGEXP: GET_REGEXP_FROM_BYTECODE(jp->script, pc, 0, obj); do_regexp: - if (!js_regexp_toString(cx, obj, &val)) + if (!js_regexp_toString(cx, obj, Valueify(&val))) return NULL; str = JSVAL_TO_STRING(val); goto sprint_string; @@ -4268,7 +4272,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) if (tmp) { VOUCH_DOES_NOT_REQUIRE_STACK(); ok = js_MergeSort(table, (size_t)j, sizeof(TableEntry), - CompareOffsets, NULL, tmp); + CompareOffsets, NULL, tmp, + JS_SORTING_GENERIC); cx->free(tmp); } else { ok = JS_FALSE; @@ -4316,11 +4321,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) } else { table[k].label = NULL; } - JS_GET_SCRIPT_ATOM(jp->script, pc, GET_INDEX(pc2), atom); + uint16 constIndex = GET_INDEX(pc2); pc2 += INDEX_LEN; off2 = GetJumpOffset(pc, pc2); pc2 += jmplen; - table[k].key = ATOM_KEY(atom); + table[k].key = Jsvalify(jp->script->getConst(constIndex)); table[k].offset = off2; } @@ -5110,13 +5115,15 @@ js_DecompileFunction(JSPrinter *jp) } char * -js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, +js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v_in, JSString *fallback) { JSStackFrame *fp; jsbytecode *pc; JSScript *script; + Value v = Valueify(v_in); + JS_ASSERT(spindex < 0 || spindex == JSDVG_IGNORE_STACK || spindex == JSDVG_SEARCH_STACK); @@ -5163,8 +5170,8 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, * calculated value matching v under assumption that it is * it that caused exception, see bug 328664. */ - jsval *stackBase = StackBase(fp); - jsval *sp = i.sp(); + Value *stackBase = fp->base(); + Value *sp = i.sp(); do { if (sp == stackBase) { pcdepth = -1; diff --git a/js/src/jsopcode.h b/js/src/jsopcode.h index ce4db34e1718..85ac38746850 100644 --- a/js/src/jsopcode.h +++ b/js/src/jsopcode.h @@ -47,6 +47,10 @@ #include "jspubtd.h" #include "jsutil.h" +#ifdef __cplusplus +# include "jsvalue.h" +#endif + JS_BEGIN_EXTERN_C /* @@ -100,7 +104,7 @@ typedef enum JSOp { #define JOF_INCDEC (3U<<10) /* increment or decrement opcode */ #define JOF_POST (1U<<12) /* postorder increment or decrement */ #define JOF_FOR (1U<<13) /* for-in property op (akin to JOF_SET) */ -#define JOF_ASSIGNING JOF_SET /* hint for JSClass.resolve, used for ops +#define JOF_ASSIGNING JOF_SET /* hint for Class.resolve, used for ops that do simplex assignment */ #define JOF_DETECTING (1U<<14) /* object detection for JSNewResolveOp */ #define JOF_BACKPATCH (1U<<15) /* backpatch placeholder during codegen */ @@ -332,14 +336,13 @@ js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc, * Unfortunately some bytecodes such as JSOP_LOOKUPSWITCH have immediates that * might be string or double atoms. Those opcodes cannot be used from imacros. * See the assertions in the JSOP_DOUBLE and JSOP_LOOKUPSWTICH* opcode cases in - * jsops.cpp. + * jsinterp.cpp. */ -#define GET_DOUBLE_FROM_BYTECODE(script, pc, pcoff, atom) \ +#define GET_DOUBLE_FROM_BYTECODE(script, pc, pcoff, dbl) \ JS_BEGIN_MACRO \ uintN index_ = js_GetIndexFromBytecode(cx, (script), (pc), (pcoff)); \ - JS_ASSERT(index_ < (script)->atomMap.length); \ - (atom) = (script)->atomMap.vector[index_]; \ - JS_ASSERT(ATOM_IS_DOUBLE(atom)); \ + JS_ASSERT(index_ < (script)->consts()->length); \ + (dbl) = (script)->getConst(index_).toDouble(); \ JS_END_MACRO #define GET_OBJECT_FROM_BYTECODE(script, pc, pcoff, obj) \ @@ -463,6 +466,19 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v, #define JSDVG_IGNORE_STACK 0 #define JSDVG_SEARCH_STACK 1 +#ifdef __cplusplus +namespace js { + +static inline char * +DecompileValueGenerator(JSContext *cx, intN spindex, const Value &v, + JSString *fallback) +{ + return js_DecompileValueGenerator(cx, spindex, Jsvalify(v), fallback); +} + +} +#endif + /* * Given bytecode address pc in script's main program code, return the operand * stack depth just before (JSOp) *pc executes. diff --git a/js/src/jsops.cpp b/js/src/jsops.cpp deleted file mode 100644 index fdf2346663ec..000000000000 --- a/js/src/jsops.cpp +++ /dev/null @@ -1,3994 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=79: - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (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.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* This file needs to be included in possibly multiple places. */ - -#if JS_THREADED_INTERP - interrupt: -#else /* !JS_THREADED_INTERP */ - case -1: - JS_ASSERT(switchMask == -1); -#endif /* !JS_THREADED_INTERP */ - { - bool moreInterrupts = false; - JSInterruptHook hook = cx->debugHooks->interruptHook; - if (hook) { -#ifdef JS_TRACER - if (TRACE_RECORDER(cx)) - AbortRecording(cx, "interrupt hook"); -#endif - switch (hook(cx, script, regs.pc, &rval, - cx->debugHooks->interruptHookData)) { - case JSTRAP_ERROR: - goto error; - case JSTRAP_CONTINUE: - break; - case JSTRAP_RETURN: - fp->rval = rval; - ok = JS_TRUE; - goto forced_return; - case JSTRAP_THROW: - cx->throwing = JS_TRUE; - cx->exception = rval; - goto error; - default:; - } - moreInterrupts = true; - } - -#ifdef JS_TRACER - if (TraceRecorder* tr = TRACE_RECORDER(cx)) { - AbortableRecordingStatus status = tr->monitorRecording(op); - JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR); - switch (status) { - case ARECORD_CONTINUE: - moreInterrupts = true; - break; - case ARECORD_IMACRO: - case ARECORD_IMACRO_ABORTED: - atoms = COMMON_ATOMS_START(&rt->atomState); - op = JSOp(*regs.pc); - if (status == ARECORD_IMACRO) - DO_OP(); /* keep interrupting for op. */ - break; - case ARECORD_ERROR: - // The code at 'error:' aborts the recording. - goto error; - case ARECORD_ABORTED: - case ARECORD_COMPLETED: - break; - case ARECORD_STOP: - /* A 'stop' error should have already aborted recording. */ - default: - JS_NOT_REACHED("Bad recording status"); - } - } -#endif /* !JS_TRACER */ - -#if JS_THREADED_INTERP -#ifdef MOZ_TRACEVIS - if (!moreInterrupts) - ExitTraceVisState(cx, R_ABORT); -#endif - jumpTable = moreInterrupts ? interruptJumpTable : normalJumpTable; - JS_EXTENSION_(goto *normalJumpTable[op]); -#else - switchMask = moreInterrupts ? -1 : 0; - switchOp = intN(op); - goto do_switch; -#endif - } - -/* No-ops for ease of decompilation. */ -ADD_EMPTY_CASE(JSOP_NOP) -ADD_EMPTY_CASE(JSOP_CONDSWITCH) -ADD_EMPTY_CASE(JSOP_TRY) -ADD_EMPTY_CASE(JSOP_TRACE) -#if JS_HAS_XML_SUPPORT -ADD_EMPTY_CASE(JSOP_STARTXML) -ADD_EMPTY_CASE(JSOP_STARTXMLEXPR) -#endif -END_EMPTY_CASES - -/* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */ -BEGIN_CASE(JSOP_LINENO) -END_CASE(JSOP_LINENO) - -BEGIN_CASE(JSOP_PUSH) - PUSH_OPND(JSVAL_VOID); -END_CASE(JSOP_PUSH) - -BEGIN_CASE(JSOP_POP) - regs.sp--; -END_CASE(JSOP_POP) - -BEGIN_CASE(JSOP_POPN) - regs.sp -= GET_UINT16(regs.pc); -#ifdef DEBUG - JS_ASSERT(StackBase(fp) <= regs.sp); - obj = fp->blockChain; - JS_ASSERT_IF(obj, - OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj) - <= (size_t) (regs.sp - StackBase(fp))); - for (obj = fp->scopeChain; obj; obj = obj->getParent()) { - clasp = obj->getClass(); - if (clasp != &js_BlockClass && clasp != &js_WithClass) - continue; - if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, fp)) - break; - JS_ASSERT(StackBase(fp) + OBJ_BLOCK_DEPTH(cx, obj) - + ((clasp == &js_BlockClass) - ? OBJ_BLOCK_COUNT(cx, obj) - : 1) - <= regs.sp); - } -#endif -END_CASE(JSOP_POPN) - -BEGIN_CASE(JSOP_SETRVAL) -BEGIN_CASE(JSOP_POPV) - ASSERT_NOT_THROWING(cx); - fp->rval = POP_OPND(); -END_CASE(JSOP_POPV) - -BEGIN_CASE(JSOP_ENTERWITH) - if (!js_EnterWith(cx, -1)) - goto error; - - /* - * We must ensure that different "with" blocks have different stack depth - * associated with them. This allows the try handler search to properly - * recover the scope chain. Thus we must keep the stack at least at the - * current level. - * - * We set sp[-1] to the current "with" object to help asserting the - * enter/leave balance in [leavewith]. - */ - regs.sp[-1] = OBJECT_TO_JSVAL(fp->scopeChain); -END_CASE(JSOP_ENTERWITH) - -BEGIN_CASE(JSOP_LEAVEWITH) - JS_ASSERT(regs.sp[-1] == OBJECT_TO_JSVAL(fp->scopeChain)); - regs.sp--; - js_LeaveWith(cx); -END_CASE(JSOP_LEAVEWITH) - -BEGIN_CASE(JSOP_RETURN) - fp->rval = POP_OPND(); - /* FALL THROUGH */ - -BEGIN_CASE(JSOP_RETRVAL) /* fp->rval already set */ -BEGIN_CASE(JSOP_STOP) - /* - * When the inlined frame exits with an exception or an error, ok will be - * false after the inline_return label. - */ - ASSERT_NOT_THROWING(cx); - CHECK_BRANCH(); - - if (fp->imacpc) { - /* - * If we are at the end of an imacro, return to its caller in the - * current frame. - */ - JS_ASSERT(op == JSOP_STOP); - JS_ASSERT((uintN)(regs.sp - fp->slots()) <= script->nslots); - regs.pc = fp->imacpc + js_CodeSpec[*fp->imacpc].length; - fp->imacpc = NULL; - atoms = script->atomMap.vector; - op = JSOp(*regs.pc); - DO_OP(); - } - - JS_ASSERT(regs.sp == StackBase(fp)); - if ((fp->flags & JSFRAME_CONSTRUCTING) && JSVAL_IS_PRIMITIVE(fp->rval)) - fp->rval = fp->thisv; - ok = JS_TRUE; - if (inlineCallCount) - inline_return: - { - JS_ASSERT(!fp->blockChain); - JS_ASSERT(!js_IsActiveWithOrBlock(cx, fp->scopeChain, 0)); - - if (JS_LIKELY(script->staticLevel < JS_DISPLAY_SIZE)) - cx->display[script->staticLevel] = fp->displaySave; - - void *hookData = fp->hookData; - if (JS_UNLIKELY(hookData != NULL)) { - JSInterpreterHook hook; - JSBool status; - - hook = cx->debugHooks->callHook; - if (hook) { - /* - * Do not pass &ok directly as exposing the address inhibits - * optimizations and uninitialised warnings. - */ - status = ok; - hook(cx, fp, JS_FALSE, &status, hookData); - ok = status; - CHECK_INTERRUPT_HANDLER(); - } - } - - /* - * If fp has a call object, sync values and clear the back- - * pointer. This can happen for a lightweight function if it calls eval - * unexpectedly (in a way that is hidden from the compiler). See bug - * 325540. - */ - fp->putActivationObjects(cx); - - DTrace::exitJSFun(cx, fp, fp->fun, fp->rval); - - /* Restore context version only if callee hasn't set version. */ - if (JS_LIKELY(cx->version == currentVersion)) { - currentVersion = fp->callerVersion; - if (currentVersion != cx->version) - js_SetVersion(cx, currentVersion); - } - - /* - * If inline-constructing, replace primitive rval with the new object - * passed in via |this|, and instrument this constructor invocation. - */ - if (fp->flags & JSFRAME_CONSTRUCTING) { - if (JSVAL_IS_PRIMITIVE(fp->rval)) - fp->rval = fp->thisv; - JS_RUNTIME_METER(cx->runtime, constructs); - } - - JSStackFrame *down = fp->down; - bool recursive = fp->script == down->script; - - /* Pop the frame. */ - cx->stack().popInlineFrame(cx, fp, down); - - /* Propagate return value before fp is lost. */ - regs.sp[-1] = fp->rval; - - /* Sync interpreter registers. */ - fp = cx->fp; - script = fp->script; - atoms = FrameAtomBase(cx, fp); - - /* Resume execution in the calling frame. */ - inlineCallCount--; - if (JS_LIKELY(ok)) { - JS_ASSERT(js_CodeSpec[js_GetOpcode(cx, script, regs.pc)].length - == JSOP_CALL_LENGTH); - TRACE_0(LeaveFrame); - if (!TRACE_RECORDER(cx) && recursive) { - if (*(regs.pc + JSOP_CALL_LENGTH) == JSOP_TRACE) { - regs.pc += JSOP_CALL_LENGTH; - MONITOR_BRANCH(Record_LeaveFrame); - op = (JSOp)*regs.pc; - DO_OP(); - } - } - if (*(regs.pc + JSOP_CALL_LENGTH) == JSOP_TRACE || - *(regs.pc + JSOP_CALL_LENGTH) == JSOP_NOP) { - JS_STATIC_ASSERT(JSOP_TRACE_LENGTH == JSOP_NOP_LENGTH); - regs.pc += JSOP_CALL_LENGTH; - len = JSOP_TRACE_LENGTH; - } else { - len = JSOP_CALL_LENGTH; - } - DO_NEXT_OP(len); - } - goto error; - } - goto exit; - -BEGIN_CASE(JSOP_DEFAULT) - (void) POP(); - /* FALL THROUGH */ -BEGIN_CASE(JSOP_GOTO) - len = GET_JUMP_OFFSET(regs.pc); - BRANCH(len); -END_CASE(JSOP_GOTO) - -BEGIN_CASE(JSOP_IFEQ) - POP_BOOLEAN(cx, rval, cond); - if (cond == JS_FALSE) { - len = GET_JUMP_OFFSET(regs.pc); - BRANCH(len); - } -END_CASE(JSOP_IFEQ) - -BEGIN_CASE(JSOP_IFNE) - POP_BOOLEAN(cx, rval, cond); - if (cond != JS_FALSE) { - len = GET_JUMP_OFFSET(regs.pc); - BRANCH(len); - } -END_CASE(JSOP_IFNE) - -BEGIN_CASE(JSOP_OR) - POP_BOOLEAN(cx, rval, cond); - if (cond == JS_TRUE) { - len = GET_JUMP_OFFSET(regs.pc); - PUSH_OPND(rval); - DO_NEXT_OP(len); - } -END_CASE(JSOP_OR) - -BEGIN_CASE(JSOP_AND) - POP_BOOLEAN(cx, rval, cond); - if (cond == JS_FALSE) { - len = GET_JUMP_OFFSET(regs.pc); - PUSH_OPND(rval); - DO_NEXT_OP(len); - } -END_CASE(JSOP_AND) - -BEGIN_CASE(JSOP_DEFAULTX) - (void) POP(); - /* FALL THROUGH */ -BEGIN_CASE(JSOP_GOTOX) - len = GET_JUMPX_OFFSET(regs.pc); - BRANCH(len); -END_CASE(JSOP_GOTOX); - -BEGIN_CASE(JSOP_IFEQX) - POP_BOOLEAN(cx, rval, cond); - if (cond == JS_FALSE) { - len = GET_JUMPX_OFFSET(regs.pc); - BRANCH(len); - } -END_CASE(JSOP_IFEQX) - -BEGIN_CASE(JSOP_IFNEX) - POP_BOOLEAN(cx, rval, cond); - if (cond != JS_FALSE) { - len = GET_JUMPX_OFFSET(regs.pc); - BRANCH(len); - } -END_CASE(JSOP_IFNEX) - -BEGIN_CASE(JSOP_ORX) - POP_BOOLEAN(cx, rval, cond); - if (cond == JS_TRUE) { - len = GET_JUMPX_OFFSET(regs.pc); - PUSH_OPND(rval); - DO_NEXT_OP(len); - } -END_CASE(JSOP_ORX) - -BEGIN_CASE(JSOP_ANDX) - POP_BOOLEAN(cx, rval, cond); - if (cond == JS_FALSE) { - len = GET_JUMPX_OFFSET(regs.pc); - PUSH_OPND(rval); - DO_NEXT_OP(len); - } -END_CASE(JSOP_ANDX) - -/* - * If the index value at sp[n] is not an int that fits in a jsval, it could - * be an object (an XML QName, AttributeName, or AnyName), but only if we are - * compiling with JS_HAS_XML_SUPPORT. Otherwise convert the index value to a - * string atom id. - */ -#define FETCH_ELEMENT_ID(obj, n, id) \ - JS_BEGIN_MACRO \ - jsval idval_ = FETCH_OPND(n); \ - if (JSVAL_IS_INT(idval_)) { \ - id = INT_JSVAL_TO_JSID(idval_); \ - } else { \ - if (!js_InternNonIntElementId(cx, obj, idval_, &id)) \ - goto error; \ - regs.sp[n] = ID_TO_VALUE(id); \ - } \ - JS_END_MACRO - -#define TRY_BRANCH_AFTER_COND(cond,spdec) \ - JS_BEGIN_MACRO \ - uintN diff_; \ - JS_ASSERT(js_CodeSpec[op].length == 1); \ - diff_ = (uintN) regs.pc[1] - (uintN) JSOP_IFEQ; \ - if (diff_ <= 1) { \ - regs.sp -= spdec; \ - if (cond == (diff_ != 0)) { \ - ++regs.pc; \ - len = GET_JUMP_OFFSET(regs.pc); \ - BRANCH(len); \ - } \ - len = 1 + JSOP_IFEQ_LENGTH; \ - DO_NEXT_OP(len); \ - } \ - JS_END_MACRO - -BEGIN_CASE(JSOP_IN) - rval = FETCH_OPND(-1); - if (JSVAL_IS_PRIMITIVE(rval)) { - js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rval, NULL); - goto error; - } - obj = JSVAL_TO_OBJECT(rval); - FETCH_ELEMENT_ID(obj, -2, id); - if (!obj->lookupProperty(cx, id, &obj2, &prop)) - goto error; - cond = prop != NULL; - if (prop) - obj2->dropProperty(cx, prop); - TRY_BRANCH_AFTER_COND(cond, 2); - regs.sp--; - STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); -END_CASE(JSOP_IN) - -BEGIN_CASE(JSOP_ITER) - JS_ASSERT(regs.sp > StackBase(fp)); - flags = regs.pc[1]; - if (!js_ValueToIterator(cx, flags, ®s.sp[-1])) - goto error; - CHECK_INTERRUPT_HANDLER(); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1])); -END_CASE(JSOP_ITER) - -BEGIN_CASE(JSOP_MOREITER) - JS_ASSERT(regs.sp - 1 >= StackBase(fp)); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1])); - PUSH_OPND(JSVAL_NULL); - if (!IteratorMore(cx, JSVAL_TO_OBJECT(regs.sp[-2]), &cond, ®s.sp[-1])) - goto error; - CHECK_INTERRUPT_HANDLER(); - TRY_BRANCH_AFTER_COND(cond, 1); - JS_ASSERT(regs.pc[1] == JSOP_IFNEX); - STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); -END_CASE(JSOP_MOREITER) - -BEGIN_CASE(JSOP_ENDITER) - JS_ASSERT(regs.sp - 1 >= StackBase(fp)); - ok = js_CloseIterator(cx, regs.sp[-1]); - regs.sp--; - if (!ok) - goto error; -END_CASE(JSOP_ENDITER) - -BEGIN_CASE(JSOP_FORARG) - JS_ASSERT(regs.sp - 1 >= StackBase(fp)); - slot = GET_ARGNO(regs.pc); - JS_ASSERT(slot < fp->fun->nargs); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1])); - if (!IteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-1]), &fp->argv[slot])) - goto error; -END_CASE(JSOP_FORARG) - -BEGIN_CASE(JSOP_FORLOCAL) - JS_ASSERT(regs.sp - 1 >= StackBase(fp)); - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < fp->script->nslots); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1])); - if (!IteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-1]), &fp->slots()[slot])) - goto error; -END_CASE(JSOP_FORLOCAL) - -BEGIN_CASE(JSOP_FORNAME) - JS_ASSERT(regs.sp - 1 >= StackBase(fp)); - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) - goto error; - if (prop) - obj2->dropProperty(cx, prop); - { - AutoValueRooter tvr(cx); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1])); - if (!IteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-1]), tvr.addr())) - goto error; - ok = obj->setProperty(cx, id, tvr.addr()); - if (!ok) - goto error; - } -END_CASE(JSOP_FORNAME) - -BEGIN_CASE(JSOP_FORPROP) - JS_ASSERT(regs.sp - 2 >= StackBase(fp)); - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - FETCH_OBJECT(cx, -1, lval, obj); - { - AutoValueRooter tvr(cx); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-2])); - if (!IteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-2]), tvr.addr())) - goto error; - ok = obj->setProperty(cx, id, tvr.addr()); - if (!ok) - goto error; - } - regs.sp--; -END_CASE(JSOP_FORPROP) - -BEGIN_CASE(JSOP_FORELEM) - /* - * JSOP_FORELEM simply dups the property identifier at top of stack and - * lets the subsequent JSOP_ENUMELEM opcode sequence handle the left-hand - * side expression evaluation and assignment. This opcode exists solely to - * help the decompiler. - */ - JS_ASSERT(regs.sp - 1 >= StackBase(fp)); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(regs.sp[-1])); - PUSH_OPND(JSVAL_NULL); - if (!IteratorNext(cx, JSVAL_TO_OBJECT(regs.sp[-2]), ®s.sp[-1])) - goto error; -END_CASE(JSOP_FORELEM) - -BEGIN_CASE(JSOP_DUP) - JS_ASSERT(regs.sp > StackBase(fp)); - rval = FETCH_OPND(-1); - PUSH(rval); -END_CASE(JSOP_DUP) - -BEGIN_CASE(JSOP_DUP2) - JS_ASSERT(regs.sp - 2 >= StackBase(fp)); - lval = FETCH_OPND(-2); - rval = FETCH_OPND(-1); - PUSH(lval); - PUSH(rval); -END_CASE(JSOP_DUP2) - -BEGIN_CASE(JSOP_SWAP) - JS_ASSERT(regs.sp - 2 >= StackBase(fp)); - lval = FETCH_OPND(-2); - rval = FETCH_OPND(-1); - STORE_OPND(-1, lval); - STORE_OPND(-2, rval); -END_CASE(JSOP_SWAP) - -BEGIN_CASE(JSOP_PICK) - i = regs.pc[1]; - JS_ASSERT(regs.sp - (i+1) >= StackBase(fp)); - lval = regs.sp[-(i+1)]; - memmove(regs.sp - (i+1), regs.sp - i, sizeof(jsval)*i); - regs.sp[-1] = lval; -END_CASE(JSOP_PICK) - -#define PROPERTY_OP(n, call) \ - JS_BEGIN_MACRO \ - /* Fetch the left part and resolve it to a non-null object. */ \ - FETCH_OBJECT(cx, n, lval, obj); \ - \ - /* Get or set the property. */ \ - if (!call) \ - goto error; \ - JS_END_MACRO - -#define ELEMENT_OP(n, call) \ - JS_BEGIN_MACRO \ - /* Fetch the left part and resolve it to a non-null object. */ \ - FETCH_OBJECT(cx, n - 1, lval, obj); \ - \ - /* Fetch index and convert it to id suitable for use with obj. */ \ - FETCH_ELEMENT_ID(obj, n, id); \ - \ - /* Get or set the element. */ \ - if (!call) \ - goto error; \ - JS_END_MACRO - -#define NATIVE_GET(cx,obj,pobj,sprop,getHow,vp) \ - JS_BEGIN_MACRO \ - if (sprop->hasDefaultGetter()) { \ - /* Fast path for Object instance properties. */ \ - JS_ASSERT((sprop)->slot != SPROP_INVALID_SLOT || \ - !sprop->hasDefaultSetter()); \ - *vp = ((sprop)->slot != SPROP_INVALID_SLOT) \ - ? (pobj)->lockedGetSlot((sprop)->slot) \ - : JSVAL_VOID; \ - } else { \ - if (!js_NativeGet(cx, obj, pobj, sprop, getHow, vp)) \ - goto error; \ - } \ - JS_END_MACRO - -#define NATIVE_SET(cx,obj,sprop,entry,vp) \ - JS_BEGIN_MACRO \ - TRACE_2(SetPropHit, entry, sprop); \ - if (sprop->hasDefaultSetter() && \ - (sprop)->slot != SPROP_INVALID_SLOT && \ - !(obj)->scope()->brandedOrHasMethodBarrier()) { \ - /* Fast path for, e.g., plain Object instance properties. */ \ - (obj)->lockedSetSlot((sprop)->slot, *vp); \ - } else { \ - if (!js_NativeSet(cx, obj, sprop, false, vp)) \ - goto error; \ - } \ - JS_END_MACRO - -/* - * Skip the JSOP_POP typically found after a JSOP_SET* opcode, where oplen is - * the constant length of the SET opcode sequence, and spdec is the constant - * by which to decrease the stack pointer to pop all of the SET op's operands. - * - * NB: unlike macros that could conceivably be replaced by functions (ignoring - * goto error), where a call should not have to be braced in order to expand - * correctly (e.g., in if (cond) FOO(); else BAR()), these three macros lack - * JS_{BEGIN,END}_MACRO brackets. They are also indented so as to align with - * nearby opcode code. - */ -#define SKIP_POP_AFTER_SET(oplen,spdec) \ - if (regs.pc[oplen] == JSOP_POP) { \ - regs.sp -= spdec; \ - regs.pc += oplen + JSOP_POP_LENGTH; \ - op = (JSOp) *regs.pc; \ - DO_OP(); \ - } - -#define END_SET_CASE(OP) \ - SKIP_POP_AFTER_SET(OP##_LENGTH, 1); \ - END_CASE(OP) - -#define END_SET_CASE_STORE_RVAL(OP,spdec) \ - SKIP_POP_AFTER_SET(OP##_LENGTH, spdec); \ - rval = FETCH_OPND(-1); \ - regs.sp -= (spdec) - 1; \ - STORE_OPND(-1, rval); \ - END_CASE(OP) - -BEGIN_CASE(JSOP_SETCONST) - LOAD_ATOM(0); - obj = fp->varobj(cx); - rval = FETCH_OPND(-1); - if (!obj->defineProperty(cx, ATOM_TO_JSID(atom), rval, - JS_PropertyStub, JS_PropertyStub, - JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { - goto error; - } -END_SET_CASE(JSOP_SETCONST); - -#if JS_HAS_DESTRUCTURING -BEGIN_CASE(JSOP_ENUMCONSTELEM) - rval = FETCH_OPND(-3); - FETCH_OBJECT(cx, -2, lval, obj); - FETCH_ELEMENT_ID(obj, -1, id); - if (!obj->defineProperty(cx, id, rval, - JS_PropertyStub, JS_PropertyStub, - JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) { - goto error; - } - regs.sp -= 3; -END_CASE(JSOP_ENUMCONSTELEM) -#endif - -BEGIN_CASE(JSOP_BINDNAME) - do { - PropertyCacheEntry *entry; - - /* - * We can skip the property lookup for the global object. If the - * property does not exist anywhere on the scope chain, JSOP_SETNAME - * adds the property to the global. - * - * As a consequence of this optimization for the global object we run - * its JSRESOLVE_ASSIGNING-tolerant resolve hooks only in JSOP_SETNAME, - * after the interpreter evaluates the right- hand-side of the - * assignment, and not here. - * - * This should be transparent to the hooks because the script, instead - * of name = rhs, could have used global.name = rhs given a global - * object reference, which also calls the hooks only after evaluating - * the rhs. We desire such resolve hook equivalence between the two - * forms. - */ - obj = fp->scopeChain; - if (!obj->getParent()) - break; - - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - break; - } - - id = ATOM_TO_JSID(atom); - obj = js_FindIdentifierBase(cx, fp->scopeChain, id); - if (!obj) - goto error; - } while (0); - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_BINDNAME) - -BEGIN_CASE(JSOP_IMACOP) - JS_ASSERT(JS_UPTRDIFF(fp->imacpc, script->code) < script->length); - op = JSOp(*fp->imacpc); - DO_OP(); - -#define BITWISE_OP(OP) \ - JS_BEGIN_MACRO \ - FETCH_INT(cx, -2, i); \ - FETCH_INT(cx, -1, j); \ - i = i OP j; \ - regs.sp--; \ - STORE_INT(cx, -1, i); \ - JS_END_MACRO - -BEGIN_CASE(JSOP_BITOR) - BITWISE_OP(|); -END_CASE(JSOP_BITOR) - -BEGIN_CASE(JSOP_BITXOR) - BITWISE_OP(^); -END_CASE(JSOP_BITXOR) - -BEGIN_CASE(JSOP_BITAND) - BITWISE_OP(&); -END_CASE(JSOP_BITAND) - -#define RELATIONAL_OP(OP) \ - JS_BEGIN_MACRO \ - rval = FETCH_OPND(-1); \ - lval = FETCH_OPND(-2); \ - /* Optimize for two int-tagged operands (typical loop control). */ \ - if ((lval & rval) & JSVAL_INT) { \ - cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval); \ - } else { \ - if (!JSVAL_IS_PRIMITIVE(lval)) \ - DEFAULT_VALUE(cx, -2, JSTYPE_NUMBER, lval); \ - if (!JSVAL_IS_PRIMITIVE(rval)) \ - DEFAULT_VALUE(cx, -1, JSTYPE_NUMBER, rval); \ - if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { \ - str = JSVAL_TO_STRING(lval); \ - str2 = JSVAL_TO_STRING(rval); \ - cond = js_CompareStrings(str, str2) OP 0; \ - } else { \ - VALUE_TO_NUMBER(cx, lval, d); \ - VALUE_TO_NUMBER(cx, rval, d2); \ - cond = JSDOUBLE_COMPARE(d, OP, d2, JS_FALSE); \ - } \ - } \ - TRY_BRANCH_AFTER_COND(cond, 2); \ - regs.sp--; \ - STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \ - JS_END_MACRO - -/* - * NB: These macros can't use JS_BEGIN_MACRO/JS_END_MACRO around their bodies - * because they begin if/else chains, so callers must not put semicolons after - * the call expressions! - */ -#if JS_HAS_XML_SUPPORT -#define XML_EQUALITY_OP(OP) \ - if ((ltmp == JSVAL_OBJECT && \ - (obj2 = JSVAL_TO_OBJECT(lval)) && \ - obj2->isXML()) || \ - (rtmp == JSVAL_OBJECT && \ - (obj2 = JSVAL_TO_OBJECT(rval)) && \ - obj2->isXML())) { \ - if (JSVAL_IS_OBJECT(rval) && obj2 == JSVAL_TO_OBJECT(rval)) \ - rval = lval; \ - if (!js_TestXMLEquality(cx, obj2, rval, &cond)) \ - goto error; \ - cond = cond OP JS_TRUE; \ - } else - -#define EXTENDED_EQUALITY_OP(OP) \ - if (ltmp == JSVAL_OBJECT && \ - (obj2 = JSVAL_TO_OBJECT(lval)) && \ - ((clasp = obj2->getClass())->flags & JSCLASS_IS_EXTENDED) && \ - (((JSExtendedClass *) clasp)->equality)) { \ - if (!((JSExtendedClass *) clasp)->equality(cx, obj2, rval, &cond)) \ - goto error; \ - cond = cond OP JS_TRUE; \ - } else -#else -#define XML_EQUALITY_OP(OP) /* nothing */ -#define EXTENDED_EQUALITY_OP(OP) /* nothing */ -#endif - -#define EQUALITY_OP(OP, IFNAN) \ - JS_BEGIN_MACRO \ - rval = FETCH_OPND(-1); \ - lval = FETCH_OPND(-2); \ - ltmp = JSVAL_TAG(lval); \ - rtmp = JSVAL_TAG(rval); \ - XML_EQUALITY_OP(OP) \ - if (ltmp == rtmp) { \ - if (ltmp == JSVAL_STRING) { \ - str = JSVAL_TO_STRING(lval); \ - str2 = JSVAL_TO_STRING(rval); \ - cond = js_EqualStrings(str, str2) OP JS_TRUE; \ - } else if (ltmp == JSVAL_DOUBLE) { \ - d = *JSVAL_TO_DOUBLE(lval); \ - d2 = *JSVAL_TO_DOUBLE(rval); \ - cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \ - } else { \ - EXTENDED_EQUALITY_OP(OP) \ - /* Handle all undefined (=>NaN) and int combinations. */ \ - cond = lval OP rval; \ - } \ - } else { \ - if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { \ - cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1; \ - } else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { \ - cond = 1 OP 0; \ - } else { \ - if (ltmp == JSVAL_OBJECT) { \ - DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); \ - ltmp = JSVAL_TAG(lval); \ - } else if (rtmp == JSVAL_OBJECT) { \ - DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); \ - rtmp = JSVAL_TAG(rval); \ - } \ - if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) { \ - str = JSVAL_TO_STRING(lval); \ - str2 = JSVAL_TO_STRING(rval); \ - cond = js_EqualStrings(str, str2) OP JS_TRUE; \ - } else { \ - VALUE_TO_NUMBER(cx, lval, d); \ - VALUE_TO_NUMBER(cx, rval, d2); \ - cond = JSDOUBLE_COMPARE(d, OP, d2, IFNAN); \ - } \ - } \ - } \ - TRY_BRANCH_AFTER_COND(cond, 2); \ - regs.sp--; \ - STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \ - JS_END_MACRO - -BEGIN_CASE(JSOP_EQ) - EQUALITY_OP(==, JS_FALSE); -END_CASE(JSOP_EQ) - -BEGIN_CASE(JSOP_NE) - EQUALITY_OP(!=, JS_TRUE); -END_CASE(JSOP_NE) - -#define STRICT_EQUALITY_OP(OP) \ - JS_BEGIN_MACRO \ - rval = FETCH_OPND(-1); \ - lval = FETCH_OPND(-2); \ - cond = js_StrictlyEqual(cx, lval, rval) OP JS_TRUE; \ - regs.sp--; \ - STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \ - JS_END_MACRO - -BEGIN_CASE(JSOP_STRICTEQ) - STRICT_EQUALITY_OP(==); -END_CASE(JSOP_STRICTEQ) - -BEGIN_CASE(JSOP_STRICTNE) - STRICT_EQUALITY_OP(!=); -END_CASE(JSOP_STRICTNE) - -BEGIN_CASE(JSOP_CASE) - STRICT_EQUALITY_OP(==); - (void) POP(); - if (cond) { - len = GET_JUMP_OFFSET(regs.pc); - BRANCH(len); - } - PUSH(lval); -END_CASE(JSOP_CASE) - -BEGIN_CASE(JSOP_CASEX) - STRICT_EQUALITY_OP(==); - (void) POP(); - if (cond) { - len = GET_JUMPX_OFFSET(regs.pc); - BRANCH(len); - } - PUSH(lval); -END_CASE(JSOP_CASEX) - -BEGIN_CASE(JSOP_LT) - RELATIONAL_OP(<); -END_CASE(JSOP_LT) - -BEGIN_CASE(JSOP_LE) - RELATIONAL_OP(<=); -END_CASE(JSOP_LE) - -BEGIN_CASE(JSOP_GT) - RELATIONAL_OP(>); -END_CASE(JSOP_GT) - -BEGIN_CASE(JSOP_GE) - RELATIONAL_OP(>=); -END_CASE(JSOP_GE) - -#undef EQUALITY_OP -#undef RELATIONAL_OP - -#define SIGNED_SHIFT_OP(OP) \ - JS_BEGIN_MACRO \ - FETCH_INT(cx, -2, i); \ - FETCH_INT(cx, -1, j); \ - i = i OP (j & 31); \ - regs.sp--; \ - STORE_INT(cx, -1, i); \ - JS_END_MACRO - -BEGIN_CASE(JSOP_LSH) - SIGNED_SHIFT_OP(<<); -END_CASE(JSOP_LSH) - -BEGIN_CASE(JSOP_RSH) - SIGNED_SHIFT_OP(>>); -END_CASE(JSOP_RSH) - -BEGIN_CASE(JSOP_URSH) -{ - uint32_t u; - - FETCH_UINT(cx, -2, u); - FETCH_INT(cx, -1, j); - u >>= (j & 31); - regs.sp--; - STORE_UINT(cx, -1, u); -} -END_CASE(JSOP_URSH) - -#undef BITWISE_OP -#undef SIGNED_SHIFT_OP - -BEGIN_CASE(JSOP_ADD) - rval = FETCH_OPND(-1); - lval = FETCH_OPND(-2); -#if JS_HAS_XML_SUPPORT - if (!JSVAL_IS_PRIMITIVE(lval) && - (obj2 = JSVAL_TO_OBJECT(lval), obj2->isXML()) && - VALUE_IS_XML(rval)) { - if (!js_ConcatenateXML(cx, obj2, rval, &rval)) - goto error; - regs.sp--; - STORE_OPND(-1, rval); - } else -#endif - { - if (!JSVAL_IS_PRIMITIVE(lval)) - DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval); - if (!JSVAL_IS_PRIMITIVE(rval)) - DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval); - if ((cond = JSVAL_IS_STRING(lval)) || JSVAL_IS_STRING(rval)) { - if (cond) { - str = JSVAL_TO_STRING(lval); - str2 = js_ValueToString(cx, rval); - if (!str2) - goto error; - regs.sp[-1] = STRING_TO_JSVAL(str2); - } else { - str2 = JSVAL_TO_STRING(rval); - str = js_ValueToString(cx, lval); - if (!str) - goto error; - regs.sp[-2] = STRING_TO_JSVAL(str); - } - str = js_ConcatStrings(cx, str, str2); - if (!str) - goto error; - regs.sp--; - STORE_OPND(-1, STRING_TO_JSVAL(str)); - } else { - VALUE_TO_NUMBER(cx, lval, d); - VALUE_TO_NUMBER(cx, rval, d2); - d += d2; - regs.sp--; - STORE_NUMBER(cx, -1, d); - } - } -END_CASE(JSOP_ADD) - -BEGIN_CASE(JSOP_OBJTOSTR) - rval = FETCH_OPND(-1); - if (!JSVAL_IS_PRIMITIVE(rval)) { - str = js_ValueToString(cx, rval); - if (!str) - goto error; - STORE_OPND(-1, STRING_TO_JSVAL(str)); - } -END_CASE(JSOP_OBJTOSTR) - -BEGIN_CASE(JSOP_CONCATN) -{ - JSCharBuffer buf(cx); - argc = GET_ARGC(regs.pc); - for (vp = regs.sp - argc; vp < regs.sp; vp++) { - JS_ASSERT(JSVAL_IS_PRIMITIVE(*vp)); - if (!js_ValueToCharBuffer(cx, *vp, buf)) - goto error; - } - str = js_NewStringFromCharBuffer(cx, buf); - if (!str) - goto error; - regs.sp -= argc - 1; - STORE_OPND(-1, STRING_TO_JSVAL(str)); -} -END_CASE(JSOP_CONCATN) - -#define BINARY_OP(OP) \ - JS_BEGIN_MACRO \ - FETCH_NUMBER(cx, -2, d); \ - FETCH_NUMBER(cx, -1, d2); \ - d = d OP d2; \ - regs.sp--; \ - STORE_NUMBER(cx, -1, d); \ - JS_END_MACRO - -BEGIN_CASE(JSOP_SUB) - BINARY_OP(-); -END_CASE(JSOP_SUB) - -BEGIN_CASE(JSOP_MUL) - BINARY_OP(*); -END_CASE(JSOP_MUL) - -BEGIN_CASE(JSOP_DIV) - FETCH_NUMBER(cx, -1, d2); - FETCH_NUMBER(cx, -2, d); - regs.sp--; - if (d2 == 0) { -#ifdef XP_WIN - /* XXX MSVC miscompiles such that (NaN == 0) */ - if (JSDOUBLE_IS_NaN(d2)) - rval = rt->NaNValue; - else -#endif - if (d == 0 || JSDOUBLE_IS_NaN(d)) - rval = rt->NaNValue; - else if (JSDOUBLE_IS_NEG(d) != JSDOUBLE_IS_NEG(d2)) - rval = rt->negativeInfinityValue; - else - rval = rt->positiveInfinityValue; - STORE_OPND(-1, rval); - } else { - d /= d2; - STORE_NUMBER(cx, -1, d); - } -END_CASE(JSOP_DIV) - -BEGIN_CASE(JSOP_MOD) - FETCH_NUMBER(cx, -1, d2); - FETCH_NUMBER(cx, -2, d); - regs.sp--; - if (d2 == 0) { - STORE_OPND(-1, rt->NaNValue); - } else { - d = js_fmod(d, d2); - STORE_NUMBER(cx, -1, d); - } -END_CASE(JSOP_MOD) - -BEGIN_CASE(JSOP_NOT) - POP_BOOLEAN(cx, rval, cond); - PUSH_OPND(BOOLEAN_TO_JSVAL(!cond)); -END_CASE(JSOP_NOT) - -BEGIN_CASE(JSOP_BITNOT) - FETCH_INT(cx, -1, i); - i = ~i; - STORE_INT(cx, -1, i); -END_CASE(JSOP_BITNOT) - -BEGIN_CASE(JSOP_NEG) - /* - * When the operand is int jsval, INT_FITS_IN_JSVAL(i) implies - * INT_FITS_IN_JSVAL(-i) unless i is 0 or JSVAL_INT_MIN when the - * results, -0.0 or JSVAL_INT_MAX + 1, are jsdouble values. - */ - rval = FETCH_OPND(-1); - if (JSVAL_IS_INT(rval) && - rval != INT_TO_JSVAL(JSVAL_INT_MIN) && - (i = JSVAL_TO_INT(rval)) != 0) { - JS_STATIC_ASSERT(!INT_FITS_IN_JSVAL(-JSVAL_INT_MIN)); - i = -i; - JS_ASSERT(INT_FITS_IN_JSVAL(i)); - regs.sp[-1] = INT_TO_JSVAL(i); - } else { - if (!ValueToNumber(cx, regs.sp[-1], &d)) - goto error; - d = -d; - if (!js_NewNumberInRootedValue(cx, d, ®s.sp[-1])) - goto error; - } -END_CASE(JSOP_NEG) - -BEGIN_CASE(JSOP_POS) - if (!ValueToNumberValue(cx, ®s.sp[-1])) - goto error; -END_CASE(JSOP_POS) - -BEGIN_CASE(JSOP_DELNAME) - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - if (!js_FindProperty(cx, id, &obj, &obj2, &prop)) - goto error; - - /* ECMA says to return true if name is undefined or inherited. */ - PUSH_OPND(JSVAL_TRUE); - if (prop) { - obj2->dropProperty(cx, prop); - if (!obj->deleteProperty(cx, id, ®s.sp[-1])) - goto error; - } -END_CASE(JSOP_DELNAME) - -BEGIN_CASE(JSOP_DELPROP) - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - PROPERTY_OP(-1, obj->deleteProperty(cx, id, &rval)); - STORE_OPND(-1, rval); -END_CASE(JSOP_DELPROP) - -BEGIN_CASE(JSOP_DELELEM) - ELEMENT_OP(-1, obj->deleteProperty(cx, id, &rval)); - regs.sp--; - STORE_OPND(-1, rval); -END_CASE(JSOP_DELELEM) - -BEGIN_CASE(JSOP_TYPEOFEXPR) -BEGIN_CASE(JSOP_TYPEOF) - rval = FETCH_OPND(-1); - type = JS_TypeOfValue(cx, rval); - atom = rt->atomState.typeAtoms[type]; - STORE_OPND(-1, ATOM_KEY(atom)); -END_CASE(JSOP_TYPEOF) - -BEGIN_CASE(JSOP_VOID) - STORE_OPND(-1, JSVAL_VOID); -END_CASE(JSOP_VOID) - -BEGIN_CASE(JSOP_INCELEM) -BEGIN_CASE(JSOP_DECELEM) -BEGIN_CASE(JSOP_ELEMINC) -BEGIN_CASE(JSOP_ELEMDEC) - /* - * Delay fetching of id until we have the object to ensure the proper - * evaluation order. See bug 372331. - */ - id = 0; - i = -2; - goto fetch_incop_obj; - -BEGIN_CASE(JSOP_INCPROP) -BEGIN_CASE(JSOP_DECPROP) -BEGIN_CASE(JSOP_PROPINC) -BEGIN_CASE(JSOP_PROPDEC) - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - i = -1; - - fetch_incop_obj: - FETCH_OBJECT(cx, i, lval, obj); - if (id == 0) - FETCH_ELEMENT_ID(obj, -1, id); - goto do_incop; - -BEGIN_CASE(JSOP_INCNAME) -BEGIN_CASE(JSOP_DECNAME) -BEGIN_CASE(JSOP_NAMEINC) -BEGIN_CASE(JSOP_NAMEDEC) -{ - PropertyCacheEntry *entry; - - obj = fp->scopeChain; - - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - if (obj == obj2 && entry->vword.isSlot()) { - slot = entry->vword.toSlot(); - JS_ASSERT(slot < obj->scope()->freeslot); - rval = obj->lockedGetSlot(slot); - if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { - rtmp = rval; - rval += (js_CodeSpec[op].format & JOF_INC) ? 2 : -2; - if (!(js_CodeSpec[op].format & JOF_POST)) - rtmp = rval; - obj->lockedSetSlot(slot, rval); - PUSH_OPND(rtmp); - len = JSOP_INCNAME_LENGTH; - DO_NEXT_OP(len); - } - } - LOAD_ATOM(0); - } - - id = ATOM_TO_JSID(atom); - if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) - goto error; - if (!prop) - goto atom_not_defined; - obj2->dropProperty(cx, prop); -} - -do_incop: -{ - const JSCodeSpec *cs; - jsval v; - - /* - * We need a root to store the value to leave on the stack until - * we have done with obj->setProperty. - */ - PUSH_OPND(JSVAL_NULL); - if (!obj->getProperty(cx, id, ®s.sp[-1])) - goto error; - - cs = &js_CodeSpec[op]; - JS_ASSERT(cs->ndefs == 1); - JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) == JOF_TMPSLOT2); - v = regs.sp[-1]; - if (JS_LIKELY(CAN_DO_FAST_INC_DEC(v))) { - jsval incr; - - incr = (cs->format & JOF_INC) ? 2 : -2; - if (cs->format & JOF_POST) { - regs.sp[-1] = v + incr; - } else { - v += incr; - regs.sp[-1] = v; - } - fp->flags |= JSFRAME_ASSIGNING; - ok = obj->setProperty(cx, id, ®s.sp[-1]); - fp->flags &= ~JSFRAME_ASSIGNING; - if (!ok) - goto error; - - /* - * We must set regs.sp[-1] to v for both post and pre increments - * as the setter overwrites regs.sp[-1]. - */ - regs.sp[-1] = v; - } else { - /* We need an extra root for the result. */ - PUSH_OPND(JSVAL_NULL); - if (!js_DoIncDec(cx, cs, ®s.sp[-2], ®s.sp[-1])) - goto error; - fp->flags |= JSFRAME_ASSIGNING; - ok = obj->setProperty(cx, id, ®s.sp[-1]); - fp->flags &= ~JSFRAME_ASSIGNING; - if (!ok) - goto error; - regs.sp--; - } - - if (cs->nuses == 0) { - /* regs.sp[-1] already contains the result of name increment. */ - } else { - rtmp = regs.sp[-1]; - regs.sp -= cs->nuses; - regs.sp[-1] = rtmp; - } - len = cs->length; - DO_NEXT_OP(len); -} - -{ - jsval incr, incr2; - - /* Position cases so the most frequent i++ does not need a jump. */ -BEGIN_CASE(JSOP_DECARG) - incr = -2; incr2 = -2; goto do_arg_incop; -BEGIN_CASE(JSOP_ARGDEC) - incr = -2; incr2 = 0; goto do_arg_incop; -BEGIN_CASE(JSOP_INCARG) - incr = 2; incr2 = 2; goto do_arg_incop; -BEGIN_CASE(JSOP_ARGINC) - incr = 2; incr2 = 0; - - do_arg_incop: - slot = GET_ARGNO(regs.pc); - JS_ASSERT(slot < fp->fun->nargs); - METER_SLOT_OP(op, slot); - vp = fp->argv + slot; - goto do_int_fast_incop; - -BEGIN_CASE(JSOP_DECLOCAL) - incr = -2; incr2 = -2; goto do_local_incop; -BEGIN_CASE(JSOP_LOCALDEC) - incr = -2; incr2 = 0; goto do_local_incop; -BEGIN_CASE(JSOP_INCLOCAL) - incr = 2; incr2 = 2; goto do_local_incop; -BEGIN_CASE(JSOP_LOCALINC) - incr = 2; incr2 = 0; - - /* - * do_local_incop comes right before do_int_fast_incop as we want to - * avoid an extra jump for variable cases as local++ is more frequent - * than arg++. - */ - do_local_incop: - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < fp->script->nslots); - vp = fp->slots() + slot; - METER_SLOT_OP(op, slot); - vp = fp->slots() + slot; - - do_int_fast_incop: - rval = *vp; - if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { - *vp = rval + incr; - JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length); - SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0); - PUSH_OPND(rval + incr2); - } else { - PUSH_OPND(rval); - if (!js_DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-1], vp)) - goto error; - } - len = JSOP_INCARG_LENGTH; - JS_ASSERT(len == js_CodeSpec[op].length); - DO_NEXT_OP(len); -} - -/* NB: This macro doesn't use JS_BEGIN_MACRO/JS_END_MACRO around its body. */ -#define FAST_GLOBAL_INCREMENT_OP(SLOWOP,INCR,INCR2) \ - op2 = SLOWOP; \ - incr = INCR; \ - incr2 = INCR2; \ - goto do_global_incop - -{ - jsval incr, incr2; - -BEGIN_CASE(JSOP_DECGVAR) - FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, -2, -2); -BEGIN_CASE(JSOP_GVARDEC) - FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, -2, 0); -BEGIN_CASE(JSOP_INCGVAR) - FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME, 2, 2); -BEGIN_CASE(JSOP_GVARINC) - FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC, 2, 0); - -#undef FAST_GLOBAL_INCREMENT_OP - - do_global_incop: - JS_ASSERT((js_CodeSpec[op].format & JOF_TMPSLOT_MASK) == - JOF_TMPSLOT2); - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < GlobalVarCount(fp)); - METER_SLOT_OP(op, slot); - lval = fp->slots()[slot]; - if (JSVAL_IS_NULL(lval)) { - op = op2; - DO_OP(); - } - slot = JSVAL_TO_INT(lval); - JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); - rval = cx->activeCallStack()->getInitialVarObj()->getSlotMT(cx, slot); - if (JS_LIKELY(CAN_DO_FAST_INC_DEC(rval))) { - PUSH_OPND(rval + incr2); - rval += incr; - } else { - PUSH_OPND(rval); - PUSH_OPND(JSVAL_NULL); /* Extra root */ - if (!js_DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-2], ®s.sp[-1])) - goto error; - rval = regs.sp[-1]; - --regs.sp; - } - fp->varobj(cx)->setSlotMT(cx, slot, rval); - len = JSOP_INCGVAR_LENGTH; /* all gvar incops are same length */ - JS_ASSERT(len == js_CodeSpec[op].length); - DO_NEXT_OP(len); -} - -#define COMPUTE_THIS(cx, fp, obj) \ - JS_BEGIN_MACRO \ - if (!(obj = (fp)->getThisObject(cx))) \ - goto error; \ - JS_END_MACRO - -BEGIN_CASE(JSOP_THIS) - COMPUTE_THIS(cx, fp, obj); - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_THIS) - -BEGIN_CASE(JSOP_UNBRANDTHIS) - COMPUTE_THIS(cx, fp, obj); - if (!obj->unbrand(cx)) - goto error; -END_CASE(JSOP_UNBRANDTHIS) - -BEGIN_CASE(JSOP_GETTHISPROP) - i = 0; - COMPUTE_THIS(cx, fp, obj); - PUSH(JSVAL_NULL); - goto do_getprop_with_obj; - -#undef COMPUTE_THIS - -BEGIN_CASE(JSOP_GETARGPROP) - i = ARGNO_LEN; - slot = GET_ARGNO(regs.pc); - JS_ASSERT(slot < fp->fun->nargs); - PUSH_OPND(fp->argv[slot]); - goto do_getprop_body; - -BEGIN_CASE(JSOP_GETLOCALPROP) - i = SLOTNO_LEN; - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < script->nslots); - PUSH_OPND(fp->slots()[slot]); - goto do_getprop_body; - -BEGIN_CASE(JSOP_GETPROP) -BEGIN_CASE(JSOP_GETXPROP) - i = 0; - - do_getprop_body: - lval = FETCH_OPND(-1); - - do_getprop_with_lval: - VALUE_TO_OBJECT(cx, -1, lval, obj); - - do_getprop_with_obj: - do { - JSObject *aobj; - PropertyCacheEntry *entry; - - /* - * We do not impose the method read barrier if in an imacro, - * assuming any property gets it does (e.g., for 'toString' - * from JSOP_NEW) will not be leaked to the calling script. - */ - aobj = js_GetProtoIfDenseArray(obj); - - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(i, aobj, obj2, entry); - if (entry->vword.isObject()) { - rval = entry->vword.toJsval(); - } else if (entry->vword.isSlot()) { - slot = entry->vword.toSlot(); - JS_ASSERT(slot < obj2->scope()->freeslot); - rval = obj2->lockedGetSlot(slot); - } else { - JS_ASSERT(entry->vword.isSprop()); - sprop = entry->vword.toSprop(); - NATIVE_GET(cx, obj, obj2, sprop, - fp->imacpc ? JSGET_NO_METHOD_BARRIER : JSGET_METHOD_BARRIER, - &rval); - } - break; - } - - id = ATOM_TO_JSID(atom); - if (JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty) - ? !js_GetPropertyHelper(cx, obj, id, - fp->imacpc - ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER - : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER, - &rval) - : !obj->getProperty(cx, id, &rval)) { - goto error; - } - } while (0); - - STORE_OPND(-1, rval); - JS_ASSERT(JSOP_GETPROP_LENGTH + i == js_CodeSpec[op].length); - len = JSOP_GETPROP_LENGTH + i; -END_VARLEN_CASE - -BEGIN_CASE(JSOP_LENGTH) - lval = FETCH_OPND(-1); - if (JSVAL_IS_STRING(lval)) { - str = JSVAL_TO_STRING(lval); - regs.sp[-1] = INT_TO_JSVAL(str->length()); - } else if (!JSVAL_IS_PRIMITIVE(lval)) { - obj = JSVAL_TO_OBJECT(lval); - if (obj->isArray()) { - jsuint length = obj->getArrayLength(); - - if (length <= JSVAL_INT_MAX) - regs.sp[-1] = INT_TO_JSVAL(length); - else if (!js_NewDoubleInRootedValue(cx, (jsdouble) length, ®s.sp[-1])) - goto error; - } else if (obj->isArguments() && !obj->isArgsLengthOverridden()) { - uint32 length = obj->getArgsLength(); - - JS_ASSERT(INT_FITS_IN_JSVAL(length)); - regs.sp[-1] = INT_TO_JSVAL(length); - } else { - i = -2; - goto do_getprop_with_lval; - } - } else { - i = -2; - goto do_getprop_with_lval; - } -END_CASE(JSOP_LENGTH) - -BEGIN_CASE(JSOP_CALLPROP) -{ - JSObject *aobj; - PropertyCacheEntry *entry; - - lval = FETCH_OPND(-1); - if (!JSVAL_IS_PRIMITIVE(lval)) { - obj = JSVAL_TO_OBJECT(lval); - } else { - JSProtoKey protoKey; - if (JSVAL_IS_STRING(lval)) { - protoKey = JSProto_String; - } else if (JSVAL_IS_NUMBER(lval)) { - protoKey = JSProto_Number; - } else if (JSVAL_IS_BOOLEAN(lval)) { - protoKey = JSProto_Boolean; - } else { - JS_ASSERT(JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)); - js_ReportIsNullOrUndefined(cx, -1, lval, NULL); - goto error; - } - if (!js_GetClassPrototype(cx, NULL, protoKey, &obj)) - goto error; - } - - aobj = js_GetProtoIfDenseArray(obj); - - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, aobj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(0, aobj, obj2, entry); - if (entry->vword.isObject()) { - rval = entry->vword.toJsval(); - } else if (entry->vword.isSlot()) { - slot = entry->vword.toSlot(); - JS_ASSERT(slot < obj2->scope()->freeslot); - rval = obj2->lockedGetSlot(slot); - } else { - JS_ASSERT(entry->vword.isSprop()); - sprop = entry->vword.toSprop(); - NATIVE_GET(cx, obj, obj2, sprop, JSGET_NO_METHOD_BARRIER, &rval); - } - STORE_OPND(-1, rval); - PUSH_OPND(lval); - goto end_callprop; - } - - /* - * Cache miss: use the immediate atom that was loaded for us under - * PropertyCache::test. - */ - id = ATOM_TO_JSID(atom); - PUSH(JSVAL_NULL); - if (!JSVAL_IS_PRIMITIVE(lval)) { - if (!js_GetMethod(cx, obj, id, - JS_LIKELY(aobj->map->ops->getProperty == js_GetProperty) - ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER - : JSGET_NO_METHOD_BARRIER, - &rval)) { - goto error; - } - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - STORE_OPND(-2, rval); - } else { - JS_ASSERT(obj->map->ops->getProperty == js_GetProperty); - if (!js_GetPropertyHelper(cx, obj, id, - JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER, - &rval)) { - goto error; - } - STORE_OPND(-1, lval); - STORE_OPND(-2, rval); - } - - end_callprop: - /* Wrap primitive lval in object clothing if necessary. */ - if (JSVAL_IS_PRIMITIVE(lval)) { - /* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=412571 */ - if (!VALUE_IS_FUNCTION(cx, rval) || - (obj = JSVAL_TO_OBJECT(rval), - fun = GET_FUNCTION_PRIVATE(cx, obj), - !PRIMITIVE_THIS_TEST(fun, lval))) { - if (!js_PrimitiveToObject(cx, ®s.sp[-1])) - goto error; - } - } -#if JS_HAS_NO_SUCH_METHOD - if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) { - LOAD_ATOM(0); - regs.sp[-2] = ATOM_KEY(atom); - if (!js_OnUnknownMethod(cx, regs.sp - 2)) - goto error; - } -#endif -} -END_CASE(JSOP_CALLPROP) - -BEGIN_CASE(JSOP_UNBRAND) - JS_ASSERT(regs.sp - fp->slots() >= 1); - lval = FETCH_OPND(-1); - obj = JSVAL_TO_OBJECT(lval); - if (!obj->unbrand(cx)) - goto error; -END_CASE(JSOP_UNBRAND) - -BEGIN_CASE(JSOP_SETNAME) -BEGIN_CASE(JSOP_SETPROP) -BEGIN_CASE(JSOP_SETMETHOD) - rval = FETCH_OPND(-1); - JS_ASSERT_IF(op == JSOP_SETMETHOD, VALUE_IS_FUNCTION(cx, rval)); - lval = FETCH_OPND(-2); - JS_ASSERT_IF(op == JSOP_SETNAME, !JSVAL_IS_PRIMITIVE(lval)); - VALUE_TO_OBJECT(cx, -2, lval, obj); - - do { - PropertyCache *cache = &JS_PROPERTY_CACHE(cx); - PropertyCacheEntry *entry = NULL; - atom = NULL; - - /* - * Probe the property cache, specializing for two important - * set-property cases. First: - * - * function f(a, b, c) { - * var o = {p:a, q:b, r:c}; - * return o; - * } - * - * or similar real-world cases, which evolve a newborn native - * object predicatably through some bounded number of property - * additions. And second: - * - * o.p = x; - * - * in a frequently executed method or loop body, where p will - * (possibly after the first iteration) always exist in native - * object o. - */ - if (cache->testForSet(cx, regs.pc, obj, &entry, &obj2, &atom)) { - /* - * Fast property cache hit, only partially confirmed by - * testForSet. We know that the entry applies to regs.pc and - * that obj's shape matches. - * - * The entry predicts either a new property to be added - * directly to obj by this set, or on an existing "own" - * property, or on a prototype property that has a setter. - */ - JS_ASSERT(entry->vword.isSprop()); - sprop = entry->vword.toSprop(); - JS_ASSERT_IF(sprop->isDataDescriptor(), sprop->writable()); - JS_ASSERT_IF(sprop->hasSlot(), entry->vcapTag() == 0); - - JSScope *scope = obj->scope(); - JS_ASSERT(!scope->sealed()); - - /* - * Fastest path: check whether the cached sprop is already - * in scope and call NATIVE_SET and break to get out of the - * do-while(0). But we can call NATIVE_SET only if obj owns - * scope or sprop is shared. - */ - bool checkForAdd; - if (!sprop->hasSlot()) { - if (entry->vcapTag() == 0 || - ((obj2 = obj->getProto()) && - obj2->isNative() && - obj2->shape() == entry->vshape())) { - goto fast_set_propcache_hit; - } - - /* The cache entry doesn't apply. vshape mismatch. */ - checkForAdd = false; - } else if (!scope->isSharedEmpty()) { - if (sprop == scope->lastProperty() || scope->hasProperty(sprop)) { - fast_set_propcache_hit: - PCMETER(cache->pchits++); - PCMETER(cache->setpchits++); - NATIVE_SET(cx, obj, sprop, entry, &rval); - break; - } - checkForAdd = sprop->hasSlot() && sprop->parent == scope->lastProperty(); - } else { - /* - * We check that cx own obj here and will continue to - * own it after js_GetMutableScope returns so we can - * continue to skip JS_UNLOCK_OBJ calls. - */ - JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); - scope = js_GetMutableScope(cx, obj); - JS_ASSERT(CX_OWNS_OBJECT_TITLE(cx, obj)); - if (!scope) - goto error; - checkForAdd = !sprop->parent; - } - - if (checkForAdd && - entry->vshape() == rt->protoHazardShape && - sprop->hasDefaultSetter() && - (slot = sprop->slot) == scope->freeslot) { - /* - * Fast path: adding a plain old property that was once - * at the frontier of the property tree, whose slot is - * next to claim among the allocated slots in obj, - * where scope->table has not been created yet. - * - * We may want to remove hazard conditions above and - * inline compensation code here, depending on - * real-world workloads. - */ - PCMETER(cache->pchits++); - PCMETER(cache->addpchits++); - - if (slot < obj->numSlots()) { - ++scope->freeslot; - } else { - if (!js_AllocSlot(cx, obj, &slot)) - goto error; - JS_ASSERT(slot + 1 == scope->freeslot); - } - - /* - * If this obj's number of reserved slots differed, or - * if something created a hash table for scope, we must - * pay the price of JSScope::putProperty. - * - * (A built-in object with a pre-allocated but not fixed - * population of reserved slots hook can cause scopes of the - * same shape to have different freeslot values. Arguments, - * Block, Call, and certain Function objects pre-allocate - * reserveds lots this way. This is what causes the slot != - * sprop->slot case. See js_GetMutableScope. FIXME 558451) - */ - if (slot == sprop->slot && !scope->table) { - scope->extend(cx, sprop); - } else { - JSScopeProperty *sprop2 = - scope->putProperty(cx, sprop->id, - sprop->getter(), sprop->setter(), - slot, sprop->attributes(), - sprop->getFlags(), sprop->shortid); - if (!sprop2) { - js_FreeSlot(cx, obj, slot); - goto error; - } - sprop = sprop2; - } - - /* - * No method change check here because here we are - * adding a new property, not updating an existing - * slot's value that might contain a method of a - * branded scope. - */ - TRACE_2(SetPropHit, entry, sprop); - obj->lockedSetSlot(slot, rval); - - /* - * Purge the property cache of the id we may have just - * shadowed in obj's scope and proto chains. We do this - * after unlocking obj's scope to avoid lock nesting. - */ - js_PurgeScopeChain(cx, obj, sprop->id); - break; - } - PCMETER(cache->setpcmisses++); - atom = NULL; - } else if (!atom) { - /* - * Slower property cache hit, fully confirmed by testForSet (in - * the slow path, via fullTest). - */ - ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - sprop = NULL; - if (obj == obj2) { - sprop = entry->vword.toSprop(); - JS_ASSERT(sprop->writable()); - JS_ASSERT(!obj2->scope()->sealed()); - NATIVE_SET(cx, obj, sprop, entry, &rval); - } - if (sprop) - break; - } - - if (!atom) - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - if (entry && JS_LIKELY(obj->map->ops->setProperty == js_SetProperty)) { - uintN defineHow; - if (op == JSOP_SETMETHOD) - defineHow = JSDNP_CACHE_RESULT | JSDNP_SET_METHOD; - else if (op == JSOP_SETNAME) - defineHow = JSDNP_CACHE_RESULT | JSDNP_UNQUALIFIED; - else - defineHow = JSDNP_CACHE_RESULT; - if (!js_SetPropertyHelper(cx, obj, id, defineHow, &rval)) - goto error; - } else { - if (!obj->setProperty(cx, id, &rval)) - goto error; - ABORT_RECORDING(cx, "Non-native set"); - } - } while (0); -END_SET_CASE_STORE_RVAL(JSOP_SETPROP, 2); - -BEGIN_CASE(JSOP_GETELEM) - /* Open-coded ELEMENT_OP optimized for strings and dense arrays. */ - lval = FETCH_OPND(-2); - rval = FETCH_OPND(-1); - if (JSVAL_IS_STRING(lval) && JSVAL_IS_INT(rval)) { - str = JSVAL_TO_STRING(lval); - i = JSVAL_TO_INT(rval); - if ((size_t)i < str->length()) { - str = JSString::getUnitString(cx, str, size_t(i)); - if (!str) - goto error; - rval = STRING_TO_JSVAL(str); - goto end_getelem; - } - } - - VALUE_TO_OBJECT(cx, -2, lval, obj); - if (JSVAL_IS_INT(rval)) { - if (obj->isDenseArray()) { - jsuint idx = jsuint(JSVAL_TO_INT(rval)); - - if (idx < obj->getArrayLength() && - idx < obj->getDenseArrayCapacity()) { - rval = obj->getDenseArrayElement(idx); - if (rval != JSVAL_HOLE) - goto end_getelem; - - /* Reload rval from the stack in the rare hole case. */ - rval = FETCH_OPND(-1); - } - } else if (obj->isArguments() -#ifdef JS_TRACER - && !GetArgsPrivateNative(obj) -#endif - ) { - uint32 arg = uint32(JSVAL_TO_INT(rval)); - - if (arg < obj->getArgsLength()) { - JSStackFrame *afp = (JSStackFrame *) obj->getPrivate(); - if (afp) { - rval = afp->argv[arg]; - goto end_getelem; - } - - rval = obj->getArgsElement(arg); - if (rval != JSVAL_HOLE) - goto end_getelem; - rval = FETCH_OPND(-1); - } - } - id = INT_JSVAL_TO_JSID(rval); - } else { - if (!js_InternNonIntElementId(cx, obj, rval, &id)) - goto error; - } - - if (!obj->getProperty(cx, id, &rval)) - goto error; - end_getelem: - regs.sp--; - STORE_OPND(-1, rval); -END_CASE(JSOP_GETELEM) - -BEGIN_CASE(JSOP_CALLELEM) - ELEMENT_OP(-1, js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, &rval)); -#if JS_HAS_NO_SUCH_METHOD - if (JS_UNLIKELY(JSVAL_IS_VOID(rval))) { - regs.sp[-2] = regs.sp[-1]; - regs.sp[-1] = OBJECT_TO_JSVAL(obj); - if (!js_OnUnknownMethod(cx, regs.sp - 2)) - goto error; - } else -#endif - { - STORE_OPND(-2, rval); - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - } -END_CASE(JSOP_CALLELEM) - -BEGIN_CASE(JSOP_SETELEM) - rval = FETCH_OPND(-1); - FETCH_OBJECT(cx, -3, lval, obj); - FETCH_ELEMENT_ID(obj, -2, id); - do { - if (obj->isDenseArray() && JSID_IS_INT(id)) { - jsuint length; - - length = obj->getDenseArrayCapacity(); - i = JSID_TO_INT(id); - if ((jsuint)i < length) { - if (obj->getDenseArrayElement(i) == JSVAL_HOLE) { - if (js_PrototypeHasIndexedProperties(cx, obj)) - break; - if ((jsuint)i >= obj->getArrayLength()) - obj->setDenseArrayLength(i + 1); - obj->incDenseArrayCountBy(1); - } - obj->setDenseArrayElement(i, rval); - goto end_setelem; - } - } - } while (0); - if (!obj->setProperty(cx, id, &rval)) - goto error; - end_setelem: -END_SET_CASE_STORE_RVAL(JSOP_SETELEM, 3) - -BEGIN_CASE(JSOP_ENUMELEM) - /* Funky: the value to set is under the [obj, id] pair. */ - rval = FETCH_OPND(-3); - FETCH_OBJECT(cx, -2, lval, obj); - FETCH_ELEMENT_ID(obj, -1, id); - if (!obj->setProperty(cx, id, &rval)) - goto error; - regs.sp -= 3; -END_CASE(JSOP_ENUMELEM) - -BEGIN_CASE(JSOP_NEW) - /* Get immediate argc and find the constructor function. */ - argc = GET_ARGC(regs.pc); - vp = regs.sp - (2 + argc); - JS_ASSERT(vp >= StackBase(fp)); - - /* - * Assign lval, obj, and fun exactly as the code at inline_call: expects to - * find them, to avoid nesting a js_Interpret call via js_InvokeConstructor. - */ - lval = *vp; - if (VALUE_IS_FUNCTION(cx, lval)) { - obj = JSVAL_TO_OBJECT(lval); - fun = GET_FUNCTION_PRIVATE(cx, obj); - if (FUN_INTERPRETED(fun)) { - /* Root as we go using vp[1]. */ - if (!obj->getProperty(cx, - ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), - &vp[1])) { - goto error; - } - rval = vp[1]; - obj2 = NewObject(cx, &js_ObjectClass, - JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL, - obj->getParent()); - if (!obj2) - goto error; - - if (fun->u.i.script->isEmpty()) { - *vp = OBJECT_TO_JSVAL(obj2); - regs.sp = vp + 1; - goto end_new; - } - - vp[1] = OBJECT_TO_JSVAL(obj2); - flags = JSFRAME_CONSTRUCTING; - goto inline_call; - } - } - - if (!js_InvokeConstructor(cx, InvokeArgsGuard(vp, argc))) - goto error; - regs.sp = vp + 1; - CHECK_INTERRUPT_HANDLER(); - TRACE_0(NativeCallComplete); - - end_new: -END_CASE(JSOP_NEW) - -BEGIN_CASE(JSOP_CALL) -BEGIN_CASE(JSOP_EVAL) -BEGIN_CASE(JSOP_APPLY) - argc = GET_ARGC(regs.pc); - vp = regs.sp - (argc + 2); - - lval = *vp; - if (VALUE_IS_FUNCTION(cx, lval)) { - obj = JSVAL_TO_OBJECT(lval); - fun = GET_FUNCTION_PRIVATE(cx, obj); - - /* Clear frame flags since this is not a constructor call. */ - flags = 0; - if (FUN_INTERPRETED(fun)) - inline_call: - { - JSScript *newscript = fun->u.i.script; - if (JS_UNLIKELY(newscript->isEmpty())) { - *vp = JSVAL_VOID; - regs.sp = vp + 1; - goto end_call; - } - - /* Restrict recursion of lightweight functions. */ - if (JS_UNLIKELY(inlineCallCount >= JS_MAX_INLINE_CALL_COUNT)) { - js_ReportOverRecursed(cx); - goto error; - } - - /* - * Get pointer to new frame/slots, without changing global state. - * Initialize missing args if there are any. - */ - StackSpace &stack = cx->stack(); - uintN nfixed = newscript->nslots; - uintN funargs = fun->nargs; - JSStackFrame *newfp; - if (argc < funargs) { - uintN missing = funargs - argc; - newfp = stack.getInlineFrame(cx, regs.sp, missing, nfixed); - if (!newfp) - goto error; - for (jsval *v = regs.sp, *end = v + missing; v != end; ++v) - *v = JSVAL_VOID; - } else { - newfp = stack.getInlineFrame(cx, regs.sp, 0, nfixed); - if (!newfp) - goto error; - } - - /* Initialize stack frame. */ - newfp->callobj = NULL; - newfp->argsobj = NULL; - newfp->script = newscript; - newfp->fun = fun; - newfp->argc = argc; - newfp->argv = vp + 2; - newfp->rval = JSVAL_VOID; - newfp->annotation = NULL; - newfp->scopeChain = parent = obj->getParent(); - newfp->flags = flags; - newfp->blockChain = NULL; - if (JS_LIKELY(newscript->staticLevel < JS_DISPLAY_SIZE)) { - JSStackFrame **disp = &cx->display[newscript->staticLevel]; - newfp->displaySave = *disp; - *disp = newfp; - } - JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags)); - newfp->thisv = vp[1]; - newfp->imacpc = NULL; - - /* Push void to initialize local variables. */ - jsval *newsp = StackBase(newfp); - for (jsval *v = newfp->slots(); v != newsp; ++v) - *v = JSVAL_VOID; - - /* Switch version if currentVersion wasn't overridden. */ - newfp->callerVersion = (JSVersion) cx->version; - if (JS_LIKELY(cx->version == currentVersion)) { - currentVersion = (JSVersion) newscript->version; - if (JS_UNLIKELY(currentVersion != cx->version)) - js_SetVersion(cx, currentVersion); - } - - /* Push the frame. */ - stack.pushInlineFrame(cx, fp, regs.pc, newfp); - - /* Initializer regs after pushInlineFrame snapshots pc. */ - regs.pc = newscript->code; - regs.sp = newsp; - - /* Import into locals. */ - JS_ASSERT(newfp == cx->fp); - fp = newfp; - script = newscript; - atoms = script->atomMap.vector; - - /* Now that the new frame is rooted, maybe create a call object. */ - if (fun->isHeavyweight() && !js_GetCallObject(cx, fp)) - goto error; - - /* Call the debugger hook if present. */ - if (JSInterpreterHook hook = cx->debugHooks->callHook) { - fp->hookData = hook(cx, fp, JS_TRUE, 0, - cx->debugHooks->callHookData); - CHECK_INTERRUPT_HANDLER(); - } else { - fp->hookData = NULL; - } - - inlineCallCount++; - JS_RUNTIME_METER(rt, inlineCalls); - - DTrace::enterJSFun(cx, fp, fun, fp->down, fp->argc, fp->argv); - -#ifdef JS_TRACER - if (TraceRecorder *tr = TRACE_RECORDER(cx)) { - AbortableRecordingStatus status = tr->record_EnterFrame(inlineCallCount); - RESTORE_INTERP_VARS(); - if (StatusAbortsRecorderIfActive(status)) { - if (TRACE_RECORDER(cx)) { - JS_ASSERT(TRACE_RECORDER(cx) == tr); - AbortRecording(cx, "record_EnterFrame failed"); - } - if (status == ARECORD_ERROR) - goto error; - } - } else if (fp->script == fp->down->script && - *fp->down->savedPC == JSOP_CALL && - *regs.pc == JSOP_TRACE) { - MONITOR_BRANCH(Record_EnterFrame); - } -#endif - - /* Load first op and dispatch it (safe since JSOP_STOP). */ - op = (JSOp) *regs.pc; - DO_OP(); - } - - if (fun->flags & JSFUN_FAST_NATIVE) { - DTrace::enterJSFun(cx, NULL, fun, fp, argc, vp + 2, &lval); - - JS_ASSERT(fun->u.n.extra == 0); - JS_ASSERT(JSVAL_IS_OBJECT(vp[1]) || - PRIMITIVE_THIS_TEST(fun, vp[1])); - ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp); - DTrace::exitJSFun(cx, NULL, fun, *vp, &lval); - regs.sp = vp + 1; - if (!ok) - goto error; - TRACE_0(NativeCallComplete); - goto end_call; - } - } - - ok = js_Invoke(cx, InvokeArgsGuard(vp, argc), 0); - regs.sp = vp + 1; - CHECK_INTERRUPT_HANDLER(); - if (!ok) - goto error; - JS_RUNTIME_METER(rt, nonInlineCalls); - TRACE_0(NativeCallComplete); - - end_call: -END_CASE(JSOP_CALL) - -BEGIN_CASE(JSOP_SETCALL) - argc = GET_ARGC(regs.pc); - vp = regs.sp - argc - 2; - if (js_Invoke(cx, InvokeArgsGuard(vp, argc), 0)) - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS); - goto error; -END_CASE(JSOP_SETCALL) - -BEGIN_CASE(JSOP_NAME) -BEGIN_CASE(JSOP_CALLNAME) -{ - PropertyCacheEntry *entry; - - obj = fp->scopeChain; - - JS_PROPERTY_CACHE(cx).test(cx, regs.pc, obj, obj2, entry, atom); - if (!atom) { - ASSERT_VALID_PROPERTY_CACHE_HIT(0, obj, obj2, entry); - if (entry->vword.isObject()) { - rval = entry->vword.toJsval(); - goto do_push_rval; - } - - if (entry->vword.isSlot()) { - slot = entry->vword.toSlot(); - JS_ASSERT(slot < obj2->scope()->freeslot); - rval = obj2->lockedGetSlot(slot); - goto do_push_rval; - } - - JS_ASSERT(entry->vword.isSprop()); - sprop = entry->vword.toSprop(); - goto do_native_get; - } - - id = ATOM_TO_JSID(atom); - if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop)) - goto error; - if (!prop) { - /* Kludge to allow (typeof foo == "undefined") tests. */ - endpc = script->code + script->length; - op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH); - if (op2 == JSOP_TYPEOF) { - PUSH_OPND(JSVAL_VOID); - len = JSOP_NAME_LENGTH; - DO_NEXT_OP(len); - } - goto atom_not_defined; - } - - /* Take the slow path if prop was not found in a native object. */ - if (!obj->isNative() || !obj2->isNative()) { - obj2->dropProperty(cx, prop); - if (!obj->getProperty(cx, id, &rval)) - goto error; - } else { - sprop = (JSScopeProperty *)prop; - do_native_get: - NATIVE_GET(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, &rval); - JS_UNLOCK_OBJ(cx, obj2); - } - - do_push_rval: - PUSH_OPND(rval); - if (op == JSOP_CALLNAME) - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -} -END_CASE(JSOP_NAME) - -BEGIN_CASE(JSOP_UINT16) - i = (jsint) GET_UINT16(regs.pc); - rval = INT_TO_JSVAL(i); - PUSH_OPND(rval); -END_CASE(JSOP_UINT16) - -BEGIN_CASE(JSOP_UINT24) - i = (jsint) GET_UINT24(regs.pc); - rval = INT_TO_JSVAL(i); - PUSH_OPND(rval); -END_CASE(JSOP_UINT24) - -BEGIN_CASE(JSOP_INT8) - i = GET_INT8(regs.pc); - rval = INT_TO_JSVAL(i); - PUSH_OPND(rval); -END_CASE(JSOP_INT8) - -BEGIN_CASE(JSOP_INT32) - i = GET_INT32(regs.pc); - rval = INT_TO_JSVAL(i); - PUSH_OPND(rval); -END_CASE(JSOP_INT32) - -BEGIN_CASE(JSOP_INDEXBASE) - /* - * Here atoms can exceed script->atomMap.length as we use atoms as a - * segment register for object literals as well. - */ - atoms += GET_INDEXBASE(regs.pc); -END_CASE(JSOP_INDEXBASE) - -BEGIN_CASE(JSOP_INDEXBASE1) -BEGIN_CASE(JSOP_INDEXBASE2) -BEGIN_CASE(JSOP_INDEXBASE3) - atoms += (op - JSOP_INDEXBASE1 + 1) << 16; -END_CASE(JSOP_INDEXBASE3) - -BEGIN_CASE(JSOP_RESETBASE0) -BEGIN_CASE(JSOP_RESETBASE) - atoms = script->atomMap.vector; -END_CASE(JSOP_RESETBASE) - -BEGIN_CASE(JSOP_DOUBLE) - JS_ASSERT(!fp->imacpc); - JS_ASSERT(size_t(atoms - script->atomMap.vector) < script->atomMap.length); - /* FALL THROUGH */ - -BEGIN_CASE(JSOP_STRING) - LOAD_ATOM(0); - PUSH_OPND(ATOM_KEY(atom)); -END_CASE(JSOP_DOUBLE) - -BEGIN_CASE(JSOP_OBJECT) - LOAD_OBJECT(0); - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_OBJECT) - -BEGIN_CASE(JSOP_REGEXP) { - /* - * Push a regexp object cloned from the regexp literal object mapped by the - * bytecode at pc. ES5 finally fixed this bad old ES3 design flaw which was - * flouted by many browser-based implementations. - * - * We avoid the js_GetScopeChain call here and pass fp->scopeChain as - * js_GetClassPrototype uses the latter only to locate the global. - */ - index = GET_FULL_INDEX(0); - JSObject *proto; - if (!js_GetClassPrototype(cx, fp->scopeChain, JSProto_RegExp, &proto)) - goto error; - JS_ASSERT(proto); - obj = js_CloneRegExpObject(cx, script->getRegExp(index), proto); - if (!obj) - goto error; - rval = OBJECT_TO_JSVAL(obj); - PUSH_OPND(rval); -} -END_CASE(JSOP_REGEXP) - -BEGIN_CASE(JSOP_ZERO) - PUSH_OPND(JSVAL_ZERO); -END_CASE(JSOP_ZERO) - -BEGIN_CASE(JSOP_ONE) - PUSH_OPND(JSVAL_ONE); -END_CASE(JSOP_ONE) - -BEGIN_CASE(JSOP_NULL) - PUSH_OPND(JSVAL_NULL); -END_CASE(JSOP_NULL) - -BEGIN_CASE(JSOP_FALSE) - PUSH_OPND(JSVAL_FALSE); -END_CASE(JSOP_FALSE) - -BEGIN_CASE(JSOP_TRUE) - PUSH_OPND(JSVAL_TRUE); -END_CASE(JSOP_TRUE) - -BEGIN_CASE(JSOP_TABLESWITCH) - pc2 = regs.pc; - len = GET_JUMP_OFFSET(pc2); - - /* - * ECMAv2+ forbids conversion of discriminant, so we will skip to the - * default case if the discriminant isn't already an int jsval. (This - * opcode is emitted only for dense jsint-domain switches.) - */ - rval = POP_OPND(); - if (JSVAL_IS_INT(rval)) { - i = JSVAL_TO_INT(rval); - } else if (JSVAL_IS_DOUBLE(rval) && *JSVAL_TO_DOUBLE(rval) == 0) { - /* Treat -0 (double) as 0. */ - i = 0; - } else { - DO_NEXT_OP(len); - } - - pc2 += JUMP_OFFSET_LEN; - low = GET_JUMP_OFFSET(pc2); - pc2 += JUMP_OFFSET_LEN; - high = GET_JUMP_OFFSET(pc2); - - i -= low; - if ((jsuint)i < (jsuint)(high - low + 1)) { - pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i; - off = (jsint) GET_JUMP_OFFSET(pc2); - if (off) - len = off; - } -END_VARLEN_CASE - -BEGIN_CASE(JSOP_TABLESWITCHX) - pc2 = regs.pc; - len = GET_JUMPX_OFFSET(pc2); - - /* - * ECMAv2+ forbids conversion of discriminant, so we will skip to the - * default case if the discriminant isn't already an int jsval. (This - * opcode is emitted only for dense jsint-domain switches.) - */ - rval = POP_OPND(); - if (JSVAL_IS_INT(rval)) { - i = JSVAL_TO_INT(rval); - } else if (JSVAL_IS_DOUBLE(rval) && *JSVAL_TO_DOUBLE(rval) == 0) { - /* Treat -0 (double) as 0. */ - i = 0; - } else { - DO_NEXT_OP(len); - } - - pc2 += JUMPX_OFFSET_LEN; - low = GET_JUMP_OFFSET(pc2); - pc2 += JUMP_OFFSET_LEN; - high = GET_JUMP_OFFSET(pc2); - - i -= low; - if ((jsuint)i < (jsuint)(high - low + 1)) { - pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i; - off = (jsint) GET_JUMPX_OFFSET(pc2); - if (off) - len = off; - } -END_VARLEN_CASE - -BEGIN_CASE(JSOP_LOOKUPSWITCHX) - off = JUMPX_OFFSET_LEN; - goto do_lookup_switch; - -BEGIN_CASE(JSOP_LOOKUPSWITCH) - off = JUMP_OFFSET_LEN; - - do_lookup_switch: - /* - * JSOP_LOOKUPSWITCH and JSOP_LOOKUPSWITCHX are never used if any atom - * index in it would exceed 64K limit. - */ - JS_ASSERT(!fp->imacpc); - JS_ASSERT(atoms == script->atomMap.vector); - pc2 = regs.pc; - lval = POP_OPND(); - - if (!JSVAL_IS_PRIMITIVE(lval)) - goto end_lookup_switch; - - pc2 += off; - npairs = (jsint) GET_UINT16(pc2); - pc2 += UINT16_LEN; - JS_ASSERT(npairs); /* empty switch uses JSOP_TABLESWITCH */ - -#define SEARCH_PAIRS(MATCH_CODE) \ - for (;;) { \ - JS_ASSERT(GET_INDEX(pc2) < script->atomMap.length); \ - atom = atoms[GET_INDEX(pc2)]; \ - rval = ATOM_KEY(atom); \ - MATCH_CODE \ - pc2 += INDEX_LEN; \ - if (match) \ - break; \ - pc2 += off; \ - if (--npairs == 0) { \ - pc2 = regs.pc; \ - break; \ - } \ - } - - if (JSVAL_IS_STRING(lval)) { - str = JSVAL_TO_STRING(lval); - SEARCH_PAIRS( - match = (JSVAL_IS_STRING(rval) && - ((str2 = JSVAL_TO_STRING(rval)) == str || - js_EqualStrings(str2, str))); - ) - } else if (JSVAL_IS_DOUBLE(lval)) { - d = *JSVAL_TO_DOUBLE(lval); - SEARCH_PAIRS( - match = (JSVAL_IS_DOUBLE(rval) && - *JSVAL_TO_DOUBLE(rval) == d); - ) - } else { - SEARCH_PAIRS( - match = (lval == rval); - ) - } -#undef SEARCH_PAIRS - - end_lookup_switch: - len = (op == JSOP_LOOKUPSWITCH) - ? GET_JUMP_OFFSET(pc2) - : GET_JUMPX_OFFSET(pc2); -END_VARLEN_CASE - -BEGIN_CASE(JSOP_TRAP) -{ - JSTrapStatus status; - - status = JS_HandleTrap(cx, script, regs.pc, &rval); - switch (status) { - case JSTRAP_ERROR: - goto error; - case JSTRAP_RETURN: - fp->rval = rval; - ok = JS_TRUE; - goto forced_return; - case JSTRAP_THROW: - cx->throwing = JS_TRUE; - cx->exception = rval; - goto error; - default: - break; - } - JS_ASSERT(status == JSTRAP_CONTINUE); - CHECK_INTERRUPT_HANDLER(); - JS_ASSERT(JSVAL_IS_INT(rval)); - op = (JSOp) JSVAL_TO_INT(rval); - JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT); - DO_OP(); -} - -BEGIN_CASE(JSOP_ARGUMENTS) - if (!js_GetArgsValue(cx, fp, &rval)) - goto error; - PUSH_OPND(rval); -END_CASE(JSOP_ARGUMENTS) - -BEGIN_CASE(JSOP_ARGSUB) - id = INT_TO_JSID(GET_ARGNO(regs.pc)); - if (!js_GetArgsProperty(cx, fp, id, &rval)) - goto error; - PUSH_OPND(rval); -END_CASE(JSOP_ARGSUB) - -BEGIN_CASE(JSOP_ARGCNT) - id = ATOM_TO_JSID(rt->atomState.lengthAtom); - if (!js_GetArgsProperty(cx, fp, id, &rval)) - goto error; - PUSH_OPND(rval); -END_CASE(JSOP_ARGCNT) - -BEGIN_CASE(JSOP_GETARG) -BEGIN_CASE(JSOP_CALLARG) - slot = GET_ARGNO(regs.pc); - JS_ASSERT(slot < fp->fun->nargs); - METER_SLOT_OP(op, slot); - PUSH_OPND(fp->argv[slot]); - if (op == JSOP_CALLARG) - PUSH_OPND(JSVAL_NULL); -END_CASE(JSOP_GETARG) - -BEGIN_CASE(JSOP_SETARG) - slot = GET_ARGNO(regs.pc); - JS_ASSERT(slot < fp->fun->nargs); - METER_SLOT_OP(op, slot); - vp = &fp->argv[slot]; - *vp = FETCH_OPND(-1); -END_SET_CASE(JSOP_SETARG) - -BEGIN_CASE(JSOP_GETLOCAL) - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < script->nslots); - PUSH_OPND(fp->slots()[slot]); -END_CASE(JSOP_GETLOCAL) - -BEGIN_CASE(JSOP_CALLLOCAL) - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < script->nslots); - PUSH_OPND(fp->slots()[slot]); - PUSH_OPND(JSVAL_NULL); -END_CASE(JSOP_CALLLOCAL) - -BEGIN_CASE(JSOP_SETLOCAL) - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < script->nslots); - vp = &fp->slots()[slot]; - *vp = FETCH_OPND(-1); -END_SET_CASE(JSOP_SETLOCAL) - -BEGIN_CASE(JSOP_GETUPVAR) -BEGIN_CASE(JSOP_CALLUPVAR) -{ - JSUpvarArray *uva = script->upvars(); - - index = GET_UINT16(regs.pc); - JS_ASSERT(index < uva->length); - - rval = js_GetUpvar(cx, script->staticLevel, uva->vector[index]); - PUSH_OPND(rval); - - if (op == JSOP_CALLUPVAR) - PUSH_OPND(JSVAL_NULL); -} -END_CASE(JSOP_GETUPVAR) - -BEGIN_CASE(JSOP_GETUPVAR_DBG) -BEGIN_CASE(JSOP_CALLUPVAR_DBG) - fun = fp->fun; - JS_ASSERT(FUN_KIND(fun) == JSFUN_INTERPRETED); - JS_ASSERT(fun->u.i.wrapper); - - /* Scope for tempPool mark and local names allocation in it. */ - { - void *mark = JS_ARENA_MARK(&cx->tempPool); - jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool); - if (!names) - goto error; - - index = fun->countArgsAndVars() + GET_UINT16(regs.pc); - atom = JS_LOCAL_NAME_TO_ATOM(names[index]); - id = ATOM_TO_JSID(atom); - - ok = js_FindProperty(cx, id, &obj, &obj2, &prop); - JS_ARENA_RELEASE(&cx->tempPool, mark); - if (!ok) - goto error; - } - - if (!prop) - goto atom_not_defined; - - /* Minimize footprint with generic code instead of NATIVE_GET. */ - obj2->dropProperty(cx, prop); - vp = regs.sp; - PUSH_OPND(JSVAL_NULL); - if (!obj->getProperty(cx, id, vp)) - goto error; - - if (op == JSOP_CALLUPVAR_DBG) - PUSH_OPND(JSVAL_NULL); -END_CASE(JSOP_GETUPVAR_DBG) - -BEGIN_CASE(JSOP_GETDSLOT) -BEGIN_CASE(JSOP_CALLDSLOT) - JS_ASSERT(fp->argv); - obj = JSVAL_TO_OBJECT(fp->argv[-2]); - JS_ASSERT(obj); - JS_ASSERT(obj->dslots); - - index = GET_UINT16(regs.pc); - JS_ASSERT(JS_INITIAL_NSLOTS + index < jsatomid(obj->dslots[-1])); - JS_ASSERT_IF(obj->scope()->object == obj, - JS_INITIAL_NSLOTS + index < obj->scope()->freeslot); - - PUSH_OPND(obj->dslots[index]); - if (op == JSOP_CALLDSLOT) - PUSH_OPND(JSVAL_NULL); -END_CASE(JSOP_GETDSLOT) - -BEGIN_CASE(JSOP_GETGVAR) -BEGIN_CASE(JSOP_CALLGVAR) - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < GlobalVarCount(fp)); - METER_SLOT_OP(op, slot); - lval = fp->slots()[slot]; - if (JSVAL_IS_NULL(lval)) { - op = (op == JSOP_GETGVAR) ? JSOP_NAME : JSOP_CALLNAME; - DO_OP(); - } - JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); - obj = cx->activeCallStack()->getInitialVarObj(); - slot = JSVAL_TO_INT(lval); - rval = obj->getSlotMT(cx, slot); - PUSH_OPND(rval); - if (op == JSOP_CALLGVAR) - PUSH_OPND(JSVAL_NULL); -END_CASE(JSOP_GETGVAR) - -BEGIN_CASE(JSOP_SETGVAR) - slot = GET_SLOTNO(regs.pc); - JS_ASSERT(slot < GlobalVarCount(fp)); - METER_SLOT_OP(op, slot); - rval = FETCH_OPND(-1); - JS_ASSERT(fp->varobj(cx) == cx->activeCallStack()->getInitialVarObj()); - obj = cx->activeCallStack()->getInitialVarObj(); - lval = fp->slots()[slot]; - if (JSVAL_IS_NULL(lval)) { - /* - * Inline-clone and deoptimize JSOP_SETNAME code here because - * JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval] - * as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME. - */ -#ifdef JS_TRACER - if (TRACE_RECORDER(cx)) - AbortRecording(cx, "SETGVAR with NULL slot"); -#endif - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - if (!obj->setProperty(cx, id, &rval)) - goto error; - } else { - slot = JSVAL_TO_INT(lval); - JS_LOCK_OBJ(cx, obj); - JSScope *scope = obj->scope(); - if (!scope->methodWriteBarrier(cx, slot, rval)) { - JS_UNLOCK_SCOPE(cx, scope); - goto error; - } - obj->lockedSetSlot(slot, rval); - JS_UNLOCK_SCOPE(cx, scope); - } -END_SET_CASE(JSOP_SETGVAR) - -BEGIN_CASE(JSOP_DEFCONST) -BEGIN_CASE(JSOP_DEFVAR) - index = GET_INDEX(regs.pc); - atom = atoms[index]; - - /* - * index is relative to atoms at this point but for global var - * code below we need the absolute value. - */ - index += atoms - script->atomMap.vector; - obj = fp->varobj(cx); - JS_ASSERT(obj->map->ops->defineProperty == js_DefineProperty); - attrs = JSPROP_ENUMERATE; - if (!(fp->flags & JSFRAME_EVAL)) - attrs |= JSPROP_PERMANENT; - if (op == JSOP_DEFCONST) - attrs |= JSPROP_READONLY; - - /* Lookup id in order to check for redeclaration problems. */ - id = ATOM_TO_JSID(atom); - prop = NULL; - if (op == JSOP_DEFVAR) { - /* - * Redundant declaration of a |var|, even one for a non-writable - * property like |undefined| in ES5, does nothing. - */ - if (!obj->lookupProperty(cx, id, &obj2, &prop)) - goto error; - } else { - if (!js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop)) - goto error; - } - - /* Bind a variable only if it's not yet defined. */ - if (!prop) { - if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, JS_PropertyStub, JS_PropertyStub, - attrs, 0, 0, &prop)) { - goto error; - } - JS_ASSERT(prop); - obj2 = obj; - } - - /* - * Try to optimize a property we either just created, or found - * directly in the global object, that is permanent, has a slot, - * and has stub getter and setter, into a "fast global" accessed - * by the JSOP_*GVAR opcodes. - */ - if (!fp->fun && - index < GlobalVarCount(fp) && - obj2 == obj && - obj->isNative()) { - sprop = (JSScopeProperty *) prop; - if (!sprop->configurable() && - SPROP_HAS_VALID_SLOT(sprop, obj->scope()) && - sprop->hasDefaultGetterOrIsMethod() && - sprop->hasDefaultSetter()) { - /* - * Fast globals use frame variables to map the global name's atom - * index to the permanent varobj slot number, tagged as a jsval. - * The atom index for the global's name literal is identical to its - * variable index. - */ - fp->slots()[index] = INT_TO_JSVAL(sprop->slot); - } - } - - obj2->dropProperty(cx, prop); -END_CASE(JSOP_DEFVAR) - -BEGIN_CASE(JSOP_DEFFUN) -{ - JSPropertyOp getter, setter; - bool doSet; - JSObject *pobj; - JSProperty *prop; - uint32 old; - - /* - * A top-level function defined in Global or Eval code (see ECMA-262 - * Ed. 3), or else a SpiderMonkey extension: a named function statement in - * a compound statement (not at the top statement level of global code, or - * at the top level of a function body). - */ - LOAD_FUNCTION(0); - obj = FUN_OBJECT(fun); - - if (FUN_NULL_CLOSURE(fun)) { - /* - * Even a null closure needs a parent for principals finding. - * FIXME: bug 476950, although debugger users may also demand some kind - * of scope link for debugger-assisted eval-in-frame. - */ - obj2 = fp->scopeChain; - } else { - JS_ASSERT(!FUN_FLAT_CLOSURE(fun)); - - /* - * Inline js_GetScopeChain a bit to optimize for the case of a - * top-level function. - */ - if (!fp->blockChain) { - obj2 = fp->scopeChain; - } else { - obj2 = js_GetScopeChain(cx, fp); - if (!obj2) - goto error; - } - } - - /* - * If static link is not current scope, clone fun's object to link to the - * current scope via parent. We do this to enable sharing of compiled - * functions among multiple equivalent scopes, amortizing the cost of - * compilation over a number of executions. Examples include XUL scripts - * and event handlers shared among Firefox or other Mozilla app chrome - * windows, and user-defined JS functions precompiled and then shared among - * requests in server-side JS. - */ - if (obj->getParent() != obj2) { - obj = CloneFunctionObject(cx, fun, obj2); - if (!obj) - goto error; - } - - /* - * Protect obj from any GC hiding below JSObject::setProperty or - * JSObject::defineProperty. All paths from here must flow through the - * fp->scopeChain code below the parent->defineProperty call. - */ - MUST_FLOW_THROUGH("restore_scope"); - fp->scopeChain = obj; - - rval = OBJECT_TO_JSVAL(obj); - - /* - * ECMA requires functions defined when entering Eval code to be - * impermanent. - */ - attrs = (fp->flags & JSFRAME_EVAL) - ? JSPROP_ENUMERATE - : JSPROP_ENUMERATE | JSPROP_PERMANENT; - - /* - * Load function flags that are also property attributes. Getters and - * setters do not need a slot, their value is stored elsewhere in the - * property itself, not in obj slots. - */ - getter = setter = JS_PropertyStub; - flags = JSFUN_GSFLAG2ATTR(fun->flags); - if (flags) { - /* Function cannot be both getter a setter. */ - JS_ASSERT(flags == JSPROP_GETTER || flags == JSPROP_SETTER); - attrs |= flags | JSPROP_SHARED; - rval = JSVAL_VOID; - if (flags == JSPROP_GETTER) - getter = CastAsPropertyOp(obj); - else - setter = CastAsPropertyOp(obj); - } - - /* - * We define the function as a property of the variable object and not the - * current scope chain even for the case of function expression statements - * and functions defined by eval inside let or with blocks. - */ - parent = fp->varobj(cx); - JS_ASSERT(parent); - - /* - * Check for a const property of the same name -- or any kind of property - * if executing with the strict option. We check here at runtime as well - * as at compile-time, to handle eval as well as multiple HTML script tags. - */ - id = ATOM_TO_JSID(fun->atom); - prop = NULL; - ok = js_CheckRedeclaration(cx, parent, id, attrs, &pobj, &prop); - if (!ok) - goto restore_scope; - - /* - * We deviate from 10.1.2 in ECMA 262 v3 and under eval use for function - * declarations JSObject::setProperty, not JSObject::defineProperty, to - * preserve the JSOP_PERMANENT attribute of existing properties and make - * sure that such properties cannot be deleted. - * - * We also use JSObject::setProperty for the existing properties of Call - * objects with matching attributes to preserve the native getters and - * setters that store the value of the property in the interpreter frame, - * see bug 467495. - */ - doSet = (attrs == JSPROP_ENUMERATE); - JS_ASSERT_IF(doSet, fp->flags & JSFRAME_EVAL); - if (prop) { - if (parent == pobj && - parent->getClass() == &js_CallClass && - (old = ((JSScopeProperty *) prop)->attributes(), - !(old & (JSPROP_GETTER|JSPROP_SETTER)) && - (old & (JSPROP_ENUMERATE|JSPROP_PERMANENT)) == attrs)) { - /* - * js_CheckRedeclaration must reject attempts to add a getter or - * setter to an existing property without a getter or setter. - */ - JS_ASSERT(!(attrs & ~(JSPROP_ENUMERATE|JSPROP_PERMANENT))); - JS_ASSERT(!(old & JSPROP_READONLY)); - doSet = JS_TRUE; - } - pobj->dropProperty(cx, prop); - } - ok = doSet - ? parent->setProperty(cx, id, &rval) - : parent->defineProperty(cx, id, rval, getter, setter, attrs); - - restore_scope: - /* Restore fp->scopeChain now that obj is defined in fp->callobj. */ - fp->scopeChain = obj2; - if (!ok) - goto error; -} -END_CASE(JSOP_DEFFUN) - -BEGIN_CASE(JSOP_DEFFUN_FC) -BEGIN_CASE(JSOP_DEFFUN_DBGFC) - LOAD_FUNCTION(0); - - obj = (op == JSOP_DEFFUN_FC) - ? js_NewFlatClosure(cx, fun) - : js_NewDebuggableFlatClosure(cx, fun); - if (!obj) - goto error; - rval = OBJECT_TO_JSVAL(obj); - - attrs = (fp->flags & JSFRAME_EVAL) - ? JSPROP_ENUMERATE - : JSPROP_ENUMERATE | JSPROP_PERMANENT; - - flags = JSFUN_GSFLAG2ATTR(fun->flags); - if (flags) { - attrs |= flags | JSPROP_SHARED; - rval = JSVAL_VOID; - } - - parent = fp->varobj(cx); - JS_ASSERT(parent); - - id = ATOM_TO_JSID(fun->atom); - ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL); - if (ok) { - if (attrs == JSPROP_ENUMERATE) { - JS_ASSERT(fp->flags & JSFRAME_EVAL); - ok = parent->setProperty(cx, id, &rval); - } else { - JS_ASSERT(attrs & JSPROP_PERMANENT); - - ok = parent->defineProperty(cx, id, rval, - (flags & JSPROP_GETTER) - ? CastAsPropertyOp(obj) - : JS_PropertyStub, - (flags & JSPROP_SETTER) - ? CastAsPropertyOp(obj) - : JS_PropertyStub, - attrs); - } - } - - if (!ok) - goto error; -END_CASE(JSOP_DEFFUN_FC) - -BEGIN_CASE(JSOP_DEFLOCALFUN) - /* - * Define a local function (i.e., one nested at the top level of another - * function), parented by the current scope chain, stored in a local - * variable slot that the compiler allocated. This is an optimization over - * JSOP_DEFFUN that avoids requiring a call object for the outer function's - * activation. - */ - LOAD_FUNCTION(SLOTNO_LEN); - JS_ASSERT(FUN_INTERPRETED(fun)); - JS_ASSERT(!FUN_FLAT_CLOSURE(fun)); - obj = FUN_OBJECT(fun); - - if (FUN_NULL_CLOSURE(fun)) { - obj = CloneFunctionObject(cx, fun, fp->scopeChain); - if (!obj) - goto error; - } else { - parent = js_GetScopeChain(cx, fp); - if (!parent) - goto error; - - if (obj->getParent() != parent) { -#ifdef JS_TRACER - if (TRACE_RECORDER(cx)) - AbortRecording(cx, "DEFLOCALFUN for closure"); -#endif - obj = CloneFunctionObject(cx, fun, parent); - if (!obj) - goto error; - } - } - - slot = GET_SLOTNO(regs.pc); - TRACE_2(DefLocalFunSetSlot, slot, obj); - - fp->slots()[slot] = OBJECT_TO_JSVAL(obj); -END_CASE(JSOP_DEFLOCALFUN) - -BEGIN_CASE(JSOP_DEFLOCALFUN_FC) - LOAD_FUNCTION(SLOTNO_LEN); - - obj = js_NewFlatClosure(cx, fun); - if (!obj) - goto error; - - slot = GET_SLOTNO(regs.pc); - TRACE_2(DefLocalFunSetSlot, slot, obj); - - fp->slots()[slot] = OBJECT_TO_JSVAL(obj); -END_CASE(JSOP_DEFLOCALFUN_FC) - -BEGIN_CASE(JSOP_DEFLOCALFUN_DBGFC) - LOAD_FUNCTION(SLOTNO_LEN); - - obj = js_NewDebuggableFlatClosure(cx, fun); - if (!obj) - goto error; - - slot = GET_SLOTNO(regs.pc); - fp->slots()[slot] = OBJECT_TO_JSVAL(obj); -END_CASE(JSOP_DEFLOCALFUN_DBGFC) - -BEGIN_CASE(JSOP_LAMBDA) - /* Load the specified function object literal. */ - LOAD_FUNCTION(0); - obj = FUN_OBJECT(fun); - - /* do-while(0) so we can break instead of using a goto. */ - do { - if (FUN_NULL_CLOSURE(fun)) { - parent = fp->scopeChain; - - if (obj->getParent() == parent) { - op = JSOp(regs.pc[JSOP_LAMBDA_LENGTH]); - - /* - * Optimize ({method: function () { ... }, ...}) and - * this.method = function () { ... }; bytecode sequences. - */ - if (op == JSOP_SETMETHOD) { -#ifdef DEBUG - op2 = JSOp(regs.pc[JSOP_LAMBDA_LENGTH + JSOP_SETMETHOD_LENGTH]); - JS_ASSERT(op2 == JSOP_POP || op2 == JSOP_POPV); -#endif - - lval = FETCH_OPND(-1); - if (JSVAL_IS_OBJECT(lval) && - (obj2 = JSVAL_TO_OBJECT(lval)) && - obj2->getClass() == &js_ObjectClass) { - break; - } - } else if (op == JSOP_INITMETHOD) { - lval = FETCH_OPND(-1); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval)); - obj2 = JSVAL_TO_OBJECT(lval); - JS_ASSERT(obj2->getClass() == &js_ObjectClass); - JS_ASSERT(obj2->scope()->object == obj2); - break; - } - } - } else { - parent = js_GetScopeChain(cx, fp); - if (!parent) - goto error; - } - - obj = CloneFunctionObject(cx, fun, parent); - if (!obj) - goto error; - } while (0); - - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_LAMBDA) - -BEGIN_CASE(JSOP_LAMBDA_FC) - LOAD_FUNCTION(0); - - obj = js_NewFlatClosure(cx, fun); - if (!obj) - goto error; - - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_LAMBDA_FC) - -BEGIN_CASE(JSOP_LAMBDA_DBGFC) - LOAD_FUNCTION(0); - - obj = js_NewDebuggableFlatClosure(cx, fun); - if (!obj) - goto error; - - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_LAMBDA_DBGFC) - -BEGIN_CASE(JSOP_CALLEE) - PUSH_OPND(fp->argv[-2]); -END_CASE(JSOP_CALLEE) - -BEGIN_CASE(JSOP_GETTER) -BEGIN_CASE(JSOP_SETTER) - do_getter_setter: - op2 = (JSOp) *++regs.pc; - switch (op2) { - case JSOP_INDEXBASE: - atoms += GET_INDEXBASE(regs.pc); - regs.pc += JSOP_INDEXBASE_LENGTH - 1; - goto do_getter_setter; - case JSOP_INDEXBASE1: - case JSOP_INDEXBASE2: - case JSOP_INDEXBASE3: - atoms += (op2 - JSOP_INDEXBASE1 + 1) << 16; - goto do_getter_setter; - - case JSOP_SETNAME: - case JSOP_SETPROP: - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - rval = FETCH_OPND(-1); - i = -1; - goto gs_pop_lval; - - case JSOP_SETELEM: - rval = FETCH_OPND(-1); - id = 0; - i = -2; - gs_pop_lval: - FETCH_OBJECT(cx, i - 1, lval, obj); - break; - - case JSOP_INITPROP: - JS_ASSERT(regs.sp - StackBase(fp) >= 2); - rval = FETCH_OPND(-1); - i = -1; - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - goto gs_get_lval; - - default: - JS_ASSERT(op2 == JSOP_INITELEM); - - JS_ASSERT(regs.sp - StackBase(fp) >= 3); - rval = FETCH_OPND(-1); - id = 0; - i = -2; - gs_get_lval: - lval = FETCH_OPND(i-1); - JS_ASSERT(JSVAL_IS_OBJECT(lval)); - obj = JSVAL_TO_OBJECT(lval); - break; - } - - /* Ensure that id has a type suitable for use with obj. */ - if (id == 0) - FETCH_ELEMENT_ID(obj, i, id); - - if (!js_IsCallable(rval)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_GETTER_OR_SETTER, - (op == JSOP_GETTER) - ? js_getter_str - : js_setter_str); - goto error; - } - - /* - * Getters and setters are just like watchpoints from an access control - * point of view. - */ - if (!CheckAccess(cx, obj, id, JSACC_WATCH, &rtmp, &attrs)) - goto error; - - if (op == JSOP_GETTER) { - getter = CastAsPropertyOp(JSVAL_TO_OBJECT(rval)); - setter = JS_PropertyStub; - attrs = JSPROP_GETTER; - } else { - getter = JS_PropertyStub; - setter = CastAsPropertyOp(JSVAL_TO_OBJECT(rval)); - attrs = JSPROP_SETTER; - } - attrs |= JSPROP_ENUMERATE | JSPROP_SHARED; - - /* Check for a readonly or permanent property of the same name. */ - if (!js_CheckRedeclaration(cx, obj, id, attrs, NULL, NULL)) - goto error; - - if (!obj->defineProperty(cx, id, JSVAL_VOID, getter, setter, attrs)) - goto error; - - regs.sp += i; - if (js_CodeSpec[op2].ndefs > js_CodeSpec[op2].nuses) { - JS_ASSERT(js_CodeSpec[op2].ndefs == js_CodeSpec[op2].nuses + 1); - STORE_OPND(-1, rval); - } - len = js_CodeSpec[op2].length; - DO_NEXT_OP(len); - -BEGIN_CASE(JSOP_HOLE) - PUSH_OPND(JSVAL_HOLE); -END_CASE(JSOP_HOLE) - -BEGIN_CASE(JSOP_NEWARRAY) - len = GET_UINT16(regs.pc); - cx->assertValidStackDepth(len); - obj = js_NewArrayObject(cx, len, regs.sp - len, JS_TRUE); - if (!obj) - goto error; - regs.sp -= len - 1; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_NEWARRAY) - -BEGIN_CASE(JSOP_NEWINIT) - i = GET_INT8(regs.pc); - JS_ASSERT(i == JSProto_Array || i == JSProto_Object); - if (i == JSProto_Array) { - obj = js_NewArrayObject(cx, 0, NULL); - if (!obj) - goto error; - } else { - obj = NewBuiltinClassInstance(cx, &js_ObjectClass); - if (!obj) - goto error; - - if (regs.pc[JSOP_NEWINIT_LENGTH] != JSOP_ENDINIT) { - JS_LOCK_OBJ(cx, obj); - JSScope *scope = js_GetMutableScope(cx, obj); - if (!scope) { - JS_UNLOCK_OBJ(cx, obj); - goto error; - } - - /* - * We cannot assume that js_GetMutableScope above creates a scope - * owned by cx and skip JS_UNLOCK_SCOPE. A new object debugger - * hook may add properties to the newly created object, suspend - * the current request and share the object with other threads. - */ - JS_UNLOCK_SCOPE(cx, scope); - } - } - - PUSH_OPND(OBJECT_TO_JSVAL(obj)); - CHECK_INTERRUPT_HANDLER(); -END_CASE(JSOP_NEWINIT) - -BEGIN_CASE(JSOP_ENDINIT) - /* Re-set the newborn root to the top of this object tree. */ - JS_ASSERT(regs.sp - StackBase(fp) >= 1); - lval = FETCH_OPND(-1); - JS_ASSERT(JSVAL_IS_OBJECT(lval)); - cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = JSVAL_TO_OBJECT(lval); -END_CASE(JSOP_ENDINIT) - -BEGIN_CASE(JSOP_INITPROP) -BEGIN_CASE(JSOP_INITMETHOD) -{ - /* Load the property's initial value into rval. */ - JS_ASSERT(regs.sp - StackBase(fp) >= 2); - rval = FETCH_OPND(-1); - - /* Load the object being initialized into lval/obj. */ - lval = FETCH_OPND(-2); - obj = JSVAL_TO_OBJECT(lval); - JS_ASSERT(obj->isNative()); - - JSScope *scope = obj->scope(); - PropertyCacheEntry *entry; - - /* - * Probe the property cache. - * - * We can not assume that the object created by JSOP_NEWINIT is still - * single-threaded as the debugger can access it from other threads. - * So check first. - * - * On a hit, if the cached sprop has a non-default setter, it must be - * __proto__. If sprop->parent != scope->lastProperty(), there is a - * repeated property name. The fast path does not handle these two cases. - */ - if (CX_OWNS_OBJECT_TITLE(cx, obj) && - JS_PROPERTY_CACHE(cx).testForInit(rt, regs.pc, obj, scope, &sprop, &entry) && - sprop->hasDefaultSetter() && - sprop->parent == scope->lastProperty()) - { - /* Fast path. Property cache hit. */ - slot = sprop->slot; - JS_ASSERT(slot == scope->freeslot); - if (slot < obj->numSlots()) { - ++scope->freeslot; - } else { - if (!js_AllocSlot(cx, obj, &slot)) - goto error; - JS_ASSERT(slot == sprop->slot); - } - - JS_ASSERT(!scope->lastProperty() || - scope->shape == scope->lastProperty()->shape); - if (scope->table) { - JSScopeProperty *sprop2 = - scope->addProperty(cx, sprop->id, sprop->getter(), sprop->setter(), slot, - sprop->attributes(), sprop->getFlags(), sprop->shortid); - if (!sprop2) { - js_FreeSlot(cx, obj, slot); - goto error; - } - JS_ASSERT(sprop2 == sprop); - } else { - JS_ASSERT(!scope->isSharedEmpty()); - scope->extend(cx, sprop); - } - - /* - * No method change check here because here we are adding a new - * property, not updating an existing slot's value that might - * contain a method of a branded scope. - */ - TRACE_2(SetPropHit, entry, sprop); - obj->lockedSetSlot(slot, rval); - } else { - PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++); - - /* Get the immediate property name into id. */ - LOAD_ATOM(0); - id = ATOM_TO_JSID(atom); - - /* Set the property named by obj[id] to rval. */ - if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, - NULL, NULL)) { - goto error; - } - - uintN defineHow = (op == JSOP_INITMETHOD) - ? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD - : JSDNP_CACHE_RESULT; - if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom) - ? js_SetPropertyHelper(cx, obj, id, defineHow, &rval) - : js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL, - JSPROP_ENUMERATE, 0, 0, NULL, - defineHow))) { - goto error; - } - } - - /* Common tail for property cache hit and miss cases. */ - regs.sp--; -} -END_CASE(JSOP_INITPROP); - -BEGIN_CASE(JSOP_INITELEM) - /* Pop the element's value into rval. */ - JS_ASSERT(regs.sp - StackBase(fp) >= 3); - rval = FETCH_OPND(-1); - - /* Find the object being initialized at top of stack. */ - lval = FETCH_OPND(-3); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval)); - obj = JSVAL_TO_OBJECT(lval); - - /* Fetch id now that we have obj. */ - FETCH_ELEMENT_ID(obj, -2, id); - - /* - * Check for property redeclaration strict warning (we may be in an object - * initialiser, not an array initialiser). - */ - if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL, NULL)) - goto error; - - /* - * If rval is a hole, do not call JSObject::defineProperty. In this case, - * obj must be an array, so if the current op is the last element - * initialiser, set the array length to one greater than id. - */ - if (rval == JSVAL_HOLE) { - JS_ASSERT(obj->isArray()); - JS_ASSERT(JSID_IS_INT(id)); - JS_ASSERT(jsuint(JSID_TO_INT(id)) < JS_ARGS_LENGTH_MAX); - if (js_GetOpcode(cx, script, regs.pc + JSOP_INITELEM_LENGTH) == JSOP_ENDINIT && - !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) { - goto error; - } - } else { - if (!obj->defineProperty(cx, id, rval, NULL, NULL, JSPROP_ENUMERATE)) - goto error; - } - regs.sp -= 2; -END_CASE(JSOP_INITELEM) - -#if JS_HAS_SHARP_VARS - -BEGIN_CASE(JSOP_DEFSHARP) - slot = GET_UINT16(regs.pc); - JS_ASSERT(slot + 1 < fp->script->nfixed); - lval = fp->slots()[slot]; - if (!JSVAL_IS_PRIMITIVE(lval)) { - obj = JSVAL_TO_OBJECT(lval); - } else { - JS_ASSERT(JSVAL_IS_VOID(lval)); - obj = js_NewArrayObject(cx, 0, NULL); - if (!obj) - goto error; - fp->slots()[slot] = OBJECT_TO_JSVAL(obj); - } - i = (jsint) GET_UINT16(regs.pc + UINT16_LEN); - id = INT_TO_JSID(i); - rval = FETCH_OPND(-1); - if (JSVAL_IS_PRIMITIVE(rval)) { - char numBuf[12]; - JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i); - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_SHARP_DEF, numBuf); - goto error; - } - if (!obj->defineProperty(cx, id, rval, NULL, NULL, JSPROP_ENUMERATE)) - goto error; -END_CASE(JSOP_DEFSHARP) - -BEGIN_CASE(JSOP_USESHARP) - slot = GET_UINT16(regs.pc); - JS_ASSERT(slot + 1 < fp->script->nfixed); - lval = fp->slots()[slot]; - i = (jsint) GET_UINT16(regs.pc + UINT16_LEN); - if (JSVAL_IS_VOID(lval)) { - rval = JSVAL_VOID; - } else { - obj = JSVAL_TO_OBJECT(fp->slots()[slot]); - id = INT_TO_JSID(i); - if (!obj->getProperty(cx, id, &rval)) - goto error; - } - if (!JSVAL_IS_OBJECT(rval)) { - char numBuf[12]; - - JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i); - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_SHARP_USE, numBuf); - goto error; - } - PUSH_OPND(rval); -END_CASE(JSOP_USESHARP) - -BEGIN_CASE(JSOP_SHARPINIT) - slot = GET_UINT16(regs.pc); - JS_ASSERT(slot + 1 < fp->script->nfixed); - vp = &fp->slots()[slot]; - rval = vp[1]; - - /* - * We peek ahead safely here because empty initialisers get zero - * JSOP_SHARPINIT ops, and non-empty ones get two: the first comes - * immediately after JSOP_NEWINIT followed by one or more property - * initialisers; and the second comes directly before JSOP_ENDINIT. - */ - if (regs.pc[JSOP_SHARPINIT_LENGTH] != JSOP_ENDINIT) { - rval = JSVAL_IS_VOID(rval) ? JSVAL_ONE : rval + 2; - } else { - JS_ASSERT(JSVAL_IS_INT(rval)); - rval -= 2; - if (rval == JSVAL_ZERO) - vp[0] = JSVAL_VOID; - } - vp[1] = rval; -END_CASE(JSOP_SHARPINIT) - -#endif /* JS_HAS_SHARP_VARS */ - -BEGIN_CASE(JSOP_GOSUB) - PUSH(JSVAL_FALSE); - i = (regs.pc - script->main) + JSOP_GOSUB_LENGTH; - PUSH(INT_TO_JSVAL(i)); - len = GET_JUMP_OFFSET(regs.pc); -END_VARLEN_CASE - -BEGIN_CASE(JSOP_GOSUBX) - PUSH(JSVAL_FALSE); - i = (regs.pc - script->main) + JSOP_GOSUBX_LENGTH; - len = GET_JUMPX_OFFSET(regs.pc); - PUSH(INT_TO_JSVAL(i)); -END_VARLEN_CASE - -BEGIN_CASE(JSOP_RETSUB) - /* Pop [exception or hole, retsub pc-index]. */ - rval = POP(); - lval = POP(); - JS_ASSERT(JSVAL_IS_BOOLEAN(lval)); - if (JSVAL_TO_BOOLEAN(lval)) { - /* - * Exception was pending during finally, throw it *before* we adjust - * pc, because pc indexes into script->trynotes. This turns out not to - * be necessary, but it seems clearer. And it points out a FIXME: - * 350509, due to Igor Bukanov. - */ - cx->throwing = JS_TRUE; - cx->exception = rval; - goto error; - } - JS_ASSERT(JSVAL_IS_INT(rval)); - len = JSVAL_TO_INT(rval); - regs.pc = script->main; -END_VARLEN_CASE - -BEGIN_CASE(JSOP_EXCEPTION) - JS_ASSERT(cx->throwing); - PUSH(cx->exception); - cx->throwing = JS_FALSE; - CHECK_BRANCH(); -END_CASE(JSOP_EXCEPTION) - -BEGIN_CASE(JSOP_FINALLY) - CHECK_BRANCH(); -END_CASE(JSOP_FINALLY) - -BEGIN_CASE(JSOP_THROWING) - JS_ASSERT(!cx->throwing); - cx->throwing = JS_TRUE; - cx->exception = POP_OPND(); -END_CASE(JSOP_THROWING) - -BEGIN_CASE(JSOP_THROW) - JS_ASSERT(!cx->throwing); - CHECK_BRANCH(); - cx->throwing = JS_TRUE; - cx->exception = POP_OPND(); - /* let the code at error try to catch the exception. */ - goto error; - -BEGIN_CASE(JSOP_SETLOCALPOP) - /* - * The stack must have a block with at least one local slot below the - * exception object. - */ - JS_ASSERT((size_t) (regs.sp - StackBase(fp)) >= 2); - slot = GET_UINT16(regs.pc); - JS_ASSERT(slot + 1 < script->nslots); - fp->slots()[slot] = POP_OPND(); -END_CASE(JSOP_SETLOCALPOP) - -BEGIN_CASE(JSOP_IFPRIMTOP) - /* - * If the top of stack is of primitive type, jump to our target. Otherwise - * advance to the next opcode. - */ - JS_ASSERT(regs.sp > StackBase(fp)); - rval = FETCH_OPND(-1); - if (JSVAL_IS_PRIMITIVE(rval)) { - len = GET_JUMP_OFFSET(regs.pc); - BRANCH(len); - } -END_CASE(JSOP_IFPRIMTOP) - -BEGIN_CASE(JSOP_PRIMTOP) - JS_ASSERT(regs.sp > StackBase(fp)); - lval = FETCH_OPND(-1); - i = GET_INT8(regs.pc); - if (!JSVAL_IS_PRIMITIVE(lval)) { - lval = FETCH_OPND(-2); - js_ReportValueError2(cx, JSMSG_CANT_CONVERT_TO, -2, lval, NULL, - (i == JSTYPE_VOID) ? "primitive type" : JS_TYPE_STR(i)); - goto error; - } -END_CASE(JSOP_PRIMTOP) - -BEGIN_CASE(JSOP_OBJTOP) - lval = FETCH_OPND(-1); - if (JSVAL_IS_PRIMITIVE(lval)) { - js_ReportValueError(cx, GET_UINT16(regs.pc), -1, lval, NULL); - goto error; - } -END_CASE(JSOP_OBJTOP) - -BEGIN_CASE(JSOP_INSTANCEOF) - rval = FETCH_OPND(-1); - if (JSVAL_IS_PRIMITIVE(rval) || - !(obj = JSVAL_TO_OBJECT(rval))->map->ops->hasInstance) { - js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, - -1, rval, NULL); - goto error; - } - lval = FETCH_OPND(-2); - cond = JS_FALSE; - if (!obj->map->ops->hasInstance(cx, obj, lval, &cond)) - goto error; - regs.sp--; - STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); -END_CASE(JSOP_INSTANCEOF) - -#if JS_HAS_DEBUGGER_KEYWORD -BEGIN_CASE(JSOP_DEBUGGER) -{ - JSDebuggerHandler handler = cx->debugHooks->debuggerHandler; - if (handler) { - switch (handler(cx, script, regs.pc, &rval, cx->debugHooks->debuggerHandlerData)) { - case JSTRAP_ERROR: - goto error; - case JSTRAP_CONTINUE: - break; - case JSTRAP_RETURN: - fp->rval = rval; - ok = JS_TRUE; - goto forced_return; - case JSTRAP_THROW: - cx->throwing = JS_TRUE; - cx->exception = rval; - goto error; - default:; - } - CHECK_INTERRUPT_HANDLER(); - } -} -END_CASE(JSOP_DEBUGGER) -#endif /* JS_HAS_DEBUGGER_KEYWORD */ - -#if JS_HAS_XML_SUPPORT -BEGIN_CASE(JSOP_DEFXMLNS) - rval = POP(); - if (!js_SetDefaultXMLNamespace(cx, rval)) - goto error; -END_CASE(JSOP_DEFXMLNS) - -BEGIN_CASE(JSOP_ANYNAME) - if (!js_GetAnyName(cx, &rval)) - goto error; - PUSH_OPND(rval); -END_CASE(JSOP_ANYNAME) - -BEGIN_CASE(JSOP_QNAMEPART) - LOAD_ATOM(0); - PUSH_OPND(ATOM_KEY(atom)); -END_CASE(JSOP_QNAMEPART) - -BEGIN_CASE(JSOP_QNAMECONST) - LOAD_ATOM(0); - rval = ATOM_KEY(atom); - lval = FETCH_OPND(-1); - obj = js_ConstructXMLQNameObject(cx, lval, rval); - if (!obj) - goto error; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_QNAMECONST) - -BEGIN_CASE(JSOP_QNAME) - rval = FETCH_OPND(-1); - lval = FETCH_OPND(-2); - obj = js_ConstructXMLQNameObject(cx, lval, rval); - if (!obj) - goto error; - regs.sp--; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_QNAME) - -BEGIN_CASE(JSOP_TOATTRNAME) - rval = FETCH_OPND(-1); - if (!js_ToAttributeName(cx, &rval)) - goto error; - STORE_OPND(-1, rval); -END_CASE(JSOP_TOATTRNAME) - -BEGIN_CASE(JSOP_TOATTRVAL) - rval = FETCH_OPND(-1); - JS_ASSERT(JSVAL_IS_STRING(rval)); - str = js_EscapeAttributeValue(cx, JSVAL_TO_STRING(rval), JS_FALSE); - if (!str) - goto error; - STORE_OPND(-1, STRING_TO_JSVAL(str)); -END_CASE(JSOP_TOATTRVAL) - -BEGIN_CASE(JSOP_ADDATTRNAME) -BEGIN_CASE(JSOP_ADDATTRVAL) - rval = FETCH_OPND(-1); - lval = FETCH_OPND(-2); - str = JSVAL_TO_STRING(lval); - str2 = JSVAL_TO_STRING(rval); - str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2); - if (!str) - goto error; - regs.sp--; - STORE_OPND(-1, STRING_TO_JSVAL(str)); -END_CASE(JSOP_ADDATTRNAME) - -BEGIN_CASE(JSOP_BINDXMLNAME) - lval = FETCH_OPND(-1); - if (!js_FindXMLProperty(cx, lval, &obj, &id)) - goto error; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); - PUSH_OPND(ID_TO_VALUE(id)); -END_CASE(JSOP_BINDXMLNAME) - -BEGIN_CASE(JSOP_SETXMLNAME) - obj = JSVAL_TO_OBJECT(FETCH_OPND(-3)); - rval = FETCH_OPND(-1); - FETCH_ELEMENT_ID(obj, -2, id); - if (!obj->setProperty(cx, id, &rval)) - goto error; - rval = FETCH_OPND(-1); - regs.sp -= 2; - STORE_OPND(-1, rval); -END_CASE(JSOP_SETXMLNAME) - -BEGIN_CASE(JSOP_CALLXMLNAME) -BEGIN_CASE(JSOP_XMLNAME) - lval = FETCH_OPND(-1); - if (!js_FindXMLProperty(cx, lval, &obj, &id)) - goto error; - if (!obj->getProperty(cx, id, &rval)) - goto error; - STORE_OPND(-1, rval); - if (op == JSOP_CALLXMLNAME) - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_XMLNAME) - -BEGIN_CASE(JSOP_DESCENDANTS) -BEGIN_CASE(JSOP_DELDESC) - FETCH_OBJECT(cx, -2, lval, obj); - rval = FETCH_OPND(-1); - if (!js_GetXMLDescendants(cx, obj, rval, &rval)) - goto error; - - if (op == JSOP_DELDESC) { - regs.sp[-1] = rval; /* set local root */ - if (!js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval))) - goto error; - rval = JSVAL_TRUE; /* always succeed */ - } - - regs.sp--; - STORE_OPND(-1, rval); -END_CASE(JSOP_DESCENDANTS) - -BEGIN_CASE(JSOP_FILTER) - /* - * We push the hole value before jumping to [enditer] so we can detect the - * first iteration and direct js_StepXMLListFilter to initialize filter's - * state. - */ - PUSH_OPND(JSVAL_HOLE); - len = GET_JUMP_OFFSET(regs.pc); - JS_ASSERT(len > 0); -END_VARLEN_CASE - -BEGIN_CASE(JSOP_ENDFILTER) - cond = (regs.sp[-1] != JSVAL_HOLE); - if (cond) { - /* Exit the "with" block left from the previous iteration. */ - js_LeaveWith(cx); - } - if (!js_StepXMLListFilter(cx, cond)) - goto error; - if (regs.sp[-1] != JSVAL_NULL) { - /* - * Decrease sp after EnterWith returns as we use sp[-1] there to root - * temporaries. - */ - JS_ASSERT(VALUE_IS_XML(regs.sp[-1])); - if (!js_EnterWith(cx, -2)) - goto error; - regs.sp--; - len = GET_JUMP_OFFSET(regs.pc); - JS_ASSERT(len < 0); - BRANCH(len); - } - regs.sp--; -END_CASE(JSOP_ENDFILTER); - -BEGIN_CASE(JSOP_TOXML) - rval = FETCH_OPND(-1); - obj = js_ValueToXMLObject(cx, rval); - if (!obj) - goto error; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_TOXML) - -BEGIN_CASE(JSOP_TOXMLLIST) - rval = FETCH_OPND(-1); - obj = js_ValueToXMLListObject(cx, rval); - if (!obj) - goto error; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_TOXMLLIST) - -BEGIN_CASE(JSOP_XMLTAGEXPR) - rval = FETCH_OPND(-1); - str = js_ValueToString(cx, rval); - if (!str) - goto error; - STORE_OPND(-1, STRING_TO_JSVAL(str)); -END_CASE(JSOP_XMLTAGEXPR) - -BEGIN_CASE(JSOP_XMLELTEXPR) - rval = FETCH_OPND(-1); - if (VALUE_IS_XML(rval)) { - str = js_ValueToXMLString(cx, rval); - } else { - str = js_ValueToString(cx, rval); - if (str) - str = js_EscapeElementValue(cx, str); - } - if (!str) - goto error; - STORE_OPND(-1, STRING_TO_JSVAL(str)); -END_CASE(JSOP_XMLELTEXPR) - -BEGIN_CASE(JSOP_XMLCDATA) - LOAD_ATOM(0); - str = ATOM_TO_STRING(atom); - obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, str); - if (!obj) - goto error; - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_XMLCDATA) - -BEGIN_CASE(JSOP_XMLCOMMENT) - LOAD_ATOM(0); - str = ATOM_TO_STRING(atom); - obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, str); - if (!obj) - goto error; - PUSH_OPND(OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_XMLCOMMENT) - -BEGIN_CASE(JSOP_XMLPI) - LOAD_ATOM(0); - str = ATOM_TO_STRING(atom); - rval = FETCH_OPND(-1); - str2 = JSVAL_TO_STRING(rval); - obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, str, str2); - if (!obj) - goto error; - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); -END_CASE(JSOP_XMLPI) - -BEGIN_CASE(JSOP_GETFUNNS) - if (!js_GetFunctionNamespace(cx, &rval)) - goto error; - PUSH_OPND(rval); -END_CASE(JSOP_GETFUNNS) -#endif /* JS_HAS_XML_SUPPORT */ - -BEGIN_CASE(JSOP_ENTERBLOCK) - LOAD_OBJECT(0); - JS_ASSERT(!OBJ_IS_CLONED_BLOCK(obj)); - JS_ASSERT(StackBase(fp) + OBJ_BLOCK_DEPTH(cx, obj) == regs.sp); - vp = regs.sp + OBJ_BLOCK_COUNT(cx, obj); - JS_ASSERT(regs.sp < vp); - JS_ASSERT(vp <= fp->slots() + script->nslots); - while (regs.sp < vp) { - STORE_OPND(0, JSVAL_VOID); - regs.sp++; - } - -#ifdef DEBUG - JS_ASSERT(fp->blockChain == obj->getParent()); - - /* - * The young end of fp->scopeChain may omit blocks if we haven't closed - * over them, but if there are any closure blocks on fp->scopeChain, they'd - * better be (clones of) ancestors of the block we're entering now; - * anything else we should have popped off fp->scopeChain when we left its - * static scope. - */ - obj2 = fp->scopeChain; - while ((clasp = obj2->getClass()) == &js_WithClass) - obj2 = obj2->getParent(); - if (clasp == &js_BlockClass && - obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) { - JSObject *youngestProto = obj2->getProto(); - JS_ASSERT(!OBJ_IS_CLONED_BLOCK(youngestProto)); - parent = obj; - while ((parent = parent->getParent()) != youngestProto) - JS_ASSERT(parent); - } -#endif - - fp->blockChain = obj; -END_CASE(JSOP_ENTERBLOCK) - -BEGIN_CASE(JSOP_LEAVEBLOCKEXPR) -BEGIN_CASE(JSOP_LEAVEBLOCK) -{ -#ifdef DEBUG - JS_ASSERT(fp->blockChain->getClass() == &js_BlockClass); - uintN blockDepth = OBJ_BLOCK_DEPTH(cx, fp->blockChain); - - JS_ASSERT(blockDepth <= StackDepth(script)); -#endif - /* - * If we're about to leave the dynamic scope of a block that has been - * cloned onto fp->scopeChain, clear its private data, move its locals from - * the stack into the clone, and pop it off the chain. - */ - obj = fp->scopeChain; - if (obj->getProto() == fp->blockChain) { - JS_ASSERT(obj->getClass() == &js_BlockClass); - if (!js_PutBlockObject(cx, JS_TRUE)) - goto error; - } - - /* Pop the block chain, too. */ - fp->blockChain = fp->blockChain->getParent(); - - /* Move the result of the expression to the new topmost stack slot. */ - if (op == JSOP_LEAVEBLOCKEXPR) - rval = FETCH_OPND(-1); - regs.sp -= GET_UINT16(regs.pc); - if (op == JSOP_LEAVEBLOCKEXPR) { - JS_ASSERT(StackBase(fp) + blockDepth == regs.sp - 1); - STORE_OPND(-1, rval); - } else { - JS_ASSERT(StackBase(fp) + blockDepth == regs.sp); - } -} -END_CASE(JSOP_LEAVEBLOCK) - -#if JS_HAS_GENERATORS -BEGIN_CASE(JSOP_GENERATOR) - ASSERT_NOT_THROWING(cx); - regs.pc += JSOP_GENERATOR_LENGTH; - obj = js_NewGenerator(cx); - if (!obj) - goto error; - JS_ASSERT(!fp->callobj && !fp->argsobj); - fp->rval = OBJECT_TO_JSVAL(obj); - ok = JS_TRUE; - if (inlineCallCount != 0) - goto inline_return; - goto exit; - -BEGIN_CASE(JSOP_YIELD) - ASSERT_NOT_THROWING(cx); - if (cx->generatorFor(fp)->state == JSGEN_CLOSING) { - js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, - JSDVG_SEARCH_STACK, fp->argv[-2], NULL); - goto error; - } - fp->rval = FETCH_OPND(-1); - fp->flags |= JSFRAME_YIELDING; - regs.pc += JSOP_YIELD_LENGTH; - ok = JS_TRUE; - goto exit; - -BEGIN_CASE(JSOP_ARRAYPUSH) - slot = GET_UINT16(regs.pc); - JS_ASSERT(script->nfixed <= slot); - JS_ASSERT(slot < script->nslots); - lval = fp->slots()[slot]; - obj = JSVAL_TO_OBJECT(lval); - rval = FETCH_OPND(-1); - if (!js_ArrayCompPush(cx, obj, rval)) - goto error; - regs.sp--; -END_CASE(JSOP_ARRAYPUSH) -#endif /* JS_HAS_GENERATORS */ - - L_JSOP_UNUSED180: - -#if JS_THREADED_INTERP - L_JSOP_BACKPATCH: - L_JSOP_BACKPATCH_POP: - -# if !JS_HAS_GENERATORS - L_JSOP_GENERATOR: - L_JSOP_YIELD: - L_JSOP_ARRAYPUSH: -# endif - -# if !JS_HAS_SHARP_VARS - L_JSOP_DEFSHARP: - L_JSOP_USESHARP: - L_JSOP_SHARPINIT: -# endif - -# if !JS_HAS_DESTRUCTURING - L_JSOP_ENUMCONSTELEM: -# endif - -# if !JS_HAS_XML_SUPPORT - L_JSOP_CALLXMLNAME: - L_JSOP_STARTXMLEXPR: - L_JSOP_STARTXML: - L_JSOP_DELDESC: - L_JSOP_GETFUNNS: - L_JSOP_XMLPI: - L_JSOP_XMLCOMMENT: - L_JSOP_XMLCDATA: - L_JSOP_XMLELTEXPR: - L_JSOP_XMLTAGEXPR: - L_JSOP_TOXMLLIST: - L_JSOP_TOXML: - L_JSOP_ENDFILTER: - L_JSOP_FILTER: - L_JSOP_DESCENDANTS: - L_JSOP_XMLNAME: - L_JSOP_SETXMLNAME: - L_JSOP_BINDXMLNAME: - L_JSOP_ADDATTRVAL: - L_JSOP_ADDATTRNAME: - L_JSOP_TOATTRVAL: - L_JSOP_TOATTRNAME: - L_JSOP_QNAME: - L_JSOP_QNAMECONST: - L_JSOP_QNAMEPART: - L_JSOP_ANYNAME: - L_JSOP_DEFXMLNS: -# endif - - L_JSOP_UNUSED218: - -#endif /* !JS_THREADED_INTERP */ diff --git a/js/src/jsparse.cpp b/js/src/jsparse.cpp index e75984a61afe..bafa70f72183 100644 --- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -88,6 +88,8 @@ #include "jsdhash.h" #endif +#include "jsatominlines.h" + using namespace js; /* @@ -3188,7 +3190,7 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc) if (slot >= blockObj->numSlots() && !blockObj->growSlots(cx, slot + 1)) return false; blockObj->scope()->freeslot = slot + 1; - blockObj->setSlot(slot, PRIVATE_TO_JSVAL(pn)); + blockObj->setSlot(slot, PrivateValue(pn)); return true; } @@ -3904,7 +3906,7 @@ CheckDestructuring(JSContext *cx, BindData *data, ok = !!js_DefineNativeProperty(cx, tc->blockChain, ATOM_TO_JSID(cx->runtime-> atomState.emptyAtom), - JSVAL_VOID, NULL, NULL, + UndefinedValue(), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_SHARED, @@ -4076,7 +4078,7 @@ CloneParseTree(JSParseNode *opn, JSTreeContext *tc) NULLCHECK(pn->pn_right = CloneParseTree(opn->pn_right, tc)); else pn->pn_right = pn->pn_left; - pn->pn_val = opn->pn_val; + pn->pn_pval = opn->pn_pval; pn->pn_iflags = opn->pn_iflags; break; @@ -7883,8 +7885,11 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) return NULL; pn3->pn_dval = tokenStream.currentToken().t_dval; if (tc->needStrictChecks()) { - atom = js_AtomizeDouble(context, pn3->pn_dval); - if (!atom) + /* + * Use string-valued atoms for detecting duplicate + * properties so that 1 and "1" properly collide. + */ + if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom)) return NULL; } else { atom = NULL; /* for the compiler */ @@ -7912,8 +7917,11 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) return NULL; pn3->pn_dval = tokenStream.currentToken().t_dval; if (tc->needStrictChecks()) { - atom = js_AtomizeDouble(context, pn3->pn_dval); - if (!atom) + /* + * Use string-valued atoms for detecting duplicate + * properties so that 1 and "1" properly collide. + */ + if (!js_ValueToAtom(context, DoubleValue(pn3->pn_dval), &atom)) return NULL; } else { atom = NULL; /* for the compiler */ @@ -7995,19 +8003,6 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot) attributesMask = 0; } - /* - * Use only string-valued atoms for detecting duplicate - * properties so that 1 and "1" properly collide. - */ - if (ATOM_IS_DOUBLE(atom)) { - JSString *str = js_NumberToString(context, pn3->pn_dval); - if (!str) - return JS_FALSE; - atom = js_AtomizeString(context, str, 0); - if (!atom) - return JS_FALSE; - } - JSAtomListElement *ale = seen.lookup(atom); if (ale) { if (ALE_INDEX(ale) & attributesMask) { @@ -8386,7 +8381,7 @@ FoldType(JSContext *cx, JSParseNode *pn, TokenKind type) case TOK_NUMBER: if (pn->pn_type == TOK_STRING) { jsdouble d; - if (!JS_ValueToNumber(cx, ATOM_KEY(pn->pn_atom), &d)) + if (!ValueToNumber(cx, StringValue(ATOM_TO_STRING(pn->pn_atom)), &d)) return JS_FALSE; pn->pn_dval = d; pn->pn_type = TOK_NUMBER; @@ -8597,7 +8592,7 @@ FoldXMLConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc) if (accum) { { - AutoValueRooter tvr(cx, accum); + AutoStringRooter tvr(cx, accum); str = ((tt == TOK_XMLSTAGO || tt == TOK_XMLPTAGC) && i != 0) ? js_AddAttributePart(cx, i & 1, accum, str) : js_ConcatStrings(cx, accum, str); @@ -9145,15 +9140,14 @@ js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc, bool inCond) case TOK_AT: if (pn1->pn_type == TOK_XMLNAME) { - jsval v; JSObjectBox *xmlbox; - v = ATOM_KEY(pn1->pn_atom); + Value v = StringValue(ATOM_TO_STRING(pn1->pn_atom)); if (!js_ToAttributeName(cx, &v)) return JS_FALSE; - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + JS_ASSERT(v.isObject()); - xmlbox = tc->parser->newObjectBox(JSVAL_TO_OBJECT(v)); + xmlbox = tc->parser->newObjectBox(&v.toObject()); if (!xmlbox) return JS_FALSE; diff --git a/js/src/jsparse.h b/js/src/jsparse.h index 40799885b926..d71e851e49ba 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -320,7 +320,7 @@ struct JSParseNode { struct { /* two kids if binary */ JSParseNode *left; JSParseNode *right; - jsval val; /* switch case value */ + js::Value *pval; /* switch case value */ uintN iflags; /* JSITER_* flags for TOK_FOR node */ } binary; struct { /* one kid if unary */ @@ -372,7 +372,7 @@ struct JSParseNode { #define pn_kid3 pn_u.ternary.kid3 #define pn_left pn_u.binary.left #define pn_right pn_u.binary.right -#define pn_val pn_u.binary.val +#define pn_pval pn_u.binary.pval #define pn_iflags pn_u.binary.iflags #define pn_kid pn_u.unary.kid #define pn_num pn_u.unary.num diff --git a/js/src/jspropertycache.cpp b/js/src/jspropertycache.cpp index 50576b850167..ab9e8a94f60f 100644 --- a/js/src/jspropertycache.cpp +++ b/js/src/jspropertycache.cpp @@ -139,26 +139,24 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI * getter, so get of a function is idempotent. */ if (cs->format & JOF_CALLOP) { - jsval v; - if (sprop->isMethod()) { /* * A compiler-created function object, AKA a method, already * memoized in the property tree. */ JS_ASSERT(scope->hasMethodBarrier()); - v = sprop->methodValue(); - JS_ASSERT(VALUE_IS_FUNCTION(cx, v)); - JS_ASSERT(v == pobj->lockedGetSlot(sprop->slot)); - vword.setObject(JSVAL_TO_OBJECT(v)); + JSObject &funobj = sprop->methodObject(); + JS_ASSERT(&funobj == &pobj->lockedGetSlot(sprop->slot).toObject()); + vword.setFunObj(funobj); break; } if (!scope->generic() && sprop->hasDefaultGetter() && SPROP_HAS_VALID_SLOT(sprop, scope)) { - v = pobj->lockedGetSlot(sprop->slot); - if (VALUE_IS_FUNCTION(cx, v)) { + const Value &v = pobj->lockedGetSlot(sprop->slot); + JSObject *funobj; + if (IsFunctionObject(v, &funobj)) { /* * Great, we have a function-valued prototype property * where the getter is JS_PropertyStub. The type id in @@ -184,7 +182,7 @@ PropertyCache::fill(JSContext *cx, JSObject *obj, uintN scopeIndex, uintN protoI if (!scope->brand(cx, sprop->slot, v)) return JS_NO_PROP_CACHE_FILL; } - vword.setObject(JSVAL_TO_OBJECT(v)); + vword.setFunObj(*funobj); break; } } diff --git a/js/src/jspropertycache.h b/js/src/jspropertycache.h index 3215ba685203..960c1260ab35 100644 --- a/js/src/jspropertycache.h +++ b/js/src/jspropertycache.h @@ -94,10 +94,9 @@ class PCVal bool isNull() const { return v == 0; } void setNull() { v = 0; } - bool isObject() const { return (v & TAG) == OBJECT; } - JSObject *toObject() const { JS_ASSERT(isObject()); return reinterpret_cast(v); } - jsval toJsval() const { return OBJECT_TO_JSVAL(toObject()); } - void setObject(JSObject *obj) { v = reinterpret_cast(obj); } + bool isFunObj() const { return (v & TAG) == OBJECT; } + JSObject &toFunObj() const { JS_ASSERT(isFunObj()); return *reinterpret_cast(v); } + void setFunObj(JSObject &obj) { v = reinterpret_cast(&obj); } bool isSlot() const { return v & SLOT; } uint32 toSlot() const { JS_ASSERT(isSlot()); return uint32(v) >> 1; } diff --git a/js/src/jspropertytree.cpp b/js/src/jspropertytree.cpp index 6d332fde368f..adea4b874408 100644 --- a/js/src/jspropertytree.cpp +++ b/js/src/jspropertytree.cpp @@ -236,8 +236,8 @@ PropertyTree::insertChild(JSContext *cx, JSScopeProperty *parent, { JS_ASSERT(parent); JS_ASSERT(!child->parent); - JS_ASSERT(!JSVAL_IS_NULL(parent->id)); - JS_ASSERT(!JSVAL_IS_NULL(child->id)); + JS_ASSERT(!JSID_IS_VOID(parent->id)); + JS_ASSERT(!JSID_IS_VOID(child->id)); JSScopeProperty **childp = &parent->kids; if (JSScopeProperty *kids = *childp) { @@ -333,7 +333,7 @@ PropertyTree::removeChild(JSContext *cx, JSScopeProperty *child) JSScopeProperty *parent = child->parent; JS_ASSERT(parent); - JS_ASSERT(!JSVAL_IS_NULL(parent->id)); + JS_ASSERT(!JSID_IS_VOID(parent->id)); JSScopeProperty *kids = parent->kids; if (!KIDS_IS_CHUNKY(kids)) { @@ -470,7 +470,7 @@ PropertyTree::getChild(JSContext *cx, JSScopeProperty *parent, uint32 shape, if (sprop) goto out; } else { - JS_ASSERT(!JSVAL_IS_NULL(parent->id)); + JS_ASSERT(!JSID_IS_VOID(parent->id)); /* * Because chunks are appended at the end and never deleted except by @@ -618,18 +618,17 @@ js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number, void JSScopeProperty::dump(JSContext *cx, FILE *fp) { - JS_ASSERT(!JSVAL_IS_NULL(id)); + JS_ASSERT(!JSID_IS_VOID(id)); - jsval idval = ID_TO_VALUE(id); - if (JSVAL_IS_INT(idval)) { - fprintf(fp, "[%ld]", (long) JSVAL_TO_INT(idval)); + if (JSID_IS_INT(id)) { + fprintf(fp, "[%ld]", (long) JSID_TO_INT(id)); } else { JSString *str; - if (JSVAL_IS_STRING(idval)) { - str = JSVAL_TO_STRING(idval); + if (JSID_IS_ATOM(id)) { + str = JSID_TO_STRING(id); } else { - JS_ASSERT(JSVAL_IS_OBJECT(idval)); - str = js_ValueToString(cx, idval); + JS_ASSERT(JSID_IS_OBJECT(id)); + str = js_ValueToString(cx, IdToValue(id)); fputs("object ", fp); } if (!str) @@ -727,7 +726,7 @@ OrphanNodeKids(JSContext *cx, JSScopeProperty *sprop) if (!kid) break; - if (!JSVAL_IS_NULL(kid->id)) { + if (!JSID_IS_VOID(kid->id)) { JS_ASSERT(kid->parent == sprop); kid->parent = NULL; } @@ -736,7 +735,7 @@ OrphanNodeKids(JSContext *cx, JSScopeProperty *sprop) } else { JSScopeProperty *kid = kids; - if (!JSVAL_IS_NULL(kid->id)) { + if (!JSID_IS_VOID(kid->id)) { JS_ASSERT(kid->parent == sprop); kid->parent = NULL; } @@ -859,7 +858,7 @@ js::SweepScopeProperties(JSContext *cx) for (JSScopeProperty *sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) { /* If the id is null, sprop is already on the freelist. */ - if (JSVAL_IS_NULL(sprop->id)) + if (JSID_IS_VOID(sprop->id)) continue; /* diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 122aa421d3c2..6fe6322909ff 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -54,16 +54,16 @@ using namespace js; namespace js { -static jsval +static inline const Value & GetCall(JSObject *proxy) { JS_ASSERT(proxy->isFunctionProxy()); return proxy->getSlot(JSSLOT_PROXY_CALL); } -static jsval +static inline Value GetConstruct(JSObject *proxy) { if (proxy->numSlots() <= JSSLOT_PROXY_CONSTRUCT) - return JSVAL_VOID; + return UndefinedValue(); return proxy->getSlot(JSSLOT_PROXY_CONSTRUCT); } @@ -91,7 +91,7 @@ bool JSProxyHandler::has(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { JS_ASSERT(OperationInProgress(cx, proxy)); - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); if (!getPropertyDescriptor(cx, proxy, id, &desc)) return false; *bp = !!desc.obj; @@ -102,7 +102,7 @@ bool JSProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) { JS_ASSERT(OperationInProgress(cx, proxy)); - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); if (!getOwnPropertyDescriptor(cx, proxy, id, &desc)) return false; *bp = !!desc.obj; @@ -110,14 +110,14 @@ JSProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) } bool -JSProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) +JSProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp) { JS_ASSERT(OperationInProgress(cx, proxy)); - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); if (!getPropertyDescriptor(cx, proxy, id, &desc)) return false; if (!desc.obj) { - *vp = JSVAL_VOID; + vp->setUndefined(); return true; } if (!desc.getter) { @@ -125,8 +125,8 @@ JSProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, return true; } if (desc.attrs & JSPROP_GETTER) { - return js_InternalGetOrSet(cx, proxy, id, CastAsObjectJSVal(desc.getter), - JSACC_READ, 0, 0, vp); + return InternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.getter), + JSACC_READ, 0, 0, vp); } if (desc.attrs & JSPROP_SHORTID) id = INT_TO_JSID(desc.shortid); @@ -134,18 +134,18 @@ JSProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, } bool -JSProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) +JSProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp) { JS_ASSERT(OperationInProgress(cx, proxy)); - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); if (!getOwnPropertyDescriptor(cx, proxy, id, &desc)) return false; /* The control-flow here differs from ::get() because of the fall-through case below. */ if (desc.obj) { if (desc.setter) { if (desc.attrs & JSPROP_SETTER) { - return js_InternalGetOrSet(cx, proxy, id, CastAsObjectJSVal(desc.setter), - JSACC_READ, 0, 0, vp); + return InternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.setter), + JSACC_READ, 0, 0, vp); } if (desc.attrs & JSPROP_SHORTID) id = INT_TO_JSID(desc.shortid); @@ -161,8 +161,8 @@ JSProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, if (desc.obj) { if (desc.setter) { if (desc.attrs & JSPROP_SETTER) { - return js_InternalGetOrSet(cx, proxy, id, CastAsObjectJSVal(desc.setter), - JSACC_READ, 0, 0, vp); + return InternalGetOrSet(cx, proxy, id, CastAsObjectJsval(desc.setter), + JSACC_READ, 0, 0, vp); } if (desc.attrs & JSPROP_SHORTID) id = INT_TO_JSID(desc.shortid); @@ -175,14 +175,14 @@ JSProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, desc.obj = proxy; desc.value = *vp; desc.attrs = 0; - desc.getter = JSVAL_NULL; - desc.setter = JSVAL_NULL; + desc.getter = NULL; + desc.setter = NULL; desc.shortid = 0; return defineProperty(cx, proxy, id, &desc); } bool -JSProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &props) +JSProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props) { JS_ASSERT(OperationInProgress(cx, proxy)); JS_ASSERT(props.length() == 0); @@ -191,7 +191,7 @@ JSProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &pr return false; /* Select only the enumerable properties through in-place iteration. */ - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); size_t i = 0; for (size_t j = 0, len = props.length(); j < len; j++) { JS_ASSERT(i <= j); @@ -209,13 +209,13 @@ JSProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &pr } bool -JSProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp) +JSProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp) { JS_ASSERT(OperationInProgress(cx, proxy)); - AutoValueVector props(cx); + AutoIdVector props(cx); if (!enumerate(cx, proxy, props)) return false; - return IdVectorToIterator(cx, proxy, flags, props, vp); + return EnumeratedIdVectorToIterator(cx, proxy, flags, props, vp); } JSString * @@ -232,26 +232,25 @@ JSString * JSProxyHandler::fun_toString(JSContext *cx, JSObject *proxy, uintN indent) { JS_ASSERT(proxy->isProxy()); - jsval fval = GetCall(proxy); + Value fval = GetCall(proxy); if (proxy->isFunctionProxy() && - (JSVAL_IS_PRIMITIVE(fval) || - !JSVAL_TO_OBJECT(fval)->isFunction())) { + (fval.isPrimitive() || !fval.toObject().isFunction())) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, js_Function_str, js_toString_str, "object"); return NULL; } - return fun_toStringHelper(cx, JSVAL_TO_OBJECT(fval), indent); + return fun_toStringHelper(cx, &fval.toObject(), indent); } bool -JSProxyHandler::call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp) +JSProxyHandler::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp) { JS_ASSERT(OperationInProgress(cx, proxy)); AutoValueRooter rval(cx); - JSBool ok = js_InternalInvoke(cx, vp[1], GetCall(proxy), 0, argc, JS_ARGV(cx, vp), - rval.addr()); + JSBool ok = InternalInvoke(cx, vp[1], GetCall(proxy), 0, argc, JS_ARGV(cx, vp), + rval.addr()); if (ok) JS_SET_RVAL(cx, vp, rval.value()); return ok; @@ -259,16 +258,16 @@ JSProxyHandler::call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp) bool JSProxyHandler::construct(JSContext *cx, JSObject *proxy, - uintN argc, jsval *argv, jsval *rval) + uintN argc, Value *argv, Value *rval) { JS_ASSERT(OperationInProgress(cx, proxy)); - jsval fval = GetConstruct(proxy); - if (JSVAL_IS_VOID(fval)) { + Value fval = GetConstruct(proxy); + if (fval.isUndefined()) { fval = GetCall(proxy); - JSObject *obj = JS_New(cx, JSVAL_TO_OBJECT(fval), argc, argv); + JSObject *obj = JS_New(cx, &fval.toObject(), argc, Jsvalify(argv)); if (!obj) return false; - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); return true; } @@ -276,9 +275,9 @@ JSProxyHandler::construct(JSContext *cx, JSObject *proxy, * FIXME: The Proxy proposal says to pass undefined as the this argument, * but primitive this is not supported yet. See bug 576644. */ - JS_ASSERT(!JSVAL_IS_PRIMITIVE(fval)); - JSObject *thisobj = JSVAL_TO_OBJECT(fval)->getGlobal(); - return js_InternalCall(cx, thisobj, fval, argc, argv, rval); + JS_ASSERT(fval.isObject()); + JSObject *thisobj = fval.toObject().getGlobal(); + return InternalCall(cx, thisobj, fval, argc, argv, rval); } void @@ -292,13 +291,13 @@ JSProxyHandler::trace(JSTracer *trc, JSObject *proxy) } static bool -GetTrap(JSContext *cx, JSObject *handler, JSAtom *atom, jsval *fvalp) +GetTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp) { return handler->getProperty(cx, ATOM_TO_JSID(atom), fvalp); } static bool -FundamentalTrap(JSContext *cx, JSObject *handler, JSAtom *atom, jsval *fvalp) +FundamentalTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp) { if (!GetTrap(cx, handler, atom, fvalp)) return false; @@ -313,7 +312,7 @@ FundamentalTrap(JSContext *cx, JSObject *handler, JSAtom *atom, jsval *fvalp) } static bool -DerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, jsval *fvalp) +DerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, Value *fvalp) { JS_ASSERT(atom == ATOM(has) || atom == ATOM(hasOwn) || @@ -326,40 +325,40 @@ DerivedTrap(JSContext *cx, JSObject *handler, JSAtom *atom, jsval *fvalp) } static bool -Trap(JSContext *cx, JSObject *handler, jsval fval, uintN argc, jsval* argv, jsval *rval) +Trap(JSContext *cx, JSObject *handler, Value fval, uintN argc, Value* argv, Value *rval) { JS_CHECK_RECURSION(cx, return false); - return js_InternalCall(cx, handler, fval, argc, argv, rval); + return InternalCall(cx, handler, fval, argc, argv, rval); } static bool -Trap1(JSContext *cx, JSObject *handler, jsval fval, jsid id, jsval *rval) +Trap1(JSContext *cx, JSObject *handler, Value fval, jsid id, Value *rval) { - JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); + JSString *str = js_ValueToString(cx, IdToValue(id)); if (!str) return false; - *rval = STRING_TO_JSVAL(str); + rval->setString(str); return Trap(cx, handler, fval, 1, rval, rval); } static bool -Trap2(JSContext *cx, JSObject *handler, jsval fval, jsid id, jsval v, jsval *rval) +Trap2(JSContext *cx, JSObject *handler, Value fval, jsid id, Value v, Value *rval) { - JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); + JSString *str = js_ValueToString(cx, IdToValue(id)); if (!str) return false; - *rval = STRING_TO_JSVAL(str); - jsval argv[2] = { *rval, v }; + rval->setString(str); + Value argv[2] = { *rval, v }; return Trap(cx, handler, fval, 2, argv, rval); } static bool -ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, jsval v, - JSPropertyDescriptor *desc) +ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, const Value &v, + PropertyDescriptor *desc) { - AutoDescriptorArray descs(cx); - PropertyDescriptor *d = descs.append(); + AutoPropDescArrayRooter descs(cx); + PropDesc *d = descs.append(); if (!d || !d->initialize(cx, id, v)) return false; desc->obj = obj; @@ -373,37 +372,34 @@ ParsePropertyDescriptorObject(JSContext *cx, JSObject *obj, jsid id, jsval v, } static bool -MakePropertyDescriptorObject(JSContext *cx, jsid id, JSPropertyDescriptor *desc, jsval *vp) +MakePropertyDescriptorObject(JSContext *cx, jsid id, PropertyDescriptor *desc, Value *vp) { if (!desc->obj) { - *vp = JSVAL_VOID; + vp->setUndefined(); return true; } uintN attrs = desc->attrs; - jsval getter = (attrs & JSPROP_GETTER) ? CastAsObjectJSVal(desc->getter) : JSVAL_VOID; - jsval setter = (attrs & JSPROP_SETTER) ? CastAsObjectJSVal(desc->setter) : JSVAL_VOID; + Value getter = (attrs & JSPROP_GETTER) ? CastAsObjectJsval(desc->getter) : UndefinedValue(); + Value setter = (attrs & JSPROP_SETTER) ? CastAsObjectJsval(desc->setter) : UndefinedValue(); return js_NewPropertyDescriptorObject(cx, id, attrs, getter, setter, desc->value, vp); } static bool -ValueToBool(JSContext *cx, jsval v, bool *bp) +ValueToBool(JSContext *cx, const Value &v, bool *bp) { - JSBool b; - if (!JS_ValueToBoolean(cx, v, &b)) - return false; - *bp = !!b; + *bp = !!js_ValueToBoolean(v); return true; } bool -ArrayToIdVector(JSContext *cx, jsval array, AutoValueVector &props) +ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props) { JS_ASSERT(props.length() == 0); - if (JSVAL_IS_PRIMITIVE(array)) + if (array.isPrimitive()) return true; - JSObject *obj = JSVAL_TO_OBJECT(array); + JSObject *obj = &array.toObject(); jsuint length; if (!js_GetLengthProperty(cx, obj, &length)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); @@ -417,7 +413,7 @@ ArrayToIdVector(JSContext *cx, jsval array, AutoValueVector &props) return false; if (!obj->getProperty(cx, idr.id(), tvr.addr())) return false; - if (!JS_ValueToId(cx, tvr.value(), idr.addr())) + if (!ValueToId(cx, tvr.value(), idr.addr())) return false; if (!props.append(js_CheckForStringIndex(idr.id()))) return false; @@ -434,23 +430,23 @@ class JSScriptedProxyHandler : public JSProxyHandler { /* ES5 Harmony fundamental proxy traps. */ virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc); + PropertyDescriptor *desc); virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc); + PropertyDescriptor *desc); virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc); - virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoValueVector &props); + PropertyDescriptor *desc); + virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props); virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp); - virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoValueVector &props); - virtual bool fix(JSContext *cx, JSObject *proxy, jsval *vp); + virtual bool enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props); + virtual bool fix(JSContext *cx, JSObject *proxy, Value *vp); /* ES5 Harmony derived proxy traps. */ virtual bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp); virtual bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp); - virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); - virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); - virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &props); - virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp); + virtual bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp); + virtual bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp); + virtual bool enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props); + virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp); static JSScriptedProxyHandler singleton; }; @@ -466,11 +462,11 @@ JSScriptedProxyHandler::~JSScriptedProxyHandler() } static bool -ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, jsval v) +ReturnedValueMustNotBePrimitive(JSContext *cx, JSObject *proxy, JSAtom *atom, const Value &v) { - if (JSVAL_IS_PRIMITIVE(v)) { + if (v.isPrimitive()) { js_ReportValueError2(cx, JSMSG_BAD_TRAP_RETURN_VALUE, - JSDVG_SEARCH_STACK, OBJECT_TO_JSVAL(proxy), NULL, + JSDVG_SEARCH_STACK, ObjectOrNullValue(proxy), NULL, js_AtomToPrintableString(cx, atom)); return false; } @@ -481,12 +477,12 @@ static JSObject * GetProxyHandlerObject(JSContext *cx, JSObject *proxy) { JS_ASSERT(OperationInProgress(cx, proxy)); - return JSVAL_TO_OBJECT(proxy->getProxyPrivate()); + return proxy->getProxyPrivate().toObjectOrNull(); } bool JSScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc) + PropertyDescriptor *desc) { JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); @@ -498,7 +494,7 @@ JSScriptedProxyHandler::getPropertyDescriptor(JSContext *cx, JSObject *proxy, js bool JSScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc) + PropertyDescriptor *desc) { JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); @@ -510,7 +506,7 @@ JSScriptedProxyHandler::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, bool JSScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc) + PropertyDescriptor *desc) { JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); @@ -521,7 +517,7 @@ JSScriptedProxyHandler::defineProperty(JSContext *cx, JSObject *proxy, jsid id, } bool -JSScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoValueVector &props) +JSScriptedProxyHandler::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props) { JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); @@ -541,7 +537,7 @@ JSScriptedProxyHandler::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *b } bool -JSScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoValueVector &props) +JSScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props) { JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); @@ -551,7 +547,7 @@ JSScriptedProxyHandler::enumerate(JSContext *cx, JSObject *proxy, AutoValueVecto } bool -JSScriptedProxyHandler::fix(JSContext *cx, JSObject *proxy, jsval *vp) +JSScriptedProxyHandler::fix(JSContext *cx, JSObject *proxy, Value *vp) { JSObject *handler = GetProxyHandlerObject(cx, proxy); return FundamentalTrap(cx, handler, ATOM(fix), vp) && @@ -585,14 +581,14 @@ JSScriptedProxyHandler::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp } bool -JSScriptedProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) +JSScriptedProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp) { JSObject *handler = GetProxyHandlerObject(cx, proxy); - JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); + JSString *str = js_ValueToString(cx, IdToValue(id)); if (!str) return false; - AutoValueRooter tvr(cx, STRING_TO_JSVAL(str)); - jsval argv[] = { OBJECT_TO_JSVAL(receiver), tvr.value() }; + AutoValueRooter tvr(cx, StringValue(str)); + Value argv[] = { ObjectOrNullValue(receiver), tvr.value() }; AutoValueRooter fval(cx); if (!DerivedTrap(cx, handler, ATOM(get), fval.addr())) return false; @@ -602,14 +598,14 @@ JSScriptedProxyHandler::get(JSContext *cx, JSObject *proxy, JSObject *receiver, } bool -JSScriptedProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) +JSScriptedProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp) { JSObject *handler = GetProxyHandlerObject(cx, proxy); - JSString *str = js_ValueToString(cx, ID_TO_VALUE(id)); + JSString *str = js_ValueToString(cx, IdToValue(id)); if (!str) return false; - AutoValueRooter tvr(cx, STRING_TO_JSVAL(str)); - jsval argv[] = { OBJECT_TO_JSVAL(receiver), tvr.value(), *vp }; + AutoValueRooter tvr(cx, StringValue(str)); + Value argv[] = { ObjectOrNullValue(receiver), tvr.value(), *vp }; AutoValueRooter fval(cx); if (!DerivedTrap(cx, handler, ATOM(set), fval.addr())) return false; @@ -619,7 +615,7 @@ JSScriptedProxyHandler::set(JSContext *cx, JSObject *proxy, JSObject *receiver, } bool -JSScriptedProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &props) +JSScriptedProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props) { JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); @@ -632,7 +628,7 @@ JSScriptedProxyHandler::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVe } bool -JSScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp) +JSScriptedProxyHandler::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp) { JSObject *handler = GetProxyHandlerObject(cx, proxy); AutoValueRooter tvr(cx); @@ -663,56 +659,56 @@ class AutoPendingProxyOperation { }; bool -JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) +JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->getPropertyDescriptor(cx, proxy, id, desc); } bool -JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp) +JSProxy::getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, Value *vp) { AutoPendingProxyOperation pending(cx, proxy); - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); return JSProxy::getPropertyDescriptor(cx, proxy, id, &desc) && MakePropertyDescriptorObject(cx, id, &desc, vp); } bool JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc) + PropertyDescriptor *desc) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->getOwnPropertyDescriptor(cx, proxy, id, desc); } bool -JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp) +JSProxy::getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, Value *vp) { AutoPendingProxyOperation pending(cx, proxy); - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); return JSProxy::getOwnPropertyDescriptor(cx, proxy, id, &desc) && MakePropertyDescriptorObject(cx, id, &desc, vp); } bool -JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc) +JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->defineProperty(cx, proxy, id, desc); } bool -JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, jsval v) +JSProxy::defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v) { AutoPendingProxyOperation pending(cx, proxy); - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); return ParsePropertyDescriptorObject(cx, proxy, id, v, &desc) && JSProxy::defineProperty(cx, proxy, id, &desc); } bool -JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoValueVector &props) +JSProxy::getOwnPropertyNames(JSContext *cx, JSObject *proxy, AutoIdVector &props) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->getOwnPropertyNames(cx, proxy, props); @@ -726,14 +722,14 @@ JSProxy::delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) } bool -JSProxy::enumerate(JSContext *cx, JSObject *proxy, AutoValueVector &props) +JSProxy::enumerate(JSContext *cx, JSObject *proxy, AutoIdVector &props) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->enumerate(cx, proxy, props); } bool -JSProxy::fix(JSContext *cx, JSObject *proxy, jsval *vp) +JSProxy::fix(JSContext *cx, JSObject *proxy, Value *vp) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->fix(cx, proxy, vp); @@ -754,42 +750,42 @@ JSProxy::hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp) } bool -JSProxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) +JSProxy::get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->get(cx, proxy, receiver, id, vp); } bool -JSProxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp) +JSProxy::set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->set(cx, proxy, receiver, id, vp); } bool -JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, AutoValueVector &props) +JSProxy::enumerateOwn(JSContext *cx, JSObject *proxy, AutoIdVector &props) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->enumerateOwn(cx, proxy, props); } bool -JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp) +JSProxy::iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->iterate(cx, proxy, flags, vp); } bool -JSProxy::call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp) +JSProxy::call(JSContext *cx, JSObject *proxy, uintN argc, Value *vp) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->call(cx, proxy, argc, vp); } bool -JSProxy::construct(JSContext *cx, JSObject *proxy, uintN argc, jsval *argv, jsval *rval) +JSProxy::construct(JSContext *cx, JSObject *proxy, uintN argc, Value *argv, Value *rval) { AutoPendingProxyOperation pending(cx, proxy); return proxy->getProxyHandler()->construct(cx, proxy, argc, argv, rval); @@ -818,7 +814,7 @@ proxy_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, return false; if (found) { - *propp = (JSProperty *)id; + *propp = (JSProperty *)0x1; *objp = obj; } else { *objp = NULL; @@ -828,12 +824,12 @@ proxy_LookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, } static JSBool -proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs) +proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *value, + PropertyOp getter, PropertyOp setter, uintN attrs) { - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); desc.obj = obj; - desc.value = value; + desc.value = *value; desc.attrs = (attrs & (~JSPROP_SHORTID)); desc.getter = getter; desc.setter = setter; @@ -842,13 +838,13 @@ proxy_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, } static JSBool -proxy_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +proxy_GetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return JSProxy::get(cx, obj, obj, id, vp); } static JSBool -proxy_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +proxy_SetProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return JSProxy::set(cx, obj, obj, id, vp); } @@ -856,7 +852,7 @@ proxy_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) static JSBool proxy_GetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, &desc)) return false; *attrsp = desc.attrs; @@ -867,7 +863,7 @@ static JSBool proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { /* Lookup the current property descriptor so we have setter/getter/value. */ - AutoDescriptor desc(cx); + AutoPropertyDescriptorRooter desc(cx); if (!JSProxy::getOwnPropertyDescriptor(cx, obj, id, &desc)) return false; desc.attrs = (*attrsp & (~JSPROP_SHORTID)); @@ -875,12 +871,12 @@ proxy_SetAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) } static JSBool -proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsval id, jsval *rval) +proxy_DeleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval) { bool deleted; if (!JSProxy::delete_(cx, obj, id, &deleted)) return false; - *rval = BOOLEAN_TO_JSVAL(deleted); + rval->setBoolean(deleted); return true; } @@ -892,7 +888,7 @@ proxy_TraceObject(JSTracer *trc, JSObject *obj) if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList)) js_TraceWatchPoints(trc, obj); - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); if (clasp->mark) { if (clasp->flags & JSCLASS_MARK_IS_TRACE) ((JSTraceOp) clasp->mark)(trc, obj); @@ -902,10 +898,10 @@ proxy_TraceObject(JSTracer *trc, JSObject *obj) obj->traceProtoAndParent(trc); obj->getProxyHandler()->trace(trc, obj); - JS_CALL_VALUE_TRACER(trc, obj->getProxyPrivate(), "private"); + MarkValue(trc, obj->getProxyPrivate(), "private"); if (obj->isFunctionProxy()) { - JS_CALL_VALUE_TRACER(trc, GetCall(obj), "call"); - JS_CALL_VALUE_TRACER(trc, GetConstruct(obj), "construct"); + MarkValue(trc, GetCall(obj), "call"); + MarkValue(trc, GetConstruct(obj), "construct"); } } @@ -919,7 +915,7 @@ void proxy_Finalize(JSContext *cx, JSObject *obj) { JS_ASSERT(obj->isProxy()); - if (obj->getSlot(JSSLOT_PROXY_HANDLER) != JSVAL_VOID) + if (!obj->getSlot(JSSLOT_PROXY_HANDLER).isUndefined()) obj->getProxyHandler()->finalize(cx, obj); } @@ -947,32 +943,32 @@ JSObjectOps js_ObjectProxyObjectOps = { }; static JSObjectOps * -obj_proxy_getObjectOps(JSContext *cx, JSClass *clasp) +obj_proxy_getObjectOps(JSContext *cx, Class *clasp) { return &js_ObjectProxyObjectOps; } -JS_FRIEND_API(JSClass) ObjectProxyClass = { +JS_FRIEND_API(Class) ObjectProxyClass = { "Proxy", JSCLASS_HAS_RESERVED_SLOTS(2), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, obj_proxy_getObjectOps, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; JSBool -proxy_Call(JSContext *cx, uintN argc, jsval *vp) +proxy_Call(JSContext *cx, uintN argc, Value *vp) { - JSObject *proxy = JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)); + JSObject *proxy = &JS_CALLEE(cx, vp).toObject(); JS_ASSERT(proxy->isProxy()); return JSProxy::call(cx, proxy, argc, vp); } JSBool -proxy_Construct(JSContext *cx, JSObject * /*obj*/, uintN argc, jsval *argv, jsval *rval) +proxy_Construct(JSContext *cx, JSObject * /*obj*/, uintN argc, Value *argv, Value *rval) { - JSObject *proxy = JSVAL_TO_OBJECT(argv[-2]); + JSObject *proxy = &argv[-2].toObject(); JS_ASSERT(proxy->isProxy()); return JSProxy::construct(cx, proxy, argc, argv, rval); } @@ -1009,51 +1005,51 @@ JSObjectOps js_FunctionProxyObjectOps = { }; static JSObjectOps * -fun_proxy_getObjectOps(JSContext *cx, JSClass *clasp) +fun_proxy_getObjectOps(JSContext *cx, Class *clasp) { return &js_FunctionProxyObjectOps; } -JS_FRIEND_API(JSClass) FunctionProxyClass = { +JS_FRIEND_API(Class) FunctionProxyClass = { "Proxy", JSCLASS_HAS_RESERVED_SLOTS(4), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, fun_proxy_getObjectOps, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; JS_FRIEND_API(JSObject *) -NewProxyObject(JSContext *cx, JSProxyHandler *handler, jsval priv, JSObject *proto, JSObject *parent, +NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObject *proto, JSObject *parent, JSObject *call, JSObject *construct) { bool fun = call || construct; - JSClass *clasp = fun ? &FunctionProxyClass : &ObjectProxyClass; + Class *clasp = fun ? &FunctionProxyClass : &ObjectProxyClass; JSObject *obj = NewObjectWithGivenProto(cx, clasp, proto, parent); if (!obj || (construct && !js_EnsureReservedSlots(cx, obj, 0))) return NULL; - obj->setSlot(JSSLOT_PROXY_HANDLER, PRIVATE_TO_JSVAL(handler)); + obj->setSlot(JSSLOT_PROXY_HANDLER, PrivateValue(handler)); obj->setSlot(JSSLOT_PROXY_PRIVATE, priv); if (fun) { - obj->setSlot(JSSLOT_PROXY_CALL, call ? OBJECT_TO_JSVAL(call) : JSVAL_VOID); + obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue()); if (construct) - obj->setSlot(JSSLOT_PROXY_CONSTRUCT, construct ? OBJECT_TO_JSVAL(construct) : JSVAL_VOID); + obj->setSlot(JSSLOT_PROXY_CONSTRUCT, construct ? ObjectValue(*construct) : UndefinedValue()); } return obj; } static JSObject * -NonNullObject(JSContext *cx, jsval v) +NonNullObject(JSContext *cx, const Value &v) { - if (JSVAL_IS_PRIMITIVE(v)) { + if (v.isPrimitive()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT); return NULL; } - return JSVAL_TO_OBJECT(v); + return &v.toObject(); } static JSBool -proxy_create(JSContext *cx, uintN argc, jsval *vp) +proxy_create(JSContext *cx, uintN argc, Value *vp) { if (argc < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -1064,26 +1060,26 @@ proxy_create(JSContext *cx, uintN argc, jsval *vp) if (!(handler = NonNullObject(cx, vp[2]))) return false; JSObject *proto, *parent = NULL; - if (argc > 1 && !JSVAL_IS_PRIMITIVE(vp[3])) { - proto = JSVAL_TO_OBJECT(vp[3]); + if (argc > 1 && vp[3].isObject()) { + proto = &vp[3].toObject(); parent = proto->getParent(); } else { - JS_ASSERT(VALUE_IS_FUNCTION(cx, vp[0])); + JS_ASSERT(IsFunctionObject(vp[0])); proto = NULL; } if (!parent) - parent = JSVAL_TO_OBJECT(vp[0])->getParent(); - JSObject *proxy = NewProxyObject(cx, &JSScriptedProxyHandler::singleton, OBJECT_TO_JSVAL(handler), + parent = vp[0].toObject().getParent(); + JSObject *proxy = NewProxyObject(cx, &JSScriptedProxyHandler::singleton, ObjectValue(*handler), proto, parent); if (!proxy) return false; - *vp = OBJECT_TO_JSVAL(proxy); + vp->setObject(*proxy); return true; } static JSBool -proxy_createFunction(JSContext *cx, uintN argc, jsval *vp) +proxy_createFunction(JSContext *cx, uintN argc, Value *vp) { if (argc < 2) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -1094,7 +1090,7 @@ proxy_createFunction(JSContext *cx, uintN argc, jsval *vp) if (!(handler = NonNullObject(cx, vp[2]))) return false; JSObject *proto, *parent; - parent = JSVAL_TO_OBJECT(vp[0])->getParent(); + parent = vp[0].toObject().getParent(); if (!js_GetClassPrototype(cx, parent, JSProto_Function, &proto)) return false; parent = proto->getParent(); @@ -1109,19 +1105,20 @@ proxy_createFunction(JSContext *cx, uintN argc, jsval *vp) return false; } - JSObject *proxy = NewProxyObject(cx, &JSScriptedProxyHandler::singleton, OBJECT_TO_JSVAL(handler), + JSObject *proxy = NewProxyObject(cx, &JSScriptedProxyHandler::singleton, + ObjectValue(*handler), proto, parent, call, construct); if (!proxy) return false; - *vp = OBJECT_TO_JSVAL(proxy); + vp->setObject(*proxy); return true; } #ifdef DEBUG static JSBool -proxy_isTrapping(JSContext *cx, uintN argc, jsval *vp) +proxy_isTrapping(JSContext *cx, uintN argc, Value *vp) { if (argc < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -1131,12 +1128,12 @@ proxy_isTrapping(JSContext *cx, uintN argc, jsval *vp) JSObject *obj; if (!(obj = NonNullObject(cx, vp[2]))) return false; - *vp = BOOLEAN_TO_JSVAL(obj->isProxy()); + vp->setBoolean(obj->isProxy()); return true; } static JSBool -proxy_fix(JSContext *cx, uintN argc, jsval *vp) +proxy_fix(JSContext *cx, uintN argc, Value *vp) { if (argc < 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED, @@ -1150,9 +1147,9 @@ proxy_fix(JSContext *cx, uintN argc, jsval *vp) JSBool flag; if (!FixProxy(cx, obj, &flag)) return false; - *vp = BOOLEAN_TO_JSVAL(flag); + vp->setBoolean(flag); } else { - *vp = JSVAL_TRUE; + vp->setBoolean(true); } return true; } @@ -1169,64 +1166,67 @@ static JSFunctionSpec static_methods[] = { JS_FS_END }; -extern JSClass CallableObjectClass; +extern Class CallableObjectClass; static const uint32 JSSLOT_CALLABLE_CALL = JSSLOT_PRIVATE; static const uint32 JSSLOT_CALLABLE_CONSTRUCT = JSSLOT_PRIVATE + 1; static JSBool -callable_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +callable_Call(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { - JSObject *callable = JSVAL_TO_OBJECT(argv[-2]); + JSObject *callable = &argv[-2].toObject(); JS_ASSERT(callable->getClass() == &CallableObjectClass); - jsval fval = callable->fslots[JSSLOT_CALLABLE_CALL]; - return js_InternalCall(cx, obj, fval, argc, argv, rval); + const Value &fval = callable->fslots[JSSLOT_CALLABLE_CALL]; + return InternalCall(cx, obj, fval, argc, argv, rval); } static JSBool -callable_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +callable_Construct(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { - JSObject *callable = JSVAL_TO_OBJECT(argv[-2]); + JSObject *callable = &argv[-2].toObject(); JS_ASSERT(callable->getClass() == &CallableObjectClass); - jsval fval = callable->fslots[JSSLOT_CALLABLE_CONSTRUCT]; - if (fval == JSVAL_VOID) { + Value fval = callable->fslots[JSSLOT_CALLABLE_CONSTRUCT]; + if (fval.isUndefined()) { /* We don't have an explicit constructor so allocate a new object and use the call. */ fval = callable->fslots[JSSLOT_CALLABLE_CALL]; - JS_ASSERT(JSVAL_IS_OBJECT(fval)); + JS_ASSERT(fval.isObject()); /* callable is the constructor, so get callable.prototype is the proto of the new object. */ if (!callable->getProperty(cx, ATOM_TO_JSID(ATOM(classPrototype)), rval)) return false; JSObject *proto; - if (!JSVAL_IS_PRIMITIVE(*rval)) { - proto = JSVAL_TO_OBJECT(*rval); + if (rval->isObject()) { + proto = &rval->toObject(); } else { if (!js_GetClassPrototype(cx, NULL, JSProto_Object, &proto)) return false; } JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent()); - *rval = OBJECT_TO_JSVAL(newobj); + if (!newobj) + return false; + + rval->setObject(*newobj); /* If the call returns an object, return that, otherwise the original newobj. */ - if (!js_InternalCall(cx, newobj, callable->fslots[JSSLOT_CALLABLE_CALL], - argc, argv, rval)) { + if (!InternalCall(cx, newobj, callable->fslots[JSSLOT_CALLABLE_CALL], + argc, argv, rval)) { return false; } - if (JSVAL_IS_PRIMITIVE(*rval)) - *rval = OBJECT_TO_JSVAL(newobj); + if (rval->isPrimitive()) + rval->setObject(*newobj); return true; } - return js_InternalCall(cx, obj, fval, argc, argv, rval); + return InternalCall(cx, obj, fval, argc, argv, rval); } -JSClass CallableObjectClass = { +Class CallableObjectClass = { "Function", JSCLASS_HAS_RESERVED_SLOTS(2), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, NULL, NULL, callable_Call, callable_Construct, NULL, NULL, NULL, NULL }; @@ -1237,7 +1237,7 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp) AutoValueRooter tvr(cx); if (!JSProxy::fix(cx, proxy, tvr.addr())) return false; - if (tvr.value() == JSVAL_VOID) { + if (tvr.value().isUndefined()) { *bp = false; return true; } @@ -1253,13 +1253,13 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp) JSObject *proto = proxy->getProto(); JSObject *parent = proxy->getParent(); - JSClass *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass; + Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass; /* Make a blank object from the recipe fix provided to us. */ JSObject *newborn = NewObjectWithGivenProto(cx, clasp, proto, parent); if (!newborn) return NULL; - AutoValueRooter tvr2(cx, newborn); + AutoObjectRooter tvr2(cx, newborn); if (clasp == &CallableObjectClass) { newborn->fslots[JSSLOT_CALLABLE_CALL] = GetCall(proxy); @@ -1283,11 +1283,11 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp) } -JSClass js_ProxyClass = { +Class js_ProxyClass = { "Proxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index 5ccb8e0b9281..abbad5e0345e 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -57,28 +57,28 @@ class JSProxyHandler { /* ES5 Harmony fundamental proxy traps. */ virtual bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc) = 0; + PropertyDescriptor *desc) = 0; virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc) = 0; + PropertyDescriptor *desc) = 0; virtual bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc) = 0; - virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, js::AutoValueVector &props) = 0; + PropertyDescriptor *desc) = 0; + virtual bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, js::AutoIdVector &props) = 0; virtual bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp) = 0; - virtual bool enumerate(JSContext *cx, JSObject *proxy, js::AutoValueVector &props) = 0; - virtual bool fix(JSContext *cx, JSObject *proxy, jsval *vp) = 0; + virtual bool enumerate(JSContext *cx, JSObject *proxy, js::AutoIdVector &props) = 0; + virtual bool fix(JSContext *cx, JSObject *proxy, Value *vp) = 0; /* ES5 Harmony derived proxy traps. */ virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *proxy, jsid id, bool *bp); virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp); - virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); - virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); - virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoValueVector &props); - virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp); + virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, js::Value *vp); + virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, js::Value *vp); + virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoIdVector &props); + virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *proxy, uintN flags, js::Value *vp); /* Spidermonkey extensions. */ - virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp); + virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *proxy, uintN argc, js::Value *vp); virtual JS_FRIEND_API(bool) construct(JSContext *cx, JSObject *proxy, - uintN argc, jsval *argv, jsval *rval); + uintN argc, js::Value *argv, js::Value *rval); virtual JS_FRIEND_API(JSString *) obj_toString(JSContext *cx, JSObject *proxy); virtual JS_FRIEND_API(JSString *) fun_toString(JSContext *cx, JSObject *proxy, uintN indent); virtual JS_FRIEND_API(void) finalize(JSContext *cx, JSObject *proxy); @@ -94,29 +94,29 @@ class JSProxy { public: /* ES5 Harmony fundamental proxy traps. */ static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc); - static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp); + PropertyDescriptor *desc); + static bool getPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, Value *vp); static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, - JSPropertyDescriptor *desc); - static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, jsval *vp); - static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, JSPropertyDescriptor *desc); - static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, jsval v); - static bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, js::AutoValueVector &props); + PropertyDescriptor *desc); + static bool getOwnPropertyDescriptor(JSContext *cx, JSObject *proxy, jsid id, Value *vp); + static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, PropertyDescriptor *desc); + static bool defineProperty(JSContext *cx, JSObject *proxy, jsid id, const Value &v); + static bool getOwnPropertyNames(JSContext *cx, JSObject *proxy, js::AutoIdVector &props); static bool delete_(JSContext *cx, JSObject *proxy, jsid id, bool *bp); - static bool enumerate(JSContext *cx, JSObject *proxy, js::AutoValueVector &props); - static bool fix(JSContext *cx, JSObject *proxy, jsval *vp); + static bool enumerate(JSContext *cx, JSObject *proxy, js::AutoIdVector &props); + static bool fix(JSContext *cx, JSObject *proxy, Value *vp); /* ES5 Harmony derived proxy traps. */ static bool has(JSContext *cx, JSObject *proxy, jsid id, bool *bp); static bool hasOwn(JSContext *cx, JSObject *proxy, jsid id, bool *bp); - static bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); - static bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, jsval *vp); - static bool enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoValueVector &props); - static bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp); + static bool get(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp); + static bool set(JSContext *cx, JSObject *proxy, JSObject *receiver, jsid id, Value *vp); + static bool enumerateOwn(JSContext *cx, JSObject *proxy, js::AutoIdVector &props); + static bool iterate(JSContext *cx, JSObject *proxy, uintN flags, Value *vp); /* Spidermonkey extensions. */ - static bool call(JSContext *cx, JSObject *proxy, uintN argc, jsval *vp); - static bool construct(JSContext *cx, JSObject *proxy, uintN argc, jsval *argv, jsval *rval); + static bool call(JSContext *cx, JSObject *proxy, uintN argc, js::Value *vp); + static bool construct(JSContext *cx, JSObject *proxy, uintN argc, js::Value *argv, js::Value *rval); static JSString *obj_toString(JSContext *cx, JSObject *proxy); static JSString *fun_toString(JSContext *cx, JSObject *proxy, uintN indent); }; @@ -128,9 +128,9 @@ const uint32 JSSLOT_PROXY_PRIVATE = JSSLOT_PRIVATE + 1; const uint32 JSSLOT_PROXY_CALL = JSSLOT_PRIVATE + 2; const uint32 JSSLOT_PROXY_CONSTRUCT = JSSLOT_PRIVATE + 3; -extern JS_FRIEND_API(JSClass) ObjectProxyClass; -extern JS_FRIEND_API(JSClass) FunctionProxyClass; -extern JSClass CallableObjectClass; +extern JS_FRIEND_API(js::Class) ObjectProxyClass; +extern JS_FRIEND_API(js::Class) FunctionProxyClass; +extern js::Class CallableObjectClass; } @@ -156,11 +156,10 @@ inline js::JSProxyHandler * JSObject::getProxyHandler() const { JS_ASSERT(isProxy()); - jsval handler = getSlot(js::JSSLOT_PROXY_HANDLER); - return (js::JSProxyHandler *) JSVAL_TO_PRIVATE(handler); + return (js::JSProxyHandler *) getSlot(js::JSSLOT_PROXY_HANDLER).toPrivate(); } -inline jsval +inline const js::Value & JSObject::getProxyPrivate() const { JS_ASSERT(isProxy()); @@ -168,7 +167,7 @@ JSObject::getProxyPrivate() const } inline void -JSObject::setProxyPrivate(jsval priv) +JSObject::setProxyPrivate(const js::Value &priv) { JS_ASSERT(isProxy()); setSlot(js::JSSLOT_PROXY_PRIVATE, priv); @@ -177,7 +176,8 @@ JSObject::setProxyPrivate(jsval priv) namespace js { JS_FRIEND_API(JSObject *) -NewProxyObject(JSContext *cx, JSProxyHandler *handler, jsval priv, JSObject *proto, JSObject *parent, +NewProxyObject(JSContext *cx, JSProxyHandler *handler, const js::Value &priv, + JSObject *proto, JSObject *parent, JSObject *call = NULL, JSObject *construct = NULL); JS_FRIEND_API(JSBool) @@ -187,7 +187,7 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp); JS_BEGIN_EXTERN_C -extern JSClass js_ProxyClass; +extern js::Class js_ProxyClass; extern JS_FRIEND_API(JSObject *) js_InitProxyClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsprvtd.h b/js/src/jsprvtd.h index b8548b50df63..a5a1b03e2e1a 100644 --- a/js/src/jsprvtd.h +++ b/js/src/jsprvtd.h @@ -57,26 +57,7 @@ #include "jspubtd.h" #include "jsutil.h" -/* Internal identifier (jsid) macros. */ - -#define JSID_IS_ATOM(id) JSVAL_IS_STRING((jsval)(id)) -#define JSID_TO_ATOM(id) ((JSAtom *)(id)) -#define ATOM_TO_JSID(atom) (JS_ASSERT(ATOM_IS_STRING(atom)), \ - (jsid)(atom)) - -#define JSID_IS_INT(id) JSVAL_IS_INT((jsval)(id)) -#define JSID_TO_INT(id) JSVAL_TO_INT((jsval)(id)) -#define INT_TO_JSID(i) ((jsid)INT_TO_JSVAL(i)) -#define INT_JSVAL_TO_JSID(v) ((jsid)(v)) -#define INT_JSID_TO_JSVAL(id) ((jsval)(id)) -#define INT_FITS_IN_JSID(i) INT_FITS_IN_JSVAL(i) - -#define JSID_IS_OBJECT(id) JSVAL_IS_OBJECT((jsval)(id)) -#define JSID_TO_OBJECT(id) JSVAL_TO_OBJECT((jsval)(id)) -#define OBJECT_TO_JSID(obj) ((jsid)OBJECT_TO_JSVAL(obj)) -#define OBJECT_JSVAL_TO_JSID(v) ((jsid)v) - -#define ID_TO_VALUE(id) ((jsval)(id)) +JS_BEGIN_EXTERN_C /* * Convenience constants. @@ -84,6 +65,10 @@ #define JS_BITS_PER_UINT32_LOG2 5 #define JS_BITS_PER_UINT32 32 +/* The alignment required of objects stored in GC arenas. */ +static const uintN JS_GCTHING_ALIGN = 8; +static const uintN JS_GCTHING_ZEROBITS = 3; + /* Scalar typedefs. */ typedef uint8 jsbytecode; typedef uint8 jssrcnote; @@ -192,11 +177,6 @@ class DeflatedStringCache; class PropertyCache; struct PropertyCacheEntry; -static inline JSPropertyOp -CastAsPropertyOp(JSObject *object) -{ - return JS_DATA_TO_FUNC_PTR(JSPropertyOp, object); -} } /* namespace js */ @@ -232,7 +212,7 @@ typedef JSTrapStatus void *closure); typedef JSBool -(* JSWatchPointHandler)(JSContext *cx, JSObject *obj, jsval id, jsval old, +(* JSWatchPointHandler)(JSContext *cx, JSObject *obj, jsid id, jsval old, jsval *newp, void *closure); /* called just after script creation */ @@ -341,7 +321,7 @@ typedef JSBool * value, with the specified getter, setter, and attributes. */ typedef JSBool -(* JSDefinePropOp)(JSContext *cx, JSObject *obj, jsid id, jsval value, +(* JSDefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const jsval *value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs); /* @@ -380,4 +360,6 @@ typedef JSBool extern JSBool js_CStringsAreUTF8; #endif +JS_END_EXTERN_C + #endif /* jsprvtd_h___ */ diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 942e35caddb3..c030ee972e6b 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -44,6 +44,7 @@ */ #include "jstypes.h" #include "jscompat.h" +#include "jsval.h" JS_BEGIN_EXTERN_C @@ -52,8 +53,6 @@ typedef uint16 jschar; typedef int32 jsint; typedef uint32 jsuint; typedef float64 jsdouble; -typedef jsword jsval; -typedef jsword jsid; typedef int32 jsrefcount; /* PRInt32 if JS_THREADSAFE, see jslock.h */ /* @@ -150,13 +149,11 @@ typedef struct JSTracer JSTracer; typedef struct JSIdArray JSIdArray; typedef struct JSPropertyDescriptor JSPropertyDescriptor; typedef struct JSPropertySpec JSPropertySpec; -typedef struct JSObject JSObject; typedef struct JSObjectMap JSObjectMap; typedef struct JSObjectOps JSObjectOps; typedef struct JSRuntime JSRuntime; typedef struct JSScript JSScript; typedef struct JSStackFrame JSStackFrame; -typedef struct JSString JSString; typedef struct JSXDRState JSXDRState; typedef struct JSExceptionState JSExceptionState; typedef struct JSLocaleCallbacks JSLocaleCallbacks; @@ -172,14 +169,14 @@ typedef class JSCrossCompartmentWrapper JSCrossCompartmentWrapper; /* JSClass (and JSObjectOps where appropriate) function pointer typedefs. */ /* - * Add, delete, get or set a property named by id in obj. Note the jsval id + * Add, delete, get or set a property named by id in obj. Note the jsid id * type -- id may be a string (Unicode property identifier) or an int (element * index). The *vp out parameter, on success, is the new property value after * an add, get, or set. After a successful delete, *vp is JSVAL_FALSE iff * obj[id] can't be deleted (because it's permanent). */ typedef JSBool -(* JSPropertyOp)(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +(* JSPropertyOp)(JSContext *cx, JSObject *obj, jsid id, jsval *vp); /* * This function type is used for callbacks that enumerate the properties of @@ -237,7 +234,7 @@ typedef JSBool * NB: JSNewResolveOp provides a cheaper way to resolve lazy properties. */ typedef JSBool -(* JSResolveOp)(JSContext *cx, JSObject *obj, jsval id); +(* JSResolveOp)(JSContext *cx, JSObject *obj, jsid id); /* * Like JSResolveOp, but flags provide contextual information as follows: @@ -269,7 +266,7 @@ typedef JSBool * *objp without a new JSClass flag. */ typedef JSBool -(* JSNewResolveOp)(JSContext *cx, JSObject *obj, jsval id, uintN flags, +(* JSNewResolveOp)(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); /* @@ -330,7 +327,7 @@ typedef JSObjectOps * * is either a string or an int jsval. */ typedef JSBool -(* JSCheckAccessOp)(JSContext *cx, JSObject *obj, jsval id, JSAccessMode mode, +(* JSCheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp); /* @@ -346,7 +343,7 @@ typedef JSBool * *bp otherwise. */ typedef JSBool -(* JSHasInstanceOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +(* JSHasInstanceOp)(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); /* * Deprecated function type for JSClass.mark. All new code should define @@ -400,10 +397,10 @@ extern JSMarkOp js_WrongTypeForClassTracer; * JS_TraceChildren on the passed thing. In this case the callback must be * prepared to deal with cycles in the traversal graph. * - * kind argument is one of JSTRACE_OBJECT, JSTRACE_DOUBLE, JSTRACE_STRING or - * a tag denoting internal implementation-specific traversal kind. In the - * latter case the only operations on thing that the callback can do is to call - * JS_TraceChildren or DEBUG-only JS_PrintTraceThingInfo. + * kind argument is one of JSTRACE_OBJECT, JSTRACE_STRING or a tag denoting + * internal implementation-specific traversal kind. In the latter case the only + * operations on thing that the callback can do is to call JS_TraceChildren or + * DEBUG-only JS_PrintTraceThingInfo. */ typedef void (* JSTraceCallback)(JSTracer *trc, void *thing, uint32 kind); @@ -418,7 +415,7 @@ typedef void /* JSExtendedClass function pointer typedefs. */ typedef JSBool -(* JSEqualityOp)(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +(* JSEqualityOp)(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); /* * A generic type for functions mapping an object to another object, or null diff --git a/js/src/jsrecursion.cpp b/js/src/jsrecursion.cpp index 98dedcee3bd1..807b47edd41c 100644 --- a/js/src/jsrecursion.cpp +++ b/js/src/jsrecursion.cpp @@ -38,6 +38,8 @@ * * ***** END LICENSE BLOCK ***** */ +#include "jsapi.h" + class RecursiveSlotMap : public SlotMap { protected: @@ -128,15 +130,15 @@ TraceRecorder::assertDownFrameIsConsistent(VMSideExit* anchor, FrameInfo* fi) JS_ASSERT(anchor->recursive_down->callerHeight == fi->callerHeight); unsigned downPostSlots = fi->callerHeight; - TraceType* typeMap = fi->get_typemap(); + JSValueType* typeMap = fi->get_typemap(); captureStackTypes(1, typeMap); - const TraceType* m1 = anchor->recursive_down->get_typemap(); + const JSValueType* m1 = anchor->recursive_down->get_typemap(); for (unsigned i = 0; i < downPostSlots; i++) { if (m1[i] == typeMap[i]) continue; - if ((typeMap[i] == TT_INT32 && m1[i] == TT_DOUBLE) || - (typeMap[i] == TT_DOUBLE && m1[i] == TT_INT32)) { + if ((typeMap[i] == JSVAL_TYPE_INT32 && m1[i] == JSVAL_TYPE_DOUBLE) || + (typeMap[i] == JSVAL_TYPE_DOUBLE && m1[i] == JSVAL_TYPE_INT32)) { continue; } JS_NOT_REACHED("invalid RECURSIVE_MISMATCH exit"); @@ -154,8 +156,8 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame) unsigned downPostSlots = downFrame->callerHeight; unsigned ngslots = tree->globalSlots->length(); unsigned exitTypeMapLen = downPostSlots + 1 + ngslots; - TraceType* exitTypeMap = (TraceType*)alloca(sizeof(TraceType) * exitTypeMapLen); - TraceType* typeMap = downFrame->get_typemap(); + JSValueType* exitTypeMap = (JSValueType*)alloca(sizeof(JSValueType) * exitTypeMapLen); + JSValueType* typeMap = downFrame->get_typemap(); /* Add stack slots. */ @@ -167,13 +169,13 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame) if (*cx->regs->pc == JSOP_RETURN) exitTypeMap[downPostSlots] = determineSlotType(&stackval(-1)); else - exitTypeMap[downPostSlots] = TT_VOID; + exitTypeMap[downPostSlots] = JSVAL_TYPE_UNDEFINED; /* Add global types. */ determineGlobalTypes(&exitTypeMap[downPostSlots + 1]); VMSideExit* exit = (VMSideExit*) - traceMonitor->traceAlloc->alloc(sizeof(VMSideExit) + sizeof(TraceType) * exitTypeMapLen); + traceMonitor->traceAlloc->alloc(sizeof(VMSideExit) + sizeof(JSValueType) * exitTypeMapLen); PodZero(exit); exit->from = fragment; @@ -191,14 +193,14 @@ TraceRecorder::downSnapshot(FrameInfo* downFrame) exit->rp_adj = exit->calldepth * sizeof(FrameInfo*); exit->nativeCalleeWord = 0; exit->lookupFlags = js_InferFlags(cx, 0); - memcpy(exit->fullTypeMap(), exitTypeMap, sizeof(TraceType) * exitTypeMapLen); + memcpy(exit->fullTypeMap(), exitTypeMap, sizeof(JSValueType) * exitTypeMapLen); #if defined JS_JIT_SPEW TreevisLogExit(cx, exit); #endif return exit; } -static JS_REQUIRES_STACK jsval * +static JS_REQUIRES_STACK Value * DownFrameSP(JSContext *cx) { FrameRegsIter i(cx); @@ -245,7 +247,7 @@ TraceRecorder::upRecursion() */ unsigned totalSlots = NativeStackSlots(cx, 1); unsigned downPostSlots = totalSlots - NativeStackSlots(cx, 0); - FrameInfo* fi = (FrameInfo*)alloca(sizeof(FrameInfo) + totalSlots * sizeof(TraceType)); + FrameInfo* fi = (FrameInfo*)alloca(sizeof(FrameInfo) + totalSlots * sizeof(JSValueType)); fi->block = NULL; fi->pc = (jsbytecode*)return_pc; fi->imacpc = NULL; @@ -279,7 +281,7 @@ TraceRecorder::upRecursion() } else { /* Case 2: Guess that up-recursion is backing out, infer types from our Tree. */ JS_ASSERT(tree->nStackTypes == downPostSlots + 1); - TraceType* typeMap = fi->get_typemap(); + JSValueType* typeMap = fi->get_typemap(); for (unsigned i = 0; i < downPostSlots; i++) typeMap[i] = tree->typeMap[i]; } @@ -322,13 +324,13 @@ TraceRecorder::upRecursion() rval_ins = get(&stackval(-1)); JS_ASSERT(rval_ins); } else { - rval_ins = INS_VOID(); + rval_ins = INS_UNDEFINED(); } - TraceType returnType = exit->stackTypeMap()[downPostSlots]; - if (returnType == TT_INT32) { + JSValueType returnType = exit->stackTypeMap()[downPostSlots]; + if (returnType == JSVAL_TYPE_INT32) { JS_ASSERT(*cx->regs->pc == JSOP_RETURN); - JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32); + JS_ASSERT(determineSlotType(&stackval(-1)) == JSVAL_TYPE_INT32); JS_ASSERT(isPromoteInt(rval_ins)); rval_ins = demote(lir, rval_ins); } @@ -339,7 +341,7 @@ TraceRecorder::upRecursion() if (*cx->regs->pc == JSOP_RETURN) slotMap.addSlot(&stackval(-1)); else - slotMap.addSlot(TT_VOID); + slotMap.addSlot(JSVAL_TYPE_UNDEFINED); VisitGlobalSlots(slotMap, cx, *tree->globalSlots); if (recursive_pc == (jsbytecode*)fragment->root->ip) { debug_only_print0(LC_TMTracer, "Compiling up-recursive loop...\n"); @@ -358,7 +360,7 @@ class SlurpInfo { public: unsigned curSlot; - TraceType* typeMap; + JSValueType* typeMap; VMSideExit* exit; unsigned slurpFailSlot; }; @@ -481,7 +483,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) unsigned safeSlots = NativeStackSlots(cx, frameDepth) + 1 + numGlobalSlots; jsbytecode* recursive_pc = return_pc + JSOP_CALL_LENGTH; VMSideExit* exit = (VMSideExit*) - traceMonitor->traceAlloc->alloc(sizeof(VMSideExit) + sizeof(TraceType) * safeSlots); + traceMonitor->traceAlloc->alloc(sizeof(VMSideExit) + sizeof(JSValueType) * safeSlots); PodZero(exit); exit->pc = (jsbytecode*)recursive_pc; exit->from = fragment; @@ -495,7 +497,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) * Build the exit typemap. This may capture extra types, but they are * thrown away. */ - TraceType* typeMap = exit->stackTypeMap(); + JSValueType* typeMap = exit->stackTypeMap(); jsbytecode* oldpc = cx->regs->pc; cx->regs->pc = exit->pc; captureStackTypes(frameDepth, typeMap); @@ -505,7 +507,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) if (*cx->regs->pc == JSOP_RETURN) typeMap[downPostSlots] = determineSlotType(&stackval(-1)); else - typeMap[downPostSlots] = TT_VOID; + typeMap[downPostSlots] = JSVAL_TYPE_UNDEFINED; } else { typeMap[downPostSlots] = anchor->stackTypeMap()[anchor->numStackSlots - 1]; } @@ -525,7 +527,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) */ LIns* rval_ins; intptr_t offset = exit->sp_adj - sizeof(double); - TraceType returnType = exit->stackTypeMap()[downPostSlots]; + JSValueType returnType = exit->stackTypeMap()[downPostSlots]; if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) { /* @@ -537,13 +539,13 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) if (op == JSOP_RETURN) { rval_ins = get(&stackval(-1)); - if (returnType == TT_INT32) { - JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32); + if (returnType == JSVAL_TYPE_INT32) { + JS_ASSERT(determineSlotType(&stackval(-1)) == JSVAL_TYPE_INT32); JS_ASSERT(isPromoteInt(rval_ins)); rval_ins = demote(lir, rval_ins); } } else { - rval_ins = INS_VOID(); + rval_ins = INS_UNDEFINED(); } /* @@ -554,18 +556,18 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) } else { switch (returnType) { - case TT_SPECIAL: - case TT_VOID: - case TT_INT32: + case JSVAL_TYPE_BOOLEAN: + case JSVAL_TYPE_UNDEFINED: + case JSVAL_TYPE_INT32: rval_ins = lir->insLoad(LIR_ldi, lirbuf->sp, offset, ACC_STACK); break; - case TT_DOUBLE: + case JSVAL_TYPE_DOUBLE: rval_ins = lir->insLoad(LIR_ldd, lirbuf->sp, offset, ACC_STACK); break; - case TT_FUNCTION: - case TT_OBJECT: - case TT_STRING: - case TT_NULL: + case JSVAL_TYPE_FUNOBJ: + case JSVAL_TYPE_NONFUNOBJ: + case JSVAL_TYPE_STRING: + case JSVAL_TYPE_NULL: rval_ins = lir->insLoad(LIR_ldp, lirbuf->sp, offset, ACC_STACK); break; default: @@ -585,52 +587,36 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) JSStackFrame *const fp = i.fp(); /* callee */ - slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -2 * ptrdiff_t(sizeof(jsval)), ACC_OTHER), - &fp->argv[-2], - &info); + slurpSlot(argv_ins, -2 * ptrdiff_t(sizeof(Value)), &fp->argv[-2], &info); /* this */ - slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -1 * ptrdiff_t(sizeof(jsval)), ACC_OTHER), - &fp->argv[-1], - &info); + slurpSlot(argv_ins, -1 * ptrdiff_t(sizeof(Value)), &fp->argv[-1], &info); /* args[0..n] */ for (unsigned i = 0; i < JS_MAX(fp->argc, fp->fun->nargs); i++) - slurpSlot(lir->insLoad(LIR_ldp, argv_ins, i * sizeof(jsval), ACC_OTHER), - &fp->argv[i], - &info); + slurpSlot(argv_ins, i * sizeof(Value), &fp->argv[i], &info); /* argsobj */ - slurpSlot(addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argsobj), ACC_OTHER), - "argsobj"), - &fp->argsobj, - &info); + slurpFrameObjPtrSlot(fp_ins, offsetof(JSStackFrame, argsobj), &fp->argsobj, &info); /* scopeChain */ - slurpSlot(addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, scopeChain), ACC_OTHER), - "scopeChain"), - &fp->scopeChainVal, - &info); + slurpFrameObjPtrSlot(fp_ins, offsetof(JSStackFrame, scopeChain), &fp->scopeChain, &info); /* vars */ LIns* slots_ins = addName(lir->ins2(LIR_addp, fp_ins, INS_CONSTWORD(sizeof(JSStackFrame))), "slots"); for (unsigned i = 0; i < fp->script->nfixed; i++) - slurpSlot(lir->insLoad(LIR_ldp, slots_ins, i * sizeof(jsval), ACC_OTHER), - &fp->slots()[i], - &info); + slurpSlot(slots_ins, i * sizeof(Value), &fp->slots()[i], &info); /* stack vals */ unsigned nfixed = fp->script->nfixed; - jsval* stack = StackBase(fp); + Value* stack = fp->base(); LIns* stack_ins = addName(lir->ins2(LIR_addp, slots_ins, - INS_CONSTWORD(nfixed * sizeof(jsval))), + INS_CONSTWORD(nfixed * sizeof(Value))), "stackBase"); - size_t limit = size_t(i.sp() - StackBase(fp)); + size_t limit = size_t(i.sp() - fp->base()); if (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT) limit--; else limit -= fp->fun->nargs + 2; for (size_t i = 0; i < limit; i++) - slurpSlot(lir->insLoad(LIR_ldp, stack_ins, i * sizeof(jsval), ACC_OTHER), - &stack[i], - &info); + slurpSlot(stack_ins, i * sizeof(Value), &stack[i], &info); JS_ASSERT(info.curSlot == downPostSlots); @@ -647,7 +633,7 @@ TraceRecorder::slurpDownFrames(jsbytecode* return_pc) if (*cx->regs->pc == JSOP_RETURN) slotMap.addSlot(&stackval(-1), typeMap[downPostSlots]); else - slotMap.addSlot(TT_VOID); + slotMap.addSlot(JSVAL_TYPE_UNDEFINED); VisitGlobalSlots(slotMap, cx, *tree->globalSlots); debug_only_print0(LC_TMTracer, "Compiling up-recursive slurp...\n"); exit = copy(exit); @@ -669,11 +655,18 @@ public: {} JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) { + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + /* N.B. vp may point to a JSObject*. */ for (size_t i = 0; i < count; ++i) mRecorder.get(vp++); return true; } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame* fp) { + /* visitStackSlots only uses the address of its argument. */ + return visitStackSlots((Value *)p, 1, fp); + } }; JS_REQUIRES_STACK AbortableRecordingStatus @@ -740,157 +733,63 @@ TraceRecorder::downRecursion() return closeLoop(exit); } -JS_REQUIRES_STACK LIns* -TraceRecorder::slurpInt32Slot(LIns* val_ins, jsval* vp, VMSideExit* exit) +#if JS_BITS_PER_WORD == 32 +JS_REQUIRES_STACK inline LIns* +TraceRecorder::slurpDoubleSlot(LIns* addr_ins, ptrdiff_t offset, VMSideExit* exit) { - guard(true, - lir->ins2(LIR_ori, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(JSVAL_TAGMASK)), - INS_CONSTWORD(JSVAL_DOUBLE)), - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(1)), - INS_CONSTWORD(1))), - exit); - LIns* space = lir->insAlloc(sizeof(int32)); - LIns* args[] = { space, val_ins }; - LIns* result = lir->insCall(&js_TryUnboxInt32_ci, args); - guard(false, lir->insEqI_0(result), exit); - LIns* int32_ins = lir->insLoad(LIR_ldi, space, 0, ACC_OTHER); - return int32_ins; + LIns* tag_ins = lir->insLoad(LIR_ldi, addr_ins, offset + sTagOffset, ACC_OTHER); + return unbox_number_as_double(addr_ins, offset, tag_ins, exit, ACC_OTHER); } JS_REQUIRES_STACK LIns* -TraceRecorder::slurpDoubleSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) +TraceRecorder::slurpObjectSlot(LIns* addr_ins, ptrdiff_t offset, JSValueType type, VMSideExit* exit) { - guard(true, - lir->ins2(LIR_ori, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(JSVAL_TAGMASK)), - INS_CONSTWORD(JSVAL_DOUBLE)), - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(1)), - INS_CONSTWORD(1))), - exit); - LIns* args[] = { val_ins }; - LIns* dbl_ins = lir->insCall(&js_UnboxDouble_ci, args); - return dbl_ins; + LIns* tag_ins = lir->insLoad(LIR_ldi, addr_ins, offset + sTagOffset, ACC_OTHER); + return unbox_object(addr_ins, offset, tag_ins, type, exit, ACC_OTHER); +} + +JS_REQUIRES_STACK inline LIns* +TraceRecorder::slurpNonDoubleObjectSlot(LIns* addr_ins, ptrdiff_t offset, JSValueType type, VMSideExit* exit) +{ + LIns* tag_ins = lir->insLoad(LIR_ldi, addr_ins, offset + sTagOffset, ACC_OTHER); + return unbox_non_double_object(addr_ins, offset, tag_ins, type, exit, ACC_OTHER); +} +#elif JS_BITS_PER_WORD == 64 +JS_REQUIRES_STACK inline LIns* +TraceRecorder::slurpDoubleSlot(LIns* addr_ins, ptrdiff_t offset, VMSideExit* exit) +{ + LIns* v_ins = lir->insLoad(LIR_ldq, addr_ins, offset, ACC_OTHER); + return unbox_number_as_double(v_ins, exit); } JS_REQUIRES_STACK LIns* -TraceRecorder::slurpSpecialSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) +TraceRecorder::slurpObjectSlot(LIns* addr_ins, ptrdiff_t offset, JSValueType type, VMSideExit* exit) { - guard(true, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(JSVAL_TAGMASK)), - INS_CONSTWORD(JSVAL_SPECIAL)), - exit); - LIns* bool_ins = lir->ins2(LIR_rshp, val_ins, INS_CONST(JSVAL_TAGBITS)); - bool_ins = p2i(bool_ins); - return bool_ins; + LIns* v_ins = lir->insLoad(LIR_ldq, addr_ins, offset, ACC_OTHER); + return unbox_object(v_ins, type, exit); } -JS_REQUIRES_STACK LIns* -TraceRecorder::slurpVoidSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) +JS_REQUIRES_STACK inline LIns* +TraceRecorder::slurpNonDoubleObjectSlot(LIns* addr_ins, ptrdiff_t offset, JSValueType type, VMSideExit* exit) { - guard(true, lir->ins2(LIR_eqp, val_ins, INS_CONSTWORD(JSVAL_VOID)), exit); - return INS_VOID(); + LIns* v_ins = lir->insLoad(LIR_ldq, addr_ins, offset, ACC_OTHER); + return unbox_non_double_object(v_ins, type, exit); } +#endif -JS_REQUIRES_STACK LIns* -TraceRecorder::slurpStringSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) +JS_REQUIRES_STACK inline LIns* +TraceRecorder::slurpSlot(LIns* addr_ins, ptrdiff_t offset, Value* vp, VMSideExit* exit) { - guard(true, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(JSVAL_TAGMASK)), - INS_CONSTWORD(JSVAL_STRING)), - exit); - LIns* str_ins = lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(~JSVAL_TAGMASK)); - return str_ins; -} - -JS_REQUIRES_STACK LIns* -TraceRecorder::slurpNullSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) -{ - guard(true, lir->insEqP_0(val_ins), exit); - return val_ins; -} - -JS_REQUIRES_STACK LIns* -TraceRecorder::slurpObjectSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) -{ - /* Must not be NULL */ - guard(false, lir->insEqP_0(val_ins), exit); - - /* Must be an object */ - guard(true, - lir->insEqP_0(lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(JSVAL_TAGMASK))), - exit); - - /* Must NOT have a function class */ - guard(false, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, - lir->insLoad(LIR_ldp, val_ins, offsetof(JSObject, classword), - ACC_OTHER), - INS_CONSTWORD(~JSSLOT_CLASS_MASK_BITS)), - INS_CONSTPTR(&js_FunctionClass)), - exit); - return val_ins; -} - -JS_REQUIRES_STACK LIns* -TraceRecorder::slurpFunctionSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) -{ - /* Must not be NULL */ - guard(false, lir->insEqP_0(val_ins), exit); - - /* Must be an object */ - guard(true, - lir->insEqP_0(lir->ins2(LIR_andp, val_ins, INS_CONSTWORD(JSVAL_TAGMASK))), - exit); - - /* Must have a function class */ - guard(true, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, - lir->insLoad(LIR_ldp, val_ins, offsetof(JSObject, classword), - ACC_OTHER), - INS_CONSTWORD(~JSSLOT_CLASS_MASK_BITS)), - INS_CONSTPTR(&js_FunctionClass)), - exit); - return val_ins; -} - -JS_REQUIRES_STACK LIns* -TraceRecorder::slurpSlot(LIns* val_ins, jsval* vp, VMSideExit* exit) -{ - switch (exit->slurpType) - { - case TT_SPECIAL: - return slurpSpecialSlot(val_ins, vp, exit); - case TT_VOID: - return slurpVoidSlot(val_ins, vp, exit); - case TT_INT32: - return slurpInt32Slot(val_ins, vp, exit); - case TT_DOUBLE: - return slurpDoubleSlot(val_ins, vp, exit); - case TT_STRING: - return slurpStringSlot(val_ins, vp, exit); - case TT_NULL: - return slurpNullSlot(val_ins, vp, exit); - case TT_OBJECT: - return slurpObjectSlot(val_ins, vp, exit); - case TT_FUNCTION: - return slurpFunctionSlot(val_ins, vp, exit); - default: - JS_NOT_REACHED("invalid type in typemap"); - return NULL; - } + if (exit->slurpType == JSVAL_TYPE_DOUBLE) + return slurpDoubleSlot(addr_ins, offset, exit); + if (exit->slurpType == JSVAL_TYPE_FUNOBJ || exit->slurpType == JSVAL_TYPE_NONFUNOBJ) + return slurpObjectSlot(addr_ins, offset, exit->slurpType, exit); + JSValueType type = exit->slurpType; + return slurpNonDoubleObjectSlot(addr_ins, offset, type, exit); } JS_REQUIRES_STACK void -TraceRecorder::slurpSlot(LIns* val_ins, jsval* vp, SlurpInfo* info) +TraceRecorder::slurpSlot(LIns* addr_ins, ptrdiff_t offset, Value* vp, SlurpInfo* info) { /* Don't re-read slots that aren't needed. */ if (info->curSlot < info->slurpFailSlot) { @@ -901,18 +800,51 @@ TraceRecorder::slurpSlot(LIns* val_ins, jsval* vp, SlurpInfo* info) exit->slurpFailSlot = info->curSlot; exit->slurpType = info->typeMap[info->curSlot]; -#if defined DEBUG /* Make sure that we don't try and record infinity branches */ JS_ASSERT_IF(anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT && info->curSlot == info->slurpFailSlot, anchor->slurpType != exit->slurpType); -#endif - LIns* val = slurpSlot(val_ins, vp, exit); + LIns* val = slurpSlot(addr_ins, offset, vp, exit); lir->insStore(val, - lirbuf->sp, - -tree->nativeStackBase + ptrdiff_t(info->curSlot) * sizeof(double), - ACC_STACK); + lirbuf->sp, + -tree->nativeStackBase + ptrdiff_t(info->curSlot) * sizeof(double), + ACC_STACK); info->curSlot++; } +JS_REQUIRES_STACK void +TraceRecorder::slurpFrameObjPtrSlot(LIns* addr_ins, ptrdiff_t offset, JSObject** p, SlurpInfo* info) +{ + /* Don't re-read slots that aren't needed. */ + if (info->curSlot < info->slurpFailSlot) { + info->curSlot++; + return; + } + VMSideExit* exit = copy(info->exit); + exit->slurpFailSlot = info->curSlot; + exit->slurpType = info->typeMap[info->curSlot]; + + /* Make sure that we don't try and record infinity branches */ + JS_ASSERT_IF(anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT && + info->curSlot == info->slurpFailSlot, + anchor->slurpType != exit->slurpType); + + LIns *val; + LIns *ptr_val = lir->insLoad(LIR_ldp, addr_ins, offset, ACC_OTHER); + LIns *ptr_is_null_ins = lir->insEqP_0(ptr_val); + if (exit->slurpType == JSVAL_TYPE_NULL) { + guard(true, ptr_is_null_ins, exit); + val = INS_NULL(); + } else { + JS_ASSERT(exit->slurpType == JSVAL_TYPE_NONFUNOBJ); + guard(false, ptr_is_null_ins, exit); + val = ptr_val; + } + + lir->insStore(val, + lirbuf->sp, + -tree->nativeStackBase + ptrdiff_t(info->curSlot) * sizeof(double), + ACC_STACK); + info->curSlot++; +} diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 6942060696ec..a3c9fbc21ac0 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -2242,9 +2242,9 @@ CharSet::disjoint(const CharSet &other) const /* Check char-char overlap. */ jschar tmp[CharSet::sBufSize]; js_MergeSort(charBuf, charEnd - charBuf, sizeof(jschar), - CharCmp, 0, tmp); + CharCmp, 0, tmp, JS_SORTING_GENERIC); js_MergeSort(other.charBuf, other.charEnd - other.charBuf, sizeof(jschar), - CharCmp, 0, tmp); + CharCmp, 0, tmp, JS_SORTING_GENERIC); return set_disjoint(charBuf, charEnd, other.charBuf, other.charEnd); } @@ -4890,7 +4890,7 @@ bad: JSBool js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, - JSBool test, jsval *rval) + JSBool test, Value *rval) { REGlobalData gData; REMatchState *x, *result; @@ -4951,7 +4951,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, if (!ok) goto out; if (!result) { - *rval = JSVAL_NULL; + rval->setNull(); goto out; } cp = result->cp; @@ -4967,7 +4967,7 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, * Testing for a match and updating cx->regExpStatics: don't allocate * an array object, do return true. */ - *rval = JSVAL_TRUE; + rval->setBoolean(true); /* Avoid warning. (gcc doesn't detect that obj is needed iff !test); */ obj = NULL; @@ -4983,11 +4983,12 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, ok = JS_FALSE; goto out; } - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); -#define DEFVAL(val, id) { \ - ok = js_DefineProperty(cx, obj, id, val, \ - JS_PropertyStub, JS_PropertyStub, \ +#define DEFVAL(valinit, id) { \ + Value tmp = valinit; \ + ok = js_DefineProperty(cx, obj, id, &tmp, \ + PropertyStub, PropertyStub, \ JSPROP_ENUMERATE); \ if (!ok) \ goto out; \ @@ -4999,7 +5000,8 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, ok = JS_FALSE; goto out; } - DEFVAL(STRING_TO_JSVAL(matchstr), INT_TO_JSID(0)); + + DEFVAL(StringValue(matchstr), INT_TO_JSID(0)); } res = &cx->regExpStatics; @@ -5024,8 +5026,9 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, if (test) continue; if (parsub->index == -1) { - ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1), JSVAL_VOID, NULL, NULL, - JSPROP_ENUMERATE); + Value tmp = UndefinedValue(); + ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1), + &tmp, NULL, NULL, JSPROP_ENUMERATE); } else { parstr = js_NewDependentString(cx, str, gData.cpbegin + parsub->index - @@ -5035,8 +5038,9 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, ok = JS_FALSE; goto out; } - ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1), STRING_TO_JSVAL(parstr), - NULL, NULL, JSPROP_ENUMERATE); + Value tmp = StringValue(parstr); + ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1), + &tmp, NULL, NULL, JSPROP_ENUMERATE); } if (!ok) goto out; @@ -5054,9 +5058,9 @@ js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, * Define the index and input properties last for better for/in loop * order (so they come after the elements). */ - DEFVAL(INT_TO_JSVAL(start + gData.skipped), + DEFVAL(Int32Value(start + gData.skipped), ATOM_TO_JSID(cx->runtime->atomState.indexAtom)); - DEFVAL(STRING_TO_JSVAL(str), + DEFVAL(StringValue(str), ATOM_TO_JSID(cx->runtime->atomState.inputAtom)); } @@ -5082,16 +5086,16 @@ out: /************************************************************************/ -static JSBool +static void SetRegExpLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex) { JS_ASSERT(obj->isRegExp()); - return JS_NewNumberValue(cx, lastIndex, obj->addressOfRegExpLastIndex()); + obj->setRegExpLastIndex(NumberValue(lastIndex)); } #define DEFINE_GETTER(name, code) \ static JSBool \ - name(JSContext *cx, JSObject *obj, jsval id, jsval *vp) \ + name(JSContext *cx, JSObject *obj, jsid id, Value *vp) \ { \ while (obj->getClass() != &js_RegExpClass) { \ obj = obj->getProto(); \ @@ -5107,14 +5111,14 @@ SetRegExpLastIndex(JSContext *cx, JSObject *obj, jsdouble lastIndex) /* lastIndex is stored in the object, re = re silences the compiler warning. */ DEFINE_GETTER(lastIndex_getter, re = re; *vp = obj->getRegExpLastIndex()) -DEFINE_GETTER(source_getter, *vp = STRING_TO_JSVAL(re->source)) -DEFINE_GETTER(global_getter, *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_GLOB) != 0)) -DEFINE_GETTER(ignoreCase_getter, *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_FOLD) != 0)) -DEFINE_GETTER(multiline_getter, *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_MULTILINE) != 0)) -DEFINE_GETTER(sticky_getter, *vp = BOOLEAN_TO_JSVAL((re->flags & JSREG_STICKY) != 0)) +DEFINE_GETTER(source_getter, vp->setString(re->source)) +DEFINE_GETTER(global_getter, vp->setBoolean((re->flags & JSREG_GLOB) != 0)) +DEFINE_GETTER(ignoreCase_getter, vp->setBoolean((re->flags & JSREG_FOLD) != 0)) +DEFINE_GETTER(multiline_getter, vp->setBoolean((re->flags & JSREG_MULTILINE) != 0)) +DEFINE_GETTER(sticky_getter, vp->setBoolean((re->flags & JSREG_STICKY) != 0)) static JSBool -lastIndex_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +lastIndex_setter(JSContext *cx, JSObject *obj, jsid id, Value *vp) { while (obj->getClass() != &js_RegExpClass) { obj = obj->getProto(); @@ -5122,16 +5126,17 @@ lastIndex_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return true; } jsdouble lastIndex; - if (!JS_ValueToNumber(cx, *vp, &lastIndex)) + if (!ValueToNumber(cx, *vp, &lastIndex)) return false; lastIndex = js_DoubleToInteger(lastIndex); - return SetRegExpLastIndex(cx, obj, lastIndex); + SetRegExpLastIndex(cx, obj, lastIndex); + return true; } static const struct LazyProp { const char *name; uint16 atomOffset; - JSPropertyOp getter; + PropertyOp getter; } lazyRegExpProps[] = { { js_source_str, ATOM_OFFSET(source), source_getter }, { js_global_str, ATOM_OFFSET(global), global_getter }, @@ -5168,7 +5173,7 @@ regexp_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **ob return JS_TRUE; if (id == ATOM_TO_JSID(cx->runtime->atomState.lastIndexAtom)) { - if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, + if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), lastIndex_getter, lastIndex_setter, JSPROP_PERMANENT | JSPROP_SHARED, 0, 0, NULL)) { return JS_FALSE; @@ -5181,7 +5186,7 @@ regexp_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **ob const LazyProp &lazy = lazyRegExpProps[i]; JSAtom *atom = OFFSET_TO_ATOM(cx->runtime, lazy.atomOffset); if (id == ATOM_TO_JSID(atom)) { - if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID, + if (!js_DefineNativeProperty(cx, obj, id, UndefinedValue(), lazy.getter, NULL, JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_READONLY, 0, 0, NULL)) { @@ -5225,7 +5230,7 @@ js_InitRegExpStatics(JSContext *cx) JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - AutoValueRooter *tvr) + AutoStringRooter *tvr) { statics->copy(cx->regExpStatics); if (statics->input) @@ -5235,7 +5240,7 @@ js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - AutoValueRooter *tvr) + AutoStringRooter *tvr) { /* Clear/free any new JSRegExpStatics data before clobbering. */ cx->regExpStatics.copy(*statics); @@ -5259,14 +5264,15 @@ js_FreeRegExpStatics(JSContext *cx) #define DEFINE_STATIC_GETTER(name, code) \ static JSBool \ - name(JSContext *cx, JSObject *obj, jsval id, jsval *vp) \ + name(JSContext *cx, JSObject *obj, jsid id, jsval *vp) \ { \ JSRegExpStatics *res = &cx->regExpStatics; \ code; \ } static bool -MakeString(JSContext *cx, JSSubString *sub, jsval *vp) { +MakeString(JSContext *cx, JSSubString *sub, jsval *vp) +{ JSString *str = js_NewStringCopyN(cx, sub->chars, sub->length); if (!str) return false; @@ -5303,7 +5309,7 @@ DEFINE_STATIC_GETTER(static_paren9_getter, return Paren(cx, res, 8, vp)) #define DEFINE_STATIC_SETTER(name, code) \ static JSBool \ - name(JSContext *cx, JSObject *obj, jsval id, jsval *vp) \ + name(JSContext *cx, JSObject *obj, jsid id, jsval *vp) \ { \ JSRegExpStatics *res = &cx->regExpStatics; \ code; \ @@ -5322,6 +5328,9 @@ DEFINE_STATIC_SETTER(static_multiline_setter, const uint8 REGEXP_STATIC_PROP_ATTRS = JSPROP_PERMANENT | JSPROP_SHARED | JSPROP_ENUMERATE; const uint8 RO_REGEXP_STATIC_PROP_ATTRS = REGEXP_STATIC_PROP_ATTRS | JSPROP_READONLY; +#define G Jsvalify(regexp_static_getProperty) +#define S Jsvalify(regexp_static_setProperty) + static JSPropertySpec regexp_static_props[] = { {"input", 0, REGEXP_STATIC_PROP_ATTRS, static_input_getter, static_input_setter}, {"multiline", 0, REGEXP_STATIC_PROP_ATTRS, static_multiline_getter, @@ -5353,13 +5362,13 @@ regexp_finalize(JSContext *cx, JSObject *obj) /* Forward static prototype. */ static JSBool -regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - JSBool test, jsval *rval); +regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, + JSBool test, Value *rval); static JSBool -regexp_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +regexp_call(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { - return regexp_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, JS_FALSE, rval); + return regexp_exec_sub(cx, &argv[-2].toObject(), argc, argv, JS_FALSE, rval); } #if JS_HAS_XDR @@ -5415,15 +5424,15 @@ regexp_trace(JSTracer *trc, JSObject *obj) JS_CALL_STRING_TRACER(trc, re->source, "source"); } -JSClass js_RegExpClass = { +Class js_RegExpClass = { js_RegExp_str, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(JSObject::REGEXP_FIXED_RESERVED_SLOTS) | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp), - JS_PropertyStub, JS_PropertyStub, - JS_PropertyStub, JS_PropertyStub, + PropertyStub, PropertyStub, + PropertyStub, PropertyStub, regexp_enumerate, reinterpret_cast(regexp_resolve), - JS_ConvertStub, regexp_finalize, + ConvertStub, regexp_finalize, NULL, NULL, regexp_call, NULL, js_XDRRegExpObject, NULL, @@ -5433,7 +5442,7 @@ JSClass js_RegExpClass = { static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0}; JSBool -js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp) +js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp) { JSRegExp *re; const jschar *source; @@ -5442,13 +5451,13 @@ js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp) uintN flags; JSString *str; - if (!JS_InstanceOf(cx, obj, &js_RegExpClass, vp + 2)) + if (!InstanceOf(cx, obj, &js_RegExpClass, vp + 2)) return JS_FALSE; JS_LOCK_OBJ(cx, obj); re = (JSRegExp *) obj->getPrivate(); if (!re) { JS_UNLOCK_OBJ(cx, obj); - *vp = STRING_TO_JSVAL(cx->runtime->emptyString); + vp->setString(cx->runtime->emptyString); return JS_TRUE; } @@ -5488,22 +5497,20 @@ js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp) cx->free(chars); return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -regexp_toString(JSContext *cx, uintN argc, jsval *vp) +regexp_toString(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); return obj && js_regexp_toString(cx, obj, vp); } static JSBool -regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, + Value *rval) { JSString *opt, *str; JSRegExp *oldre, *re; @@ -5512,13 +5519,13 @@ regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, const jschar *cp, *start, *end; jschar *nstart, *ncp, *tmp; - if (!JS_InstanceOf(cx, obj, &js_RegExpClass, argv)) + if (!InstanceOf(cx, obj, &js_RegExpClass, argv)) return JS_FALSE; opt = NULL; if (argc == 0) { str = cx->runtime->emptyString; } else { - if (JSVAL_IS_OBJECT(argv[0])) { + if (argv[0].isObjectOrNull()) { /* * If we get passed in a RegExp object we construct a new * RegExp that is a duplicate of it by re-compiling the @@ -5526,9 +5533,9 @@ regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, * here if the flags are specified. (We must use the flags * from the original RegExp also). */ - obj2 = JSVAL_TO_OBJECT(argv[0]); + obj2 = argv[0].toObjectOrNull(); if (obj2 && obj2->getClass() == &js_RegExpClass) { - if (argc >= 2 && !JSVAL_IS_VOID(argv[1])) { /* 'flags' passed */ + if (argc >= 2 && !argv[1].isUndefined()) { /* 'flags' passed */ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NEWREGEXP_FLAGGED); return JS_FALSE; @@ -5547,15 +5554,15 @@ regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, str = js_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); + argv[0].setString(str); if (argc > 1) { - if (JSVAL_IS_VOID(argv[1])) { + if (argv[1].isUndefined()) { opt = NULL; } else { opt = js_ValueToString(cx, argv[1]); if (!opt) return JS_FALSE; - argv[1] = STRING_TO_JSVAL(opt); + argv[1].setString(opt); } } @@ -5596,7 +5603,7 @@ regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, cx->free(nstart); return JS_FALSE; } - argv[0] = STRING_TO_JSVAL(str); + argv[0].setString(str); } } @@ -5611,22 +5618,20 @@ created: JS_UNLOCK_OBJ(cx, obj); if (oldre) js_DestroyRegExp(cx, oldre); - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); return JS_TRUE; } static JSBool -regexp_compile(JSContext *cx, uintN argc, jsval *vp) +regexp_compile(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); return obj && regexp_compile_sub(cx, obj, argc, vp + 2, vp); } static JSBool -regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - JSBool test, jsval *rval) +regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, Value *argv, + JSBool test, Value *rval) { JSBool ok, sticky; JSRegExp *re; @@ -5634,7 +5639,7 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JSString *str; size_t i; - ok = JS_InstanceOf(cx, obj, &js_RegExpClass, argv); + ok = InstanceOf(cx, obj, &js_RegExpClass, argv); if (!ok) return JS_FALSE; JS_LOCK_OBJ(cx, obj); @@ -5648,13 +5653,7 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, HOLD_REGEXP(cx, re); sticky = (re->flags & JSREG_STICKY) != 0; if (re->flags & (JSREG_GLOB | JSREG_STICKY)) { - jsval v = obj->getRegExpLastIndex(); - if (JSVAL_IS_INT(v)) { - lastIndex = JSVAL_TO_INT(v); - } else { - JS_ASSERT(JSVAL_IS_DOUBLE(v)); - lastIndex = *JSVAL_TO_DOUBLE(v); - } + lastIndex = obj->getRegExpLastIndex().toNumber(); } else { lastIndex = 0; } @@ -5684,21 +5683,21 @@ regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, ok = JS_FALSE; goto out; } - argv[0] = STRING_TO_JSVAL(str); + argv[0].setString(str); } if (lastIndex < 0 || str->length() < lastIndex) { obj->zeroRegExpLastIndex(); - *rval = JSVAL_NULL; + rval->setNull(); } else { i = (size_t) lastIndex; ok = js_ExecuteRegExp(cx, re, str, &i, test, rval); if (ok && - ((re->flags & JSREG_GLOB) || (*rval != JSVAL_NULL && sticky))) { - if (*rval == JSVAL_NULL) + ((re->flags & JSREG_GLOB) || (!rval->isNull() && sticky))) { + if (rval->isNull()) obj->zeroRegExpLastIndex(); else - ok = SetRegExpLastIndex(cx, obj, i); + SetRegExpLastIndex(cx, obj, i); } } @@ -5708,19 +5707,20 @@ out: } static JSBool -regexp_exec(JSContext *cx, uintN argc, jsval *vp) +regexp_exec(JSContext *cx, uintN argc, Value *vp) { - return regexp_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, JS_FALSE, - vp); + return regexp_exec_sub(cx, ComputeThisFromVp(cx, vp), + argc, vp + 2, JS_FALSE, vp); } static JSBool -regexp_test(JSContext *cx, uintN argc, jsval *vp) +regexp_test(JSContext *cx, uintN argc, Value *vp) { - if (!regexp_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, JS_TRUE, vp)) + if (!regexp_exec_sub(cx, ComputeThisFromVp(cx, vp), + argc, vp + 2, JS_TRUE, vp)) return JS_FALSE; - if (*vp != JSVAL_TRUE) - *vp = JSVAL_FALSE; + if (!vp->isTrue()) + vp->setBoolean(false); return JS_TRUE; } @@ -5736,7 +5736,7 @@ static JSFunctionSpec regexp_methods[] = { }; static JSBool -RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +RegExp(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { if (!JS_IsConstructing(cx)) { /* @@ -5744,9 +5744,8 @@ RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * (regexp_compile_sub detects the regexp + flags case and throws a * TypeError.) See 10.15.3.1. */ - if ((argc < 2 || JSVAL_IS_VOID(argv[1])) && - !JSVAL_IS_PRIMITIVE(argv[0]) && - JSVAL_TO_OBJECT(argv[0])->getClass() == &js_RegExpClass) { + if ((argc < 2 || argv[1].isUndefined()) && argv[0].isObject() && + argv[0].toObject().getClass() == &js_RegExpClass) { *rval = argv[0]; return JS_TRUE; } @@ -5760,7 +5759,7 @@ RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * regexp_compile_sub does not use rval to root its temporaries so we * can use it to root obj. */ - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); } return regexp_compile_sub(cx, obj, argc, argv, rval); } @@ -5778,7 +5777,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj) return NULL; /* Give RegExp.prototype private data so it matches the empty string. */ - jsval rval; + Value rval; if (!JS_AliasProperty(cx, ctor, "input", "$_") || !JS_AliasProperty(cx, ctor, "multiline", "$*") || !JS_AliasProperty(cx, ctor, "lastMatch", "$&") || @@ -5803,7 +5802,7 @@ js_NewRegExpObject(JSContext *cx, TokenStream *ts, str = js_NewStringCopyN(cx, chars, length); if (!str) return NULL; - AutoValueRooter tvr(cx, str); + AutoStringRooter tvr(cx, str); re = js_NewRegExp(cx, ts, str, flags, JS_FALSE); if (!re) return NULL; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index 09659ed71a5c..b299c336f8cc 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -50,17 +50,15 @@ #include "jsdhash.h" #endif -JS_BEGIN_EXTERN_C - -namespace js { class AutoValueRooter; } +namespace js { class AutoStringRooter; } extern JS_FRIEND_API(void) js_SaveAndClearRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - js::AutoValueRooter *tvr); + js::AutoStringRooter *tvr); extern JS_FRIEND_API(void) js_RestoreRegExpStatics(JSContext *cx, JSRegExpStatics *statics, - js::AutoValueRooter *tvr); + js::AutoStringRooter *tvr); /* * This struct holds a bitmap representation of a class from a regexp. @@ -115,7 +113,7 @@ js_DestroyRegExp(JSContext *cx, JSRegExp *re); */ extern JSBool js_ExecuteRegExp(JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, - JSBool test, jsval *rval); + JSBool test, js::Value *rval); extern void js_InitRegExpStatics(JSContext *cx); @@ -127,9 +125,9 @@ extern void js_FreeRegExpStatics(JSContext *cx); #define VALUE_IS_REGEXP(cx, v) \ - (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isRegExp()) + ((v).isObject() && v.toObject().isRegExp()) -extern JSClass js_RegExpClass; +extern js::Class js_RegExpClass; inline bool JSObject::isRegExp() const @@ -147,7 +145,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj); * Export js_regexp_toString to the decompiler. */ extern JSBool -js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp); +js_regexp_toString(JSContext *cx, JSObject *obj, js::Value *vp); /* * Create, serialize/deserialize, or clone a RegExp object. @@ -166,6 +164,4 @@ js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto); extern bool js_ContainsRegExpMetaChars(const jschar *chars, size_t length); -JS_END_EXTERN_C - #endif /* jsregexp_h___ */ diff --git a/js/src/jsscope.cpp b/js/src/jsscope.cpp index b3796fe76009..39c9c06e3436 100644 --- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -132,7 +132,7 @@ js_GetMutableScope(JSContext *cx, JSObject *obj) newscope->freeslot = nslots; #ifdef DEBUG if (newscope->freeslot < nslots) - obj->setSlot(newscope->freeslot, JSVAL_VOID); + obj->setSlot(newscope->freeslot, UndefinedValue()); #endif JS_DROP_ALL_EMPTY_SCOPE_LOCKS(cx, scope); @@ -211,7 +211,7 @@ JSScope::createTable(JSContext *cx, bool report) } JSScope * -JSScope::create(JSContext *cx, const JSObjectOps *ops, JSClass *clasp, +JSScope::create(JSContext *cx, const JSObjectOps *ops, Class *clasp, JSObject *obj, uint32 shape) { JS_ASSERT(ops->isNative()); @@ -234,7 +234,7 @@ JSScope::create(JSContext *cx, const JSObjectOps *ops, JSClass *clasp, } JSEmptyScope::JSEmptyScope(JSContext *cx, const JSObjectOps *ops, - JSClass *clasp) + Class *clasp) : JSScope(ops, NULL), clasp(clasp) { /* @@ -318,7 +318,7 @@ JSScope::initRuntimeState(JSContext *cx) * is less than freeslot to succeed. As the shared emptyArgumentsScope is * never mutated, it's safe to pretend to have all the slots possible. * - * Note how the fast paths in jsops.cpp for JSOP_LENGTH and JSOP_GETELEM + * Note how the fast paths in jsinterp.cpp for JSOP_LENGTH and JSOP_GETELEM * bypass resolution of scope properties for length and element indices on * arguments objects. This helps ensure that any arguments object needing * its own mutable scope (with unique shape) is a rare event. @@ -383,9 +383,9 @@ JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4); JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD); #if JS_BYTES_PER_WORD == 4 -# define HASH_ID(id) ((JSHashNumber)(id)) +# define HASH_ID(id) ((JSHashNumber)(JSID_BITS(id))) #elif JS_BYTES_PER_WORD == 8 -# define HASH_ID(id) ((JSHashNumber)(id) ^ (JSHashNumber)((id) >> 32)) +# define HASH_ID(id) ((JSHashNumber)(JSID_BITS(id)) ^ (JSHashNumber)((JSID_BITS(id)) >> 32)) #else # error "Unsupported configuration" #endif @@ -409,7 +409,7 @@ JSScope::searchTable(jsid id, bool adding) uint32 sizeMask; JS_ASSERT(table); - JS_ASSERT(!JSVAL_IS_NULL(id)); + JS_ASSERT(!JSID_IS_VOID(id)); /* Compute the primary hash address. */ METER(hashes); @@ -543,7 +543,7 @@ JSScopeProperty * JSScope::getChildProperty(JSContext *cx, JSScopeProperty *parent, JSScopeProperty &child) { - JS_ASSERT(!JSVAL_IS_NULL(child.id)); + JS_ASSERT(!JSID_IS_VOID(child.id)); JS_ASSERT(!child.inDictionary()); /* @@ -640,7 +640,7 @@ JSScope::reportReadOnlyScope(JSContext *cx) JSString *str; const char *bytes; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(object)); + str = js_ValueToString(cx, ObjectOrNullValue(object)); if (!str) return; bytes = js_GetStringBytes(cx, str); @@ -774,14 +774,14 @@ JSScope::toDictionaryMode(JSContext *cx, JSScopeProperty *&aprop) JSScopeProperty * JSScope::addProperty(JSContext *cx, jsid id, - JSPropertyOp getter, JSPropertyOp setter, + PropertyOp getter, PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid) { JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, this)); CHECK_ANCESTOR_LINE(this, true); - JS_ASSERT(!JSVAL_IS_NULL(id)); + JS_ASSERT(!JSID_IS_VOID(id)); JS_ASSERT_IF(!cx->runtime->gcRegenShapes, hasRegenFlag(cx->runtime->gcRegenShapesScopeFlag)); @@ -809,10 +809,10 @@ JSScope::addProperty(JSContext *cx, jsid id, static inline bool NormalizeGetterAndSetter(JSContext *cx, JSScope *scope, jsid id, uintN attrs, uintN flags, - JSPropertyOp &getter, - JSPropertyOp &setter) + PropertyOp &getter, + PropertyOp &setter) { - if (setter == JS_PropertyStub) { + if (setter == PropertyStub) { JS_ASSERT(!(attrs & JSPROP_SETTER)); setter = NULL; } @@ -822,7 +822,7 @@ NormalizeGetterAndSetter(JSContext *cx, JSScope *scope, JS_ASSERT(!setter || setter == js_watch_set); JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); } else { - if (getter == JS_PropertyStub) { + if (getter == PropertyStub) { JS_ASSERT(!(attrs & JSPROP_GETTER)); getter = NULL; } @@ -846,7 +846,7 @@ NormalizeGetterAndSetter(JSContext *cx, JSScope *scope, JSScopeProperty * JSScope::addPropertyHelper(JSContext *cx, jsid id, - JSPropertyOp getter, JSPropertyOp setter, + PropertyOp getter, PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid, JSScopeProperty **spp) @@ -905,7 +905,7 @@ JSScope::addPropertyHelper(JSContext *cx, jsid id, JSScopeProperty * JSScope::putProperty(JSContext *cx, jsid id, - JSPropertyOp getter, JSPropertyOp setter, + PropertyOp getter, PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid) { @@ -914,7 +914,7 @@ JSScope::putProperty(JSContext *cx, jsid id, JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, this)); CHECK_ANCESTOR_LINE(this, true); - JS_ASSERT(!JSVAL_IS_NULL(id)); + JS_ASSERT(!JSID_IS_VOID(id)); JS_ASSERT_IF(!cx->runtime->gcRegenShapes, hasRegenFlag(cx->runtime->gcRegenShapesScopeFlag)); @@ -1015,14 +1015,14 @@ JSScope::putProperty(JSContext *cx, jsid id, JSScopeProperty * JSScope::changeProperty(JSContext *cx, JSScopeProperty *sprop, uintN attrs, uintN mask, - JSPropertyOp getter, JSPropertyOp setter) + PropertyOp getter, PropertyOp setter) { JSScopeProperty *newsprop; JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, this)); CHECK_ANCESTOR_LINE(this, true); - JS_ASSERT(!JSVAL_IS_NULL(sprop->id)); + JS_ASSERT(!JSID_IS_VOID(sprop->id)); JS_ASSERT(hasProperty(sprop)); attrs |= sprop->attrs & mask; @@ -1034,9 +1034,9 @@ JSScope::changeProperty(JSContext *cx, JSScopeProperty *sprop, /* Don't allow method properties to be changed to have a getter. */ JS_ASSERT_IF(getter != sprop->rawGetter, !sprop->isMethod()); - if (getter == JS_PropertyStub) + if (getter == PropertyStub) getter = NULL; - if (setter == JS_PropertyStub) + if (setter == PropertyStub) setter = NULL; if (sprop->attrs == attrs && sprop->getter() == getter && sprop->setter() == setter) return sprop; @@ -1181,7 +1181,7 @@ JSScope::clear(JSContext *cx) clearOwnShape(); LeaveTraceIfGlobalObject(cx, object); - JSClass *clasp = object->getClass(); + Class *clasp = object->getClass(); JSObject *proto = object->getProto(); JSEmptyScope *emptyScope; uint32 newShape; @@ -1201,18 +1201,18 @@ JSScope::clear(JSContext *cx) void JSScope::deletingShapeChange(JSContext *cx, JSScopeProperty *sprop) { - JS_ASSERT(!JSVAL_IS_NULL(sprop->id)); + JS_ASSERT(!JSID_IS_VOID(sprop->id)); generateOwnShape(cx); } bool JSScope::methodShapeChange(JSContext *cx, JSScopeProperty *sprop) { - JS_ASSERT(!JSVAL_IS_NULL(sprop->id)); + JS_ASSERT(!JSID_IS_VOID(sprop->id)); if (sprop->isMethod()) { #ifdef DEBUG - jsval prev = object->lockedGetSlot(sprop->slot); - JS_ASSERT(sprop->methodValue() == prev); + const Value &prev = object->lockedGetSlot(sprop->slot); + JS_ASSERT(&sprop->methodObject() == &prev.toObject()); JS_ASSERT(hasMethodBarrier()); JS_ASSERT(object->getClass() == &js_ObjectClass); JS_ASSERT(!sprop->rawSetter || sprop->rawSetter == js_watch_set); @@ -1243,7 +1243,7 @@ JSScope::methodShapeChange(JSContext *cx, uint32 slot) generateOwnShape(cx); } else { for (JSScopeProperty *sprop = lastProp; sprop; sprop = sprop->parent) { - JS_ASSERT(!JSVAL_IS_NULL(sprop->id)); + JS_ASSERT(!JSID_IS_VOID(sprop->id)); if (sprop->slot == slot) return methodShapeChange(cx, sprop); } @@ -1260,7 +1260,7 @@ JSScope::protoShapeChange(JSContext *cx) void JSScope::shadowingShapeChange(JSContext *cx, JSScopeProperty *sprop) { - JS_ASSERT(!JSVAL_IS_NULL(sprop->id)); + JS_ASSERT(!JSID_IS_VOID(sprop->id)); generateOwnShape(cx); } @@ -1271,15 +1271,6 @@ JSScope::globalObjectOwnShapeChange(JSContext *cx) return !js_IsPropertyCacheDisabled(cx); } -void -js_TraceId(JSTracer *trc, jsid id) -{ - jsval v; - - v = ID_TO_VALUE(id); - JS_CALL_VALUE_TRACER(trc, v, "id"); -} - #ifdef DEBUG static void PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize) @@ -1292,12 +1283,12 @@ PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize) JS_ASSERT(trc->debugPrinter == PrintPropertyGetterOrSetter); sprop = (JSScopeProperty *)trc->debugPrintArg; id = sprop->id; - JS_ASSERT(!JSVAL_IS_NULL(id)); + JS_ASSERT(!JSID_IS_VOID(id)); name = trc->debugPrintIndex ? js_setter_str : js_getter_str; if (JSID_IS_ATOM(id)) { n = js_PutEscapedString(buf, bufsize - 1, - ATOM_TO_STRING(JSID_TO_ATOM(id)), 0); + JSID_TO_STRING(id), 0); if (n < bufsize - 1) JS_snprintf(buf + n, bufsize - n, " %s", name); } else if (JSID_IS_INT(sprop->id)) { @@ -1317,10 +1308,10 @@ PrintPropertyMethod(JSTracer *trc, char *buf, size_t bufsize) JS_ASSERT(trc->debugPrinter == PrintPropertyMethod); sprop = (JSScopeProperty *)trc->debugPrintArg; id = sprop->id; - JS_ASSERT(!JSVAL_IS_NULL(id)); + JS_ASSERT(!JSID_IS_VOID(id)); JS_ASSERT(JSID_IS_ATOM(id)); - n = js_PutEscapedString(buf, bufsize - 1, ATOM_TO_STRING(JSID_TO_ATOM(id)), 0); + n = js_PutEscapedString(buf, bufsize - 1, JSID_TO_STRING(id), 0); if (n < bufsize - 1) JS_snprintf(buf + n, bufsize - n, " method"); } @@ -1331,21 +1322,21 @@ JSScopeProperty::trace(JSTracer *trc) { if (IS_GC_MARKING_TRACER(trc)) mark(); - js_TraceId(trc, id); + MarkId(trc, id, "id"); if (attrs & (JSPROP_GETTER | JSPROP_SETTER)) { if ((attrs & JSPROP_GETTER) && rawGetter) { JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, this, 0); - js_CallGCMarker(trc, getterObject(), JSTRACE_OBJECT); + Mark(trc, getterObject(), JSTRACE_OBJECT); } if ((attrs & JSPROP_SETTER) && rawSetter) { JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, this, 1); - js_CallGCMarker(trc, setterObject(), JSTRACE_OBJECT); + Mark(trc, setterObject(), JSTRACE_OBJECT); } } if (isMethod()) { JS_SET_TRACING_DETAILS(trc, PrintPropertyMethod, this, 0); - js_CallGCMarker(trc, methodObject(), JSTRACE_OBJECT); + Mark(trc, &methodObject(), JSTRACE_OBJECT); } } diff --git a/js/src/jsscope.h b/js/src/jsscope.h index 6f0baeccab25..9f1adfeef865 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -63,8 +63,6 @@ #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */ #endif -JS_BEGIN_EXTERN_C - /* * Given P independent, non-unique properties each of size S words mapped by * all scopes in a runtime, construct a property tree of N nodes each of size @@ -287,10 +285,10 @@ struct JSScope : public JSObjectMap JSScopeProperty **searchTable(jsid id, bool adding); inline JSScopeProperty **search(jsid id, bool adding); - inline JSEmptyScope *createEmptyScope(JSContext *cx, JSClass *clasp); + inline JSEmptyScope *createEmptyScope(JSContext *cx, js::Class *clasp); JSScopeProperty *addPropertyHelper(JSContext *cx, jsid id, - JSPropertyOp getter, JSPropertyOp setter, + js::PropertyOp getter, js::PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid, JSScopeProperty **spp); @@ -301,7 +299,7 @@ struct JSScope : public JSObjectMap /* Create a mutable, owned, empty scope. */ static JSScope *create(JSContext *cx, const JSObjectOps *ops, - JSClass *clasp, JSObject *obj, uint32 shape); + js::Class *clasp, JSObject *obj, uint32 shape); void destroy(JSContext *cx); @@ -312,11 +310,11 @@ struct JSScope : public JSObjectMap * If |this| is the scope of an object |proto|, the resulting scope can be * used as the scope of a new object whose prototype is |proto|. */ - inline JSEmptyScope *getEmptyScope(JSContext *cx, JSClass *clasp); + inline JSEmptyScope *getEmptyScope(JSContext *cx, js::Class *clasp); - inline bool ensureEmptyScope(JSContext *cx, JSClass *clasp); + inline bool ensureEmptyScope(JSContext *cx, js::Class *clasp); - inline bool canProvideEmptyScope(JSObjectOps *ops, JSClass *clasp); + inline bool canProvideEmptyScope(JSObjectOps *ops, js::Class *clasp); JSScopeProperty *lookup(jsid id); @@ -325,7 +323,7 @@ struct JSScope : public JSObjectMap /* Add a property whose id is not yet in this scope. */ JSScopeProperty *addProperty(JSContext *cx, jsid id, - JSPropertyOp getter, JSPropertyOp setter, + js::PropertyOp getter, js::PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid); @@ -337,14 +335,14 @@ struct JSScope : public JSObjectMap /* Add or overwrite a property for id in this scope. */ JSScopeProperty *putProperty(JSContext *cx, jsid id, - JSPropertyOp getter, JSPropertyOp setter, + js::PropertyOp getter, js::PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid); /* Change the given property into a sibling with the same id in this scope. */ JSScopeProperty *changeProperty(JSContext *cx, JSScopeProperty *sprop, uintN attrs, uintN mask, - JSPropertyOp getter, JSPropertyOp setter); + js::PropertyOp getter, js::PropertyOp setter); /* Remove id from this scope. */ bool removeProperty(JSContext *cx, jsid id); @@ -360,7 +358,7 @@ struct JSScope : public JSObjectMap * Defined in jsscopeinlines.h, but not declared inline per standard style * in order to avoid gcc warnings. */ - bool methodReadBarrier(JSContext *cx, JSScopeProperty *sprop, jsval *vp); + bool methodReadBarrier(JSContext *cx, JSScopeProperty *sprop, js::Value *vp); /* * Write barrier to check for a method value change. Defined inline below @@ -369,8 +367,8 @@ struct JSScope : public JSObjectMap * flags show this is necessary. The methodShapeChange overload (directly * below) parallels this. */ - bool methodWriteBarrier(JSContext *cx, JSScopeProperty *sprop, jsval v); - bool methodWriteBarrier(JSContext *cx, uint32 slot, jsval v); + bool methodWriteBarrier(JSContext *cx, JSScopeProperty *sprop, const js::Value &v); + bool methodWriteBarrier(JSContext *cx, uint32 slot, const js::Value &v); void trace(JSTracer *trc); @@ -427,7 +425,7 @@ struct JSScope : public JSObjectMap */ bool branded() { return flags & BRANDED; } - bool brand(JSContext *cx, uint32 slot, jsval v) { + bool brand(JSContext *cx, uint32 slot, const js::Value &) { JS_ASSERT(!generic()); JS_ASSERT(!branded()); generateOwnShape(cx); @@ -527,10 +525,10 @@ struct JSScope : public JSObjectMap struct JSEmptyScope : public JSScope { - JSClass * const clasp; - jsrefcount nrefs; /* count of all referencing objects */ + js::Class * const clasp; + jsrefcount nrefs; /* count of all referencing objects */ - JSEmptyScope(JSContext *cx, const JSObjectOps *ops, JSClass *clasp); + JSEmptyScope(JSContext *cx, const JSObjectOps *ops, js::Class *clasp); JSEmptyScope *hold() { /* The method is only called for already held objects. */ @@ -581,7 +579,7 @@ JSObject::shape() const return map->shape; } -inline jsval +inline const js::Value & JSObject::lockedGetSlot(uintN slot) const { OBJ_CHECK_SLOT(this, slot); @@ -589,30 +587,14 @@ JSObject::lockedGetSlot(uintN slot) const } inline void -JSObject::lockedSetSlot(uintN slot, jsval value) +JSObject::lockedSetSlot(uintN slot, const js::Value &value) { OBJ_CHECK_SLOT(this, slot); this->setSlot(slot, value); } -/* - * Helpers for reinterpreting JSPropertyOp as JSObject* for scripted getters - * and setters. - */ namespace js { -inline JSObject * -CastAsObject(JSPropertyOp op) -{ - return JS_FUNC_TO_DATA_PTR(JSObject *, op); -} - -inline jsval -CastAsObjectJSVal(JSPropertyOp op) -{ - return OBJECT_TO_JSVAL(JS_FUNC_TO_DATA_PTR(JSObject *, op)); -} - class PropertyTree; } /* namespace js */ @@ -624,18 +606,18 @@ struct JSScopeProperty { uint32 number, void *arg); friend void js::SweepScopeProperties(JSContext *cx); - jsid id; /* int-tagged jsval/untagged JSAtom* */ + jsid id; private: union { - JSPropertyOp rawGetter; /* getter and setter hooks or objects */ + js::PropertyOp rawGetter; /* getter and setter hooks or objects */ JSObject *getterObj; /* user-defined callable "get" object or null if sprop->hasGetterValue() */ JSScopeProperty *next; /* next node in freelist */ }; union { - JSPropertyOp rawSetter; /* getter is JSObject* and setter is 0 + js::PropertyOp rawSetter; /* getter is JSObject* and setter is 0 if sprop->isMethod() */ JSObject *setterObj; /* user-defined callable "set" object or null if sprop->hasSetterValue() */ @@ -644,7 +626,7 @@ struct JSScopeProperty { }; void insertFree(JSScopeProperty *&list) { - id = JSVAL_NULL; + id = JSID_VOID; next = list; prevp = &list; if (list) @@ -653,7 +635,7 @@ struct JSScopeProperty { } void removeFree() { - JS_ASSERT(JSVAL_IS_NULL(id)); + JS_ASSERT(JSID_IS_VOID(id)); *prevp = next; if (next) next->prevp = prevp; @@ -698,7 +680,7 @@ struct JSScopeProperty { IN_DICTIONARY = 0x20 }; - JSScopeProperty(jsid id, JSPropertyOp getter, JSPropertyOp setter, uint32 slot, + JSScopeProperty(jsid id, js::PropertyOp getter, js::PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid); bool marked() const { return (flags & MARK) != 0; } @@ -725,38 +707,47 @@ struct JSScopeProperty { bool hasShortID() const { return (flags & HAS_SHORTID) != 0; } bool isMethod() const { return (flags & METHOD) != 0; } - JSObject *methodObject() const { JS_ASSERT(isMethod()); return getterObj; } - jsval methodValue() const { return OBJECT_TO_JSVAL(methodObject()); } + JSObject &methodObject() const { JS_ASSERT(isMethod()); return *getterObj; } - JSPropertyOp getter() const { return rawGetter; } + js::PropertyOp getter() const { return rawGetter; } bool hasDefaultGetter() const { return !rawGetter; } - JSPropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return rawGetter; } + js::PropertyOp getterOp() const { JS_ASSERT(!hasGetterValue()); return rawGetter; } JSObject *getterObject() const { JS_ASSERT(hasGetterValue()); return getterObj; } // Per ES5, decode null getterObj as the undefined value, which encodes as null. - jsval getterValue() const { + js::Value getterValue() const { JS_ASSERT(hasGetterValue()); - return getterObj ? OBJECT_TO_JSVAL(getterObj) : JSVAL_VOID; + return getterObj ? js::ObjectValue(*getterObj) : js::UndefinedValue(); } - JSPropertyOp setter() const { return rawSetter; } + js::Value getterOrUndefined() const { + JSObject *obj = hasGetterValue() ? getterObj : NULL; + return obj ? js::ObjectValue(*obj) : js::UndefinedValue(); + } + + js::PropertyOp setter() const { return rawSetter; } bool hasDefaultSetter() const { return !rawSetter; } - JSPropertyOp setterOp() const { JS_ASSERT(!hasSetterValue()); return rawSetter; } + js::PropertyOp setterOp() const { JS_ASSERT(!hasSetterValue()); return rawSetter; } JSObject *setterObject() const { JS_ASSERT(hasSetterValue()); return setterObj; } // Per ES5, decode null setterObj as the undefined value, which encodes as null. - jsval setterValue() const { + js::Value setterValue() const { JS_ASSERT(hasSetterValue()); - return setterObj ? OBJECT_TO_JSVAL(setterObj) : JSVAL_VOID; + return setterObj ? js::ObjectValue(*setterObj) : js::UndefinedValue(); + } + + js::Value setterOrUndefined() const { + return setterObj ? js::ObjectValue(*setterObj) : js::UndefinedValue(); } inline JSDHashNumber hash() const; inline bool matches(const JSScopeProperty *p) const; - inline bool matchesParamsAfterId(JSPropertyOp agetter, JSPropertyOp asetter, uint32 aslot, - uintN aattrs, uintN aflags, intN ashortid) const; + inline bool matchesParamsAfterId(js::PropertyOp agetter, js::PropertyOp asetter, + uint32 aslot, uintN aattrs, uintN aflags, + intN ashortid) const; - bool get(JSContext* cx, JSObject* obj, JSObject *pobj, jsval* vp); - bool set(JSContext* cx, JSObject* obj, jsval* vp); + bool get(JSContext* cx, JSObject *obj, JSObject *pobj, js::Value* vp); + bool set(JSContext* cx, JSObject *obj, js::Value* vp); inline bool isSharedPermanent() const; @@ -826,7 +817,7 @@ JSScope::hasProperty(JSScopeProperty *sprop) inline JSScopeProperty * JSScope::lastProperty() const { - JS_ASSERT_IF(lastProp, !JSVAL_IS_NULL(lastProp->id)); + JS_ASSERT_IF(lastProp, !JSID_IS_VOID(lastProp->id)); return lastProp; } @@ -837,8 +828,8 @@ JSScope::lastProperty() const inline void JSScope::setLastProperty(JSScopeProperty *sprop) { - JS_ASSERT(!JSVAL_IS_NULL(sprop->id)); - JS_ASSERT_IF(lastProp, !JSVAL_IS_NULL(lastProp->id)); + JS_ASSERT(!JSID_IS_VOID(sprop->id)); + JS_ASSERT_IF(lastProp, !JSID_IS_VOID(lastProp->id)); lastProp = sprop; } @@ -847,7 +838,7 @@ inline void JSScope::removeLastProperty() { JS_ASSERT(!inDictionaryMode()); - JS_ASSERT_IF(lastProp->parent, !JSVAL_IS_NULL(lastProp->parent->id)); + JS_ASSERT_IF(lastProp->parent, !JSID_IS_VOID(lastProp->parent->id)); lastProp = lastProp->parent; --entryCount; @@ -859,12 +850,12 @@ JSScope::removeDictionaryProperty(JSScopeProperty *sprop) JS_ASSERT(inDictionaryMode()); JS_ASSERT(sprop->inDictionary()); JS_ASSERT(sprop->childp); - JS_ASSERT(!JSVAL_IS_NULL(sprop->id)); + JS_ASSERT(!JSID_IS_VOID(sprop->id)); JS_ASSERT(lastProp->inDictionary()); JS_ASSERT(lastProp->childp == &lastProp); - JS_ASSERT_IF(lastProp != sprop, !JSVAL_IS_NULL(lastProp->id)); - JS_ASSERT_IF(lastProp->parent, !JSVAL_IS_NULL(lastProp->parent->id)); + JS_ASSERT_IF(lastProp != sprop, !JSID_IS_VOID(lastProp->id)); + JS_ASSERT_IF(lastProp->parent, !JSID_IS_VOID(lastProp->parent->id)); if (sprop->parent) sprop->parent->childp = sprop->childp; @@ -882,12 +873,12 @@ JSScope::insertDictionaryProperty(JSScopeProperty *sprop, JSScopeProperty **chil */ JS_ASSERT(sprop->inDictionary()); JS_ASSERT(!sprop->childp); - JS_ASSERT(!JSVAL_IS_NULL(sprop->id)); + JS_ASSERT(!JSID_IS_VOID(sprop->id)); JS_ASSERT_IF(*childp, (*childp)->inDictionary()); JS_ASSERT_IF(lastProp, lastProp->inDictionary()); JS_ASSERT_IF(lastProp, lastProp->childp == &lastProp); - JS_ASSERT_IF(lastProp, !JSVAL_IS_NULL(lastProp->id)); + JS_ASSERT_IF(lastProp, !JSID_IS_VOID(lastProp->id)); sprop->parent = *childp; *childp = sprop; @@ -902,8 +893,8 @@ JSScope::insertDictionaryProperty(JSScopeProperty *sprop, JSScopeProperty **chil * than id when calling sprop's getter or setter. */ #define SPROP_USERID(sprop) \ - ((sprop)->hasShortID() ? INT_TO_JSVAL((sprop)->shortid) \ - : ID_TO_VALUE((sprop)->id)) + ((sprop)->hasShortID() ? INT_TO_JSID((sprop)->shortid) \ + : (sprop)->id) #define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->freeslot) #define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope) @@ -972,7 +963,7 @@ JSScope::search(jsid id, bool adding) #undef METER inline bool -JSScope::canProvideEmptyScope(JSObjectOps *ops, JSClass *clasp) +JSScope::canProvideEmptyScope(JSObjectOps *ops, js::Class *clasp) { /* * An empty scope cannot provide another empty scope, or wrongful two-level @@ -992,11 +983,6 @@ JSScopeProperty::isSharedPermanent() const extern JSScope * js_GetMutableScope(JSContext *cx, JSObject *obj); -extern void -js_TraceId(JSTracer *trc, jsid id); - -JS_END_EXTERN_C - #ifdef _MSC_VER #pragma warning(pop) #pragma warning(pop) diff --git a/js/src/jsscopeinlines.h b/js/src/jsscopeinlines.h index 9cdf54c6fe9f..45c4c544ef14 100644 --- a/js/src/jsscopeinlines.h +++ b/js/src/jsscopeinlines.h @@ -49,7 +49,7 @@ #include "jscntxtinlines.h" inline JSEmptyScope * -JSScope::createEmptyScope(JSContext *cx, JSClass *clasp) +JSScope::createEmptyScope(JSContext *cx, js::Class *clasp) { JS_ASSERT(!emptyScope); emptyScope = cx->create(cx, ops, clasp); @@ -57,7 +57,7 @@ JSScope::createEmptyScope(JSContext *cx, JSClass *clasp) } inline JSEmptyScope * -JSScope::getEmptyScope(JSContext *cx, JSClass *clasp) +JSScope::getEmptyScope(JSContext *cx, js::Class *clasp) { if (emptyScope) { JS_ASSERT(clasp == emptyScope->clasp); @@ -67,7 +67,7 @@ JSScope::getEmptyScope(JSContext *cx, JSClass *clasp) } inline bool -JSScope::ensureEmptyScope(JSContext *cx, JSClass *clasp) +JSScope::ensureEmptyScope(JSContext *cx, js::Class *clasp) { if (emptyScope) { JS_ASSERT(clasp == emptyScope->clasp); @@ -115,44 +115,51 @@ JSScope::extend(JSContext *cx, JSScopeProperty *sprop, bool isDefinitelyAtom) * objects optimized as typically non-escaping, ad-hoc methods in obj. */ inline bool -JSScope::methodReadBarrier(JSContext *cx, JSScopeProperty *sprop, jsval *vp) +JSScope::methodReadBarrier(JSContext *cx, JSScopeProperty *sprop, js::Value *vp) { JS_ASSERT(hasMethodBarrier()); JS_ASSERT(hasProperty(sprop)); JS_ASSERT(sprop->isMethod()); - JS_ASSERT(sprop->methodValue() == *vp); + JS_ASSERT(&vp->toObject() == &sprop->methodObject()); JS_ASSERT(object->getClass() == &js_ObjectClass); - JSObject *funobj = JSVAL_TO_OBJECT(*vp); + JSObject *funobj = &vp->toObject(); JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj); JS_ASSERT(FUN_OBJECT(fun) == funobj && FUN_NULL_CLOSURE(fun)); funobj = CloneFunctionObject(cx, fun, funobj->getParent()); if (!funobj) return false; - *vp = OBJECT_TO_JSVAL(funobj); + vp->setObject(*funobj); return !!js_SetPropertyHelper(cx, object, sprop->id, 0, vp); } +static JS_ALWAYS_INLINE bool +ChangesMethodValue(const js::Value &prev, const js::Value &v) +{ + JSObject *prevObj; + return prev.isObject() && (prevObj = &prev.toObject())->isFunction() && + (!v.isObject() || &v.toObject() != prevObj); +} + inline bool -JSScope::methodWriteBarrier(JSContext *cx, JSScopeProperty *sprop, jsval v) +JSScope::methodWriteBarrier(JSContext *cx, JSScopeProperty *sprop, + const js::Value &v) { if (flags & (BRANDED | METHOD_BARRIER)) { - jsval prev = object->lockedGetSlot(sprop->slot); - - if (prev != v && VALUE_IS_FUNCTION(cx, prev)) + const js::Value &prev = object->lockedGetSlot(sprop->slot); + if (ChangesMethodValue(prev, v)) return methodShapeChange(cx, sprop); } return true; } inline bool -JSScope::methodWriteBarrier(JSContext *cx, uint32 slot, jsval v) +JSScope::methodWriteBarrier(JSContext *cx, uint32 slot, const js::Value &v) { if (flags & (BRANDED | METHOD_BARRIER)) { - jsval prev = object->lockedGetSlot(slot); - - if (prev != v && VALUE_IS_FUNCTION(cx, prev)) + const js::Value &prev = object->lockedGetSlot(slot); + if (ChangesMethodValue(prev, v)) return methodShapeChange(cx, slot); } return true; @@ -211,7 +218,7 @@ JSScope::trace(JSTracer *trc) } inline -JSScopeProperty::JSScopeProperty(jsid id, JSPropertyOp getter, JSPropertyOp setter, +JSScopeProperty::JSScopeProperty(jsid id, js::PropertyOp getter, js::PropertyOp setter, uint32 slot, uintN attrs, uintN flags, intN shortid) : id(id), rawGetter(getter), rawSetter(setter), slot(slot), attrs(uint8(attrs)), flags(uint8(flags)), shortid(int16(shortid)) @@ -235,25 +242,25 @@ JSScopeProperty::hash() const hash = JS_ROTATE_LEFT32(hash, 4) ^ attrs; hash = JS_ROTATE_LEFT32(hash, 4) ^ shortid; hash = JS_ROTATE_LEFT32(hash, 4) ^ slot; - hash = JS_ROTATE_LEFT32(hash, 4) ^ id; + hash = JS_ROTATE_LEFT32(hash, 4) ^ JSID_BITS(id); return hash; } inline bool JSScopeProperty::matches(const JSScopeProperty *p) const { - JS_ASSERT(!JSVAL_IS_NULL(id)); - JS_ASSERT(!JSVAL_IS_NULL(p->id)); + JS_ASSERT(!JSID_IS_VOID(id)); + JS_ASSERT(!JSID_IS_VOID(p->id)); return id == p->id && matchesParamsAfterId(p->rawGetter, p->rawSetter, p->slot, p->attrs, p->flags, p->shortid); } inline bool -JSScopeProperty::matchesParamsAfterId(JSPropertyOp agetter, JSPropertyOp asetter, uint32 aslot, +JSScopeProperty::matchesParamsAfterId(js::PropertyOp agetter, js::PropertyOp asetter, uint32 aslot, uintN aattrs, uintN aflags, intN ashortid) const { - JS_ASSERT(!JSVAL_IS_NULL(id)); + JS_ASSERT(!JSID_IS_VOID(id)); return rawGetter == agetter && rawSetter == asetter && slot == aslot && @@ -263,19 +270,19 @@ JSScopeProperty::matchesParamsAfterId(JSPropertyOp agetter, JSPropertyOp asetter } inline bool -JSScopeProperty::get(JSContext* cx, JSObject* obj, JSObject *pobj, jsval* vp) +JSScopeProperty::get(JSContext* cx, JSObject* obj, JSObject *pobj, js::Value* vp) { - JS_ASSERT(!JSVAL_IS_NULL(this->id)); + JS_ASSERT(!JSID_IS_VOID(this->id)); JS_ASSERT(!hasDefaultGetter()); if (hasGetterValue()) { JS_ASSERT(!isMethod()); - jsval fval = getterValue(); - return js_InternalGetOrSet(cx, obj, id, fval, JSACC_READ, 0, 0, vp); + js::Value fval = getterValue(); + return js::InternalGetOrSet(cx, obj, id, fval, JSACC_READ, 0, 0, vp); } if (isMethod()) { - *vp = methodValue(); + vp->setObject(methodObject()); JSScope *scope = pobj->scope(); JS_ASSERT(scope->object == pobj); @@ -292,17 +299,17 @@ JSScopeProperty::get(JSContext* cx, JSObject* obj, JSObject *pobj, jsval* vp) } inline bool -JSScopeProperty::set(JSContext* cx, JSObject* obj, jsval* vp) +JSScopeProperty::set(JSContext* cx, JSObject* obj, js::Value* vp) { JS_ASSERT_IF(hasDefaultSetter(), hasGetterValue()); if (attrs & JSPROP_SETTER) { - jsval fval = setterValue(); - return js_InternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp); + js::Value fval = setterValue(); + return js::InternalGetOrSet(cx, obj, id, fval, JSACC_WRITE, 1, vp, vp); } if (attrs & JSPROP_GETTER) - return !!js_ReportGetterOnlyAssignment(cx); + return js_ReportGetterOnlyAssignment(cx); /* See the comment in JSScopeProperty::get as to why we check for With. */ if (obj->getClass() == &js_WithClass) diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 850c6f406696..1eac6d594c32 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -74,7 +74,7 @@ static const jsbytecode emptyScriptCode[] = {JSOP_STOP, SRC_NULL}; /* static */ const JSScript JSScript::emptyScriptConst = { const_cast(emptyScriptCode), - 1, JSVERSION_DEFAULT, 0, 0, 0, 0, 0, true, false, false, false, + 1, JSVERSION_DEFAULT, 0, 0, 0, 0, 0, 0, true, false, false, false, const_cast(emptyScriptCode), {0, NULL}, NULL, 0, 0, 0, NULL }; @@ -90,7 +90,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, JSBool ok; jsbytecode *code; uint32 length, lineno, nslots, magic; - uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, i; + uint32 natoms, nsrcnotes, ntrynotes, nobjects, nupvars, nregexps, nconsts, i; uint32 prologLength, version; JSPrincipals *principals; uint32 encodeable; @@ -100,7 +100,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, cx = xdr->cx; script = *scriptp; - nsrcnotes = ntrynotes = natoms = nobjects = nupvars = nregexps = 0; + nsrcnotes = ntrynotes = natoms = nobjects = nupvars = nregexps = nconsts = 0; filenameWasSaved = JS_FALSE; notes = NULL; @@ -145,7 +145,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, * the shorthand (0 length word) for us. Make a new mutable empty * script here and return it immediately. */ - script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0); + script = js_NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0); if (!script) return JS_FALSE; @@ -185,6 +185,8 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, nregexps = script->regexps()->length; if (script->trynotesOffset != 0) ntrynotes = script->trynotes()->length; + if (script->constOffset != 0) + nconsts = script->consts()->length; } if (!JS_XDRUint32(xdr, &prologLength)) @@ -208,12 +210,14 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, return JS_FALSE; if (!JS_XDRUint32(xdr, &nregexps)) return JS_FALSE; + if (!JS_XDRUint32(xdr, &nconsts)) + return JS_FALSE; AutoScriptRooter tvr(cx, NULL); if (xdr->mode == JSXDR_DECODE) { script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nupvars, - nregexps, ntrynotes); + nregexps, ntrynotes, nconsts); if (!script) return JS_FALSE; @@ -310,7 +314,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, JSObject **objp = &script->objects()->vector[i]; uint32 isBlock; if (xdr->mode == JSXDR_ENCODE) { - JSClass *clasp = (*objp)->getClass(); + Class *clasp = (*objp)->getClass(); JS_ASSERT(clasp == &js_FunctionClass || clasp == &js_BlockClass); isBlock = (clasp == &js_BlockClass) ? 1 : 0; @@ -366,6 +370,11 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, } while (tn != tnfirst); } + for (i = 0; i != nconsts; ++i) { + if (!JS_XDRValue(xdr, Jsvalify(&script->consts()->vector[i]))) + goto error; + } + xdr->script = oldscript; return JS_TRUE; @@ -400,12 +409,12 @@ script_trace(JSTracer *trc, JSObject *obj) js_TraceScript(trc, script); } -JSClass js_ScriptClass = { +Class js_ScriptClass = { "Script", JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, script_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, script_finalize, NULL, NULL, NULL, NULL,/*XXXbe xdr*/ NULL, NULL, JS_CLASS_TRACE(script_trace), NULL }; @@ -805,16 +814,16 @@ JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) + JSScript * js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, uint32 nobjects, uint32 nupvars, uint32 nregexps, - uint32 ntrynotes) + uint32 ntrynotes, uint32 nconsts) { size_t size, vectorSize; JSScript *script; uint8 *cursor; + unsigned constPadding = 0; size = sizeof(JSScript) + - sizeof(JSAtom *) * natoms + - length * sizeof(jsbytecode) + - nsrcnotes * sizeof(jssrcnote); + sizeof(JSAtom *) * natoms; + if (nobjects != 0) size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *); if (nupvars != 0) @@ -824,6 +833,19 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, if (ntrynotes != 0) size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote); + if (nconsts != 0) { + size += sizeof(JSConstArray); + /* + * Calculate padding assuming that consts go after the other arrays, + * but before the bytecode and source notes. + */ + constPadding = (8 - (size % 8)) % 8; + size += constPadding + nconsts * sizeof(Value); + } + + size += length * sizeof(jsbytecode) + + nsrcnotes * sizeof(jssrcnote); + script = (JSScript *) cx->malloc(size); if (!script) return NULL; @@ -848,6 +870,10 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, script->trynotesOffset = (uint8)(cursor - (uint8 *)script); cursor += sizeof(JSTryNoteArray); } + if (nconsts != 0) { + script->constOffset = (uint8)(cursor - (uint8 *)script); + cursor += sizeof(JSConstArray); + } if (natoms != 0) { script->atomMap.length = natoms; @@ -900,6 +926,17 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, cursor += vectorSize; } + /* Must go after other arrays; see constPadding definition. */ + if (nconsts != 0) { + cursor += constPadding; + script->consts()->length = nconsts; + script->consts()->vector = (Value *)cursor; + JS_ASSERT((size_t)cursor % sizeof(double) == 0); + vectorSize = nconsts * sizeof(script->consts()->vector[0]); + memset(cursor, 0, vectorSize); + cursor += vectorSize; + } + script->code = script->main = (jsbytecode *)cursor; JS_ASSERT(cursor + length * sizeof(jsbytecode) + @@ -987,7 +1024,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) script = js_NewScript(cx, prologLength + mainLength, nsrcnotes, cg->atomList.count, cg->objectList.length, cg->upvarList.count, cg->regexpList.length, - cg->ntrynotes); + cg->ntrynotes, cg->constList.length()); if (!script) return NULL; @@ -1027,6 +1064,8 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg) cg->objectList.finish(script->objects()); if (cg->regexpList.length != 0) cg->regexpList.finish(script->regexps()); + if (cg->constList.length() != 0) + cg->constList.finish(script->consts()); if (cg->flags & TCF_NO_SCRIPT_RVAL) script->noScriptRval = true; if (cg->hasSharps()) @@ -1172,50 +1211,41 @@ js_DestroyScript(JSContext *cx, JSScript *script) void js_TraceScript(JSTracer *trc, JSScript *script) { - JSAtomMap *map; - uintN i, length; - JSAtom **vector; - jsval v; - JSObjectArray *objarray; - - map = &script->atomMap; - length = map->length; - vector = map->vector; - for (i = 0; i < length; i++) { - v = ATOM_KEY(vector[i]); - if (JSVAL_IS_TRACEABLE(v)) { - JS_SET_TRACING_INDEX(trc, "atomMap", i); - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); - } - } + JSAtomMap *map = &script->atomMap; + MarkAtomRange(trc, map->length, map->vector, "atomMap"); if (script->objectsOffset != 0) { - objarray = script->objects(); - i = objarray->length; + JSObjectArray *objarray = script->objects(); + uintN i = objarray->length; do { --i; if (objarray->vector[i]) { JS_SET_TRACING_INDEX(trc, "objects", i); - js_CallGCMarker(trc, objarray->vector[i], JSTRACE_OBJECT); + Mark(trc, objarray->vector[i], JSTRACE_OBJECT); } } while (i != 0); } if (script->regexpsOffset != 0) { - objarray = script->regexps(); - i = objarray->length; + JSObjectArray *objarray = script->regexps(); + uintN i = objarray->length; do { --i; if (objarray->vector[i]) { JS_SET_TRACING_INDEX(trc, "regexps", i); - js_CallGCMarker(trc, objarray->vector[i], JSTRACE_OBJECT); + Mark(trc, objarray->vector[i], JSTRACE_OBJECT); } } while (i != 0); } + if (script->constOffset != 0) { + JSConstArray *constarray = script->consts(); + MarkValueRange(trc, constarray->length, constarray->vector, "consts"); + } + if (script->u.object) { JS_SET_TRACING_NAME(trc, "object"); - js_CallGCMarker(trc, script->u.object, JSTRACE_OBJECT); + Mark(trc, script->u.object, JSTRACE_OBJECT); } if (IS_GC_MARKING_TRACER(trc) && script->filename) diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 2de5a5e42cec..1a45b3243dc8 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -47,8 +47,6 @@ #include "jsprvtd.h" #include "jsdbgapi.h" -JS_BEGIN_EXTERN_C - /* * Type of try note associated with each catch or finally block, and also with * for-in loops. @@ -130,6 +128,11 @@ typedef struct JSUpvarArray { uint32 length; /* count of indexed upvar cookies */ } JSUpvarArray; +typedef struct JSConstArray { + js::Value *vector; /* array of indexed constant values */ + uint32 length; +} JSConstArray; + #define JS_OBJECT_ARRAY_SIZE(length) \ (offsetof(JSObjectArray, vector) + sizeof(JSObject *) * (length)) @@ -152,6 +155,8 @@ struct JSScript { regexps or 0 if none. */ uint8 trynotesOffset; /* offset to the array of try notes or 0 if none */ + uint8 constOffset; /* offset to the array of constants or + 0 if none */ bool noScriptRval:1; /* no need for result value of last expression statement */ bool savedCallerFun:1; /* object 0 is caller function */ @@ -196,6 +201,11 @@ struct JSScript { return (JSTryNoteArray *) ((uint8 *) this + trynotesOffset); } + JSConstArray *consts() { + JS_ASSERT(constOffset != 0); + return (JSConstArray *) ((uint8 *) this + constOffset); + } + JSAtom *getAtom(size_t index) { JS_ASSERT(index < atomMap.length); return atomMap.vector[index]; @@ -211,6 +221,12 @@ struct JSScript { inline JSObject *getRegExp(size_t index); + const js::Value &getConst(size_t index) { + JSConstArray *arr = consts(); + JS_ASSERT(index < arr->length); + return arr->vector[index]; + } + /* * The isEmpty method tells whether this script has code that computes any * result (not return value, result AKA normal completion value) other than @@ -264,7 +280,7 @@ StackDepth(JSScript *script) } \ JS_END_MACRO -extern JS_FRIEND_DATA(JSClass) js_ScriptClass; +extern JS_FRIEND_DATA(js::Class) js_ScriptClass; extern JSObject * js_InitScriptClass(JSContext *cx, JSObject *obj); @@ -323,7 +339,7 @@ js_SweepScriptFilenames(JSRuntime *rt); extern JSScript * js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms, uint32 nobjects, uint32 nupvars, uint32 nregexps, - uint32 ntrynotes); + uint32 ntrynotes, uint32 nconsts); extern JSScript * js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg); @@ -402,6 +418,4 @@ extern JSBool js_XDRScript(JSXDRState *xdr, JSScript **scriptp, bool needMutableScript, JSBool *hasMagic); -JS_END_EXTERN_C - #endif /* jsscript_h___ */ diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 0ce039ce5b3c..3bccbb5062dd 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -79,13 +79,14 @@ #include "jscntxtinlines.h" #include "jsobjinlines.h" #include "jsstrinlines.h" +#include "jscntxtinlines.h" using namespace js; #define JSSTRDEP_RECURSION_LIMIT 100 JS_STATIC_ASSERT(size_t(JSString::MAX_LENGTH) <= size_t(JSVAL_INT_MAX)); -JS_STATIC_ASSERT(INT_FITS_IN_JSVAL(JSString::MAX_LENGTH)); +JS_STATIC_ASSERT(JSString::MAX_LENGTH <= JSVAL_INT_MAX); static size_t MinimizeDependentStrings(JSString *str, int level, JSString **basep) @@ -250,35 +251,30 @@ js_MakeStringImmutable(JSContext *cx, JSString *str) } static JSString * -ArgToRootedString(JSContext *cx, uintN argc, jsval *vp, uintN arg) +ArgToRootedString(JSContext *cx, uintN argc, Value *vp, uintN arg) { if (arg >= argc) return ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); vp += 2 + arg; - if (!JSVAL_IS_PRIMITIVE(*vp) && !DefaultValue(cx, JSVAL_TO_OBJECT(*vp), JSTYPE_STRING, vp)) + if (vp->isObject() && !DefaultValue(cx, &vp->toObject(), JSTYPE_STRING, vp)) return NULL; JSString *str; - if (JSVAL_IS_STRING(*vp)) { - str = JSVAL_TO_STRING(*vp); - } else if (JSVAL_IS_BOOLEAN(*vp)) { + if (vp->isString()) { + str = vp->toString(); + } else if (vp->isBoolean()) { str = ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[ - JSVAL_TO_BOOLEAN(*vp)? 1 : 0]); - } else if (JSVAL_IS_NULL(*vp)) { + (int)vp->toBoolean()]); + } else if (vp->isNull()) { str = ATOM_TO_STRING(cx->runtime->atomState.nullAtom); - } else if (JSVAL_IS_VOID(*vp)) { + } else if (vp->isUndefined()) { str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); } else { - if (JSVAL_IS_INT(*vp)) { - str = js_NumberToString(cx, JSVAL_TO_INT(*vp)); - } else { - JS_ASSERT(JSVAL_IS_DOUBLE(*vp)); - str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(*vp)); - } + str = js_NumberToString(cx, vp->toNumber()); if (str) - *vp = STRING_TO_JSVAL(str); + vp->setString(str); } return str; } @@ -287,16 +283,16 @@ ArgToRootedString(JSContext *cx, uintN argc, jsval *vp, uintN arg) * Forward declarations for URI encode/decode and helper routines */ static JSBool -str_decodeURI(JSContext *cx, uintN argc, jsval *vp); +str_decodeURI(JSContext *cx, uintN argc, Value *vp); static JSBool -str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp); +str_decodeURI_Component(JSContext *cx, uintN argc, Value *vp); static JSBool -str_encodeURI(JSContext *cx, uintN argc, jsval *vp); +str_encodeURI(JSContext *cx, uintN argc, Value *vp); static JSBool -str_encodeURI_Component(JSContext *cx, uintN argc, jsval *vp); +str_encodeURI_Component(JSContext *cx, uintN argc, Value *vp); static const uint32 OVERLONG_UTF8 = UINT32_MAX; @@ -344,7 +340,7 @@ static const uint8 urlCharType[256] = /* See ECMA-262 Edition 3 B.2.1 */ JSBool -js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +js_str_escape(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { JSString *str; size_t i, ni, length, newlength; @@ -437,23 +433,21 @@ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval cx->free(newchars); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + rval->setString(str); return JS_TRUE; } #undef IS_OK static JSBool -str_escape(JSContext *cx, uintN argc, jsval *vp) +str_escape(JSContext *cx, uintN argc, Value *vp) { - JSObject *obj; - - obj = JS_THIS_OBJECT(cx, vp); + JSObject *obj = ComputeThisFromVp(cx, vp); return obj && js_str_escape(cx, obj, argc, vp + 2, vp); } /* See ECMA-262 Edition 3 B.2.2 */ static JSBool -str_unescape(JSContext *cx, uintN argc, jsval *vp) +str_unescape(JSContext *cx, uintN argc, Value *vp) { JSString *str; size_t i, ni, length; @@ -500,20 +494,20 @@ str_unescape(JSContext *cx, uintN argc, jsval *vp) cx->free(newchars); return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } #if JS_HAS_UNEVAL static JSBool -str_uneval(JSContext *cx, uintN argc, jsval *vp) +str_uneval(JSContext *cx, uintN argc, Value *vp) { JSString *str; - str = js_ValueToSource(cx, argc != 0 ? vp[2] : JSVAL_VOID); + str = js_ValueToSource(cx, argc != 0 ? vp[2] : UndefinedValue()); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } #endif @@ -546,25 +540,22 @@ jschar js_empty_ucstr[] = {0}; JSSubString js_EmptySubString = {0, js_empty_ucstr}; static JSBool -str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +str_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - jsval v; JSString *str; - if (id == ATOM_KEY(cx->runtime->atomState.lengthAtom)) { + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { if (obj->getClass() == &js_StringClass) { /* Follow ECMA-262 by fetching intrinsic length of our string. */ - v = obj->getPrimitiveThis(); - JS_ASSERT(JSVAL_IS_STRING(v)); - str = JSVAL_TO_STRING(v); + str = obj->getPrimitiveThis().toString(); } else { /* Preserve compatibility: convert obj to a string primitive. */ - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, ObjectValue(*obj)); if (!str) return JS_FALSE; } - *vp = INT_TO_JSVAL((jsint) str->length()); + vp->setInt32(str->length()); } return JS_TRUE; @@ -575,52 +566,43 @@ str_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) static JSBool str_enumerate(JSContext *cx, JSObject *obj) { - jsval v; JSString *str, *str1; size_t i, length; - v = obj->getPrimitiveThis(); - JS_ASSERT(JSVAL_IS_STRING(v)); - str = JSVAL_TO_STRING(v); + str = obj->getPrimitiveThis().toString(); length = str->length(); for (i = 0; i < length; i++) { str1 = js_NewDependentString(cx, str, i, 1); if (!str1) return JS_FALSE; - if (!obj->defineProperty(cx, INT_TO_JSID(i), STRING_TO_JSVAL(str1), - JS_PropertyStub, JS_PropertyStub, + if (!obj->defineProperty(cx, INT_TO_JSID(i), StringValue(str1), + PropertyStub, PropertyStub, STRING_ELEMENT_ATTRS)) { return JS_FALSE; } } return obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), - JSVAL_VOID, NULL, NULL, + UndefinedValue(), NULL, NULL, JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_SHARED); } static JSBool -str_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +str_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { - jsval v; - JSString *str, *str1; - jsint slot; - - if (!JSVAL_IS_INT(id) || (flags & JSRESOLVE_ASSIGNING)) + if (!JSID_IS_INT(id) || (flags & JSRESOLVE_ASSIGNING)) return JS_TRUE; - v = obj->getPrimitiveThis(); - JS_ASSERT(JSVAL_IS_STRING(v)); - str = JSVAL_TO_STRING(v); + JSString *str = obj->getPrimitiveThis().toString(); - slot = JSVAL_TO_INT(id); + jsint slot = JSID_TO_INT(id); if ((size_t)slot < str->length()) { - str1 = JSString::getUnitString(cx, str, size_t(slot)); + JSString *str1 = JSString::getUnitString(cx, str, size_t(slot)); if (!str1) return JS_FALSE; - if (!obj->defineProperty(cx, INT_TO_JSID(slot), STRING_TO_JSVAL(str1), NULL, NULL, + if (!obj->defineProperty(cx, id, StringValue(str1), NULL, NULL, STRING_ELEMENT_ATTRS)) { return JS_FALSE; } @@ -629,19 +611,19 @@ str_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, return JS_TRUE; } -JSClass js_StringClass = { +Class js_StringClass = { js_String_str, JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_String), - JS_PropertyStub, JS_PropertyStub, str_getProperty, JS_PropertyStub, - str_enumerate, (JSResolveOp)str_resolve, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, str_getProperty, PropertyStub, + str_enumerate, (JSResolveOp)str_resolve, ConvertStub, NULL, JSCLASS_NO_OPTIONAL_MEMBERS }; #define NORMALIZE_THIS(cx,vp,str) \ JS_BEGIN_MACRO \ - if (JSVAL_IS_STRING(vp[1])) { \ - str = JSVAL_TO_STRING(vp[1]); \ + if (vp[1].isString()) { \ + str = vp[1].toString(); \ } else { \ str = NormalizeThis(cx, vp); \ if (!str) \ @@ -650,11 +632,9 @@ JSClass js_StringClass = { JS_END_MACRO static JSString * -NormalizeThis(JSContext *cx, jsval *vp) +NormalizeThis(JSContext *cx, Value *vp) { - JSString *str; - - if (JSVAL_IS_NULL(vp[1]) && JSVAL_IS_NULL(JS_THIS(cx, vp))) + if (vp[1].isNull() && (!ComputeThisFromVp(cx, vp) || vp[1].isNull())) return NULL; /* @@ -663,18 +643,18 @@ NormalizeThis(JSContext *cx, jsval *vp) * vp[1] is a String object) here. Note that vp[1] can still be a * primitive value at this point. */ - if (!JSVAL_IS_PRIMITIVE(vp[1])) { - JSObject *obj = JSVAL_TO_OBJECT(vp[1]); + if (vp[1].isObject()) { + JSObject *obj = &vp[1].toObject(); if (obj->getClass() == &js_StringClass) { vp[1] = obj->getPrimitiveThis(); - return JSVAL_TO_STRING(vp[1]); + return vp[1].toString(); } } - str = js_ValueToString(cx, vp[1]); + JSString *str = js_ValueToString(cx, vp[1]); if (!str) return NULL; - vp[1] = STRING_TO_JSVAL(str); + vp[1].setString(str); return str; } @@ -685,7 +665,7 @@ NormalizeThis(JSContext *cx, jsval *vp) * toSource, toString, and valueOf. */ static JSBool -str_quote(JSContext *cx, uintN argc, jsval *vp) +str_quote(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -693,24 +673,23 @@ str_quote(JSContext *cx, uintN argc, jsval *vp) str = js_QuoteString(cx, str, '"'); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -str_toSource(JSContext *cx, uintN argc, jsval *vp) +str_toSource(JSContext *cx, uintN argc, Value *vp) { - jsval v; JSString *str; size_t i, j, k, n; char buf[16]; const jschar *s; jschar *t; - if (!js_GetPrimitiveThis(cx, vp, &js_StringClass, &v)) + const Value *primp; + if (!js_GetPrimitiveThis(cx, vp, &js_StringClass, &primp)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_STRING(v)); - str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"'); + str = js_QuoteString(cx, primp->toString(), '"'); if (!str) return JS_FALSE; j = JS_snprintf(buf, sizeof buf, "(new %s(", js_StringClass.name); @@ -731,16 +710,20 @@ str_toSource(JSContext *cx, uintN argc, jsval *vp) cx->free(t); return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } #endif /* JS_HAS_TOSOURCE */ JSBool -js_str_toString(JSContext *cx, uintN argc, jsval *vp) +js_str_toString(JSContext *cx, uintN argc, Value *vp) { - return js_GetPrimitiveThis(cx, vp, &js_StringClass, vp); + const Value *primp; + if (!js_GetPrimitiveThis(cx, vp, &js_StringClass, &primp)) + return false; + *vp = *primp; + return true; } /* @@ -770,7 +753,7 @@ SubstringTail(JSContext *cx, JSString *str, jsdouble length, jsdouble begin, jsd } static JSBool -str_substring(JSContext *cx, uintN argc, jsval *vp) +str_substring(JSContext *cx, uintN argc, Value *vp) { JSString *str; jsdouble d; @@ -794,7 +777,7 @@ str_substring(JSContext *cx, uintN argc, jsval *vp) if (!str) return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } @@ -802,11 +785,10 @@ str_substring(JSContext *cx, uintN argc, jsval *vp) static JSString* FASTCALL String_p_toString(JSContext* cx, JSObject* obj) { - if (!JS_InstanceOf(cx, obj, &js_StringClass, NULL)) + if (!InstanceOf(cx, obj, &js_StringClass, NULL)) return NULL; - jsval v = obj->getPrimitiveThis(); - JS_ASSERT(JSVAL_IS_STRING(v)); - return JSVAL_TO_STRING(v); + Value v = obj->getPrimitiveThis(); + return v.toString(); } #endif @@ -833,7 +815,7 @@ js_toLowerCase(JSContext *cx, JSString *str) } static JSBool -str_toLowerCase(JSContext *cx, uintN argc, jsval *vp) +str_toLowerCase(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -841,12 +823,12 @@ str_toLowerCase(JSContext *cx, uintN argc, jsval *vp) str = js_toLowerCase(cx, str); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -str_toLocaleLowerCase(JSContext *cx, uintN argc, jsval *vp) +str_toLocaleLowerCase(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -856,7 +838,7 @@ str_toLocaleLowerCase(JSContext *cx, uintN argc, jsval *vp) */ if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) { NORMALIZE_THIS(cx, vp, str); - return cx->localeCallbacks->localeToLowerCase(cx, str, vp); + return cx->localeCallbacks->localeToLowerCase(cx, str, Jsvalify(vp)); } return str_toLowerCase(cx, 0, vp); } @@ -884,7 +866,7 @@ js_toUpperCase(JSContext *cx, JSString *str) } static JSBool -str_toUpperCase(JSContext *cx, uintN argc, jsval *vp) +str_toUpperCase(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -892,12 +874,12 @@ str_toUpperCase(JSContext *cx, uintN argc, jsval *vp) str = js_toUpperCase(cx, str); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -str_toLocaleUpperCase(JSContext *cx, uintN argc, jsval *vp) +str_toLocaleUpperCase(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -907,44 +889,42 @@ str_toLocaleUpperCase(JSContext *cx, uintN argc, jsval *vp) */ if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) { NORMALIZE_THIS(cx, vp, str); - return cx->localeCallbacks->localeToUpperCase(cx, str, vp); + return cx->localeCallbacks->localeToUpperCase(cx, str, Jsvalify(vp)); } return str_toUpperCase(cx, 0, vp); } static JSBool -str_localeCompare(JSContext *cx, uintN argc, jsval *vp) +str_localeCompare(JSContext *cx, uintN argc, Value *vp) { JSString *str, *thatStr; NORMALIZE_THIS(cx, vp, str); if (argc == 0) { - *vp = JSVAL_ZERO; + vp->setInt32(0); } else { thatStr = js_ValueToString(cx, vp[2]); if (!thatStr) return JS_FALSE; if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) { - vp[2] = STRING_TO_JSVAL(thatStr); - return cx->localeCallbacks->localeCompare(cx, str, thatStr, vp); + vp[2].setString(thatStr); + return cx->localeCallbacks->localeCompare(cx, str, thatStr, Jsvalify(vp)); } - *vp = INT_TO_JSVAL(js_CompareStrings(str, thatStr)); + vp->setInt32(js_CompareStrings(str, thatStr)); } return JS_TRUE; } static JSBool -str_charAt(JSContext *cx, uintN argc, jsval *vp) +str_charAt(JSContext *cx, uintN argc, Value *vp) { - jsval t; JSString *str; jsint i; jsdouble d; - t = vp[1]; - if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_INT(vp[2])) { - str = JSVAL_TO_STRING(t); - i = JSVAL_TO_INT(vp[2]); + if (vp[1].isString() && argc != 0 && vp[2].isInt32()) { + str = vp[1].toString(); + i = vp[2].toInt32(); if ((size_t)i >= str->length()) goto out_of_range; } else { @@ -966,26 +946,25 @@ str_charAt(JSContext *cx, uintN argc, jsval *vp) str = JSString::getUnitString(cx, str, size_t(i)); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; out_of_range: - *vp = JS_GetEmptyStringValue(cx); + vp->setString(cx->runtime->emptyString); return JS_TRUE; } static JSBool -str_charCodeAt(JSContext *cx, uintN argc, jsval *vp) +str_charCodeAt(JSContext *cx, uintN argc, Value *vp) { - jsval t; + Value t; JSString *str; jsint i; jsdouble d; - t = vp[1]; - if (JSVAL_IS_STRING(t) && argc != 0 && JSVAL_IS_INT(vp[2])) { - str = JSVAL_TO_STRING(t); - i = JSVAL_TO_INT(vp[2]); + if (vp[1].isString() && argc != 0 && vp[2].isInt32()) { + str = vp[1].toString(); + i = vp[2].toInt32(); if ((size_t)i >= str->length()) goto out_of_range; } else { @@ -1004,11 +983,11 @@ str_charCodeAt(JSContext *cx, uintN argc, jsval *vp) i = (jsint) d; } - *vp = INT_TO_JSVAL(str->chars()[i]); + vp->setInt32(str->chars()[i]); return JS_TRUE; out_of_range: - *vp = JS_GetNaNValue(cx); + vp->setDouble(js_NaN); return JS_TRUE; } @@ -1228,7 +1207,7 @@ StringMatch(const jschar *text, jsuint textlen, } static JSBool -str_indexOf(JSContext *cx, uintN argc, jsval *vp) +str_indexOf(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -1245,9 +1224,8 @@ str_indexOf(JSContext *cx, uintN argc, jsval *vp) jsuint start; if (argc > 1) { - jsval indexVal = vp[3]; - if (JSVAL_IS_INT(indexVal)) { - jsint i = JSVAL_TO_INT(indexVal); + if (vp[3].isInt32()) { + jsint i = vp[3].toInt32(); if (i <= 0) { start = 0; } else if (jsuint(i) > textlen) { @@ -1279,12 +1257,12 @@ str_indexOf(JSContext *cx, uintN argc, jsval *vp) } jsint match = StringMatch(text, textlen, pat, patlen); - *vp = INT_TO_JSVAL((match == -1) ? -1 : start + match); + vp->setInt32((match == -1) ? -1 : start + match); return true; } static JSBool -str_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) +str_lastIndexOf(JSContext *cx, uintN argc, Value *vp) { JSString *str, *str2; const jschar *text, *pat; @@ -1295,8 +1273,8 @@ str_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) text = str->chars(); textlen = (jsint) str->length(); - if (argc != 0 && JSVAL_IS_STRING(vp[2])) { - str2 = JSVAL_TO_STRING(vp[2]); + if (argc != 0 && vp[2].isString()) { + str2 = vp[2].toString(); } else { str2 = ArgToRootedString(cx, argc, vp, 0); if (!str2) @@ -1307,13 +1285,13 @@ str_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) i = textlen - patlen; // Start searching here if (i < 0) { - *vp = INT_TO_JSVAL(-1); + vp->setInt32(-1); return JS_TRUE; } if (argc > 1) { - if (JSVAL_IS_INT(vp[3])) { - j = JSVAL_TO_INT(vp[3]); + if (vp[3].isInt32()) { + j = vp[3].toInt32(); if (j <= 0) i = 0; else if (j < i) @@ -1332,7 +1310,7 @@ str_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) } if (patlen == 0) { - *vp = INT_TO_JSVAL(i); + vp->setInt32(i); return JS_TRUE; } @@ -1349,18 +1327,18 @@ str_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) if (*t1 != *p1) goto break_continue; } - *vp = INT_TO_JSVAL(t - text); + vp->setInt32(t - text); return JS_TRUE; } break_continue:; } - *vp = INT_TO_JSVAL(-1); + vp->setInt32(-1); return JS_TRUE; } static JSBool -js_TrimString(JSContext *cx, jsval *vp, JSBool trimLeft, JSBool trimRight) +js_TrimString(JSContext *cx, Value *vp, JSBool trimLeft, JSBool trimRight) { JSString *str; const jschar *chars; @@ -1385,24 +1363,24 @@ js_TrimString(JSContext *cx, jsval *vp, JSBool trimLeft, JSBool trimRight) if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -str_trim(JSContext *cx, uintN argc, jsval *vp) +str_trim(JSContext *cx, uintN argc, Value *vp) { return js_TrimString(cx, vp, JS_TRUE, JS_TRUE); } static JSBool -str_trimLeft(JSContext *cx, uintN argc, jsval *vp) +str_trimLeft(JSContext *cx, uintN argc, Value *vp) { return js_TrimString(cx, vp, JS_TRUE, JS_FALSE); } static JSBool -str_trimRight(JSContext *cx, uintN argc, jsval *vp) +str_trimRight(JSContext *cx, uintN argc, Value *vp) { return js_TrimString(cx, vp, JS_FALSE, JS_TRUE); } @@ -1443,11 +1421,10 @@ class RegExpGuard /* init must succeed in order to call tryFlatMatch or normalizeRegExp. */ bool - init(uintN argc, jsval *vp) + init(uintN argc, Value *vp) { - jsval patval = vp[2]; - if (argc != 0 && VALUE_IS_REGEXP(mCx, patval)) { - mReobj = JSVAL_TO_OBJECT(patval); + if (argc != 0 && VALUE_IS_REGEXP(mCx, vp[2])) { + mReobj = &vp[2].toObject(); mRe = (JSRegExp *) mReobj->getPrivate(); HOLD_REGEXP(mCx, mRe); } else { @@ -1494,7 +1471,7 @@ class RegExpGuard /* If the pattern is not already a regular expression, make it so. */ bool - normalizeRegExp(bool flat, uintN optarg, uintN argc, jsval *vp) + normalizeRegExp(bool flat, uintN optarg, uintN argc, Value *vp) { /* If we don't have a RegExp, build RegExp from pattern string. */ if (mRe) @@ -1521,9 +1498,9 @@ class RegExpGuard /* js_ExecuteRegExp indicates success in two ways, based on the 'test' flag. */ static JS_ALWAYS_INLINE bool -Matched(bool test, jsval v) +Matched(bool test, const Value &v) { - return test ? (v == JSVAL_TRUE) : !JSVAL_IS_NULL(v); + return test ? v.isTrue() : !v.isNull(); } typedef bool (*DoMatchCallback)(JSContext *cx, size_t count, void *data); @@ -1544,7 +1521,7 @@ enum MatchControlFlags { /* Factor out looping and matching logic. */ static bool -DoMatch(JSContext *cx, jsval *vp, JSString *str, const RegExpGuard &g, +DoMatch(JSContext *cx, Value *vp, JSString *str, const RegExpGuard &g, DoMatchCallback callback, void *data, MatchControlFlags flags) { if (g.re()->flags & JSREG_GLOB) { @@ -1577,6 +1554,8 @@ DoMatch(JSContext *cx, jsval *vp, JSString *str, const RegExpGuard &g, return true; } +typedef JSObject **MatchArgType; + /* * DoMatch will only callback on global matches, hence this function builds * only the "array of matches" returned by match on global regexps. @@ -1584,15 +1563,13 @@ DoMatch(JSContext *cx, jsval *vp, JSString *str, const RegExpGuard &g, static bool MatchCallback(JSContext *cx, size_t count, void *p) { - JS_ASSERT(count <= JSVAL_INT_MAX); /* by max string length */ + JS_ASSERT(count <= JSID_INT_MAX); /* by max string length */ - jsval &arrayval = *static_cast(p); - JSObject *arrayobj = JSVAL_TO_OBJECT(arrayval); + JSObject *&arrayobj = *static_cast(p); if (!arrayobj) { arrayobj = js_NewArrayObject(cx, 0, NULL); if (!arrayobj) return false; - arrayval = OBJECT_TO_JSVAL(arrayobj); } JSString *str = cx->regExpStatics.input; @@ -1603,7 +1580,7 @@ MatchCallback(JSContext *cx, size_t count, void *p) if (!matchstr) return false; - jsval v = STRING_TO_JSVAL(matchstr); + Value v = StringValue(matchstr); JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING); return !!arrayobj->setProperty(cx, INT_TO_JSID(count), &v); @@ -1611,10 +1588,10 @@ MatchCallback(JSContext *cx, size_t count, void *p) static bool BuildFlatMatchArray(JSContext *cx, JSString *textstr, const RegExpGuard &g, - jsval *vp) + Value *vp) { if (g.match < 0) { - *vp = JSVAL_NULL; + vp->setNull(); return true; } @@ -1622,17 +1599,17 @@ BuildFlatMatchArray(JSContext *cx, JSString *textstr, const RegExpGuard &g, JSObject *obj = js_NewSlowArrayObject(cx); if (!obj) return false; - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); - return obj->defineProperty(cx, INT_TO_JSID(0), STRING_TO_JSVAL(g.patstr)) && + return obj->defineProperty(cx, INT_TO_JSID(0), StringValue(g.patstr)) && obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.indexAtom), - INT_TO_JSVAL(g.match)) && + Int32Value(g.match)) && obj->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.inputAtom), - STRING_TO_JSVAL(textstr)); + StringValue(textstr)); } static JSBool -str_match(JSContext *cx, uintN argc, jsval *vp) +str_match(JSContext *cx, uintN argc, Value *vp) { JSString *str; NORMALIZE_THIS(cx, vp, str); @@ -1645,18 +1622,19 @@ str_match(JSContext *cx, uintN argc, jsval *vp) if (!g.normalizeRegExp(false, 1, argc, vp)) return false; - AutoValueRooter array(cx, JSVAL_NULL); - if (!DoMatch(cx, vp, str, g, MatchCallback, array.addr(), MATCH_ARGS)) + AutoObjectRooter array(cx); + MatchArgType arg = array.addr(); + if (!DoMatch(cx, vp, str, g, MatchCallback, arg, MATCH_ARGS)) return false; /* When not global, DoMatch will leave |RegEx.exec()| in *vp. */ if (g.re()->flags & JSREG_GLOB) - *vp = array.value(); + vp->setObjectOrNull(array.object()); return true; } static JSBool -str_search(JSContext *cx, uintN argc, jsval *vp) +str_search(JSContext *cx, uintN argc, Value *vp) { JSString *str; NORMALIZE_THIS(cx, vp, str); @@ -1665,7 +1643,7 @@ str_search(JSContext *cx, uintN argc, jsval *vp) if (!g.init(argc, vp)) return false; if (g.tryFlatMatch(str, false, 1, argc)) { - *vp = INT_TO_JSVAL(g.match); + vp->setInt32(g.match); return true; } if (!g.normalizeRegExp(false, 1, argc, vp)) @@ -1675,10 +1653,10 @@ str_search(JSContext *cx, uintN argc, jsval *vp) if (!js_ExecuteRegExp(cx, g.re(), str, &i, true, vp)) return false; - if (*vp == JSVAL_TRUE) - *vp = INT_TO_JSVAL(cx->regExpStatics.leftContext.length); + if (vp->isTrue()) + vp->setInt32(cx->regExpStatics.leftContext.length); else - *vp = INT_TO_JSVAL(-1); + vp->setInt32(-1); return true; } @@ -1765,14 +1743,14 @@ InterpretDollar(JSContext *cx, jschar *dp, jschar *ep, ReplaceData &rdata, } static JS_ALWAYS_INLINE bool -PushRegExpSubstr(JSContext *cx, const JSSubString &sub, jsval *&sp) +PushRegExpSubstr(JSContext *cx, const JSSubString &sub, Value *&sp) { JSString *whole = cx->regExpStatics.input; size_t off = sub.chars - whole->chars(); JSString *str = js_NewDependentString(cx, whole, off, sub.length); if (!str) return false; - *sp++ = STRING_TO_JSVAL(str); + sp++->setString(str); return true; } @@ -1820,9 +1798,9 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep) PreserveRegExpStatics save(cx); /* Push lambda and its 'this' parameter. */ - jsval *sp = rdata.args.getvp(); - *sp++ = OBJECT_TO_JSVAL(lambda); - *sp++ = OBJECT_TO_JSVAL(lambda->getParent()); + Value *sp = rdata.args.getvp(); + sp++->setObject(*lambda); + sp++->setObjectOrNull(lambda->getParent()); /* Push $&, $1, $2, ... */ if (!PushRegExpSubstr(cx, cx->regExpStatics.lastMatch, sp)) @@ -1836,13 +1814,13 @@ FindReplaceLength(JSContext *cx, ReplaceData &rdata, size_t *sizep) /* Make sure to push undefined for any unmatched parens. */ for (; i < p; i++) - *sp++ = JSVAL_VOID; + *sp++ = UndefinedValue(); /* Push match index and input string. */ - *sp++ = INT_TO_JSVAL((jsint)cx->regExpStatics.leftContext.length); - *sp++ = STRING_TO_JSVAL(rdata.str); + sp++->setInt32(cx->regExpStatics.leftContext.length); + sp++->setString(rdata.str); - if (!js_Invoke(cx, rdata.args, 0)) + if (!Invoke(cx, rdata.args, 0)) return false; /* @@ -1924,7 +1902,7 @@ ReplaceCallback(JSContext *cx, size_t count, void *p) return false; size_t growth = leftlen + replen; - if (!rdata.cb.growBy(growth)) + if (!rdata.cb.growByUninitialized(growth)) return false; jschar *chars = rdata.cb.begin() + rdata.index; @@ -1937,10 +1915,10 @@ ReplaceCallback(JSContext *cx, size_t count, void *p) static bool BuildFlatReplacement(JSContext *cx, JSString *textstr, JSString *repstr, - const RegExpGuard &g, jsval *vp) + const RegExpGuard &g, Value *vp) { if (g.match == -1) { - *vp = STRING_TO_JSVAL(textstr); + vp->setString(textstr); return true; } @@ -1959,19 +1937,19 @@ BuildFlatReplacement(JSContext *cx, JSString *textstr, JSString *repstr, JSString *str = js_NewStringFromCharBuffer(cx, cb); if (!str) return false; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return true; } static JSBool -str_replace(JSContext *cx, uintN argc, jsval *vp) +str_replace(JSContext *cx, uintN argc, Value *vp) { ReplaceData rdata(cx); NORMALIZE_THIS(cx, vp, rdata.str); /* Extract replacement string/function. */ if (argc >= 2 && js_IsCallable(vp[3])) { - rdata.lambda = JSVAL_TO_OBJECT(vp[3]); + rdata.lambda = &vp[3].toObject(); rdata.repstr = NULL; rdata.dollar = rdata.dollarEnd = NULL; } else { @@ -2006,7 +1984,7 @@ str_replace(JSContext *cx, uintN argc, jsval *vp) if (!rdata.calledBack) { /* Didn't match, so the string is unmodified. */ - *vp = STRING_TO_JSVAL(rdata.str); + vp->setString(rdata.str); return true; } @@ -2018,7 +1996,7 @@ str_replace(JSContext *cx, uintN argc, jsval *vp) if (!retstr) return false; - *vp = STRING_TO_JSVAL(retstr); + vp->setString(retstr); return true; } @@ -2064,14 +2042,14 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip, */ if (re) { size_t index; - jsval rval; + Value rval; again: /* JS1.2 deviated from Perl by never matching at end of string. */ index = (size_t)i; if (!js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, &rval)) return -2; - if (rval != JSVAL_TRUE) { + if (!rval.isTrue()) { /* Mismatch: ensure our caller advances i past end of string. */ sep->length = 1; return length; @@ -2126,24 +2104,24 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip, } static JSBool -str_split(JSContext *cx, uintN argc, jsval *vp) +str_split(JSContext *cx, uintN argc, Value *vp) { JSString *str; NORMALIZE_THIS(cx, vp, str); if (argc == 0) { - jsval v = STRING_TO_JSVAL(str); + Value v = StringValue(str); JSObject *aobj = js_NewArrayObject(cx, 1, &v); if (!aobj) return false; - *vp = OBJECT_TO_JSVAL(aobj); + vp->setObject(*aobj); return true; } JSRegExp *re; JSSubString *sep, tmp; if (VALUE_IS_REGEXP(cx, vp[2])) { - re = (JSRegExp *) JSVAL_TO_OBJECT(vp[2])->getPrivate(); + re = (JSRegExp *) vp[2].toObject().getPrivate(); sep = &tmp; /* Set a magic value so we can detect a successful re match. */ @@ -2153,7 +2131,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp) JSString *str2 = js_ValueToString(cx, vp[2]); if (!str2) return false; - vp[2] = STRING_TO_JSVAL(str2); + vp[2].setString(str2); /* * Point sep at a local copy of str2's header because find_split @@ -2166,7 +2144,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp) /* Use the second argument as the split limit, if given. */ uint32 limit = 0; /* Avoid warning. */ - bool limited = (argc > 1) && !JSVAL_IS_VOID(vp[3]); + bool limited = (argc > 1) && !vp[3].isUndefined(); if (limited) { jsdouble d; if (!ValueToNumber(cx, vp[3], &d)) @@ -2187,7 +2165,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp) break; JSString *sub = js_NewDependentString(cx, str, i, size_t(j - i)); - if (!sub || !splits.append(sub)) + if (!sub || !splits.append(StringValue(sub))) return false; len++; @@ -2203,7 +2181,7 @@ str_split(JSContext *cx, uintN argc, jsval *vp) break; JSSubString *parsub = &res->parens[num]; sub = js_NewStringCopyN(cx, parsub->chars, parsub->length); - if (!sub || !splits.append(sub)) + if (!sub || !splits.append(StringValue(sub))) return false; len++; } @@ -2218,13 +2196,13 @@ str_split(JSContext *cx, uintN argc, jsval *vp) JSObject *aobj = js_NewArrayObject(cx, splits.length(), splits.begin()); if (!aobj) return false; - *vp = OBJECT_TO_JSVAL(aobj); + vp->setObject(*aobj); return true; } #if JS_HAS_PERL_SUBSTR static JSBool -str_substr(JSContext *cx, uintN argc, jsval *vp) +str_substr(JSContext *cx, uintN argc, Value *vp) { JSString *str; jsdouble d; @@ -2263,7 +2241,7 @@ str_substr(JSContext *cx, uintN argc, jsval *vp) if (!str) return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } #endif /* JS_HAS_PERL_SUBSTR */ @@ -2272,45 +2250,40 @@ str_substr(JSContext *cx, uintN argc, jsval *vp) * Python-esque sequence operations. */ static JSBool -str_concat(JSContext *cx, uintN argc, jsval *vp) +str_concat(JSContext *cx, uintN argc, Value *vp) { JSString *str, *str2; - jsval *argv; + Value *argv; uintN i; NORMALIZE_THIS(cx, vp, str); /* Set vp (aka rval) early to handle the argc == 0 case. */ - *vp = STRING_TO_JSVAL(str); + vp->setString(str); for (i = 0, argv = vp + 2; i < argc; i++) { str2 = js_ValueToString(cx, argv[i]); if (!str2) return JS_FALSE; - argv[i] = STRING_TO_JSVAL(str2); + argv[i].setString(str2); str = js_ConcatStrings(cx, str, str2); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); } return JS_TRUE; } static JSBool -str_slice(JSContext *cx, uintN argc, jsval *vp) +str_slice(JSContext *cx, uintN argc, Value *vp) { - jsval t, v; - JSString *str; - - t = vp[1]; - v = vp[2]; - if (argc == 1 && JSVAL_IS_STRING(t) && JSVAL_IS_INT(v)) { + if (argc == 1 && vp[1].isString() && vp[2].isInt32()) { size_t begin, end, length; - str = JSVAL_TO_STRING(t); - begin = JSVAL_TO_INT(v); + JSString *str = vp[1].toString(); + begin = vp[2].toInt32(); end = str->length(); if (begin <= end) { length = end - begin; @@ -2323,11 +2296,12 @@ str_slice(JSContext *cx, uintN argc, jsval *vp) if (!str) return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } } + JSString *str; NORMALIZE_THIS(cx, vp, str); if (argc != 0) { @@ -2368,7 +2342,7 @@ str_slice(JSContext *cx, uintN argc, jsval *vp) if (!str) return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } @@ -2378,7 +2352,7 @@ str_slice(JSContext *cx, uintN argc, jsval *vp) */ static JSBool tagify(JSContext *cx, const char *begin, JSString *param, const char *end, - jsval *vp) + Value *vp) { JSString *str; jschar *tagbuf; @@ -2436,12 +2410,12 @@ tagify(JSContext *cx, const char *begin, JSString *param, const char *end, js_free((char *)tagbuf); return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } static JSBool -tagify_value(JSContext *cx, uintN argc, jsval *vp, +tagify_value(JSContext *cx, uintN argc, Value *vp, const char *begin, const char *end) { JSString *param; @@ -2453,79 +2427,79 @@ tagify_value(JSContext *cx, uintN argc, jsval *vp, } static JSBool -str_bold(JSContext *cx, uintN argc, jsval *vp) +str_bold(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "b", NULL, NULL, vp); } static JSBool -str_italics(JSContext *cx, uintN argc, jsval *vp) +str_italics(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "i", NULL, NULL, vp); } static JSBool -str_fixed(JSContext *cx, uintN argc, jsval *vp) +str_fixed(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "tt", NULL, NULL, vp); } static JSBool -str_fontsize(JSContext *cx, uintN argc, jsval *vp) +str_fontsize(JSContext *cx, uintN argc, Value *vp) { return tagify_value(cx, argc, vp, "font size", "font"); } static JSBool -str_fontcolor(JSContext *cx, uintN argc, jsval *vp) +str_fontcolor(JSContext *cx, uintN argc, Value *vp) { return tagify_value(cx, argc, vp, "font color", "font"); } static JSBool -str_link(JSContext *cx, uintN argc, jsval *vp) +str_link(JSContext *cx, uintN argc, Value *vp) { return tagify_value(cx, argc, vp, "a href", "a"); } static JSBool -str_anchor(JSContext *cx, uintN argc, jsval *vp) +str_anchor(JSContext *cx, uintN argc, Value *vp) { return tagify_value(cx, argc, vp, "a name", "a"); } static JSBool -str_strike(JSContext *cx, uintN argc, jsval *vp) +str_strike(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "strike", NULL, NULL, vp); } static JSBool -str_small(JSContext *cx, uintN argc, jsval *vp) +str_small(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "small", NULL, NULL, vp); } static JSBool -str_big(JSContext *cx, uintN argc, jsval *vp) +str_big(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "big", NULL, NULL, vp); } static JSBool -str_blink(JSContext *cx, uintN argc, jsval *vp) +str_blink(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "blink", NULL, NULL, vp); } static JSBool -str_sup(JSContext *cx, uintN argc, jsval *vp) +str_sup(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "sup", NULL, NULL, vp); } static JSBool -str_sub(JSContext *cx, uintN argc, jsval *vp) +str_sub(JSContext *cx, uintN argc, Value *vp) { return tagify(cx, "sub", NULL, NULL, vp); } @@ -2928,7 +2902,7 @@ const char JSString::deflatedUnitStringTable[] = { #undef O25 JSBool -js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +js_String(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { JSString *str; @@ -2936,15 +2910,15 @@ js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) str = js_ValueToString(cx, argv[0]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); + argv[0].setString(str); } else { str = cx->runtime->emptyString; } if (!JS_IsConstructing(cx)) { - *rval = STRING_TO_JSVAL(str); + rval->setString(str); return JS_TRUE; } - obj->setPrimitiveThis(STRING_TO_JSVAL(str)); + obj->setPrimitiveThis(StringValue(str)); return JS_TRUE; } @@ -2954,7 +2928,7 @@ JSObject* FASTCALL js_String_tn(JSContext* cx, JSObject* proto, JSString* str) { JS_ASSERT(JS_ON_TRACE(cx)); - return js_NewObjectWithClassProto(cx, &js_StringClass, proto, STRING_TO_JSVAL(str)); + return js_NewObjectWithClassProto(cx, &js_StringClass, proto, StringValue(str)); } JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, STRING, 0, nanojit::ACC_STORE_ANY) @@ -2962,9 +2936,9 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, js_String_tn, CONTEXT, CALLEE_PROTOTYPE, ST #endif /* !JS_TRACER */ static JSBool -str_fromCharCode(JSContext *cx, uintN argc, jsval *vp) +str_fromCharCode(JSContext *cx, uintN argc, Value *vp) { - jsval *argv; + Value *argv; uintN i; jschar *chars; JSString *str; @@ -2979,10 +2953,10 @@ str_fromCharCode(JSContext *cx, uintN argc, jsval *vp) str = JSString::unitString(code); if (!str) return JS_FALSE; - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } - argv[0] = INT_TO_JSVAL(code); + argv[0].setInt32(code); } chars = (jschar *) cx->malloc((argc + 1) * sizeof(jschar)); if (!chars) @@ -3001,7 +2975,7 @@ str_fromCharCode(JSContext *cx, uintN argc, jsval *vp) cx->free(chars); return JS_FALSE; } - *vp = STRING_TO_JSVAL(str); + vp->setString(str); return JS_TRUE; } @@ -3034,14 +3008,14 @@ js_InitStringClass(JSContext *cx, JSObject *obj) if (!JS_DefineFunctions(cx, obj, string_functions)) return NULL; - proto = JS_InitClass(cx, obj, NULL, &js_StringClass, js_String, 1, + proto = js_InitClass(cx, obj, NULL, &js_StringClass, js_String, 1, NULL, string_methods, NULL, string_static_methods); if (!proto) return NULL; - proto->setPrimitiveThis(STRING_TO_JSVAL(cx->runtime->emptyString)); + proto->setPrimitiveThis(StringValue(cx->runtime->emptyString)); if (!js_DefineNativeProperty(cx, proto, ATOM_TO_JSID(cx->runtime->atomState.lengthAtom), - JSVAL_VOID, NULL, NULL, + UndefinedValue(), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED, 0, 0, NULL)) { return JS_FALSE; @@ -3215,7 +3189,7 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s) } JS_FRIEND_API(const char *) -js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun) +js_ValueToPrintable(JSContext *cx, const Value &v, JSValueToStringFun v2sfun) { JSString *str; @@ -3228,23 +3202,23 @@ js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun) return js_GetStringBytes(cx, str); } -JS_FRIEND_API(JSString *) -js_ValueToString(JSContext *cx, jsval v) +JSString * +js_ValueToString(JSContext *cx, const Value &arg) { - JSString *str; - - if (!JSVAL_IS_PRIMITIVE(v) && !DefaultValue(cx, JSVAL_TO_OBJECT(v), JSTYPE_STRING, &v)) + Value v = arg; + if (v.isObject() && !DefaultValue(cx, &v.toObject(), JSTYPE_STRING, &v)) return NULL; - if (JSVAL_IS_STRING(v)) { - str = JSVAL_TO_STRING(v); - } else if (JSVAL_IS_INT(v)) { - str = js_NumberToString(cx, JSVAL_TO_INT(v)); - } else if (JSVAL_IS_DOUBLE(v)) { - str = js_NumberToString(cx, *JSVAL_TO_DOUBLE(v)); - } else if (JSVAL_IS_BOOLEAN(v)) { - str = js_BooleanToString(cx, JSVAL_TO_BOOLEAN(v)); - } else if (JSVAL_IS_NULL(v)) { + JSString *str; + if (v.isString()) { + str = v.toString(); + } else if (v.isInt32()) { + str = js_NumberToString(cx, v.toInt32()); + } else if (v.isDouble()) { + str = js_NumberToString(cx, v.toDouble()); + } else if (v.isBoolean()) { + str = js_BooleanToString(cx, v.toBoolean()); + } else if (v.isNull()) { str = ATOM_TO_STRING(cx->runtime->atomState.nullAtom); } else { str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); @@ -3263,39 +3237,39 @@ AppendAtom(JSAtom *atom, JSCharBuffer &cb) } /* This function implements E-262-3 section 9.8, toString. */ -JS_FRIEND_API(JSBool) -js_ValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb) +JSBool +js_ValueToCharBuffer(JSContext *cx, const Value &arg, JSCharBuffer &cb) { - if (!JSVAL_IS_PRIMITIVE(v) && !DefaultValue(cx, JSVAL_TO_OBJECT(v), JSTYPE_STRING, &v)) + Value v = arg; + if (v.isObject() && !DefaultValue(cx, &v.toObject(), JSTYPE_STRING, &v)) return JS_FALSE; - if (JSVAL_IS_STRING(v)) { - JSString *str = JSVAL_TO_STRING(v); + if (v.isString()) { const jschar *chars; size_t length; - str->getCharsAndLength(chars, length); + v.toString()->getCharsAndLength(chars, length); return cb.append(chars, length); } - if (JSVAL_IS_NUMBER(v)) + if (v.isNumber()) return js_NumberValueToCharBuffer(cx, v, cb); - if (JSVAL_IS_BOOLEAN(v)) - return js_BooleanToCharBuffer(cx, JSVAL_TO_BOOLEAN(v), cb); - if (JSVAL_IS_NULL(v)) + if (v.isBoolean()) + return js_BooleanToCharBuffer(cx, v.toBoolean(), cb); + if (v.isNull()) return AppendAtom(cx->runtime->atomState.nullAtom, cb); - JS_ASSERT(JSVAL_IS_VOID(v)); + JS_ASSERT(v.isUndefined()); return AppendAtom(cx->runtime->atomState.typeAtoms[JSTYPE_VOID], cb); } JS_FRIEND_API(JSString *) -js_ValueToSource(JSContext *cx, jsval v) +js_ValueToSource(JSContext *cx, const Value &v) { - if (JSVAL_IS_VOID(v)) + if (v.isUndefined()) return ATOM_TO_STRING(cx->runtime->atomState.void0Atom); - if (JSVAL_IS_STRING(v)) - return js_QuoteString(cx, JSVAL_TO_STRING(v), '"'); - if (JSVAL_IS_PRIMITIVE(v)) { + if (v.isString()) + return js_QuoteString(cx, v.toString(), '"'); + if (v.isPrimitive()) { /* Special case to preserve negative zero, _contra_ toString. */ - if (JSVAL_IS_DOUBLE(v) && JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) { + if (v.isDouble() && JSDOUBLE_IS_NEGZERO(v.toDouble())) { /* NB: _ucNstr rather than _ucstr to indicate non-terminated. */ static const jschar js_negzero_ucNstr[] = {'-', '0'}; @@ -3305,8 +3279,8 @@ js_ValueToSource(JSContext *cx, jsval v) } JSAtom *atom = cx->runtime->atomState.toSourceAtom; - AutoValueRooter tvr(cx, JSVAL_NULL); - if (!js_TryMethod(cx, JSVAL_TO_OBJECT(v), atom, 0, NULL, tvr.addr())) + AutoValueRooter tvr(cx); + if (!js_TryMethod(cx, &v.toObject(), atom, 0, NULL, tvr.addr())) return NULL; return js_ValueToString(cx, tvr.value()); } @@ -5252,12 +5226,12 @@ const bool js_alnum[] = { #define URI_CHUNK 64U static inline bool -TransferBufferToString(JSContext *cx, JSCharBuffer &cb, jsval *rval) +TransferBufferToString(JSContext *cx, JSCharBuffer &cb, Value *rval) { JSString *str = js_NewStringFromCharBuffer(cx, cb); if (!str) return false; - *rval = STRING_TO_JSVAL(str); + rval->setString(str); return true;; } @@ -5270,7 +5244,7 @@ TransferBufferToString(JSContext *cx, JSCharBuffer &cb, jsval *rval) */ static JSBool Encode(JSContext *cx, JSString *str, const jschar *unescapedSet, - const jschar *unescapedSet2, jsval *rval) + const jschar *unescapedSet2, Value *rval) { size_t length, j, k, L; JSCharBuffer cb(cx); @@ -5283,7 +5257,7 @@ Encode(JSContext *cx, JSString *str, const jschar *unescapedSet, str->getCharsAndLength(chars, length); if (length == 0) { - *rval = STRING_TO_JSVAL(cx->runtime->emptyString); + rval->setString(cx->runtime->emptyString); return JS_TRUE; } @@ -5333,7 +5307,7 @@ Encode(JSContext *cx, JSString *str, const jschar *unescapedSet, } static JSBool -Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval) +Decode(JSContext *cx, JSString *str, const jschar *reservedSet, Value *rval) { size_t length, start, k; JSCharBuffer cb(cx); @@ -5346,7 +5320,7 @@ Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval) str->getCharsAndLength(chars, length); if (length == 0) { - *rval = STRING_TO_JSVAL(cx->runtime->emptyString); + rval->setString(cx->runtime->emptyString); return JS_TRUE; } @@ -5420,7 +5394,7 @@ Decode(JSContext *cx, JSString *str, const jschar *reservedSet, jsval *rval) } static JSBool -str_decodeURI(JSContext *cx, uintN argc, jsval *vp) +str_decodeURI(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -5431,7 +5405,7 @@ str_decodeURI(JSContext *cx, uintN argc, jsval *vp) } static JSBool -str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp) +str_decodeURI_Component(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -5442,7 +5416,7 @@ str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp) } static JSBool -str_encodeURI(JSContext *cx, uintN argc, jsval *vp) +str_encodeURI(JSContext *cx, uintN argc, Value *vp) { JSString *str; @@ -5454,7 +5428,7 @@ str_encodeURI(JSContext *cx, uintN argc, jsval *vp) } static JSBool -str_encodeURI_Component(JSContext *cx, uintN argc, jsval *vp) +str_encodeURI_Component(JSContext *cx, uintN argc, Value *vp) { JSString *str; diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 080ec55b56e1..0b42ae288dab 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -49,13 +49,12 @@ * allocated from the malloc heap. */ #include -#include "jspubtd.h" +#include "jsapi.h" #include "jsprvtd.h" #include "jshashtable.h" #include "jslock.h" #include "jsobj.h" - -JS_BEGIN_EXTERN_C +#include "jsvalue.h" #define JSSTRING_BIT(n) ((size_t)1 << (n)) #define JSSTRING_BITMASK(n) (JSSTRING_BIT(n) - 1) @@ -301,6 +300,8 @@ struct JSString { static JSString *intString(jsint i); }; +JS_STATIC_ASSERT(sizeof(JSString) % JS_GCTHING_ALIGN == 0); + extern const jschar * js_GetStringChars(JSContext *cx, JSString *str); @@ -472,7 +473,7 @@ JS_ISSPACE(jschar c) #define JS7_ISLET(c) ((c) < 128 && isalpha(c)) /* Initialize the String class, returning its prototype object. */ -extern JSClass js_StringClass; +extern js::Class js_StringClass; inline bool JSObject::isString() const @@ -518,10 +519,10 @@ js_NewStringCopyZ(JSContext *cx, const jschar *s); /* * Convert a value to a printable C string. */ -typedef JSString *(*JSValueToStringFun)(JSContext *cx, jsval v); +typedef JSString *(*JSValueToStringFun)(JSContext *cx, const js::Value &v); extern JS_FRIEND_API(const char *) -js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun); +js_ValueToPrintable(JSContext *cx, const js::Value &, JSValueToStringFun v2sfun); #define js_ValueToPrintableString(cx,v) \ js_ValueToPrintable(cx, v, js_ValueToString) @@ -533,23 +534,23 @@ js_ValueToPrintable(JSContext *cx, jsval v, JSValueToStringFun v2sfun); * Convert a value to a string, returning null after reporting an error, * otherwise returning a new string reference. */ -extern JS_FRIEND_API(JSString *) -js_ValueToString(JSContext *cx, jsval v); +extern JSString * +js_ValueToString(JSContext *cx, const js::Value &v); /* * This function implements E-262-3 section 9.8, toString. Convert the given * value to a string of jschars appended to the given buffer. On error, the * passed buffer may have partial results appended. */ -extern JS_FRIEND_API(JSBool) -js_ValueToCharBuffer(JSContext *cx, jsval v, JSCharBuffer &cb); +extern JSBool +js_ValueToCharBuffer(JSContext *cx, const js::Value &v, JSCharBuffer &cb); /* * Convert a value to its source expression, returning null after reporting * an error, otherwise returning a new string reference. */ extern JS_FRIEND_API(JSString *) -js_ValueToSource(JSContext *cx, jsval v); +js_ValueToSource(JSContext *cx, const js::Value &v); /* * Compute a hash function from str. The caller can call this function even if @@ -678,11 +679,11 @@ js_GetStringBytes(JSContext *cx, JSString *str); /* Export a few natives and a helper to other files in SpiderMonkey. */ extern JSBool -js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_str_escape(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv, + js::Value *rval); extern JSBool -js_str_toString(JSContext *cx, uintN argc, jsval *vp); +js_str_toString(JSContext *cx, uintN argc, js::Value *vp); /* * Convert one UCS-4 char and write it into a UTF-8 buffer, which must be at @@ -718,9 +719,7 @@ js_PutEscapedStringImpl(char *buffer, size_t bufferSize, FILE *fp, JSString *str, uint32 quote); extern JSBool -js_String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); - -JS_END_EXTERN_C +js_String(JSContext *cx, JSObject *obj, uintN argc, js::Value *argv, js::Value *rval); namespace js { diff --git a/js/src/jstl.h b/js/src/jstl.h index 29f02c2f16c4..94c25726264e 100644 --- a/js/src/jstl.h +++ b/js/src/jstl.h @@ -405,6 +405,58 @@ PodArrayZero(T (&t)[N]) memset(t, 0, N * sizeof(T)); } +template +class AlignedPtrAndFlag +{ + uintptr_t bits; + + public: + AlignedPtrAndFlag(T *t, bool flag) { + JS_ASSERT((uintptr_t(t) & 1) == 0); + bits = uintptr_t(t) | uintptr_t(flag); + } + + T *ptr() const { + return (T *)(bits & ~uintptr_t(1)); + } + + bool flag() const { + return (bits & 1) != 0; + } + + void setPtr(T *t) { + JS_ASSERT((uintptr_t(t) & 1) == 0); + bits = uintptr_t(t) | uintptr_t(flag()); + } + + void setFlag() { + bits |= 1; + } + + void unsetFlag() { + bits &= ~uintptr_t(1); + } + + void set(T *t, bool flag) { + JS_ASSERT((uintptr_t(t) & 1) == 0); + bits = uintptr_t(t) | flag; + } +}; + +template +static inline void +Reverse(T *beg, T *end) +{ + while (beg != end) { + if (--end == beg) + return; + T tmp = *beg; + *beg = *end; + *end = tmp; + ++beg; + } +} + } /* namespace js */ #endif /* jstl_h_ */ diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 3305fc1c0bb6..d22cd4d9327c 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -83,6 +83,7 @@ #include "jsobjinlines.h" #include "jsscopeinlines.h" #include "jsscriptinlines.h" +#include "jscntxtinlines.h" #include "jsautooplen.h" // generated headers last #include "imacros.c.out" @@ -187,7 +188,7 @@ using namespace nanojit; #if JS_HAS_XML_SUPPORT #define RETURN_VALUE_IF_XML(val, ret) \ JS_BEGIN_MACRO \ - if (!JSVAL_IS_PRIMITIVE(val) && JSVAL_TO_OBJECT(val)->isXML()) \ + if (!val.isPrimitive() && val.toObject().isXML()) \ RETURN_VALUE("xml detected", ret); \ JS_END_MACRO #else @@ -197,12 +198,48 @@ using namespace nanojit; #define RETURN_IF_XML_A(val) RETURN_VALUE_IF_XML(val, ARECORD_STOP) #define RETURN_IF_XML(val) RETURN_VALUE_IF_XML(val, RECORD_STOP) -JS_STATIC_ASSERT(sizeof(TraceType) == 1); +JS_STATIC_ASSERT(sizeof(JSValueType) == 1); JS_STATIC_ASSERT(offsetof(TraceNativeStorage, stack_global_buf) % 16 == 0); /* Map to translate a type tag into a printable representation. */ -static const char typeChar[] = "OIDXSNBUF"; -static const char tagChar[] = "OIDISIBI"; +#ifdef DEBUG +static char +TypeToChar(JSValueType type) +{ + switch (type) { + case JSVAL_TYPE_DOUBLE: return 'D'; + case JSVAL_TYPE_INT32: return 'I'; + case JSVAL_TYPE_STRING: return 'S'; + case JSVAL_TYPE_OBJECT: return '!'; + case JSVAL_TYPE_BOOLEAN: return 'B'; + case JSVAL_TYPE_NULL: return 'N'; + case JSVAL_TYPE_UNDEFINED: return 'U'; + case JSVAL_TYPE_MAGIC: return 'M'; + case JSVAL_TYPE_FUNOBJ: return 'F'; + case JSVAL_TYPE_NONFUNOBJ: return 'O'; + case JSVAL_TYPE_BOXED: return '#'; + case JSVAL_TYPE_STRORNULL: return 's'; + case JSVAL_TYPE_OBJORNULL: return 'o'; + case JSVAL_TYPE_UNINITIALIZED: return '*'; + } + return '?'; +} + +static char +ValueToTypeChar(const Value &v) +{ + if (v.isInt32()) return 'I'; + if (v.isDouble()) return 'D'; + if (v.isString()) return 'S'; + if (v.isObject()) return v.toObject().isFunction() ? 'F' : 'O'; + if (v.isBoolean()) return 'B'; + if (v.isNull()) return 'N'; + if (v.isUndefined()) return 'U'; + if (v.isMagic()) return 'M'; + return '?'; +} +#endif + /* Blacklist parameters. */ @@ -238,7 +275,7 @@ static const char tagChar[] = "OIDISIBI"; /* Max memory needed to rebuild the interpreter stack when falling off trace. */ #define MAX_INTERP_STACK_BYTES \ - (MAX_NATIVE_STACK_SLOTS * sizeof(jsval) + \ + (MAX_NATIVE_STACK_SLOTS * sizeof(Value) + \ MAX_CALL_STACK_ENTRIES * sizeof(JSInlineFrame) + \ sizeof(JSInlineFrame)) /* possibly slow native frame at top of stack */ @@ -310,16 +347,16 @@ jitstats_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { int index = -1; - if (JSVAL_IS_STRING(id)) { - JSString* str = JSVAL_TO_STRING(id); + if (JSID_IS_STRING(id)) { + JSString* str = JSID_TO_STRING(id); if (strcmp(JS_GetStringBytes(str), "HOTLOOP") == 0) { *vp = INT_TO_JSVAL(HOTLOOP); return JS_TRUE; } } - if (JSVAL_IS_INT(id)) - index = JSVAL_TO_INT(id); + if (JSID_IS_INT(id)) + index = JSID_TO_INT(id); uint64 result = 0; switch (index) { @@ -369,23 +406,23 @@ InitJITStatsClass(JSContext *cx, JSObject *glob) */ #define INS_CONST(c) addName(lir->insImmI(c), #c) +#define INS_CONSTU(c) addName(lir->insImmI((uint32_t)c), #c) #define INS_CONSTPTR(p) addName(lir->insImmP(p), #p) #define INS_CONSTWORD(v) addName(lir->insImmP((void *) (v)), #v) -#define INS_CONSTVAL(v) addName(insImmVal(v), #v) +#define INS_CONSTQWORD(c) addName(lir->insImmQ(c), #c) #define INS_CONSTOBJ(obj) addName(insImmObj(obj), #obj) #define INS_CONSTFUN(fun) addName(insImmFun(fun), #fun) #define INS_CONSTSTR(str) addName(insImmStr(str), #str) #define INS_CONSTSPROP(sprop) addName(insImmSprop(sprop), #sprop) +#define INS_CONSTID(id) addName(insImmId(id), #id) #define INS_ATOM(atom) INS_CONSTSTR(ATOM_TO_STRING(atom)) #define INS_NULL() INS_CONSTPTR(NULL) -#define INS_VOID() INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)) -#define INS_HOLE() INS_CONST(JSVAL_TO_SPECIAL(JSVAL_HOLE)) +#define INS_UNDEFINED() INS_CONST(0) -static JS_ALWAYS_INLINE JSBool -JSVAL_IS_HOLE(jsval v) -{ - return v == JSVAL_HOLE; -} +static const size_t sPayloadOffset = offsetof(jsval_layout, s.payload); +#if JS_BITS_PER_WORD == 32 +static const size_t sTagOffset = offsetof(jsval_layout, s.tag); +#endif static avmplus::AvmCore s_core = avmplus::AvmCore(); static avmplus::AvmCore* core = &s_core; @@ -833,6 +870,12 @@ PrintOnTrace(char* format, uint32 argc, double *argv) GET_ARG(); fprintf(out, "%s", u.cstr); break; + case 'v': { + GET_ARG(); + Value *v = (Value *) u.i.lo; + js_DumpValue(*v); + break; + } default: fprintf(out, "[invalid %%%c]", *p); } @@ -1005,93 +1048,66 @@ argSlots(JSStackFrame* fp) } static inline bool -isNumber(jsval v) +hasInt32Repr(const Value &v) { - return JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v); -} - -static inline jsdouble -asNumber(jsval v) -{ - JS_ASSERT(isNumber(v)); - if (JSVAL_IS_DOUBLE(v)) - return *JSVAL_TO_DOUBLE(v); - return (jsdouble)JSVAL_TO_INT(v); -} - -static inline bool -isInt32(jsval v) -{ - if (!isNumber(v)) + if (!v.isNumber()) return false; - jsdouble d = asNumber(v); - jsint i; - return !!JSDOUBLE_IS_INT(d, i); + if (v.isInt32()) + return true; + int32_t _; + return JSDOUBLE_IS_INT32(v.toDouble(), &_); } static inline jsint -asInt32(jsval v) +asInt32(const Value &v) { - JS_ASSERT(isNumber(v)); - if (JSVAL_IS_INT(v)) - return JSVAL_TO_INT(v); + JS_ASSERT(v.isNumber()); + if (v.isInt32()) + return v.toInt32(); #ifdef DEBUG - jsint i; - JS_ASSERT(JSDOUBLE_IS_INT(*JSVAL_TO_DOUBLE(v), i)); + int32_t _; + JS_ASSERT(JSDOUBLE_IS_INT32(v.toDouble(), &_)); #endif - return jsint(*JSVAL_TO_DOUBLE(v)); + return jsint(v.toDouble()); } -/* Return TT_DOUBLE for all numbers (int and double) and the tag otherwise. */ -static inline TraceType -GetPromotedType(jsval v) +/* Return JSVAL_TYPE_DOUBLE for all numbers (int and double) and the tag otherwise. */ +static inline JSValueType +GetPromotedType(const Value &v) { - if (JSVAL_IS_INT(v)) - return TT_DOUBLE; - if (JSVAL_IS_OBJECT(v)) { - if (JSVAL_IS_NULL(v)) - return TT_NULL; - if (JSVAL_TO_OBJECT(v)->isFunction()) - return TT_FUNCTION; - return TT_OBJECT; - } - /* N.B. void and hole are JSVAL_SPECIAL. */ - if (JSVAL_IS_VOID(v)) - return TT_VOID; - if (JSVAL_IS_HOLE(v)) - return TT_MAGIC; - uint8_t tag = JSVAL_TAG(v); - JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL); - JS_STATIC_ASSERT(static_cast(TT_DOUBLE) == JSVAL_DOUBLE); - JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); - return TraceType(tag); + if (v.isNumber()) + return JSVAL_TYPE_DOUBLE; + if (v.isObject()) + return v.toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return v.extractNonDoubleObjectTraceType(); } -/* Return TT_INT32 for all whole numbers that fit into signed 32-bit and the tag otherwise. */ -static inline TraceType -getCoercedType(jsval v) +/* Return JSVAL_TYPE_INT32 for all whole numbers that fit into signed 32-bit and the tag otherwise. */ +static inline JSValueType +getCoercedType(const Value &v) { - if (isInt32(v)) - return TT_INT32; - if (JSVAL_IS_OBJECT(v)) { - if (JSVAL_IS_NULL(v)) - return TT_NULL; - if (JSVAL_TO_OBJECT(v)->isFunction()) - return TT_FUNCTION; - return TT_OBJECT; + if (v.isNumber()) { + int32_t _; + return (v.isInt32() || JSDOUBLE_IS_INT32(v.toDouble(), &_)) + ? JSVAL_TYPE_INT32 + : JSVAL_TYPE_DOUBLE; } - /* N.B. void and hole are JSVAL_SPECIAL. */ - if (JSVAL_IS_VOID(v)) - return TT_VOID; - if (JSVAL_IS_HOLE(v)) - return TT_MAGIC; - uint8_t tag = JSVAL_TAG(v); - JS_ASSERT(tag == JSVAL_DOUBLE || tag == JSVAL_STRING || tag == JSVAL_SPECIAL); - JS_STATIC_ASSERT(static_cast(TT_DOUBLE) == JSVAL_DOUBLE); - JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); - return TraceType(tag); + if (v.isObject()) + return v.toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return v.extractNonDoubleObjectTraceType(); +} + +static inline JSValueType +getFrameObjPtrTraceType(JSObject *obj) +{ + JS_ASSERT_IF(obj, !obj->isFunction()); + return obj ? JSVAL_TYPE_NONFUNOBJ : JSVAL_TYPE_NULL; +} + +static inline bool +IsFrameObjPtrTraceType(JSValueType t) +{ + return t == JSVAL_TYPE_NULL || t == JSVAL_TYPE_NONFUNOBJ || t == JSVAL_TYPE_FUNOBJ; } /* Constant seed and accumulate step borrowed from the DJB hash. */ @@ -1251,7 +1267,7 @@ class FrameInfoCache { typedef FrameInfo *Lookup; static HashNumber hash(const FrameInfo* fi) { - size_t len = sizeof(FrameInfo) + fi->callerHeight * sizeof(TraceType); + size_t len = sizeof(FrameInfo) + fi->callerHeight * sizeof(JSValueType); HashNumber h = 0; const unsigned char *s = (const unsigned char*)fi; for (size_t i = 0; i < len; i++, s++) @@ -1263,7 +1279,7 @@ class FrameInfoCache if (memcmp(fi1, fi2, sizeof(FrameInfo)) != 0) return false; return memcmp(fi1->get_typemap(), fi2->get_typemap(), - fi1->callerHeight * sizeof(TraceType)) == 0; + fi1->callerHeight * sizeof(JSValueType)) == 0; } }; @@ -1284,8 +1300,8 @@ class FrameInfoCache FrameSet::AddPtr p = set.lookupForAdd(fi); if (!p) { FrameInfo* n = (FrameInfo*) - allocator->alloc(sizeof(FrameInfo) + fi->callerHeight * sizeof(TraceType)); - memcpy(n, fi, sizeof(FrameInfo) + fi->callerHeight * sizeof(TraceType)); + allocator->alloc(sizeof(FrameInfo) + fi->callerHeight * sizeof(JSValueType)); + memcpy(n, fi, sizeof(FrameInfo) + fi->callerHeight * sizeof(JSValueType)); if (!set.add(p, n)) return NULL; } @@ -1458,7 +1474,7 @@ TreeFragment::initialize(JSContext* cx, SlotList *globalSlots, bool speculate) /* Capture the coerced type of each active slot in the type map. */ this->typeMap.captureTypes(cx, globalObj, *globalSlots, 0 /* callDepth */, speculate); this->nStackTypes = this->typeMap.length() - globalSlots->length(); - this->spOffsetAtEntry = cx->regs->sp - StackBase(cx->fp); + this->spOffsetAtEntry = cx->regs->sp - cx->fp->base(); #ifdef DEBUG this->treeFileName = cx->fp->script->filename; @@ -1473,7 +1489,7 @@ TreeFragment::initialize(JSContext* cx, SlotList *globalSlots, bool speculate) this->sideExits.clear(); /* Determine the native frame layout at the entry point. */ - this->nativeStackBase = (nStackTypes - (cx->regs->sp - StackBase(cx->fp))) * + this->nativeStackBase = (nStackTypes - (cx->regs->sp - cx->fp->base())) * sizeof(double); this->maxNativeStackSlots = nStackTypes; this->maxCallDepth = 0; @@ -1732,7 +1748,7 @@ VisitFrameSlots(Visitor &visitor, JSContext *cx, unsigned depth, FrameRegsIter &i, JSStackFrame *up) { JSStackFrame *const fp = i.fp(); - jsval *const sp = i.sp(); + Value *const sp = i.sp(); if (depth > 0 && !VisitFrameSlots(visitor, cx, depth-1, ++i, fp)) return false; @@ -1744,13 +1760,13 @@ VisitFrameSlots(Visitor &visitor, JSContext *cx, unsigned depth, return false; } visitor.setStackSlotKind("arguments"); - if (!visitor.visitStackSlots(&fp->argsobj, 1, fp)) + if (!visitor.visitFrameObjPtr(&fp->argsobj, fp)) return false; // We want to import and track |JSObject *scopeChain|, but the tracker - // requires type |jsval|. But the bits are the same, so we can import + // requires type |Value|. But the bits are the same, so we can import // it with a cast and the (identity function) unboxing will be OK. visitor.setStackSlotKind("scopeChain"); - if (!visitor.visitStackSlots(&fp->scopeChainVal, 1, fp)) + if (!visitor.visitFrameObjPtr(&fp->scopeChain, fp)) return false; visitor.setStackSlotKind("var"); if (!visitor.visitStackSlots(fp->slots(), fp->script->nfixed, fp)) @@ -1758,7 +1774,7 @@ VisitFrameSlots(Visitor &visitor, JSContext *cx, unsigned depth, } visitor.setStackSlotKind("stack"); - jsval *base = StackBase(fp); + Value *base = fp->base(); JS_ASSERT(sp >= base && sp <= fp->slots() + fp->script->nslots); if (!visitor.visitStackSlots(base, size_t(sp - base), fp)) return false; @@ -1865,20 +1881,20 @@ struct CountSlotsVisitor : public SlotVisitorBase { unsigned mCount; bool mDone; - jsval* mStop; + const void* mStop; public: - JS_ALWAYS_INLINE CountSlotsVisitor(jsval* stop = NULL) : + JS_ALWAYS_INLINE CountSlotsVisitor(const void* stop = NULL) : mCount(0), mDone(false), mStop(stop) {} JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) { + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { if (mDone) return false; - if (mStop && size_t(mStop - vp) < count) { - mCount += size_t(mStop - vp); + if (mStop && size_t(((const Value *)mStop) - vp) < count) { + mCount += size_t(((const Value *)mStop) - vp); mDone = true; return false; } @@ -1886,6 +1902,18 @@ public: return true; } + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame* fp) { + if (mDone) + return false; + if (mStop && mStop == p) { + mDone = true; + return false; + } + mCount++; + return true; + } + JS_ALWAYS_INLINE unsigned count() { return mCount; } @@ -1911,7 +1939,7 @@ NativeStackSlots(JSContext *cx, unsigned callDepth) * header comment. */ JSStackFrame *const fp = i.fp(); - slots += i.sp() - StackBase(fp); + slots += i.sp() - fp->base(); if (fp->argv) slots += fp->script->nfixed + SPECIAL_FRAME_SLOTS; if (depth-- == 0) { @@ -1934,44 +1962,54 @@ NativeStackSlots(JSContext *cx, unsigned callDepth) class CaptureTypesVisitor : public SlotVisitorBase { JSContext* mCx; - TraceType* mTypeMap; - TraceType* mPtr; + JSValueType* mTypeMap; + JSValueType* mPtr; Oracle * mOracle; public: - JS_ALWAYS_INLINE CaptureTypesVisitor(JSContext* cx, TraceType* typeMap, bool speculate) : + JS_ALWAYS_INLINE CaptureTypesVisitor(JSContext* cx, JSValueType* typeMap, bool speculate) : mCx(cx), mTypeMap(typeMap), mPtr(typeMap), mOracle(speculate ? JS_TRACE_MONITOR(cx).oracle : NULL) {} JS_REQUIRES_STACK JS_ALWAYS_INLINE void - visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { - TraceType type = getCoercedType(*vp); - if (type == TT_INT32 && (!mOracle || mOracle->isGlobalSlotUndemotable(mCx, slot))) - type = TT_DOUBLE; - JS_ASSERT(type != TT_JSVAL); + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { + JSValueType type = getCoercedType(*vp); + if (type == JSVAL_TYPE_INT32 && (!mOracle || mOracle->isGlobalSlotUndemotable(mCx, slot))) + type = JSVAL_TYPE_DOUBLE; + JS_ASSERT(type != JSVAL_TYPE_BOXED); debug_only_printf(LC_TMTracer, - "capture type global%d: %d=%c\n", - n, type, typeChar[type]); + "capture type global%d: %c\n", + n, TypeToChar(type)); *mPtr++ = type; } JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, int count, JSStackFrame* fp) { + visitStackSlots(Value *vp, int count, JSStackFrame* fp) { for (int i = 0; i < count; ++i) { - TraceType type = getCoercedType(vp[i]); - if (type == TT_INT32 && (!mOracle || mOracle->isStackSlotUndemotable(mCx, length()))) - type = TT_DOUBLE; - JS_ASSERT(type != TT_JSVAL); + JSValueType type = getCoercedType(vp[i]); + if (type == JSVAL_TYPE_INT32 && (!mOracle || mOracle->isStackSlotUndemotable(mCx, length()))) + type = JSVAL_TYPE_DOUBLE; + JS_ASSERT(type != JSVAL_TYPE_BOXED); debug_only_printf(LC_TMTracer, - "capture type %s%d: %d=%c\n", - stackSlotKind(), i, type, typeChar[type]); + "capture type %s%d: %c\n", + stackSlotKind(), i, TypeToChar(type)); *mPtr++ = type; } return true; } + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame* fp) { + JSValueType type = getFrameObjPtrTraceType(*p); + debug_only_printf(LC_TMTracer, + "capture type %s%d: %c\n", + stackSlotKind(), 0, TypeToChar(type)); + *mPtr++ = type; + return true; + } + JS_ALWAYS_INLINE uintptr_t length() { return mPtr - mTypeMap; } @@ -1979,11 +2017,11 @@ public: void TypeMap::set(unsigned stackSlots, unsigned ngslots, - const TraceType* stackTypeMap, const TraceType* globalTypeMap) + const JSValueType* stackTypeMap, const JSValueType* globalTypeMap) { setLength(ngslots + stackSlots); - memcpy(data(), stackTypeMap, stackSlots * sizeof(TraceType)); - memcpy(data() + stackSlots, globalTypeMap, ngslots * sizeof(TraceType)); + memcpy(data(), stackTypeMap, stackSlots * sizeof(JSValueType)); + memcpy(data() + stackSlots, globalTypeMap, ngslots * sizeof(JSValueType)); } /* @@ -2022,7 +2060,7 @@ TypeMap::matches(TypeMap& other) const } void -TypeMap::fromRaw(TraceType* other, unsigned numSlots) +TypeMap::fromRaw(JSValueType* other, unsigned numSlots) { unsigned oldLength = length(); setLength(length() + numSlots); @@ -2036,12 +2074,12 @@ TypeMap::fromRaw(TraceType* other, unsigned numSlots) * map. */ static void -MergeTypeMaps(TraceType** partial, unsigned* plength, TraceType* complete, unsigned clength, TraceType* mem) +MergeTypeMaps(JSValueType** partial, unsigned* plength, JSValueType* complete, unsigned clength, JSValueType* mem) { unsigned l = *plength; JS_ASSERT(l < clength); - memcpy(mem, *partial, l * sizeof(TraceType)); - memcpy(mem + l, complete + l, (clength - l) * sizeof(TraceType)); + memcpy(mem, *partial, l * sizeof(JSValueType)); + memcpy(mem + l, complete + l, (clength - l) * sizeof(JSValueType)); *partial = mem; *plength = clength; } @@ -2051,7 +2089,7 @@ MergeTypeMaps(TraceType** partial, unsigned* plength, TraceType* complete, unsig * dependent trees. */ static JS_REQUIRES_STACK void -SpecializeTreesToLateGlobals(JSContext* cx, TreeFragment* root, TraceType* globalTypeMap, +SpecializeTreesToLateGlobals(JSContext* cx, TreeFragment* root, JSValueType* globalTypeMap, unsigned numGlobalSlots) { for (unsigned i = root->nGlobalTypes(); i < numGlobalSlots; i++) @@ -2119,7 +2157,7 @@ InitConst(const T &t) JS_REQUIRES_STACK TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* fragment, - unsigned stackSlots, unsigned ngslots, TraceType* typeMap, + unsigned stackSlots, unsigned ngslots, JSValueType* typeMap, VMSideExit* innermost, jsbytecode* outer, uint32 outerArgc, RecordReason recordReason, bool speculate) : cx(cx), @@ -2147,6 +2185,7 @@ TraceRecorder::TraceRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* frag global_dslots(NULL), callDepth(anchor ? anchor->calldepth : 0), atoms(FrameAtomBase(cx, cx->fp)), + consts(cx->fp->script->constOffset ? cx->fp->script->consts()->vector : NULL), cfgMerges(&tempAlloc()), trashSelf(false), whichTreesToTrash(&tempAlloc()), @@ -2433,32 +2472,24 @@ TraceRecorder::addName(LIns* ins, const char* name) return ins; } -inline LIns* -TraceRecorder::insImmVal(jsval val) -{ - if (JSVAL_IS_TRACEABLE(val)) - tree->gcthings.addUnique(val); - return lir->insImmWord(val); -} - inline LIns* TraceRecorder::insImmObj(JSObject* obj) { - tree->gcthings.addUnique(OBJECT_TO_JSVAL(obj)); + tree->gcthings.addUnique(ObjectValue(*obj)); return lir->insImmP((void*)obj); } inline LIns* TraceRecorder::insImmFun(JSFunction* fun) { - tree->gcthings.addUnique(OBJECT_TO_JSVAL(FUN_OBJECT(fun))); + tree->gcthings.addUnique(ObjectValue(*fun)); return lir->insImmP((void*)fun); } inline LIns* TraceRecorder::insImmStr(JSString* str) { - tree->gcthings.addUnique(STRING_TO_JSVAL(str)); + tree->gcthings.addUnique(StringValue(str)); return lir->insImmP((void*)str); } @@ -2469,6 +2500,14 @@ TraceRecorder::insImmSprop(JSScopeProperty* sprop) return lir->insImmP((void*)sprop); } +inline LIns* +TraceRecorder::insImmId(jsid id) +{ + if (JSID_IS_GCTHING(id)) + tree->gcthings.addUnique(IdToValue(id)); + return lir->insImmP((void*)JSID_BITS(id)); +} + inline LIns* TraceRecorder::p2i(nanojit::LIns* ins) { @@ -2480,7 +2519,7 @@ TraceRecorder::p2i(nanojit::LIns* ins) } ptrdiff_t -TraceRecorder::nativeGlobalSlot(jsval* p) const +TraceRecorder::nativeGlobalSlot(const Value* p) const { JS_ASSERT(isGlobal(p)); if (size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) @@ -2490,19 +2529,25 @@ TraceRecorder::nativeGlobalSlot(jsval* p) const /* Determine the offset in the native global frame for a jsval we track. */ ptrdiff_t -TraceRecorder::nativeGlobalOffset(jsval* p) const +TraceRecorder::nativeGlobalOffset(const Value* p) const { return nativeGlobalSlot(p) * sizeof(double); } /* Determine whether a value is a global stack slot. */ bool -TraceRecorder::isGlobal(jsval* p) const +TraceRecorder::isGlobal(const Value* p) const { return ((size_t(p - globalObj->fslots) < JS_INITIAL_NSLOTS) || (size_t(p - globalObj->dslots) < (globalObj->numSlots() - JS_INITIAL_NSLOTS))); } +bool +TraceRecorder::isVoidPtrGlobal(const void* p) const +{ + return isGlobal((const Value *)p); +} + /* * Return the offset in the native stack for the given jsval. More formally, * |p| must be the address of a jsval that is represented in the native stack @@ -2511,7 +2556,7 @@ TraceRecorder::isGlobal(jsval* p) const * relative to TracerState::sp, subtract TreeFragment::nativeStackBase. */ JS_REQUIRES_STACK ptrdiff_t -TraceRecorder::nativeStackOffset(jsval* p) const +TraceRecorder::nativeStackOffsetImpl(const void* p) const { CountSlotsVisitor visitor(p); VisitStackSlots(visitor, cx, callDepth); @@ -2522,16 +2567,29 @@ TraceRecorder::nativeStackOffset(jsval* p) const * frame above sp but below fp->slots() + script->nslots. */ if (!visitor.stopped()) { - JS_ASSERT(size_t(p - cx->fp->slots()) < cx->fp->script->nslots); - offset += size_t(p - cx->regs->sp) * sizeof(double); + const Value *vp = (const Value *)p; + JS_ASSERT(size_t(vp - cx->fp->slots()) < cx->fp->script->nslots); + offset += size_t(vp - cx->regs->sp) * sizeof(double); } return offset; } -JS_REQUIRES_STACK ptrdiff_t -TraceRecorder::nativeStackSlot(jsval* p) const +JS_REQUIRES_STACK inline ptrdiff_t +TraceRecorder::nativeStackOffset(const Value* p) const { - return nativeStackOffset(p) / sizeof(double); + return nativeStackOffsetImpl(p); +} + +JS_REQUIRES_STACK inline ptrdiff_t +TraceRecorder::nativeStackSlotImpl(const void* p) const +{ + return nativeStackOffsetImpl(p) / sizeof(double); +} + +JS_REQUIRES_STACK inline ptrdiff_t +TraceRecorder::nativeStackSlot(const Value* p) const +{ + return nativeStackSlotImpl(p); } /* @@ -2539,9 +2597,15 @@ TraceRecorder::nativeStackSlot(jsval* p) const * -TreeFragment::nativeStackBase + nativeStackOffset(p). */ inline JS_REQUIRES_STACK ptrdiff_t -TraceRecorder::nativespOffset(jsval* p) const +TraceRecorder::nativespOffsetImpl(const void* p) const { - return -tree->nativeStackBase + nativeStackOffset(p); + return -tree->nativeStackBase + nativeStackOffsetImpl(p); +} + +inline JS_REQUIRES_STACK ptrdiff_t +TraceRecorder::nativespOffset(const Value* p) const +{ + return nativespOffsetImpl(p); } /* Track the maximum number of native frame slots we need during execution. */ @@ -2557,96 +2621,82 @@ TraceRecorder::trackNativeStackUse(unsigned slots) * directly (instead of storing a pointer to them). We assert instead of * type checking. The caller must ensure the types are compatible. */ -static void -ValueToNative(JSContext* cx, jsval v, TraceType type, double* slot) +static inline void +ValueToNative(const Value &v, JSValueType type, double* slot) { - uint8_t tag = JSVAL_TAG(v); + JS_ASSERT(type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); + if (type > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) + v.unboxNonDoubleTo((uint64 *)slot); + else if (type == JSVAL_TYPE_INT32) + *(int32_t *)slot = v.isInt32() ? v.toInt32() : (int32_t)v.toDouble(); + else + *(double *)slot = v.toNumber(); + +#ifdef DEBUG + int32_t _; switch (type) { - case TT_OBJECT: - JS_ASSERT(tag == JSVAL_OBJECT); - JS_ASSERT(!JSVAL_IS_NULL(v) && !JSVAL_TO_OBJECT(v)->isFunction()); - *(JSObject**)slot = JSVAL_TO_OBJECT(v); + case JSVAL_TYPE_NONFUNOBJ: { + JS_ASSERT(!IsFunctionObject(v)); debug_only_printf(LC_TMTracer, - "object<%p:%s> ", (void*)JSVAL_TO_OBJECT(v), - JSVAL_IS_NULL(v) - ? "null" - : JSVAL_TO_OBJECT(v)->getClass()->name); + "object<%p:%s> ", (void*)*(JSObject **)slot, + v.toObject().getClass()->name); + return; + } + + case JSVAL_TYPE_INT32: + JS_ASSERT(v.isInt32() || (v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), &_))); + debug_only_printf(LC_TMTracer, "int<%d> ", *(jsint *)slot); return; - case TT_INT32: - jsint i; - if (JSVAL_IS_INT(v)) - *(jsint*)slot = JSVAL_TO_INT(v); - else if (tag == JSVAL_DOUBLE && JSDOUBLE_IS_INT(*JSVAL_TO_DOUBLE(v), i)) - *(jsint*)slot = i; - else - JS_ASSERT(JSVAL_IS_INT(v)); - debug_only_printf(LC_TMTracer, "int<%d> ", *(jsint*)slot); + case JSVAL_TYPE_DOUBLE: + JS_ASSERT(v.isNumber()); + debug_only_printf(LC_TMTracer, "double<%g> ", *(jsdouble *)slot); return; - case TT_DOUBLE: - jsdouble d; - if (JSVAL_IS_INT(v)) - d = JSVAL_TO_INT(v); - else - d = *JSVAL_TO_DOUBLE(v); - JS_ASSERT(JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v)); - *(jsdouble*)slot = d; - debug_only_printf(LC_TMTracer, "double<%g> ", d); - return; - - case TT_JSVAL: + case JSVAL_TYPE_BOXED: JS_NOT_REACHED("found jsval type in an entry type map"); return; - case TT_STRING: - JS_ASSERT(tag == JSVAL_STRING); - *(JSString**)slot = JSVAL_TO_STRING(v); - debug_only_printf(LC_TMTracer, "string<%p> ", (void*)(*(JSString**)slot)); + case JSVAL_TYPE_STRING: + JS_ASSERT(v.isString()); + debug_only_printf(LC_TMTracer, "string<%p> ", (void*)*(JSString**)slot); return; - case TT_NULL: - JS_ASSERT(tag == JSVAL_OBJECT); - *(JSObject**)slot = NULL; + case JSVAL_TYPE_NULL: + JS_ASSERT(v.isNull()); debug_only_print0(LC_TMTracer, "null "); return; - case TT_SPECIAL: - JS_ASSERT(tag == JSVAL_SPECIAL); - *(JSBool*)slot = JSVAL_TO_SPECIAL(v); + case JSVAL_TYPE_BOOLEAN: + JS_ASSERT(v.isBoolean()); debug_only_printf(LC_TMTracer, "special<%d> ", *(JSBool*)slot); return; - case TT_VOID: - JS_ASSERT(JSVAL_IS_VOID(v)); - *(JSBool*)slot = JSVAL_TO_SPECIAL(JSVAL_VOID); + case JSVAL_TYPE_UNDEFINED: + JS_ASSERT(v.isUndefined()); debug_only_print0(LC_TMTracer, "undefined "); return; - case TT_MAGIC: - JS_ASSERT(JSVAL_IS_HOLE(v)); - *(JSBool*)slot = JSVAL_TO_SPECIAL(JSVAL_HOLE); + case JSVAL_TYPE_MAGIC: + JS_ASSERT(v.isMagic()); debug_only_print0(LC_TMTracer, "hole "); return; - case TT_FUNCTION: { - JS_ASSERT(tag == JSVAL_OBJECT); - JSObject* obj = JSVAL_TO_OBJECT(v); - *(JSObject**)slot = obj; -#ifdef DEBUG - JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj); + case JSVAL_TYPE_FUNOBJ: { + JS_ASSERT(IsFunctionObject(v)); + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &v.toObject()); debug_only_printf(LC_TMTracer, - "function<%p:%s> ", (void*) obj, + "function<%p:%s> ", (void*)*(JSObject **)slot, fun->atom ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom)) : "unnamed"); -#endif return; } default: JS_NOT_REACHED("unexpected type"); break; } +#endif } void @@ -2699,12 +2749,13 @@ TraceMonitor::flush() static inline void MarkTree(JSTracer* trc, TreeFragment *f) { - jsval* vp = f->gcthings.data(); + Value* vp = f->gcthings.data(); unsigned len = f->gcthings.length(); while (len--) { - jsval v = *vp++; + Value &v = *vp++; JS_SET_TRACING_NAME(trc, "jitgcthing"); - js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v)); + JS_ASSERT(v.isMarkable()); + Mark(trc, v.asGCThing(), v.gcKind()); } JSScopeProperty** spropp = f->sprops.data(); len = f->sprops.length(); @@ -2738,110 +2789,98 @@ TraceMonitor::mark(JSTracer* trc) } /* - * Box a value from the native stack back into the jsval format. Integers that - * are too large to fit into a jsval are automatically boxed into - * heap-allocated doubles. + * Box a value from the native stack back into the Value format. */ -bool -NativeToValue(JSContext* cx, jsval& v, TraceType type, double* slot) +static inline void +NativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot) { - JSBool ok; - jsint i; - jsdouble d; + if (type == JSVAL_TYPE_DOUBLE) { + v.setNumber(*slot); + } else if (JS_LIKELY(type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET)) { + v.boxNonDoubleFrom(type, (uint64 *)slot); + } else if (type == JSVAL_TYPE_STRORNULL) { + JSString *str = *(JSString **)slot; + v = str ? StringValue(str) : NullValue(); + } else if (type == JSVAL_TYPE_OBJORNULL) { + JSObject *obj = *(JSObject **)slot; + v = obj ? ObjectValue(*obj) : NullValue(); + } else { + JS_ASSERT(type == JSVAL_TYPE_BOXED); + JS_STATIC_ASSERT(sizeof(Value) == sizeof(double)); + v = *(Value *)slot; + } + +#ifdef DEBUG switch (type) { - case TT_OBJECT: - v = OBJECT_TO_JSVAL(*(JSObject**)slot); + case JSVAL_TYPE_NONFUNOBJ: + JS_ASSERT(!IsFunctionObject(v)); debug_only_printf(LC_TMTracer, - "object<%p:%s> ", (void*)JSVAL_TO_OBJECT(v), - JSVAL_IS_NULL(v) - ? "null" - : JSVAL_TO_OBJECT(v)->getClass()->name); + "object<%p:%s> ", + (void*) &v.toObject(), + v.toObject().getClass()->name); break; - - case TT_INT32: - i = *(jsint*)slot; - debug_only_printf(LC_TMTracer, "int<%d> ", i); - store_int: - if (INT_FITS_IN_JSVAL(i)) { - v = INT_TO_JSVAL(i); - break; - } - d = (jsdouble)i; - goto store_double; - case TT_DOUBLE: - d = *slot; - debug_only_printf(LC_TMTracer, "double<%g> ", d); - if (JSDOUBLE_IS_INT(d, i)) - goto store_int; - store_double: - ok = js_NewDoubleInRootedValue(cx, d, &v); - if (!ok) { - js_ReportOutOfMemory(cx); - return false; - } - return true; - - case TT_JSVAL: - v = *(jsval*)slot; - debug_only_printf(LC_TMTracer, "box<%p> ", (void*)v); + case JSVAL_TYPE_INT32: + debug_only_printf(LC_TMTracer, "int<%d> ", v.toInt32()); break; - - case TT_STRING: - v = STRING_TO_JSVAL(*(JSString**)slot); - debug_only_printf(LC_TMTracer, "string<%p> ", (void*)(*(JSString**)slot)); + case JSVAL_TYPE_DOUBLE: + debug_only_printf(LC_TMTracer, "double<%g> ", v.toNumber()); break; - - case TT_NULL: - JS_ASSERT(*(JSObject**)slot == NULL); - v = JSVAL_NULL; - debug_only_printf(LC_TMTracer, "null<%p> ", (void*)(*(JSObject**)slot)); + case JSVAL_TYPE_STRING: + debug_only_printf(LC_TMTracer, "string<%p> ", (void*)v.toString()); break; - - case TT_SPECIAL: - JS_ASSERT(*(JSBool*)slot != JSVAL_TO_SPECIAL(JSVAL_VOID)); - v = SPECIAL_TO_JSVAL(*(JSBool*)slot); - debug_only_printf(LC_TMTracer, "special<%d> ", *(JSBool*)slot); + case JSVAL_TYPE_NULL: + debug_only_print0(LC_TMTracer, "null "); break; - - case TT_VOID: - v = JSVAL_VOID; + case JSVAL_TYPE_BOOLEAN: + debug_only_printf(LC_TMTracer, "bool<%d> ", v.toBoolean()); + break; + case JSVAL_TYPE_UNDEFINED: debug_only_print0(LC_TMTracer, "undefined "); break; - - case TT_MAGIC: - v = JSVAL_HOLE; - debug_only_print0(LC_TMTracer, "hole "); + case JSVAL_TYPE_MAGIC: + debug_only_printf(LC_TMTracer, "magic<%d> ", v.whyMagic()); break; - - case TT_FUNCTION: { - JS_ASSERT((*(JSObject**)slot)->isFunction()); - v = OBJECT_TO_JSVAL(*(JSObject**)slot); -#ifdef DEBUG - JSFunction* fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(v)); + case JSVAL_TYPE_FUNOBJ: { + JS_ASSERT(IsFunctionObject(v)); + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &v.toObject()); debug_only_printf(LC_TMTracer, - "function<%p:%s> ", (void*)JSVAL_TO_OBJECT(v), + "function<%p:%s> ", (void*) &v.toObject(), fun->atom ? JS_GetStringBytes(ATOM_TO_STRING(fun->atom)) : "unnamed"); -#endif break; } + case JSVAL_TYPE_STRORNULL: + debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)v.toString()); + break; + case JSVAL_TYPE_OBJORNULL: + debug_only_printf(LC_TMTracer, "nullablestr<%p> ", v.isNull() ? NULL : (void *)&v.toObject()); + break; + case JSVAL_TYPE_BOXED: + debug_only_printf(LC_TMTracer, "box<%llx> ", v.asRawBits()); + break; default: JS_NOT_REACHED("unexpected type"); break; } - return true; +#endif +} + +void +ExternNativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot) +{ + return NativeToValue(cx, v, type, slot); } class BuildNativeFrameVisitor : public SlotVisitorBase { JSContext *mCx; - TraceType *mTypeMap; + JSValueType *mTypeMap; double *mGlobal; double *mStack; public: BuildNativeFrameVisitor(JSContext *cx, - TraceType *typemap, + JSValueType *typemap, double *global, double *stack) : mCx(cx), @@ -2851,25 +2890,46 @@ public: {} JS_REQUIRES_STACK JS_ALWAYS_INLINE void - visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { debug_only_printf(LC_TMTracer, "global%d: ", n); - ValueToNative(mCx, *vp, *mTypeMap++, &mGlobal[slot]); + ValueToNative(*vp, *mTypeMap++, &mGlobal[slot]); } JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, int count, JSStackFrame* fp) { + visitStackSlots(Value *vp, int count, JSStackFrame* fp) { for (int i = 0; i < count; ++i) { debug_only_printf(LC_TMTracer, "%s%d: ", stackSlotKind(), i); - ValueToNative(mCx, *vp++, *mTypeMap++, mStack++); + ValueToNative(*vp++, *mTypeMap++, mStack++); } return true; } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame* fp) { + debug_only_printf(LC_TMTracer, "%s%d: ", stackSlotKind(), 0); + *(JSObject **)mStack = *p; +#ifdef DEBUG + if (*mTypeMap == JSVAL_TYPE_NULL) { + JS_ASSERT(*p == NULL); + debug_only_print0(LC_TMTracer, "null "); + } else { + JS_ASSERT(*mTypeMap == JSVAL_TYPE_NONFUNOBJ); + JS_ASSERT(!(*p)->isFunction()); + debug_only_printf(LC_TMTracer, + "object<%p:%s> ", (void*)*p, + (*p)->getClass()->name); + } +#endif + mTypeMap++; + mStack++; + return true; + } }; static JS_REQUIRES_STACK void BuildNativeFrame(JSContext *cx, JSObject *globalObj, unsigned callDepth, unsigned ngslots, uint16 *gslots, - TraceType *typeMap, double *global, double *stack) + JSValueType *typeMap, double *global, double *stack) { BuildNativeFrameVisitor visitor(cx, typeMap, global, stack); VisitSlots(visitor, cx, globalObj, callDepth, ngslots, gslots); @@ -2879,11 +2939,11 @@ BuildNativeFrame(JSContext *cx, JSObject *globalObj, unsigned callDepth, class FlushNativeGlobalFrameVisitor : public SlotVisitorBase { JSContext *mCx; - TraceType *mTypeMap; + JSValueType *mTypeMap; double *mGlobal; public: FlushNativeGlobalFrameVisitor(JSContext *cx, - TraceType *typeMap, + JSValueType *typeMap, double *global) : mCx(cx), mTypeMap(typeMap), @@ -2891,27 +2951,26 @@ public: {} JS_REQUIRES_STACK JS_ALWAYS_INLINE void - visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { debug_only_printf(LC_TMTracer, "global%d=", n); JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota); - if (!NativeToValue(mCx, *vp, *mTypeMap++, &mGlobal[slot])) - OutOfMemoryAbort(); + NativeToValue(mCx, *vp, *mTypeMap++, &mGlobal[slot]); } }; class FlushNativeStackFrameVisitor : public SlotVisitorBase { JSContext *mCx; - const TraceType *mInitTypeMap; - const TraceType *mTypeMap; + const JSValueType *mInitTypeMap; + const JSValueType *mTypeMap; double *mStack; - jsval *mStop; + Value *mStop; unsigned mIgnoreSlots; public: FlushNativeStackFrameVisitor(JSContext *cx, - const TraceType *typeMap, + const JSValueType *typeMap, double *stack, - jsval *stop, + Value *stop, unsigned ignoreSlots) : mCx(cx), mInitTypeMap(typeMap), @@ -2921,34 +2980,59 @@ public: mIgnoreSlots(ignoreSlots) {} - const TraceType* getTypeMap() + const JSValueType* getTypeMap() { return mTypeMap; } JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) { + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota); for (size_t i = 0; i < count; ++i) { if (vp == mStop) return false; debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), unsigned(i)); - if (unsigned(mTypeMap - mInitTypeMap) >= mIgnoreSlots) { - if (!NativeToValue(mCx, *vp, *mTypeMap, mStack)) - OutOfMemoryAbort(); - } + if (unsigned(mTypeMap - mInitTypeMap) >= mIgnoreSlots) + NativeToValue(mCx, *vp, *mTypeMap, mStack); vp++; mTypeMap++; mStack++; } return true; } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame* fp) { + JS_ASSERT(JS_THREAD_DATA(mCx)->waiveGCQuota); + if ((Value *)p == mStop) + return false; + debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), 0); + if (unsigned(mTypeMap - mInitTypeMap) >= mIgnoreSlots) { + *p = *(JSObject **)mStack; +#ifdef DEBUG + JSValueType type = *mTypeMap; + if (type == JSVAL_TYPE_NULL) { + debug_only_print0(LC_TMTracer, "null "); + } else { + JS_ASSERT(type == JSVAL_TYPE_NONFUNOBJ); + JS_ASSERT(!(*p)->isFunction()); + debug_only_printf(LC_TMTracer, + "object<%p:%s> ", + (void*) *p, + (*p)->getClass()->name); + } +#endif + } + mTypeMap++; + mStack++; + return true; + } }; /* Box the given native frame into a JS frame. This is infallible. */ static JS_REQUIRES_STACK void FlushNativeGlobalFrame(JSContext *cx, JSObject *globalObj, double *global, unsigned ngslots, - uint16 *gslots, TraceType *typemap) + uint16 *gslots, JSValueType *typemap) { FlushNativeGlobalFrameVisitor visitor(cx, typemap, global); VisitGlobalSlots(visitor, cx, globalObj, ngslots, gslots); @@ -2983,7 +3067,7 @@ StackDepthFromCallStack(TracerState* state, uint32 callDepth) * callDepth Call depth of current point relative to trace entry */ template -inline TraceType +inline JSValueType GetUpvarOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth, double* result) { TracerState* state = cx->tracerState; @@ -3036,15 +3120,15 @@ GetUpvarOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDepth, */ JS_ASSERT(upvarLevel < JS_DISPLAY_SIZE); JSStackFrame* fp = cx->display[upvarLevel]; - jsval v = T::interp_get(fp, slot); - TraceType type = getCoercedType(v); - ValueToNative(cx, v, type, result); + Value v = T::interp_get(fp, slot); + JSValueType type = getCoercedType(v); + ValueToNative(v, type, result); return type; } // For this traits type, 'slot' is the argument index, which may be -2 for callee. struct UpvarArgTraits { - static jsval interp_get(JSStackFrame* fp, int32 slot) { + static Value interp_get(JSStackFrame* fp, int32 slot) { return fp->argv[slot]; } @@ -3061,7 +3145,7 @@ GetUpvarArgOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDept // For this traits type, 'slot' is an index into the local slots array. struct UpvarVarTraits { - static jsval interp_get(JSStackFrame* fp, int32 slot) { + static Value interp_get(JSStackFrame* fp, int32 slot) { return fp->slots()[slot]; } @@ -3082,7 +3166,7 @@ GetUpvarVarOnTrace(JSContext* cx, uint32 upvarLevel, int32 slot, uint32 callDept * the only one that can have no function.) */ struct UpvarStackTraits { - static jsval interp_get(JSStackFrame* fp, int32 slot) { + static Value interp_get(JSStackFrame* fp, int32 slot) { return fp->slots()[slot + fp->script->nfixed]; } @@ -3162,7 +3246,7 @@ GetFromClosure(JSContext* cx, JSObject* call, const ClosureVarInfo* cv, double* } JSStackFrame* fp = (JSStackFrame*) call->getPrivate(); - jsval v; + Value v; if (fp) { v = T::slots(fp)[slot]; } else { @@ -3176,8 +3260,8 @@ GetFromClosure(JSContext* cx, JSObject* call, const ClosureVarInfo* cv, double* JS_ASSERT(slot < T::slot_count(call)); v = T::slots(call)[slot]; } - TraceType type = getCoercedType(v); - ValueToNative(cx, v, type, result); + JSValueType type = getCoercedType(v); + ValueToNative(v, type, result); return type; } @@ -3194,10 +3278,10 @@ struct ArgClosureTraits // Get the right frame slots to use our slot index with. // See also UpvarArgTraits. - static inline jsval* slots(JSStackFrame* fp) { return fp->argv; } + static inline Value* slots(JSStackFrame* fp) { return fp->argv; } // Get the right object slots to use our slot index with. - static inline jsval* slots(JSObject* obj) { + static inline Value* slots(JSObject* obj) { // We know Call objects use dslots. return obj->dslots + slot_offset(obj); } @@ -3233,8 +3317,8 @@ struct VarClosureTraits } // See also UpvarVarTraits. - static inline jsval* slots(JSStackFrame* fp) { return fp->slots(); } - static inline jsval* slots(JSObject* obj) { + static inline Value* slots(JSStackFrame* fp) { return fp->slots(); } + static inline Value* slots(JSObject* obj) { // We know Call objects use dslots. return obj->dslots + slot_offset(obj); } @@ -3263,7 +3347,7 @@ GetClosureVar(JSContext* cx, JSObject* callee, const ClosureVarInfo* cv, double* * @param callDepth the distance between the entry frame into our trace and * cx->fp when we make this call. If this is not called as a * result of a nested exit, callDepth is 0. - * @param mp an array of TraceType that indicate what the types of the things + * @param mp an array of JSValueType that indicate what the types of the things * on the stack are. * @param np pointer to the native stack. We want to copy values from here to * the JS stack as needed. @@ -3272,10 +3356,10 @@ GetClosureVar(JSContext* cx, JSObject* callee, const ClosureVarInfo* cv, double* * @return the number of things we popped off of np. */ static JS_REQUIRES_STACK int -FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const TraceType* mp, double* np, +FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const JSValueType* mp, double* np, JSStackFrame* stopFrame, unsigned ignoreSlots) { - jsval* stopAt = stopFrame ? &stopFrame->argv[-2] : NULL; + Value* stopAt = stopFrame ? &stopFrame->argv[-2] : NULL; /* Root all string and object references first (we don't need to call the GC for this). */ FlushNativeStackFrameVisitor visitor(cx, mp, np, stopAt, ignoreSlots); @@ -3301,11 +3385,11 @@ FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const TraceType* mp, do for (; n != 0; fp = fp->down) { --n; if (fp->argv) { - if (fp->argsobj && GetArgsPrivateNative(JSVAL_TO_OBJECT(fp->argsobj))) - JSVAL_TO_OBJECT(fp->argsobj)->setPrivate(fp); + if (fp->argsobj && GetArgsPrivateNative(fp->argsobj)) + fp->argsobj->setPrivate(fp); - JS_ASSERT(JSVAL_IS_OBJECT(fp->argv[-1])); - JS_ASSERT(fp->calleeObject()->isFunction()); + JS_ASSERT(fp->argv[-1].isObjectOrNull()); + JS_ASSERT(fp->callee()->isFunction()); JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee()) == fp->fun); if (FUN_INTERPRETED(fp->fun) && @@ -3335,13 +3419,13 @@ FlushNativeStackFrame(JSContext* cx, unsigned callDepth, const TraceType* mp, do /* Emit load instructions onto the trace that read the initial stack state. */ JS_REQUIRES_STACK void -TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, TraceType t, - const char *prefix, uintN index, JSStackFrame *fp) +TraceRecorder::importImpl(LIns* base, ptrdiff_t offset, const void* p, JSValueType t, + const char *prefix, uintN index, JSStackFrame *fp) { LIns* ins; AccSet accSet = base == lirbuf->sp ? ACC_STACK : ACC_OTHER; - if (t == TT_INT32) { /* demoted */ - JS_ASSERT(isInt32(*p)); + if (t == JSVAL_TYPE_INT32) { /* demoted */ + JS_ASSERT(hasInt32Repr(*(const Value *)p)); /* * Ok, we have a valid demotion attempt pending, so insert an integer @@ -3349,20 +3433,21 @@ TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, TraceType t, * to see doubles on entry. The first op to use this slot will emit a * d2i cast which will cancel out the i2d we insert here. */ - ins = lir->insLoad(LIR_ldi, base, offset, accSet); + ins = lir->insLoad(LIR_ldi, base, offset + sPayloadOffset, accSet); ins = lir->ins1(LIR_i2d, ins); } else { - JS_ASSERT_IF(t != TT_JSVAL, isNumber(*p) == (t == TT_DOUBLE)); - if (t == TT_DOUBLE) { + JS_ASSERT_IF(t != JSVAL_TYPE_BOXED && !IsFrameObjPtrTraceType(t), + ((const Value *)p)->isNumber() == (t == JSVAL_TYPE_DOUBLE)); + if (t == JSVAL_TYPE_DOUBLE) { ins = lir->insLoad(LIR_ldd, base, offset, accSet); - } else if (t == TT_SPECIAL) { - ins = lir->insLoad(LIR_ldi, base, offset, accSet); - } else if (t == TT_VOID) { - ins = INS_VOID(); - } else if (t == TT_MAGIC) { - ins = INS_HOLE(); + } else if (t == JSVAL_TYPE_BOOLEAN) { + ins = lir->insLoad(LIR_ldi, base, offset + sPayloadOffset, accSet); + } else if (t == JSVAL_TYPE_UNDEFINED) { + ins = INS_UNDEFINED(); + } else if (t == JSVAL_TYPE_MAGIC) { + ins = lir->insLoad(LIR_ldi, base, offset + sPayloadOffset, accSet); } else { - ins = lir->insLoad(LIR_ldp, base, offset, accSet); + ins = lir->insLoad(LIR_ldp, base, offset + sPayloadOffset, accSet); } } checkForGlobalObjectReallocation(); @@ -3398,26 +3483,30 @@ TraceRecorder::import(LIns* base, ptrdiff_t offset, jsval* p, TraceType t, JS_ARENA_RELEASE(&cx->tempPool, mark); addName(ins, name); - static const char* typestr[] = { - "object", "int", "double", "jsval", "string", "null", "boolean", "function" - }; - debug_only_printf(LC_TMTracer, "import vp=%p name=%s type=%s flags=%d\n", - (void*)p, name, typestr[t & 7], t >> 3); + debug_only_printf(LC_TMTracer, "import vp=%p name=%s type=%c\n", + p, name, TypeToChar(t)); #endif } +JS_REQUIRES_STACK void +TraceRecorder::import(LIns* base, ptrdiff_t offset, const Value* p, JSValueType t, + const char *prefix, uintN index, JSStackFrame *fp) +{ + return importImpl(base, offset, p, t, prefix, index, fp); +} + class ImportBoxedStackSlotVisitor : public SlotVisitorBase { TraceRecorder &mRecorder; LIns *mBase; ptrdiff_t mStackOffset; - TraceType *mTypemap; + JSValueType *mTypemap; JSStackFrame *mFp; public: ImportBoxedStackSlotVisitor(TraceRecorder &recorder, LIns *base, ptrdiff_t stackOffset, - TraceType *typemap) : + JSValueType *typemap) : mRecorder(recorder), mBase(base), mStackOffset(stackOffset), @@ -3425,12 +3514,12 @@ public: {} JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) { + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { for (size_t i = 0; i < count; ++i) { - if (*mTypemap == TT_JSVAL) { - mRecorder.import(mBase, mStackOffset, vp, TT_JSVAL, + if (*mTypemap == JSVAL_TYPE_BOXED) { + mRecorder.import(mBase, mStackOffset, vp, JSVAL_TYPE_BOXED, "jsval", i, fp); - LIns *vp_ins = mRecorder.unbox_jsval(*vp, mRecorder.get(vp), + LIns *vp_ins = mRecorder.unbox_value(*vp, mBase, mStackOffset, mRecorder.copy(mRecorder.anchor)); mRecorder.set(vp, vp_ins); } @@ -3440,11 +3529,19 @@ public: } return true; } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame *fp) { + JS_ASSERT(*mTypemap != JSVAL_TYPE_BOXED); + mTypemap++; + mStackOffset += sizeof(double); + return true; + } }; JS_REQUIRES_STACK void TraceRecorder::import(TreeFragment* tree, LIns* sp, unsigned stackSlots, unsigned ngslots, - unsigned callDepth, TraceType* typeMap) + unsigned callDepth, JSValueType* typeMap) { /* * If we get a partial list that doesn't have all the types (i.e. recording @@ -3461,7 +3558,7 @@ TraceRecorder::import(TreeFragment* tree, LIns* sp, unsigned stackSlots, unsigne * this is always safe to do. */ - TraceType* globalTypeMap = typeMap + stackSlots; + JSValueType* globalTypeMap = typeMap + stackSlots; unsigned length = tree->nGlobalTypes(); /* @@ -3471,7 +3568,7 @@ TraceRecorder::import(TreeFragment* tree, LIns* sp, unsigned stackSlots, unsigne if (ngslots < length) { MergeTypeMaps(&globalTypeMap /* out param */, &ngslots /* out param */, tree->globalTypeMap(), length, - (TraceType*)alloca(sizeof(TraceType) * length)); + (JSValueType*)alloca(sizeof(JSValueType) * length)); } JS_ASSERT(ngslots == tree->nGlobalTypes()); @@ -3525,16 +3622,16 @@ TraceRecorder::importGlobalSlot(unsigned slot) JS_ASSERT(slot == uint16(slot)); JS_ASSERT(globalObj->numSlots() <= MAX_GLOBAL_SLOTS); - jsval* vp = &globalObj->getSlotRef(slot); + Value* vp = &globalObj->getSlotRef(slot); JS_ASSERT(!known(vp)); /* Add the slot to the list of interned global slots. */ - TraceType type; + JSValueType type; int index = tree->globalSlots->offsetOf(uint16(slot)); if (index == -1) { type = getCoercedType(*vp); - if (type == TT_INT32 && (!oracle || oracle->isGlobalSlotUndemotable(cx, slot))) - type = TT_DOUBLE; + if (type == JSVAL_TYPE_INT32 && (!oracle || oracle->isGlobalSlotUndemotable(cx, slot))) + type = JSVAL_TYPE_DOUBLE; index = (int)tree->globalSlots->length(); tree->globalSlots->add(uint16(slot)); tree->typeMap.add(type); @@ -3542,7 +3639,7 @@ TraceRecorder::importGlobalSlot(unsigned slot) JS_ASSERT(tree->nGlobalTypes() == tree->globalSlots->length()); } else { type = importTypeMap[importStackSlots + index]; - JS_ASSERT(type != TT_IGNORE); + JS_ASSERT(type != JSVAL_TYPE_UNINITIALIZED); } import(eos_ins, slot * sizeof(double), vp, type, "global", index, NULL); } @@ -3559,7 +3656,7 @@ TraceRecorder::lazilyImportGlobalSlot(unsigned slot) */ if (globalObj->numSlots() > MAX_GLOBAL_SLOTS) return false; - jsval* vp = &globalObj->getSlotRef(slot); + Value* vp = &globalObj->getSlotRef(slot); if (known(vp)) return true; /* we already have it */ importGlobalSlot(slot); @@ -3582,7 +3679,7 @@ TraceRecorder::writeBack(LIns* i, LIns* base, ptrdiff_t offset, bool shouldDemot /* Update the tracker, then issue a write back store. */ JS_REQUIRES_STACK void -TraceRecorder::set(jsval* p, LIns* i, bool demote) +TraceRecorder::setImpl(void* p, LIns* i, bool demote) { JS_ASSERT(i != NULL); checkForGlobalObjectReallocation(); @@ -3596,10 +3693,10 @@ TraceRecorder::set(jsval* p, LIns* i, bool demote) */ LIns* x = nativeFrameTracker.get(p); if (!x) { - if (isGlobal(p)) - x = writeBack(i, eos_ins, nativeGlobalOffset(p), demote); + if (isVoidPtrGlobal(p)) + x = writeBack(i, eos_ins, nativeGlobalOffset((Value *)p), demote); else - x = writeBack(i, lirbuf->sp, nativespOffset(p), demote); + x = writeBack(i, lirbuf->sp, nativespOffsetImpl(p), demote); nativeFrameTracker.set(p, x); } else { #if defined NANOJIT_64BIT @@ -3620,15 +3717,28 @@ TraceRecorder::set(jsval* p, LIns* i, bool demote) JS_ASSERT(base == lirbuf->sp || base == eos_ins); JS_ASSERT(disp == ((base == lirbuf->sp) - ? nativespOffset(p) - : nativeGlobalOffset(p))); + ? nativespOffsetImpl(p) + : nativeGlobalOffset((Value *)p))); writeBack(i, base, disp, demote); } } +JS_REQUIRES_STACK inline void +TraceRecorder::set(Value* p, LIns* i, bool demote) +{ + return setImpl(p, i, demote); +} + +JS_REQUIRES_STACK void +TraceRecorder::setFrameObjPtr(JSObject** p, LIns* i, bool demote) +{ + JS_ASSERT(isValidFrameObjPtr(p)); + return setImpl(p, i, demote); +} + JS_REQUIRES_STACK LIns* -TraceRecorder::attemptImport(jsval* p) +TraceRecorder::attemptImport(const Value* p) { if (LIns* i = getFromTracker(p)) return i; @@ -3643,36 +3753,68 @@ TraceRecorder::attemptImport(jsval* p) return NULL; } -nanojit::LIns* -TraceRecorder::getFromTracker(jsval* p) +inline nanojit::LIns* +TraceRecorder::getFromTrackerImpl(const void* p) { checkForGlobalObjectReallocation(); return tracker.get(p); } -JS_REQUIRES_STACK LIns* -TraceRecorder::get(jsval* p) +inline nanojit::LIns* +TraceRecorder::getFromTracker(const Value* p) { - LIns* x = getFromTracker(p); + return getFromTrackerImpl(p); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::getImpl(const void *p) +{ + LIns* x = getFromTrackerImpl(p); if (x) return x; - if (isGlobal(p)) { - unsigned slot = nativeGlobalSlot(p); + if (isVoidPtrGlobal(p)) { + unsigned slot = nativeGlobalSlot((const Value *)p); JS_ASSERT(tree->globalSlots->offsetOf(uint16(slot)) != -1); importGlobalSlot(slot); } else { - unsigned slot = nativeStackSlot(p); - TraceType type = importTypeMap[slot]; - JS_ASSERT(type != TT_IGNORE); - import(lirbuf->sp, -tree->nativeStackBase + slot * sizeof(jsdouble), - p, type, "stack", slot, cx->fp); + unsigned slot = nativeStackSlotImpl(p); + JSValueType type = importTypeMap[slot]; + JS_ASSERT(type != JSVAL_TYPE_UNINITIALIZED); + importImpl(lirbuf->sp, -tree->nativeStackBase + slot * sizeof(jsdouble), + p, type, "stack", slot, cx->fp); } - JS_ASSERT(known(p)); + JS_ASSERT(knownImpl(p)); return tracker.get(p); } JS_REQUIRES_STACK LIns* -TraceRecorder::addr(jsval* p) +TraceRecorder::get(const Value *p) +{ + return getImpl(p); +} + +#ifdef DEBUG +bool +TraceRecorder::isValidFrameObjPtr(JSObject **p) +{ + JSStackFrame *fp = cx->fp; + for (; fp; fp = fp->down) { + if (&fp->scopeChain == p || &fp->argsobj == p) + return true; + } + return false; +} +#endif + +JS_REQUIRES_STACK LIns* +TraceRecorder::getFrameObjPtr(JSObject **p) +{ + JS_ASSERT(isValidFrameObjPtr(p)); + return getImpl(p); +} + +JS_REQUIRES_STACK LIns* +TraceRecorder::addr(Value* p) { return isGlobal(p) ? lir->ins2(LIR_addp, eos_ins, INS_CONSTWORD(nativeGlobalOffset(p))) @@ -3680,13 +3822,25 @@ TraceRecorder::addr(jsval* p) INS_CONSTWORD(nativespOffset(p))); } -JS_REQUIRES_STACK bool -TraceRecorder::known(jsval* p) +JS_REQUIRES_STACK inline bool +TraceRecorder::knownImpl(const void* p) { checkForGlobalObjectReallocation(); return tracker.has(p); } +JS_REQUIRES_STACK inline bool +TraceRecorder::known(const Value* vp) +{ + return knownImpl(vp); +} + +JS_REQUIRES_STACK inline bool +TraceRecorder::known(JSObject** p) +{ + return knownImpl(p); +} + /* * The dslots of the global object are sometimes reallocated by the interpreter. * This function check for that condition and re-maps the entries of the tracker @@ -3698,9 +3852,9 @@ TraceRecorder::checkForGlobalObjectReallocation() if (global_dslots != globalObj->dslots) { debug_only_print0(LC_TMTracer, "globalObj->dslots relocated, updating tracker\n"); - jsval* src = global_dslots; - jsval* dst = globalObj->dslots; - jsuint length = globalObj->dslots[-1] - JS_INITIAL_NSLOTS; + Value* src = global_dslots; + Value* dst = globalObj->dslots; + jsuint length = globalObj->dslots[-1].toPrivateUint32() - JS_INITIAL_NSLOTS; LIns** map = (LIns**)alloca(sizeof(LIns*) * length); for (jsuint n = 0; n < length; ++n) { map[n] = tracker.get(src); @@ -3736,10 +3890,10 @@ class AdjustCallerGlobalTypesVisitor : public SlotVisitorBase JSContext *mCx; nanojit::LirBuffer *mLirbuf; nanojit::LirWriter *mLir; - TraceType *mTypeMap; + JSValueType *mTypeMap; public: AdjustCallerGlobalTypesVisitor(TraceRecorder &recorder, - TraceType *typeMap) : + JSValueType *typeMap) : mRecorder(recorder), mCx(mRecorder.cx), mLirbuf(mRecorder.lirbuf), @@ -3747,16 +3901,16 @@ public: mTypeMap(typeMap) {} - TraceType* getTypeMap() + JSValueType* getTypeMap() { return mTypeMap; } JS_REQUIRES_STACK JS_ALWAYS_INLINE void - visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { LIns *ins = mRecorder.get(vp); bool isPromote = isPromoteInt(ins); - if (isPromote && *mTypeMap == TT_DOUBLE) { + if (isPromote && *mTypeMap == JSVAL_TYPE_DOUBLE) { mLir->insStore(mRecorder.get(vp), mRecorder.eos_ins, mRecorder.nativeGlobalOffset(vp), ACC_OTHER); @@ -3766,7 +3920,7 @@ public: */ JS_TRACE_MONITOR(mCx).oracle->markGlobalSlotUndemotable(mCx, slot); } - JS_ASSERT(!(!isPromote && *mTypeMap == TT_INT32)); + JS_ASSERT(!(!isPromote && *mTypeMap == JSVAL_TYPE_INT32)); ++mTypeMap; } }; @@ -3778,10 +3932,10 @@ class AdjustCallerStackTypesVisitor : public SlotVisitorBase nanojit::LirBuffer *mLirbuf; nanojit::LirWriter *mLir; unsigned mSlotnum; - TraceType *mTypeMap; + JSValueType *mTypeMap; public: AdjustCallerStackTypesVisitor(TraceRecorder &recorder, - TraceType *typeMap) : + JSValueType *typeMap) : mRecorder(recorder), mCx(mRecorder.cx), mLirbuf(mRecorder.lirbuf), @@ -3790,19 +3944,20 @@ public: mTypeMap(typeMap) {} - TraceType* getTypeMap() + JSValueType* getTypeMap() { return mTypeMap; } JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) { + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { + /* N.B. vp may actually point to a JSObject*. */ for (size_t i = 0; i < count; ++i) { LIns *ins = mRecorder.get(vp); bool isPromote = isPromoteInt(ins); - if (isPromote && *mTypeMap == TT_DOUBLE) { - mLir->insStore(mRecorder.get(vp), mLirbuf->sp, - mRecorder.nativespOffset(vp), ACC_STACK); + if (isPromote && *mTypeMap == JSVAL_TYPE_DOUBLE) { + mLir->insStore(ins, mLirbuf->sp, + mRecorder.nativespOffset(vp), ACC_STACK); /* * Aggressively undo speculation so the inner tree will compile @@ -3810,13 +3965,21 @@ public: */ JS_TRACE_MONITOR(mCx).oracle->markStackSlotUndemotable(mCx, mSlotnum); } - JS_ASSERT(!(!isPromote && *mTypeMap == TT_INT32)); + JS_ASSERT(!(!isPromote && *mTypeMap == JSVAL_TYPE_INT32)); ++vp; ++mTypeMap; ++mSlotnum; } return true; } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame* fp) { + JS_ASSERT(*mTypeMap != JSVAL_TYPE_BOXED); + ++mTypeMap; + ++mSlotnum; + return true; + } }; /* @@ -3836,69 +3999,61 @@ TraceRecorder::adjustCallerTypes(TreeFragment* f) JS_ASSERT(f == f->root); } -JS_REQUIRES_STACK TraceType -TraceRecorder::determineSlotType(jsval* vp) +JS_REQUIRES_STACK inline JSValueType +TraceRecorder::determineSlotType(Value* vp) { - TraceType m; - if (isNumber(*vp)) { - LIns* i = getFromTracker(vp); + if (vp->isNumber()) { + LIns *i = getFromTracker(vp); + JSValueType t; if (i) { - m = isPromoteInt(i) ? TT_INT32 : TT_DOUBLE; + t = isPromoteInt(i) ? JSVAL_TYPE_INT32 : JSVAL_TYPE_DOUBLE; } else if (isGlobal(vp)) { int offset = tree->globalSlots->offsetOf(uint16(nativeGlobalSlot(vp))); JS_ASSERT(offset != -1); - m = importTypeMap[importStackSlots + offset]; + t = importTypeMap[importStackSlots + offset]; } else { - m = importTypeMap[nativeStackSlot(vp)]; + t = importTypeMap[nativeStackSlot(vp)]; } - JS_ASSERT(m != TT_IGNORE); - } else if (JSVAL_IS_OBJECT(*vp)) { - if (JSVAL_IS_NULL(*vp)) - m = TT_NULL; - else if (JSVAL_TO_OBJECT(*vp)->isFunction()) - m = TT_FUNCTION; - else - m = TT_OBJECT; - } else if (JSVAL_IS_VOID(*vp)) { - /* N.B. void is JSVAL_SPECIAL. */ - m = TT_VOID; - } else if (JSVAL_IS_HOLE(*vp)) { - /* N.B. hole is JSVAL_SPECIAL. */ - m = TT_MAGIC; - } else { - JS_ASSERT(JSVAL_IS_STRING(*vp) || JSVAL_IS_SPECIAL(*vp)); - JS_STATIC_ASSERT(static_cast(TT_STRING) == JSVAL_STRING); - JS_STATIC_ASSERT(static_cast(TT_SPECIAL) == JSVAL_SPECIAL); - m = TraceType(JSVAL_TAG(*vp)); + JS_ASSERT(t != JSVAL_TYPE_UNINITIALIZED); + JS_ASSERT_IF(t == JSVAL_TYPE_INT32, hasInt32Repr(*vp)); + return t; } - JS_ASSERT(m != TT_INT32 || isInt32(*vp)); - return m; + + if (vp->isObject()) + return vp->toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return vp->extractNonDoubleObjectTraceType(); } class DetermineTypesVisitor : public SlotVisitorBase { TraceRecorder &mRecorder; - TraceType *mTypeMap; + JSValueType *mTypeMap; public: DetermineTypesVisitor(TraceRecorder &recorder, - TraceType *typeMap) : + JSValueType *typeMap) : mRecorder(recorder), mTypeMap(typeMap) {} JS_REQUIRES_STACK JS_ALWAYS_INLINE void - visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { *mTypeMap++ = mRecorder.determineSlotType(vp); } JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) { + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { for (size_t i = 0; i < count; ++i) *mTypeMap++ = mRecorder.determineSlotType(vp++); return true; } - TraceType* getTypeMap() + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame* fp) { + *mTypeMap++ = getFrameObjPtrTraceType(*p); + return true; + } + + JSValueType* getTypeMap() { return mTypeMap; } @@ -3914,10 +4069,10 @@ TreevisLogExit(JSContext* cx, VMSideExit* exit) js_FramePCToLineNumber(cx, cx->fp), FramePCOffset(cx, cx->fp)); debug_only_print0(LC_TMTreeVis, " STACK=\""); for (unsigned i = 0; i < exit->numStackSlots; i++) - debug_only_printf(LC_TMTreeVis, "%c", typeChar[exit->stackTypeMap()[i]]); + debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(exit->stackTypeMap()[i])); debug_only_print0(LC_TMTreeVis, "\" GLOBALS=\""); for (unsigned i = 0; i < exit->numGlobalSlots; i++) - debug_only_printf(LC_TMTreeVis, "%c", typeChar[exit->globalTypeMap()[i]]); + debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(exit->globalTypeMap()[i])); debug_only_print0(LC_TMTreeVis, "\"\n"); } #endif @@ -3964,10 +4119,10 @@ TraceRecorder::snapshot(ExitType exitType) /* Capture the type map into a temporary location. */ unsigned ngslots = tree->globalSlots->length(); - unsigned typemap_size = (stackSlots + ngslots) * sizeof(TraceType); + unsigned typemap_size = (stackSlots + ngslots) * sizeof(JSValueType); /* Use the recorder-local temporary type map. */ - TraceType* typemap = NULL; + JSValueType* typemap = NULL; if (tempTypeMap.resize(typemap_size)) typemap = tempTypeMap.begin(); /* crash if resize() fails. */ @@ -3984,10 +4139,10 @@ TraceRecorder::snapshot(ExitType exitType) ngslots + stackSlots); /* - * If this snapshot is for a side exit that leaves a boxed jsval result on + * If this snapshot is for a side exit that leaves a boxed Value result on * the stack, make a note of this in the typemap. Examples include the * builtinStatus guard after calling a _FAIL builtin, a JSFastNative, or - * GetPropertyByName; and the type guard in unbox_jsval after such a call + * GetPropertyByName; and the type guard in unbox_value after such a call * (also at the beginning of a trace branched from such a type guard). */ if (pendingUnboxSlot || @@ -3995,8 +4150,14 @@ TraceRecorder::snapshot(ExitType exitType) unsigned pos = stackSlots - 1; if (pendingUnboxSlot == cx->regs->sp - 2) pos = stackSlots - 2; - typemap[pos] = TT_JSVAL; - } + typemap[pos] = JSVAL_TYPE_BOXED; + } else if (pendingSpecializedNative && + (pendingSpecializedNative->flags & JSTN_RETURN_NULLABLE_STR)) { + typemap[stackSlots - 1] = JSVAL_TYPE_STRORNULL; + } else if (pendingSpecializedNative && + (pendingSpecializedNative->flags & JSTN_RETURN_NULLABLE_OBJ)) { + typemap[stackSlots - 1] = JSVAL_TYPE_OBJORNULL; + } /* Now restore the the original pc (after which early returns are ok). */ if (resumeAfter) { @@ -4037,7 +4198,7 @@ TraceRecorder::snapshot(ExitType exitType) /* We couldn't find a matching side exit, so create a new one. */ VMSideExit* exit = (VMSideExit*) - traceAlloc().alloc(sizeof(VMSideExit) + (stackSlots + ngslots) * sizeof(TraceType)); + traceAlloc().alloc(sizeof(VMSideExit) + (stackSlots + ngslots) * sizeof(JSValueType)); /* Setup side exit structure. */ exit->from = fragment; @@ -4050,7 +4211,7 @@ TraceRecorder::snapshot(ExitType exitType) exit->exitType = exitType; exit->block = fp->blockChain; if (fp->blockChain) - tree->gcthings.addUnique(OBJECT_TO_JSVAL(fp->blockChain)); + tree->gcthings.addUnique(ObjectValue(*fp->blockChain)); exit->pc = pc; exit->imacpc = fp->imacpc; exit->sp_adj = (stackSlots * sizeof(double)) - tree->nativeStackBase; @@ -4162,10 +4323,10 @@ TraceRecorder::copy(VMSideExit* copy) { size_t typemap_size = copy->numGlobalSlots + copy->numStackSlots; VMSideExit* exit = (VMSideExit*) - traceAlloc().alloc(sizeof(VMSideExit) + typemap_size * sizeof(TraceType)); + traceAlloc().alloc(sizeof(VMSideExit) + typemap_size * sizeof(JSValueType)); /* Copy side exit structure. */ - memcpy(exit, copy, sizeof(VMSideExit) + typemap_size * sizeof(TraceType)); + memcpy(exit, copy, sizeof(VMSideExit) + typemap_size * sizeof(JSValueType)); exit->guards = NULL; exit->from = fragment; exit->target = NULL; @@ -4329,16 +4490,19 @@ class SlotMap : public SlotVisitorBase SlotInfo() : vp(NULL), promoteInt(false), lastCheck(TypeCheck_Bad) {} - SlotInfo(jsval* vp, bool promoteInt) + SlotInfo(Value* vp, bool promoteInt) : vp(vp), promoteInt(promoteInt), lastCheck(TypeCheck_Bad), type(getCoercedType(*vp)) {} - SlotInfo(jsval* vp, TraceType t) - : vp(vp), promoteInt(t == TT_INT32), lastCheck(TypeCheck_Bad), type(t) + SlotInfo(JSObject** p) + : vp(vp), promoteInt(false), lastCheck(TypeCheck_Bad), type(getFrameObjPtrTraceType(*p)) {} - jsval *vp; + SlotInfo(Value* vp, JSValueType t) + : vp(vp), promoteInt(t == JSVAL_TYPE_INT32), lastCheck(TypeCheck_Bad), type(t) + {} + void *vp; bool promoteInt; TypeCheckResult lastCheck; - TraceType type; + JSValueType type; }; SlotMap(TraceRecorder& rec) @@ -4353,7 +4517,7 @@ class SlotMap : public SlotVisitorBase } JS_REQUIRES_STACK JS_ALWAYS_INLINE void - visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { addSlot(vp); } @@ -4407,33 +4571,39 @@ class SlotMap : public SlotVisitorBase } JS_REQUIRES_STACK JS_ALWAYS_INLINE void - addSlot(jsval* vp) + addSlot(Value* vp) { bool promoteInt = false; - if (isNumber(*vp)) { + if (vp->isNumber()) { if (LIns* i = mRecorder.getFromTracker(vp)) { promoteInt = isPromoteInt(i); } else if (mRecorder.isGlobal(vp)) { int offset = mRecorder.tree->globalSlots->offsetOf(uint16(mRecorder.nativeGlobalSlot(vp))); JS_ASSERT(offset != -1); promoteInt = mRecorder.importTypeMap[mRecorder.importStackSlots + offset] == - TT_INT32; + JSVAL_TYPE_INT32; } else { promoteInt = mRecorder.importTypeMap[mRecorder.nativeStackSlot(vp)] == - TT_INT32; + JSVAL_TYPE_INT32; } } slots.add(SlotInfo(vp, promoteInt)); } JS_REQUIRES_STACK JS_ALWAYS_INLINE void - addSlot(TraceType t) + addSlot(JSObject** p) + { + slots.add(SlotInfo(p)); + } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE void + addSlot(JSValueType t) { slots.add(SlotInfo(NULL, t)); } JS_REQUIRES_STACK JS_ALWAYS_INLINE void - addSlot(jsval *vp, TraceType t) + addSlot(Value *vp, JSValueType t) { slots.add(SlotInfo(vp, t)); } @@ -4465,7 +4635,7 @@ class SlotMap : public SlotVisitorBase JS_ASSERT(info.lastCheck != TypeCheck_Undemote && info.lastCheck != TypeCheck_Bad); #ifdef DEBUG if (info.lastCheck == TypeCheck_Promote) { - JS_ASSERT(info.type == TT_INT32 || info.type == TT_DOUBLE); + JS_ASSERT(info.type == JSVAL_TYPE_INT32 || info.type == JSVAL_TYPE_DOUBLE); /* * This should only happen if the slot has a trivial conversion, i.e. * isPromoteInt() is true. We check this. @@ -4476,42 +4646,42 @@ class SlotMap : public SlotVisitorBase * get() has side-effects, which is not good in an assertion. * Not checking unused slots isn't so bad. */ - LIns* ins = mRecorder.getFromTracker(info.vp); + LIns* ins = mRecorder.getFromTrackerImpl(info.vp); JS_ASSERT_IF(ins, isPromoteInt(ins)); } else #endif if (info.lastCheck == TypeCheck_Demote) { - JS_ASSERT(info.type == TT_INT32 || info.type == TT_DOUBLE); - JS_ASSERT(mRecorder.get(info.vp)->isD()); + JS_ASSERT(info.type == JSVAL_TYPE_INT32 || info.type == JSVAL_TYPE_DOUBLE); + JS_ASSERT(mRecorder.getImpl(info.vp)->isD()); /* Never demote this final i2d. */ - mRecorder.set(info.vp, mRecorder.get(info.vp), false); + mRecorder.setImpl(info.vp, mRecorder.getImpl(info.vp), false); } } private: TypeCheckResult - checkType(unsigned i, TraceType t) + checkType(unsigned i, JSValueType t) { debug_only_printf(LC_TMTracer, "checkType slot %d: interp=%c typemap=%c isNum=%d promoteInt=%d\n", i, - typeChar[slots[i].type], - typeChar[t], - slots[i].type == TT_INT32 || slots[i].type == TT_DOUBLE, + TypeToChar(slots[i].type), + TypeToChar(t), + slots[i].type == JSVAL_TYPE_INT32 || slots[i].type == JSVAL_TYPE_DOUBLE, slots[i].promoteInt); switch (t) { - case TT_INT32: - if (slots[i].type != TT_INT32 && slots[i].type != TT_DOUBLE) + case JSVAL_TYPE_INT32: + if (slots[i].type != JSVAL_TYPE_INT32 && slots[i].type != JSVAL_TYPE_DOUBLE) return TypeCheck_Bad; /* Not a number? Type mismatch. */ /* This is always a type mismatch, we can't close a double to an int. */ if (!slots[i].promoteInt) return TypeCheck_Undemote; /* Looks good, slot is an int32, the last instruction should be promotable. */ - JS_ASSERT_IF(slots[i].vp, isInt32(*slots[i].vp) && slots[i].promoteInt); + JS_ASSERT_IF(slots[i].vp, hasInt32Repr(*(const Value *)slots[i].vp) && slots[i].promoteInt); return slots[i].vp ? TypeCheck_Promote : TypeCheck_Okay; - case TT_DOUBLE: - if (slots[i].type != TT_INT32 && slots[i].type != TT_DOUBLE) + case JSVAL_TYPE_DOUBLE: + if (slots[i].type != JSVAL_TYPE_INT32 && slots[i].type != JSVAL_TYPE_DOUBLE) return TypeCheck_Bad; /* Not a number? Type mismatch. */ if (slots[i].promoteInt) return slots[i].vp ? TypeCheck_Demote : TypeCheck_Bad; @@ -4539,12 +4709,19 @@ class DefaultSlotMap : public SlotMap } JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { for (size_t i = 0; i < count; i++) addSlot(&vp[i]); return true; } + + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject** p, JSStackFrame* fp) + { + addSlot(p); + return true; + } }; JS_REQUIRES_STACK TypeConsensus @@ -4781,7 +4958,7 @@ TypeMapLinkability(JSContext* cx, const TypeMap& typeMap, TreeFragment* peer) for (unsigned i = 0; i < minSlots; i++) { if (typeMap[i] == peerMap[i]) continue; - if (typeMap[i] == TT_INT32 && peerMap[i] == TT_DOUBLE && + if (typeMap[i] == JSVAL_TYPE_INT32 && peerMap[i] == JSVAL_TYPE_DOUBLE && IsSlotUndemotable(JS_TRACE_MONITOR(cx).oracle, cx, peer, i, peer->ip)) { consensus = TypeConsensus_Undemotes; } else { @@ -4798,7 +4975,7 @@ TraceRecorder::findUndemotesInTypemaps(const TypeMap& typeMap, LinkableFragment* undemotes.setLength(0); unsigned minSlots = JS_MIN(typeMap.length(), f->typeMap.length()); for (unsigned i = 0; i < minSlots; i++) { - if (typeMap[i] == TT_INT32 && f->typeMap[i] == TT_DOUBLE) { + if (typeMap[i] == JSVAL_TYPE_INT32 && f->typeMap[i] == JSVAL_TYPE_DOUBLE) { undemotes.add(i); } else if (typeMap[i] != f->typeMap[i]) { return 0; @@ -5000,7 +5177,7 @@ TraceRecorder::prepareTreeCall(TreeFragment* inner) } static unsigned -BuildGlobalTypeMapFromInnerTree(Queue& typeMap, VMSideExit* inner) +BuildGlobalTypeMapFromInnerTree(Queue& typeMap, VMSideExit* inner) { #if defined DEBUG unsigned initialSlots = typeMap.length(); @@ -5089,14 +5266,14 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) /* Read back all registers, in case the called tree changed any of them. */ #ifdef DEBUG - TraceType* map; + JSValueType* map; size_t i; map = exit->globalTypeMap(); for (i = 0; i < exit->numGlobalSlots; i++) - JS_ASSERT(map[i] != TT_JSVAL); + JS_ASSERT(map[i] != JSVAL_TYPE_BOXED); map = exit->stackTypeMap(); for (i = 0; i < exit->numStackSlots; i++) - JS_ASSERT(map[i] != TT_JSVAL); + JS_ASSERT(map[i] != JSVAL_TYPE_BOXED); #endif /* @@ -5110,7 +5287,7 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) SlotList& gslots = *tree->globalSlots; for (unsigned i = 0; i < gslots.length(); i++) { unsigned slot = gslots[i]; - jsval* vp = &globalObj->getSlotRef(slot); + Value* vp = &globalObj->getSlotRef(slot); tracker.set(vp, NULL); } @@ -5118,7 +5295,7 @@ TraceRecorder::emitTreeCall(TreeFragment* inner, VMSideExit* exit) importTypeMap.setLength(NativeStackSlots(cx, callDepth)); #ifdef DEBUG for (unsigned i = importStackSlots; i < importTypeMap.length(); i++) - importTypeMap[i] = TT_IGNORE; + importTypeMap[i] = JSVAL_TYPE_UNINITIALIZED; #endif unsigned startOfInnerFrame = importTypeMap.length() - exit->numStackSlots; for (unsigned i = 0; i < exit->numStackSlots; i++) @@ -5239,7 +5416,7 @@ TraceRecorder::checkTraceEnd(jsbytecode *pc) JSFrameRegs orig = *cx->regs; cx->regs->pc = (jsbytecode*)tree->ip; - cx->regs->sp = StackBase(cx->fp) + tree->spOffsetAtEntry; + cx->regs->sp = cx->fp->base() + tree->spOffsetAtEntry; JSContext* localcx = cx; AbortableRecordingStatus ars = closeLoop(); @@ -5348,7 +5525,7 @@ CheckGlobalObjectShape(JSContext* cx, TraceMonitor* tm, JSObject* globalObj, bool JS_REQUIRES_STACK TraceRecorder::startRecorder(JSContext* cx, VMSideExit* anchor, VMFragment* f, unsigned stackSlots, unsigned ngslots, - TraceType* typeMap, VMSideExit* expectedInnerExit, + JSValueType* typeMap, VMSideExit* expectedInnerExit, jsbytecode* outer, uint32 outerArgc, RecordReason recordReason, bool speculate) { @@ -5409,22 +5586,22 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee) JS_ASSERT(FUN_INTERPRETED(fun)); /* Assert that we have a correct sp distance from cx->fp->slots in fi. */ - JSStackFrame* fp = cx->fp; + JSStackFrame* const fp = cx->fp; JS_ASSERT_IF(!fi.imacpc, js_ReconstructStackDepth(cx, fp->script, fi.pc) == uintN(fi.spdist - fp->script->nfixed)); /* Simulate js_Interpret locals for when |cx->fp == fp|. */ JSScript* newscript = fun->u.i.script; - jsval* sp = fp->slots() + fi.spdist; + Value* sp = fp->slots() + fi.spdist; uintN argc = fi.get_argc(); - jsval* vp = sp - (2 + argc); + Value* vp = sp - (2 + argc); /* Fixup |fp| using |fi|. */ cx->regs->sp = sp; cx->regs->pc = fi.pc; fp->imacpc = fi.imacpc; - + fp->blockChain = fi.block; fp->blockChain = fi.block; #ifdef DEBUG if (fi.block != fp->blockChain) { @@ -5444,13 +5621,13 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee) StackSpace &stack = cx->stack(); uintN nslots = newscript->nslots; uintN funargs = fun->nargs; - jsval *argv = vp + 2; + Value *argv = vp + 2; JSStackFrame *newfp; if (argc < funargs) { uintN missing = funargs - argc; newfp = stack.getInlineFrame(cx, sp, missing, nslots); - for (jsval *v = argv + argc, *end = v + missing; v != end; ++v) - *v = JSVAL_VOID; + for (Value *v = argv + argc, *end = v + missing; v != end; ++v) + v->setUndefined(); } else { newfp = stack.getInlineFrame(cx, sp, 0, nslots); } @@ -5465,14 +5642,14 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee) #ifdef DEBUG // Initialize argv[-1] to a known-bogus value so we'll catch it if // someone forgets to initialize it later. - newfp->argv[-1] = JSVAL_HOLE; + newfp->argv[-1].setMagic(JS_THIS_POISON); #endif - newfp->rval = JSVAL_VOID; + newfp->rval = UndefinedValue(); newfp->annotation = NULL; newfp->scopeChain = NULL; // will be updated in FlushNativeStackFrame newfp->flags = fi.is_constructing() ? JSFRAME_CONSTRUCTING : 0; newfp->blockChain = NULL; - newfp->thisv = JSVAL_NULL; // will be updated in FlushNativeStackFrame + newfp->thisv.setNull(); // will be updated in FlushNativeStackFrame newfp->imacpc = NULL; if (newscript->staticLevel < JS_DISPLAY_SIZE) { JSStackFrame **disp = &cx->display[newscript->staticLevel]; @@ -5491,7 +5668,7 @@ SynthesizeFrame(JSContext* cx, const FrameInfo& fi, JSObject* callee) /* Initialize regs after pushInlineFrame snapshots pc. */ cx->regs->pc = newscript->code; - cx->regs->sp = StackBase(newfp); + cx->regs->sp = newfp->base(); /* * If there's a call hook, invoke it to compute the hookData used by @@ -5530,7 +5707,7 @@ SynthesizeSlowNativeFrame(TracerState& state, JSContext *cx, VMSideExit *exit) cx->stack().getSynthesizedSlowNativeFrame(cx, cs, fp); #ifdef DEBUG - JSObject *callee = JSVAL_TO_OBJECT(state.nativeVp[0]); + JSObject *callee = &state.nativeVp[0].toObject(); JSFunction *fun = GET_FUNCTION_PRIVATE(cx, callee); JS_ASSERT(!fun->isInterpreted() && !fun->isFastNative()); JS_ASSERT(fun->u.n.extra == 0); @@ -5543,8 +5720,8 @@ SynthesizeSlowNativeFrame(TracerState& state, JSContext *cx, VMSideExit *exit) fp->thisv = state.nativeVp[1]; fp->argc = state.nativeVpLen - 2; fp->argv = state.nativeVp + 2; - fp->fun = GET_FUNCTION_PRIVATE(cx, fp->calleeObject()); - fp->rval = JSVAL_VOID; + fp->fun = GET_FUNCTION_PRIVATE(cx, fp->callee()); + fp->rval = UndefinedValue(); fp->annotation = NULL; JS_ASSERT(cx->fp->scopeChain); fp->scopeChain = cx->fp->scopeChain; @@ -5613,10 +5790,10 @@ RecordTree(JSContext* cx, TreeFragment* first, jsbytecode* outer, FramePCOffset(cx, cx->fp)); debug_only_print0(LC_TMTreeVis, " STACK=\""); for (unsigned i = 0; i < f->nStackTypes; i++) - debug_only_printf(LC_TMTreeVis, "%c", typeChar[f->typeMap[i]]); + debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(f->typeMap[i])); debug_only_print0(LC_TMTreeVis, "\" GLOBALS=\""); for (unsigned i = 0; i < f->nGlobalTypes(); i++) - debug_only_printf(LC_TMTreeVis, "%c", typeChar[f->typeMap[f->nStackTypes + i]]); + debug_only_printf(LC_TMTreeVis, "%c", TypeToChar(f->typeMap[f->nStackTypes + i])); debug_only_print0(LC_TMTreeVis, "\"\n"); #endif @@ -5643,7 +5820,7 @@ FindLoopEdgeTarget(JSContext* cx, VMSideExit* exit, TreeFragment** peerp) /* Mark all double slots as undemotable */ uint16* gslots = from->globalSlots->data(); for (unsigned i = 0; i < typeMap.length(); i++) { - if (typeMap[i] == TT_DOUBLE) { + if (typeMap[i] == JSVAL_TYPE_DOUBLE) { if (exit->exitType == RECURSIVE_UNLINKED_EXIT) { if (i < exit->numStackSlots) oracle->markStackSlotUndemotable(cx, i, exit->recursive_pc); @@ -5831,7 +6008,7 @@ AttemptToExtendTree(JSContext* cx, VMSideExit* anchor, VMSideExit* exitedFrom, j /* start tracing secondary trace from this point */ unsigned stackSlots; unsigned ngslots; - TraceType* typeMap; + JSValueType* typeMap; TypeMap fullMap(NULL); if (!exitedFrom) { /* @@ -6070,72 +6247,70 @@ TraceRecorder::attemptTreeCall(TreeFragment* f, uintN& inlineCallCount) } } -static bool -IsEntryTypeCompatible(jsval* vp, TraceType* m) +static inline bool +IsEntryTypeCompatible(const Value &v, JSValueType type) { - unsigned tag = JSVAL_TAG(*vp); +#ifdef DEBUG + char tag = ValueToTypeChar(v); + debug_only_printf(LC_TMTracer, "%c/%c ", tag, TypeToChar(type)); +#endif - debug_only_printf(LC_TMTracer, "%c/%c ", tagChar[tag], typeChar[*m]); - - switch (*m) { - case TT_OBJECT: - if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp) && - !JSVAL_TO_OBJECT(*vp)->isFunction()) { + JS_ASSERT(type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); + switch (type) { + case JSVAL_TYPE_DOUBLE: + if (v.isNumber()) return true; - } - debug_only_printf(LC_TMTracer, "object != tag%u ", tag); - return false; - case TT_INT32: - jsint i; - if (JSVAL_IS_INT(*vp)) + debug_only_printf(LC_TMTracer, "double != tag%c ", tag); + break; + case JSVAL_TYPE_INT32: { + int32_t _; + if (v.isInt32() || (v.isDouble() && JSDOUBLE_IS_INT32(v.toDouble(), &_))) return true; - if (tag == JSVAL_DOUBLE && JSDOUBLE_IS_INT(*JSVAL_TO_DOUBLE(*vp), i)) + debug_only_printf(LC_TMTracer, "int != tag%c ", tag); + break; + } + case JSVAL_TYPE_UNDEFINED: + if (v.isUndefined()) return true; - debug_only_printf(LC_TMTracer, "int != tag%u(value=%lu) ", tag, (unsigned long)*vp); - return false; - case TT_DOUBLE: - if (JSVAL_IS_INT(*vp) || tag == JSVAL_DOUBLE) + debug_only_printf(LC_TMTracer, "undefined != tag%c ", tag); + break; + case JSVAL_TYPE_BOOLEAN: + if (v.isBoolean()) return true; - debug_only_printf(LC_TMTracer, "double != tag%u ", tag); - return false; - case TT_JSVAL: - JS_NOT_REACHED("shouldn't see jsval type in entry"); - return false; - case TT_STRING: - if (tag == JSVAL_STRING) + debug_only_printf(LC_TMTracer, "bool != tag%c ", tag); + break; + case JSVAL_TYPE_MAGIC: + if (v.isMagic()) return true; - debug_only_printf(LC_TMTracer, "string != tag%u ", tag); - return false; - case TT_NULL: - if (JSVAL_IS_NULL(*vp)) + debug_only_printf(LC_TMTracer, "magic != tag%c ", tag); + break; + case JSVAL_TYPE_STRING: + if (v.isString()) return true; - debug_only_printf(LC_TMTracer, "null != tag%u ", tag); - return false; - case TT_SPECIAL: - /* N.B. void and hole are JSVAL_SPECIAL. */ - if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp)) + debug_only_printf(LC_TMTracer, "string != tag%c ", tag); + break; + case JSVAL_TYPE_NULL: + if (v.isNull()) return true; - debug_only_printf(LC_TMTracer, "bool != tag%u ", tag); - return false; - case TT_VOID: - if (JSVAL_IS_VOID(*vp)) + debug_only_printf(LC_TMTracer, "null != tag%c ", tag); + break; + case JSVAL_TYPE_OBJECT: + JS_NOT_REACHED("JSVAL_TYPE_OBJECT does not belong in a type map"); + break; + case JSVAL_TYPE_NONFUNOBJ: + if (v.isObject() && !v.toObject().isFunction()) return true; - debug_only_printf(LC_TMTracer, "undefined != tag%u ", tag); - return false; - case TT_MAGIC: - if (JSVAL_IS_HOLE(*vp)) + debug_only_printf(LC_TMTracer, "object != tag%c ", tag); + break; + case JSVAL_TYPE_FUNOBJ: + if (v.isObject() && v.toObject().isFunction()) return true; - debug_only_printf(LC_TMTracer, "hole != tag%u ", tag); - return false; + debug_only_printf(LC_TMTracer, "fun != tag%c ", tag); + break; default: - JS_ASSERT(*m == TT_FUNCTION); - if (tag == JSVAL_OBJECT && !JSVAL_IS_NULL(*vp) && - JSVAL_TO_OBJECT(*vp)->isFunction()) { - return true; - } - debug_only_printf(LC_TMTracer, "fun != tag%u ", tag); - return false; + JS_NOT_REACHED("unexpected type"); } + return false; } class TypeCompatibilityVisitor : public SlotVisitorBase @@ -6143,12 +6318,12 @@ class TypeCompatibilityVisitor : public SlotVisitorBase TraceRecorder &mRecorder; JSContext *mCx; Oracle *mOracle; - TraceType *mTypeMap; + JSValueType *mTypeMap; unsigned mStackSlotNum; bool mOk; public: TypeCompatibilityVisitor (TraceRecorder &recorder, - TraceType *typeMap) : + JSValueType *typeMap) : mRecorder(recorder), mCx(mRecorder.cx), mOracle(JS_TRACE_MONITOR(mCx).oracle), @@ -6158,29 +6333,29 @@ public: {} JS_REQUIRES_STACK JS_ALWAYS_INLINE void - visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { debug_only_printf(LC_TMTracer, "global%d=", n); - if (!IsEntryTypeCompatible(vp, mTypeMap)) { + if (!IsEntryTypeCompatible(*vp, *mTypeMap)) { mOk = false; - } else if (!isPromoteInt(mRecorder.get(vp)) && *mTypeMap == TT_INT32) { + } else if (!isPromoteInt(mRecorder.get(vp)) && *mTypeMap == JSVAL_TYPE_INT32) { mOracle->markGlobalSlotUndemotable(mCx, slot); mOk = false; - } else if (JSVAL_IS_INT(*vp) && *mTypeMap == TT_DOUBLE) { + } else if (vp->isInt32() && *mTypeMap == JSVAL_TYPE_DOUBLE) { mOracle->markGlobalSlotUndemotable(mCx, slot); } mTypeMap++; } JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) { + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { for (size_t i = 0; i < count; ++i) { debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), unsigned(i)); - if (!IsEntryTypeCompatible(vp, mTypeMap)) { + if (!IsEntryTypeCompatible(*vp, *mTypeMap)) { mOk = false; - } else if (!isPromoteInt(mRecorder.get(vp)) && *mTypeMap == TT_INT32) { + } else if (!isPromoteInt(mRecorder.get(vp)) && *mTypeMap == JSVAL_TYPE_INT32) { mOracle->markStackSlotUndemotable(mCx, mStackSlotNum); mOk = false; - } else if (JSVAL_IS_INT(*vp) && *mTypeMap == TT_DOUBLE) { + } else if (vp->isInt32() && *mTypeMap == JSVAL_TYPE_DOUBLE) { mOracle->markStackSlotUndemotable(mCx, mStackSlotNum); } vp++; @@ -6190,6 +6365,16 @@ public: return true; } + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame* fp) { + debug_only_printf(LC_TMTracer, "%s%u=", stackSlotKind(), 0); + if (!IsEntryTypeCompatible(ObjectOrNullValue(*p), *mTypeMap)) + mOk = false; + mTypeMap++; + mStackSlotNum++; + return true; + } + bool isOk() { return mOk; } @@ -6235,35 +6420,41 @@ TraceRecorder::findNestedCompatiblePeer(TreeFragment* f) class CheckEntryTypeVisitor : public SlotVisitorBase { bool mOk; - TraceType *mTypeMap; + JSValueType *mTypeMap; public: - CheckEntryTypeVisitor(TraceType *typeMap) : + CheckEntryTypeVisitor(JSValueType *typeMap) : mOk(true), mTypeMap(typeMap) {} - JS_ALWAYS_INLINE void checkSlot(jsval *vp, char const *name, int i) { + JS_ALWAYS_INLINE void checkSlot(const Value &v, char const *name, int i) { debug_only_printf(LC_TMTracer, "%s%d=", name, i); JS_ASSERT(*(uint8_t*)mTypeMap != 0xCD); - mOk = IsEntryTypeCompatible(vp, mTypeMap++); + mOk = IsEntryTypeCompatible(v, *mTypeMap++); } JS_REQUIRES_STACK JS_ALWAYS_INLINE void - visitGlobalSlot(jsval *vp, unsigned n, unsigned slot) { + visitGlobalSlot(Value *vp, unsigned n, unsigned slot) { if (mOk) - checkSlot(vp, "global", n); + checkSlot(*vp, "global", n); } JS_REQUIRES_STACK JS_ALWAYS_INLINE bool - visitStackSlots(jsval *vp, size_t count, JSStackFrame* fp) { + visitStackSlots(Value *vp, size_t count, JSStackFrame* fp) { for (size_t i = 0; i < count; ++i) { if (!mOk) break; - checkSlot(vp++, stackSlotKind(), i); + checkSlot(*vp++, stackSlotKind(), i); } return mOk; } + JS_REQUIRES_STACK JS_ALWAYS_INLINE bool + visitFrameObjPtr(JSObject **p, JSStackFrame *fp) { + checkSlot(ObjectOrNullValue(*p), stackSlotKind(), 0); + return mOk; + } + bool isOk() { return mOk; } @@ -6350,7 +6541,8 @@ TracerState::TracerState(JSContext* cx, TraceMonitor* tm, TreeFragment* f, startTime(rdtsc()), #endif builtinStatus(0), - nativeVp(NULL) + nativeVp(NULL), + bailedSlowNativeRegs(bailedSlowNativeRegs) { JS_ASSERT(!tm->tracecx); tm->tracecx = cx; @@ -6672,15 +6864,13 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr) * (Some opcodes, like JSOP_CALLELEM, produce two values, hence the * loop.) */ - TraceType* typeMap = innermost->stackTypeMap(); + JSValueType* typeMap = innermost->stackTypeMap(); for (int i = 1; i <= cs.ndefs; i++) { - if (!NativeToValue(cx, - regs->sp[-i], - typeMap[innermost->numStackSlots - i], - (jsdouble *) state.deepBailSp - + innermost->sp_adj / sizeof(jsdouble) - i)) { - OutOfMemoryAbort(); - } + NativeToValue(cx, + regs->sp[-i], + typeMap[innermost->numStackSlots - i], + (jsdouble *) state.deepBailSp + + innermost->sp_adj / sizeof(jsdouble) - i); } } return; @@ -6774,7 +6964,7 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr) */ cx->regs->pc = innermost->pc; fp->imacpc = innermost->imacpc; - cx->regs->sp = StackBase(fp) + (innermost->sp_adj / sizeof(double)) - calldepth_slots; + cx->regs->sp = fp->base() + (innermost->sp_adj / sizeof(double)) - calldepth_slots; JS_ASSERT_IF(!fp->imacpc, fp->slots() + fp->script->nfixed + js_ReconstructStackDepth(cx, fp->script, cx->regs->pc) == cx->regs->sp); @@ -6794,7 +6984,7 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr) js_CodeName[fp->imacpc ? *fp->imacpc : *cx->regs->pc], (void*)lr, getExitName(lr->exitType), - (long long int)(cx->regs->sp - StackBase(fp)), + (long long int)(cx->regs->sp - fp->base()), calldepth, (unsigned long long int)cycles); @@ -6809,7 +6999,7 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr) uint16* gslots = outermostTree->globalSlots->data(); unsigned ngslots = outermostTree->globalSlots->length(); JS_ASSERT(ngslots == outermostTree->nGlobalTypes()); - TraceType* globalTypeMap; + JSValueType* globalTypeMap; /* Are there enough globals? */ TypeMap& typeMap = *tm->cachedTempTypeMap; @@ -6857,7 +7047,7 @@ LeaveTree(TraceMonitor *tm, TracerState& state, VMSideExit* lr) #ifdef DEBUG /* Verify that our state restoration worked. */ for (JSStackFrame* fp = cx->fp; fp; fp = fp->down) { - JS_ASSERT_IF(fp->argv, JSVAL_IS_OBJECT(fp->argv[-1])); + JS_ASSERT_IF(fp->argv, fp->argv[-1].isObjectOrNull()); } #endif #ifdef JS_JIT_SPEW @@ -7121,8 +7311,15 @@ TraceRecorder::monitorRecording(JSOp op) /* Handle one-shot request to unbox the result of a property get. */ if (pendingUnboxSlot) { LIns* val_ins = get(pendingUnboxSlot); - val_ins = unbox_jsval(*pendingUnboxSlot, val_ins, snapshot(BRANCH_EXIT)); - set(pendingUnboxSlot, val_ins); + /* + * We need to know from where to unbox the value. Since pendingUnboxSlot + * is only set in finishGetProp, we can depend on LIns* tracked for + * pendingUnboxSlot to have this information. + */ + LIns* unboxed_ins = unbox_value(*pendingUnboxSlot, + val_ins->oprnd1(), val_ins->disp(), + snapshot(BRANCH_EXIT)); + set(pendingUnboxSlot, unboxed_ins); pendingUnboxSlot = 0; } @@ -7782,26 +7979,42 @@ DeepBail(JSContext *cx) state->deepBailSp = state->sp; } -JS_REQUIRES_STACK jsval& +JS_REQUIRES_STACK Value& TraceRecorder::argval(unsigned n) const { JS_ASSERT(n < cx->fp->fun->nargs); return cx->fp->argv[n]; } -JS_REQUIRES_STACK jsval& +JS_REQUIRES_STACK Value& TraceRecorder::varval(unsigned n) const { JS_ASSERT(n < cx->fp->script->nslots); return cx->fp->slots()[n]; } -JS_REQUIRES_STACK jsval& +JS_REQUIRES_STACK Value& TraceRecorder::stackval(int n) const { return cx->regs->sp[n]; } +JS_REQUIRES_STACK void +TraceRecorder::updateAtoms() +{ + atoms = FrameAtomBase(cx, cx->fp); + consts = cx->fp->imacpc || cx->fp->script->constOffset == 0 + ? 0 + : cx->fp->script->consts()->vector; +} + +JS_REQUIRES_STACK void +TraceRecorder::updateAtoms(JSScript *script) +{ + atoms = script->atomMap.vector; + consts = script->constOffset == 0 ? 0 : script->consts()->vector; +} + /* * Generate LIR to compute the scope chain. */ @@ -7809,7 +8022,7 @@ JS_REQUIRES_STACK LIns* TraceRecorder::scopeChain() { return cx->fp->callee() - ? get(&cx->fp->scopeChainVal) + ? getFrameObjPtr(&cx->fp->scopeChain) : entryScopeChain(); } @@ -7863,7 +8076,7 @@ JS_DEFINE_CALLINFO_4(extern, UINT32, GetClosureArg, CONTEXT, OBJECT, CVIPTR, DOU * NameResult describes how to look up name; see comment for NameResult in jstracer.h */ JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::scopeChainProp(JSObject* chainHead, jsval*& vp, LIns*& ins, NameResult& nr) +TraceRecorder::scopeChainProp(JSObject* chainHead, Value*& vp, LIns*& ins, NameResult& nr) { JS_ASSERT(chainHead == cx->fp->scopeChain); JS_ASSERT(chainHead != globalObj); @@ -7893,7 +8106,7 @@ TraceRecorder::scopeChainProp(JSObject* chainHead, jsval*& vp, LIns*& ins, NameR // Skip any Call object when inside a function. Any reference to a // Call name the compiler resolves statically and we do not need // to match shapes of the Call objects. - chainHead = cx->fp->calleeObject()->getParent(); + chainHead = cx->fp->callee()->getParent(); head_ins = stobj_get_parent(get(&cx->fp->argv[-2])); } else { head_ins = scopeChain(); @@ -7937,7 +8150,7 @@ TraceRecorder::scopeChainProp(JSObject* chainHead, jsval*& vp, LIns*& ins, NameR * Generate LIR to access a property of a Call object. */ JS_REQUIRES_STACK RecordingStatus -TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp, +TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, Value*& vp, LIns*& ins, NameResult& nr) { JSScopeProperty *sprop = (JSScopeProperty*) prop; @@ -7994,7 +8207,7 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp, } LIns* obj_ins; - JSObject* parent = cx->fp->calleeObject()->getParent(); + JSObject* parent = cx->fp->callee()->getParent(); LIns* parent_ins = stobj_get_parent(get(&cx->fp->argv[-2])); CHECK_STATUS(traverseScopeChain(parent, parent_ins, obj, obj_ins)); @@ -8021,8 +8234,8 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp, JS_ASSERT(sprop->hasShortID()); LIns* base = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER); - LIns* val_ins = lir->insLoad(LIR_ldp, base, dslot_index * sizeof(jsval), ACC_OTHER); - ins = unbox_jsval(obj->dslots[dslot_index], val_ins, snapshot(BRANCH_EXIT)); + ins = unbox_value(obj->dslots[dslot_index], base, dslot_index * sizeof(Value), + snapshot(BRANCH_EXIT)); } else { ClosureVarInfo* cv = new (traceAlloc()) ClosureVarInfo(); cv->slot = slot; @@ -8052,7 +8265,7 @@ TraceRecorder::callProp(JSObject* obj, JSProperty* prop, jsid id, jsval*& vp, call_ins = lir->insCall(ci, args); - TraceType type = getCoercedType(nr.v); + JSValueType type = getCoercedType(nr.v); guard(true, addName(lir->ins2(LIR_eqi, call_ins, lir->insImmI(type)), "guard(type-stable name access)"), @@ -8274,8 +8487,16 @@ TraceRecorder::d2i(LIns* f, bool resultCanBeImpreciseIfFractional) if (f->isCall()) { const CallInfo* ci = f->callInfo(); if (ci == &js_UnboxDouble_ci) { - LIns* args[] = { fcallarg(f, 0) }; +#if JS_BITS_PER_WORD == 32 + LIns *tag_ins = fcallarg(f, 0); + LIns *payload_ins = fcallarg(f, 1); + LIns* args[] = { payload_ins, tag_ins }; return lir->insCall(&js_UnboxInt32_ci, args); +#else + LIns* val_ins = fcallarg(f, 0); + LIns* args[] = { val_ins }; + return lir->insCall(&js_UnboxInt32_ci, args); +#endif } if (ci == &js_StringToNumber_ci) { LIns* args[] = { fcallarg(f, 1), fcallarg(f, 0) }; @@ -8329,21 +8550,19 @@ TraceRecorder::makeNumberInt32(LIns* f) } JS_REQUIRES_STACK LIns* -TraceRecorder::stringify(jsval& v) +TraceRecorder::stringify(const Value& v) { LIns* v_ins = get(&v); - if (JSVAL_IS_STRING(v)) + if (v.isString()) return v_ins; LIns* args[] = { v_ins, cx_ins }; const CallInfo* ci; - if (JSVAL_IS_NUMBER(v)) { + if (v.isNumber()) { ci = &js_NumberToString_ci; - } else if (JSVAL_IS_VOID(v)) { - /* N.B. void is JSVAL_SPECIAL. */ + } else if (v.isUndefined()) { return INS_ATOM(cx->runtime->atomState.booleanAtoms[2]); - } else if (JSVAL_IS_SPECIAL(v)) { - JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + } else if (v.isBoolean()) { ci = &js_BooleanIntToString_ci; } else { /* @@ -8351,7 +8570,7 @@ TraceRecorder::stringify(jsval& v) * calling an imacro. We don't try to guess about which imacro, with * what valueOf hint, here. */ - JS_ASSERT(JSVAL_IS_NULL(v)); + JS_ASSERT(v.isNull()); return INS_ATOM(cx->runtime->atomState.nullAtom); } @@ -8381,36 +8600,36 @@ TraceRecorder::callImacroInfallibly(jsbytecode* imacro) JSFrameRegs* regs = cx->regs; fp->imacpc = regs->pc; regs->pc = imacro; - atoms = COMMON_ATOMS_START(&cx->runtime->atomState); + updateAtoms(); return RECORD_IMACRO; } JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::ifop() { - jsval& v = stackval(-1); + Value& v = stackval(-1); LIns* v_ins = get(&v); bool cond; LIns* x; - if (JSVAL_IS_NULL(v)) { + if (v.isNull() || v.isUndefined()) { cond = false; x = lir->insImmI(0); - } else if (!JSVAL_IS_PRIMITIVE(v)) { + } else if (!v.isPrimitive()) { cond = true; x = lir->insImmI(1); - } else if (JSVAL_IS_SPECIAL(v)) { + } else if (v.isBoolean()) { /* Test for boolean is true, negate later if we are testing for false. */ - cond = JSVAL_TO_SPECIAL(v) == JS_TRUE; + cond = v.isTrue(); x = lir->ins2ImmI(LIR_eqi, v_ins, 1); - } else if (isNumber(v)) { - jsdouble d = asNumber(v); + } else if (v.isNumber()) { + jsdouble d = v.toNumber(); cond = !JSDOUBLE_IS_NaN(d) && d; x = lir->ins2(LIR_andi, lir->ins2(LIR_eqd, v_ins, v_ins), lir->insEqI_0(lir->ins2(LIR_eqd, v_ins, lir->insImmD(0)))); - } else if (JSVAL_IS_STRING(v)) { - cond = JSVAL_TO_STRING(v)->length() != 0; + } else if (v.isString()) { + cond = v.toString()->length() != 0; x = lir->insLoad(LIR_ldp, v_ins, offsetof(JSString, mLength), ACC_OTHER); } else { JS_NOT_REACHED("ifop"); @@ -8431,10 +8650,10 @@ TraceRecorder::ifop() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::tableswitch() { - jsval& v = stackval(-1); + Value& v = stackval(-1); /* No need to guard if the condition can't match any of the cases. */ - if (!isNumber(v)) + if (!v.isNumber()) return ARECORD_CONTINUE; /* No need to guard if the condition is constant. */ @@ -8486,40 +8705,34 @@ TraceRecorder::tableswitch() } #endif -static JS_ALWAYS_INLINE int32_t -UnboxBooleanOrUndefined(jsval v) -{ - /* Although this says 'special', we really only expect 3 special values: */ - JS_ASSERT(v == JSVAL_TRUE || v == JSVAL_FALSE || v == JSVAL_VOID); - return JSVAL_TO_SPECIAL(v); -} - JS_REQUIRES_STACK RecordingStatus TraceRecorder::switchop() { - jsval& v = stackval(-1); + Value& v = stackval(-1); LIns* v_ins = get(&v); /* No need to guard if the condition is constant. */ if (v_ins->isImmAny()) return RECORD_CONTINUE; - if (isNumber(v)) { - jsdouble d = asNumber(v); + if (v.isNumber()) { + jsdouble d = v.toNumber(); guard(true, addName(lir->ins2(LIR_eqd, v_ins, lir->insImmD(d)), "guard(switch on numeric)"), BRANCH_EXIT); - } else if (JSVAL_IS_STRING(v)) { - LIns* args[] = { INS_CONSTSTR(JSVAL_TO_STRING(v)), v_ins }; + } else if (v.isString()) { + LIns* args[] = { INS_CONSTSTR(v.toString()), v_ins }; guard(true, addName(lir->insEqI_0(lir->insEqI_0(lir->insCall(&js_EqualStrings_ci, args))), "guard(switch on string)"), BRANCH_EXIT); - } else if (JSVAL_IS_SPECIAL(v)) { + } else if (v.isBoolean()) { guard(true, - addName(lir->ins2(LIR_eqi, v_ins, lir->insImmI(UnboxBooleanOrUndefined(v))), + addName(lir->ins2(LIR_eqi, v_ins, lir->insImmI(v.isTrue())), "guard(switch on boolean)"), BRANCH_EXIT); + } else if (v.isUndefined()) { + // This is a unit type, so no guard is needed. } else { RETURN_STOP("switch on object or null"); } @@ -8527,7 +8740,7 @@ TraceRecorder::switchop() } JS_REQUIRES_STACK RecordingStatus -TraceRecorder::inc(jsval& v, jsint incr, bool pre) +TraceRecorder::inc(Value& v, jsint incr, bool pre) { LIns* v_ins = get(&v); CHECK_STATUS(inc(v, v_ins, incr, pre)); @@ -8540,7 +8753,7 @@ TraceRecorder::inc(jsval& v, jsint incr, bool pre) * (pre- or post-increment as described by pre) is stacked. */ JS_REQUIRES_STACK RecordingStatus -TraceRecorder::inc(jsval v, LIns*& v_ins, jsint incr, bool pre) +TraceRecorder::inc(const Value &v, LIns*& v_ins, jsint incr, bool pre) { LIns* v_after; CHECK_STATUS(incHelper(v, v_ins, v_after, incr)); @@ -8556,22 +8769,22 @@ TraceRecorder::inc(jsval v, LIns*& v_ins, jsint incr, bool pre) * Do an increment operation without storing anything to the stack. */ JS_REQUIRES_STACK RecordingStatus -TraceRecorder::incHelper(jsval v, LIns* v_ins, LIns*& v_after, jsint incr) +TraceRecorder::incHelper(const Value &v, LIns* v_ins, LIns*& v_after, jsint incr) { - if (!isNumber(v)) + if (!v.isNumber()) RETURN_STOP("can only inc numbers"); - v_after = alu(LIR_addd, asNumber(v), incr, v_ins, lir->insImmD(incr)); + v_after = alu(LIR_addd, v.toNumber(), incr, v_ins, lir->insImmD(incr)); return RECORD_CONTINUE; } JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::incProp(jsint incr, bool pre) { - jsval& l = stackval(-1); - if (JSVAL_IS_PRIMITIVE(l)) + Value& l = stackval(-1); + if (l.isPrimitive()) RETURN_STOP_A("incProp on primitive"); - JSObject* obj = JSVAL_TO_OBJECT(l); + JSObject* obj = &l.toObject(); LIns* obj_ins = get(&l); uint32 slot; @@ -8581,30 +8794,30 @@ TraceRecorder::incProp(jsint incr, bool pre) if (slot == SPROP_INVALID_SLOT) RETURN_STOP_A("incProp on invalid slot"); - jsval& v = obj->getSlotRef(slot); + Value& v = obj->getSlotRef(slot); CHECK_STATUS_A(inc(v, v_ins, incr, pre)); LIns* dslots_ins = NULL; - stobj_set_slot(obj_ins, slot, dslots_ins, box_jsval(v, v_ins)); + stobj_set_slot(obj_ins, slot, dslots_ins, v, v_ins); return ARECORD_CONTINUE; } JS_REQUIRES_STACK RecordingStatus TraceRecorder::incElem(jsint incr, bool pre) { - jsval& r = stackval(-1); - jsval& l = stackval(-2); - jsval* vp; + Value& r = stackval(-1); + Value& l = stackval(-2); + Value* vp; LIns* v_ins; LIns* addr_ins; - if (!JSVAL_IS_PRIMITIVE(l) && JSVAL_TO_OBJECT(l)->isDenseArray() && JSVAL_IS_INT(r)) { + if (!l.isPrimitive() && l.toObject().isDenseArray() && r.isInt32()) { guardDenseArray(get(&l), MISMATCH_EXIT); CHECK_STATUS(denseArrayElement(l, r, vp, v_ins, addr_ins)); if (!addr_ins) // if we read a hole, abort return RECORD_STOP; CHECK_STATUS(inc(*vp, v_ins, incr, pre)); - lir->insStore(box_jsval(*vp, v_ins), addr_ins, 0, ACC_OTHER); + box_value_into(*vp, v_ins, addr_ins, 0, ACC_OTHER); return RECORD_CONTINUE; } @@ -8651,34 +8864,34 @@ EvalCmp(LOpcode op, JSString* l, JSString* r) JS_REQUIRES_STACK void TraceRecorder::strictEquality(bool equal, bool cmpCase) { - jsval& r = stackval(-1); - jsval& l = stackval(-2); + Value& r = stackval(-1); + Value& l = stackval(-2); LIns* l_ins = get(&l); LIns* r_ins = get(&r); LIns* x; bool cond; - TraceType ltag = GetPromotedType(l); + JSValueType ltag = GetPromotedType(l); if (ltag != GetPromotedType(r)) { cond = !equal; x = lir->insImmI(cond); - } else if (ltag == TT_STRING) { + } else if (ltag == JSVAL_TYPE_STRING) { LIns* args[] = { r_ins, l_ins }; x = lir->ins2ImmI(LIR_eqi, lir->insCall(&js_EqualStrings_ci, args), equal); - cond = !!js_EqualStrings(JSVAL_TO_STRING(l), JSVAL_TO_STRING(r)); + cond = !!js_EqualStrings(l.toString(), r.toString()); } else { LOpcode op; - if (ltag == TT_DOUBLE) + if (ltag == JSVAL_TYPE_DOUBLE) op = LIR_eqd; - else if (ltag == TT_NULL || ltag == TT_OBJECT || ltag == TT_FUNCTION) + else if (ltag == JSVAL_TYPE_NULL || ltag == JSVAL_TYPE_NONFUNOBJ || ltag == JSVAL_TYPE_FUNOBJ) op = LIR_eqp; else op = LIR_eqi; x = lir->ins2(op, l_ins, r_ins); if (!equal) x = lir->insEqI_0(x); - cond = (ltag == TT_DOUBLE) - ? asNumber(l) == asNumber(r) + cond = (ltag == JSVAL_TYPE_DOUBLE) + ? l.toNumber() == r.toNumber() : l == r; } cond = (cond == equal); @@ -8696,8 +8909,8 @@ TraceRecorder::strictEquality(bool equal, bool cmpCase) JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::equality(bool negate, bool tryBranchAfterCond) { - jsval& rval = stackval(-1); - jsval& lval = stackval(-2); + Value& rval = stackval(-1); + Value& lval = stackval(-2); LIns* l_ins = get(&lval); LIns* r_ins = get(&rval); @@ -8705,9 +8918,9 @@ TraceRecorder::equality(bool negate, bool tryBranchAfterCond) } JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::equalityHelper(jsval& l, jsval& r, LIns* l_ins, LIns* r_ins, +TraceRecorder::equalityHelper(Value& l, Value& r, LIns* l_ins, LIns* r_ins, bool negate, bool tryBranchAfterCond, - jsval& rval) + Value& rval) { LOpcode op = LIR_eqi; bool cond; @@ -8725,67 +8938,67 @@ TraceRecorder::equalityHelper(jsval& l, jsval& r, LIns* l_ins, LIns* r_ins, */ if (GetPromotedType(l) == GetPromotedType(r)) { - if (JSVAL_IS_VOID(l) || JSVAL_IS_NULL(l)) { + if (l.isUndefined() || l.isNull()) { cond = true; - if (JSVAL_IS_NULL(l)) + if (l.isNull()) op = LIR_eqp; - } else if (JSVAL_IS_OBJECT(l)) { - JSClass *clasp = JSVAL_TO_OBJECT(l)->getClass(); + } else if (l.isObject()) { + Class *clasp = l.toObject().getClass(); if ((clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*) clasp)->equality) RETURN_STOP_A("Can't trace extended class equality operator"); op = LIR_eqp; cond = (l == r); - } else if (JSVAL_IS_SPECIAL(l)) { - JS_ASSERT(JSVAL_IS_BOOLEAN(l) && JSVAL_IS_BOOLEAN(r)); + } else if (l.isBoolean()) { + JS_ASSERT(r.isBoolean()); cond = (l == r); - } else if (JSVAL_IS_STRING(l)) { + } else if (l.isString()) { args[0] = r_ins, args[1] = l_ins; l_ins = lir->insCall(&js_EqualStrings_ci, args); r_ins = lir->insImmI(1); - cond = !!js_EqualStrings(JSVAL_TO_STRING(l), JSVAL_TO_STRING(r)); + cond = !!js_EqualStrings(l.toString(), r.toString()); } else { - JS_ASSERT(isNumber(l) && isNumber(r)); - cond = (asNumber(l) == asNumber(r)); + JS_ASSERT(l.isNumber() && r.isNumber()); + cond = (l.toNumber() == r.toNumber()); op = LIR_eqd; } - } else if (JSVAL_IS_NULL(l) && JSVAL_IS_VOID(r)) { - l_ins = INS_VOID(); + } else if (l.isNull() && r.isUndefined()) { + l_ins = INS_UNDEFINED(); cond = true; - } else if (JSVAL_IS_VOID(l) && JSVAL_IS_NULL(r)) { - r_ins = INS_VOID(); + } else if (l.isUndefined() && r.isNull()) { + r_ins = INS_UNDEFINED(); cond = true; - } else if (isNumber(l) && JSVAL_IS_STRING(r)) { + } else if (l.isNumber() && r.isString()) { args[0] = r_ins, args[1] = cx_ins; r_ins = lir->insCall(&js_StringToNumber_ci, args); - cond = (asNumber(l) == js_StringToNumber(cx, JSVAL_TO_STRING(r))); + cond = (l.toNumber() == js_StringToNumber(cx, r.toString())); op = LIR_eqd; - } else if (JSVAL_IS_STRING(l) && isNumber(r)) { + } else if (l.isString() && r.isNumber()) { args[0] = l_ins, args[1] = cx_ins; l_ins = lir->insCall(&js_StringToNumber_ci, args); - cond = (js_StringToNumber(cx, JSVAL_TO_STRING(l)) == asNumber(r)); + cond = (js_StringToNumber(cx, l.toString()) == r.toNumber()); op = LIR_eqd; } else { // Below we may assign to l or r, which modifies the interpreter state. // This is fine as long as we also update the tracker. - if (JSVAL_IS_BOOLEAN(l)) { + if (l.isBoolean()) { l_ins = i2d(l_ins); set(&l, l_ins); - l = INT_TO_JSVAL(l == JSVAL_TRUE); + l.setInt32(l.isTrue()); return equalityHelper(l, r, l_ins, r_ins, negate, tryBranchAfterCond, rval); } - if (JSVAL_IS_BOOLEAN(r)) { + if (r.isBoolean()) { r_ins = i2d(r_ins); set(&r, r_ins); - r = INT_TO_JSVAL(r == JSVAL_TRUE); + r.setInt32(r.isTrue()); return equalityHelper(l, r, l_ins, r_ins, negate, tryBranchAfterCond, rval); } - if ((JSVAL_IS_STRING(l) || isNumber(l)) && !JSVAL_IS_PRIMITIVE(r)) { + if ((l.isString() || l.isNumber()) && !r.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(r)); return InjectStatus(callImacro(equality_imacros.any_obj)); } - if (!JSVAL_IS_PRIMITIVE(l) && (JSVAL_IS_STRING(r) || isNumber(r))) { + if (!l.isPrimitive() && (r.isString() || r.isNumber())) { CHECK_STATUS_A(guardNativeConversion(l)); return InjectStatus(callImacro(equality_imacros.obj_any)); } @@ -8833,8 +9046,8 @@ TraceRecorder::equalityHelper(jsval& l, jsval& r, LIns* l_ins, LIns* r_ins, JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) { - jsval& r = stackval(-1); - jsval& l = stackval(-2); + Value& r = stackval(-1); + Value& l = stackval(-2); LIns* x = NULL; bool cond; LIns* l_ins = get(&l); @@ -8847,83 +9060,63 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) * property; if both arguments are objects with non-function-valued valueOf * properties, abort. */ - if (!JSVAL_IS_PRIMITIVE(l)) { + if (!l.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(l)); - if (!JSVAL_IS_PRIMITIVE(r)) { + if (!r.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(r)); return InjectStatus(callImacro(binary_imacros.obj_obj)); } return InjectStatus(callImacro(binary_imacros.obj_any)); } - if (!JSVAL_IS_PRIMITIVE(r)) { + if (!r.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(r)); return InjectStatus(callImacro(binary_imacros.any_obj)); } /* 11.8.5 steps 3, 16-21. */ - if (JSVAL_IS_STRING(l) && JSVAL_IS_STRING(r)) { + if (l.isString() && r.isString()) { LIns* args[] = { r_ins, l_ins }; l_ins = lir->insCall(&js_CompareStrings_ci, args); r_ins = lir->insImmI(0); - cond = EvalCmp(op, JSVAL_TO_STRING(l), JSVAL_TO_STRING(r)); + cond = EvalCmp(op, l.toString(), r.toString()); goto do_comparison; } /* 11.8.5 steps 4-5. */ - if (!JSVAL_IS_NUMBER(l)) { + if (!l.isNumber()) { LIns* args[] = { l_ins, cx_ins }; - switch (JSVAL_TAG(l)) { - case JSVAL_SPECIAL: - if (JSVAL_IS_VOID(l)) - l_ins = lir->insImmD(js_NaN); - else - l_ins = i2d(l_ins); - break; - case JSVAL_STRING: + if (l.isBoolean()) { + l_ins = i2d(l_ins); + } else if (l.isUndefined()) { + l_ins = lir->insImmD(js_NaN); + } else if (l.isString()) { l_ins = lir->insCall(&js_StringToNumber_ci, args); - break; - case JSVAL_OBJECT: - if (JSVAL_IS_NULL(l)) { - l_ins = lir->insImmD(0.0); - break; - } - // FALL THROUGH - case JSVAL_INT: - case JSVAL_DOUBLE: - default: + } else if (l.isNull()) { + l_ins = lir->insImmD(0.0); + } else { JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should " "have been handled at start of method"); RETURN_STOP_A("safety belt"); } } - if (!JSVAL_IS_NUMBER(r)) { + if (!r.isNumber()) { LIns* args[] = { r_ins, cx_ins }; - switch (JSVAL_TAG(r)) { - case JSVAL_SPECIAL: - if (JSVAL_IS_VOID(r)) - r_ins = lir->insImmD(js_NaN); - else - r_ins = i2d(r_ins); - break; - case JSVAL_STRING: + if (r.isBoolean()) { + r_ins = i2d(r_ins); + } else if (r.isUndefined()) { + r_ins = lir->insImmD(js_NaN); + } else if (r.isString()) { r_ins = lir->insCall(&js_StringToNumber_ci, args); - break; - case JSVAL_OBJECT: - if (JSVAL_IS_NULL(r)) { - r_ins = lir->insImmD(0.0); - break; - } - // FALL THROUGH - case JSVAL_INT: - case JSVAL_DOUBLE: - default: + } else if (r.isNull()) { + r_ins = lir->insImmD(0.0); + } else { JS_NOT_REACHED("JSVAL_IS_NUMBER if int/double, objects should " "have been handled at start of method"); RETURN_STOP_A("safety belt"); } } { - AutoValueRooter tvr(cx, JSVAL_NULL); + AutoValueRooter tvr(cx); *tvr.addr() = l; ValueToNumber(cx, tvr.value(), &lnum); *tvr.addr() = r; @@ -8975,9 +9168,9 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond) JS_REQUIRES_STACK RecordingStatus TraceRecorder::unary(LOpcode op) { - jsval& v = stackval(-1); + Value& v = stackval(-1); bool intop = retTypes[op] == LTy_I; - if (isNumber(v)) { + if (v.isNumber()) { LIns* a = get(&v); if (intop) a = d2i(a); @@ -8993,18 +9186,18 @@ TraceRecorder::unary(LOpcode op) JS_REQUIRES_STACK RecordingStatus TraceRecorder::binary(LOpcode op) { - jsval& r = stackval(-1); - jsval& l = stackval(-2); + Value& r = stackval(-1); + Value& l = stackval(-2); - if (!JSVAL_IS_PRIMITIVE(l)) { + if (!l.isPrimitive()) { CHECK_STATUS(guardNativeConversion(l)); - if (!JSVAL_IS_PRIMITIVE(r)) { + if (!r.isPrimitive()) { CHECK_STATUS(guardNativeConversion(r)); return callImacro(binary_imacros.obj_obj); } return callImacro(binary_imacros.obj_any); } - if (!JSVAL_IS_PRIMITIVE(r)) { + if (!r.isPrimitive()) { CHECK_STATUS(guardNativeConversion(r)); return callImacro(binary_imacros.any_obj); } @@ -9013,45 +9206,42 @@ TraceRecorder::binary(LOpcode op) LIns* a = get(&l); LIns* b = get(&r); - bool leftIsNumber = isNumber(l); - jsdouble lnum = leftIsNumber ? asNumber(l) : 0; + bool leftIsNumber = l.isNumber(); + jsdouble lnum = leftIsNumber ? l.toNumber() : 0; - bool rightIsNumber = isNumber(r); - jsdouble rnum = rightIsNumber ? asNumber(r) : 0; + bool rightIsNumber = r.isNumber(); + jsdouble rnum = rightIsNumber ? r.toNumber() : 0; - if (JSVAL_IS_STRING(l)) { + if (l.isString()) { NanoAssert(op != LIR_addd); // LIR_addd/IS_STRING case handled by record_JSOP_ADD() LIns* args[] = { a, cx_ins }; a = lir->insCall(&js_StringToNumber_ci, args); - lnum = js_StringToNumber(cx, JSVAL_TO_STRING(l)); + lnum = js_StringToNumber(cx, l.toString()); leftIsNumber = true; } - if (JSVAL_IS_STRING(r)) { + if (r.isString()) { NanoAssert(op != LIR_addd); // LIR_addd/IS_STRING case handled by record_JSOP_ADD() LIns* args[] = { b, cx_ins }; b = lir->insCall(&js_StringToNumber_ci, args); - rnum = js_StringToNumber(cx, JSVAL_TO_STRING(r)); + rnum = js_StringToNumber(cx, r.toString()); rightIsNumber = true; } - /* N.B. void is JSVAL_SPECIAL. */ - if (JSVAL_IS_SPECIAL(l)) { - if (JSVAL_IS_VOID(l)) { - a = lir->insImmD(js_NaN); - lnum = js_NaN; - } else { - a = i2d(a); - lnum = JSVAL_TO_SPECIAL(l); - } + if (l.isBoolean()) { + a = i2d(a); + lnum = l.toBoolean(); + leftIsNumber = true; + } else if (l.isUndefined()) { + a = lir->insImmD(js_NaN); + lnum = js_NaN; leftIsNumber = true; } - if (JSVAL_IS_SPECIAL(r)) { - if (JSVAL_IS_VOID(r)) { - b = lir->insImmD(js_NaN); - rnum = js_NaN; - } else { - b = i2d(b); - rnum = JSVAL_TO_SPECIAL(r); - } + if (r.isBoolean()) { + b = i2d(b); + rnum = r.toBoolean(); + rightIsNumber = true; + } else if (r.isUndefined()) { + b = lir->insImmD(js_NaN); + rnum = js_NaN; rightIsNumber = true; } if (leftIsNumber && rightIsNumber) { @@ -9087,7 +9277,7 @@ DumpShape(JSObject* obj, const char* prefix) fprintf(shapefp, "\n%s: shape %u flags %x\n", prefix, scope->shape, scope->flags); for (JSScopeProperty* sprop = scope->lastProperty(); sprop; sprop = sprop->parent) { if (JSID_IS_ATOM(sprop->id)) { - fprintf(shapefp, " %s", JS_GetStringBytes(JSVAL_TO_STRING(ID_TO_VALUE(sprop->id)))); + fprintf(shapefp, " %s", JS_GetStringBytes(JSID_TO_STRING(sprop->id))); } else { JS_ASSERT(!JSID_IS_OBJECT(sprop->id)); fprintf(shapefp, " %d", JSID_TO_INT(sprop->id)); @@ -9328,71 +9518,434 @@ TraceRecorder::guardPropertyCacheHit(LIns* obj_ins, } void -TraceRecorder::stobj_set_fslot(LIns *obj_ins, unsigned slot, LIns* v_ins) +TraceRecorder::stobj_set_fslot(LIns *obj_ins, unsigned slot, const Value &v, LIns* v_ins) { - lir->insStore(v_ins, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval), ACC_OTHER); + box_value_into(v, v_ins, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(Value), ACC_OTHER); } void -TraceRecorder::stobj_set_dslot(LIns *obj_ins, unsigned slot, LIns*& dslots_ins, LIns* v_ins) +TraceRecorder::stobj_set_dslot(LIns *obj_ins, unsigned slot, LIns*& dslots_ins, + const Value &v, LIns* v_ins) { if (!dslots_ins) dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER); - lir->insStore(v_ins, dslots_ins, slot * sizeof(jsval), ACC_OTHER); + box_value_into(v, v_ins, dslots_ins, slot * sizeof(Value), ACC_OTHER); } void -TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins, LIns* v_ins) +TraceRecorder::stobj_set_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins, + const Value &v, LIns* v_ins) { if (slot < JS_INITIAL_NSLOTS) { - stobj_set_fslot(obj_ins, slot, v_ins); + stobj_set_fslot(obj_ins, slot, v, v_ins); } else { - stobj_set_dslot(obj_ins, slot - JS_INITIAL_NSLOTS, dslots_ins, v_ins); + stobj_set_dslot(obj_ins, slot - JS_INITIAL_NSLOTS, dslots_ins, v, v_ins); } } -LIns* -TraceRecorder::stobj_get_fslot(LIns* obj_ins, unsigned slot) +#if JS_BITS_PER_WORD == 32 || JS_BITS_PER_WORD == 64 +void +TraceRecorder::set_array_fslot(LIns *obj_ins, unsigned slot, uint32 val) { - JS_ASSERT(slot < JS_INITIAL_NSLOTS); - return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval), - ACC_OTHER); + /* + * We can assume the destination fslot has been appropriately tagged so we + * can just overwrite the 32-bit payload. + */ + lir->insStore(INS_CONSTU(val), obj_ins, + offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset, + ACC_OTHER); } LIns* -TraceRecorder::stobj_get_const_fslot(LIns* obj_ins, unsigned slot) +TraceRecorder::stobj_get_fslot_uint32(LIns* obj_ins, unsigned slot) { JS_ASSERT(slot < JS_INITIAL_NSLOTS); - return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(jsval), + return lir->insLoad(LIR_ldi, obj_ins, + offsetof(JSObject, fslots) + slot * sizeof(Value) + sPayloadOffset, + ACC_OTHER); +} +#endif + +LIns* +TraceRecorder::unbox_slot(JSObject *obj, LIns *obj_ins, uint32 slot, VMSideExit *exit) +{ + LIns *vaddr_ins; + ptrdiff_t offset; + if (slot < JS_INITIAL_NSLOTS) { + vaddr_ins = obj_ins; + offset = offsetof(JSObject, fslots) + slot * sizeof(Value); + } else { + vaddr_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER); + offset = (slot - JS_INITIAL_NSLOTS) * sizeof(Value); + } + + const Value &v = obj->getSlot(slot); + return unbox_value(v, vaddr_ins, offset, exit); +} + +#if JS_BITS_PER_WORD == 32 + +LIns* +TraceRecorder::stobj_get_const_private_ptr(LIns *obj_ins) +{ + return lir->insLoad(LIR_ldi, obj_ins, + offsetof(JSObject, fslots) + JSSLOT_PRIVATE * sizeof(Value) + sPayloadOffset, ACC_READONLY); } LIns* -TraceRecorder::stobj_get_dslot(LIns* obj_ins, unsigned index, LIns*& dslots_ins) +TraceRecorder::stobj_get_fslot_ptr(LIns *obj_ins, unsigned slot) { - if (!dslots_ins) - dslots_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER); - return lir->insLoad(LIR_ldp, dslots_ins, index * sizeof(jsval), ACC_OTHER); + JS_ASSERT(slot < JS_INITIAL_NSLOTS); + return lir->insLoad(LIR_ldi, obj_ins, offsetof(JSObject, fslots) + slot * sizeof(Value), + ACC_OTHER); +} + +void +TraceRecorder::box_undefined_into(LIns *vaddr_ins, ptrdiff_t offset, AccSet accSet) +{ + lir->insStore(INS_CONSTU(JSVAL_TAG_UNDEFINED), vaddr_ins, offset + sTagOffset, accSet); + lir->insStore(INS_CONST(0), vaddr_ins, offset + sPayloadOffset, accSet); +} + +void +TraceRecorder::box_null_into(LIns *dstaddr_ins, ptrdiff_t offset, AccSet accSet) +{ + lir->insStore(INS_CONSTU(JSVAL_TAG_NULL), dstaddr_ins, offset + sTagOffset, accSet); + lir->insStore(INS_CONST(0), dstaddr_ins, offset + sPayloadOffset, accSet); +} + +inline LIns* +TraceRecorder::unbox_number_as_double(LIns *vaddr_ins, ptrdiff_t offset, LIns *tag_ins, + VMSideExit *exit, AccSet accSet) +{ + guard(true, lir->ins2(LIR_leui, tag_ins, INS_CONSTU(JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET)), exit); + LIns *val_ins = lir->insLoad(LIR_ldi, vaddr_ins, offset + sPayloadOffset, accSet); + LIns* args[] = { val_ins, tag_ins }; + return lir->insCall(&js_UnboxDouble_ci, args); +} + +inline LIns* +TraceRecorder::unbox_non_double_object(LIns* vaddr_ins, ptrdiff_t offset, LIns* tag_ins, + JSValueType type, VMSideExit* exit, AccSet accSet) +{ + LIns *val_ins; + if (type == JSVAL_TYPE_UNDEFINED) { + val_ins = INS_UNDEFINED(); + } else if (type == JSVAL_TYPE_NULL) { + val_ins = INS_NULL(); + } else { + JS_ASSERT(type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_OBJECT || + type == JSVAL_TYPE_STRING || type == JSVAL_TYPE_BOOLEAN || + type == JSVAL_TYPE_MAGIC); + val_ins = lir->insLoad(LIR_ldi, vaddr_ins, offset + sPayloadOffset, accSet); + } + + guard(true, lir->ins2(LIR_eqi, tag_ins, INS_CONSTU(JSVAL_TYPE_TO_TAG(type))), exit); + return val_ins; } LIns* -TraceRecorder::stobj_get_slot(LIns* obj_ins, unsigned slot, LIns*& dslots_ins) +TraceRecorder::unbox_object(LIns* vaddr_ins, ptrdiff_t offset, LIns* tag_ins, + JSValueType type, VMSideExit* exit, AccSet accSet) { - if (slot < JS_INITIAL_NSLOTS) - return stobj_get_fslot(obj_ins, slot); - return stobj_get_dslot(obj_ins, slot - JS_INITIAL_NSLOTS, dslots_ins); + JS_ASSERT(type == JSVAL_TYPE_FUNOBJ || type == JSVAL_TYPE_NONFUNOBJ); + guard(true, lir->ins2(LIR_eqi, tag_ins, INS_CONSTU(JSVAL_TAG_OBJECT)), exit); + LIns *payload_ins = lir->insLoad(LIR_ldi, vaddr_ins, offset + sPayloadOffset, accSet); + if (type == JSVAL_TYPE_FUNOBJ) + guardClass(payload_ins, &js_FunctionClass, exit, ACC_OTHER); + else + guardNotClass(payload_ins, &js_FunctionClass, exit, ACC_OTHER); + return payload_ins; } +LIns* +TraceRecorder::unbox_value(const Value &v, LIns *vaddr_ins, ptrdiff_t offset, VMSideExit *exit, + bool force_double) +{ + AccSet accSet = vaddr_ins == lirbuf->sp ? ACC_STACK : ACC_OTHER; + LIns *tag_ins = lir->insLoad(LIR_ldi, vaddr_ins, offset + sTagOffset, accSet); + + if (v.isNumber() && force_double) + return unbox_number_as_double(vaddr_ins, offset, tag_ins, exit, accSet); + + if (v.isInt32()) { + guard(true, lir->ins2(LIR_eqi, tag_ins, INS_CONSTU(JSVAL_TAG_INT32)), exit); + return i2d(lir->insLoad(LIR_ldi, vaddr_ins, offset + sPayloadOffset, accSet)); + } + + if (v.isDouble()) { + guard(true, lir->ins2(LIR_ltui, tag_ins, INS_CONSTU(JSVAL_TAG_CLEAR)), exit); + return lir->insLoad(LIR_ldd, vaddr_ins, offset + sPayloadOffset, accSet); + } + + if (v.isObject()) { + JSValueType type = v.toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return unbox_object(vaddr_ins, offset, tag_ins, type, exit, accSet); + } + + JSValueType type = v.extractNonDoubleObjectTraceType(); + return unbox_non_double_object(vaddr_ins, offset, tag_ins, type, exit, accSet); +} + +void +TraceRecorder::unbox_any_object(LIns *vaddr_ins, LIns **obj_ins, LIns **is_obj_ins, AccSet accSet) +{ + LIns *tag_ins = lir->insLoad(LIR_ldp, vaddr_ins, sTagOffset, accSet); + *is_obj_ins = lir->ins2(LIR_eqi, tag_ins, INS_CONSTU(JSVAL_TAG_OBJECT)); + *obj_ins = lir->insLoad(LIR_ldp, vaddr_ins, sPayloadOffset, accSet); +} + +LIns* +TraceRecorder::is_boxed_true(LIns *vaddr_ins, AccSet accSet) +{ + LIns *tag_ins = lir->insLoad(LIR_ldi, vaddr_ins, sTagOffset, ACC_OTHER); + LIns *bool_ins = lir->ins2(LIR_eqi, tag_ins, INS_CONSTU(JSVAL_TAG_BOOLEAN)); + LIns *payload_ins = lir->insLoad(LIR_ldi, vaddr_ins, sPayloadOffset, ACC_OTHER); + return lir->ins2(LIR_andi, bool_ins, payload_ins); +} + +void +TraceRecorder::box_value_into(const Value &v, LIns *v_ins, LIns *dstaddr_ins, ptrdiff_t offset, + AccSet accSet) +{ + if (v.isNumber()) { + JS_ASSERT(v_ins->isD()); + if (fcallinfo(v_ins) == &js_UnboxDouble_ci) { + LIns *tag_ins = fcallarg(v_ins, 0); + LIns *payload_ins = fcallarg(v_ins, 1); + lir->insStore(tag_ins, dstaddr_ins, offset + sTagOffset, accSet); + lir->insStore(payload_ins, dstaddr_ins, offset + sPayloadOffset, accSet); + } else if (isPromoteInt(v_ins)) { + LIns *int_ins = demote(lir, v_ins); + lir->insStore(INS_CONSTU(JSVAL_TAG_INT32), dstaddr_ins, + offset + sTagOffset, accSet); + lir->insStore(int_ins, dstaddr_ins, offset + sPayloadOffset, accSet); + } else { + lir->insStore(v_ins, dstaddr_ins, offset, accSet); + } + return; + } + + if (v.isUndefined()) { + box_undefined_into(dstaddr_ins, offset, accSet); + } else if (v.isNull()) { + box_null_into(dstaddr_ins, offset, accSet); + } else { + JSValueTag tag = v.isObject() ? JSVAL_TAG_OBJECT : v.extractNonDoubleObjectTraceTag(); + lir->insStore(INS_CONSTU(tag), dstaddr_ins, offset + sTagOffset, ACC_OTHER); + lir->insStore(v_ins, dstaddr_ins, offset + sPayloadOffset, ACC_OTHER); + } +} + +LIns* +TraceRecorder::box_value_into_alloc(const Value &v, LIns *v_ins) +{ + LIns *boxed_ins = lir->insAlloc(sizeof(Value)); + box_value_into(v, v_ins, boxed_ins, 0, ACC_OTHER); + return boxed_ins; +} + +LIns* +TraceRecorder::box_value_for_native_call(const Value &v, LIns *v_ins) +{ + return box_value_into_alloc(v, v_ins); +} + +#elif JS_BITS_PER_WORD == 64 + +LIns* +TraceRecorder::stobj_get_const_private_ptr(LIns *obj_ins) +{ + /* N.B. On 64-bit, privates are encoded differently than other pointers. */ + LIns *v_ins = lir->insLoad(LIR_ldq, obj_ins, + offsetof(JSObject, fslots) + JSSLOT_PRIVATE * sizeof(Value), + ACC_READONLY); + return lir->ins2ImmI(LIR_lshq, v_ins, 1); +} + +LIns* +TraceRecorder::stobj_get_fslot_ptr(LIns *obj_ins, unsigned slot) +{ + JS_ASSERT(slot < JS_INITIAL_NSLOTS); + LIns *v_ins = lir->insLoad(LIR_ldq, obj_ins, + offsetof(JSObject, fslots) + slot * sizeof(Value), + ACC_OTHER); + return unpack_ptr(v_ins); +} + +void +TraceRecorder::box_undefined_into(LIns *vaddr_ins, ptrdiff_t offset, AccSet accSet) +{ + lir->insStore(INS_CONSTQWORD(JSVAL_BITS(JSVAL_VOID)), vaddr_ins, offset, accSet); +} + +inline LIns * +TraceRecorder::non_double_object_value_has_type(LIns *v_ins, JSValueType type) +{ + return lir->ins2(LIR_eqi, + lir->ins1(LIR_q2i, lir->ins2ImmI(LIR_rshuq, v_ins, JSVAL_TAG_SHIFT)), + INS_CONSTU(JSVAL_TYPE_TO_TAG(type))); +} + +inline LIns * +TraceRecorder::unpack_ptr(LIns *v_ins) +{ + return lir->ins2(LIR_andq, v_ins, INS_CONSTQWORD(JSVAL_PAYLOAD_MASK)); +} + +inline LIns * +TraceRecorder::unbox_number_as_double(LIns *v_ins, VMSideExit *exit) +{ + guard(true, + lir->ins2(LIR_ltuq, v_ins, INS_CONSTQWORD(JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET)), + exit); + LIns* args[] = { v_ins }; + return lir->insCall(&js_UnboxDouble_ci, args); +} + +inline nanojit::LIns* +TraceRecorder::unbox_non_double_object(LIns* v_ins, JSValueType type, VMSideExit* exit) +{ + JS_ASSERT(type <= JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET); + LIns *unboxed_ins; + if (type == JSVAL_TYPE_UNDEFINED) { + unboxed_ins = INS_UNDEFINED(); + } else if (type == JSVAL_TYPE_NULL) { + unboxed_ins = INS_NULL(); + } else if (type >= JSVAL_LOWER_INCL_TYPE_OF_GCTHING_SET) { + unboxed_ins = unpack_ptr(v_ins); + } else { + JS_ASSERT(type == JSVAL_TYPE_INT32 || type == JSVAL_TYPE_BOOLEAN || type == JSVAL_TYPE_MAGIC); + unboxed_ins = lir->ins1(LIR_q2i, v_ins); + } + + guard(true, non_double_object_value_has_type(v_ins, type), exit); + return unboxed_ins; +} + +LIns* +TraceRecorder::unbox_object(LIns* v_ins, JSValueType type, VMSideExit* exit) +{ + JS_STATIC_ASSERT(JSVAL_TYPE_OBJECT == JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET); + JS_ASSERT(type == JSVAL_TYPE_FUNOBJ || type == JSVAL_TYPE_NONFUNOBJ); + guard(true, + lir->ins2(LIR_geuq, v_ins, INS_CONSTQWORD(JSVAL_SHIFTED_TAG_OBJECT)), + exit); + v_ins = unpack_ptr(v_ins); + if (type == JSVAL_TYPE_FUNOBJ) + guardClass(v_ins, &js_FunctionClass, exit, ACC_OTHER); + else + guardNotClass(v_ins, &js_FunctionClass, exit, ACC_OTHER); + return v_ins; +} + +LIns* +TraceRecorder::unbox_value(const Value &v, LIns *vaddr_ins, ptrdiff_t offset, VMSideExit *exit, + bool force_double) +{ + AccSet accSet = vaddr_ins == lirbuf->sp ? ACC_STACK : ACC_OTHER; + LIns *v_ins = lir->insLoad(LIR_ldq, vaddr_ins, offset, accSet); + + if (v.isNumber() && force_double) + return unbox_number_as_double(v_ins, exit); + + if (v.isInt32()) { + guard(true, non_double_object_value_has_type(v_ins, JSVAL_TYPE_INT32), exit); + return i2d(lir->ins1(LIR_q2i, v_ins)); + } + + if (v.isDouble()) { + guard(true, lir->ins2(LIR_leuq, v_ins, INS_CONSTQWORD(JSVAL_SHIFTED_TAG_MAX_DOUBLE)), exit); + /* Without LIR_q2d, we need to re-load the value. */ + return lir->insLoad(LIR_ldd, vaddr_ins, offset, accSet); + } + + if (v.isObject()) { + JSValueType type = v.toObject().isFunction() ? JSVAL_TYPE_FUNOBJ : JSVAL_TYPE_NONFUNOBJ; + return unbox_object(v_ins, type, exit); + } + + JSValueType type = v.extractNonDoubleObjectTraceType(); + return unbox_non_double_object(v_ins, type, exit); +} + +void +TraceRecorder::unbox_any_object(LIns *vaddr_ins, LIns **obj_ins, LIns **is_obj_ins, AccSet accSet) +{ + JS_STATIC_ASSERT(JSVAL_TYPE_OBJECT == JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET); + LIns *v_ins = lir->insLoad(LIR_ldq, vaddr_ins, 0, accSet); + *is_obj_ins = lir->ins2(LIR_geuq, v_ins, INS_CONSTQWORD(JSVAL_TYPE_OBJECT)); + *obj_ins = unpack_ptr(v_ins); +} + +LIns* +TraceRecorder::is_boxed_true(LIns *vaddr_ins, AccSet accSet) +{ + LIns *v_ins = lir->insLoad(LIR_ldq, vaddr_ins, 0, accSet); + return lir->ins2(LIR_eqq, v_ins, lir->insImmQ(JSVAL_BITS(JSVAL_TRUE))); +} + +LIns* +TraceRecorder::box_value_for_native_call(const Value &v, LIns *v_ins) +{ + if (v.isNumber()) { + JS_ASSERT(v_ins->isD()); + if (fcallinfo(v_ins) == &js_UnboxDouble_ci) + return fcallarg(v_ins, 0); + if (isPromoteInt(v_ins)) { + return lir->ins2(LIR_orq, + lir->ins1(LIR_ui2uq, demote(lir, v_ins)), + INS_CONSTQWORD(JSVAL_SHIFTED_TAG_INT32)); + } + // TODO: this is very sad; remove when there is a LIR_d2q + LIns *tmp = lir->insAlloc(sizeof(Value)); + lir->insStore(v_ins, tmp, 0, ACC_OTHER); + return lir->insLoad(LIR_ldq, tmp, 0, ACC_OTHER); + } + + if (v.isNull()) + return INS_CONSTQWORD(JSVAL_BITS(JSVAL_NULL)); + if (v.isUndefined()) + return INS_CONSTQWORD(JSVAL_BITS(JSVAL_VOID)); + + JSValueTag tag = v.isObject() ? JSVAL_TAG_OBJECT : v.extractNonDoubleObjectTraceTag(); + uint64 shiftedTag = ((uint64)tag) << JSVAL_TAG_SHIFT; + LIns *shiftedTag_ins = INS_CONSTQWORD(shiftedTag); + + if (v.isGCThing()) + return lir->ins2(LIR_orq, v_ins, shiftedTag_ins); + return lir->ins2(LIR_orq, lir->ins1(LIR_ui2uq, v_ins), shiftedTag_ins); +} + +void +TraceRecorder::box_value_into(const Value &v, LIns *v_ins, LIns *dstaddr_ins, ptrdiff_t offset, + AccSet accSet) +{ + LIns *boxed_ins = box_value_for_native_call(v, v_ins); + lir->insStore(boxed_ins, dstaddr_ins, offset, accSet); +} + +LIns* +TraceRecorder::box_value_into_alloc(const Value &v, LIns *v_ins) +{ + LIns *alloc_ins = lir->insAlloc(sizeof(Value)); + box_value_into(v, v_ins, alloc_ins, 0, ACC_OTHER); + return alloc_ins; +} + +#endif /* JS_BITS_PER_WORD */ + LIns* TraceRecorder::stobj_get_parent(nanojit::LIns* obj_ins) { - return stobj_get_fslot(obj_ins, JSSLOT_PARENT); + return stobj_get_fslot_ptr(obj_ins, JSSLOT_PARENT); } LIns* TraceRecorder::stobj_get_private(nanojit::LIns* obj_ins) { - return stobj_get_fslot(obj_ins, JSSLOT_PRIVATE); + return stobj_get_fslot_ptr(obj_ins, JSSLOT_PRIVATE); } LIns* @@ -9401,98 +9954,23 @@ TraceRecorder::stobj_get_proto(nanojit::LIns* obj_ins) return lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, proto), ACC_OTHER); } -JS_REQUIRES_STACK LIns* -TraceRecorder::box_jsval(jsval v, LIns* v_ins) +LIns* +TraceRecorder::is_string_id(LIns *id_ins) { - if (isNumber(v)) { - JS_ASSERT(v_ins->isD()); - if (fcallinfo(v_ins) == &js_UnboxDouble_ci) - return fcallarg(v_ins, 0); - if (isPromoteInt(v_ins)) { - LIns* args[] = { demote(lir, v_ins), cx_ins }; - return lir->insCall(&js_BoxInt32_ci, args); - } - LIns* args[] = { v_ins, cx_ins }; - v_ins = lir->insCall(&js_BoxDouble_ci, args); - guard(false, lir->insEqP_0(v_ins), OOM_EXIT); - return v_ins; - } - switch (JSVAL_TAG(v)) { - case JSVAL_SPECIAL: - return lir->ins2(LIR_orp, lir->ins2ImmI(LIR_lshp, lir->insUI2P(v_ins), JSVAL_TAGBITS), - INS_CONSTWORD(JSVAL_SPECIAL)); - case JSVAL_OBJECT: - return v_ins; - default: - JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING); - return lir->ins2(LIR_orp, v_ins, INS_CONSTWORD(JSVAL_STRING)); - } + return lir->insEqP_0(lir->ins2(LIR_andp, id_ins, INS_CONSTWORD(JSID_TYPE_MASK))); } -JS_REQUIRES_STACK LIns* -TraceRecorder::unbox_jsval(jsval v, LIns* v_ins, VMSideExit* exit) +LIns * +TraceRecorder::unbox_string_id(LIns *id_ins) { - if (isNumber(v)) { - // JSVAL_IS_NUMBER(v) - guard(false, - lir->insEqI_0(lir->ins2(LIR_ori, - p2i(lir->ins2(LIR_andp, v_ins, INS_CONSTWORD(JSVAL_INT))), - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, v_ins, - INS_CONSTWORD(JSVAL_TAGMASK)), - INS_CONSTWORD(JSVAL_DOUBLE)))), - exit); - LIns* args[] = { v_ins }; - return lir->insCall(&js_UnboxDouble_ci, args); - } - switch (JSVAL_TAG(v)) { - case JSVAL_SPECIAL: - if (JSVAL_IS_VOID(v)) { - guard(true, lir->ins2(LIR_eqp, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit); - return INS_VOID(); - } - if (JSVAL_IS_HOLE(v)) { - guard(true, lir->ins2(LIR_eqp, v_ins, INS_CONSTWORD(JSVAL_HOLE)), exit); - return INS_HOLE(); - } - guard(true, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, v_ins, INS_CONSTWORD(JSVAL_TAGMASK)), - INS_CONSTWORD(JSVAL_SPECIAL)), - exit); - JS_ASSERT(!v_ins->isImmP()); - guard(false, lir->ins2(LIR_eqp, v_ins, INS_CONSTWORD(JSVAL_VOID)), exit); - return p2i(lir->ins2ImmI(LIR_rshup, v_ins, JSVAL_TAGBITS)); + JS_STATIC_ASSERT(JSID_TYPE_STRING == 0); + return id_ins; +} - case JSVAL_OBJECT: - if (JSVAL_IS_NULL(v)) { - // JSVAL_NULL maps to type TT_NULL, so insist that v_ins == 0 here. - guard(true, lir->insEqP_0(v_ins), exit); - } else { - guard(false, lir->insEqP_0(v_ins), exit); - guard(true, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, v_ins, INS_CONSTWORD(JSVAL_TAGMASK)), - INS_CONSTWORD(JSVAL_OBJECT)), - exit); - - if (JSVAL_TO_OBJECT(v)->isFunction()) - guardClass(v_ins, &js_FunctionClass, exit, ACC_OTHER); - else - guardNotClass(v_ins, &js_FunctionClass, exit, ACC_OTHER); - } - return v_ins; - - default: - JS_ASSERT(JSVAL_TAG(v) == JSVAL_STRING); - guard(true, - lir->ins2(LIR_eqp, - lir->ins2(LIR_andp, v_ins, INS_CONSTWORD(JSVAL_TAGMASK)), - INS_CONSTWORD(JSVAL_STRING)), - exit); - return lir->ins2(LIR_andp, v_ins, addName(lir->insImmWord(~JSVAL_TAGMASK), - "~JSVAL_TAGMASK")); - } +LIns * +TraceRecorder::unbox_int_id(LIns *id_ins) +{ + return lir->ins2ImmI(LIR_rshi, p2i(id_ins), 1); } JS_REQUIRES_STACK RecordingStatus @@ -9501,11 +9979,11 @@ TraceRecorder::getThis(LIns*& this_ins) /* * JSStackFrame::getThisObject updates cx->fp->argv[-1], so sample it into 'original' first. */ - jsval original = JSVAL_NULL; + Value original = NullValue(); if (cx->fp->argv) { original = cx->fp->argv[-1]; - if (!JSVAL_IS_PRIMITIVE(original)) { - if (JSVAL_TO_OBJECT(original)->hasClass(&js_WithClass)) + if (!original.isPrimitive()) { + if (original.toObject().hasClass(&js_WithClass)) RETURN_STOP("can't trace getThis on With object"); guardNotClass(get(&cx->fp->argv[-1]), &js_WithClass, snapshot(MISMATCH_EXIT), ACC_OTHER); @@ -9528,8 +10006,8 @@ TraceRecorder::getThis(LIns*& this_ins) return RECORD_CONTINUE; } - jsval& thisv = cx->fp->argv[-1]; - JS_ASSERT(JSVAL_IS_OBJECT(thisv)); + Value& thisv = cx->fp->argv[-1]; + JS_ASSERT(thisv.isObject()); /* * Traces type-specialize between null and objects, so if we currently see @@ -9539,13 +10017,13 @@ TraceRecorder::getThis(LIns*& this_ins) * JSStackFrame::getThisObject, since it updates the interpreter's copy of * argv[-1]. */ - JSClass* clasp = NULL; - if (JSVAL_IS_NULL(original) || - (((clasp = JSVAL_TO_OBJECT(original)->getClass()) == &js_CallClass) || + Class* clasp = NULL; + if (original.isNull() || + (((clasp = original.toObject().getClass()) == &js_CallClass) || (clasp == &js_BlockClass))) { if (clasp) guardClass(get(&thisv), clasp, snapshot(BRANCH_EXIT), ACC_OTHER); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(thisv)); + JS_ASSERT(!thisv.isPrimitive()); if (thisObj != globalObj) RETURN_STOP("global object was wrapped while recording"); this_ins = INS_CONSTOBJ(thisObj); @@ -9571,11 +10049,10 @@ TraceRecorder::getThis(LIns*& this_ins) JS_REQUIRES_STACK void -TraceRecorder::guardClassHelper(bool cond, LIns* obj_ins, JSClass* clasp, VMSideExit* exit, +TraceRecorder::guardClassHelper(bool cond, LIns* obj_ins, Class* clasp, VMSideExit* exit, AccSet accSet) { - LIns* class_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, classword), accSet); - class_ins = lir->ins2(LIR_andp, class_ins, INS_CONSTWORD(~JSSLOT_CLASS_MASK_BITS)); + LIns* class_ins = lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, clasp), accSet); #ifdef JS_JIT_SPEW char namebuf[32]; @@ -9587,13 +10064,13 @@ TraceRecorder::guardClassHelper(bool cond, LIns* obj_ins, JSClass* clasp, VMSide } JS_REQUIRES_STACK void -TraceRecorder::guardClass(LIns* obj_ins, JSClass* clasp, VMSideExit* exit, AccSet accSet) +TraceRecorder::guardClass(LIns* obj_ins, Class* clasp, VMSideExit* exit, AccSet accSet) { guardClassHelper(true, obj_ins, clasp, exit, accSet); } JS_REQUIRES_STACK void -TraceRecorder::guardNotClass(LIns* obj_ins, JSClass* clasp, VMSideExit* exit, AccSet accSet) +TraceRecorder::guardNotClass(LIns* obj_ins, Class* clasp, VMSideExit* exit, AccSet accSet) { guardClassHelper(false, obj_ins, clasp, exit, accSet); } @@ -9645,13 +10122,13 @@ TraceRecorder::guardPrototypeHasNoIndexedProperties(JSObject* obj, LIns* obj_ins * method. Several imacros require this. */ JS_REQUIRES_STACK RecordingStatus -TraceRecorder::guardNativeConversion(jsval& v) +TraceRecorder::guardNativeConversion(Value& v) { - JSObject* obj = JSVAL_TO_OBJECT(v); + JSObject* obj = &v.toObject(); LIns* obj_ins = get(&v); - JSConvertOp convert = obj->getClass()->convert; - if (convert != JS_ConvertStub && convert != js_TryValueOf) + ConvertOp convert = obj->getClass()->convert; + if (convert != Valueify(JS_ConvertStub) && convert != js_TryValueOf) RETURN_STOP("operand has convert hook"); VMSideExit* exit = snapshot(BRANCH_EXIT); @@ -9682,8 +10159,8 @@ TraceRecorder::clearFrameSlotsFromTracker(Tracker& which, JSStackFrame* fp, unsi * we have to make sure we map those in to the cache with the right * offsets. */ - jsval* vp; - jsval* vpstop; + Value* vp; + Value* vpstop; /* * Duplicate native stack layout computation: see VisitFrameSlots header comment. @@ -9747,17 +10224,16 @@ TraceRecorder::putActivationObjects() LIns* args_ins; if (nargs) { - args_ins = lir->insAlloc(sizeof(jsval) * nargs); + args_ins = lir->insAlloc(sizeof(Value) * nargs); for (int i = 0; i < nargs; ++i) { - LIns* arg_ins = box_jsval(cx->fp->argv[i], get(&cx->fp->argv[i])); - lir->insStore(arg_ins, args_ins, i * sizeof(jsval), ACC_OTHER); + box_value_into(cx->fp->argv[i], get(&cx->fp->argv[i]), args_ins, i * sizeof(Value), ACC_OTHER); } } else { args_ins = INS_CONSTPTR(0); } if (have_args) { - LIns* argsobj_ins = get(&cx->fp->argsobj); + LIns* argsobj_ins = getFrameObjPtr(&cx->fp->argsobj); LIns* args[] = { args_ins, argsobj_ins, cx_ins }; lir->insCall(&js_PutArguments_ci, args); } @@ -9766,16 +10242,15 @@ TraceRecorder::putActivationObjects() int nslots = cx->fp->fun->countVars(); LIns* slots_ins; if (nslots) { - slots_ins = lir->insAlloc(sizeof(jsval) * nslots); + slots_ins = lir->insAlloc(sizeof(Value) * nslots); for (int i = 0; i < nslots; ++i) { - LIns* slot_ins = box_jsval(cx->fp->slots()[i], get(&cx->fp->slots()[i])); - lir->insStore(slot_ins, slots_ins, i * sizeof(jsval), ACC_OTHER); + box_value_into(cx->fp->slots()[i], get(&cx->fp->slots()[i]), slots_ins, i * sizeof(Value), ACC_OTHER); } } else { slots_ins = INS_CONSTPTR(0); } - LIns* scopeChain_ins = get(&cx->fp->scopeChainVal); + LIns* scopeChain_ins = getFrameObjPtr(&cx->fp->scopeChain); LIns* args[] = { slots_ins, INS_CONST(nslots), args_ins, INS_CONST(cx->fp->fun->nargs), scopeChain_ins, cx_ins }; lir->insCall(&js_PutCallObjectOnTrace_ci, args); @@ -9823,7 +10298,7 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount) debug_only_print0(LC_TMTracer, "----\n"); } ) - LIns* void_ins = INS_VOID(); + LIns* void_ins = INS_UNDEFINED(); // Before we enter this frame, we need to clear out any dangling insns left // in the tracer. While we also clear when returning from a function, it is @@ -9838,15 +10313,15 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount) // This doesn't do layout arithmetic, but it must initialize in the tracker all the // slots defined as imported by VisitFrameSlots. - jsval* vp = &fp->argv[fp->argc]; - jsval* vpstop = vp + ptrdiff_t(fp->fun->nargs) - ptrdiff_t(fp->argc); + Value* vp = &fp->argv[fp->argc]; + Value* vpstop = vp + ptrdiff_t(fp->fun->nargs) - ptrdiff_t(fp->argc); for (; vp < vpstop; ++vp) { nativeFrameTracker.set(vp, NULL); set(vp, void_ins); } nativeFrameTracker.set(&fp->argsobj, NULL); - set(&fp->argsobj, INS_NULL()); + setFrameObjPtr(&fp->argsobj, INS_NULL()); nativeFrameTracker.set(&fp->scopeChain, NULL); vp = fp->slots(); @@ -9867,7 +10342,7 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount) if (cx->fp->fun && JSFUN_HEAVYWEIGHT_TEST(cx->fp->fun->flags)) { // We need to make sure every part of the frame is known to the tracker // before taking a snapshot. - set(&fp->scopeChainVal, INS_NULL()); + setFrameObjPtr(&fp->scopeChain, INS_NULL()); if (js_IsNamedLambda(cx->fp->fun)) RETURN_STOP_A("can't call named lambda heavyweight on trace"); @@ -9878,9 +10353,9 @@ TraceRecorder::record_EnterFrame(uintN& inlineCallCount) LIns* call_ins = lir->insCall(&js_CreateCallObjectOnTrace_ci, args); guard(false, lir->insEqP_0(call_ins), snapshot(OOM_EXIT)); - set(&fp->scopeChainVal, call_ins); + setFrameObjPtr(&fp->scopeChain, call_ins); } else { - set(&fp->scopeChainVal, scopeChain_ins); + setFrameObjPtr(&fp->scopeChain, scopeChain_ins); } /* @@ -9966,7 +10441,7 @@ TraceRecorder::record_LeaveFrame() // LeaveFrame gets called after the interpreter popped the frame and // stored rval, so cx->fp not cx->fp->down, and -1 not 0. - atoms = FrameAtomBase(cx, cx->fp); + updateAtoms(); set(&stackval(-1), rval_ins); return ARECORD_CONTINUE; } @@ -9974,21 +10449,20 @@ TraceRecorder::record_LeaveFrame() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_PUSH() { - stack(0, INS_VOID()); + stack(0, INS_UNDEFINED()); return ARECORD_CONTINUE; } JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_POPV() { - jsval& rval = stackval(-1); - LIns *rval_ins = box_jsval(rval, get(&rval)); + Value& rval = stackval(-1); // Store it in cx->fp->rval. NB: Tricky dependencies. cx->fp is the right // frame because POPV appears only in global and eval code and we don't // trace JSOP_EVAL or leaving the frame where tracing started. LIns *fp_ins = lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp), ACC_OTHER); - lir->insStore(rval_ins, fp_ins, offsetof(JSStackFrame, rval), ACC_OTHER); + box_value_into(rval, get(&rval), fp_ins, offsetof(JSStackFrame, rval), ACC_OTHER); return ARECORD_CONTINUE; } @@ -10021,9 +10495,9 @@ TraceRecorder::record_JSOP_RETURN() putActivationObjects(); /* If we inlined this function call, make the return value available to the caller code. */ - jsval& rval = stackval(-1); + Value& rval = stackval(-1); JSStackFrame *fp = cx->fp; - if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && JSVAL_IS_PRIMITIVE(rval)) { + if ((cx->fp->flags & JSFRAME_CONSTRUCTING) && rval.isPrimitive()) { JS_ASSERT(fp->thisv == fp->argv[-1]); rval_ins = get(&fp->argv[-1]); } else { @@ -10093,7 +10567,7 @@ TraceRecorder::record_JSOP_ARGUMENTS() if (cx->fp->flags & JSFRAME_OVERRIDE_ARGS) RETURN_STOP_A("Can't trace |arguments| if |arguments| is assigned to"); - LIns* a_ins = get(&cx->fp->argsobj); + LIns* a_ins = getFrameObjPtr(&cx->fp->argsobj); LIns* args_ins; LIns* callee_ins = get(&cx->fp->argv[-2]); if (a_ins->isImmP()) { @@ -10102,7 +10576,7 @@ TraceRecorder::record_JSOP_ARGUMENTS() } else { // Generate LIR to create arguments only if it has not already been created. - LIns* mem_ins = lir->insAlloc(sizeof(jsval)); + LIns* mem_ins = lir->insAlloc(sizeof(JSObject *)); LIns* br1 = lir->insBranch(LIR_jt, lir->insEqP_0(a_ins), NULL); lir->insStore(a_ins, mem_ins, 0, ACC_OTHER); @@ -10121,7 +10595,7 @@ TraceRecorder::record_JSOP_ARGUMENTS() } stack(0, args_ins); - set(&cx->fp->argsobj, args_ins); + setFrameObjPtr(&cx->fp->argsobj, args_ins); return ARECORD_CONTINUE; } @@ -10143,8 +10617,8 @@ TraceRecorder::record_JSOP_DUP2() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_SWAP() { - jsval& l = stackval(-2); - jsval& r = stackval(-1); + Value& l = stackval(-2); + Value& r = stackval(-1); LIns* l_ins = get(&l); LIns* r_ins = get(&r); set(&r, l_ins); @@ -10155,9 +10629,9 @@ TraceRecorder::record_JSOP_SWAP() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_PICK() { - jsval* sp = cx->regs->sp; + Value* sp = cx->regs->sp; jsint n = cx->regs->pc[1]; - JS_ASSERT(sp - (n+1) >= StackBase(cx->fp)); + JS_ASSERT(sp - (n+1) >= cx->fp->base()); LIns* top = get(sp - (n+1)); for (jsint i = 0; i < n; ++i) set(sp - (n+1) + i, get(sp - n + i)); @@ -10246,23 +10720,23 @@ TraceRecorder::record_JSOP_URSH() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_ADD() { - jsval& r = stackval(-1); - jsval& l = stackval(-2); + Value& r = stackval(-1); + Value& l = stackval(-2); - if (!JSVAL_IS_PRIMITIVE(l)) { + if (!l.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(l)); - if (!JSVAL_IS_PRIMITIVE(r)) { + if (!r.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(r)); return InjectStatus(callImacro(add_imacros.obj_obj)); } return InjectStatus(callImacro(add_imacros.obj_any)); } - if (!JSVAL_IS_PRIMITIVE(r)) { + if (!r.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(r)); return InjectStatus(callImacro(add_imacros.any_obj)); } - if (JSVAL_IS_STRING(l) || JSVAL_IS_STRING(r)) { + if (l.isString() || r.isString()) { LIns* args[] = { stringify(r), stringify(l), cx_ins }; LIns* concat = lir->insCall(&js_ConcatStrings_ci, args); guard(false, lir->insEqP_0(concat), OOM_EXIT); @@ -10300,22 +10774,22 @@ TraceRecorder::record_JSOP_MOD() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_NOT() { - jsval& v = stackval(-1); - if (JSVAL_IS_SPECIAL(v)) { + Value& v = stackval(-1); + if (v.isBoolean() || v.isUndefined()) { set(&v, lir->insEqI_0(lir->ins2ImmI(LIR_eqi, get(&v), 1))); return ARECORD_CONTINUE; } - if (isNumber(v)) { + if (v.isNumber()) { LIns* v_ins = get(&v); set(&v, lir->ins2(LIR_ori, lir->ins2(LIR_eqd, v_ins, lir->insImmD(0)), lir->insEqI_0(lir->ins2(LIR_eqd, v_ins, v_ins)))); return ARECORD_CONTINUE; } - if (JSVAL_TAG(v) == JSVAL_OBJECT) { + if (v.isObjectOrNull()) { set(&v, lir->insEqP_0(get(&v))); return ARECORD_CONTINUE; } - JS_ASSERT(JSVAL_IS_STRING(v)); + JS_ASSERT(v.isString()); set(&v, lir->insEqP_0(lir->insLoad(LIR_ldp, get(&v), offsetof(JSString, mLength), ACC_OTHER))); return ARECORD_CONTINUE; @@ -10330,14 +10804,14 @@ TraceRecorder::record_JSOP_BITNOT() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_NEG() { - jsval& v = stackval(-1); + Value& v = stackval(-1); - if (!JSVAL_IS_PRIMITIVE(v)) { + if (!v.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(v)); return InjectStatus(callImacro(unary_imacros.sign)); } - if (isNumber(v)) { + if (v.isNumber()) { LIns* a = get(&v); /* @@ -10348,9 +10822,9 @@ TraceRecorder::record_JSOP_NEG() if (oracle && !oracle->isInstructionUndemotable(cx->regs->pc) && isPromoteInt(a) && - (!JSVAL_IS_INT(v) || JSVAL_TO_INT(v) != 0) && - (!JSVAL_IS_DOUBLE(v) || !JSDOUBLE_IS_NEGZERO(*JSVAL_TO_DOUBLE(v))) && - -asNumber(v) == (int)-asNumber(v)) + (!v.isInt32() || v.toInt32() != 0) && + (!v.isDouble() || !JSDOUBLE_IS_NEGZERO(v.toDouble())) && + -v.toNumber() == (int)-v.toNumber()) { VMSideExit* exit = snapshot(OVERFLOW_EXIT); a = guard_xov(LIR_subi, lir->insImmI(0), demote(lir, a), exit); @@ -10366,24 +10840,24 @@ TraceRecorder::record_JSOP_NEG() return ARECORD_CONTINUE; } - if (JSVAL_IS_NULL(v)) { + if (v.isNull()) { set(&v, lir->insImmD(-0.0)); return ARECORD_CONTINUE; } - if (JSVAL_IS_VOID(v)) { + if (v.isUndefined()) { set(&v, lir->insImmD(js_NaN)); return ARECORD_CONTINUE; } - if (JSVAL_IS_STRING(v)) { + if (v.isString()) { LIns* args[] = { get(&v), cx_ins }; set(&v, lir->ins1(LIR_negd, lir->insCall(&js_StringToNumber_ci, args))); return ARECORD_CONTINUE; } - JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + JS_ASSERT(v.isBoolean()); set(&v, lir->ins1(LIR_negd, i2d(get(&v)))); return ARECORD_CONTINUE; } @@ -10391,32 +10865,32 @@ TraceRecorder::record_JSOP_NEG() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_POS() { - jsval& v = stackval(-1); + Value& v = stackval(-1); - if (!JSVAL_IS_PRIMITIVE(v)) { + if (!v.isPrimitive()) { CHECK_STATUS_A(guardNativeConversion(v)); return InjectStatus(callImacro(unary_imacros.sign)); } - if (isNumber(v)) + if (v.isNumber()) return ARECORD_CONTINUE; - if (JSVAL_IS_NULL(v)) { + if (v.isNull()) { set(&v, lir->insImmD(0)); return ARECORD_CONTINUE; } - if (JSVAL_IS_VOID(v)) { + if (v.isUndefined()) { set(&v, lir->insImmD(js_NaN)); return ARECORD_CONTINUE; } - if (JSVAL_IS_STRING(v)) { + if (v.isString()) { LIns* args[] = { get(&v), cx_ins }; set(&v, lir->insCall(&js_StringToNumber_ci, args)); return ARECORD_CONTINUE; } - JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + JS_ASSERT(v.isBoolean()); set(&v, i2d(get(&v))); return ARECORD_CONTINUE; } @@ -10432,7 +10906,7 @@ TraceRecorder::record_JSOP_PRIMTOP() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_OBJTOP() { - jsval& v = stackval(-1); + Value& v = stackval(-1); RETURN_IF_XML_A(v); return ARECORD_CONTINUE; } @@ -10442,13 +10916,13 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins) { // ctor must be a function created via js_InitClass. #ifdef DEBUG - JSClass *clasp = FUN_CLASP(GET_FUNCTION_PRIVATE(cx, ctor)); + Class *clasp = FUN_CLASP(GET_FUNCTION_PRIVATE(cx, ctor)); JS_ASSERT(clasp); TraceMonitor &localtm = JS_TRACE_MONITOR(cx); #endif - jsval pval; + Value pval; if (!ctor->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &pval)) RETURN_ERROR("error getting prototype from constructor"); @@ -10467,8 +10941,8 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins) // Since ctor was built by js_InitClass, we can assert (rather than check) // that pval is usable. - JS_ASSERT(!JSVAL_IS_PRIMITIVE(pval)); - JSObject *proto = JSVAL_TO_OBJECT(pval); + JS_ASSERT(!pval.isPrimitive()); + JSObject *proto = &pval.toObject(); JS_ASSERT_IF(clasp != &js_ArrayClass, proto->scope()->emptyScope->clasp == clasp); proto_ins = INS_CONSTOBJ(proto); @@ -10506,11 +10980,11 @@ TraceRecorder::getClassPrototype(JSProtoKey key, LIns*& proto_ins) #define IGNORE_NATIVE_CALL_COMPLETE_CALLBACK ((JSSpecializedNative*)1) RecordingStatus -TraceRecorder::newString(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval) +TraceRecorder::newString(JSObject* ctor, uint32 argc, Value* argv, Value* rval) { JS_ASSERT(argc == 1); - if (!JSVAL_IS_PRIMITIVE(argv[0])) { + if (!argv[0].isPrimitive()) { CHECK_STATUS(guardNativeConversion(argv[0])); return callImacro(new_imacros.String); } @@ -10528,7 +11002,7 @@ TraceRecorder::newString(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval) } RecordingStatus -TraceRecorder::newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval) +TraceRecorder::newArray(JSObject* ctor, uint32 argc, Value* argv, Value* rval) { LIns *proto_ins; CHECK_STATUS(getClassPrototype(ctor, proto_ins)); @@ -10539,7 +11013,7 @@ TraceRecorder::newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval) LIns *args[] = { proto_ins, cx_ins }; arr_ins = lir->insCall(&js_NewEmptyArray_ci, args); guard(false, lir->insEqP_0(arr_ins), OOM_EXIT); - } else if (argc == 1 && JSVAL_IS_NUMBER(argv[0])) { + } else if (argc == 1 && argv[0].isNumber()) { // arr_ins = js_NewEmptyArray(cx, Array.prototype, length) LIns *args[] = { d2i(get(argv)), proto_ins, cx_ins }; // FIXME: is this 64-bit safe? arr_ins = lir->insCall(&js_NewEmptyArrayWithLength_ci, args); @@ -10553,12 +11027,11 @@ TraceRecorder::newArray(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval) // arr->dslots[i] = box_jsval(vp[i]); for i in 0..argc LIns *dslots_ins = NULL; for (uint32 i = 0; i < argc && !outOfMemory(); i++) { - LIns *elt_ins = box_jsval(argv[i], get(&argv[i])); - stobj_set_dslot(arr_ins, i, dslots_ins, elt_ins); + stobj_set_dslot(arr_ins, i, dslots_ins, argv[i], get(&argv[i])); } if (argc > 0) - stobj_set_fslot(arr_ins, JSObject::JSSLOT_DENSE_ARRAY_COUNT, INS_CONST(argc)); + set_array_fslot(arr_ins, JSObject::JSSLOT_DENSE_ARRAY_COUNT, argc); } set(rval, arr_ins); @@ -10594,21 +11067,16 @@ TraceRecorder::propagateFailureToBuiltinStatus(LIns* ok_ins, LIns*& status_ins) JS_REQUIRES_STACK void TraceRecorder::emitNativePropertyOp(JSScope* scope, JSScopeProperty* sprop, LIns* obj_ins, - bool setflag, LIns* boxed_ins) + bool setflag, LIns* addr_boxed_val_ins) { + JS_ASSERT(addr_boxed_val_ins->isop(LIR_allocp)); JS_ASSERT(setflag ? !sprop->hasSetterValue() : !sprop->hasGetterValue()); JS_ASSERT(setflag ? !sprop->hasDefaultSetter() : !sprop->hasDefaultGetterOrIsMethod()); enterDeepBailCall(); - // It is unsafe to pass the address of an object slot as the out parameter, - // because the getter or setter could end up resizing the object's dslots. - // Instead, use a word of stack and root it in nativeVp. - LIns* vp_ins = lir->insAlloc(sizeof(jsval)); - lir->insStore(vp_ins, lirbuf->state, offsetof(TracerState, nativeVp), ACC_OTHER); + lir->insStore(addr_boxed_val_ins, lirbuf->state, offsetof(TracerState, nativeVp), ACC_OTHER); lir->insStore(INS_CONST(1), lirbuf->state, offsetof(TracerState, nativeVpLen), ACC_OTHER); - if (setflag) - lir->insStore(boxed_ins, vp_ins, 0, ACC_OTHER); CallInfo* ci = new (traceAlloc()) CallInfo(); ci->_address = uintptr_t(setflag ? sprop->setterOp() : sprop->getterOp()); @@ -10619,7 +11087,7 @@ TraceRecorder::emitNativePropertyOp(JSScope* scope, JSScopeProperty* sprop, LIns #ifdef DEBUG ci->_name = "JSPropertyOp"; #endif - LIns* args[] = { vp_ins, INS_CONSTVAL(SPROP_USERID(sprop)), obj_ins, cx_ins }; + LIns* args[] = { addr_boxed_val_ins, INS_CONSTID(SPROP_USERID(sprop)), obj_ins, cx_ins }; LIns* ok_ins = lir->insCall(ci, args); // Cleanup. Immediately clear nativeVp before we might deep bail. @@ -10634,9 +11102,6 @@ TraceRecorder::emitNativePropertyOp(JSScope* scope, JSScopeProperty* sprop, LIns (int) offsetof(TracerState, builtinStatus), ACC_OTHER); propagateFailureToBuiltinStatus(ok_ins, status_ins); guard(true, lir->insEqI_0(status_ins), STATUS_EXIT); - - // Re-load the value--but this is currently unused, so commented out. - //boxed_ins = lir->insLoad(LIR_ldp, vp_ins, 0, ACC_OTHER); } JS_REQUIRES_STACK RecordingStatus @@ -10653,10 +11118,10 @@ TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[], // If we are calling a slow native, add information to the side exit // for SynthesizeSlowNativeFrame. VMSideExit* exit = enterDeepBailCall(); - JSObject* funobj = JSVAL_TO_OBJECT(stackval(0 - (2 + argc))); + JSObject* funobj = &stackval(0 - (2 + argc)).toObject(); if (FUN_SLOW_NATIVE(GET_FUNCTION_PRIVATE(cx, funobj))) { exit->setNativeCallee(funobj, constructing); - tree->gcthings.addUnique(OBJECT_TO_JSVAL(funobj)); + tree->gcthings.addUnique(ObjectValue(*funobj)); } } @@ -10675,8 +11140,8 @@ TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[], res_ins = lir->ins1(LIR_i2d, res_ins); guard(false, lir->ins2(LIR_ltd, res_ins, lir->insImmD(0)), OOM_EXIT); break; - case FAIL_VOID: - guard(false, lir->ins2ImmI(LIR_eqi, res_ins, JSVAL_TO_SPECIAL(JSVAL_VOID)), OOM_EXIT); + case FAIL_NEITHER: + guard(false, lir->ins2ImmI(LIR_eqi, res_ins, JS_NEITHER), OOM_EXIT); break; default:; } @@ -10704,8 +11169,8 @@ TraceRecorder::callSpecializedNative(JSNativeTraceInfo *trcinfo, uintN argc, JSStackFrame* const fp = cx->fp; jsbytecode *pc = cx->regs->pc; - jsval& fval = stackval(0 - (2 + argc)); - jsval& tval = stackval(0 - (1 + argc)); + Value& fval = stackval(0 - (2 + argc)); + Value& tval = stackval(0 - (1 + argc)); LIns* this_ins = get(&tval); @@ -10735,17 +11200,17 @@ TraceRecorder::callSpecializedNative(JSNativeTraceInfo *trcinfo, uintN argc, if (argtype == 'C') { *argp = cx_ins; } else if (argtype == 'T') { /* this, as an object */ - if (JSVAL_IS_PRIMITIVE(tval)) + if (tval.isPrimitive()) goto next_specialization; *argp = this_ins; } else if (argtype == 'S') { /* this, as a string */ - if (!JSVAL_IS_STRING(tval)) + if (!tval.isString()) goto next_specialization; *argp = this_ins; } else if (argtype == 'f') { - *argp = INS_CONSTOBJ(JSVAL_TO_OBJECT(fval)); + *argp = INS_CONSTOBJ(&fval.toObject()); } else if (argtype == 'p') { - CHECK_STATUS(getClassPrototype(JSVAL_TO_OBJECT(fval), *argp)); + CHECK_STATUS(getClassPrototype(&fval.toObject(), *argp)); } else if (argtype == 'R') { *argp = INS_CONSTPTR(cx->runtime); } else if (argtype == 'P') { @@ -10757,7 +11222,7 @@ TraceRecorder::callSpecializedNative(JSNativeTraceInfo *trcinfo, uintN argc, else *argp = INS_CONSTPTR(pc); } else if (argtype == 'D') { /* this, as a number */ - if (!isNumber(tval)) + if (!tval.isNumber()) goto next_specialization; *argp = this_ins; } else { @@ -10767,29 +11232,29 @@ TraceRecorder::callSpecializedNative(JSNativeTraceInfo *trcinfo, uintN argc, } for (i = knownargc; i--; ) { - jsval& arg = stackval(0 - (i + 1)); + Value& arg = stackval(0 - (i + 1)); *argp = get(&arg); argtype = sn->argtypes[i]; if (argtype == 'd' || argtype == 'i') { - if (!isNumber(arg)) + if (!arg.isNumber()) goto next_specialization; if (argtype == 'i') *argp = d2i(*argp); } else if (argtype == 'o') { - if (JSVAL_IS_PRIMITIVE(arg)) + if (arg.isPrimitive()) goto next_specialization; } else if (argtype == 's') { - if (!JSVAL_IS_STRING(arg)) + if (!arg.isString()) goto next_specialization; } else if (argtype == 'r') { if (!VALUE_IS_REGEXP(cx, arg)) goto next_specialization; } else if (argtype == 'f') { - if (!VALUE_IS_FUNCTION(cx, arg)) + if (!IsFunctionObject(arg)) goto next_specialization; } else if (argtype == 'v') { - *argp = box_jsval(arg, *argp); + *argp = box_value_for_native_call(arg, *argp); } else { goto next_specialization; } @@ -10813,14 +11278,14 @@ TraceRecorder::callNative(uintN argc, JSOp mode) JS_ASSERT(mode == JSOP_CALL || mode == JSOP_NEW || mode == JSOP_APPLY); - jsval* vp = &stackval(0 - (2 + argc)); - JSObject* funobj = JSVAL_TO_OBJECT(vp[0]); + Value* vp = &stackval(0 - (2 + argc)); + JSObject* funobj = &vp[0].toObject(); JSFunction* fun = GET_FUNCTION_PRIVATE(cx, funobj); - JSFastNative native = (JSFastNative)fun->u.n.native; + FastNative native = (FastNative)fun->u.n.native; switch (argc) { case 1: - if (isNumber(vp[2]) && + if (vp[2].isNumber() && (native == js_math_ceil || native == js_math_floor || native == js_math_round)) { LIns* a = get(&vp[2]); if (isPromote(a)) { @@ -10832,7 +11297,7 @@ TraceRecorder::callNative(uintN argc, JSOp mode) break; case 2: - if (isNumber(vp[2]) && isNumber(vp[3]) && + if (vp[2].isNumber() && vp[3].isNumber() && (native == js_math_min || native == js_math_max)) { LIns* a = get(&vp[2]); LIns* b = get(&vp[3]); @@ -10874,15 +11339,15 @@ TraceRecorder::callNative(uintN argc, JSOp mode) uintN vplen = 2 + JS_MAX(argc, unsigned(FUN_MINARGS(fun))); if (!(fun->flags & JSFUN_FAST_NATIVE)) vplen++; // slow native return value slot - LIns* invokevp_ins = lir->insAlloc(vplen * sizeof(jsval)); + LIns* invokevp_ins = lir->insAlloc(vplen * sizeof(Value)); // vp[0] is the callee. - lir->insStore(INS_CONSTVAL(OBJECT_TO_JSVAL(funobj)), invokevp_ins, 0, ACC_OTHER); + box_value_into(vp[0], INS_CONSTOBJ(funobj), invokevp_ins, 0, ACC_OTHER); // Calculate |this|. LIns* this_ins; if (mode == JSOP_NEW) { - JSClass* clasp = fun->u.n.clasp; + Class* clasp = fun->u.n.clasp; JS_ASSERT(clasp != &js_SlowArrayClass); if (!clasp) clasp = &js_ObjectClass; @@ -10902,10 +11367,9 @@ TraceRecorder::callNative(uintN argc, JSOp mode) args[2] = cx_ins; newobj_ins = lir->insCall(&js_NewInstance_ci, args); guard(false, lir->insEqP_0(newobj_ins), OOM_EXIT); - this_ins = newobj_ins; /* boxing an object is a no-op */ + this_ins = newobj_ins; } else if (JSFUN_BOUND_METHOD_TEST(fun->flags)) { - /* |funobj| was rooted above already. */ - this_ins = INS_CONSTWORD(OBJECT_TO_JSVAL(funobj->getParent())); + this_ins = INS_CONSTOBJ(funobj->getParent()); } else { this_ins = get(&vp[1]); @@ -10916,15 +11380,15 @@ TraceRecorder::callNative(uintN argc, JSOp mode) * own object so it's guaranteed to have a valid 'this' value. */ if (!(fun->flags & JSFUN_FAST_NATIVE)) { - if (JSVAL_IS_NULL(vp[1])) { - JSObject* thisObj = js_ComputeThis(cx, vp + 2); + if (vp[1].isNull()) { + JSObject* thisObj = ComputeThisFromVp(cx, vp + 2); if (!thisObj) RETURN_ERROR("error in js_ComputeGlobalThis"); this_ins = INS_CONSTOBJ(thisObj); - } else if (!JSVAL_IS_OBJECT(vp[1])) { + } else if (!vp[1].isObject()) { RETURN_STOP("slow native(primitive, args)"); } else { - if (JSVAL_TO_OBJECT(vp[1])->hasClass(&js_WithClass)) + if (vp[1].toObject().hasClass(&js_WithClass)) RETURN_STOP("can't trace slow native invocation on With object"); guardNotClass(this_ins, &js_WithClass, snapshot(MISMATCH_EXIT), ACC_READONLY); @@ -10933,15 +11397,12 @@ TraceRecorder::callNative(uintN argc, JSOp mode) this_ins, avmplus::AvmCore::use_cmov()); } } - this_ins = box_jsval(vp[1], this_ins); } - lir->insStore(this_ins, invokevp_ins, 1 * sizeof(jsval), ACC_OTHER); + box_value_into(vp[1], this_ins, invokevp_ins, 1 * sizeof(Value), ACC_OTHER); // Populate argv. for (uintN n = 2; n < 2 + argc; n++) { - LIns* i = box_jsval(vp[n], get(&vp[n])); - lir->insStore(i, invokevp_ins, n * sizeof(jsval), ACC_OTHER); - + box_value_into(vp[n], get(&vp[n]), invokevp_ins, n * sizeof(Value), ACC_OTHER); // For a very long argument list we might run out of LIR space, so // check inside the loop. if (outOfMemory()) @@ -10950,10 +11411,8 @@ TraceRecorder::callNative(uintN argc, JSOp mode) // Populate extra slots, including the return value slot for a slow native. if (2 + argc < vplen) { - LIns* undef_ins = INS_CONSTWORD(JSVAL_VOID); for (uintN n = 2 + argc; n < vplen; n++) { - lir->insStore(undef_ins, invokevp_ins, n * sizeof(jsval), ACC_OTHER); - + box_undefined_into(invokevp_ins, n * sizeof(Value), ACC_OTHER); if (outOfMemory()) RETURN_STOP("out of memory in extra slots"); } @@ -10970,10 +11429,10 @@ TraceRecorder::callNative(uintN argc, JSOp mode) args[2] = cx_ins; typesig = CallInfo::typeSig3(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P); } else { - int32_t offset = (vplen - 1) * sizeof(jsval); + int32_t offset = (vplen - 1) * sizeof(Value); native_rval_ins = lir->ins2(LIR_addp, invokevp_ins, INS_CONSTWORD(offset)); args[0] = native_rval_ins; - args[1] = lir->ins2(LIR_addp, invokevp_ins, INS_CONSTWORD(2 * sizeof(jsval))); + args[1] = lir->ins2(LIR_addp, invokevp_ins, INS_CONSTWORD(2 * sizeof(Value))); args[2] = lir->insImmI(argc); args[3] = this_ins; args[4] = cx_ins; @@ -11019,13 +11478,13 @@ TraceRecorder::callNative(uintN argc, JSOp mode) JS_REQUIRES_STACK RecordingStatus TraceRecorder::functionCall(uintN argc, JSOp mode) { - jsval& fval = stackval(0 - (2 + argc)); - JS_ASSERT(&fval >= StackBase(cx->fp)); + Value& fval = stackval(0 - (2 + argc)); + JS_ASSERT(&fval >= cx->fp->base()); - if (!VALUE_IS_FUNCTION(cx, fval)) + if (!IsFunctionObject(fval)) RETURN_STOP("callee is not a function"); - jsval& tval = stackval(0 - (1 + argc)); + Value& tval = stackval(0 - (1 + argc)); /* * If callee is not constant, it's a shapeless call and we have to guard @@ -11045,7 +11504,7 @@ TraceRecorder::functionCall(uintN argc, JSOp mode) * Bytecode sequences that push shapeless callees must guard on the callee * class being Function and the function being interpreted. */ - JSFunction* fun = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(fval)); + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &fval.toObject()); if (FUN_INTERPRETED(fun)) { if (mode == JSOP_NEW) { @@ -11058,14 +11517,14 @@ TraceRecorder::functionCall(uintN argc, JSOp mode) } if (FUN_SLOW_NATIVE(fun)) { - JSNative native = fun->u.n.native; - jsval* argv = &tval + 1; + Native native = fun->u.n.native; + Value* argv = &tval + 1; if (native == js_Array) - return newArray(JSVAL_TO_OBJECT(fval), argc, argv, &fval); + return newArray(&fval.toObject(), argc, argv, &fval); if (native == js_String && argc == 1) { if (mode == JSOP_NEW) - return newString(JSVAL_TO_OBJECT(fval), 1, argv, &fval); - if (!JSVAL_IS_PRIMITIVE(argv[0])) { + return newString(&fval.toObject(), 1, argv, &fval); + if (!argv[0].isPrimitive()) { CHECK_STATUS(guardNativeConversion(argv[0])); return callImacro(call_imacros.String); } @@ -11096,12 +11555,11 @@ JSBool JS_FASTCALL DeleteIntKey(JSContext* cx, JSObject* obj, int32 i) { LeaveTraceIfGlobalObject(cx, obj); - - jsval v = JSVAL_FALSE; + Value v = BooleanValue(false); jsid id = INT_TO_JSID(i); if (!obj->deleteProperty(cx, id, &v)) SetBuiltinError(cx); - return JSVAL_TO_BOOLEAN(v); + return v.toBoolean(); } JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, DeleteIntKey, CONTEXT, OBJECT, INT32, 0, ACC_STORE_ANY) @@ -11109,8 +11567,7 @@ JSBool JS_FASTCALL DeleteStrKey(JSContext* cx, JSObject* obj, JSString* str) { LeaveTraceIfGlobalObject(cx, obj); - - jsval v = JSVAL_FALSE; + Value v = BooleanValue(false); jsid id; /* @@ -11118,23 +11575,22 @@ DeleteStrKey(JSContext* cx, JSObject* obj, JSString* str) * jsatominlines.h) that helper early-returns if the computed property name * string is already atomized, and we are *not* on a perf-critical path! */ - if (!js_ValueToStringId(cx, STRING_TO_JSVAL(str), &id) || !obj->deleteProperty(cx, id, &v)) + if (!js_ValueToStringId(cx, StringValue(str), &id) || !obj->deleteProperty(cx, id, &v)) SetBuiltinError(cx); - return JSVAL_TO_BOOLEAN(v); + return v.toBoolean(); } JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, DeleteStrKey, CONTEXT, OBJECT, STRING, 0, ACC_STORE_ANY) JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_DELPROP() { - jsval& lval = stackval(-1); - if (JSVAL_IS_PRIMITIVE(lval)) + Value& lval = stackval(-1); + if (lval.isPrimitive()) RETURN_STOP_A("JSOP_DELPROP on primitive base expression"); - if (JSVAL_TO_OBJECT(lval) == globalObj) + if (&lval.toObject() == globalObj) RETURN_STOP_A("JSOP_DELPROP on global property"); JSAtom* atom = atoms[GET_INDEX(cx->regs->pc)]; - JS_ASSERT(ATOM_IS_STRING(atom)); enterDeepBailCall(); LIns* args[] = { INS_ATOM(atom), get(&lval), cx_ins }; @@ -11153,20 +11609,20 @@ TraceRecorder::record_JSOP_DELPROP() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_DELELEM() { - jsval& lval = stackval(-2); - if (JSVAL_IS_PRIMITIVE(lval)) + Value& lval = stackval(-2); + if (lval.isPrimitive()) RETURN_STOP_A("JSOP_DELELEM on primitive base expression"); - if (JSVAL_TO_OBJECT(lval) == globalObj) + if (&lval.toObject() == globalObj) RETURN_STOP_A("JSOP_DELELEM on global property"); - jsval& idx = stackval(-1); + Value& idx = stackval(-1); LIns* rval_ins; enterDeepBailCall(); - if (isInt32(idx)) { + if (hasInt32Repr(idx)) { LIns* args[] = { makeNumberInt32(get(&idx)), get(&lval), cx_ins }; rval_ins = lir->insCall(&DeleteIntKey_ci, args); - } else if (JSVAL_IS_STRING(idx)) { + } else if (idx.isString()) { LIns* args[] = { get(&idx), get(&lval), cx_ins }; rval_ins = lir->insCall(&DeleteStrKey_ci, args); } else { @@ -11186,23 +11642,23 @@ TraceRecorder::record_JSOP_DELELEM() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_TYPEOF() { - jsval& r = stackval(-1); + Value& r = stackval(-1); LIns* type; - if (JSVAL_IS_STRING(r)) { + if (r.isString()) { type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_STRING]); - } else if (isNumber(r)) { + } else if (r.isNumber()) { type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); - } else if (VALUE_IS_FUNCTION(cx, r)) { - type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_FUNCTION]); + } else if (r.isUndefined()) { + type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); + } else if (r.isBoolean()) { + type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_BOOLEAN]); + } else if (r.isNull()) { + type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_OBJECT]); } else { - LIns* args[] = { get(&r), cx_ins }; - if (JSVAL_IS_SPECIAL(r)) { - // We specialize identically for boolean and undefined. We must not have a hole here. - // Pass the unboxed type here, since TypeOfBoolean knows how to handle it. - JS_ASSERT(r == JSVAL_TRUE || r == JSVAL_FALSE || r == JSVAL_VOID); - type = lir->insCall(&js_TypeOfBoolean_ci, args); + if (r.toObject().isFunction()) { + type = INS_ATOM(cx->runtime->atomState.typeAtoms[JSTYPE_FUNCTION]); } else { - JS_ASSERT(JSVAL_TAG(r) == JSVAL_OBJECT); + LIns* args[] = { get(&r), cx_ins }; type = lir->insCall(&js_TypeOfObject_ci, args); } } @@ -11213,7 +11669,7 @@ TraceRecorder::record_JSOP_TYPEOF() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_VOID() { - stack(-1, INS_VOID()); + stack(-1, INS_UNDEFINED()); return ARECORD_CONTINUE; } @@ -11256,13 +11712,13 @@ TraceRecorder::record_JSOP_DECELEM() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::incName(jsint incr, bool pre) { - jsval* vp; + Value* vp; LIns* v_ins; LIns* v_after; NameResult nr; CHECK_STATUS_A(name(vp, v_ins, nr)); - jsval v = nr.tracked ? *vp : nr.v; + Value v = nr.tracked ? *vp : nr.v; CHECK_STATUS_A(incHelper(v, v_ins, v_after, incr)); LIns* v_result = pre ? v_after : v_ins; if (nr.tracked) { @@ -11325,11 +11781,11 @@ TraceRecorder::record_JSOP_GETPROP() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_SETPROP() { - jsval& l = stackval(-2); - if (JSVAL_IS_PRIMITIVE(l)) + Value& l = stackval(-2); + if (l.isPrimitive()) RETURN_STOP_A("primitive this for SETPROP"); - JSObject* obj = JSVAL_TO_OBJECT(l); + JSObject* obj = &l.toObject(); if (obj->map->ops->setProperty != js_SetProperty) RETURN_STOP_A("non-native JSObjectOps::setProperty"); return ARECORD_CONTINUE; @@ -11338,7 +11794,7 @@ TraceRecorder::record_JSOP_SETPROP() /* Emit a specialized, inlined copy of js_NativeSet. */ JS_REQUIRES_STACK RecordingStatus TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, - jsval v, LIns* v_ins) + const Value &v, LIns* v_ins) { JSScope* scope = obj->scope(); uint32 slot = sprop->slot; @@ -11363,14 +11819,9 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, */ JS_ASSERT(sprop->hasDefaultSetter() || slot == SPROP_INVALID_SLOT); - // Box the value to be stored, if necessary. - LIns* boxed_ins = NULL; - if (!sprop->hasDefaultSetter() || (slot != SPROP_INVALID_SLOT && obj != globalObj)) - boxed_ins = box_jsval(v, v_ins); - // Call the setter, if any. if (!sprop->hasDefaultSetter()) - emitNativePropertyOp(scope, sprop, obj_ins, true, boxed_ins); + emitNativePropertyOp(scope, sprop, obj_ins, true, box_value_into_alloc(v, v_ins)); // Store the value, if this property has a slot. if (slot != SPROP_INVALID_SLOT) { @@ -11382,7 +11833,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, set(&obj->getSlotRef(slot), v_ins); } else { LIns* dslots_ins = NULL; - stobj_set_slot(obj_ins, slot, dslots_ins, boxed_ins); + stobj_set_slot(obj_ins, slot, dslots_ins, v, v_ins); } } @@ -11392,16 +11843,16 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop, static JSBool FASTCALL MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - AutoValueRooter tvr(cx, funobj); + AutoObjectRooter tvr(cx, funobj); - return obj->scope()->methodWriteBarrier(cx, sprop, tvr.value()); + return obj->scope()->methodWriteBarrier(cx, sprop, ObjectValue(*tvr.object())); } JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, MethodWriteBarrier, CONTEXT, OBJECT, SCOPEPROP, OBJECT, 0, ACC_STORE_ANY) JS_REQUIRES_STACK RecordingStatus -TraceRecorder::setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* sprop, - jsval &v, LIns*& v_ins, bool isDefinitelyAtom) +TraceRecorder::setProp(Value &l, PropertyCacheEntry* entry, JSScopeProperty* sprop, + Value &v, LIns*& v_ins, bool isDefinitelyAtom) { if (entry == JS_NO_PROP_CACHE_FILL) RETURN_STOP("can't trace uncacheable property set"); @@ -11417,8 +11868,8 @@ TraceRecorder::setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* spr if (!sprop->writable()) RETURN_STOP("can't assign to readonly property"); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(l)); - JSObject* obj = JSVAL_TO_OBJECT(l); + JS_ASSERT(!l.isPrimitive()); + JSObject* obj = &l.toObject(); LIns* obj_ins = get(&l); JS_ASSERT_IF(entry->directHit(), obj->scope()->hasProperty(sprop)); @@ -11450,7 +11901,7 @@ TraceRecorder::setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* spr * this, because functions have distinct trace-type from other values and * branded-ness is implied by the shape, which we've already guarded on. */ - if (scope->brandedOrHasMethodBarrier() && VALUE_IS_FUNCTION(cx, v) && entry->directHit()) { + if (scope->brandedOrHasMethodBarrier() && IsFunctionObject(v) && entry->directHit()) { if (obj == globalObj) RETURN_STOP("can't trace function-valued property set in branded global scope"); @@ -11477,15 +11928,15 @@ TraceRecorder::setProp(jsval &l, PropertyCacheEntry* entry, JSScopeProperty* spr } JS_REQUIRES_STACK RecordingStatus -TraceRecorder::setUpwardTrackedVar(jsval* stackVp, jsval v, LIns* v_ins) +TraceRecorder::setUpwardTrackedVar(Value* stackVp, const Value &v, LIns* v_ins) { - TraceType stackT = determineSlotType(stackVp); - TraceType otherT = getCoercedType(v); + JSValueType stackT = determineSlotType(stackVp); + JSValueType otherT = getCoercedType(v); bool promote = true; if (stackT != otherT) { - if (stackT == TT_DOUBLE && otherT == TT_INT32 && isPromoteInt(v_ins)) + if (stackT == JSVAL_TYPE_DOUBLE && otherT == JSVAL_TYPE_INT32 && isPromoteInt(v_ins)) promote = false; else RETURN_STOP("can't trace this upvar mutation"); @@ -11498,7 +11949,7 @@ TraceRecorder::setUpwardTrackedVar(jsval* stackVp, jsval v, LIns* v_ins) JS_REQUIRES_STACK RecordingStatus TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty *sprop, - LIns *v_ins, jsval v) + LIns *v_ins, const Value &v) { // Set variables in on-trace-stack call objects by updating the tracker. JSStackFrame *fp = frameIfInRange(callobj); @@ -11506,14 +11957,14 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty if (sprop->setterOp() == SetCallArg) { JS_ASSERT(sprop->hasShortID()); uintN slot = uint16(sprop->shortid); - jsval *vp2 = &fp->argv[slot]; + Value *vp2 = &fp->argv[slot]; CHECK_STATUS(setUpwardTrackedVar(vp2, v, v_ins)); return RECORD_CONTINUE; } if (sprop->setterOp() == SetCallVar) { JS_ASSERT(sprop->hasShortID()); uintN slot = uint16(sprop->shortid); - jsval *vp2 = &fp->slots()[slot]; + Value *vp2 = &fp->slots()[slot]; CHECK_STATUS(setUpwardTrackedVar(vp2, v, v_ins)); return RECORD_CONTINUE; } @@ -11543,7 +11994,7 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty JS_ASSERT(sprop->hasShortID()); LIns* base = lir->insLoad(LIR_ldp, callobj_ins, offsetof(JSObject, dslots), ACC_OTHER); - lir->insStore(box_jsval(v, v_ins), base, dslot_index * sizeof(jsval), ACC_OTHER); + box_value_into(v, v_ins, base, dslot_index * sizeof(Value), ACC_OTHER); return RECORD_CONTINUE; } @@ -11589,9 +12040,9 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty LIns *type_ins = lir->insLoad(LIR_lduc2ui, lir->ins2(LIR_addp, typemap_ins, lir->insUI2P(slot_ins)), 0, ACC_READONLY); - TraceType type = getCoercedType(v); - if (type == TT_INT32 && !isPromoteInt(v_ins)) - type = TT_DOUBLE; + JSValueType type = getCoercedType(v); + if (type == JSVAL_TYPE_INT32 && !isPromoteInt(v_ins)) + type = JSVAL_TYPE_DOUBLE; guard(true, addName(lir->ins2(LIR_eqi, type_ins, lir->insImmI(type)), "guard(type-stable set upvar)"), @@ -11609,8 +12060,8 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty LIns *label1 = lir->ins0(LIR_label); br1->setTarget(label1); LIns* args[] = { - box_jsval(v, v_ins), - INS_CONSTWORD(SPROP_USERID(sprop)), + box_value_for_native_call(v, v_ins), + INS_CONSTWORD(JSID_BITS(SPROP_USERID(sprop))), callobj_ins, cx_ins }; @@ -11626,8 +12077,8 @@ TraceRecorder::setCallProp(JSObject *callobj, LIns *callobj_ins, JSScopeProperty JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_SetPropHit(PropertyCacheEntry* entry, JSScopeProperty* sprop) { - jsval& r = stackval(-1); - jsval& l = stackval(-2); + Value& r = stackval(-1); + Value& l = stackval(-2); LIns* v_ins; jsbytecode* pc = cx->regs->pc; @@ -11673,12 +12124,13 @@ TraceRecorder::leaveDeepBailCall() } JS_REQUIRES_STACK void -TraceRecorder::finishGetProp(LIns* obj_ins, LIns* vp_ins, LIns* ok_ins, jsval* outp) +TraceRecorder::finishGetProp(LIns* obj_ins, LIns* vp_ins, LIns* ok_ins, Value* outp) { // Store the boxed result (and this-object, if JOF_CALLOP) before the // guard. The deep-bail case requires this. If the property get fails, // these slots will be ignored anyway. - LIns* result_ins = lir->insLoad(LIR_ldp, vp_ins, 0, ACC_OTHER); + // N.B. monitorRecording expects get(outp)->isLoad() + LIns* result_ins = lir->insLoad(LIR_ldd, vp_ins, 0, ACC_OTHER); set(outp, result_ins); if (js_CodeSpec[*cx->regs->pc].format & JOF_CALLOP) set(outp + 1, obj_ins); @@ -11698,7 +12150,7 @@ RootedStringToId(JSContext* cx, JSString** namep, jsid* idp) { JSString* name = *namep; if (name->isAtomized()) { - *idp = ATOM_TO_JSID((JSAtom*) STRING_TO_JSVAL(name)); + *idp = INTERNED_STRING_TO_JSID(name); return true; } @@ -11711,7 +12163,7 @@ RootedStringToId(JSContext* cx, JSString** namep, jsid* idp) } static JSBool FASTCALL -GetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, jsval* vp) +GetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, Value* vp) { LeaveTraceIfGlobalObject(cx, obj); @@ -11722,25 +12174,25 @@ GetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, jsval* vp) } return cx->tracerState->builtinStatus == 0; } -JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByName, CONTEXT, OBJECT, STRINGPTR, JSVALPTR, +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByName, CONTEXT, OBJECT, STRINGPTR, VALUEPTR, 0, ACC_STORE_ANY) // Convert the value in a slot to a string and store the resulting string back // in the slot (typically in order to root it). JS_REQUIRES_STACK RecordingStatus -TraceRecorder::primitiveToStringInPlace(jsval* vp) +TraceRecorder::primitiveToStringInPlace(Value* vp) { - jsval v = *vp; - JS_ASSERT(JSVAL_IS_PRIMITIVE(v)); + Value v = *vp; + JS_ASSERT(v.isPrimitive()); - if (!JSVAL_IS_STRING(v)) { + if (!v.isString()) { // v is not a string. Turn it into one. js_ValueToString is safe // because v is not an object. JSString *str = js_ValueToString(cx, v); JS_ASSERT(TRACE_RECORDER(cx) == this); if (!str) RETURN_ERROR("failed to stringify element id"); - v = STRING_TO_JSVAL(str); + v.setString(str); set(vp, stringify(*vp)); // Write the string back to the stack to save the interpreter some work @@ -11751,7 +12203,7 @@ TraceRecorder::primitiveToStringInPlace(jsval* vp) } JS_REQUIRES_STACK RecordingStatus -TraceRecorder::getPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* outp) +TraceRecorder::getPropertyByName(LIns* obj_ins, Value* idvalp, Value* outp) { CHECK_STATUS(primitiveToStringInPlace(idvalp)); enterDeepBailCall(); @@ -11759,7 +12211,7 @@ TraceRecorder::getPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* outp) // Call GetPropertyByName. The vp parameter points to stack because this is // what the interpreter currently does. obj and id are rooted on the // interpreter stack, but the slot at vp is not a root. - LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp"); + LIns* vp_ins = addName(lir->insAlloc(sizeof(Value)), "vp"); LIns* idvalp_ins = addName(addr(idvalp), "idvalp"); LIns* args[] = {vp_ins, idvalp_ins, obj_ins, cx_ins}; LIns* ok_ins = lir->insCall(&GetPropertyByName_ci, args); @@ -11777,7 +12229,7 @@ TraceRecorder::getPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* outp) } static JSBool FASTCALL -GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) +GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, Value* vp) { LeaveTraceIfGlobalObject(cx, obj); @@ -11788,17 +12240,17 @@ GetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) } return cx->tracerState->builtinStatus == 0; } -JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByIndex, CONTEXT, OBJECT, INT32, JSVALPTR, 0, +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyByIndex, CONTEXT, OBJECT, INT32, VALUEPTR, 0, ACC_STORE_ANY) JS_REQUIRES_STACK RecordingStatus -TraceRecorder::getPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* outp) +TraceRecorder::getPropertyByIndex(LIns* obj_ins, LIns* index_ins, Value* outp) { index_ins = makeNumberInt32(index_ins); // See note in getPropertyByName about vp. enterDeepBailCall(); - LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp"); + LIns* vp_ins = addName(lir->insAlloc(sizeof(Value)), "vp"); LIns* args[] = {vp_ins, index_ins, obj_ins, cx_ins}; LIns* ok_ins = lir->insCall(&GetPropertyByIndex_ci, args); finishGetProp(obj_ins, vp_ins, ok_ins, outp); @@ -11807,7 +12259,7 @@ TraceRecorder::getPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* outp) } static JSBool FASTCALL -GetPropertyById(JSContext* cx, JSObject* obj, jsid id, jsval* vp) +GetPropertyById(JSContext* cx, JSObject* obj, jsid id, Value* vp) { LeaveTraceIfGlobalObject(cx, obj); if (!obj->getProperty(cx, id, vp)) { @@ -11816,11 +12268,11 @@ GetPropertyById(JSContext* cx, JSObject* obj, jsid id, jsval* vp) } return cx->tracerState->builtinStatus == 0; } -JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyById, CONTEXT, OBJECT, JSVAL, JSVALPTR, +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyById, CONTEXT, OBJECT, JSID, VALUEPTR, 0, ACC_STORE_ANY) JS_REQUIRES_STACK RecordingStatus -TraceRecorder::getPropertyById(LIns* obj_ins, jsval* outp) +TraceRecorder::getPropertyById(LIns* obj_ins, Value* outp) { // Find the atom. JSAtom* atom; @@ -11835,11 +12287,13 @@ TraceRecorder::getPropertyById(LIns* obj_ins, jsval* outp) atom = atoms[GET_INDEX(pc + SLOTNO_LEN)]; } + JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void *)); + jsid id = ATOM_TO_JSID(atom); + // Call GetPropertyById. See note in getPropertyByName about vp. enterDeepBailCall(); - jsid id = ATOM_TO_JSID(atom); - LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp"); - LIns* args[] = {vp_ins, INS_CONSTWORD(id), obj_ins, cx_ins}; + LIns* vp_ins = addName(lir->insAlloc(sizeof(Value)), "vp"); + LIns* args[] = {vp_ins, INS_CONSTWORD(JSID_BITS(id)), obj_ins, cx_ins}; LIns* ok_ins = lir->insCall(&GetPropertyById_ci, args); finishGetProp(obj_ins, vp_ins, ok_ins, outp); leaveDeepBailCall(); @@ -11848,7 +12302,7 @@ TraceRecorder::getPropertyById(LIns* obj_ins, jsval* outp) /* Manually inlined, specialized copy of js_NativeGet. */ static JSBool FASTCALL -GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, jsval* vp) +GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, Value* vp) { LeaveTraceIfGlobalObject(cx, obj); @@ -11865,7 +12319,7 @@ GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop // stack while recording. JS_ASSERT(obj->getClass() != &js_WithClass); - *vp = JSVAL_VOID; + vp->setUndefined(); if (!sprop->getterOp()(cx, obj, SPROP_USERID(sprop), vp)) { SetBuiltinError(cx); return JS_FALSE; @@ -11873,10 +12327,10 @@ GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop return cx->tracerState->builtinStatus == 0; } JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyWithNativeGetter, - CONTEXT, OBJECT, SCOPEPROP, JSVALPTR, 0, ACC_STORE_ANY) + CONTEXT, OBJECT, SCOPEPROP, VALUEPTR, 0, ACC_STORE_ANY) JS_REQUIRES_STACK RecordingStatus -TraceRecorder::getPropertyWithNativeGetter(LIns* obj_ins, JSScopeProperty* sprop, jsval* outp) +TraceRecorder::getPropertyWithNativeGetter(LIns* obj_ins, JSScopeProperty* sprop, Value* outp) { JS_ASSERT(!sprop->hasGetterValue()); JS_ASSERT(sprop->slot == SPROP_INVALID_SLOT); @@ -11886,7 +12340,7 @@ TraceRecorder::getPropertyWithNativeGetter(LIns* obj_ins, JSScopeProperty* sprop // FIXME - We should call the getter directly. Using a builtin function for // now because it buys some extra asserts. See bug 508310. enterDeepBailCall(); - LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp"); + LIns* vp_ins = addName(lir->insAlloc(sizeof(Value)), "vp"); LIns* args[] = {vp_ins, INS_CONSTPTR(sprop), obj_ins, cx_ins}; LIns* ok_ins = lir->insCall(&GetPropertyWithNativeGetter_ci, args); finishGetProp(obj_ins, vp_ins, ok_ins, outp); @@ -11903,21 +12357,21 @@ TraceRecorder::getPropertyWithScriptGetter(JSObject *obj, LIns* obj_ins, JSScope // Rearrange the stack in preparation for the imacro, taking care to adjust // the interpreter state and the tracker in the same way. This adjustment // is noted in imacros.jsasm with .fixup tags. - jsval getter = sprop->getterValue(); - jsval*& sp = cx->regs->sp; + Value getter = sprop->getterValue(); + Value*& sp = cx->regs->sp; switch (*cx->regs->pc) { case JSOP_GETPROP: sp++; sp[-1] = sp[-2]; set(&sp[-1], get(&sp[-2])); sp[-2] = getter; - set(&sp[-2], INS_CONSTOBJ(JSVAL_TO_OBJECT(getter))); + set(&sp[-2], INS_CONSTOBJ(&getter.toObject())); return callImacroInfallibly(getprop_imacros.scriptgetter); case JSOP_CALLPROP: sp += 2; sp[-2] = getter; - set(&sp[-2], INS_CONSTOBJ(JSVAL_TO_OBJECT(getter))); + set(&sp[-2], INS_CONSTOBJ(&getter.toObject())); sp[-1] = sp[-3]; set(&sp[-1], get(&sp[-3])); return callImacroInfallibly(callprop_imacros.scriptgetter); @@ -11927,8 +12381,8 @@ TraceRecorder::getPropertyWithScriptGetter(JSObject *obj, LIns* obj_ins, JSScope case JSOP_GETLOCALPROP: sp += 2; sp[-2] = getter; - set(&sp[-2], INS_CONSTOBJ(JSVAL_TO_OBJECT(getter))); - sp[-1] = OBJECT_TO_JSVAL(obj); + set(&sp[-2], INS_CONSTOBJ(&getter.toObject())); + sp[-1] = ObjectValue(*obj); set(&sp[-1], obj_ins); return callImacroInfallibly(getthisprop_imacros.scriptgetter); @@ -11949,18 +12403,18 @@ TraceRecorder::record_JSOP_GETELEM() { bool call = *cx->regs->pc == JSOP_CALLELEM; - jsval& idx = stackval(-1); - jsval& lval = stackval(-2); + Value& idx = stackval(-1); + Value& lval = stackval(-2); LIns* obj_ins = get(&lval); LIns* idx_ins = get(&idx); // Special case for array-like access of strings. - if (JSVAL_IS_STRING(lval) && isInt32(idx)) { + if (lval.isString() && hasInt32Repr(idx)) { if (call) RETURN_STOP_A("JSOP_CALLELEM on a string"); int i = asInt32(idx); - if (size_t(i) >= JSVAL_TO_STRING(lval)->length()) + if (size_t(i) >= lval.toString()->length()) RETURN_STOP_A("Invalid string index in JSOP_GETELEM"); idx_ins = makeNumberInt32(idx_ins); LIns* args[] = { idx_ins, obj_ins, cx_ins }; @@ -11970,18 +12424,18 @@ TraceRecorder::record_JSOP_GETELEM() return ARECORD_CONTINUE; } - if (JSVAL_IS_PRIMITIVE(lval)) + if (lval.isPrimitive()) RETURN_STOP_A("JSOP_GETLEM on a primitive"); RETURN_IF_XML_A(lval); - JSObject* obj = JSVAL_TO_OBJECT(lval); + JSObject* obj = &lval.toObject(); if (obj == globalObj) RETURN_STOP_A("JSOP_GETELEM on global"); LIns* v_ins; /* Property access using a string name or something we have to stringify. */ - if (!JSVAL_IS_INT(idx)) { - if (!JSVAL_IS_PRIMITIVE(idx)) + if (!idx.isInt32()) { + if (!idx.isPrimitive()) RETURN_STOP_A("object used as index"); return InjectStatus(getPropertyByName(obj_ins, &idx, &lval)); @@ -11991,8 +12445,8 @@ TraceRecorder::record_JSOP_GETELEM() unsigned depth; JSStackFrame *afp = guardArguments(obj, obj_ins, &depth); if (afp) { - uintN int_idx = JSVAL_TO_INT(idx); - jsval* vp = &afp->argv[int_idx]; + uintN int_idx = idx.toInt32(); + Value* vp = &afp->argv[int_idx]; if (idx_ins->isImmD()) { if (int_idx < 0 || int_idx >= afp->argc) RETURN_STOP_A("cannot trace arguments with out of range index"); @@ -12014,7 +12468,7 @@ TraceRecorder::record_JSOP_GETELEM() "guard(upvar index in range)"), MISMATCH_EXIT); - TraceType type = getCoercedType(*vp); + JSValueType type = getCoercedType(*vp); // Guard that the argument has the same type on trace as during recording. LIns* typemap_ins; @@ -12023,7 +12477,7 @@ TraceRecorder::record_JSOP_GETELEM() // The entry type map is not necessarily up-to-date, so we capture a new type map // for this point in the code. unsigned stackSlots = NativeStackSlots(cx, 0 /* callDepth */); - TraceType* typemap = new (traceAlloc()) TraceType[stackSlots]; + JSValueType* typemap = new (traceAlloc()) JSValueType[stackSlots]; DetermineTypesVisitor detVisitor(*this, typemap); VisitStackSlots(detVisitor, cx, 0); typemap_ins = INS_CONSTPTR(typemap + 2 /* callee, this */); @@ -12036,13 +12490,13 @@ TraceRecorder::record_JSOP_GETELEM() LIns* fip_ins = lir->insLoad(LIR_ldp, lirbuf->rp, (callDepth-depth)*sizeof(FrameInfo*), ACC_RSTACK); - typemap_ins = lir->ins2(LIR_addp, fip_ins, INS_CONSTWORD(sizeof(FrameInfo) + 2/*callee,this*/ * sizeof(TraceType))); + typemap_ins = lir->ins2(LIR_addp, fip_ins, INS_CONSTWORD(sizeof(FrameInfo) + 2/*callee,this*/ * sizeof(JSValueType))); } LIns* typep_ins = lir->ins2(LIR_addp, typemap_ins, lir->insUI2P(lir->ins2(LIR_muli, idx_ins, - INS_CONST(sizeof(TraceType))))); + INS_CONST(sizeof(JSValueType))))); LIns* type_ins = lir->insLoad(LIR_lduc2ui, typep_ins, 0, ACC_READONLY); guard(true, addName(lir->ins2(LIR_eqi, type_ins, lir->insImmI(type)), @@ -12076,7 +12530,7 @@ TraceRecorder::record_JSOP_GETELEM() if (obj->isDenseArray()) { // Fast path for dense arrays accessed with a integer index. - jsval* vp; + Value* vp; LIns* addr_ins; guardDenseArray(obj_ins, BRANCH_EXIT); @@ -12089,7 +12543,7 @@ TraceRecorder::record_JSOP_GETELEM() if (OkToTraceTypedArrays && js_IsTypedArray(obj)) { // Fast path for typed arrays accessed with a integer index. - jsval* vp; + Value* vp; LIns* addr_ins; guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), ACC_READONLY); @@ -12106,7 +12560,7 @@ TraceRecorder::record_JSOP_GETELEM() /* Functions used by JSOP_SETELEM */ static JSBool FASTCALL -SetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, jsval* vp) +SetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, Value* vp) { LeaveTraceIfGlobalObject(cx, obj); @@ -12117,54 +12571,51 @@ SetPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, jsval* vp) } return cx->tracerState->builtinStatus == 0; } -JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, SetPropertyByName, CONTEXT, OBJECT, STRINGPTR, JSVALPTR, +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, SetPropertyByName, CONTEXT, OBJECT, STRINGPTR, VALUEPTR, 0, ACC_STORE_ANY) static JSBool FASTCALL -InitPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, jsval val) +InitPropertyByName(JSContext* cx, JSObject* obj, JSString** namep, ValueArgType arg) { LeaveTraceIfGlobalObject(cx, obj); jsid id; if (!RootedStringToId(cx, namep, &id) || - !obj->defineProperty(cx, id, val, NULL, NULL, JSPROP_ENUMERATE)) { + !obj->defineProperty(cx, id, ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) { SetBuiltinError(cx); return JS_FALSE; } return cx->tracerState->builtinStatus == 0; } -JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByName, CONTEXT, OBJECT, STRINGPTR, JSVAL, +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByName, CONTEXT, OBJECT, STRINGPTR, VALUE, 0, ACC_STORE_ANY) JS_REQUIRES_STACK RecordingStatus -TraceRecorder::initOrSetPropertyByName(LIns* obj_ins, jsval* idvalp, jsval* rvalp, bool init) +TraceRecorder::initOrSetPropertyByName(LIns* obj_ins, Value* idvalp, Value* rvalp, bool init) { CHECK_STATUS(primitiveToStringInPlace(idvalp)); - LIns* rval_ins = box_jsval(*rvalp, get(rvalp)); - - enterDeepBailCall(); - - LIns* ok_ins; - LIns* idvalp_ins = addName(addr(idvalp), "idvalp"); if (init) { - LIns* args[] = {rval_ins, idvalp_ins, obj_ins, cx_ins}; - ok_ins = lir->insCall(&InitPropertyByName_ci, args); + LIns* v_ins = box_value_for_native_call(*rvalp, get(rvalp)); + enterDeepBailCall(); + LIns* idvalp_ins = addName(addr(idvalp), "idvalp"); + LIns* args[] = {v_ins, idvalp_ins, obj_ins, cx_ins}; + pendingGuardCondition = lir->insCall(&InitPropertyByName_ci, args); } else { // See note in getPropertyByName about vp. - LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp"); - lir->insStore(rval_ins, vp_ins, 0, ACC_OTHER); + LIns* vp_ins = box_value_into_alloc(*rvalp, get(rvalp)); + enterDeepBailCall(); + LIns* idvalp_ins = addName(addr(idvalp), "idvalp"); LIns* args[] = {vp_ins, idvalp_ins, obj_ins, cx_ins}; - ok_ins = lir->insCall(&SetPropertyByName_ci, args); + pendingGuardCondition = lir->insCall(&SetPropertyByName_ci, args); } - pendingGuardCondition = ok_ins; leaveDeepBailCall(); return RECORD_CONTINUE; } static JSBool FASTCALL -SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) +SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, Value* vp) { LeaveTraceIfGlobalObject(cx, obj); @@ -12175,46 +12626,42 @@ SetPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval* vp) } return cx->tracerState->builtinStatus == 0; } -JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, SetPropertyByIndex, CONTEXT, OBJECT, INT32, JSVALPTR, 0, +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, SetPropertyByIndex, CONTEXT, OBJECT, INT32, VALUEPTR, 0, ACC_STORE_ANY) static JSBool FASTCALL -InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, jsval val) +InitPropertyByIndex(JSContext* cx, JSObject* obj, int32 index, ValueArgType arg) { LeaveTraceIfGlobalObject(cx, obj); AutoIdRooter idr(cx); if (!js_Int32ToId(cx, index, idr.addr()) || - !obj->defineProperty(cx, idr.id(), val, NULL, NULL, JSPROP_ENUMERATE)) { + !obj->defineProperty(cx, idr.id(), ValueArgToConstRef(arg), NULL, NULL, JSPROP_ENUMERATE)) { SetBuiltinError(cx); return JS_FALSE; } return cx->tracerState->builtinStatus == 0; } -JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByIndex, CONTEXT, OBJECT, INT32, JSVAL, 0, +JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, InitPropertyByIndex, CONTEXT, OBJECT, INT32, VALUE, 0, ACC_STORE_ANY) JS_REQUIRES_STACK RecordingStatus -TraceRecorder::initOrSetPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* rvalp, bool init) +TraceRecorder::initOrSetPropertyByIndex(LIns* obj_ins, LIns* index_ins, Value* rvalp, bool init) { index_ins = makeNumberInt32(index_ins); - LIns* rval_ins = box_jsval(*rvalp, get(rvalp)); - - enterDeepBailCall(); - - LIns* ok_ins; if (init) { + LIns* rval_ins = box_value_for_native_call(*rvalp, get(rvalp)); + enterDeepBailCall(); LIns* args[] = {rval_ins, index_ins, obj_ins, cx_ins}; - ok_ins = lir->insCall(&InitPropertyByIndex_ci, args); + pendingGuardCondition = lir->insCall(&InitPropertyByIndex_ci, args); } else { // See note in getPropertyByName about vp. - LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp"); - lir->insStore(rval_ins, vp_ins, 0, ACC_OTHER); + LIns* vp_ins = box_value_into_alloc(*rvalp, get(rvalp)); + enterDeepBailCall(); LIns* args[] = {vp_ins, index_ins, obj_ins, cx_ins}; - ok_ins = lir->insCall(&SetPropertyByIndex_ci, args); + pendingGuardCondition = lir->insCall(&SetPropertyByIndex_ci, args); } - pendingGuardCondition = ok_ins; leaveDeepBailCall(); return RECORD_CONTINUE; @@ -12223,27 +12670,27 @@ TraceRecorder::initOrSetPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* r JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) { - jsval& v = stackval(v_spindex); - jsval& idx = stackval(idx_spindex); - jsval& lval = stackval(lval_spindex); + Value& v = stackval(v_spindex); + Value& idx = stackval(idx_spindex); + Value& lval = stackval(lval_spindex); - if (JSVAL_IS_PRIMITIVE(lval)) + if (lval.isPrimitive()) RETURN_STOP_A("left JSOP_SETELEM operand is not an object"); RETURN_IF_XML_A(lval); - JSObject* obj = JSVAL_TO_OBJECT(lval); + JSObject* obj = &lval.toObject(); LIns* obj_ins = get(&lval); LIns* idx_ins = get(&idx); LIns* v_ins = get(&v); - if (JS_InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) + if (InstanceOf(cx, obj, &js_ArgumentsClass, NULL)) RETURN_STOP_A("can't trace setting elements of the |arguments| object"); if (obj == globalObj) RETURN_STOP_A("can't trace setting elements on the global object"); - if (!JSVAL_IS_INT(idx)) { - if (!JSVAL_IS_PRIMITIVE(idx)) + if (!idx.isInt32()) { + if (!idx.isPrimitive()) RETURN_STOP_A("non-primitive index"); CHECK_STATUS_A(initOrSetPropertyByName(obj_ins, &idx, &v, *cx->regs->pc == JSOP_INITELEM)); @@ -12255,7 +12702,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) js::TypedArray* tarray = js::TypedArray::fromJSObject(obj); - LIns* priv_ins = stobj_get_const_fslot(obj_ins, JSSLOT_PRIVATE); + LIns* priv_ins = stobj_get_const_private_ptr(obj_ins); // The index was on the stack and is therefore a LIR float; force it to // be an integer. @@ -12280,16 +12727,16 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) // If it's not a number, convert objects to NaN, // null to 0, and call StringToNumber or BooleanOrUndefinedToNumber // for those. - if (!isNumber(v)) { - if (JSVAL_IS_NULL(v)) { + if (!v.isNumber()) { + if (v.isNull()) { typed_v_ins = lir->insImmD(0); - } else if (JSVAL_IS_VOID(v)) { + } else if (v.isUndefined()) { typed_v_ins = lir->insImmD(js_NaN); - } else if (JSVAL_IS_STRING(v)) { + } else if (v.isString()) { LIns* args[] = { typed_v_ins, cx_ins }; typed_v_ins = lir->insCall(&js_StringToNumber_ci, args); - } else if (JSVAL_IS_SPECIAL(v)) { - JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + } else if (v.isBoolean()) { + JS_ASSERT(v.isBoolean()); typed_v_ins = i2d(typed_v_ins); } else { typed_v_ins = lir->insImmD(js_NaN); @@ -12359,7 +12806,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) default: JS_NOT_REACHED("Unknown typed array type in tracer"); } - } else if (JSVAL_TO_INT(idx) < 0 || !obj->isDenseArray()) { + } else if (idx.toInt32() < 0 || !obj->isDenseArray()) { CHECK_STATUS_A(initOrSetPropertyByIndex(obj_ins, idx_ins, &v, *cx->regs->pc == JSOP_INITELEM)); } else { @@ -12380,9 +12827,18 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) // unnecessarily. LIns* res_ins; LIns* args[] = { NULL, idx_ins, obj_ins, cx_ins }; - if (isNumber(v)) { + if (v.isNumber()) { if (fcallinfo(v_ins) == &js_UnboxDouble_ci) { +#if JS_BITS_PER_WORD == 32 + LIns *boxed = lir->insAlloc(sizeof(Value)); + LIns *tag_ins = fcallarg(v_ins, 0); + LIns *payload_ins = fcallarg(v_ins, 1); + lir->insStore(tag_ins, boxed, sTagOffset, ACC_OTHER); + lir->insStore(payload_ins, boxed, sPayloadOffset, ACC_OTHER); + args[0] = boxed; +#else args[0] = fcallarg(v_ins, 0); +#endif res_ins = lir->insCall(&js_Array_dense_setelem_ci, args); } else if (isPromoteInt(v_ins)) { args[0] = demote(lir, v_ins); @@ -12392,7 +12848,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex) res_ins = lir->insCall(&js_Array_dense_setelem_double_ci, args); } } else { - args[0] = box_jsval(v, v_ins); + args[0] = box_value_for_native_call(v, v_ins); res_ins = lir->insCall(&js_Array_dense_setelem_ci, args); } guard(false, lir->insEqI_0(res_ins), MISMATCH_EXIT); @@ -12416,7 +12872,7 @@ TraceRecorder::record_JSOP_CALLNAME() { JSObject* obj = cx->fp->scopeChain; if (obj != globalObj) { - jsval* vp; + Value* vp; LIns* ins; NameResult nr; CHECK_STATUS_A(scopeChainProp(obj, vp, ins, nr)); @@ -12431,12 +12887,10 @@ TraceRecorder::record_JSOP_CALLNAME() CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); - if (pcval.isNull() || !pcval.isObject()) + if (pcval.isNull() || !pcval.isFunObj()) RETURN_STOP_A("callee is not an object"); - JS_ASSERT(pcval.toObject()->isFunction()); - - stack(0, INS_CONSTOBJ(pcval.toObject())); + stack(0, INS_CONSTOBJ(&pcval.toFunObj())); stack(1, obj_ins); return ARECORD_CONTINUE; } @@ -12454,7 +12908,7 @@ JS_DEFINE_CALLINFO_5(extern, UINT32, GetUpvarStackOnTrace, CONTEXT, UINT32, INT3 * typemap. The value of the upvar is returned as v. */ JS_REQUIRES_STACK LIns* -TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v) +TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, Value& v) { /* * Try to find the upvar in the current trace's tracker. For &vr to be @@ -12464,7 +12918,7 @@ TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v) * existing reference that points to something else. */ UpvarCookie cookie = uva->vector[index]; - jsval& vr = js_GetUpvar(cx, script->staticLevel, cookie); + const Value& vr = js_GetUpvar(cx, script->staticLevel, cookie); v = vr; if (LIns* ins = attemptImport(&vr)) @@ -12502,7 +12956,7 @@ TraceRecorder::upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v) cx_ins }; LIns* call_ins = lir->insCall(ci, args); - TraceType type = getCoercedType(v); + JSValueType type = getCoercedType(v); guard(true, addName(lir->ins2(LIR_eqi, call_ins, lir->insImmI(type)), "guard(type-stable upvar)"), @@ -12519,29 +12973,29 @@ TraceRecorder::stackLoad(LIns* base, AccSet accSet, uint8 type) { LOpcode loadOp; switch (type) { - case TT_DOUBLE: + case JSVAL_TYPE_DOUBLE: loadOp = LIR_ldd; break; - case TT_OBJECT: - case TT_STRING: - case TT_FUNCTION: - case TT_NULL: + case JSVAL_TYPE_NONFUNOBJ: + case JSVAL_TYPE_STRING: + case JSVAL_TYPE_FUNOBJ: + case JSVAL_TYPE_NULL: loadOp = LIR_ldp; break; - case TT_INT32: - case TT_SPECIAL: - case TT_VOID: - case TT_MAGIC: + case JSVAL_TYPE_INT32: + case JSVAL_TYPE_BOOLEAN: + case JSVAL_TYPE_UNDEFINED: + case JSVAL_TYPE_MAGIC: loadOp = LIR_ldi; break; - case TT_JSVAL: + case JSVAL_TYPE_BOXED: default: JS_NOT_REACHED("found jsval type in an upvar type map entry"); return NULL; } LIns* result = lir->insLoad(loadOp, base, 0, accSet); - if (type == TT_INT32) + if (type == JSVAL_TYPE_INT32) result = lir->ins1(LIR_i2d, result); return result; } @@ -12554,7 +13008,7 @@ TraceRecorder::record_JSOP_GETUPVAR() JSUpvarArray* uva = script->upvars(); JS_ASSERT(index < uva->length); - jsval v; + Value v; LIns* upvar_ins = upvar(script, uva, index, v); if (!upvar_ins) return ARECORD_STOP; @@ -12573,14 +13027,13 @@ TraceRecorder::record_JSOP_CALLUPVAR() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_GETDSLOT() { - JSObject* callee = cx->fp->calleeObject(); + JSObject* callee = cx->fp->callee(); LIns* callee_ins = get(&cx->fp->argv[-2]); unsigned index = GET_UINT16(cx->regs->pc); LIns* dslots_ins = lir->insLoad(LIR_ldp, callee_ins, offsetof(JSObject, dslots), ACC_OTHER); - LIns* v_ins = lir->insLoad(LIR_ldp, dslots_ins, index * sizeof(jsval), ACC_OTHER); - - stack(0, unbox_jsval(callee->dslots[index], v_ins, snapshot(BRANCH_EXIT))); + stack(0, unbox_value(callee->dslots[index], dslots_ins, index * sizeof(Value), + snapshot(BRANCH_EXIT))); return ARECORD_CONTINUE; } @@ -12593,9 +13046,9 @@ TraceRecorder::record_JSOP_CALLDSLOT() } JS_REQUIRES_STACK RecordingStatus -TraceRecorder::guardCallee(jsval& callee) +TraceRecorder::guardCallee(Value& callee) { - JSObject* callee_obj = JSVAL_TO_OBJECT(callee); + JSObject* callee_obj = &callee.toObject(); JS_ASSERT(callee_obj->isFunction()); JSFunction* callee_fun = (JSFunction*) callee_obj->getPrivate(); @@ -12611,7 +13064,7 @@ TraceRecorder::guardCallee(jsval& callee) guard(true, lir->ins2(LIR_eqp, - stobj_get_private(callee_ins), + stobj_get_const_private_ptr(callee_ins), INS_CONSTPTR(callee_fun)), branchExit); @@ -12673,14 +13126,14 @@ TraceRecorder::guardArguments(JSObject *obj, LIns* obj_ins, unsigned *depthp) VMSideExit *exit = snapshot(MISMATCH_EXIT); guardClass(obj_ins, &js_ArgumentsClass, exit, ACC_READONLY); - LIns* args_ins = get(&afp->argsobj); + LIns* args_ins = getFrameObjPtr(&afp->argsobj); LIns* cmp = lir->ins2(LIR_eqp, args_ins, obj_ins); lir->insGuard(LIR_xf, cmp, createGuardRecord(exit)); return afp; } JS_REQUIRES_STACK RecordingStatus -TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, bool constructing) +TraceRecorder::interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc, bool constructing) { /* * The function's identity (JSFunction and therefore JSScript) is guarded, @@ -12691,12 +13144,12 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, * and does not call any TR::record_*CallComplete hook. */ if (fun->u.i.script->isEmpty()) { - LIns* rval_ins = constructing ? stack(-1 - argc) : INS_VOID(); + LIns* rval_ins = constructing ? stack(-1 - argc) : INS_UNDEFINED(); stack(-2 - argc, rval_ins); return RECORD_CONTINUE; } - if (JSVAL_TO_OBJECT(fval)->getGlobal() != globalObj) + if (fval.toObject().getGlobal() != globalObj) RETURN_STOP("JSOP_CALL or JSOP_NEW crosses global scopes"); JSStackFrame* const fp = cx->fp; @@ -12704,8 +13157,8 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, // Generate a type map for the outgoing frame and stash it in the LIR unsigned stackSlots = NativeStackSlots(cx, 0 /* callDepth */); FrameInfo* fi = (FrameInfo*) - tempAlloc().alloc(sizeof(FrameInfo) + stackSlots * sizeof(TraceType)); - TraceType* typemap = (TraceType*)(fi + 1); + tempAlloc().alloc(sizeof(FrameInfo) + stackSlots * sizeof(JSValueType)); + JSValueType* typemap = (JSValueType*)(fi + 1); DetermineTypesVisitor detVisitor(*this, typemap); VisitStackSlots(detVisitor, cx, 0); @@ -12715,7 +13168,7 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, tree->gcthings.addUnique(fval); fi->block = fp->blockChain; if (fp->blockChain) - tree->gcthings.addUnique(OBJECT_TO_JSVAL(fp->blockChain)); + tree->gcthings.addUnique(ObjectValue(*fp->blockChain)); fi->pc = cx->regs->pc; fi->imacpc = fp->imacpc; fi->spdist = cx->regs->sp - fp->slots(); @@ -12735,11 +13188,11 @@ TraceRecorder::interpretedFunctionCall(jsval& fval, JSFunction* fun, uintN argc, debug_only_printf(LC_TMTracer, "iFC frameinfo=%p, stack=%d, map=", (void*)fi, fi->callerHeight); for (unsigned i = 0; i < fi->callerHeight; i++) - debug_only_printf(LC_TMTracer, "%c", typeChar[fi->get_typemap()[i]]); + debug_only_printf(LC_TMTracer, "%c", TypeToChar(fi->get_typemap()[i])); debug_only_print0(LC_TMTracer, "\n"); #endif - atoms = fun->u.i.script->atomMap.vector; + updateAtoms(fun->u.i.script); return RECORD_CONTINUE; } @@ -12785,46 +13238,46 @@ TraceRecorder::record_JSOP_APPLY() uintN argc = GET_ARGC(pc); cx->assertValidStackDepth(argc + 2); - jsval* vp = cx->regs->sp - (argc + 2); + Value* vp = cx->regs->sp - (argc + 2); jsuint length = 0; JSObject* aobj = NULL; LIns* aobj_ins = NULL; JS_ASSERT(!cx->fp->imacpc); - if (!VALUE_IS_FUNCTION(cx, vp[0])) + if (!IsFunctionObject(vp[0])) return record_JSOP_CALL(); RETURN_IF_XML_A(vp[0]); - JSObject* obj = JSVAL_TO_OBJECT(vp[0]); + JSObject* obj = &vp[0].toObject(); JSFunction* fun = GET_FUNCTION_PRIVATE(cx, obj); if (FUN_INTERPRETED(fun)) return record_JSOP_CALL(); - bool apply = (JSFastNative)fun->u.n.native == js_fun_apply; - if (!apply && (JSFastNative)fun->u.n.native != js_fun_call) + bool apply = (FastNative)fun->u.n.native == js_fun_apply; + if (!apply && (FastNative)fun->u.n.native != js_fun_call) return record_JSOP_CALL(); /* * We don't trace apply and call with a primitive 'this', which is the * first positional parameter. */ - if (argc > 0 && !JSVAL_IS_OBJECT(vp[2])) + if (argc > 0 && !vp[2].isObject()) return record_JSOP_CALL(); /* * Guard on the identity of this, which is the function we are applying. */ - if (!VALUE_IS_FUNCTION(cx, vp[1])) + if (!IsFunctionObject(vp[1])) RETURN_STOP_A("callee is not a function"); CHECK_STATUS_A(guardCallee(vp[1])); if (apply && argc >= 2) { if (argc != 2) RETURN_STOP_A("apply with excess arguments"); - if (JSVAL_IS_PRIMITIVE(vp[3])) + if (vp[3].isPrimitive()) RETURN_STOP_A("arguments parameter of apply is primitive"); - aobj = JSVAL_TO_OBJECT(vp[3]); + aobj = &vp[3].toObject(); aobj_ins = get(&vp[3]); /* @@ -12836,8 +13289,8 @@ TraceRecorder::record_JSOP_APPLY() length = aobj->getArrayLength(); guard(true, lir->ins2ImmI(LIR_eqi, - p2i(stobj_get_fslot(aobj_ins, JSObject::JSSLOT_ARRAY_LENGTH)), - length), + stobj_get_fslot_uint32(aobj_ins, JSObject::JSSLOT_ARRAY_LENGTH), + length), BRANCH_EXIT); } else if (aobj->isArguments()) { unsigned depth; @@ -12872,7 +13325,7 @@ TraceRecorder::record_NativeCallComplete() JS_ASSERT(pendingSpecializedNative); JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY || *pc == JSOP_NEW || *pc == JSOP_SETPROP); - jsval& v = stackval(-1); + Value& v = stackval(-1); LIns* v_ins = get(&v); /* @@ -12886,7 +13339,7 @@ TraceRecorder::record_NativeCallComplete() * to restore by the length of the current opcode. If the native's return * type is jsval, snapshot() will also indicate in the type map that the * element on top of the stack is a boxed value which doesn't need to be - * boxed if the type guard generated by unbox_jsval() fails. + * boxed if the type guard generated by unbox_value() fails. */ if (JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_STATUS) { @@ -12903,11 +13356,21 @@ TraceRecorder::record_NativeCallComplete() * vector for native function calls. The actual return value of the native is a JSBool * indicating the error status. */ - v_ins = lir->insLoad(LIR_ldp, native_rval_ins, 0, ACC_OTHER); + if (*pc == JSOP_NEW) { - LIns* x = lir->insEqP_0(lir->ins2(LIR_andp, v_ins, INS_CONSTWORD(JSVAL_TAGMASK))); - x = lir->insChoose(x, v_ins, INS_CONSTWORD(0), avmplus::AvmCore::use_cmov()); + LIns *cond_ins; + LIns *x; + + // v_ins := the object payload from native_rval_ins + // cond_ins := true if native_rval_ins contains a JSObject* + unbox_any_object(native_rval_ins, &v_ins, &cond_ins, ACC_OTHER); + // x := v_ins if native_rval_ins contains a JSObject*, NULL otherwise + x = lir->insChoose(cond_ins, v_ins, INS_CONSTWORD(0), avmplus::AvmCore::use_cmov()); + // v_ins := newobj_ins if native_rval_ins doesn't contain a JSObject*, + // the object payload from native_rval_ins otherwise v_ins = lir->insChoose(lir->insEqP_0(x), newobj_ins, x, avmplus::AvmCore::use_cmov()); + } else { + v_ins = lir->insLoad(LIR_ldd, native_rval_ins, 0, ACC_OTHER); } set(&v, v_ins); @@ -12923,13 +13386,18 @@ TraceRecorder::record_NativeCallComplete() * about the top of the stack here, which is where we expected boxed values. */ JS_ASSERT(&v == &cx->regs->sp[-1] && get(&v) == v_ins); - set(&v, unbox_jsval(v, v_ins, snapshot(BRANCH_EXIT))); + set(&v, unbox_value(v, native_rval_ins, 0, snapshot(BRANCH_EXIT))); + } else if (pendingSpecializedNative->flags & + (JSTN_RETURN_NULLABLE_STR | JSTN_RETURN_NULLABLE_OBJ)) { + guard(v.isNull(), + addName(lir->insEqP_0(v_ins), "guard(nullness)"), + BRANCH_EXIT); } else if (JSTN_ERRTYPE(pendingSpecializedNative) == FAIL_NEG) { /* Already added i2d in functionCall. */ - JS_ASSERT(JSVAL_IS_NUMBER(v)); + JS_ASSERT(v.isNumber()); } else { /* Convert the result to double if the builtin returns int32. */ - if (JSVAL_IS_NUMBER(v) && + if (v.isNumber() && pendingSpecializedNative->builtin->returnType() == ARGTYPE_I) { set(&v, lir->ins1(LIR_i2d, v_ins)); } @@ -12941,7 +13409,7 @@ TraceRecorder::record_NativeCallComplete() } JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) +TraceRecorder::name(Value*& vp, LIns*& ins, NameResult& nr) { JSObject* obj = cx->fp->scopeChain; if (obj != globalObj) @@ -12992,12 +13460,12 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr) static JSObject* FASTCALL MethodReadBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj) { - AutoValueRooter tvr(cx, funobj); + Value v = ObjectValue(*funobj); + AutoValueRooter tvr(cx, v); if (!obj->scope()->methodReadBarrier(cx, sprop, tvr.addr())) return NULL; - JS_ASSERT(VALUE_IS_FUNCTION(cx, tvr.value())); - return JSVAL_TO_OBJECT(tvr.value()); + return &tvr.value().toObject(); } JS_DEFINE_CALLINFO_4(static, OBJECT_FAIL, MethodReadBarrier, CONTEXT, OBJECT, SCOPEPROP, OBJECT, 0, ACC_STORE_ANY) @@ -13011,7 +13479,7 @@ JS_DEFINE_CALLINFO_4(static, OBJECT_FAIL, MethodReadBarrier, CONTEXT, OBJECT, SC * tracing (rather than emit a call to a native getter or GetAnyProperty). */ JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, jsval *outp) +TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, Value *outp) { /* * Insist that obj have js_SetProperty as its set object-op. This suffices @@ -13042,7 +13510,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, * We could specialize to guard on just JSClass.getProperty, but a mere * class guard is simpler and slightly faster. */ - if (obj->getClass()->getProperty != JS_PropertyStub) { + if (obj->getClass()->getProperty != Valueify(JS_PropertyStub)) { RETURN_STOP_A("can't trace through access to undefined property if " "JSClass.getProperty hook isn't stubbed"); } @@ -13066,7 +13534,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, } } while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit)); - set(outp, INS_VOID()); + set(outp, INS_UNDEFINED()); return ARECORD_CONTINUE; } @@ -13075,7 +13543,7 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, JS_REQUIRES_STACK RecordingStatus TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcval, - uint32 *slotp, LIns** v_insp, jsval *outp) + uint32 *slotp, LIns** v_insp, Value *outp) { const JSCodeSpec& cs = js_CodeSpec[*cx->regs->pc]; uint32 setflags = (cs.format & (JOF_INCDEC | JOF_FOR)); @@ -13138,10 +13606,7 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcva obj = obj2; } - LIns* dslots_ins = NULL; - LIns* v_ins = unbox_jsval(obj->getSlot(slot), - stobj_get_slot(obj_ins, slot, dslots_ins), - snapshot(BRANCH_EXIT)); + LIns *v_ins = unbox_slot(obj, obj_ins, slot, snapshot(BRANCH_EXIT)); /* * Joined function object stored as a method must be cloned when extracted @@ -13170,19 +13635,17 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcva } JS_REQUIRES_STACK RecordingStatus -TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ins, +TraceRecorder::denseArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_ins, LIns*& addr_ins) { - JS_ASSERT(JSVAL_IS_OBJECT(oval) && JSVAL_IS_INT(ival)); + JS_ASSERT(oval.isObject() && ival.isInt32()); - JSObject* obj = JSVAL_TO_OBJECT(oval); + JSObject* obj = &oval.toObject(); LIns* obj_ins = get(&oval); - jsint idx = JSVAL_TO_INT(ival); + jsint idx = ival.toInt32(); LIns* idx_ins = makeNumberInt32(get(&ival)); - LIns* pidx_ins = lir->insUI2P(idx_ins); VMSideExit* exit = snapshot(BRANCH_EXIT); - /* check that the index is within bounds */ LIns* dslots_ins = addName(lir->insLoad(LIR_ldp, obj_ins, offsetof(JSObject, dslots), ACC_OTHER), "dslots"); @@ -13192,9 +13655,9 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ /* If not idx < min(length, capacity), stay on trace (and read value as undefined). */ JS_ASSERT(obj->isDenseArrayMinLenCapOk()); LIns* minLenCap = - addName(stobj_get_fslot(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_MINLENCAP), "minLenCap"); + addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_MINLENCAP), "minLenCap"); LIns* br = lir->insBranch(LIR_jf, - lir->ins2(LIR_ltup, pidx_ins, minLenCap), + lir->ins2(LIR_ltui, idx_ins, minLenCap), NULL); lir->insGuard(LIR_x, NULL, createGuardRecord(exit)); @@ -13204,7 +13667,7 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT)); // Return undefined and indicate that we didn't actually read this (addr_ins). - v_ins = INS_VOID(); + v_ins = INS_UNDEFINED(); addr_ins = NULL; return RECORD_CONTINUE; } @@ -13212,39 +13675,33 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ /* Guard array min(length, capacity). */ JS_ASSERT(obj->isDenseArrayMinLenCapOk()); LIns* minLenCap = - addName(stobj_get_fslot(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_MINLENCAP), "minLenCap"); - guard(true, - lir->ins2(LIR_ltup, pidx_ins, minLenCap), - exit); + addName(stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_DENSE_ARRAY_MINLENCAP), "minLenCap"); + guard(true, lir->ins2(LIR_ltui, idx_ins, minLenCap), exit); /* Load the value and guard on its type to unbox it. */ vp = &obj->dslots[jsuint(idx)]; + JS_ASSERT(sizeof(Value) == 8); // The |3| in the following statement requires this. addr_ins = lir->ins2(LIR_addp, dslots_ins, - lir->ins2ImmI(LIR_lshp, pidx_ins, (sizeof(jsval) == 4) ? 2 : 3)); - v_ins = unbox_jsval(*vp, lir->insLoad(LIR_ldp, addr_ins, 0, ACC_OTHER), exit); + lir->ins2ImmI(LIR_lshp, lir->insUI2P(idx_ins), 3)); + v_ins = unbox_value(*vp, addr_ins, 0, exit, true); - if (JSVAL_IS_SPECIAL(*vp) && !JSVAL_IS_VOID(*vp)) { - JS_ASSERT_IF(!JSVAL_IS_BOOLEAN(*vp), *vp == JSVAL_HOLE); - guard(*vp == JSVAL_HOLE, lir->ins2(LIR_eqi, v_ins, INS_HOLE()), exit); - - /* Don't let the hole value escape. Turn it into an undefined. */ - if (*vp == JSVAL_HOLE) { - CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT)); - v_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)); - } + /* Don't let the hole value escape. Turn it into an undefined. */ + if (vp->isMagic()) { + CHECK_STATUS(guardPrototypeHasNoIndexedProperties(obj, obj_ins, MISMATCH_EXIT)); + v_ins = INS_UNDEFINED(); } return RECORD_CONTINUE; } JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::typedArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ins, +TraceRecorder::typedArrayElement(Value& oval, Value& ival, Value*& vp, LIns*& v_ins, LIns*& addr_ins) { - JS_ASSERT(JSVAL_IS_OBJECT(oval) && JSVAL_IS_INT(ival)); + JS_ASSERT(oval.isObject() && ival.isInt32()); - JSObject* obj = JSVAL_TO_OBJECT(oval); + JSObject* obj = &oval.toObject(); LIns* obj_ins = get(&oval); - jsint idx = JSVAL_TO_INT(ival); + jsint idx = ival.toInt32(); LIns* idx_ins = makeNumberInt32(get(&ival)); LIns* pidx_ins = lir->insUI2P(idx_ins); @@ -13252,7 +13709,7 @@ TraceRecorder::typedArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ JS_ASSERT(tarray); /* priv_ins will load the TypedArray* */ - LIns* priv_ins = stobj_get_const_fslot(obj_ins, JSSLOT_PRIVATE); + LIns* priv_ins = stobj_get_const_private_ptr(obj_ins); /* for out-of-range, do the same thing that the interpreter does, which is return undefined */ if ((jsuint) idx >= tarray->length) { @@ -13261,14 +13718,14 @@ TraceRecorder::typedArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_ idx_ins, lir->insLoad(LIR_ldi, priv_ins, js::TypedArray::lengthOffset(), ACC_READONLY)), BRANCH_EXIT); - v_ins = INS_VOID(); + v_ins = INS_UNDEFINED(); return ARECORD_CONTINUE; } /* * Ensure idx < length * - * NOTE! mLength is uint32, but it's guaranteed to fit in a jsval + * NOTE! mLength is uint32, but it's guaranteed to fit in a Value * int, so we can treat it as either signed or unsigned. * If the index happens to be negative, when it's treated as * unsigned it'll be a very large int, and thus won't be less than @@ -13336,18 +13793,18 @@ TraceRecorder::getProp(JSObject* obj, LIns* obj_ins) } JS_REQUIRES_STACK AbortableRecordingStatus -TraceRecorder::getProp(jsval& v) +TraceRecorder::getProp(Value& v) { - if (JSVAL_IS_PRIMITIVE(v)) + if (v.isPrimitive()) RETURN_STOP_A("primitive lhs"); - return getProp(JSVAL_TO_OBJECT(v), get(&v)); + return getProp(&v.toObject(), get(&v)); } JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_NAME() { - jsval* vp; + Value* vp; LIns* v_ins; NameResult nr; CHECK_STATUS_A(name(vp, v_ins, nr)); @@ -13358,8 +13815,8 @@ TraceRecorder::record_JSOP_NAME() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_DOUBLE() { - jsval v = jsval(atoms[GET_INDEX(cx->regs->pc)]); - stack(0, lir->insImmD(*JSVAL_TO_DOUBLE(v))); + double d = consts[GET_INDEX(cx->regs->pc)].toDouble(); + stack(0, lir->insImmD(d)); return ARECORD_CONTINUE; } @@ -13367,7 +13824,6 @@ JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_STRING() { JSAtom* atom = atoms[GET_INDEX(cx->regs->pc)]; - JS_ASSERT(ATOM_IS_STRING(atom)); stack(0, INS_ATOM(atom)); return ARECORD_CONTINUE; } @@ -13542,8 +13998,8 @@ JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_ENDINIT() { #ifdef DEBUG - jsval& v = stackval(-1); - JS_ASSERT(!JSVAL_IS_PRIMITIVE(v)); + Value& v = stackval(-1); + JS_ASSERT(!v.isPrimitive()); #endif return ARECORD_CONTINUE; } @@ -13631,13 +14087,13 @@ TraceRecorder::record_JSOP_IMACOP() static JSBool FASTCALL ObjectToIterator(JSContext* cx, JSObject *obj, int32 flags, JSObject **objp) { - AutoValueRooter tvr(cx, obj); + AutoValueRooter tvr(cx, ObjectValue(*obj)); bool ok = js_ValueToIterator(cx, flags, tvr.addr()); if (!ok) { SetBuiltinError(cx); return false; } - *objp = JSVAL_TO_OBJECT(tvr.value()); + *objp = &tvr.value().toObject(); return cx->tracerState->builtinStatus == 0; } JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, ObjectToIterator, CONTEXT, OBJECT, INT32, OBJECTPTR, 0, @@ -13646,8 +14102,8 @@ JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, ObjectToIterator, CONTEXT, OBJECT, INT32 JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_ITER() { - jsval& v = stackval(-1); - if (JSVAL_IS_PRIMITIVE(v)) + Value& v = stackval(-1); + if (v.isPrimitive()) RETURN_STOP_A("for-in on a primitive value"); RETURN_IF_XML_A(v); @@ -13673,7 +14129,7 @@ TraceRecorder::record_JSOP_ITER() } static JSBool FASTCALL -IteratorMore(JSContext *cx, JSObject *iterobj, jsval *vp) +IteratorMore(JSContext *cx, JSObject *iterobj, Value *vp) { AutoValueRooter tvr(cx); if (!js_IteratorMore(cx, iterobj, tvr.addr())) { @@ -13683,18 +14139,18 @@ IteratorMore(JSContext *cx, JSObject *iterobj, jsval *vp) *vp = tvr.value(); return cx->tracerState->builtinStatus == 0; } -JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, IteratorMore, CONTEXT, OBJECT, JSVALPTR, 0, nanojit::ACC_STORE_ANY) +JS_DEFINE_CALLINFO_3(extern, BOOL_FAIL, IteratorMore, CONTEXT, OBJECT, VALUEPTR, 0, nanojit::ACC_STORE_ANY) JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_MOREITER() { - jsval& iterobj_val = stackval(-1); - if (JSVAL_IS_PRIMITIVE(iterobj_val)) + Value& iterobj_val = stackval(-1); + if (iterobj_val.isPrimitive()) RETURN_STOP_A("for-in on a primitive value"); RETURN_IF_XML_A(iterobj_val); - JSObject* iterobj = JSVAL_TO_OBJECT(iterobj_val); + JSObject* iterobj = &iterobj_val.toObject(); LIns* iterobj_ins = get(&iterobj_val); bool cond; LIns* cond_ins; @@ -13703,10 +14159,10 @@ TraceRecorder::record_JSOP_MOREITER() if (iterobj->hasClass(&js_IteratorClass.base)) { guardClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), ACC_OTHER); NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); - jsval *cursor = ni->props_cursor; - jsval *end = ni->props_end; + void *cursor = ni->props_cursor; + void *end = ni->props_end; - LIns *ni_ins = stobj_get_const_fslot(iterobj_ins, JSSLOT_PRIVATE); + LIns *ni_ins = stobj_get_const_private_ptr(iterobj_ins); LIns *cursor_ins = addName(lir->insLoad(LIR_ldp, ni_ins, offsetof(NativeIterator, props_cursor), ACC_OTHER), "cursor"); LIns *end_ins = addName(lir->insLoad(LIR_ldp, ni_ins, offsetof(NativeIterator, props_end), ACC_OTHER), "end"); @@ -13718,7 +14174,7 @@ TraceRecorder::record_JSOP_MOREITER() enterDeepBailCall(); - LIns* vp_ins = lir->insAlloc(sizeof(jsval)); + LIns* vp_ins = lir->insAlloc(sizeof(Value)); LIns* args[] = { vp_ins, iterobj_ins, cx_ins }; LIns* ok_ins = lir->insCall(&IteratorMore_ci, args); @@ -13743,10 +14199,8 @@ TraceRecorder::record_JSOP_MOREITER() if (!TRACE_RECORDER(localCx)) return ARECORD_ABORTED; - cond = (rooter.value() == JSVAL_TRUE); - cond_ins = lir->ins2(LIR_eqp, - lir->insLoad(LIR_ldp, vp_ins, 0, ACC_OTHER), - INS_CONSTWORD(JSVAL_TRUE)); + cond = (rooter.value().isTrue()); + cond_ins = is_boxed_true(vp_ins, ACC_OTHER); } jsbytecode* pc = cx->regs->pc; @@ -13764,7 +14218,7 @@ TraceRecorder::record_JSOP_MOREITER() static JSBool FASTCALL CloseIterator(JSContext *cx, JSObject *iterobj) { - if (!js_CloseIterator(cx, OBJECT_TO_JSVAL(iterobj))) { + if (!js_CloseIterator(cx, iterobj)) { SetBuiltinError(cx); return false; } @@ -13775,7 +14229,7 @@ JS_DEFINE_CALLINFO_2(extern, BOOL_FAIL, CloseIterator, CONTEXT, OBJECT, 0, nanoj JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_ENDITER() { - JS_ASSERT(!JSVAL_IS_PRIMITIVE(stackval(-1))); + JS_ASSERT(!stackval(-1).isPrimitive()); enterDeepBailCall(); @@ -13791,60 +14245,77 @@ TraceRecorder::record_JSOP_ENDITER() return ARECORD_CONTINUE; } +#if JS_BITS_PER_WORD == 32 +JS_REQUIRES_STACK void +TraceRecorder::storeMagic(JSWhyMagic why, nanojit::LIns *addr_ins, ptrdiff_t offset, nanojit::AccSet accSet) +{ + lir->insStore(INS_CONSTU(why), addr_ins, offset + sPayloadOffset, accSet); + lir->insStore(INS_CONSTU(JSVAL_TAG_MAGIC), addr_ins, offset + sTagOffset, accSet); +} +#elif JS_BITS_PER_WORD == 64 +JS_REQUIRES_STACK void +TraceRecorder::storeMagic(JSWhyMagic why, nanojit::LIns *addr_ins, ptrdiff_t offset, nanojit::AccSet accSet) +{ + LIns *magic = INS_CONSTQWORD(BUILD_JSVAL(JSVAL_TAG_MAGIC, why)); + lir->insStore(magic, addr_ins, offset, accSet); +} +#endif + JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::unboxNextValue(LIns* &v_ins) { - jsval &iterobj_val = stackval(-1); - JSObject *iterobj = JSVAL_TO_OBJECT(iterobj_val); + Value &iterobj_val = stackval(-1); + JSObject *iterobj = &iterobj_val.toObject(); LIns* iterobj_ins = get(&iterobj_val); if (iterobj->hasClass(&js_IteratorClass.base)) { guardClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), ACC_OTHER); NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); - jsval *cursor = ni->props_cursor; - LIns *ni_ins = stobj_get_const_fslot(iterobj_ins, JSSLOT_PRIVATE); + LIns *ni_ins = stobj_get_const_private_ptr(iterobj_ins); LIns *cursor_ins = addName(lir->insLoad(LIR_ldp, ni_ins, offsetof(NativeIterator, props_cursor), ACC_OTHER), "cursor"); - /* Read the next value from the iterator. */ - jsval v = *cursor; - v_ins = addName(lir->insLoad(LIR_ldp, cursor_ins, 0, ACC_OTHER), "next"); - /* Emit code to stringify the id if necessary. */ if (!(((NativeIterator *) iterobj->getPrivate())->flags & JSITER_FOREACH)) { + /* Read the next id from the iterator. */ + jsid id = *ni->currentKey(); + LIns *id_ins = addName(lir->insLoad(LIR_ldp, cursor_ins, 0, ACC_OTHER), "id"); + /* * Most iterations over object properties never have to actually deal with * any numeric properties, so we guard here instead of branching. */ - guard(!JSVAL_IS_INT(v), - lir->insEqP_0(lir->ins2(LIR_andp, v_ins, INS_CONSTWORD(JSVAL_INT))), - snapshot(BRANCH_EXIT)); + guard(JSID_IS_STRING(id), is_string_id(id_ins), snapshot(BRANCH_EXIT)); - if (JSVAL_IS_INT(v)) { + if (JSID_IS_STRING(id)) { + v_ins = unbox_string_id(id_ins); + } else { /* id is an integer, convert to a string. */ - LIns* args[] = { p2i(lir->ins2ImmI(LIR_rshp, v_ins, 1)), cx_ins }; + JS_ASSERT(JSID_IS_INT(id)); + LIns *id_to_int_ins = unbox_int_id(id_ins); + LIns* args[] = { id_to_int_ins, cx_ins }; v_ins = lir->insCall(&js_IntToString_ci, args); guard(false, lir->insEqP_0(v_ins), OOM_EXIT); - } else { - JS_ASSERT(JSVAL_IS_STRING(v)); - v_ins = lir->ins2(LIR_andp, v_ins, lir->insImmWord(~JSVAL_TAGMASK)); } + + /* Increment the cursor by one jsid and store it back. */ + cursor_ins = lir->ins2(LIR_addp, cursor_ins, INS_CONSTWORD(sizeof(jsid))); } else { - v_ins = unbox_jsval(v, v_ins, snapshot(BRANCH_EXIT)); + /* Read the next value from the iterator. */ + Value v = *ni->currentValue(); + v_ins = unbox_value(v, cursor_ins, 0, snapshot(BRANCH_EXIT)); + + /* Increment the cursor by one Value and store it back. */ + cursor_ins = lir->ins2(LIR_addp, cursor_ins, INS_CONSTWORD(sizeof(Value))); } - /* Increment the cursor and store it back. */ - cursor_ins = lir->ins2(LIR_addp, cursor_ins, INS_CONSTWORD(sizeof(jsval))); lir->insStore(LIR_stp, cursor_ins, ni_ins, offsetof(NativeIterator, props_cursor), ACC_OTHER); } else { guardNotClass(iterobj_ins, &js_IteratorClass.base, snapshot(BRANCH_EXIT), ACC_OTHER); - jsval v = cx->iterValue; - v_ins = addName(lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, iterValue), ACC_OTHER), "next"); - - v_ins = unbox_jsval(v, v_ins, snapshot(BRANCH_EXIT)); - - lir->insStore(INS_CONSTWORD(JSVAL_HOLE), cx_ins, offsetof(JSContext, iterValue), ACC_OTHER); + v_ins = unbox_value(cx->iterValue, cx_ins, offsetof(JSContext, iterValue), + snapshot(BRANCH_EXIT)); + storeMagic(JS_NO_ITER_VALUE, cx_ins, offsetof(JSContext, iterValue), ACC_OTHER); } return ARECORD_CONTINUE; @@ -13853,7 +14324,7 @@ TraceRecorder::unboxNextValue(LIns* &v_ins) JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_FORNAME() { - jsval* vp; + Value* vp; LIns* x_ins; NameResult nr; CHECK_STATUS_A(name(vp, x_ins, nr)); @@ -13945,7 +14416,7 @@ TraceRecorder::traverseScopeChain(JSObject *obj, LIns *obj_ins, JSObject *target for (;;) { if (searchObj != globalObj) { - JSClass* clasp = searchObj->getClass(); + Class* clasp = searchObj->getClass(); if (clasp == &js_BlockClass) { foundBlockObj = true; } else if (clasp == &js_CallClass && @@ -14063,8 +14534,8 @@ TraceRecorder::record_JSOP_BINDNAME() // We don't have the scope chain on trace, so instead we get a start object // that is on the scope chain and doesn't skip the target object (the one // that contains the property). - jsval *callee = &cx->fp->argv[-2]; - obj = JSVAL_TO_OBJECT(*callee)->getParent(); + Value *callee = &cx->fp->argv[-2]; + obj = callee->toObject().getParent(); if (obj == globalObj) { stack(0, INS_CONSTOBJ(obj)); return ARECORD_CONTINUE; @@ -14109,21 +14580,22 @@ TraceRecorder::record_JSOP_THROW() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_IN() { - jsval& rval = stackval(-1); - jsval& lval = stackval(-2); + Value& rval = stackval(-1); + Value& lval = stackval(-2); - if (JSVAL_IS_PRIMITIVE(rval)) + if (rval.isPrimitive()) RETURN_STOP_A("JSOP_IN on non-object right operand"); - JSObject* obj = JSVAL_TO_OBJECT(rval); + JSObject* obj = &rval.toObject(); LIns* obj_ins = get(&rval); jsid id; LIns* x; - if (JSVAL_IS_INT(lval)) { - id = INT_JSVAL_TO_JSID(lval); + if (lval.isInt32()) { + if (!js_Int32ToId(cx, lval.toInt32(), &id)) + RETURN_ERROR_A("OOM converting left operand of JSOP_IN to string"); LIns* args[] = { makeNumberInt32(get(&lval)), obj_ins, cx_ins }; x = lir->insCall(&js_HasNamedPropertyInt32_ci, args); - } else if (JSVAL_IS_STRING(lval)) { + } else if (lval.isString()) { if (!js_ValueToStringId(cx, lval, &id)) RETURN_ERROR_A("left operand of JSOP_IN didn't convert to a string-id"); LIns* args[] = { get(&lval), obj_ins, cx_ins }; @@ -14132,7 +14604,7 @@ TraceRecorder::record_JSOP_IN() RETURN_STOP_A("string or integer expected"); } - guard(false, lir->ins2ImmI(LIR_eqi, x, JSVAL_TO_SPECIAL(JSVAL_VOID)), OOM_EXIT); + guard(false, lir->ins2ImmI(LIR_eqi, x, JS_NEITHER), OOM_EXIT); x = lir->ins2ImmI(LIR_eqi, x, 1); TraceMonitor &localtm = *traceMonitor; @@ -14173,25 +14645,26 @@ TraceRecorder::record_JSOP_IN() } static JSBool FASTCALL -HasInstance(JSContext* cx, JSObject* ctor, jsval val) +HasInstance(JSContext* cx, JSObject* ctor, ValueArgType arg) { + const Value &argref = ValueArgToConstRef(arg); JSBool result = JS_FALSE; - if (!ctor->map->ops->hasInstance(cx, ctor, val, &result)) + if (!ctor->map->ops->hasInstance(cx, ctor, &argref, &result)) SetBuiltinError(cx); return result; } -JS_DEFINE_CALLINFO_3(static, BOOL_FAIL, HasInstance, CONTEXT, OBJECT, JSVAL, 0, ACC_STORE_ANY) +JS_DEFINE_CALLINFO_3(static, BOOL_FAIL, HasInstance, CONTEXT, OBJECT, VALUE, 0, ACC_STORE_ANY) JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_INSTANCEOF() { // If the rhs isn't an object, we are headed for a TypeError. - jsval& ctor = stackval(-1); - if (JSVAL_IS_PRIMITIVE(ctor)) + Value& ctor = stackval(-1); + if (ctor.isPrimitive()) RETURN_STOP_A("non-object on rhs of instanceof"); - jsval& val = stackval(-2); - LIns* val_ins = box_jsval(val, get(&val)); + Value& val = stackval(-2); + LIns* val_ins = box_value_for_native_call(val, get(&val)); enterDeepBailCall(); LIns* args[] = {val_ins, get(&ctor), cx_ins}; @@ -14264,7 +14737,7 @@ JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_ENUMELEM() { /* - * To quote from jsops.cpp's JSOP_ENUMELEM case: + * To quote from jsinterp.cpp's JSOP_ENUMELEM case: * Funky: the value to set is under the [obj, id] pair. */ return setElem(-2, -1, -3); @@ -14327,7 +14800,7 @@ TraceRecorder::record_JSOP_LAMBDA() * JSOP_SETMETHOD or JSOP_INITMETHOD, since we optimize away the clone for * these combinations and clone only if the "method value" escapes. * - * See jsops.cpp, the JSOP_LAMBDA null closure case. The JSOP_SETMETHOD and + * See jsinterp.cpp, the JSOP_LAMBDA null closure case. The JSOP_SETMETHOD and * JSOP_INITMETHOD logic governing the early ARECORD_CONTINUE returns below * must agree with the corresponding break-from-do-while(0) logic there. */ @@ -14337,10 +14810,10 @@ TraceRecorder::record_JSOP_LAMBDA() JSOp op2 = JSOp(cx->regs->pc[JSOP_LAMBDA_LENGTH]); if (op2 == JSOP_SETMETHOD) { - jsval lval = stackval(-1); + Value lval = stackval(-1); - if (!JSVAL_IS_PRIMITIVE(lval) && - JSVAL_TO_OBJECT(lval)->getClass() == &js_ObjectClass) { + if (!lval.isPrimitive() && + lval.toObject().getClass() == &js_ObjectClass) { stack(0, INS_CONSTOBJ(FUN_OBJECT(fun))); return ARECORD_CONTINUE; } @@ -14395,12 +14868,12 @@ TraceRecorder::record_JSOP_LAMBDA_FC() if (fun->u.i.nupvars) { JSUpvarArray *uva = fun->u.i.script->upvars(); for (uint32 i = 0, n = uva->length; i < n; i++) { - jsval v; + Value v; LIns* upvar_ins = upvar(fun->u.i.script, uva, i, v); if (!upvar_ins) return ARECORD_STOP; LIns* dslots_ins = NULL; - stobj_set_dslot(call_ins, i, dslots_ins, box_jsval(v, upvar_ins)); + stobj_set_dslot(call_ins, i, dslots_ins, v, upvar_ins); } } @@ -14426,7 +14899,7 @@ JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_IFPRIMTOP() { // Traces are type-specialized, including null vs. object, so we need do - // nothing here. The upstream unbox_jsval called after valueOf or toString + // nothing here. The upstream unbox_value called after valueOf or toString // from an imacro (e.g.) will fork the trace for us, allowing us to just // follow along mindlessly :-). return ARECORD_CONTINUE; @@ -14475,9 +14948,9 @@ TraceRecorder::guardArgsLengthNotAssigned(LIns* argsobj_ins) { // The following implements IsOverriddenArgsLength on trace. // The '2' bit is set if length was overridden. - LIns *len_ins = stobj_get_fslot(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH); - LIns *ovr_ins = lir->ins2(LIR_andp, len_ins, INS_CONSTWORD(2)); - guard(true, lir->insEqP_0(ovr_ins), snapshot(BRANCH_EXIT)); + LIns *len_ins = stobj_get_fslot_uint32(argsobj_ins, JSObject::JSSLOT_ARGS_LENGTH); + LIns *ovr_ins = lir->ins2(LIR_andi, len_ins, INS_CONST(2)); + guard(true, lir->insEqI_0(ovr_ins), snapshot(BRANCH_EXIT)); return len_ins; } @@ -14493,9 +14966,9 @@ TraceRecorder::record_JSOP_ARGCNT() // We also have to check that arguments.length has not been mutated // at record time, because if so we will generate incorrect constant // LIR, which will assert in alu(). - if (cx->fp->argsobj && JSVAL_TO_OBJECT(cx->fp->argsobj)->isArgsLengthOverridden()) + if (cx->fp->argsobj && cx->fp->argsobj->isArgsLengthOverridden()) RETURN_STOP_A("can't trace JSOP_ARGCNT if arguments.length has been modified"); - LIns *a_ins = get(&cx->fp->argsobj); + LIns *a_ins = getFrameObjPtr(&cx->fp->argsobj); if (callDepth == 0) { LIns *br = lir->insBranch(LIR_jt, lir->insEqP_0(a_ins), NULL); guardArgsLengthNotAssigned(a_ins); @@ -14631,11 +15104,11 @@ TraceRecorder::record_JSOP_RETRVAL() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_GETGVAR() { - jsval slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; - if (JSVAL_IS_NULL(slotval)) + Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; + if (slotval.isNull()) return ARECORD_CONTINUE; // We will see JSOP_NAME from the interpreter's jump, so no-op here. - uint32 slot = JSVAL_TO_INT(slotval); + uint32 slot = slotval.toInt32(); if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); @@ -14647,11 +15120,11 @@ TraceRecorder::record_JSOP_GETGVAR() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_SETGVAR() { - jsval slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; - if (JSVAL_IS_NULL(slotval)) + Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; + if (slotval.isNull()) return ARECORD_CONTINUE; // We will see JSOP_NAME from the interpreter's jump, so no-op here. - uint32 slot = JSVAL_TO_INT(slotval); + uint32 slot = slotval.toInt32(); if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); @@ -14663,12 +15136,12 @@ TraceRecorder::record_JSOP_SETGVAR() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_INCGVAR() { - jsval slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; - if (JSVAL_IS_NULL(slotval)) + Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; + if (slotval.isNull()) // We will see JSOP_INCNAME from the interpreter's jump, so no-op here. return ARECORD_CONTINUE; - uint32 slot = JSVAL_TO_INT(slotval); + uint32 slot = slotval.toInt32(); if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); @@ -14679,12 +15152,12 @@ TraceRecorder::record_JSOP_INCGVAR() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_DECGVAR() { - jsval slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; - if (JSVAL_IS_NULL(slotval)) + Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; + if (slotval.isNull()) // We will see JSOP_INCNAME from the interpreter's jump, so no-op here. return ARECORD_CONTINUE; - uint32 slot = JSVAL_TO_INT(slotval); + uint32 slot = slotval.toInt32(); if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); @@ -14695,12 +15168,12 @@ TraceRecorder::record_JSOP_DECGVAR() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_GVARINC() { - jsval slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; - if (JSVAL_IS_NULL(slotval)) + Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; + if (slotval.isNull()) // We will see JSOP_INCNAME from the interpreter's jump, so no-op here. return ARECORD_CONTINUE; - uint32 slot = JSVAL_TO_INT(slotval); + uint32 slot = slotval.toInt32(); if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); @@ -14711,12 +15184,12 @@ TraceRecorder::record_JSOP_GVARINC() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_GVARDEC() { - jsval slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; - if (JSVAL_IS_NULL(slotval)) + Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; + if (slotval.isNull()) // We will see JSOP_INCNAME from the interpreter's jump, so no-op here. return ARECORD_CONTINUE; - uint32 slot = JSVAL_TO_INT(slotval); + uint32 slot = slotval.toInt32(); if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); @@ -14910,31 +15383,28 @@ TraceRecorder::record_JSOP_STARTXMLEXPR() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_CALLPROP() { - jsval& l = stackval(-1); + Value& l = stackval(-1); JSObject* obj; LIns* obj_ins; LIns* this_ins; - if (!JSVAL_IS_PRIMITIVE(l)) { - obj = JSVAL_TO_OBJECT(l); + if (!l.isPrimitive()) { + obj = &l.toObject(); obj_ins = get(&l); this_ins = obj_ins; // |this| for subsequent call } else { JSProtoKey protoKey; debug_only_stmt(const char* protoname = NULL;) - if (JSVAL_IS_STRING(l)) { + if (l.isString()) { protoKey = JSProto_String; debug_only_stmt(protoname = "String.prototype";) - } else if (JSVAL_IS_NUMBER(l)) { + } else if (l.isNumber()) { protoKey = JSProto_Number; debug_only_stmt(protoname = "Number.prototype";) - } else if (JSVAL_IS_SPECIAL(l)) { - if (l == JSVAL_VOID) - RETURN_STOP_A("callprop on void"); - guard(false, lir->ins2ImmI(LIR_eqi, get(&l), JSVAL_TO_SPECIAL(JSVAL_VOID)), MISMATCH_EXIT); + } else if (l.isBoolean()) { protoKey = JSProto_Boolean; debug_only_stmt(protoname = "Boolean.prototype";) } else { - JS_ASSERT(JSVAL_IS_NULL(l) || JSVAL_IS_VOID(l)); + JS_ASSERT(l.isNull() || l.isUndefined()); RETURN_STOP_A("callprop on null or void"); } @@ -14950,25 +15420,20 @@ TraceRecorder::record_JSOP_CALLPROP() PCVal pcval; CHECK_STATUS_A(test_property_cache(obj, obj_ins, obj2, pcval)); - if (pcval.isObject()) { - if (pcval.isNull()) - RETURN_STOP_A("callprop of missing method"); + if (pcval.isNull()) + RETURN_STOP_A("callprop of missing method"); - JS_ASSERT(pcval.toObject()->isFunction()); - - if (JSVAL_IS_PRIMITIVE(l)) { - JSFunction* fun = GET_FUNCTION_PRIVATE(cx, pcval.toObject()); - if (!PRIMITIVE_THIS_TEST(fun, l)) + if (pcval.isFunObj()) { + if (l.isPrimitive()) { + JSFunction* fun = GET_FUNCTION_PRIVATE(cx, &pcval.toFunObj()); + if (!PrimitiveThisTest(fun, l)) RETURN_STOP_A("callee does not accept primitive |this|"); } - - set(&l, INS_CONSTOBJ(pcval.toObject())); + set(&l, INS_CONSTOBJ(&pcval.toFunObj())); } else { - if (JSVAL_IS_PRIMITIVE(l)) + if (l.isPrimitive()) RETURN_STOP_A("callprop of primitive method"); - JS_ASSERT_IF(pcval.isSprop(), !pcval.toSprop()->isMethod()); - CHECK_STATUS_A(propTail(obj, obj_ins, obj2, pcval, NULL, NULL, &l)); } stack(0, this_ins); @@ -14998,14 +15463,14 @@ TraceRecorder::record_JSOP_INDEXBASE() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_RESETBASE() { - atoms = cx->fp->script->atomMap.vector; + updateAtoms(); return ARECORD_CONTINUE; } JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_RESETBASE0() { - atoms = cx->fp->script->atomMap.vector; + updateAtoms(); return ARECORD_CONTINUE; } @@ -15031,7 +15496,7 @@ TraceRecorder::record_JSOP_STOP() * interpreter's JSOP_STOP case will return from the imacro, back to * the pc after the calling op, still in the same JSStackFrame. */ - atoms = fp->script->atomMap.vector; + updateAtoms(fp->script); return ARECORD_CONTINUE; } @@ -15049,7 +15514,7 @@ TraceRecorder::record_JSOP_STOP() JS_ASSERT(fp->thisv == fp->argv[-1]); rval_ins = get(&fp->argv[-1]); } else { - rval_ins = INS_VOID(); + rval_ins = INS_UNDEFINED(); } clearCurrentFrameSlotsFromTracker(nativeFrameTracker); return ARECORD_CONTINUE; @@ -15058,11 +15523,11 @@ TraceRecorder::record_JSOP_STOP() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_GETXPROP() { - jsval& l = stackval(-1); - if (JSVAL_IS_PRIMITIVE(l)) + Value& l = stackval(-1); + if (l.isPrimitive()) RETURN_STOP_A("primitive-this for GETXPROP?"); - jsval* vp; + Value* vp; LIns* v_ins; NameResult nr; CHECK_STATUS_A(name(vp, v_ins, nr)); @@ -15088,7 +15553,7 @@ TraceRecorder::record_JSOP_ENTERBLOCK() JSObject* obj; obj = cx->fp->script->getObject(getFullIndex(0)); - LIns* void_ins = INS_VOID(); + LIns* void_ins = INS_UNDEFINED(); for (int i = 0, n = OBJ_BLOCK_COUNT(cx, obj); i < n; i++) stack(i, void_ins); return ARECORD_CONTINUE; @@ -15121,15 +15586,15 @@ TraceRecorder::record_JSOP_ARRAYPUSH() uint32_t slot = GET_UINT16(cx->regs->pc); JS_ASSERT(cx->fp->script->nfixed <= slot); JS_ASSERT(cx->fp->slots() + slot < cx->regs->sp - 1); - jsval &arrayval = cx->fp->slots()[slot]; - JS_ASSERT(JSVAL_IS_OBJECT(arrayval)); - JS_ASSERT(JSVAL_TO_OBJECT(arrayval)->isDenseArray()); + Value &arrayval = cx->fp->slots()[slot]; + JS_ASSERT(arrayval.isObject()); + JS_ASSERT(arrayval.toObject().isDenseArray()); LIns *array_ins = get(&arrayval); - jsval &elt = stackval(-1); - LIns *elt_ins = box_jsval(elt, get(&elt)); + Value &elt = stackval(-1); + LIns *elt_ins = box_value_for_native_call(elt, get(&elt)); LIns *args[] = { elt_ins, array_ins, cx_ins }; - LIns *ok_ins = lir->insCall(&js_ArrayCompPush_ci, args); + LIns *ok_ins = lir->insCall(&js_ArrayCompPush_tn_ci, args); guard(false, lir->insEqI_0(ok_ins), OOM_EXIT); return ARECORD_CONTINUE; } @@ -15161,7 +15626,7 @@ TraceRecorder::record_JSOP_GETTHISPROP() * ARECORD_STOP if thisv is not available. */ JS_ASSERT(cx->fp->flags & JSFRAME_COMPUTED_THIS); - CHECK_STATUS_A(getProp(JSVAL_TO_OBJECT(cx->fp->thisv), this_ins)); + CHECK_STATUS_A(getProp(&cx->fp->thisv.toObject(), this_ins)); return ARECORD_CONTINUE; } @@ -15201,17 +15666,17 @@ TraceRecorder::record_JSOP_INDEXBASE3() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_CALLGVAR() { - jsval slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; - if (JSVAL_IS_NULL(slotval)) + Value slotval = cx->fp->slots()[GET_SLOTNO(cx->regs->pc)]; + if (slotval.isNull()) // We will see JSOP_CALLNAME from the interpreter's jump, so no-op here. return ARECORD_CONTINUE; - uint32 slot = JSVAL_TO_INT(slotval); + uint32 slot = slotval.toInt32(); if (!lazilyImportGlobalSlot(slot)) RETURN_STOP_A("lazy import of global slot failed"); - jsval& v = globalObj->getSlotRef(slot); + Value& v = globalObj->getSlotRef(slot); stack(0, get(&v)); stack(1, INS_NULL()); return ARECORD_CONTINUE; @@ -15258,9 +15723,9 @@ TraceRecorder::record_JSOP_INT32() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_LENGTH() { - jsval& l = stackval(-1); - if (JSVAL_IS_PRIMITIVE(l)) { - if (!JSVAL_IS_STRING(l)) + Value& l = stackval(-1); + if (l.isPrimitive()) { + if (!l.isString()) RETURN_STOP_A("non-string primitive JSOP_LENGTH unsupported"); set(&l, lir->ins1(LIR_i2d, p2i(lir->insLoad(LIR_ldp, get(&l), @@ -15268,7 +15733,7 @@ TraceRecorder::record_JSOP_LENGTH() return ARECORD_CONTINUE; } - JSObject* obj = JSVAL_TO_OBJECT(l); + JSObject* obj = &l.toObject(); LIns* obj_ins = get(&l); if (obj->isArguments()) { @@ -15285,7 +15750,7 @@ TraceRecorder::record_JSOP_LENGTH() // slot_ins is the value from the slot; right-shift by 2 bits to get // the length (see GetArgsLength in jsfun.cpp). - LIns* v_ins = lir->ins1(LIR_i2d, lir->ins2ImmI(LIR_rshi, p2i(slot_ins), 2)); + LIns* v_ins = lir->ins1(LIR_i2d, lir->ins2ImmI(LIR_rshi, slot_ins, 1)); set(&l, v_ins); return ARECORD_CONTINUE; } @@ -15298,12 +15763,12 @@ TraceRecorder::record_JSOP_LENGTH() JS_ASSERT(obj->isSlowArray()); guardClass(obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT), ACC_OTHER); } - v_ins = lir->ins1(LIR_i2d, p2i(stobj_get_fslot(obj_ins, JSObject::JSSLOT_ARRAY_LENGTH))); + v_ins = lir->ins1(LIR_i2d, stobj_get_fslot_uint32(obj_ins, JSObject::JSSLOT_ARRAY_LENGTH)); } else if (OkToTraceTypedArrays && js_IsTypedArray(obj)) { // Ensure array is a typed array and is the same type as what was written guardClass(obj_ins, obj->getClass(), snapshot(BRANCH_EXIT), ACC_OTHER); v_ins = lir->ins1(LIR_i2d, lir->insLoad(LIR_ldi, - stobj_get_const_fslot(obj_ins, JSSLOT_PRIVATE), + stobj_get_const_private_ptr(obj_ins), js::TypedArray::lengthOffset(), ACC_READONLY)); } else { if (!obj->isNative()) @@ -15330,15 +15795,14 @@ TraceRecorder::record_JSOP_NEWARRAY() LIns* dslots_ins = NULL; uint32 count = 0; for (uint32 i = 0; i < len; i++) { - jsval& v = stackval(int(i) - int(len)); - if (v != JSVAL_HOLE) + Value& v = stackval(int(i) - int(len)); + if (!v.isMagic()) count++; - LIns* elt_ins = box_jsval(v, get(&v)); - stobj_set_dslot(v_ins, i, dslots_ins, elt_ins); + stobj_set_dslot(v_ins, i, dslots_ins, v, get(&v)); } if (count > 0) - stobj_set_fslot(v_ins, JSObject::JSSLOT_DENSE_ARRAY_COUNT, INS_CONST(count)); + set_array_fslot(v_ins, JSObject::JSSLOT_DENSE_ARRAY_COUNT, count); stack(-int(len), v_ins); return ARECORD_CONTINUE; @@ -15347,7 +15811,7 @@ TraceRecorder::record_JSOP_NEWARRAY() JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_HOLE() { - stack(0, INS_HOLE()); + stack(0, INS_CONST(JS_ARRAY_HOLE)); return ARECORD_CONTINUE; } @@ -15362,10 +15826,10 @@ static const uint32 sMaxConcatNSize = 32; JS_REQUIRES_STACK AbortableRecordingStatus TraceRecorder::record_JSOP_OBJTOSTR() { - jsval &v = stackval(-1); - JS_ASSERT_IF(cx->fp->imacpc, JSVAL_IS_PRIMITIVE(v) && + Value &v = stackval(-1); + JS_ASSERT_IF(cx->fp->imacpc, v.isPrimitive() && *cx->fp->imacpc == JSOP_OBJTOSTR); - if (JSVAL_IS_PRIMITIVE(v)) + if (v.isPrimitive()) return ARECORD_CONTINUE; CHECK_STATUS_A(guardNativeConversion(v)); return InjectStatus(callImacro(objtostr_imacros.toString)); @@ -15376,7 +15840,7 @@ TraceRecorder::record_JSOP_CONCATN() { JSFrameRegs regs = *cx->regs; uint32 argc = GET_ARGC(regs.pc); - jsval *argBase = regs.sp - argc; + Value *argBase = regs.sp - argc; /* Prevent code/alloca explosion. */ if (argc > sMaxConcatNSize) @@ -15386,8 +15850,8 @@ TraceRecorder::record_JSOP_CONCATN() int32_t bufSize = argc * sizeof(JSString *); LIns *buf_ins = lir->insAlloc(bufSize); int32_t d = 0; - for (jsval *vp = argBase; vp != regs.sp; ++vp, d += sizeof(void *)) { - JS_ASSERT(JSVAL_IS_PRIMITIVE(*vp)); + for (Value *vp = argBase; vp != regs.sp; ++vp, d += sizeof(void *)) { + JS_ASSERT(vp->isPrimitive()); lir->insStore(stringify(*vp), buf_ins, d, ACC_OTHER); } @@ -15483,22 +15947,22 @@ DumpPeerStability(TraceMonitor* tm, const void* ip, JSObject* globalObj, uint32 if (looped) JS_ASSERT(f->nStackTypes == length); for (unsigned i = 0; i < f->nStackTypes; i++) - debug_only_printf(LC_TMRecorder, "%c", typeChar[f->stackTypeMap()[i]]); + debug_only_printf(LC_TMRecorder, "%c", TypeToChar(f->stackTypeMap()[i])); debug_only_print0(LC_TMRecorder, " GLOBALS="); for (unsigned i = 0; i < f->nGlobalTypes(); i++) - debug_only_printf(LC_TMRecorder, "%c", typeChar[f->globalTypeMap()[i]]); + debug_only_printf(LC_TMRecorder, "%c", TypeToChar(f->globalTypeMap()[i])); debug_only_print0(LC_TMRecorder, "\n"); UnstableExit* uexit = f->unstableExits; while (uexit != NULL) { debug_only_print0(LC_TMRecorder, "EXIT "); - TraceType* m = uexit->exit->fullTypeMap(); + JSValueType* m = uexit->exit->fullTypeMap(); debug_only_print0(LC_TMRecorder, "STACK="); for (unsigned i = 0; i < uexit->exit->numStackSlots; i++) - debug_only_printf(LC_TMRecorder, "%c", typeChar[m[i]]); + debug_only_printf(LC_TMRecorder, "%c", TypeToChar(m[i])); debug_only_print0(LC_TMRecorder, " GLOBALS="); for (unsigned i = 0; i < uexit->exit->numGlobalSlots; i++) { debug_only_printf(LC_TMRecorder, "%c", - typeChar[m[uexit->exit->numStackSlots + i]]); + TypeToChar(m[uexit->exit->numStackSlots + i])); } debug_only_print0(LC_TMRecorder, "\n"); uexit = uexit->next; @@ -15530,11 +15994,11 @@ StartTraceVis(const char* filename = "tracevis.dat") } JS_FRIEND_API(JSBool) -StartTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +StartTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { JSBool ok; - if (argc > 0 && JSVAL_IS_STRING(argv[0])) { + if (argc > 0 && argv[0].isString()) { JSString *str = JSVAL_TO_STRING(argv[0]); char *filename = js_DeflateString(cx, str->chars(), str->length()); if (!filename) @@ -15568,7 +16032,7 @@ StopTraceVis() } JS_FRIEND_API(JSBool) -StopTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +StopTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { JSBool ok = StopTraceVis(); @@ -15583,14 +16047,14 @@ StopTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval #endif /* MOZ_TRACEVIS */ JS_REQUIRES_STACK void -TraceRecorder::captureStackTypes(unsigned callDepth, TraceType* typeMap) +TraceRecorder::captureStackTypes(unsigned callDepth, JSValueType* typeMap) { CaptureTypesVisitor capVisitor(cx, typeMap, !!oracle); VisitStackSlots(capVisitor, cx, callDepth); } JS_REQUIRES_STACK void -TraceRecorder::determineGlobalTypes(TraceType* typeMap) +TraceRecorder::determineGlobalTypes(JSValueType* typeMap) { DetermineTypesVisitor detVisitor(*this, typeMap); VisitGlobalSlots(detVisitor, cx, *tree->globalSlots); diff --git a/js/src/jstracer.h b/js/src/jstracer.h index aba0e1134532..248dc98258f4 100644 --- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -321,71 +321,20 @@ public: } }; -#if defined(_MSC_VER) && _MSC_VER >= 1400 || (defined(__GNUC__) && __GNUC__ >= 4) -#define USE_TRACE_TYPE_ENUM -#endif - -/* - * The types of values calculated during tracing, used to specialize operations - * to the types of those values. These loosely correspond to the values of the - * JSVAL_* language types, but we add a few further divisions to enable further - * optimization at execution time. Do not rely on this loose correspondence for - * correctness without adding static assertions! - * - * The ifdefs enforce that this enum occupies only one byte of memory, where - * possible. If it doesn't, type maps will occupy more space but should - * otherwise work correctly. A static assertion in jstracer.cpp verifies that - * this requirement is correctly enforced by these compilers. - */ -enum TraceType_ -#if defined(_MSC_VER) && _MSC_VER >= 1400 -: int8_t -#endif -{ - TT_OBJECT = 0, /* pointer to JSObject whose class is not js_FunctionClass */ - TT_INT32 = 1, /* 32-bit signed integer */ - TT_DOUBLE = 2, /* pointer to jsdouble */ - TT_JSVAL = 3, /* arbitrary jsval */ - TT_STRING = 4, /* pointer to JSString */ - TT_NULL = 5, /* null */ - TT_SPECIAL = 6, /* true, false, hole, or areturn (0, 1, 6, or 8) */ - TT_VOID = 7, /* undefined (2) */ - TT_FUNCTION = 8, /* pointer to JSObject whose class is js_FunctionClass */ - TT_MAGIC = 9, /* a 'magic' value, aka a hole */ - TT_IGNORE = 10 -} -#if defined(__GNUC__) && defined(USE_TRACE_TYPE_ENUM) -__attribute__((packed)) -#endif -; - -#ifdef USE_TRACE_TYPE_ENUM -typedef TraceType_ TraceType; -#else -typedef int8_t TraceType; -#endif - -/* - * This indicates an invalid type or error. Note that it should not be used in typemaps, - * because it is the wrong size. It can only be used as a uint32, for example as the - * return value from a function that returns a type as a uint32. - */ -const uint32 TT_INVALID = uint32(-1); - typedef Queue SlotList; -class TypeMap : public Queue { +class TypeMap : public Queue { Oracle *oracle; public: - TypeMap(nanojit::Allocator* alloc) : Queue(alloc) {} + TypeMap(nanojit::Allocator* alloc) : Queue(alloc) {} void set(unsigned stackSlots, unsigned ngslots, - const TraceType* stackTypeMap, const TraceType* globalTypeMap); + const JSValueType* stackTypeMap, const JSValueType* globalTypeMap); JS_REQUIRES_STACK void captureTypes(JSContext* cx, JSObject* globalObj, SlotList& slots, unsigned callDepth, bool speculate); JS_REQUIRES_STACK void captureMissingGlobalTypes(JSContext* cx, JSObject* globalObj, SlotList& slots, unsigned stackSlots, bool speculate); bool matches(TypeMap& other) const; - void fromRaw(TraceType* other, unsigned numSlots); + void fromRaw(JSValueType* other, unsigned numSlots); }; #define JS_TM_EXITCODES(_) \ @@ -463,7 +412,7 @@ struct VMSideExit : public nanojit::SideExit FrameInfo* recursive_down; unsigned hitcount; unsigned slurpFailSlot; - TraceType slurpType; + JSValueType slurpType; /* * Ordinarily 0. If a slow native function is atop the stack, the 1 bit is @@ -483,20 +432,20 @@ struct VMSideExit : public nanojit::SideExit nativeCalleeWord = uintptr_t(callee) | (constructing ? 1 : 0); } - inline TraceType* stackTypeMap() { - return (TraceType*)(this + 1); + inline JSValueType* stackTypeMap() { + return (JSValueType*)(this + 1); } - inline TraceType& stackType(unsigned i) { + inline JSValueType& stackType(unsigned i) { JS_ASSERT(i < numStackSlots); return stackTypeMap()[i]; } - inline TraceType* globalTypeMap() { - return (TraceType*)(this + 1) + this->numStackSlots; + inline JSValueType* globalTypeMap() { + return (JSValueType*)(this + 1) + this->numStackSlots; } - inline TraceType* fullTypeMap() { + inline JSValueType* fullTypeMap() { return stackTypeMap(); } @@ -639,8 +588,8 @@ struct FrameInfo { bool is_constructing() const { return (argc & CONSTRUCTING_FLAG) != 0; } // The typemap just before the callee is called. - TraceType* get_typemap() { return (TraceType*) (this+1); } - const TraceType* get_typemap() const { return (TraceType*) (this+1); } + JSValueType* get_typemap() { return (JSValueType*) (this+1); } + const JSValueType* get_typemap() const { return (JSValueType*) (this+1); } }; struct UnstableExit @@ -728,17 +677,17 @@ struct TreeFragment : public LinkableFragment ptrdiff_t nativeStackBase; unsigned maxCallDepth; /* All embedded GC things are registered here so the GC can scan them. */ - Queue gcthings; + Queue gcthings; Queue sprops; unsigned maxNativeStackSlots; inline unsigned nGlobalTypes() { return typeMap.length() - nStackTypes; } - inline TraceType* globalTypeMap() { + inline JSValueType* globalTypeMap() { return typeMap.data() + nStackTypes; } - inline TraceType* stackTypeMap() { + inline JSValueType* stackTypeMap() { return typeMap.data(); } @@ -769,9 +718,9 @@ struct ArgsPrivateNative { return (ArgsPrivateNative*) new (alloc) char[sizeof(ArgsPrivateNative) + argc]; } - TraceType *typemap() + JSValueType *typemap() { - return (TraceType*) (this+1); + return (JSValueType*) (this+1); } }; @@ -1010,13 +959,14 @@ class TraceRecorder Tracker nativeFrameTracker; /* The start of the global object's dslots we assume for the trackers. */ - jsval* global_dslots; + Value* global_dslots; /* The number of interpreted calls entered (and not yet left) since recording began. */ unsigned callDepth; /* The current atom table, mirroring the interpreter loop's variable of the same name. */ JSAtom** atoms; + Value* consts; /* FIXME: Dead, but soon to be used for something or other. */ Queue cfgMerges; @@ -1045,7 +995,7 @@ class TraceRecorder JSSpecializedNative* pendingSpecializedNative; /* Carry whether this is a jsval on the native stack from finishGetProp to monitorRecording. */ - jsval* pendingUnboxSlot; + Value* pendingUnboxSlot; /* Carry a guard condition to the beginning of the next monitorRecording. */ nanojit::LIns* pendingGuardCondition; @@ -1056,16 +1006,17 @@ class TraceRecorder /* Temporary JSSpecializedNative used to describe non-specialized fast natives. */ JSSpecializedNative generatedSpecializedNative; - /* Temporary TraceType array used to construct temporary typemaps. */ - js::Vector tempTypeMap; + /* Temporary JSValueType array used to construct temporary typemaps. */ + js::Vector tempTypeMap; /************************************************************* 10 bajillion member functions */ - nanojit::LIns* insImmVal(jsval val); + nanojit::LIns* insImmVal(const Value& val); nanojit::LIns* insImmObj(JSObject* obj); nanojit::LIns* insImmFun(JSFunction* fun); nanojit::LIns* insImmStr(JSString* str); nanojit::LIns* insImmSprop(JSScopeProperty* sprop); + nanojit::LIns* insImmId(jsid id); nanojit::LIns* p2i(nanojit::LIns* ins); /* @@ -1096,18 +1047,24 @@ class TraceRecorder JS_REQUIRES_STACK void assertDownFrameIsConsistent(VMSideExit* anchor, FrameInfo* fi); - JS_REQUIRES_STACK void captureStackTypes(unsigned callDepth, TraceType* typeMap); + JS_REQUIRES_STACK void captureStackTypes(unsigned callDepth, JSValueType* typeMap); - bool isGlobal(jsval* p) const; - ptrdiff_t nativeGlobalSlot(jsval *p) const; - ptrdiff_t nativeGlobalOffset(jsval* p) const; - JS_REQUIRES_STACK ptrdiff_t nativeStackOffset(jsval* p) const; - JS_REQUIRES_STACK ptrdiff_t nativeStackSlot(jsval* p) const; - JS_REQUIRES_STACK ptrdiff_t nativespOffset(jsval* p) const; - JS_REQUIRES_STACK void import(nanojit::LIns* base, ptrdiff_t offset, jsval* p, TraceType t, + bool isVoidPtrGlobal(const void* p) const; + bool isGlobal(const Value* p) const; + ptrdiff_t nativeGlobalSlot(const Value *p) const; + ptrdiff_t nativeGlobalOffset(const Value* p) const; + JS_REQUIRES_STACK ptrdiff_t nativeStackOffsetImpl(const void* p) const; + JS_REQUIRES_STACK ptrdiff_t nativeStackOffset(const Value* p) const; + JS_REQUIRES_STACK ptrdiff_t nativeStackSlotImpl(const void* p) const; + JS_REQUIRES_STACK ptrdiff_t nativeStackSlot(const Value* p) const; + JS_REQUIRES_STACK ptrdiff_t nativespOffsetImpl(const void* p) const; + JS_REQUIRES_STACK ptrdiff_t nativespOffset(const Value* p) const; + JS_REQUIRES_STACK void importImpl(nanojit::LIns* base, ptrdiff_t offset, const void* p, JSValueType t, + const char *prefix, uintN index, JSStackFrame *fp); + JS_REQUIRES_STACK void import(nanojit::LIns* base, ptrdiff_t offset, const Value* p, JSValueType t, const char *prefix, uintN index, JSStackFrame *fp); JS_REQUIRES_STACK void import(TreeFragment* tree, nanojit::LIns* sp, unsigned stackSlots, - unsigned callDepth, unsigned ngslots, TraceType* typeMap); + unsigned callDepth, unsigned ngslots, JSValueType* typeMap); void trackNativeStackUse(unsigned slots); JS_REQUIRES_STACK bool isValidSlot(JSScope* scope, JSScopeProperty* sprop); @@ -1118,25 +1075,15 @@ class TraceRecorder JS_REQUIRES_STACK void guard(bool expected, nanojit::LIns* cond, VMSideExit* exit); JS_REQUIRES_STACK nanojit::LIns* guard_xov(nanojit::LOpcode op, nanojit::LIns* d0, nanojit::LIns* d1, VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpInt32Slot(nanojit::LIns* val_ins, jsval* vp, - VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpDoubleSlot(nanojit::LIns* val_ins, jsval* vp, + JS_REQUIRES_STACK nanojit::LIns* slurpNonDoubleObjectSlot(nanojit::LIns* val_ins, ptrdiff_t offset, + JSValueType type, VMSideExit* exit); + JS_REQUIRES_STACK nanojit::LIns* slurpObjectSlot(nanojit::LIns* val_ins, ptrdiff_t offset, + JSValueType type, VMSideExit* exit); + JS_REQUIRES_STACK nanojit::LIns* slurpDoubleSlot(nanojit::LIns* val_ins, ptrdiff_t offset, VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpStringSlot(nanojit::LIns* val_ins, jsval* vp, - VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpObjectSlot(nanojit::LIns* val_ins, jsval* vp, - VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpFunctionSlot(nanojit::LIns* val_ins, jsval* vp, - VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpNullSlot(nanojit::LIns* val_ins, jsval* vp, - VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpSpecialSlot(nanojit::LIns* val_ins, jsval* vp, - VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpVoidSlot(nanojit::LIns* val_ins, jsval* vp, - VMSideExit* exit); - JS_REQUIRES_STACK nanojit::LIns* slurpSlot(nanojit::LIns* val_ins, jsval* vp, - VMSideExit* exit); - JS_REQUIRES_STACK void slurpSlot(nanojit::LIns* val_ins, jsval* vp, SlurpInfo* info); + JS_REQUIRES_STACK nanojit::LIns* slurpSlot(nanojit::LIns* val_ins, ptrdiff_t offset, Value* vp, VMSideExit* exit); + JS_REQUIRES_STACK void slurpSlot(nanojit::LIns* val_ins, ptrdiff_t offset, Value* vp, SlurpInfo* info); + JS_REQUIRES_STACK void slurpFrameObjPtrSlot(nanojit::LIns* val_ins, ptrdiff_t offset, JSObject** p, SlurpInfo* info); JS_REQUIRES_STACK AbortableRecordingStatus slurpDownFrames(jsbytecode* return_pc); JS_REQUIRES_STACK AbortableRecordingStatus upRecursion(); JS_REQUIRES_STACK AbortableRecordingStatus downRecursion(); @@ -1145,29 +1092,44 @@ class TraceRecorder nanojit::LIns* writeBack(nanojit::LIns* i, nanojit::LIns* base, ptrdiff_t offset, bool demote); - JS_REQUIRES_STACK void set(jsval* p, nanojit::LIns* l, bool demote = true); - nanojit::LIns* getFromTracker(jsval* p); - JS_REQUIRES_STACK nanojit::LIns* get(jsval* p); - JS_REQUIRES_STACK nanojit::LIns* attemptImport(jsval* p); - JS_REQUIRES_STACK nanojit::LIns* addr(jsval* p); - JS_REQUIRES_STACK bool known(jsval* p); +#ifdef DEBUG + bool isValidFrameObjPtr(JSObject **obj); +#endif + + JS_REQUIRES_STACK void setImpl(void* p, nanojit::LIns* l, bool demote = true); + JS_REQUIRES_STACK void set(Value* p, nanojit::LIns* l, bool demote = true); + JS_REQUIRES_STACK void setFrameObjPtr(JSObject** p, nanojit::LIns* l, bool demote = true); + nanojit::LIns* getFromTrackerImpl(const void *p); + nanojit::LIns* getFromTracker(const Value* p); + JS_REQUIRES_STACK nanojit::LIns* getImpl(const void* p); + JS_REQUIRES_STACK nanojit::LIns* get(const Value* p); + JS_REQUIRES_STACK nanojit::LIns* getFrameObjPtr(JSObject** p); + JS_REQUIRES_STACK nanojit::LIns* attemptImport(const Value* p); + JS_REQUIRES_STACK nanojit::LIns* addr(Value* p); + + JS_REQUIRES_STACK bool knownImpl(const void* p); + JS_REQUIRES_STACK bool known(const Value* p); + JS_REQUIRES_STACK bool known(JSObject** p); JS_REQUIRES_STACK void checkForGlobalObjectReallocation(); JS_REQUIRES_STACK TypeConsensus selfTypeStability(SlotMap& smap); JS_REQUIRES_STACK TypeConsensus peerTypeStability(SlotMap& smap, const void* ip, TreeFragment** peer); - JS_REQUIRES_STACK jsval& argval(unsigned n) const; - JS_REQUIRES_STACK jsval& varval(unsigned n) const; - JS_REQUIRES_STACK jsval& stackval(int n) const; + JS_REQUIRES_STACK Value& argval(unsigned n) const; + JS_REQUIRES_STACK Value& varval(unsigned n) const; + JS_REQUIRES_STACK Value& stackval(int n) const; + + JS_REQUIRES_STACK void updateAtoms(); + JS_REQUIRES_STACK void updateAtoms(JSScript *script); struct NameResult { // |tracked| is true iff the result of the name lookup is a variable that // is already in the tracker. The rest of the fields are set only if // |tracked| is false. bool tracked; - jsval v; // current property value + Value v; // current property value JSObject *obj; // Call object where name was found nanojit::LIns *obj_ins; // LIR value for obj JSScopeProperty *sprop; // sprop name was resolved to @@ -1177,14 +1139,14 @@ class TraceRecorder JS_REQUIRES_STACK nanojit::LIns* entryScopeChain() const; JS_REQUIRES_STACK JSStackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const; JS_REQUIRES_STACK RecordingStatus traverseScopeChain(JSObject *obj, nanojit::LIns *obj_ins, JSObject *obj2, nanojit::LIns *&obj2_ins); - JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, jsval*& vp, nanojit::LIns*& ins, NameResult& nr); - JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* sprop, jsid id, jsval*& vp, nanojit::LIns*& ins, NameResult& nr); + JS_REQUIRES_STACK AbortableRecordingStatus scopeChainProp(JSObject* obj, Value*& vp, nanojit::LIns*& ins, NameResult& nr); + JS_REQUIRES_STACK RecordingStatus callProp(JSObject* obj, JSProperty* sprop, jsid id, Value*& vp, nanojit::LIns*& ins, NameResult& nr); JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n); JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i); JS_REQUIRES_STACK nanojit::LIns* var(unsigned n); JS_REQUIRES_STACK void var(unsigned n, nanojit::LIns* i); - JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, jsval& v); + JS_REQUIRES_STACK nanojit::LIns* upvar(JSScript* script, JSUpvarArray* uva, uintN index, Value& v); nanojit::LIns* stackLoad(nanojit::LIns* addr, nanojit::AccSet accSet, uint8 type); JS_REQUIRES_STACK nanojit::LIns* stack(int n); JS_REQUIRES_STACK void stack(int n, nanojit::LIns* i); @@ -1196,7 +1158,7 @@ class TraceRecorder nanojit::LIns* d2i(nanojit::LIns* f, bool resultCanBeImpreciseIfFractional = false); nanojit::LIns* f2u(nanojit::LIns* f); JS_REQUIRES_STACK nanojit::LIns* makeNumberInt32(nanojit::LIns* f); - JS_REQUIRES_STACK nanojit::LIns* stringify(jsval& v); + JS_REQUIRES_STACK nanojit::LIns* stringify(const Value& v); JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins); @@ -1209,10 +1171,10 @@ class TraceRecorder #ifdef NANOJIT_IA32 JS_REQUIRES_STACK AbortableRecordingStatus tableswitch(); #endif - JS_REQUIRES_STACK RecordingStatus inc(jsval& v, jsint incr, bool pre = true); - JS_REQUIRES_STACK RecordingStatus inc(jsval v, nanojit::LIns*& v_ins, jsint incr, + JS_REQUIRES_STACK RecordingStatus inc(Value& v, jsint incr, bool pre = true); + JS_REQUIRES_STACK RecordingStatus inc(const Value &v, nanojit::LIns*& v_ins, jsint incr, bool pre = true); - JS_REQUIRES_STACK RecordingStatus incHelper(jsval v, nanojit::LIns* v_ins, + JS_REQUIRES_STACK RecordingStatus incHelper(const Value &v, nanojit::LIns* v_ins, nanojit::LIns*& v_after, jsint incr); JS_REQUIRES_STACK AbortableRecordingStatus incProp(jsint incr, bool pre = true); JS_REQUIRES_STACK RecordingStatus incElem(jsint incr, bool pre = true); @@ -1220,10 +1182,10 @@ class TraceRecorder JS_REQUIRES_STACK void strictEquality(bool equal, bool cmpCase); JS_REQUIRES_STACK AbortableRecordingStatus equality(bool negate, bool tryBranchAfterCond); - JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(jsval& l, jsval& r, + JS_REQUIRES_STACK AbortableRecordingStatus equalityHelper(Value& l, Value& r, nanojit::LIns* l_ins, nanojit::LIns* r_ins, bool negate, bool tryBranchAfterCond, - jsval& rval); + Value& rval); JS_REQUIRES_STACK AbortableRecordingStatus relational(nanojit::LOpcode op, bool tryBranchAfterCond); JS_REQUIRES_STACK RecordingStatus unary(nanojit::LOpcode op); @@ -1247,88 +1209,134 @@ class TraceRecorder PropertyCacheEntry* entry, PCVal& pcval); - void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot, + void stobj_set_fslot(nanojit::LIns *obj_ins, unsigned slot, const Value &v, nanojit::LIns* v_ins); - void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot, nanojit::LIns*& dslots_ins, - nanojit::LIns* v_ins); - void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot, nanojit::LIns*& dslots_ins, - nanojit::LIns* v_ins); + void stobj_set_dslot(nanojit::LIns *obj_ins, unsigned slot, + nanojit::LIns*& dslots_ins, const Value &v, nanojit::LIns* v_ins); + void stobj_set_slot(nanojit::LIns* obj_ins, unsigned slot, + nanojit::LIns*& dslots_ins, const Value &v, nanojit::LIns* v_ins); + void set_array_fslot(nanojit::LIns *obj_ins, unsigned slot, uint32 val); - nanojit::LIns* stobj_get_const_fslot(nanojit::LIns* obj_ins, unsigned slot); - nanojit::LIns* stobj_get_fslot(nanojit::LIns* obj_ins, unsigned slot); - nanojit::LIns* stobj_get_dslot(nanojit::LIns* obj_ins, unsigned index, - nanojit::LIns*& dslots_ins); - nanojit::LIns* stobj_get_slot(nanojit::LIns* obj_ins, unsigned slot, - nanojit::LIns*& dslots_ins); + nanojit::LIns* stobj_get_const_private_ptr(nanojit::LIns* obj_ins); + nanojit::LIns* stobj_get_fslot_uint32(nanojit::LIns* obj_ins, unsigned slot); + nanojit::LIns* stobj_get_fslot_ptr(nanojit::LIns* obj_ins, unsigned slot); + nanojit::LIns* unbox_slot(JSObject *obj, nanojit::LIns *obj_ins, uint32 slot, + VMSideExit *exit); nanojit::LIns* stobj_get_parent(nanojit::LIns* obj_ins); nanojit::LIns* stobj_get_private(nanojit::LIns* obj_ins); - nanojit::LIns* stobj_get_proto(nanojit::LIns* obj_ins); - JS_REQUIRES_STACK AbortableRecordingStatus name(jsval*& vp, nanojit::LIns*& ins, NameResult& nr); + JS_REQUIRES_STACK AbortableRecordingStatus name(Value*& vp, nanojit::LIns*& ins, NameResult& nr); JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins, uint32 *slotp, nanojit::LIns** v_insp, - jsval* outp); + Value* outp); JS_REQUIRES_STACK RecordingStatus propTail(JSObject* obj, nanojit::LIns* obj_ins, JSObject* obj2, PCVal pcval, uint32 *slotp, nanojit::LIns** v_insp, - jsval* outp); - JS_REQUIRES_STACK RecordingStatus denseArrayElement(jsval& oval, jsval& idx, jsval*& vp, + Value* outp); + JS_REQUIRES_STACK RecordingStatus denseArrayElement(Value& oval, Value& idx, Value*& vp, nanojit::LIns*& v_ins, nanojit::LIns*& addr_ins); - JS_REQUIRES_STACK AbortableRecordingStatus typedArrayElement(jsval& oval, jsval& idx, jsval*& vp, + JS_REQUIRES_STACK AbortableRecordingStatus typedArrayElement(Value& oval, Value& idx, Value*& vp, nanojit::LIns*& v_ins, nanojit::LIns*& addr_ins); JS_REQUIRES_STACK AbortableRecordingStatus getProp(JSObject* obj, nanojit::LIns* obj_ins); - JS_REQUIRES_STACK AbortableRecordingStatus getProp(jsval& v); + JS_REQUIRES_STACK AbortableRecordingStatus getProp(Value& v); JS_REQUIRES_STACK RecordingStatus getThis(nanojit::LIns*& this_ins); + JS_REQUIRES_STACK void storeMagic(JSWhyMagic why, nanojit::LIns *addr_ins, ptrdiff_t offset, + nanojit::AccSet accSet); JS_REQUIRES_STACK AbortableRecordingStatus unboxNextValue(nanojit::LIns* &v_ins); JS_REQUIRES_STACK VMSideExit* enterDeepBailCall(); JS_REQUIRES_STACK void leaveDeepBailCall(); - JS_REQUIRES_STACK RecordingStatus primitiveToStringInPlace(jsval* vp); + JS_REQUIRES_STACK RecordingStatus primitiveToStringInPlace(Value* vp); JS_REQUIRES_STACK void finishGetProp(nanojit::LIns* obj_ins, nanojit::LIns* vp_ins, - nanojit::LIns* ok_ins, jsval* outp); - JS_REQUIRES_STACK RecordingStatus getPropertyByName(nanojit::LIns* obj_ins, jsval* idvalp, - jsval* outp); + nanojit::LIns* ok_ins, Value* outp); + JS_REQUIRES_STACK RecordingStatus getPropertyByName(nanojit::LIns* obj_ins, Value* idvalp, + Value* outp); JS_REQUIRES_STACK RecordingStatus getPropertyByIndex(nanojit::LIns* obj_ins, - nanojit::LIns* index_ins, jsval* outp); - JS_REQUIRES_STACK RecordingStatus getPropertyById(nanojit::LIns* obj_ins, jsval* outp); + nanojit::LIns* index_ins, Value* outp); + JS_REQUIRES_STACK RecordingStatus getPropertyById(nanojit::LIns* obj_ins, Value* outp); JS_REQUIRES_STACK RecordingStatus getPropertyWithNativeGetter(nanojit::LIns* obj_ins, JSScopeProperty* sprop, - jsval* outp); + Value* outp); JS_REQUIRES_STACK RecordingStatus getPropertyWithScriptGetter(JSObject *obj, nanojit::LIns* obj_ins, JSScopeProperty* sprop); JS_REQUIRES_STACK RecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins, JSScopeProperty* sprop, - jsval v, nanojit::LIns* v_ins); - JS_REQUIRES_STACK RecordingStatus setProp(jsval &l, PropertyCacheEntry* entry, + const Value &v, nanojit::LIns* v_ins); + JS_REQUIRES_STACK RecordingStatus setProp(Value &l, PropertyCacheEntry* entry, JSScopeProperty* sprop, - jsval &v, nanojit::LIns*& v_ins, + Value &v, nanojit::LIns*& v_ins, bool isDefinitelyAtom); JS_REQUIRES_STACK RecordingStatus setCallProp(JSObject *callobj, nanojit::LIns *callobj_ins, JSScopeProperty *sprop, nanojit::LIns *v_ins, - jsval v); + const Value &v); JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByName(nanojit::LIns* obj_ins, - jsval* idvalp, jsval* rvalp, + Value* idvalp, Value* rvalp, bool init); JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByIndex(nanojit::LIns* obj_ins, nanojit::LIns* index_ins, - jsval* rvalp, bool init); + Value* rvalp, bool init); JS_REQUIRES_STACK AbortableRecordingStatus setElem(int lval_spindex, int idx_spindex, int v_spindex); - JS_REQUIRES_STACK nanojit::LIns* box_jsval(jsval v, nanojit::LIns* v_ins); - JS_REQUIRES_STACK nanojit::LIns* unbox_jsval(jsval v, nanojit::LIns* v_ins, VMSideExit* exit); - JS_REQUIRES_STACK void guardClassHelper(bool cond, nanojit::LIns* obj_ins, JSClass* clasp, + void box_undefined_into(nanojit::LIns *dstaddr_ins, ptrdiff_t offset, nanojit::AccSet); +#if JS_BITS_PER_WORD == 32 + void box_null_into(nanojit::LIns *dstaddr_ins, ptrdiff_t offset, nanojit::AccSet); + nanojit::LIns* unbox_number_as_double(nanojit::LIns* vaddr_ins, ptrdiff_t offset, + nanojit::LIns* tag_ins, VMSideExit* exit, + nanojit::AccSet); + nanojit::LIns* unbox_object(nanojit::LIns* vaddr_ins, ptrdiff_t offset, + nanojit::LIns* tag_ins, JSValueType type, VMSideExit* exit, + nanojit::AccSet); + nanojit::LIns* unbox_non_double_object(nanojit::LIns* vaddr_ins, ptrdiff_t offset, + nanojit::LIns* tag_ins, JSValueType type, + VMSideExit* exit, nanojit::AccSet); +#elif JS_BITS_PER_WORD == 64 + nanojit::LIns* non_double_object_value_has_type(nanojit::LIns* v_ins, JSValueType type); + nanojit::LIns* unpack_ptr(nanojit::LIns* v_ins); + nanojit::LIns* unbox_number_as_double(nanojit::LIns* v_ins, VMSideExit* exit); + nanojit::LIns* unbox_object(nanojit::LIns* v_ins, JSValueType type, VMSideExit* exit); + nanojit::LIns* unbox_non_double_object(nanojit::LIns* v_ins, JSValueType type, VMSideExit* exit); +#endif + + nanojit::LIns* unbox_value(const Value& v, nanojit::LIns* vaddr_ins, + ptrdiff_t offset, VMSideExit* exit, + bool force_double=false); + void unbox_any_object(nanojit::LIns* vaddr_ins, nanojit::LIns** obj_ins, + nanojit::LIns** is_obj_ins, nanojit::AccSet); + nanojit::LIns* is_boxed_true(nanojit::LIns* vaddr_ins, nanojit::AccSet); + + nanojit::LIns* is_string_id(nanojit::LIns* id_ins); + nanojit::LIns* unbox_string_id(nanojit::LIns* id_ins); + nanojit::LIns* unbox_int_id(nanojit::LIns* id_ins); + + /* Box a slot on trace into the given address at the given offset. */ + void box_value_into(const Value& v, nanojit::LIns* v_ins, + nanojit::LIns* dstaddr_ins, ptrdiff_t offset, + nanojit::AccSet); + + /* + * Box a slot so that it may be passed with value semantics to a native. On + * 32-bit, this currently means boxing the value into insAlloc'd memory and + * returning the address which is passed as a Value*. On 64-bit, this + * currently means returning the boxed value which is passed as a jsval. + */ + nanojit::LIns* box_value_for_native_call(const Value& v, nanojit::LIns* v_ins); + + /* Box a slot into insAlloc'd memory. */ + nanojit::LIns* box_value_into_alloc(const Value& v, nanojit::LIns* v_ins); + + JS_REQUIRES_STACK void guardClassHelper(bool cond, nanojit::LIns* obj_ins, Class* clasp, VMSideExit* exit, nanojit::AccSet accSet); - JS_REQUIRES_STACK void guardClass(nanojit::LIns* obj_ins, JSClass* clasp, + JS_REQUIRES_STACK void guardClass(nanojit::LIns* obj_ins, Class* clasp, VMSideExit* exit, nanojit::AccSet accSet); - JS_REQUIRES_STACK void guardNotClass(nanojit::LIns* obj_ins, JSClass* clasp, + JS_REQUIRES_STACK void guardNotClass(nanojit::LIns* obj_ins, Class* clasp, VMSideExit* exit, nanojit::AccSet accSet); JS_REQUIRES_STACK void guardDenseArray(nanojit::LIns* obj_ins, ExitType exitType); JS_REQUIRES_STACK void guardDenseArray(nanojit::LIns* obj_ins, VMSideExit* exit); @@ -1338,13 +1346,13 @@ class TraceRecorder JS_REQUIRES_STACK RecordingStatus guardPrototypeHasNoIndexedProperties(JSObject* obj, nanojit::LIns* obj_ins, ExitType exitType); - JS_REQUIRES_STACK RecordingStatus guardNativeConversion(jsval& v); + JS_REQUIRES_STACK RecordingStatus guardNativeConversion(Value& v); JS_REQUIRES_STACK JSStackFrame* entryFrame() const; JS_REQUIRES_STACK void clearEntryFrameSlotsFromTracker(Tracker& which); JS_REQUIRES_STACK void clearCurrentFrameSlotsFromTracker(Tracker& which); JS_REQUIRES_STACK void clearFrameSlotsFromTracker(Tracker& which, JSStackFrame* fp, unsigned nslots); JS_REQUIRES_STACK void putActivationObjects(); - JS_REQUIRES_STACK RecordingStatus guardCallee(jsval& callee); + JS_REQUIRES_STACK RecordingStatus guardCallee(Value& callee); JS_REQUIRES_STACK JSStackFrame *guardArguments(JSObject *obj, nanojit::LIns* obj_ins, unsigned *depthp); JS_REQUIRES_STACK nanojit::LIns* guardArgsLengthNotAssigned(nanojit::LIns* argsobj_ins); @@ -1352,11 +1360,11 @@ class TraceRecorder nanojit::LIns*& proto_ins); JS_REQUIRES_STACK RecordingStatus getClassPrototype(JSProtoKey key, nanojit::LIns*& proto_ins); - JS_REQUIRES_STACK RecordingStatus newArray(JSObject* ctor, uint32 argc, jsval* argv, - jsval* rval); - JS_REQUIRES_STACK RecordingStatus newString(JSObject* ctor, uint32 argc, jsval* argv, - jsval* rval); - JS_REQUIRES_STACK RecordingStatus interpretedFunctionCall(jsval& fval, JSFunction* fun, + JS_REQUIRES_STACK RecordingStatus newArray(JSObject* ctor, uint32 argc, Value* argv, + Value* rval); + JS_REQUIRES_STACK RecordingStatus newString(JSObject* ctor, uint32 argc, Value* argv, + Value* rval); + JS_REQUIRES_STACK RecordingStatus interpretedFunctionCall(Value& fval, JSFunction* fun, uintN argc, bool constructing); JS_REQUIRES_STACK void propagateFailureToBuiltinStatus(nanojit::LIns *ok_ins, nanojit::LIns *&status_ins); @@ -1366,7 +1374,7 @@ class TraceRecorder JSScopeProperty* sprop, nanojit::LIns* obj_ins, bool setflag, - nanojit::LIns* boxed_ins); + nanojit::LIns* addr_boxed_val_ins); JS_REQUIRES_STACK RecordingStatus callSpecializedNative(JSNativeTraceInfo* trcinfo, uintN argc, bool constructing); JS_REQUIRES_STACK RecordingStatus callNative(uintN argc, JSOp mode); @@ -1382,9 +1390,9 @@ class TraceRecorder JS_REQUIRES_STACK jsatomid getFullIndex(ptrdiff_t pcoff = 0); - JS_REQUIRES_STACK TraceType determineSlotType(jsval* vp); + JS_REQUIRES_STACK JSValueType determineSlotType(Value* vp); - JS_REQUIRES_STACK RecordingStatus setUpwardTrackedVar(jsval* stackVp, jsval v, + JS_REQUIRES_STACK RecordingStatus setUpwardTrackedVar(Value* stackVp, const Value& v, nanojit::LIns* v_ins); JS_REQUIRES_STACK AbortableRecordingStatus compile(); @@ -1397,7 +1405,7 @@ class TraceRecorder JS_REQUIRES_STACK void adjustCallerTypes(TreeFragment* f); JS_REQUIRES_STACK void prepareTreeCall(TreeFragment* inner); JS_REQUIRES_STACK void emitTreeCall(TreeFragment* inner, VMSideExit* exit); - JS_REQUIRES_STACK void determineGlobalTypes(TraceType* typeMap); + JS_REQUIRES_STACK void determineGlobalTypes(JSValueType* typeMap); JS_REQUIRES_STACK VMSideExit* downSnapshot(FrameInfo* downFrame); JS_REQUIRES_STACK TreeFragment* findNestedCompatiblePeer(TreeFragment* f); JS_REQUIRES_STACK AbortableRecordingStatus attemptTreeCall(TreeFragment* inner, @@ -1422,7 +1430,7 @@ class TraceRecorder JS_REQUIRES_STACK TraceRecorder(JSContext* cx, VMSideExit*, VMFragment*, - unsigned stackSlots, unsigned ngslots, TraceType* typeMap, + unsigned stackSlots, unsigned ngslots, JSValueType* typeMap, VMSideExit* expectedInnerExit, jsbytecode* outerTree, uint32 outerArgc, RecordReason reason, bool speculate); @@ -1449,7 +1457,7 @@ class TraceRecorder public: static bool JS_REQUIRES_STACK startRecorder(JSContext*, VMSideExit*, VMFragment*, - unsigned stackSlots, unsigned ngslots, TraceType* typeMap, + unsigned stackSlots, unsigned ngslots, JSValueType* typeMap, VMSideExit* expectedInnerExit, jsbytecode* outerTree, uint32 outerArgc, RecordReason reason, bool speculate); @@ -1549,8 +1557,8 @@ GetBuiltinFunction(JSContext *cx, uintN index); extern void SetMaxCodeCacheBytes(JSContext* cx, uint32 bytes); -extern bool -NativeToValue(JSContext* cx, jsval& v, TraceType type, double* slot); +extern void +ExternNativeToValue(JSContext* cx, Value& v, JSValueType type, double* slot); #ifdef MOZ_TRACEVIS @@ -1558,13 +1566,13 @@ extern JS_FRIEND_API(bool) StartTraceVis(const char* filename); extern JS_FRIEND_API(JSBool) -StartTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +StartTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval); extern JS_FRIEND_API(bool) StopTraceVis(); extern JS_FRIEND_API(JSBool) -StopTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +StopTraceVisNative(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval); /* Must contain no more than 16 items. */ enum TraceVisState { diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index 36b77b3ba3c9..d3101c7baf4c 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -81,11 +81,11 @@ ArrayBuffer::fromJSObject(JSObject *obj) } JSBool -ArrayBuffer::prop_getByteLength(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +ArrayBuffer::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp) { ArrayBuffer *abuf = ArrayBuffer::fromJSObject(obj); if (abuf) - *vp = INT_TO_JSVAL(jsint(abuf->byteLength)); + vp->setInt32(jsint(abuf->byteLength)); return true; } @@ -103,13 +103,13 @@ ArrayBuffer::class_finalize(JSContext *cx, JSObject *obj) */ JSBool ArrayBuffer::class_constructor(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) + uintN argc, Value *argv, Value *rval) { if (!JS_IsConstructing(cx)) { obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass); if (!obj) return false; - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); } return create(cx, obj, argc, argv, rval); @@ -117,13 +117,13 @@ ArrayBuffer::class_constructor(JSContext *cx, JSObject *obj, bool ArrayBuffer::create(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) + uintN argc, Value *argv, Value *rval) { if (!obj) { obj = NewBuiltinClassInstance(cx, &ArrayBuffer::jsclass); if (!obj) return false; - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); } if (argc == 0) { @@ -135,10 +135,10 @@ ArrayBuffer::create(JSContext *cx, JSObject *obj, int32_t nbytes; if (!ValueToECMAInt32(cx, argv[0], &nbytes)) return false; - if (nbytes < 0 || !INT_FITS_IN_JSVAL(nbytes)) { + if (nbytes < 0) { /* * We're just not going to support arrays that are bigger than what will fit - * as an integer jsval; if someone actually ever complains (validly), then we + * as an integer value; if someone actually ever complains (validly), then we * can fix. */ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, @@ -224,12 +224,12 @@ TypedArray::isArrayIndex(JSContext *cx, jsid id, jsuint *ip) return false; } -typedef jsval (* TypedArrayPropertyGetter)(TypedArray *tarray); +typedef Value (* TypedArrayPropertyGetter)(TypedArray *tarray); template class TypedArrayGetter { public: - static inline bool get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { + static inline bool get(JSContext *cx, JSObject *obj, jsid id, Value *vp) { do { if (js_IsTypedArray(obj)) { TypedArray *tarray = TypedArray::fromJSObject(obj); @@ -242,50 +242,50 @@ class TypedArrayGetter { } }; -inline jsval +inline Value getBuffer(TypedArray *tarray) { - return OBJECT_TO_JSVAL(tarray->bufferJS); + return ObjectValue(*tarray->bufferJS); } JSBool -TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +TypedArray::prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return TypedArrayGetter::get(cx, obj, id, vp); } -inline jsval +inline Value getByteOffset(TypedArray *tarray) { - return INT_TO_JSVAL(tarray->byteOffset); + return Int32Value(tarray->byteOffset); } JSBool -TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +TypedArray::prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return TypedArrayGetter::get(cx, obj, id, vp); } -inline jsval +inline Value getByteLength(TypedArray *tarray) { - return INT_TO_JSVAL(tarray->byteLength); + return Int32Value(tarray->byteLength); } JSBool -TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +TypedArray::prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return TypedArrayGetter::get(cx, obj, id, vp); } -inline jsval +inline Value getLength(TypedArray *tarray) { - return INT_TO_JSVAL(tarray->length); + return Int32Value(tarray->length); } JSBool -TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +TypedArray::prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp) { return TypedArrayGetter::get(cx, obj, id, vp); } @@ -298,7 +298,7 @@ TypedArray::obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JS_ASSERT(tarray); if (tarray->isArrayIndex(cx, id)) { - *propp = (JSProperty *) id; + *propp = (JSProperty *) 1; /* non-null to indicate found */ *objp = obj; return true; } @@ -327,7 +327,7 @@ TypedArray::obj_trace(JSTracer *trc, JSObject *obj) JSBool TypedArray::obj_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { - *attrsp = (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) + *attrsp = (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) ? JSPROP_PERMANENT | JSPROP_READONLY : JSPROP_PERMANENT | JSPROP_ENUMERATE; return true; @@ -497,29 +497,29 @@ class TypedArrayTemplate static JSFunctionSpec jsfuncs[]; - static inline JSClass *slowClass() + static inline Class *slowClass() { return &TypedArray::slowClasses[ArrayTypeID()]; } - static inline JSClass *fastClass() + static inline Class *fastClass() { return &TypedArray::fastClasses[ArrayTypeID()]; } - static JSObjectOps *getObjectOps(JSContext *cx, JSClass *clasp) + static JSObjectOps *getObjectOps(JSContext *cx, Class *clasp) { return &fastObjectOps; } static JSBool - obj_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) + obj_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); JS_ASSERT(tarray); - if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { - *vp = INT_TO_JSVAL(tarray->length); + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + vp->setNumber(tarray->length); return true; } @@ -534,11 +534,11 @@ class TypedArrayTemplate JSObject *proto = obj->getProto(); if (!proto) { - *vp = JSVAL_VOID; + vp->setUndefined(); return true; } - *vp = JSVAL_VOID; + vp->setUndefined(); if (js_LookupPropertyWithFlags(cx, proto, id, cx->resolveFlags, &obj2, &prop) < 0) return false; @@ -556,13 +556,13 @@ class TypedArrayTemplate } static JSBool - obj_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) + obj_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); JS_ASSERT(tarray); - if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { - *vp = INT_TO_JSVAL(tarray->length); + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + vp->setNumber(tarray->length); return true; } @@ -579,30 +579,30 @@ class TypedArrayTemplate // these objects. This is especially true when these arrays // are used to implement HTML Canvas 2D's PixelArray objects, // which used to be plain old arrays. - *vp = JSVAL_VOID; + vp->setUndefined(); return true; } - if (JSVAL_IS_INT(*vp)) { - tarray->setIndex(index, NativeType(JSVAL_TO_INT(*vp))); + if (vp->isInt32()) { + tarray->setIndex(index, NativeType(vp->toInt32())); return true; } jsdouble d; - if (JSVAL_IS_DOUBLE(*vp)) { - d = *JSVAL_TO_DOUBLE(*vp); - } else if (JSVAL_IS_NULL(*vp)) { + if (vp->isDouble()) { + d = vp->toDouble(); + } else if (vp->isNull()) { d = 0.0f; - } else if (JSVAL_IS_PRIMITIVE(*vp)) { - JS_ASSERT(JSVAL_IS_STRING(*vp) || JSVAL_IS_SPECIAL(*vp)); - if (JSVAL_IS_STRING(*vp)) { + } else if (vp->isPrimitive()) { + JS_ASSERT(vp->isString() || vp->isUndefined() || vp->isBoolean()); + if (vp->isString()) { // note that ValueToNumber will always succeed with a string arg ValueToNumber(cx, *vp, &d); - } else if (*vp == JSVAL_VOID) { + } else if (vp->isUndefined()) { d = js_NaN; } else { - d = (double) JSVAL_TO_BOOLEAN(*vp); + d = (double) vp->toBoolean(); } } else { // non-primitive assignments become NaN or 0 (for float/int arrays) @@ -634,20 +634,21 @@ class TypedArrayTemplate } static JSBool - obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs) + obj_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, + PropertyOp getter, PropertyOp setter, uintN attrs) { - if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) return true; - return obj_setProperty(cx, obj, id, &value); + Value tmp = *v; + return obj_setProperty(cx, obj, id, &tmp); } static JSBool - obj_deleteProperty(JSContext *cx, JSObject *obj, jsval id, jsval *rval) + obj_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval) { - if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { - *rval = JSVAL_FALSE; + if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) { + rval->setBoolean(false); return true; } @@ -655,17 +656,17 @@ class TypedArrayTemplate JS_ASSERT(tarray); if (tarray->isArrayIndex(cx, id)) { - *rval = JSVAL_FALSE; + rval->setBoolean(false); return true; } - *rval = JSVAL_TRUE; + rval->setBoolean(true); return true; } static JSBool obj_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, - jsval *statep, jsid *idp) + Value *statep, jsid *idp) { ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); JS_ASSERT(tarray); @@ -677,35 +678,35 @@ class TypedArrayTemplate */ switch (enum_op) { case JSENUMERATE_INIT_ALL: - *statep = JSVAL_TRUE; + statep->setBoolean(true); if (idp) *idp = INT_TO_JSID(tarray->length + 1); break; case JSENUMERATE_INIT: - *statep = JSVAL_ZERO; + statep->setInt32(0); if (idp) *idp = INT_TO_JSID(tarray->length); break; case JSENUMERATE_NEXT: - if (*statep == JSVAL_TRUE) { + if (statep->isTrue()) { *idp = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); - *statep = JSVAL_ZERO; + statep->setInt32(0); } else { - uint32 index = JSVAL_TO_INT(*statep); + uint32 index = statep->toInt32(); if (index < uint32(tarray->length)) { - *idp = *statep; - *statep = INT_TO_JSID(JSVAL_TO_INT(*statep) + 1); + *idp = INT_TO_JSID(index); + statep->setInt32(index + 1); } else { JS_ASSERT(index == tarray->length); - *statep = JSVAL_NULL; + statep->setNull(); } } break; case JSENUMERATE_DESTROY: - *statep = JSVAL_NULL; + statep->setNull(); break; } @@ -726,7 +727,7 @@ class TypedArrayTemplate */ static JSBool class_constructor(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval) + uintN argc, Value *argv, Value *rval) { // // Note: this is a constructor for slowClass, not fastClass! @@ -736,20 +737,20 @@ class TypedArrayTemplate obj = NewBuiltinClassInstance(cx, slowClass()); if (!obj) return false; - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); } return create(cx, obj, argc, argv, rval); } static bool - create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) + create(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { if (!obj) { obj = NewBuiltinClassInstance(cx, slowClass()); if (!obj) return false; - *rval = OBJECT_TO_JSVAL(obj); + rval->setObject(*obj); } ThisTypeArray *tarray = 0; @@ -762,8 +763,8 @@ class TypedArrayTemplate } // figure out the type of the first argument - if (JSVAL_IS_INT(argv[0])) { - int32 len = JSVAL_TO_INT(argv[0]); + if (argv[0].isInt32()) { + int32 len = argv[0].toInt32(); if (len < 0) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_ARRAY_LENGTH); @@ -781,7 +782,7 @@ class TypedArrayTemplate delete tarray; return false; } - } else if (!JSVAL_IS_PRIMITIVE(argv[0])) { + } else if (argv[0].isObject()) { int32_t byteOffset = -1; int32_t length = -1; @@ -811,7 +812,7 @@ class TypedArrayTemplate return false; } - if (!tarray->init(cx, JSVAL_TO_OBJECT(argv[0]), byteOffset, length)) { + if (!tarray->init(cx, &argv[0].toObject(), byteOffset, length)) { delete tarray; return false; } @@ -834,15 +835,15 @@ class TypedArrayTemplate /* slice(start[, end]) */ static JSBool - fun_slice(JSContext *cx, uintN argc, jsval *vp) + fun_slice(JSContext *cx, uintN argc, Value *vp) { - jsval *argv; + Value *argv; JSObject *obj; argv = JS_ARGV(cx, vp); - obj = JS_THIS_OBJECT(cx, vp); + obj = ComputeThisFromVp(cx, vp); - if (!JS_InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp+2)) + if (!InstanceOf(cx, obj, ThisTypeArray::fastClass(), vp+2)) return false; ThisTypeArray *tarray = ThisTypeArray::fromJSObject(obj); @@ -890,7 +891,7 @@ class TypedArrayTemplate // note the usage of JS_NewObject here -- we don't want the // constructor to be called! - JSObject *nobj = JS_NewObject(cx, slowClass(), NULL, NULL); + JSObject *nobj = NewObject(cx, slowClass(), NULL, NULL); if (!nobj) { delete ntarray; return false; @@ -898,7 +899,7 @@ class TypedArrayTemplate makeFastWithPrivate(cx, nobj, ntarray); - *vp = OBJECT_TO_JSVAL(nobj); + vp->setObject(*nobj); return true; } @@ -914,14 +915,8 @@ class TypedArrayTemplate makeFastWithPrivate(JSContext *cx, JSObject *obj, ThisTypeArray *tarray) { JS_ASSERT(obj->getClass() == slowClass()); - obj->setPrivate(tarray); - - // now munge the classword and make this into a fast typed - // array class, since it's an instance - obj->classword ^= jsuword(slowClass()); - obj->classword |= jsuword(fastClass()); - + obj->clasp = fastClass(); obj->map = &fastObjectMap; } @@ -1026,7 +1021,7 @@ class TypedArrayTemplate *(static_cast(data) + index) = val; } - inline void copyIndexToValue(JSContext *cx, uint32 index, jsval *vp); + inline void copyIndexToValue(JSContext *cx, uint32 index, Value *vp); ThisTypeArray * slice(uint32 begin, uint32 end) @@ -1051,15 +1046,15 @@ class TypedArrayTemplate protected: static NativeType - nativeFromValue(JSContext *cx, jsval v) + nativeFromValue(JSContext *cx, const Value &v) { - if (JSVAL_IS_INT(v)) - return NativeType(JSVAL_TO_INT(v)); + if (v.isInt32()) + return NativeType(v.toInt32()); - if (JSVAL_IS_DOUBLE(v)) - return NativeType(*JSVAL_TO_DOUBLE(v)); + if (v.isDouble()) + return NativeType(v.toDouble()); - if (JSVAL_IS_PRIMITIVE(v) && v != JSVAL_HOLE) { + if (v.isPrimitive() && !v.isMagic()) { jsdouble dval; ValueToNumber(cx, v, &dval); return NativeType(dval); @@ -1079,15 +1074,13 @@ class TypedArrayTemplate if (ar->isDenseArray() && ar->getDenseArrayCapacity() >= len) { JS_ASSERT(ar->getArrayLength() == len); - jsval *src = ar->getDenseArrayElements(); + Value *src = ar->getDenseArrayElements(); - for (uintN i = 0; i < len; ++i) { - jsval v = *src++; - *dest++ = nativeFromValue(cx, v); - } + for (uintN i = 0; i < len; ++i) + *dest++ = nativeFromValue(cx, *src++); } else { // slow path - jsval v; + Value v; for (uintN i = 0; i < len; ++i) { if (!ar->getProperty(cx, INT_TO_JSID(i), &v)) @@ -1189,18 +1182,12 @@ class TypedArrayTemplate bool createBufferWithByteLength(JSContext *cx, int32 bytes) { - if (!INT_FITS_IN_JSVAL(bytes)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_NEED_DIET, "byte length"); - return false; - } - - jsval argv = INT_TO_JSVAL(bytes); + Value argv = Int32Value(bytes); AutoValueRooter tvr(cx); if (!ArrayBuffer::create(cx, NULL, 1, &argv, tvr.addr())) return false; - JSObject *obj = JSVAL_TO_OBJECT(tvr.value()); + JSObject *obj = &tvr.value().toObject(); bufferJS = obj; buffer = ArrayBuffer::fromJSObject(obj); @@ -1217,56 +1204,44 @@ class TypedArrayTemplate // less than 32-bits in size. template void -TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, jsval *vp) +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) { JS_STATIC_ASSERT(sizeof(NativeType) < 4); - *vp = INT_TO_JSVAL(getIndex(index)); + vp->setInt32(getIndex(index)); } // and we need to specialize for 32-bit integers and floats template<> void -TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, jsval *vp) +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) { int32 val = getIndex(index); - if (INT_FITS_IN_JSVAL(val)) { - *vp = INT_TO_JSVAL(val); - } else { - jsdouble *dp = js_NewWeaklyRootedDouble(cx, jsdouble(val)); - *vp = dp ? DOUBLE_TO_JSVAL(dp) : JSVAL_VOID; - } + vp->setInt32(val); } template<> void -TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, jsval *vp) +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) { uint32 val = getIndex(index); - if (val < uint32(JSVAL_INT_MAX)) { - *vp = INT_TO_JSVAL(int32(val)); - } else { - jsdouble *dp = js_NewWeaklyRootedDouble(cx, jsdouble(val)); - *vp = dp ? DOUBLE_TO_JSVAL(dp) : JSVAL_VOID; - } + vp->setNumber(val); } template<> void -TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, jsval *vp) +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) { float val = getIndex(index); - if (!js_NewWeaklyRootedNumber(cx, jsdouble(val), vp)) - *vp = JSVAL_VOID; + vp->setDouble(val); } template<> void -TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, jsval *vp) +TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, Value *vp) { double val = getIndex(index); - if (!js_NewWeaklyRootedNumber(cx, jsdouble(val), vp)) - *vp = JSVAL_VOID; + vp->setDouble(val); } /*** @@ -1277,18 +1252,18 @@ TypedArrayTemplate::copyIndexToValue(JSContext *cx, uint32 index, jsval * ArrayBuffer (base) */ -JSClass ArrayBuffer::jsclass = { +Class ArrayBuffer::jsclass = { "ArrayBuffer", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, ArrayBuffer::class_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, ArrayBuffer::class_finalize, JSCLASS_NO_OPTIONAL_MEMBERS }; JSPropertySpec ArrayBuffer::jsprops[] = { { "byteLength", -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, - ArrayBuffer::prop_getByteLength, ArrayBuffer::prop_getByteLength }, + Jsvalify(ArrayBuffer::prop_getByteLength), Jsvalify(ArrayBuffer::prop_getByteLength) }, {0,0,0,0,0} }; @@ -1299,20 +1274,19 @@ JSPropertySpec ArrayBuffer::jsprops[] = { JSPropertySpec TypedArray::jsprops[] = { { js_length_str, -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, - TypedArray::prop_getLength, TypedArray::prop_getLength }, + Jsvalify(TypedArray::prop_getLength), Jsvalify(TypedArray::prop_getLength) }, { "byteLength", -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, - TypedArray::prop_getByteLength, TypedArray::prop_getByteLength }, + Jsvalify(TypedArray::prop_getByteLength), Jsvalify(TypedArray::prop_getByteLength) }, { "byteOffset", -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, - TypedArray::prop_getByteOffset, TypedArray::prop_getByteOffset }, + Jsvalify(TypedArray::prop_getByteOffset), Jsvalify(TypedArray::prop_getByteOffset) }, { "buffer", -1, JSPROP_SHARED | JSPROP_PERMANENT | JSPROP_READONLY, - TypedArray::prop_getBuffer, TypedArray::prop_getBuffer }, + Jsvalify(TypedArray::prop_getBuffer), Jsvalify(TypedArray::prop_getBuffer) }, {0,0,0,0,0} }; - /* * TypedArray boilerplate */ @@ -1347,8 +1321,8 @@ template<> JSFunctionSpec _typedArray::jsfuncs[] = { \ { \ #_typedArray, \ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray), \ - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, \ - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, \ + PropertyStub, PropertyStub, PropertyStub, PropertyStub, \ + EnumerateStub, ResolveStub, ConvertStub, FinalizeStub, \ JSCLASS_NO_OPTIONAL_MEMBERS \ } @@ -1356,8 +1330,8 @@ template<> JSFunctionSpec _typedArray::jsfuncs[] = { \ { \ #_typedArray, \ JSCLASS_HAS_PRIVATE, \ - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, \ - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, \ + PropertyStub, PropertyStub, PropertyStub, PropertyStub, \ + EnumerateStub, ResolveStub, ConvertStub, \ _typedArray::class_finalize, \ _typedArray::getObjectOps, NULL, NULL, NULL, \ NULL, NULL, NULL, NULL \ @@ -1386,7 +1360,7 @@ IMPL_TYPED_ARRAY_STATICS(Float32Array); IMPL_TYPED_ARRAY_STATICS(Float64Array); IMPL_TYPED_ARRAY_STATICS(Uint8ClampedArray); -JSClass TypedArray::fastClasses[TYPE_MAX] = { +Class TypedArray::fastClasses[TYPE_MAX] = { IMPL_TYPED_ARRAY_FAST_CLASS(Int8Array), IMPL_TYPED_ARRAY_FAST_CLASS(Uint8Array), IMPL_TYPED_ARRAY_FAST_CLASS(Int16Array), @@ -1398,7 +1372,7 @@ JSClass TypedArray::fastClasses[TYPE_MAX] = { IMPL_TYPED_ARRAY_FAST_CLASS(Uint8ClampedArray) }; -JSClass TypedArray::slowClasses[TYPE_MAX] = { +Class TypedArray::slowClasses[TYPE_MAX] = { IMPL_TYPED_ARRAY_SLOW_CLASS(Int8Array), IMPL_TYPED_ARRAY_SLOW_CLASS(Uint8Array), IMPL_TYPED_ARRAY_SLOW_CLASS(Int16Array), @@ -1453,7 +1427,7 @@ JS_FRIEND_API(JSBool) js_IsTypedArray(JSObject *obj) { JS_ASSERT(obj); - JSClass *clasp = obj->getClass(); + Class *clasp = obj->getClass(); return clasp >= &TypedArray::fastClasses[0] && clasp < &TypedArray::fastClasses[TypedArray::TYPE_MAX]; } @@ -1461,19 +1435,19 @@ js_IsTypedArray(JSObject *obj) JS_FRIEND_API(JSObject *) js_CreateArrayBuffer(JSContext *cx, jsuint nbytes) { - AutoValueRooter tvr(cx); - if (!js_NewNumberInRootedValue(cx, jsdouble(nbytes), tvr.addr())) + Value vals[2]; + vals[0].setNumber(nbytes); + vals[1].setUndefined(); + + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + if (!ArrayBuffer::create(cx, NULL, 1, &vals[0], &vals[1])) return NULL; - AutoValueRooter rval(cx); - if (!ArrayBuffer::create(cx, NULL, 1, tvr.addr(), rval.addr())) - return NULL; - - return JSVAL_TO_OBJECT(rval.value()); + return &vals[1].toObject(); } static inline JSBool -TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, jsval *argv, jsval *rv) +TypedArrayConstruct(JSContext *cx, jsint atype, uintN argc, Value *argv, Value *rv) { switch (atype) { case TypedArray::TYPE_INT8: @@ -1514,16 +1488,15 @@ js_CreateTypedArray(JSContext *cx, jsint atype, jsuint nelements) { JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); - jsval vals[2] = { JSVAL_NULL, JSVAL_NULL }; + Value vals[2]; + vals[0].setInt32(nelements); + vals[1].setUndefined(); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); - - if (!js_NewNumberInRootedValue(cx, jsdouble(nelements), &vals[0])) - return NULL; - if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1])) return NULL; - return JSVAL_TO_OBJECT(vals[1]); + return &vals[1].toObject(); } JS_FRIEND_API(JSObject *) @@ -1531,15 +1504,15 @@ js_CreateTypedArrayWithArray(JSContext *cx, jsint atype, JSObject *arrayArg) { JS_ASSERT(atype >= 0 && atype < TypedArray::TYPE_MAX); - jsval vals[2] = { JSVAL_NULL, JSVAL_NULL }; + Value vals[2]; + vals[0].setObject(*arrayArg); + vals[1].setUndefined(); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); - - vals[0] = OBJECT_TO_JSVAL(arrayArg); - if (!TypedArrayConstruct(cx, atype, 1, &vals[0], &vals[1])) return NULL; - return JSVAL_TO_OBJECT(vals[1]); + return &vals[1].toObject(); } JS_FRIEND_API(JSObject *) @@ -1550,30 +1523,27 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, JS_ASSERT(bufArg && ArrayBuffer::fromJSObject(bufArg)); JS_ASSERT_IF(byteoffset < 0, length < 0); - jsval vals[4] = { JSVAL_NULL, JSVAL_NULL, JSVAL_NULL, JSVAL_NULL }; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); + Value vals[4]; int argc = 1; - vals[0] = OBJECT_TO_JSVAL(bufArg); + vals[0].setObject(*bufArg); + vals[3].setUndefined(); if (byteoffset >= 0) { - if (!js_NewNumberInRootedValue(cx, jsdouble(byteoffset), &vals[argc])) - return NULL; - + vals[argc].setInt32(byteoffset); argc++; } if (length >= 0) { - if (!js_NewNumberInRootedValue(cx, jsdouble(length), &vals[argc])) - return NULL; - + vals[argc].setInt32(length); argc++; } + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(vals), vals); if (!TypedArrayConstruct(cx, atype, argc, &vals[0], &vals[3])) return NULL; - return JSVAL_TO_OBJECT(vals[3]); + return &vals[3].toObject(); } JS_FRIEND_API(JSBool) diff --git a/js/src/jstypedarray.h b/js/src/jstypedarray.h index 2c4bafb392c3..404fa652cba0 100644 --- a/js/src/jstypedarray.h +++ b/js/src/jstypedarray.h @@ -41,6 +41,7 @@ #define jstypedarray_h #include "jsapi.h" +#include "jsvalue.h" typedef struct JSProperty JSProperty; @@ -55,17 +56,17 @@ namespace js { * TypedArray with a size. */ struct JS_FRIEND_API(ArrayBuffer) { - static JSClass jsclass; + static Class jsclass; static JSPropertySpec jsprops[]; - static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp); static void class_finalize(JSContext *cx, JSObject *obj); - static JSBool class_constructor(JSContext *cx, JSObject *obj, - uintN argc, jsval *argv, jsval *rval); + static JSBool class_constructor(JSContext *cx, JSObject *obj, uintN argc, Value *argv, + Value *rval); static bool create(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval); + Value *argv, Value *rval); static ArrayBuffer *fromJSObject(JSObject *obj); @@ -116,20 +117,20 @@ struct JS_FRIEND_API(TypedArray) { }; // and MUST NOT be used to construct new objects. - static JSClass fastClasses[TYPE_MAX]; + static Class fastClasses[TYPE_MAX]; // These are the slow/original classes, used // fo constructing new objects - static JSClass slowClasses[TYPE_MAX]; + static Class slowClasses[TYPE_MAX]; static JSPropertySpec jsprops[]; static TypedArray *fromJSObject(JSObject *obj); - static JSBool prop_getBuffer(JSContext *cx, JSObject *obj, jsval id, jsval *vp); - static JSBool prop_getByteOffset(JSContext *cx, JSObject *obj, jsval id, jsval *vp); - static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsval id, jsval *vp); - static JSBool prop_getLength(JSContext *cx, JSObject *obj, jsval id, jsval *vp); + static JSBool prop_getBuffer(JSContext *cx, JSObject *obj, jsid id, Value *vp); + static JSBool prop_getByteOffset(JSContext *cx, JSObject *obj, jsid id, Value *vp); + static JSBool prop_getByteLength(JSContext *cx, JSObject *obj, jsid id, Value *vp); + static JSBool prop_getLength(JSContext *cx, JSObject *obj, jsid id, Value *vp); static JSBool obj_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, JSProperty **propp); @@ -164,8 +165,6 @@ struct JS_FRIEND_API(TypedArray) { /* Friend API methods */ -JS_BEGIN_EXTERN_C - JS_FRIEND_API(JSObject *) js_InitTypedArrayClasses(JSContext *cx, JSObject *obj); @@ -213,6 +212,4 @@ js_CreateTypedArrayWithBuffer(JSContext *cx, jsint atype, JSObject *bufArg, JS_FRIEND_API(JSBool) js_ReparentTypedArrayToScope(JSContext *cx, JSObject *obj, JSObject *scope); -JS_END_EXTERN_C - #endif /* jstypedarray_h */ diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 11a7a6274094..14c3b03051fb 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -77,6 +77,9 @@ ** ** ***********************************************************************/ + +#define DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(Name) class Name + #ifdef WIN32 /* These also work for __MWERKS__ */ @@ -103,6 +106,17 @@ # ifdef HAVE_VISIBILITY_ATTRIBUTE # define JS_EXTERNAL_VIS __attribute__((visibility ("default"))) +# if defined(__GNUC__) && __GNUC__ <= 4 && __GNUC_MINOR__ < 5 + /* + * GCC wrongly produces a warning when a type with hidden visibility + * (e.g. js::Value) is a member of a local class of a static function. + * This is apparently fixed with GCC 4.5 and above. See: + * + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40145. + */ +# undef DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION +# define DEFINE_LOCAL_CLASS_OF_STATIC_FUNCTION(Name) class __attribute__((visibility ("hidden"))) Name +# endif # elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) # define JS_EXTERNAL_VIS __global # else @@ -299,6 +313,27 @@ # include "jsautocfg.h" /* Use auto-detected configuration */ #endif +/* + * Define JS_64BIT iff we are building in an environment with 64-bit + * addresses. + */ +#ifdef _MSC_VER +# if defined(_M_X64) || defined(_M_AMD64) +# define JS_64BIT +# endif +#elif defined(__GNUC__) +# ifdef __x86_64__ +# define JS_64BIT +# endif +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# ifdef __x86_64 +# define JS_64BIT +# endif +#else +# error "Implement me" +#endif + + #include "jsinttypes.h" JS_BEGIN_EXTERN_C @@ -357,6 +392,11 @@ typedef JSUintPtr JSUptrdiff; typedef JSIntn JSBool; #define JS_TRUE (JSIntn)1 #define JS_FALSE (JSIntn)0 +/* +** Special: JS_NEITHER is used by the tracer to have tri-state booleans. +** This should not be used in new code. +*/ +#define JS_NEITHER (JSIntn)2 /************************************************************************ ** TYPES: JSPackedBool diff --git a/js/src/jsval.h b/js/src/jsval.h new file mode 100644 index 000000000000..7253b179e91b --- /dev/null +++ b/js/src/jsval.h @@ -0,0 +1,732 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 30, 2010 + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * Luke Wagner + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsvalimpl_h__ +#define jsvalimpl_h__ +/* + * JS value implementation details for operations on jsval and jsid. + * Embeddings should not rely on any of the definitions in this file. For a + * description of the value representation and the engine-internal C++ value + * interface, js::Value, see jsvalue.h. + */ +#include "jsutil.h" + +JS_BEGIN_EXTERN_C + +/* + * Try to get jsvals 64-bit aligned. We could almost assert that all values are + * aligned, but MSVC and GCC occasionally break alignment. + */ +#ifdef __GNUC__ +# define JSVAL_ALIGNMENT __attribute__((aligned (8))) +#elif defined(_MSC_VER) + /* + * Structs can be aligned with MSVC, but not if they are used as parameters, + * so we just don't try to align. + */ +# define JSVAL_ALIGNMENT +#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) +# define JSVAL_ALIGNMENT +#endif + +/* + * We try to use enums so that printing a jsval_layout in the debugger shows + * nice symbolic type tags, however we can only do this when we can force the + * underlying type of the enum to be the desired size. + */ +#ifdef __cplusplus + +#if defined(_MSC_VER) +# define JS_ENUM_HEADER(id, type) enum id : type +# define JS_ENUM_MEMBER(id, type, value) id = (type)value, +# define JS_LAST_ENUM_MEMBER(id, type, value) id = (type)value +# define JS_ENUM_FOOTER(id) +#else +# define JS_ENUM_HEADER(id, type) enum id +# define JS_ENUM_MEMBER(id, type, value) id = (type)value, +# define JS_LAST_ENUM_MEMBER(id, type, value) id = (type)value +# define JS_ENUM_FOOTER(id) __attribute__((packed)) +#endif + +/* Remember to propagate changes to the C defines below. */ +JS_ENUM_HEADER(JSValueType, uint8) +{ + JSVAL_TYPE_DOUBLE = 0x00, + JSVAL_TYPE_INT32 = 0x01, + JSVAL_TYPE_UNDEFINED = 0x02, + JSVAL_TYPE_BOOLEAN = 0x03, + JSVAL_TYPE_MAGIC = 0x04, + JSVAL_TYPE_STRING = 0x05, + JSVAL_TYPE_NULL = 0x06, + JSVAL_TYPE_OBJECT = 0x07, + + /* The below types never appear in a jsval; they are only used in tracing. */ + + JSVAL_TYPE_NONFUNOBJ = 0x57, + JSVAL_TYPE_FUNOBJ = 0x67, + + JSVAL_TYPE_STRORNULL = 0x97, + JSVAL_TYPE_OBJORNULL = 0x98, + + JSVAL_TYPE_BOXED = 0x99, + JSVAL_TYPE_UNINITIALIZED = 0xcd +} JS_ENUM_FOOTER(JSValueType); + +#if JS_BITS_PER_WORD == 32 + +/* Remember to propagate changes to the C defines below. */ +JS_ENUM_HEADER(JSValueTag, uint32) +{ + JSVAL_TAG_CLEAR = 0xFFFF0000, + JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, + JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, + JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, + JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, + JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, + JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT +} JS_ENUM_FOOTER(JSValueType); + +#elif JS_BITS_PER_WORD == 64 + +/* Remember to propagate changes to the C defines below. */ +JS_ENUM_HEADER(JSValueTag, uint32) +{ + JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, + JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, + JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, + JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, + JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, + JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, + JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT +} JS_ENUM_FOOTER(JSValueType); + +#endif + +#else /* defined(__cplusplus) */ + +typedef uint8 JSValueType; +#define JSVAL_TYPE_DOUBLE ((uint8)0x00) +#define JSVAL_TYPE_INT32 ((uint8)0x01) +#define JSVAL_TYPE_UNDEFINED ((uint8)0x02) +#define JSVAL_TYPE_BOOLEAN ((uint8)0x03) +#define JSVAL_TYPE_MAGIC ((uint8)0x04) +#define JSVAL_TYPE_STRING ((uint8)0x05) +#define JSVAL_TYPE_NULL ((uint8)0x06) +#define JSVAL_TYPE_OBJECT ((uint8)0x07) +#define JSVAL_TYPE_NONFUNOBJ ((uint8)0x57) +#define JSVAL_TYPE_FUNOBJ ((uint8)0x67) +#define JSVAL_TYPE_STRORNULL ((uint8)0x97) +#define JSVAL_TYPE_OBJORNULL ((uint8)0x98) +#define JSVAL_TYPE_STRORNULL ((uint8)0x97) +#define JSVAL_TYPE_OBJORNULL ((uint8)0x98) +#define JSVAL_TYPE_BOXED ((uint8)0x99) +#define JSVAL_TYPE_UNINITIALIZED ((uint8)0xcd) + +#if JS_BITS_PER_WORD == 32 + +typedef uint32 JSValueTag; +#define JSVAL_TAG_CLEAR ((uint32)(0xFFFF0000)) +#define JSVAL_TAG_INT32 ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32)) +#define JSVAL_TAG_UNDEFINED ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED)) +#define JSVAL_TAG_STRING ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING)) +#define JSVAL_TAG_BOOLEAN ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN)) +#define JSVAL_TAG_MAGIC ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC)) +#define JSVAL_TAG_NULL ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL)) +#define JSVAL_TAG_OBJECT ((uint32)(JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT)) + +#elif JS_BITS_PER_WORD == 64 + +typedef uint32 JSValueTag; +#define JSVAL_TAG_MAX_DOUBLE ((uint32)(0x1FFF0)) +#define JSVAL_TAG_INT32 (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32) +#define JSVAL_TAG_UNDEFINED (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED) +#define JSVAL_TAG_STRING (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING) +#define JSVAL_TAG_BOOLEAN (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN) +#define JSVAL_TAG_MAGIC (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC) +#define JSVAL_TAG_NULL (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL) +#define JSVAL_TAG_OBJECT (uint32)(JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT) + +#endif /* JS_BITS_PER_WORD */ +#endif /* defined(__cplusplus) */ + +#define JSVAL_LOWER_INCL_TYPE_OF_OBJ_OR_NULL_SET JSVAL_TYPE_NULL +#define JSVAL_UPPER_EXCL_TYPE_OF_PRIMITIVE_SET JSVAL_TYPE_OBJECT +#define JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET JSVAL_TYPE_INT32 +#define JSVAL_LOWER_INCL_TYPE_OF_GCTHING_SET JSVAL_TYPE_STRING +#define JSVAL_UPPER_INCL_TYPE_OF_VALUE_SET JSVAL_TYPE_OBJECT +#define JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET JSVAL_TYPE_FUNOBJ + +#if JS_BITS_PER_WORD == 32 + +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) + +#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL +#define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT +#define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 +#define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING + +#elif JS_BITS_PER_WORD == 64 + +#define JSVAL_TAG_SHIFT 47 +#define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL +#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) +#define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) + +#define JSVAL_SHIFTED_TAG_MAX_DOUBLE (((uint64)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_INT32 (((uint64)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_UNDEFINED (((uint64)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_STRING (((uint64)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_BOOLEAN (((uint64)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_MAGIC (((uint64)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_NULL (((uint64)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT) +#define JSVAL_SHIFTED_TAG_OBJECT (((uint64)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) + +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT +#define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED +#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING + +#endif /* JS_BITS_PER_WORD */ + +typedef enum JSWhyMagic +{ + JS_ARRAY_HOLE, /* a hole in a dense array */ + JS_ARGS_HOLE, /* a hole in the args object's array */ + JS_NATIVE_ENUMERATE, /* indicates that a custom enumerate hook forwarded + * to js_Enumerate, which really means the object can be + * enumerated like a native object. */ + JS_NO_ITER_VALUE, /* there is not a pending iterator value */ + JS_GENERATOR_CLOSING, /* exception value thrown when closing a generator */ + JS_NO_CONSTANT, /* compiler sentinel value */ + JS_THIS_POISON, /* used in debug builds to catch tracing errors */ + JS_GENERIC_MAGIC /* for local use */ +} JSWhyMagic; + +typedef struct JSString JSString; +typedef struct JSObject JSObject; + +#if defined(IS_LITTLE_ENDIAN) +# if JS_BITS_PER_WORD == 32 +typedef union jsval_layout +{ + uint64 asBits; + struct { + union { + int32 i32; + uint32 u32; + JSBool boo; + JSString *str; + JSObject *obj; + void *ptr; + JSWhyMagic why; + } payload; + JSValueTag tag; + } s; + double asDouble; +} jsval_layout; +# elif JS_BITS_PER_WORD == 64 +typedef union jsval_layout +{ + uint64 asBits; + struct { + uint64 payload47 : 47; + JSValueTag tag : 17; + } debugView; + struct { + union { + int32 i32; + uint32 u32; + JSWhyMagic why; + } payload; + } s; + double asDouble; +} jsval_layout; +# endif /* JS_BITS_PER_WORD */ +#else /* defined(IS_LITTLE_ENDIAN) */ +# if JS_BITS_PER_WORD == 32 +typedef union jsval_layout +{ + uint64 asBits; + struct { + JSValueTag tag; + union { + int32 i32; + uint32 u32; + JSBool boo; + JSString *str; + JSObject *obj; + void *ptr; + JSWhyMagic why; + } payload; + } s; + double asDouble; +} jsval_layout; +# endif /* JS_BITS_PER_WORD */ +#endif /* defined(IS_LITTLE_ENDIAN) */ + +#if JS_BITS_PER_WORD == 32 + +#define BUILD_JSVAL(tag, payload) \ + ((((uint64)(uint32)(tag)) << 32) | (uint32)(payload)) + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_DOUBLE_IMPL(jsval_layout l) +{ + return l.s.tag < JSVAL_TAG_CLEAR; +} + +static JS_ALWAYS_INLINE jsval_layout +DOUBLE_TO_JSVAL_IMPL(double d) +{ + jsval_layout l; + l.asDouble = d; + JS_ASSERT(l.s.tag < JSVAL_TAG_CLEAR); + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_INT32_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_INT32; +} + +static JS_ALWAYS_INLINE int32 +JSVAL_TO_INT32_IMPL(jsval_layout l) +{ + return l.s.payload.i32; +} + +static JS_ALWAYS_INLINE jsval_layout +INT32_TO_JSVAL_IMPL(int32 i) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_INT32; + l.s.payload.i32 = i; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NUMBER_IMPL(jsval_layout l) +{ + JSValueTag tag = l.s.tag; + JS_ASSERT(tag != JSVAL_TAG_CLEAR); + return tag <= JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_UNDEFINED; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_STRING_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_STRING; +} + +static JS_ALWAYS_INLINE jsval_layout +STRING_TO_JSVAL_IMPL(JSString *str) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_STRING; + l.s.payload.str = str; + return l; +} + +static JS_ALWAYS_INLINE JSString * +JSVAL_TO_STRING_IMPL(jsval_layout l) +{ + return l.s.payload.str; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_BOOLEAN; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) +{ + return l.s.payload.boo; +} + +static JS_ALWAYS_INLINE jsval_layout +BOOLEAN_TO_JSVAL_IMPL(JSBool b) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_BOOLEAN; + l.s.payload.boo = b; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_OBJECT; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) +{ + return l.s.tag < JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) +{ + JS_ASSERT(l.s.tag <= JSVAL_TAG_OBJECT); + return l.s.tag >= JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET; +} + +static JS_ALWAYS_INLINE JSObject * +JSVAL_TO_OBJECT_IMPL(jsval_layout l) +{ + return l.s.payload.obj; +} + +static JS_ALWAYS_INLINE jsval_layout +OBJECT_TO_JSVAL_IMPL(JSObject *obj) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_OBJECT; + l.s.payload.obj = obj; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NULL_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_NULL; +} + +static JS_ALWAYS_INLINE jsval_layout +PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) +{ + jsval_layout l; + JS_ASSERT(((uint32)ptr & 1) == 0); + l.s.tag = (JSValueTag)0; + l.s.payload.ptr = ptr; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) +{ + return l.s.payload.ptr; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_GCTHING_IMPL(jsval_layout l) +{ + return l.s.tag >= JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET; +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_GCTHING_IMPL(jsval_layout l) +{ + return l.s.payload.ptr; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_STRING || l.s.tag == JSVAL_TAG_OBJECT; +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TRACE_KIND_IMPL(jsval_layout l) +{ + return (uint32)(JSBool)JSVAL_IS_STRING_IMPL(l); +} + +#elif JS_BITS_PER_WORD == 64 + +#define BUILD_JSVAL(tag, payload) \ + ((((uint64)(uint32)(tag)) << JSVAL_TAG_SHIFT) | (payload)) + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_DOUBLE_IMPL(jsval_layout l) +{ + return l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE; +} + +static JS_ALWAYS_INLINE jsval_layout +DOUBLE_TO_JSVAL_IMPL(double d) +{ + jsval_layout l; + l.asDouble = d; + JS_ASSERT(l.asBits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE); + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_INT32_IMPL(jsval_layout l) +{ + return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_INT32; +} + +static JS_ALWAYS_INLINE int32 +JSVAL_TO_INT32_IMPL(jsval_layout l) +{ + return (int32)l.asBits; +} + +static JS_ALWAYS_INLINE jsval_layout +INT32_TO_JSVAL_IMPL(int32 i32) +{ + jsval_layout l; + l.asBits = ((uint64)(uint32)i32) | JSVAL_SHIFTED_TAG_INT32; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NUMBER_IMPL(jsval_layout l) +{ + return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_UNDEFINED_IMPL(jsval_layout l) +{ + return l.asBits == JSVAL_SHIFTED_TAG_UNDEFINED; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_STRING_IMPL(jsval_layout l) +{ + return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING; +} + +static JS_ALWAYS_INLINE jsval_layout +STRING_TO_JSVAL_IMPL(JSString *str) +{ + jsval_layout l; + uint64 strBits = (uint64)str; + JS_ASSERT((strBits >> JSVAL_TAG_SHIFT) == 0); + l.asBits = strBits | JSVAL_SHIFTED_TAG_STRING; + return l; +} + +static JS_ALWAYS_INLINE JSString * +JSVAL_TO_STRING_IMPL(jsval_layout l) +{ + return (JSString *)(l.asBits & JSVAL_PAYLOAD_MASK); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_BOOLEAN_IMPL(jsval_layout l) +{ + return (uint32)(l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_BOOLEAN; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_TO_BOOLEAN_IMPL(jsval_layout l) +{ + return (JSBool)l.asBits; +} + +static JS_ALWAYS_INLINE jsval_layout +BOOLEAN_TO_JSVAL_IMPL(JSBool b) +{ + jsval_layout l; + l.asBits = ((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_PRIMITIVE_IMPL(jsval_layout l) +{ + return l.asBits < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT_IMPL(jsval_layout l) +{ + JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_SHIFTED_TAG_OBJECT); + return l.asBits >= JSVAL_SHIFTED_TAG_OBJECT; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_OBJECT_OR_NULL_IMPL(jsval_layout l) +{ + JS_ASSERT((l.asBits >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT); + return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; +} + +static JS_ALWAYS_INLINE JSObject * +JSVAL_TO_OBJECT_IMPL(jsval_layout l) +{ + uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; + JS_ASSERT((ptrBits & 0x7) == 0); + return (JSObject *)ptrBits; +} + +static JS_ALWAYS_INLINE jsval_layout +OBJECT_TO_JSVAL_IMPL(JSObject *obj) +{ + jsval_layout l; + uint64 objBits = (uint64)obj; + JS_ASSERT((objBits >> JSVAL_TAG_SHIFT) == 0); + l.asBits = objBits | JSVAL_SHIFTED_TAG_OBJECT; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_NULL_IMPL(jsval_layout l) +{ + return l.asBits == JSVAL_SHIFTED_TAG_NULL; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_GCTHING_IMPL(jsval_layout l) +{ + return l.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET; +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_GCTHING_IMPL(jsval_layout l) +{ + uint64 ptrBits = l.asBits & JSVAL_PAYLOAD_MASK; + JS_ASSERT((ptrBits & 0x7) == 0); + return (void *)ptrBits; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_TRACEABLE_IMPL(jsval_layout l) +{ + return JSVAL_IS_GCTHING_IMPL(l) && !JSVAL_IS_NULL_IMPL(l); +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TRACE_KIND_IMPL(jsval_layout l) +{ + return (uint32)(JSBool)!(JSVAL_IS_OBJECT_IMPL(l)); +} + +static JS_ALWAYS_INLINE jsval_layout +PRIVATE_PTR_TO_JSVAL_IMPL(void *ptr) +{ + jsval_layout l; + uint64 ptrBits = (uint64)ptr; + JS_ASSERT((ptrBits & 1) == 0); + l.asBits = ptrBits >> 1; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE void * +JSVAL_TO_PRIVATE_PTR_IMPL(jsval_layout l) +{ + JS_ASSERT((l.asBits & 0x8000000000000000LL) == 0); + return (void *)(l.asBits << 1); +} + +#endif + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(jsval_layout l) +{ + return JSVAL_IS_DOUBLE_IMPL(l); +} + +/* See JS_USE_JSVAL_JSID_STRUCT_TYPES comment in jsapi.h. */ +#if defined(DEBUG) && !defined(JS_NO_JSVAL_JSID_STRUCT_TYPES) +# define JS_USE_JSVAL_JSID_STRUCT_TYPES +#endif + +#ifdef JS_USE_JSVAL_JSID_STRUCT_TYPES + +typedef JSVAL_ALIGNMENT jsval_layout jsval; +typedef struct jsid { size_t asBits; } jsid; + +#if defined(__cplusplus) +extern "C++" +{ + static JS_ALWAYS_INLINE bool + operator==(jsid lhs, jsid rhs) + { + return lhs.asBits == rhs.asBits; + } + + static JS_ALWAYS_INLINE bool + operator!=(jsid lhs, jsid rhs) + { + return lhs.asBits != rhs.asBits; + } + + static JS_ALWAYS_INLINE bool + operator==(jsval lhs, jsval rhs) + { + return lhs.asBits == rhs.asBits; + } + + static JS_ALWAYS_INLINE bool + operator!=(jsval lhs, jsval rhs) + { + return lhs.asBits != rhs.asBits; + } +} +# endif /* defined(__cplusplus) */ + +/* Internal helper macros */ +#define JSVAL_BITS(v) (v.asBits) +#define IMPL_TO_JSVAL(v) (v) +#define JSID_BITS(id) (id.asBits) + +#else /* defined(JS_USE_JSVAL_JSID_STRUCT_TYPES) */ + +/* Use different primitive types so overloading works. */ +typedef JSVAL_ALIGNMENT uint64 jsval; +typedef ptrdiff_t jsid; + +/* Internal helper macros */ +#define JSVAL_BITS(v) (v) +#define IMPL_TO_JSVAL(v) ((v).asBits) +#define JSID_BITS(id) (id) + +#endif /* defined(JS_USE_JSVAL_JSID_STRUCT_TYPES) */ + +JS_END_EXTERN_C + +#endif /* jsvalimpl_h__ */ diff --git a/js/src/jsvalue.h b/js/src/jsvalue.h new file mode 100644 index 000000000000..3081664e1287 --- /dev/null +++ b/js/src/jsvalue.h @@ -0,0 +1,948 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released + * June 30, 2010 + * + * The Initial Developer of the Original Code is + * the Mozilla Corporation. + * + * Contributor(s): + * Luke Wagner + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsvalue_h__ +#define jsvalue_h__ +/* + * Private value interface. + */ +#include "jsprvtd.h" +#include "jsstdint.h" + +/* + * js::Value is a C++-ified version of jsval that provides more information and + * helper functions than the basic jsval interface exposed by jsapi.h. A few + * general notes on js::Value: + * + * - Since js::Value and jsval have the same representation, values of these + * types, function pointer types differing only in these types, and structs + * differing only in these types can be converted back and forth at no cost + * using the Jsvalify() and Valueify(). See Jsvalify comment below. + * + * - js::Value has setX() and isX() members for X in + * + * { Int32, Double, String, Boolean, Undefined, Null, Object, Magic } + * + * js::Value also contains toX() for each of the non-singleton types. + * + * - Magic is a singleton type whose payload contains a JSWhyMagic "reason" for + * the magic value. By providing JSWhyMagic values when creating and checking + * for magic values, it is possible to assert, at runtime, that only magic + * values with the expected reason flow through a particular value. For + * example, if cx->exception has a magic value, the reason must be + * JS_GENERATOR_CLOSING. + * + * - A key difference between jsval and js::Value is that js::Value gives null + * a separate type. Thus + * + * JSVAL_IS_OBJECT(v) === v.isObjectOrNull() + * !JSVAL_IS_PRIMITIVE(v) === v.isObject() + * + * To help prevent mistakenly boxing a nullable JSObject* as an object, + * Value::setObject takes a JSObject&. (Conversely, Value::asObject returns a + * JSObject&. A convenience member Value::setObjectOrNull is provided. + * + * - JSVAL_VOID is the same as the singleton value of the Undefined type. + * + * - Note that js::Value is always 64-bit. Thus, on 32-bit user code should + * avoid copying jsval/js::Value as much as possible, preferring to pass by + * const Value &. + */ + +/******************************************************************************/ + +/* To avoid a circular dependency, pull in the necessary pieces of jsnum.h. */ + +#include +#if defined(XP_WIN) || defined(XP_OS2) +#include +#endif +#ifdef SOLARIS +#include +#endif + +static inline int +JSDOUBLE_IS_NEGZERO(jsdouble d) +{ +#ifdef WIN32 + return (d == 0 && (_fpclass(d) & _FPCLASS_NZ)); +#elif defined(SOLARIS) + return (d == 0 && copysign(1, d) < 0); +#else + return (d == 0 && signbit(d)); +#endif +} + +static inline bool +JSDOUBLE_IS_INT32(jsdouble d, int32_t* pi) +{ + if (JSDOUBLE_IS_NEGZERO(d)) + return false; + return d == (*pi = int32_t(d)); +} + +/******************************************************************************/ + +/* Additional value operations used in js::Value but not in jsapi.h. */ + +#if JS_BITS_PER_WORD == 32 + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32) +{ + return l.s.tag == JSVAL_TAG_INT32 && l.s.payload.i32 == i32; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b) +{ + return (l.s.tag == JSVAL_TAG_BOOLEAN) && (l.s.payload.boo == b); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_MAGIC_IMPL(jsval_layout l) +{ + return l.s.tag == JSVAL_TAG_MAGIC; +} + +static JS_ALWAYS_INLINE jsval_layout +MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) +{ + jsval_layout l; + l.s.tag = JSVAL_TAG_MAGIC; + l.s.payload.why = why; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) +{ + JSValueTag ltag = lhs.s.tag, rtag = rhs.s.tag; + return ltag == rtag || (ltag < JSVAL_TAG_CLEAR && rtag < JSVAL_TAG_CLEAR); +} + +static JS_ALWAYS_INLINE jsval_layout +PRIVATE_UINT32_TO_JSVAL_IMPL(uint32 ui) +{ + jsval_layout l; + l.s.tag = (JSValueTag)0; + l.s.payload.u32 = ui; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l) +{ + return l.s.payload.u32; +} + +static JS_ALWAYS_INLINE JSValueType +JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) +{ + uint32 type = l.s.tag & 0xF; + JS_ASSERT(type > JSVAL_TYPE_DOUBLE); + return (JSValueType)type; +} + +static JS_ALWAYS_INLINE JSValueTag +JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(jsval_layout l) +{ + JSValueTag tag = l.s.tag; + JS_ASSERT(tag >= JSVAL_TAG_INT32); + return tag; +} + +#ifdef __cplusplus +JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ & 0xF) == JSVAL_TYPE_OBJECT); +JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0xF) == JSVAL_TYPE_OBJECT); +#endif + +static JS_ALWAYS_INLINE jsval_layout +BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot) +{ + jsval_layout l; + JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); + l.s.tag = JSVAL_TYPE_TO_TAG(type & 0xF); + l.s.payload.u32 = *(uint32 *)slot; + return l; +} + +static JS_ALWAYS_INLINE void +UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, uint64 *out) +{ + JS_ASSERT(!JSVAL_IS_DOUBLE_IMPL(l)); + *(uint32 *)out = l.s.payload.u32; +} + +#elif JS_BITS_PER_WORD == 64 + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_SPECIFIC_INT32_IMPL(jsval_layout l, int32 i32) +{ + return l.asBits == (((uint64)(uint32)i32) | JSVAL_SHIFTED_TAG_INT32); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_SPECIFIC_BOOLEAN(jsval_layout l, JSBool b) +{ + return l.asBits == (((uint64)(uint32)b) | JSVAL_SHIFTED_TAG_BOOLEAN); +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_IS_MAGIC_IMPL(jsval_layout l) +{ + return (l.asBits >> JSVAL_TAG_SHIFT) == JSVAL_TAG_MAGIC; +} + +static JS_ALWAYS_INLINE jsval_layout +MAGIC_TO_JSVAL_IMPL(JSWhyMagic why) +{ + jsval_layout l; + l.asBits = ((uint64)(uint32)why) | JSVAL_SHIFTED_TAG_MAGIC; + return l; +} + +static JS_ALWAYS_INLINE JSBool +JSVAL_SAME_TYPE_IMPL(jsval_layout lhs, jsval_layout rhs) +{ + uint64 lbits = lhs.asBits, rbits = rhs.asBits; + return (lbits <= JSVAL_TAG_MAX_DOUBLE && rbits <= JSVAL_TAG_MAX_DOUBLE) || + (((lbits ^ rbits) & 0xFFFF800000000000LL) == 0); +} + +static JS_ALWAYS_INLINE jsval_layout +PRIVATE_UINT32_TO_JSVAL_IMPL(uint32 ui) +{ + jsval_layout l; + l.asBits = (uint64)ui; + JS_ASSERT(JSVAL_IS_DOUBLE_IMPL(l)); + return l; +} + +static JS_ALWAYS_INLINE uint32 +JSVAL_TO_PRIVATE_UINT32_IMPL(jsval_layout l) +{ + JS_ASSERT((l.asBits >> 32) == 0); + return (uint32)l.asBits; +} + +static JS_ALWAYS_INLINE JSValueType +JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(jsval_layout l) +{ + uint64 type = (l.asBits >> JSVAL_TAG_SHIFT) & 0xF; + JS_ASSERT(type > JSVAL_TYPE_DOUBLE); + return (JSValueType)type; +} + +static JS_ALWAYS_INLINE JSValueTag +JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(jsval_layout l) +{ + uint64 tag = l.asBits >> JSVAL_TAG_SHIFT; + JS_ASSERT(tag > JSVAL_TAG_MAX_DOUBLE); + return (JSValueTag)tag; +} + +#ifdef __cplusplus +JS_STATIC_ASSERT(offsetof(jsval_layout, s.payload) == 0); +JS_STATIC_ASSERT((JSVAL_TYPE_NONFUNOBJ & 0xF) == JSVAL_TYPE_OBJECT); +JS_STATIC_ASSERT((JSVAL_TYPE_FUNOBJ & 0xF) == JSVAL_TYPE_OBJECT); +#endif + +static JS_ALWAYS_INLINE jsval_layout +BOX_NON_DOUBLE_JSVAL(JSValueType type, uint64 *slot) +{ + /* N.B. for 32-bit payloads, the high 32 bits of the slot are trash. */ + jsval_layout l; + JS_ASSERT(type > JSVAL_TYPE_DOUBLE && type <= JSVAL_UPPER_INCL_TYPE_OF_BOXABLE_SET); + uint32 isI32 = (uint32)(type < JSVAL_LOWER_INCL_TYPE_OF_GCTHING_SET); + uint32 shift = isI32 * 32; + uint64 mask = ((uint64)-1) >> shift; + uint64 payload = *slot & mask; + l.asBits = payload | JSVAL_TYPE_TO_SHIFTED_TAG(type & 0xF); + return l; +} + +static JS_ALWAYS_INLINE void +UNBOX_NON_DOUBLE_JSVAL(jsval_layout l, uint64 *out) +{ + JS_ASSERT(!JSVAL_IS_DOUBLE_IMPL(l)); + *out = (l.asBits & JSVAL_PAYLOAD_MASK); +} + +#endif + +/******************************************************************************/ + +namespace js { + +class Value +{ + public: + /*** Constructors ***/ + + /* N.B. the default constructor creates a double. */ + Value() { data.asBits = 0; } + + /*** Mutatators ***/ + + void setNull() { + data.asBits = JSVAL_BITS(JSVAL_NULL); + } + + void setUndefined() { + data.asBits = JSVAL_BITS(JSVAL_VOID); + } + + void setInt32(int32 i) { + data = INT32_TO_JSVAL_IMPL(i); + } + + int32 &getInt32Ref() { + JS_ASSERT(isInt32()); + return data.s.payload.i32; + } + + void setDouble(double d) { + data = DOUBLE_TO_JSVAL_IMPL(d); + } + + double &getDoubleRef() { + JS_ASSERT(isDouble()); + return data.asDouble; + } + + void setString(JSString *str) { + data = STRING_TO_JSVAL_IMPL(str); + } + + void setObject(JSObject &obj) { + JS_ASSERT(&obj != NULL); + data = OBJECT_TO_JSVAL_IMPL(&obj); + } + + void setBoolean(bool b) { + data = BOOLEAN_TO_JSVAL_IMPL(b); + } + + void setMagic(JSWhyMagic why) { + data = MAGIC_TO_JSVAL_IMPL(why); + } + + JS_ALWAYS_INLINE + void setNumber(uint32 ui) { + if (ui > JSVAL_INT_MAX) + setDouble((double)ui); + else + setInt32((int32)ui); + } + + JS_ALWAYS_INLINE + void setNumber(double d) { + int32_t i; + if (JSDOUBLE_IS_INT32(d, &i)) + setInt32(i); + else + setDouble(d); + } + + JS_ALWAYS_INLINE + void setObjectOrNull(JSObject *arg) { + if (arg) + setObject(*arg); + else + setNull(); + } + + JS_ALWAYS_INLINE + void setObjectOrUndefined(JSObject *arg) { + if (arg) + setObject(*arg); + else + setUndefined(); + } + + void swap(Value &rhs) { + uint64 tmp = rhs.data.asBits; + rhs.data.asBits = data.asBits; + data.asBits = tmp; + } + + /*** Value type queries ***/ + + bool isUndefined() const { + return JSVAL_IS_UNDEFINED_IMPL(data); + } + + bool isNull() const { + return JSVAL_IS_NULL_IMPL(data); + } + + bool isNullOrUndefined() const { + return isNull() || isUndefined(); + } + + bool isInt32() const { + return JSVAL_IS_INT32_IMPL(data); + } + + bool isInt32(int32 i32) const { + return JSVAL_IS_SPECIFIC_INT32_IMPL(data, i32); + } + + bool isDouble() const { + return JSVAL_IS_DOUBLE_IMPL(data); + } + + bool isNumber() const { + return JSVAL_IS_NUMBER_IMPL(data); + } + + bool isString() const { + return JSVAL_IS_STRING_IMPL(data); + } + + bool isObject() const { + return JSVAL_IS_OBJECT_IMPL(data); + } + + bool isPrimitive() const { + return JSVAL_IS_PRIMITIVE_IMPL(data); + } + + bool isObjectOrNull() const { + return JSVAL_IS_OBJECT_OR_NULL_IMPL(data); + } + + bool isGCThing() const { + return JSVAL_IS_GCTHING_IMPL(data); + } + + bool isBoolean() const { + return JSVAL_IS_BOOLEAN_IMPL(data); + } + + bool isTrue() const { + return JSVAL_IS_SPECIFIC_BOOLEAN(data, true); + } + + bool isFalse() const { + return JSVAL_IS_SPECIFIC_BOOLEAN(data, false); + } + + bool isMagic() const { + return JSVAL_IS_MAGIC_IMPL(data); + } + + bool isMagic(JSWhyMagic why) const { + JS_ASSERT_IF(isMagic(), data.s.payload.why == why); + return JSVAL_IS_MAGIC_IMPL(data); + } + + bool isMarkable() const { + return JSVAL_IS_TRACEABLE_IMPL(data); + } + + int32 gcKind() const { + JS_ASSERT(isMarkable()); + return JSVAL_TRACE_KIND_IMPL(data); + } + +#ifdef DEBUG + JSWhyMagic whyMagic() const { + JS_ASSERT(isMagic()); + return data.s.payload.why; + } +#endif + + /*** Comparison ***/ + + bool operator==(const Value &rhs) const { + return data.asBits == rhs.data.asBits; + } + + bool operator!=(const Value &rhs) const { + return data.asBits != rhs.data.asBits; + } + + friend bool SameType(const Value &lhs, const Value &rhs) { + return JSVAL_SAME_TYPE_IMPL(lhs.data, rhs.data); + } + + /*** Extract the value's typed payload ***/ + + int32 toInt32() const { + JS_ASSERT(isInt32()); + return JSVAL_TO_INT32_IMPL(data); + } + + double toDouble() const { + JS_ASSERT(isDouble()); + return data.asDouble; + } + + double toNumber() const { + JS_ASSERT(isNumber()); + return isDouble() ? toDouble() : double(toInt32()); + } + + JSString *toString() const { + JS_ASSERT(isString()); + return JSVAL_TO_STRING_IMPL(data); + } + + JSObject &toObject() const { + JS_ASSERT(isObject()); + return *JSVAL_TO_OBJECT_IMPL(data); + } + + JSObject *toObjectOrNull() const { + JS_ASSERT(isObjectOrNull()); + return JSVAL_TO_OBJECT_IMPL(data); + } + + void *asGCThing() const { + JS_ASSERT(isGCThing()); + return JSVAL_TO_GCTHING_IMPL(data); + } + + bool toBoolean() const { + JS_ASSERT(isBoolean()); + return JSVAL_TO_BOOLEAN_IMPL(data); + } + + uint32 payloadAsRawUint32() const { + JS_ASSERT(!isDouble()); + return data.s.payload.u32; + } + + uint64 asRawBits() const { + return data.asBits; + } + + /* + * In the extract/box/unbox functions below, "NonDouble" means this + * functions must not be called on a value that is a double. This allows + * these operations to be implemented more efficiently, since doubles + * generally already require special handling by the caller. + */ + JSValueType extractNonDoubleType() const { + return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); + } + + JSValueTag extractNonDoubleTag() const { + return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data); + } + + void unboxNonDoubleTo(uint64 *out) const { + UNBOX_NON_DOUBLE_JSVAL(data, out); + } + + void boxNonDoubleFrom(JSValueType type, uint64 *out) { + data = BOX_NON_DOUBLE_JSVAL(type, out); + } + + /* + * The trace-jit specializes JSVAL_TYPE_OBJECT into JSVAL_TYPE_FUNOBJ and + * JSVAL_TYPE_NONFUNOBJ. Since these two operations just return the type of + * a value, the caller must handle JSVAL_TYPE_OBJECT separately. + */ + JSValueType extractNonDoubleObjectTraceType() const { + JS_ASSERT(!isObject()); + return JSVAL_EXTRACT_NON_DOUBLE_TYPE_IMPL(data); + } + + JSValueTag extractNonDoubleObjectTraceTag() const { + JS_ASSERT(!isObject()); + return JSVAL_EXTRACT_NON_DOUBLE_TAG_IMPL(data); + } + + /* + * Private API + * + * Private setters/getters allow the caller to read/write arbitrary types + * that fit in the 64-bit payload. It is the caller's responsibility, after + * storing to a value with setPrivateX to only read with getPrivateX. + * Privates values are given a type type which ensures they are not marked. + */ + + bool isUnderlyingTypeOfPrivate() const { + return JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(data); + } + + void setPrivate(void *ptr) { + data = PRIVATE_PTR_TO_JSVAL_IMPL(ptr); + } + + void *toPrivate() const { + JS_ASSERT(JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(data)); + return JSVAL_TO_PRIVATE_PTR_IMPL(data); + } + + void setPrivateUint32(uint32 ui) { + data = PRIVATE_UINT32_TO_JSVAL_IMPL(ui); + } + + uint32 toPrivateUint32() const { + JS_ASSERT(JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE_IMPL(data)); + return JSVAL_TO_PRIVATE_UINT32_IMPL(data); + } + + uint32 &getPrivateUint32Ref() { + JS_ASSERT(isDouble()); + return data.s.payload.u32; + } + + private: + void staticAssertions() { + JS_STATIC_ASSERT(sizeof(JSValueType) == 1); + JS_STATIC_ASSERT(sizeof(JSValueTag) == 4); + JS_STATIC_ASSERT(sizeof(JSBool) == 4); + JS_STATIC_ASSERT(sizeof(JSWhyMagic) <= 4); + JS_STATIC_ASSERT(sizeof(jsval) == 8); + } + + jsval_layout data; +} JSVAL_ALIGNMENT; + +static JS_ALWAYS_INLINE Value +NullValue() +{ + Value v; + v.setNull(); + return v; +} + +static JS_ALWAYS_INLINE Value +UndefinedValue() +{ + Value v; + v.setUndefined(); + return v; +} + +static JS_ALWAYS_INLINE Value +Int32Value(int32 i32) +{ + Value v; + v.setInt32(i32); + return v; +} + +static JS_ALWAYS_INLINE Value +DoubleValue(double dbl) +{ + Value v; + v.setDouble(dbl); + return v; +} + +static JS_ALWAYS_INLINE Value +StringValue(JSString *str) +{ + Value v; + v.setString(str); + return v; +} + +static JS_ALWAYS_INLINE Value +BooleanValue(bool boo) +{ + Value v; + v.setBoolean(boo); + return v; +} + +static JS_ALWAYS_INLINE Value +ObjectValue(JSObject &obj) +{ + Value v; + v.setObject(obj); + return v; +} + +static JS_ALWAYS_INLINE Value +MagicValue(JSWhyMagic why) +{ + Value v; + v.setMagic(why); + return v; +} + +static JS_ALWAYS_INLINE Value +NumberValue(double dbl) +{ + Value v; + v.setNumber(dbl); + return v; +} + +static JS_ALWAYS_INLINE Value +ObjectOrNullValue(JSObject *obj) +{ + Value v; + v.setObjectOrNull(obj); + return v; +} + +static JS_ALWAYS_INLINE Value +PrivateValue(void *ptr) +{ + Value v; + v.setPrivate(ptr); + return v; +} + +/******************************************************************************/ + +/* + * As asserted above, js::Value and jsval are layout equivalent. This means: + * - an instance of jsval may be reinterpreted as a js::Value and vice versa; + * - a pointer to a function taking jsval arguments may be reinterpreted as a + * function taking the same arguments, s/jsval/js::Value/, and vice versa; + * - a struct containing jsval members may be reinterpreted as a struct with + * the same members, s/jsval/js::Value/, and vice versa. + * + * To prevent widespread conversion using casts, which would effectively + * disable the C++ typesystem in places where we want it, a set of safe + * conversions between known-equivalent types is provided below. Given a type + * JsvalT expressedin terms of jsval and an equivalent type ValueT expressed in + * terms of js::Value, instances may be converted back and forth using: + * + * JsvalT *x = ... + * ValueT *y = js::Valueify(x); + * JsvalT *z = js::Jsvalify(y); + * assert(x == z); + * + * Conversions between references is also provided for some types. If it seems + * like a cast is needed to convert between jsval/js::Value, consider adding a + * new safe overload to Jsvalify/Valueify. + */ + +static inline jsval * Jsvalify(Value *v) { return (jsval *)v; } +static inline const jsval * Jsvalify(const Value *v) { return (const jsval *)v; } +static inline jsval & Jsvalify(Value &v) { return (jsval &)v; } +static inline const jsval & Jsvalify(const Value &v) { return (const jsval &)v; } +static inline Value * Valueify(jsval *v) { return (Value *)v; } +static inline const Value * Valueify(const jsval *v) { return (const Value *)v; } +static inline Value ** Valueify(jsval **v) { return (Value **)v; } +static inline Value & Valueify(jsval &v) { return (Value &)v; } +static inline const Value & Valueify(const jsval &v) { return (const Value &)v; } + +struct Class; + +typedef JSBool +(* Native)(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval); +typedef JSBool +(* FastNative)(JSContext *cx, uintN argc, Value *vp); +typedef JSBool +(* PropertyOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp); +typedef JSBool +(* ConvertOp)(JSContext *cx, JSObject *obj, JSType type, Value *vp); +typedef JSBool +(* NewEnumerateOp)(JSContext *cx, JSObject *obj, JSIterateOp enum_op, + Value *statep, jsid *idp); +typedef JSBool +(* HasInstanceOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp); +typedef JSBool +(* CheckAccessOp)(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, + Value *vp); +typedef JSObjectOps * +(* GetObjectOps)(JSContext *cx, Class *clasp); +typedef JSBool +(* EqualityOp)(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp); +typedef JSBool +(* DefinePropOp)(JSContext *cx, JSObject *obj, jsid id, const Value *value, + PropertyOp getter, PropertyOp setter, uintN attrs); +typedef JSBool +(* PropertyIdOp)(JSContext *cx, JSObject *obj, jsid id, Value *vp); +typedef JSBool +(* CallOp)(JSContext *cx, uintN argc, Value *vp); + +static inline Native Valueify(JSNative f) { return (Native)f; } +static inline JSNative Jsvalify(Native f) { return (JSNative)f; } +static inline FastNative Valueify(JSFastNative f) { return (FastNative)f; } +static inline JSFastNative Jsvalify(FastNative f) { return (JSFastNative)f; } +static inline PropertyOp Valueify(JSPropertyOp f) { return (PropertyOp)f; } +static inline JSPropertyOp Jsvalify(PropertyOp f) { return (JSPropertyOp)f; } +static inline ConvertOp Valueify(JSConvertOp f) { return (ConvertOp)f; } +static inline JSConvertOp Jsvalify(ConvertOp f) { return (JSConvertOp)f; } +static inline NewEnumerateOp Valueify(JSNewEnumerateOp f) { return (NewEnumerateOp)f; } +static inline JSNewEnumerateOp Jsvalify(NewEnumerateOp f) { return (JSNewEnumerateOp)f; } +static inline HasInstanceOp Valueify(JSHasInstanceOp f) { return (HasInstanceOp)f; } +static inline JSHasInstanceOp Jsvalify(HasInstanceOp f) { return (JSHasInstanceOp)f; } +static inline CheckAccessOp Valueify(JSCheckAccessOp f) { return (CheckAccessOp)f; } +static inline JSCheckAccessOp Jsvalify(CheckAccessOp f) { return (JSCheckAccessOp)f; } +static inline GetObjectOps Valueify(JSGetObjectOps f) { return (GetObjectOps)f; } +static inline JSGetObjectOps Jsvalify(GetObjectOps f) { return (JSGetObjectOps)f; } +static inline EqualityOp Valueify(JSEqualityOp f); /* Same type as JSHasInstanceOp */ +static inline JSEqualityOp Jsvalify(EqualityOp f); /* Same type as HasInstanceOp */ +static inline DefinePropOp Valueify(JSDefinePropOp f) { return (DefinePropOp)f; } +static inline JSDefinePropOp Jsvalify(DefinePropOp f) { return (JSDefinePropOp)f; } +static inline PropertyIdOp Valueify(JSPropertyIdOp f); /* Same type as JSPropertyOp */ +static inline JSPropertyIdOp Jsvalify(PropertyIdOp f); /* Same type as PropertyOp */ +static inline CallOp Valueify(JSCallOp f); /* Same type as JSFastNative */ +static inline JSCallOp Jsvalify(CallOp f); /* Same type as FastNative */ + +static const PropertyOp PropertyStub = (PropertyOp)JS_PropertyStub; +static const JSEnumerateOp EnumerateStub = JS_EnumerateStub; +static const JSResolveOp ResolveStub = JS_ResolveStub; +static const ConvertOp ConvertStub = (ConvertOp)JS_ConvertStub; +static const JSFinalizeOp FinalizeStub = JS_FinalizeStub; + +struct Class { + const char *name; + uint32 flags; + + /* Mandatory non-null function pointer members. */ + PropertyOp addProperty; + PropertyOp delProperty; + PropertyOp getProperty; + PropertyOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + ConvertOp convert; + JSFinalizeOp finalize; + + /* Optionally non-null members start here. */ + GetObjectOps getObjectOps; + CheckAccessOp checkAccess; + Native call; + Native construct; + JSXDRObjectOp xdrObject; + HasInstanceOp hasInstance; + JSMarkOp mark; + void (*reserved0)(void); +}; +JS_STATIC_ASSERT(offsetof(JSClass, name) == offsetof(Class, name)); +JS_STATIC_ASSERT(offsetof(JSClass, flags) == offsetof(Class, flags)); +JS_STATIC_ASSERT(offsetof(JSClass, addProperty) == offsetof(Class, addProperty)); +JS_STATIC_ASSERT(offsetof(JSClass, delProperty) == offsetof(Class, delProperty)); +JS_STATIC_ASSERT(offsetof(JSClass, getProperty) == offsetof(Class, getProperty)); +JS_STATIC_ASSERT(offsetof(JSClass, setProperty) == offsetof(Class, setProperty)); +JS_STATIC_ASSERT(offsetof(JSClass, enumerate) == offsetof(Class, enumerate)); +JS_STATIC_ASSERT(offsetof(JSClass, resolve) == offsetof(Class, resolve)); +JS_STATIC_ASSERT(offsetof(JSClass, convert) == offsetof(Class, convert)); +JS_STATIC_ASSERT(offsetof(JSClass, finalize) == offsetof(Class, finalize)); +JS_STATIC_ASSERT(offsetof(JSClass, getObjectOps) == offsetof(Class, getObjectOps)); +JS_STATIC_ASSERT(offsetof(JSClass, checkAccess) == offsetof(Class, checkAccess)); +JS_STATIC_ASSERT(offsetof(JSClass, call) == offsetof(Class, call)); +JS_STATIC_ASSERT(offsetof(JSClass, construct) == offsetof(Class, construct)); +JS_STATIC_ASSERT(offsetof(JSClass, xdrObject) == offsetof(Class, xdrObject)); +JS_STATIC_ASSERT(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance)); +JS_STATIC_ASSERT(offsetof(JSClass, mark) == offsetof(Class, mark)); +JS_STATIC_ASSERT(offsetof(JSClass, reserved0) == offsetof(Class, reserved0)); +JS_STATIC_ASSERT(sizeof(JSClass) == sizeof(Class)); + +struct ExtendedClass { + Class base; + EqualityOp equality; + JSObjectOp outerObject; + JSObjectOp innerObject; + JSIteratorOp iteratorObject; + JSObjectOp wrappedObject; /* NB: infallible, null + returns are treated as + the original object */ + void (*reserved0)(void); + void (*reserved1)(void); + void (*reserved2)(void); +}; +JS_STATIC_ASSERT(offsetof(JSExtendedClass, base) == offsetof(ExtendedClass, base)); +JS_STATIC_ASSERT(offsetof(JSExtendedClass, equality) == offsetof(ExtendedClass, equality)); +JS_STATIC_ASSERT(offsetof(JSExtendedClass, outerObject) == offsetof(ExtendedClass, outerObject)); +JS_STATIC_ASSERT(offsetof(JSExtendedClass, innerObject) == offsetof(ExtendedClass, innerObject)); +JS_STATIC_ASSERT(offsetof(JSExtendedClass, iteratorObject) == offsetof(ExtendedClass, iteratorObject)); +JS_STATIC_ASSERT(offsetof(JSExtendedClass, wrappedObject) == offsetof(ExtendedClass, wrappedObject)); +JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved0) == offsetof(ExtendedClass, reserved0)); +JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved1) == offsetof(ExtendedClass, reserved1)); +JS_STATIC_ASSERT(offsetof(JSExtendedClass, reserved2) == offsetof(ExtendedClass, reserved2)); +JS_STATIC_ASSERT(sizeof(JSExtendedClass) == sizeof(ExtendedClass)); + +struct PropertyDescriptor { + JSObject *obj; + uintN attrs; + PropertyOp getter; + PropertyOp setter; + Value value; + uintN shortid; +}; +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, obj) == offsetof(PropertyDescriptor, obj)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, attrs) == offsetof(PropertyDescriptor, attrs)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, getter) == offsetof(PropertyDescriptor, getter)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, setter) == offsetof(PropertyDescriptor, setter)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, value) == offsetof(PropertyDescriptor, value)); +JS_STATIC_ASSERT(offsetof(JSPropertyDescriptor, shortid) == offsetof(PropertyDescriptor, shortid)); +JS_STATIC_ASSERT(sizeof(JSPropertyDescriptor) == sizeof(PropertyDescriptor)); + +static JS_ALWAYS_INLINE JSClass * Jsvalify(Class *c) { return (JSClass *)c; } +static JS_ALWAYS_INLINE Class * Valueify(JSClass *c) { return (Class *)c; } +static JS_ALWAYS_INLINE JSExtendedClass * Jsvalify(ExtendedClass *c) { return (JSExtendedClass *)c; } +static JS_ALWAYS_INLINE ExtendedClass * Valueify(JSExtendedClass *c) { return (ExtendedClass *)c; } +static JS_ALWAYS_INLINE JSPropertyDescriptor * Jsvalify(PropertyDescriptor *p) { return (JSPropertyDescriptor *) p; } +static JS_ALWAYS_INLINE PropertyDescriptor * Valueify(JSPropertyDescriptor *p) { return (PropertyDescriptor *) p; } + +/******************************************************************************/ + +/* + * In some cases (quickstubs) we want to take a value in whatever manner is + * appropriate for the architecture and normalize to a const js::Value &. On + * x64, passing a js::Value may cause the to unnecessarily be passed through + * memory instead of registers, so jsval, which is a builtin uint64 is used. + */ +#if JS_BITS_PER_WORD == 32 +typedef const js::Value *ValueArgType; + +static JS_ALWAYS_INLINE const js::Value & +ValueArgToConstRef(const js::Value *arg) +{ + return *arg; +} + +#elif JS_BITS_PER_WORD == 64 +typedef js::Value ValueArgType; + +static JS_ALWAYS_INLINE const Value & +ValueArgToConstRef(const Value &v) +{ + return v; +} +#endif + +} /* namespace js */ +#endif /* jsvalue_h__ */ diff --git a/js/src/jsvector.h b/js/src/jsvector.h index c0a3a9eb8f30..156400c7113c 100644 --- a/js/src/jsvector.h +++ b/js/src/jsvector.h @@ -190,6 +190,8 @@ class Vector : AllocPolicy bool growHeapStorageBy(size_t lengthInc); bool convertToHeapStorage(size_t lengthInc); + template inline bool growByImpl(size_t inc); + /* magic constants */ static const int sMaxInlineBytes = 1024; @@ -371,6 +373,9 @@ class Vector : AllocPolicy /* Call shrinkBy or growBy based on whether newSize > length(). */ bool resize(size_t newLength); + /* Leave new elements as uninitialized memory. */ + bool growByUninitialized(size_t incr); + void clear(); bool append(const T &t); @@ -546,15 +551,17 @@ Vector::shrinkBy(size_t incr) } template -inline bool -Vector::growBy(size_t incr) +template +JS_ALWAYS_INLINE bool +Vector::growByImpl(size_t incr) { ReentrancyGuard g(*this); if (usingInlineStorage()) { size_t freespace = sInlineCapacity - inlineLength(); if (incr <= freespace) { T *newend = inlineEnd() + incr; - Impl::initialize(inlineEnd(), newend); + if (InitNewElems) + Impl::initialize(inlineEnd(), newend); inlineLength() += incr; JS_ASSERT(usingInlineStorage()); return true; @@ -574,11 +581,26 @@ Vector::growBy(size_t incr) /* We are !usingInlineStorage(). Initialize new elements. */ JS_ASSERT(heapCapacity() - heapLength() >= incr); T *newend = heapEnd() + incr; - Impl::initialize(heapEnd(), newend); + if (InitNewElems) + Impl::initialize(heapEnd(), newend); heapEnd() = newend; return true; } +template +inline bool +Vector::growBy(size_t incr) +{ + return growByImpl(incr); +} + +template +inline bool +Vector::growByUninitialized(size_t incr) +{ + return growByImpl(incr); +} + template inline bool Vector::resize(size_t newLength) diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 00deb3f3992d..f350a0432ba6 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -65,7 +65,7 @@ JSObject::unwrap(uintN *flagsp) uintN flags = 0; if (wrapped->isWrapper()) { flags |= static_cast(wrapped->getProxyHandler())->flags(); - wrapped = JSVAL_TO_OBJECT(wrapped->getProxyPrivate()); + wrapped = wrapped->getProxyPrivate().toObjectOrNull(); } if (flagsp) *flagsp = flags; @@ -94,9 +94,10 @@ JSWrapper::~JSWrapper() bool JSWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc) + PropertyDescriptor *desc) { - GET(JS_GetPropertyDescriptorById(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, desc)); + GET(JS_GetPropertyDescriptorById(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, + Jsvalify(desc))); } static bool @@ -111,28 +112,29 @@ GetOwnPropertyDescriptor(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSP bool JSWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc) + PropertyDescriptor *desc) { - GET(GetOwnPropertyDescriptor(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, desc)); + GET(GetOwnPropertyDescriptor(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED, + Jsvalify(desc))); } bool JSWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc) + PropertyDescriptor *desc) { - SET(JS_DefinePropertyById(cx, wrappedObject(wrapper), id, desc->value, - desc->getter, desc->setter, desc->attrs)); + SET(JS_DefinePropertyById(cx, wrappedObject(wrapper), id, Jsvalify(desc->value), + Jsvalify(desc->getter), Jsvalify(desc->setter), desc->attrs)); } bool -JSWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +JSWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { - static jsid id = JSVAL_VOID; + jsid id = JSID_VOID; GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY | JSITER_HIDDEN, props)); } static bool -ValueToBoolean(jsval *vp, bool *bp) +ValueToBoolean(Value *vp, bool *bp) { *bp = js_ValueToBoolean(*vp); return true; @@ -141,22 +143,22 @@ ValueToBoolean(jsval *vp, bool *bp) bool JSWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) { - jsval v; - SET(JS_DeletePropertyById2(cx, wrappedObject(wrapper), id, &v) && + Value v; + SET(JS_DeletePropertyById2(cx, wrappedObject(wrapper), id, Jsvalify(&v)) && ValueToBoolean(&v, bp)); } bool -JSWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +JSWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { - static jsid id = JSVAL_VOID; + static jsid id = JSID_VOID; GET(GetPropertyNames(cx, wrappedObject(wrapper), 0, props)); } bool -JSWrapper::fix(JSContext *cx, JSObject *wrapper, jsval *vp) +JSWrapper::fix(JSContext *cx, JSObject *wrapper, Value *vp) { - *vp = JSVAL_VOID; + vp->setUndefined(); return true; } @@ -178,49 +180,49 @@ JSWrapper::has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) bool JSWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp) { - JSPropertyDescriptor desc; + PropertyDescriptor desc; JSObject *wobj = wrappedObject(wrapper); - GET(JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, &desc) && + GET(JS_GetPropertyDescriptorById(cx, wobj, id, JSRESOLVE_QUALIFIED, Jsvalify(&desc)) && Cond(desc.obj == wobj, bp)); } bool -JSWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp) +JSWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) { - GET(JS_GetPropertyById(cx, wrappedObject(wrapper), id, vp)); + GET(JS_GetPropertyById(cx, wrappedObject(wrapper), id, Jsvalify(vp))); } bool -JSWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp) +JSWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) { - SET(JS_SetPropertyById(cx, wrappedObject(wrapper), id, vp)); + SET(JS_SetPropertyById(cx, wrappedObject(wrapper), id, Jsvalify(vp))); } bool -JSWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +JSWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { - const jsid id = JSVAL_VOID; + const jsid id = JSID_VOID; GET(GetPropertyNames(cx, wrappedObject(wrapper), JSITER_OWNONLY, props)); } bool -JSWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp) +JSWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp) { - const jsid id = JSVAL_VOID; + const jsid id = JSID_VOID; GET(GetIterator(cx, wrappedObject(wrapper), flags, vp)); } bool -JSWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, jsval *vp) +JSWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp) { - const jsid id = JSVAL_VOID; + const jsid id = JSID_VOID; GET(JSProxyHandler::call(cx, wrapper, argc, vp)); } bool -JSWrapper::construct(JSContext *cx, JSObject *wrapper, uintN argc, jsval *argv, jsval *rval) +JSWrapper::construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, Value *rval) { - const jsid id = JSVAL_VOID; + const jsid id = JSID_VOID; GET(JSProxyHandler::construct(cx, wrapper, argc, argv, rval)); } @@ -228,7 +230,7 @@ JSString * JSWrapper::obj_toString(JSContext *cx, JSObject *wrapper) { JSString *str; - if (!enter(cx, wrapper, JSVAL_VOID, false)) + if (!enter(cx, wrapper, JSID_VOID, false)) return NULL; str = JSProxyHandler::obj_toString(cx, wrapper); leave(cx, wrapper); @@ -239,7 +241,7 @@ JSString * JSWrapper::fun_toString(JSContext *cx, JSObject *wrapper, uintN indent) { JSString *str; - if (!enter(cx, wrapper, JSVAL_VOID, false)) + if (!enter(cx, wrapper, JSID_VOID, false)) return NULL; str = JSProxyHandler::fun_toString(cx, wrapper, indent); leave(cx, wrapper); @@ -253,7 +255,7 @@ JSWrapper::trace(JSTracer *trc, JSObject *wrapper) } bool -JSWrapper::enter(JSContext *cx, JSObject *wrapper, jsval id, bool set) +JSWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, bool set) { return true; } @@ -269,7 +271,7 @@ JSObject * JSWrapper::New(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent, JSWrapper *handler) { - return NewProxyObject(cx, handler, OBJECT_TO_JSVAL(obj), proto, parent, + return NewProxyObject(cx, handler, ObjectValue(*obj), proto, parent, obj->isCallable() ? obj : NULL, NULL); } @@ -302,7 +304,7 @@ JSCompartment::init() } bool -JSCompartment::wrap(JSContext *cx, jsval *vp) +JSCompartment::wrap(JSContext *cx, Value *vp) { JS_ASSERT(cx->compartment == this); @@ -311,21 +313,17 @@ JSCompartment::wrap(JSContext *cx, jsval *vp) JS_CHECK_RECURSION(cx, return false); /* Only GC things have to be wrapped or copied. */ - if (JSVAL_IS_NULL(*vp) || !JSVAL_IS_GCTHING(*vp)) + if (!vp->isMarkable()) return true; /* Static strings do not have to be wrapped. */ - if (JSVAL_IS_STRING(*vp) && JSString::isStatic(JSVAL_TO_STRING(*vp))) + if (vp->isString() && JSString::isStatic(vp->toString())) return true; - /* Identity is no issue for doubles, so simply always copy them. */ - if (JSVAL_IS_DOUBLE(*vp)) - return js_NewNumberInRootedValue(cx, *JSVAL_TO_DOUBLE(*vp), vp); - /* Unwrap incoming objects. */ - if (!JSVAL_IS_PRIMITIVE(*vp)) { - JSObject *obj = JSVAL_TO_OBJECT(*vp)->unwrap(&flags); - *vp = OBJECT_TO_JSVAL(obj); + if (vp->isObject()) { + JSObject *obj = vp->toObject().unwrap(&flags); + vp->setObject(*obj); /* If the wrapped object is already in this compartment, we are done. */ if (obj->getCompartment(cx) == this) return true; @@ -337,15 +335,17 @@ JSCompartment::wrap(JSContext *cx, jsval *vp) return true; } - if (JSVAL_IS_STRING(*vp)) { - JSString *str = JSVAL_TO_STRING(*vp); + if (vp->isString()) { + Value orig = *vp; + JSString *str = vp->toString(); JSString *wrapped = js_NewStringCopyN(cx, str->chars(), str->length()); if (!wrapped) return false; - return crossCompartmentWrappers.put(*vp, *vp = STRING_TO_JSVAL(wrapped)); + vp->setString(wrapped); + return crossCompartmentWrappers.put(orig, *vp); } - JSObject *obj = JSVAL_TO_OBJECT(*vp); + JSObject *obj = &vp->toObject(); /* * Recurse to wrap the prototype. Long prototype chains will run out of @@ -370,7 +370,7 @@ JSCompartment::wrap(JSContext *cx, jsval *vp) if (!wrapper) return false; wrapper->setProto(proto); - *vp = OBJECT_TO_JSVAL(wrapper); + vp->setObject(*wrapper); if (!crossCompartmentWrappers.put(wrapper->getProxyPrivate(), *vp)) return false; @@ -389,10 +389,10 @@ JSCompartment::wrap(JSContext *cx, jsval *vp) bool JSCompartment::wrap(JSContext *cx, JSString **strp) { - AutoValueRooter tvr(cx, *strp); + AutoValueRooter tvr(cx, StringValue(*strp)); if (!wrap(cx, tvr.addr())) return false; - *strp = JSVAL_TO_STRING(tvr.value()); + *strp = tvr.value().toString(); return true; } @@ -401,10 +401,10 @@ JSCompartment::wrap(JSContext *cx, JSObject **objp) { if (!*objp) return true; - AutoValueRooter tvr(cx, *objp); + AutoValueRooter tvr(cx, ObjectValue(**objp)); if (!wrap(cx, tvr.addr())) return false; - *objp = JSVAL_TO_OBJECT(tvr.value()); + *objp = &tvr.value().toObject(); return true; } @@ -412,28 +412,28 @@ bool JSCompartment::wrapId(JSContext *cx, jsid *idp) { if (JSID_IS_INT(*idp)) return true; - AutoValueRooter tvr(cx, ID_TO_VALUE(*idp)); + AutoValueRooter tvr(cx, IdToValue(*idp)); if (!wrap(cx, tvr.addr())) return false; - return JS_ValueToId(cx, tvr.value(), idp); + return ValueToId(cx, tvr.value(), idp); } bool -JSCompartment::wrap(JSContext *cx, JSPropertyOp *propp) +JSCompartment::wrap(JSContext *cx, PropertyOp *propp) { union { - JSPropertyOp op; + PropertyOp op; jsval v; } u; u.op = *propp; - if (!wrap(cx, &u.v)) + if (!wrap(cx, &Valueify(u.v))) return false; *propp = u.op; return true; } bool -JSCompartment::wrap(JSContext *cx, JSPropertyDescriptor *desc) { +JSCompartment::wrap(JSContext *cx, PropertyDescriptor *desc) { return wrap(cx, &desc->obj) && (!(desc->attrs & JSPROP_GETTER) || wrap(cx, &desc->getter)) && (!(desc->attrs & JSPROP_SETTER) || wrap(cx, &desc->setter)) && @@ -441,11 +441,11 @@ JSCompartment::wrap(JSContext *cx, JSPropertyDescriptor *desc) { } bool -JSCompartment::wrap(JSContext *cx, AutoValueVector &props) { +JSCompartment::wrap(JSContext *cx, AutoIdVector &props) { jsid *vector = props.begin(); jsint length = props.length(); for (size_t n = 0; n < size_t(length); ++n) { - if (!wrap(cx, &vector[n])) + if (!wrapId(cx, &vector[n])) return false; } return true; @@ -458,7 +458,7 @@ JSCompartment::wrapException(JSContext *cx) { if (cx->throwing) { AutoValueRooter tvr(cx, cx->exception); cx->throwing = false; - cx->exception = JSVAL_NULL; + cx->exception.setNull(); if (wrap(cx, tvr.addr())) { cx->throwing = true; cx->exception = tvr.value(); @@ -473,7 +473,7 @@ JSCompartment::sweep(JSContext *cx) { /* Remove dead wrappers from the table. */ for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { - if (js_IsAboutToBeFinalized(JSVAL_TO_GCTHING(e.front().value))) + if (js_IsAboutToBeFinalized(e.front().value.asGCThing())) e.removeFront(); } } @@ -486,9 +486,9 @@ SetupFakeFrame(JSContext *cx, ExecuteFrameGuard &frame, JSFrameRegs ®s, JSObj if (!cx->stack().getExecuteFrame(cx, js_GetTopStackFrame(cx), vplen, nfixed, frame)) return false; - jsval *vp = frame.getvp(); - vp[0] = JSVAL_VOID; - vp[1] = JSVAL_VOID; + Value *vp = frame.getvp(); + vp[0].setUndefined(); + vp[1].setNull(); // satisfy LeaveTree assert JSStackFrame *fp = frame.getFrame(); PodZero(fp); // fp->fun and fp->script are both NULL @@ -573,7 +573,7 @@ JSCrossCompartmentWrapper::isCrossCompartmentWrapper(JSObject *obj) #define NOTHING (true) bool -JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc) +JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc) { PIERCE(cx, wrapper, GET, call.destination->wrapId(cx, &id), @@ -582,7 +582,7 @@ JSCrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrappe } bool -JSCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc) +JSCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc) { PIERCE(cx, wrapper, GET, call.destination->wrapId(cx, &id), @@ -591,9 +591,9 @@ JSCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wra } bool -JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc) +JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc) { - AutoDescriptor desc2(cx, desc); + AutoPropertyDescriptorRooter desc2(cx, desc); PIERCE(cx, wrapper, SET, call.destination->wrapId(cx, &id) && call.destination->wrap(cx, &desc2), JSWrapper::defineProperty(cx, wrapper, id, &desc2), @@ -601,7 +601,7 @@ JSCrossCompartmentWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid } bool -JSCrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +JSCrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { PIERCE(cx, wrapper, GET, NOTHING, @@ -619,7 +619,7 @@ JSCrossCompartmentWrapper::delete_(JSContext *cx, JSObject *wrapper, jsid id, bo } bool -JSCrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +JSCrossCompartmentWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { PIERCE(cx, wrapper, GET, NOTHING, @@ -646,7 +646,7 @@ JSCrossCompartmentWrapper::hasOwn(JSContext *cx, JSObject *wrapper, jsid id, boo } bool -JSCrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp) +JSCrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) { PIERCE(cx, wrapper, GET, call.destination->wrap(cx, &receiver) && call.destination->wrapId(cx, &id), @@ -655,7 +655,7 @@ JSCrossCompartmentWrapper::get(JSContext *cx, JSObject *wrapper, JSObject *recei } bool -JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp) +JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, Value *vp) { AutoValueRooter tvr(cx, *vp); PIERCE(cx, wrapper, SET, @@ -665,7 +665,7 @@ JSCrossCompartmentWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *recei } bool -JSCrossCompartmentWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +JSCrossCompartmentWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { PIERCE(cx, wrapper, GET, NOTHING, @@ -678,35 +678,67 @@ JSCrossCompartmentWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoVa * allows fast iteration over objects across a compartment boundary. */ static bool -CanReify(jsval *vp) +CanReify(Value *vp) { - return !JSVAL_IS_PRIMITIVE(*vp) && - JSVAL_TO_OBJECT(*vp)->getClass() == &js_IteratorClass.base && - !!(JSVAL_TO_OBJECT(*vp)->getNativeIterator()->flags & JSITER_ENUMERATE); + JSObject *obj; + return vp->isObject() && + (obj = &vp->toObject())->getClass() == &js_IteratorClass.base && + (obj->getNativeIterator()->flags & JSITER_ENUMERATE); } static bool -Reify(JSContext *cx, JSCompartment *origin, jsval *vp) +Reify(JSContext *cx, JSCompartment *origin, Value *vp) { - JSObject *iterObj = JSVAL_TO_OBJECT(*vp); + JSObject *iterObj = &vp->toObject(); NativeIterator *ni = iterObj->getNativeIterator(); - AutoValueVector props(cx); - size_t length = ni->length(); - if (length > 0) { - props.resize(length); - for (size_t n = 0; n < length; ++n) - props[n] = origin->wrap(cx, &ni->begin()[n]); + + /* Wrap the iteratee. */ + JSObject *obj = ni->obj; + if (!origin->wrap(cx, &obj)) + return false; + + /* + * Wrap the elements in the iterator's snapshot. + * N.B. the order of closing/creating iterators is important due to the + * implicit cx->enumerators state. + */ + + if (ni->isKeyIter()) { + size_t length = ni->numKeys(); + AutoIdVector keys(cx); + if (length > 0) { + if (!keys.resize(length)) + return false; + for (size_t i = 0; i < length; ++i) { + keys[i] = ni->beginKey()[i]; + if (!origin->wrapId(cx, &keys[i])) + return false; + } + } + + return js_CloseIterator(cx, iterObj) && + VectorToKeyIterator(cx, obj, ni->flags, keys, vp); } - JSObject *obj = ni->obj; - uintN flags = ni->flags; - return js_CloseIterator(cx, *vp) && - origin->wrap(cx, &obj) && - IdVectorToIterator(cx, obj, flags, props, vp); + size_t length = ni->numValues(); + AutoValueVector vals(cx); + if (length > 0) { + if (!vals.resize(length)) + return false; + for (size_t i = 0; i < length; ++i) { + vals[i] = ni->beginValue()[i]; + if (!origin->wrap(cx, &vals[i])) + return false; + } + + } + + return js_CloseIterator(cx, iterObj) && + VectorToValueIterator(cx, obj, ni->flags, vals, vp); } bool -JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp) +JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp) { PIERCE(cx, wrapper, GET, NOTHING, @@ -715,21 +747,21 @@ JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags } bool -JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, jsval *vp) +JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, Value *vp) { AutoCompartment call(cx, wrappedObject(wrapper)); if (!call.enter()) return false; - vp[0] = OBJECT_TO_JSVAL(call.target); + vp[0] = ObjectValue(*call.target); if (!call.destination->wrap(cx, &vp[1])) return false; - jsval *argv = JS_ARGV(cx, vp); + Value *argv = JS_ARGV(cx, vp); for (size_t n = 0; n < argc; ++n) { if (!call.destination->wrap(cx, &argv[n])) return false; } - jsval *fakevp = call.getvp(); + Value *fakevp = call.getvp(); fakevp[0] = vp[0]; fakevp[1] = vp[1]; if (!JSWrapper::call(cx, wrapper, argc, vp)) @@ -740,8 +772,8 @@ JSCrossCompartmentWrapper::call(JSContext *cx, JSObject *wrapper, uintN argc, js } bool -JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, uintN argc, jsval *argv, - jsval *rval) +JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, uintN argc, Value *argv, + Value *rval) { AutoCompartment call(cx, wrappedObject(wrapper)); if (!call.enter()) @@ -751,8 +783,8 @@ JSCrossCompartmentWrapper::construct(JSContext *cx, JSObject *wrapper, uintN arg if (!call.destination->wrap(cx, &argv[n])) return false; } - jsval *vp = call.getvp(); - vp[0] = OBJECT_TO_JSVAL(call.target); + Value *vp = call.getvp(); + vp[0] = ObjectValue(*call.target); if (!JSWrapper::construct(cx, wrapper, argc, argv, rval)) return false; diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index 9974b58a5da2..814a180f6218 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -59,31 +59,31 @@ class JSWrapper : public js::JSProxyHandler { /* ES5 Harmony fundamental wrapper traps. */ virtual JS_FRIEND_API(bool) getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc); + js::PropertyDescriptor *desc); virtual JS_FRIEND_API(bool) getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc); + js::PropertyDescriptor *desc); virtual JS_FRIEND_API(bool) defineProperty(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc); + js::PropertyDescriptor *desc); virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *wrapper, - js::AutoValueVector &props); + js::AutoIdVector &props); virtual JS_FRIEND_API(bool) delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); - virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props); - virtual JS_FRIEND_API(bool) fix(JSContext *cx, JSObject *wrapper, jsval *vp); + virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual JS_FRIEND_API(bool) fix(JSContext *cx, JSObject *wrapper, js::Value *vp); /* ES5 Harmony derived wrapper traps. */ virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, - jsval *vp); + js::Value *vp); virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, - jsval *vp); - virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props); - virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp); + js::Value *vp); + virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *wrapper, uintN flags, js::Value *vp); /* Spidermonkey extensions. */ - virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *wrapper, uintN argc, jsval *vp); + virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *wrapper, uintN argc, js::Value *vp); virtual JS_FRIEND_API(bool) construct(JSContext *cx, JSObject *wrapper, - uintN argc, jsval *argv, jsval *rval); + uintN argc, js::Value *argv, js::Value *rval); virtual JS_FRIEND_API(JSString *) obj_toString(JSContext *cx, JSObject *wrapper); virtual JS_FRIEND_API(JSString *) fun_toString(JSContext *cx, JSObject *wrapper, uintN indent); @@ -100,7 +100,7 @@ class JSWrapper : public js::JSProxyHandler { JSWrapper *handler); static inline JSObject *wrappedObject(JSObject *wrapper) { - return JSVAL_TO_OBJECT(wrapper->getProxyPrivate()); + return wrapper->getProxyPrivate().toObjectOrNull(); } }; @@ -113,36 +113,33 @@ class JSCrossCompartmentWrapper : public JSWrapper { /* ES5 Harmony fundamental wrapper traps. */ virtual JS_FRIEND_API(bool) getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc); + js::PropertyDescriptor *desc); virtual JS_FRIEND_API(bool) getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc); + js::PropertyDescriptor *desc); virtual JS_FRIEND_API(bool) defineProperty(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc); - virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props); + js::PropertyDescriptor *desc); + virtual JS_FRIEND_API(bool) getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); virtual JS_FRIEND_API(bool) delete_(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); - virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props); + virtual JS_FRIEND_API(bool) enumerate(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); /* ES5 Harmony derived wrapper traps. */ virtual JS_FRIEND_API(bool) has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); virtual JS_FRIEND_API(bool) hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); - virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp); - virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, jsval *vp); - virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props); - virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp); + virtual JS_FRIEND_API(bool) get(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, js::Value *vp); + virtual JS_FRIEND_API(bool) set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, js::Value *vp); + virtual JS_FRIEND_API(bool) enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual JS_FRIEND_API(bool) iterate(JSContext *cx, JSObject *wrapper, uintN flags, js::Value *vp); /* Spidermonkey extensions. */ - virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *wrapper, uintN argc, jsval *vp); + virtual JS_FRIEND_API(bool) call(JSContext *cx, JSObject *wrapper, uintN argc, js::Value *vp); virtual JS_FRIEND_API(bool) construct(JSContext *cx, JSObject *wrapper, - uintN argc, jsval *argv, jsval *rval); + uintN argc, js::Value *argv, js::Value *rval); virtual JS_FRIEND_API(JSString *) obj_toString(JSContext *cx, JSObject *wrapper); virtual JS_FRIEND_API(JSString *) fun_toString(JSContext *cx, JSObject *wrapper, uintN indent); static JS_FRIEND_API(bool) isCrossCompartmentWrapper(JSObject *obj); static JS_FRIEND_API(JSCrossCompartmentWrapper) singleton; - - /* Default id used for filter when the trap signature does not contain an id. */ - static const jsid id = JSVAL_VOID; }; namespace js { @@ -158,7 +155,7 @@ class AutoCompartment LazilyConstructed frame; JSFrameRegs regs; JSRegExpStatics statics; - AutoValueRooter input; + AutoStringRooter input; public: AutoCompartment(JSContext *cx, JSObject *target); @@ -168,7 +165,7 @@ class AutoCompartment bool enter(); void leave(); - jsval *getvp() { + js::Value *getvp() { JS_ASSERT(entered()); return frame.ref().getvp(); } diff --git a/js/src/jsxdrapi.cpp b/js/src/jsxdrapi.cpp index d9aedca9d93c..782162034525 100644 --- a/js/src/jsxdrapi.cpp +++ b/js/src/jsxdrapi.cpp @@ -36,6 +36,7 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ + #include "jsversion.h" #if JS_HAS_XDR @@ -56,6 +57,8 @@ #include "jsobjinlines.h" +using namespace js; + #ifdef DEBUG #define DBG(x) x #else @@ -504,22 +507,44 @@ XDRDoubleValue(JSXDRState *xdr, jsdouble *dp) } JS_PUBLIC_API(JSBool) -JS_XDRDouble(JSXDRState *xdr, jsdouble **dpp) +JS_XDRDouble(JSXDRState *xdr, jsdouble *dp) { - jsdouble d = (xdr->mode == JSXDR_ENCODE) ? **dpp : 0.0; + jsdouble d = (xdr->mode == JSXDR_ENCODE) ? *dp : 0.0; if (!XDRDoubleValue(xdr, &d)) return JS_FALSE; - if (xdr->mode == JSXDR_DECODE) { - *dpp = JS_NewDouble(xdr->cx, d); - if (!*dpp) - return JS_FALSE; - } + if (xdr->mode == JSXDR_DECODE) + *dp = d; return JS_TRUE; } -/* These are magic pseudo-tags: see jsapi.h, near the top, for real tags. */ -#define JSVAL_XDRNULL 0x8 -#define JSVAL_XDRVOID 0xA +enum jsvaltag { + JSVAL_OBJECT = 0x0, + JSVAL_INT = 0x1, + JSVAL_DOUBLE = 0x2, + JSVAL_STRING = 0x4, + JSVAL_SPECIAL = 0x6, + JSVAL_XDRNULL = 0x8, + JSVAL_XDRVOID = 0xA +}; + +static jsvaltag +JSVAL_TAG(jsval v) +{ + if (JSVAL_IS_NULL(v)) + return JSVAL_XDRNULL; + if (JSVAL_IS_VOID(v)) + return JSVAL_XDRVOID; + if (JSVAL_IS_OBJECT(v)) + return JSVAL_OBJECT; + if (JSVAL_IS_INT(v)) + return JSVAL_INT; + if (JSVAL_IS_DOUBLE(v)) + return JSVAL_DOUBLE; + if (JSVAL_IS_STRING(v)) + return JSVAL_STRING; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); + return JSVAL_SPECIAL; +} static JSBool XDRValueBody(JSXDRState *xdr, uint32 type, jsval *vp) @@ -542,11 +567,11 @@ XDRValueBody(JSXDRState *xdr, uint32 type, jsval *vp) break; } case JSVAL_DOUBLE: { - jsdouble *dp = (xdr->mode == JSXDR_ENCODE) ? JSVAL_TO_DOUBLE(*vp) : NULL; - if (!JS_XDRDouble(xdr, &dp)) + double d = xdr->mode == JSXDR_ENCODE ? JSVAL_TO_DOUBLE(*vp) : 0; + if (!JS_XDRDouble(xdr, &d)) return JS_FALSE; if (xdr->mode == JSXDR_DECODE) - *vp = DOUBLE_TO_JSVAL(dp); + *vp = DOUBLE_TO_JSVAL(d); break; } case JSVAL_OBJECT: { @@ -572,7 +597,7 @@ XDRValueBody(JSXDRState *xdr, uint32 type, jsval *vp) default: { uint32 i; - JS_ASSERT(type & JSVAL_INT); + JS_ASSERT(type == JSVAL_INT); if (xdr->mode == JSXDR_ENCODE) i = (uint32) JSVAL_TO_INT(*vp); if (!JS_XDRUint32(xdr, &i)) @@ -590,47 +615,28 @@ JS_XDRValue(JSXDRState *xdr, jsval *vp) { uint32 type; - if (xdr->mode == JSXDR_ENCODE) { - if (JSVAL_IS_NULL(*vp)) - type = JSVAL_XDRNULL; - else if (JSVAL_IS_VOID(*vp)) - type = JSVAL_XDRVOID; - else - type = JSVAL_TAG(*vp); - } + if (xdr->mode == JSXDR_ENCODE) + type = JSVAL_TAG(*vp); return JS_XDRUint32(xdr, &type) && XDRValueBody(xdr, type, vp); } JSBool js_XDRAtom(JSXDRState *xdr, JSAtom **atomp) { - jsval v; - uint32 type; + JSString *str; - if (xdr->mode == JSXDR_ENCODE) { - v = ATOM_KEY(*atomp); - return JS_XDRValue(xdr, &v); - } + if (xdr->mode == JSXDR_ENCODE) + str = ATOM_TO_STRING(*atomp); - /* - * Inline JS_XDRValue when decoding to avoid ceation of GC things when - * then corresponding atom already exists. See bug 321985. - */ - if (!JS_XDRUint32(xdr, &type)) + if (!JS_XDRString(xdr, &str)) return JS_FALSE; - if (type == JSVAL_STRING) - return js_XDRStringAtom(xdr, atomp); - if (type == JSVAL_DOUBLE) { - jsdouble d = 0; - if (!XDRDoubleValue(xdr, &d)) - return JS_FALSE; - *atomp = js_AtomizeDouble(xdr->cx, d); + if (xdr->mode == JSXDR_DECODE) { + *atomp = js_AtomizeString(xdr->cx, str, 0); return *atomp != NULL; } - return XDRValueBody(xdr, type, &v) && - js_AtomizePrimitiveValue(xdr->cx, v, atomp); + return JS_TRUE; } extern JSBool @@ -644,7 +650,6 @@ js_XDRStringAtom(JSXDRState *xdr, JSAtom **atomp) jschar stackChars[256]; if (xdr->mode == JSXDR_ENCODE) { - JS_ASSERT(ATOM_IS_STRING(*atomp)); str = ATOM_TO_STRING(*atomp); return JS_XDRString(xdr, &str); } diff --git a/js/src/jsxdrapi.h b/js/src/jsxdrapi.h index fcf8443cfa39..732671780661 100644 --- a/js/src/jsxdrapi.h +++ b/js/src/jsxdrapi.h @@ -164,7 +164,7 @@ extern JS_PUBLIC_API(JSBool) JS_XDRStringOrNull(JSXDRState *xdr, JSString **strp); extern JS_PUBLIC_API(JSBool) -JS_XDRDouble(JSXDRState *xdr, jsdouble **dp); +JS_XDRDouble(JSXDRState *xdr, jsdouble *dp); extern JS_PUBLIC_API(JSBool) JS_XDRValue(JSXDRState *xdr, jsval *vp); diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index 6cb68e2e0af9..8634e237ed88 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -70,6 +70,7 @@ #include "jsstaticcheck.h" #include "jsvector.h" +#include "jsatominlines.h" #include "jscntxtinlines.h" #include "jsobjinlines.h" @@ -107,6 +108,16 @@ js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval) { } +static inline void +js_LeaveLocalRootScopeWithResult(JSContext *cx, Value rval) +{ +} + +static inline void +js_LeaveLocalRootScopeWithResult(JSContext *cx, void *rval) +{ +} + #ifdef XML_METERING static struct { jsrefcount qname; @@ -203,7 +214,7 @@ AppendString(JSCharBuffer &cb, JSString *str) #define DEFINE_GETTER(name,code) \ static JSBool \ - name(JSContext *cx, JSObject *obj, jsval id, jsval *vp) \ + name(JSContext *cx, JSObject *obj, jsid id, jsval *vp) \ { \ code; \ return true; \ @@ -225,25 +236,25 @@ namespace_finalize(JSContext *cx, JSObject *obj) } static JSBool -namespace_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +namespace_equality(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) { JSObject *obj2; - JS_ASSERT(JSVAL_IS_OBJECT(v)); - obj2 = JSVAL_TO_OBJECT(v); + JS_ASSERT(v->isObjectOrNull()); + obj2 = v->toObjectOrNull(); *bp = (!obj2 || obj2->getClass() != &js_NamespaceClass.base) ? JS_FALSE : js_EqualStrings(GetURI(obj), GetURI(obj2)); return JS_TRUE; } -JS_FRIEND_DATA(JSExtendedClass) js_NamespaceClass = { +JS_FRIEND_DATA(ExtendedClass) js_NamespaceClass = { { "Namespace", JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED | JSCLASS_HAS_RESERVED_SLOTS(JSObject::NAMESPACE_FIXED_RESERVED_SLOTS) | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, namespace_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, namespace_finalize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, namespace_equality,NULL, NULL, NULL, @@ -265,7 +276,7 @@ namespace_toString(JSContext *cx, uintN argc, jsval *vp) JSObject *obj; obj = JS_THIS_OBJECT(cx, vp); - if (!JS_InstanceOf(cx, obj, &js_NamespaceClass.base, vp + 2)) + if (!JS_InstanceOf(cx, obj, Jsvalify(&js_NamespaceClass.base), vp + 2)) return JS_FALSE; *vp = obj->getNameURI(); return JS_TRUE; @@ -329,25 +340,24 @@ qname_identity(JSObject *qna, JSObject *qnb) } static JSBool -qname_equality(JSContext *cx, JSObject *qn, jsval v, JSBool *bp) +qname_equality(JSContext *cx, JSObject *qn, const Value *v, JSBool *bp) { JSObject *obj2; - JS_ASSERT(JSVAL_IS_OBJECT(v)); - obj2 = JSVAL_TO_OBJECT(v); + obj2 = v->toObjectOrNull(); *bp = (!obj2 || obj2->getClass() != &js_QNameClass.base) ? JS_FALSE : qname_identity(qn, obj2); return JS_TRUE; } -JS_FRIEND_DATA(JSExtendedClass) js_QNameClass = { +JS_FRIEND_DATA(ExtendedClass) js_QNameClass = { { "QName", JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_IS_EXTENDED | JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_QName), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, qname_equality, NULL, NULL, NULL, @@ -360,24 +370,24 @@ JS_FRIEND_DATA(JSExtendedClass) js_QNameClass = { * qname_toString method, and therefore are exposed as constructable objects * in this implementation. */ -JS_FRIEND_DATA(JSClass) js_AttributeNameClass = { +JS_FRIEND_DATA(Class) js_AttributeNameClass = { js_AttributeName_str, JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AttributeName), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, NULL, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -JS_FRIEND_DATA(JSClass) js_AnyNameClass = { +JS_FRIEND_DATA(Class) js_AnyNameClass = { js_AnyName_str, JSCLASS_CONSTRUCT_PROTOTYPE | JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_FIXED_RESERVED_SLOTS) | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_AnyName), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, anyname_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, anyname_finalize, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -395,7 +405,7 @@ static JSBool qname_toString(JSContext *cx, uintN argc, jsval *vp) { JSObject *obj; - JSClass *clasp; + Class *clasp; JSString *uri, *str, *qualstr; size_t length; jschar *chars; @@ -406,7 +416,7 @@ qname_toString(JSContext *cx, uintN argc, jsval *vp) clasp = obj->getClass(); if (clasp != &js_AttributeNameClass && clasp != &js_AnyNameClass && - !JS_InstanceOf(cx, obj, &js_QNameClass.base, vp + 2)) { + !JS_InstanceOf(cx, obj, Jsvalify(&js_QNameClass.base), vp + 2)) { return JS_FALSE; } @@ -469,7 +479,7 @@ InitXMLQName(JSObject *obj, JSString *uri, JSString *prefix, static JSObject * NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, JSString *localName, - JSClass *clasp = &js_QNameClass.base) + Class *clasp = &js_QNameClass.base) { JSObject *obj = NewBuiltinClassInstance(cx, clasp); if (!obj) @@ -481,21 +491,21 @@ NewXMLQName(JSContext *cx, JSString *uri, JSString *prefix, JSString *localName, } JSObject * -js_ConstructXMLQNameObject(JSContext *cx, jsval nsval, jsval lnval) +js_ConstructXMLQNameObject(JSContext *cx, const Value &nsval, const Value &lnval) { - jsval argv[2]; + Value argv[2]; /* * ECMA-357 11.1.2, * The _QualifiedIdentifier : PropertySelector :: PropertySelector_ * production, step 2. */ - if (!JSVAL_IS_PRIMITIVE(nsval) && - JSVAL_TO_OBJECT(nsval)->getClass() == &js_AnyNameClass) { - nsval = JSVAL_NULL; + if (nsval.isObject() && + nsval.toObject().getClass() == &js_AnyNameClass) { + argv[0].setNull(); + } else { + argv[0] = nsval; } - - argv[0] = nsval; argv[1] = lnval; return js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, argv); } @@ -535,7 +545,7 @@ js_IsXMLName(JSContext *cx, jsval v) name = GetLocalName(JSVAL_TO_OBJECT(v)); } else { older = JS_SetErrorReporter(cx, NULL); - name = js_ValueToString(cx, v); + name = js_ValueToString(cx, Valueify(v)); JS_SetErrorReporter(cx, older); if (!name) { JS_ClearPendingException(cx); @@ -557,7 +567,7 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, jsval urival, prefixval; JSObject *uriobj; JSBool isNamespace, isQName; - JSClass *clasp; + Class *clasp; JSString *empty, *uri, *prefix; isNamespace = isQName = JS_FALSE; @@ -603,7 +613,7 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, obj->setNameURI(STRING_TO_JSVAL(uri)); obj->setNamePrefix(uriobj->getNamePrefix()); } else { - uri = js_ValueToString(cx, urival); + uri = js_ValueToString(cx, Valueify(urival)); if (!uri) return JS_FALSE; obj->setNameURI(STRING_TO_JSVAL(uri)); @@ -612,7 +622,7 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, } } else if (argc == 2) { if (!isQName || !(uri = GetURI(uriobj))) { - uri = js_ValueToString(cx, urival); + uri = js_ValueToString(cx, Valueify(urival)); if (!uri) return JS_FALSE; } @@ -621,21 +631,21 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, prefixval = argv[0]; if (uri->empty()) { if (!JSVAL_IS_VOID(prefixval)) { - prefix = js_ValueToString(cx, prefixval); + prefix = js_ValueToString(cx, Valueify(prefixval)); if (!prefix) return JS_FALSE; if (!prefix->empty()) { + Value v = StringValue(prefix); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_XML_NAMESPACE, - js_ValueToPrintableString(cx, - STRING_TO_JSVAL(prefix))); + js_ValueToPrintableString(cx, v)); return JS_FALSE; } } } else if (JSVAL_IS_VOID(prefixval) || !js_IsXMLName(cx, prefixval)) { obj->setNamePrefix(JSVAL_VOID); } else { - prefix = js_ValueToString(cx, prefixval); + prefix = js_ValueToString(cx, Valueify(prefixval)); if (!prefix) return JS_FALSE; obj->setNamePrefix(STRING_TO_JSVAL(prefix)); @@ -646,11 +656,11 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, } static JSBool -Namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Namespace(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { return NamespaceHelper(cx, cx->isConstructing() ? obj : NULL, - argc, argv, rval); + argc, Jsvalify(argv), Jsvalify(rval)); } /* @@ -658,7 +668,7 @@ Namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * if argc is 1 and argv[0] is JSVAL_VOID. */ static JSBool -QNameHelper(JSContext *cx, JSObject *obj, JSClass *clasp, intN argc, +QNameHelper(JSContext *cx, JSObject *obj, Class *clasp, intN argc, jsval *argv, jsval *rval) { jsval nameval, nsval; @@ -717,7 +727,7 @@ QNameHelper(JSContext *cx, JSObject *obj, JSClass *clasp, intN argc, } else if (argc < 0) { name = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); } else { - name = js_ValueToString(cx, nameval); + name = js_ValueToString(cx, Valueify(nameval)); if (!name) return JS_FALSE; argv[argc > 1] = STRING_TO_JSVAL(name); @@ -765,7 +775,7 @@ QNameHelper(JSContext *cx, JSObject *obj, JSClass *clasp, intN argc, prefix = GetPrefix(obj2); } else { JS_ASSERT(argc > 1); - uri = js_ValueToString(cx, nsval); + uri = js_ValueToString(cx, Valueify(nsval)); if (!uri) return JS_FALSE; argv[0] = STRING_TO_JSVAL(uri); /* local root */ @@ -781,18 +791,18 @@ out: } static JSBool -QName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +QName(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Value *rval) { return QNameHelper(cx, cx->isConstructing() ? obj : NULL, - &js_QNameClass.base, argc, argv, rval); + &js_QNameClass.base, argc, Jsvalify(argv), Jsvalify(rval)); } static JSBool -AttributeName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +AttributeName(JSContext *cx, JSObject *obj, uintN argc, Value *argv, + Value *rval) { return QNameHelper(cx, cx->isConstructing() ? obj : NULL, - &js_AttributeNameClass, argc, argv, rval); + &js_AttributeNameClass, argc, Jsvalify(argv), Jsvalify(rval)); } /* @@ -1154,10 +1164,10 @@ ParseNodeToQName(Parser *parser, JSParseNode *pn, } if (!uri) { + Value v = StringValue(prefix); ReportCompileErrorNumber(parser->context, &parser->tokenStream, pn, JSREPORT_ERROR, JSMSG_BAD_XML_NAMESPACE, - js_ValueToPrintableString(parser->context, - STRING_TO_JSVAL(prefix))); + js_ValueToPrintableString(parser->context, v)); return NULL; } @@ -1373,10 +1383,10 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn, /* Enforce "Well-formedness constraint: Unique Att Spec". */ for (pn3 = head; pn3 != pn2; pn3 = pn3->pn_next->pn_next) { if (pn3->pn_atom == pn2->pn_atom) { + Value v = StringValue(ATOM_TO_STRING(pn2->pn_atom)); ReportCompileErrorNumber(cx, &parser->tokenStream, pn2, JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); + js_ValueToPrintableString(cx, v)); goto fail; } } @@ -1467,10 +1477,10 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn, attrjqn = attrj->name; if (js_EqualStrings(GetURI(attrjqn), GetURI(qn)) && js_EqualStrings(GetLocalName(attrjqn), GetLocalName(qn))) { + Value v = StringValue(ATOM_TO_STRING(pn2->pn_atom)); ReportCompileErrorNumber(cx, &parser->tokenStream, pn2, JSREPORT_ERROR, JSMSG_DUPLICATE_XML_ATTR, - js_ValueToPrintableString(cx, - ATOM_KEY(pn2->pn_atom))); + js_ValueToPrintableString(cx, v)); goto fail; } } @@ -1507,10 +1517,10 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn, xml_class = JSXML_CLASS_COMMENT; } else if (pn->pn_type == TOK_XMLPI) { if (IS_XML(str)) { + Value v = StringValue(str); ReportCompileErrorNumber(cx, &parser->tokenStream, pn, JSREPORT_ERROR, JSMSG_RESERVED_ID, - js_ValueToPrintableString(cx, - STRING_TO_JSVAL(str))); + js_ValueToPrintableString(cx, v)); goto fail; } @@ -1543,7 +1553,7 @@ ParseNodeToXML(Parser *parser, JSParseNode *pn, goto syntax; } - js_LeaveLocalRootScopeWithResult(cx, (jsval) xml); + js_LeaveLocalRootScopeWithResult(cx, xml); return xml; skip_child: @@ -1568,7 +1578,7 @@ GetXMLSetting(JSContext *cx, const char *name, jsval *vp) { jsval v; - if (!js_FindClassObject(cx, NULL, JSProto_XML, &v)) + if (!js_FindClassObject(cx, NULL, JSProto_XML, Valueify(&v))) return JS_FALSE; if (!VALUE_IS_FUNCTION(cx, v)) { *vp = JSVAL_VOID; @@ -1744,7 +1754,7 @@ ToXML(JSContext *cx, jsval v) { JSObject *obj; JSXML *xml; - JSClass *clasp; + Class *clasp; JSString *str; uint32 length; @@ -1779,7 +1789,7 @@ ToXML(JSContext *cx, jsval v) } } - str = js_ValueToString(cx, v); + str = js_ValueToString(cx, Valueify(v)); if (!str) return NULL; if (str->empty()) { @@ -1813,7 +1823,7 @@ ToXML(JSContext *cx, jsval v) bad: js_ReportValueError(cx, JSMSG_BAD_XML_CONVERSION, - JSDVG_IGNORE_STACK, v, NULL); + JSDVG_IGNORE_STACK, Valueify(v), NULL); return NULL; } @@ -1825,7 +1835,7 @@ ToXMLList(JSContext *cx, jsval v) { JSObject *obj, *listobj; JSXML *xml, *list, *kid; - JSClass *clasp; + Class *clasp; JSString *str; uint32 i, length; @@ -1860,7 +1870,7 @@ ToXMLList(JSContext *cx, jsval v) } } - str = js_ValueToString(cx, v); + str = js_ValueToString(cx, Valueify(v)); if (!str) return NULL; if (str->empty()) { @@ -1890,12 +1900,12 @@ ToXMLList(JSContext *cx, jsval v) } if (xml) - js_LeaveLocalRootScopeWithResult(cx, (jsval) listobj); + js_LeaveLocalRootScopeWithResult(cx, listobj); return listobj; bad: js_ReportValueError(cx, JSMSG_BAD_XMLLIST_CONVERSION, - JSDVG_IGNORE_STACK, v, NULL); + JSDVG_IGNORE_STACK, Valueify(v), NULL); return NULL; } @@ -2088,11 +2098,11 @@ GetNamespace(JSContext *cx, JSObject *qn, const JSXMLArray *inScopeNSes) prefix = GetPrefix(qn); JS_ASSERT(uri); if (!uri) { + Value v = StringValue(prefix); JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_XML_NAMESPACE, prefix - ? js_ValueToPrintableString(cx, - STRING_TO_JSVAL(prefix)) + ? js_ValueToPrintableString(cx, v) : js_undefined_str); return NULL; } @@ -2150,7 +2160,7 @@ GetNamespace(JSContext *cx, JSObject *qn, const JSXMLArray *inScopeNSes) argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID; argv[1] = STRING_TO_JSVAL(uri); ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL, - 2, argv); + 2, Valueify(argv)); if (!ns) return NULL; match = ns; @@ -2638,7 +2648,7 @@ XMLToXMLString(JSContext *cx, JSXML *xml, const JSXMLArray *ancestorNSes, str = js_NewStringFromCharBuffer(cx, cb); out: - js_LeaveLocalRootScopeWithResult(cx, STRING_TO_JSVAL(str)); + js_LeaveLocalRootScopeWithResult(cx, str); return str; } @@ -2658,7 +2668,7 @@ ToXMLString(JSContext *cx, jsval v, uint32 toSourceFlag) } if (JSVAL_IS_BOOLEAN(v) || JSVAL_IS_NUMBER(v)) - return js_ValueToString(cx, v); + return js_ValueToString(cx, Valueify(v)); if (JSVAL_IS_STRING(v)) { JSCharBuffer cb(cx); @@ -2667,9 +2677,9 @@ ToXMLString(JSContext *cx, jsval v, uint32 toSourceFlag) obj = JSVAL_TO_OBJECT(v); if (!obj->isXML()) { - if (!DefaultValue(cx, obj, JSTYPE_STRING, &v)) + if (!DefaultValue(cx, obj, JSTYPE_STRING, Valueify(&v))) return NULL; - str = js_ValueToString(cx, v); + str = js_ValueToString(cx, Valueify(v)); if (!str) return NULL; JSCharBuffer cb(cx); @@ -2686,7 +2696,7 @@ ToAttributeName(JSContext *cx, jsval v) { JSString *name, *uri, *prefix; JSObject *obj; - JSClass *clasp; + Class *clasp; JSObject *qn; if (JSVAL_IS_STRING(v)) { @@ -2695,7 +2705,7 @@ ToAttributeName(JSContext *cx, jsval v) } else { if (JSVAL_IS_PRIMITIVE(v)) { js_ReportValueError(cx, JSMSG_BAD_XML_ATTR_NAME, - JSDVG_IGNORE_STACK, v, NULL); + JSDVG_IGNORE_STACK, Valueify(v), NULL); return NULL; } @@ -2713,7 +2723,7 @@ ToAttributeName(JSContext *cx, jsval v) if (clasp == &js_AnyNameClass) { name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); } else { - name = js_ValueToString(cx, v); + name = js_ValueToString(cx, Valueify(v)); if (!name) return NULL; } @@ -2728,9 +2738,9 @@ ToAttributeName(JSContext *cx, jsval v) } static void -ReportBadXMLName(JSContext *cx, jsval id) +ReportBadXMLName(JSContext *cx, const Value &idval) { - js_ReportValueError(cx, JSMSG_BAD_XML_NAME, JSDVG_IGNORE_STACK, id, NULL); + js_ReportValueError(cx, JSMSG_BAD_XML_NAME, JSDVG_IGNORE_STACK, idval, NULL); } static JSBool @@ -2746,7 +2756,7 @@ IsFunctionQName(JSContext *cx, JSObject *qn, jsid *funidp) js_EqualStrings(uri, ATOM_TO_STRING(atom)))) { return JS_ValueToId(cx, STRING_TO_JSVAL(GetLocalName(qn)), funidp); } - *funidp = 0; + *funidp = JSID_VOID; return JS_TRUE; } @@ -2755,23 +2765,24 @@ js_IsFunctionQName(JSContext *cx, JSObject *obj, jsid *funidp) { if (obj->getClass() == &js_QNameClass.base) return IsFunctionQName(cx, obj, funidp); - *funidp = 0; + *funidp = JSID_VOID; return JS_TRUE; } static JSObject * ToXMLName(JSContext *cx, jsval v, jsid *funidp) { + JSAtom *atomizedName; JSString *name; JSObject *obj; - JSClass *clasp; + Class *clasp; uint32 index; if (JSVAL_IS_STRING(v)) { name = JSVAL_TO_STRING(v); } else { if (JSVAL_IS_PRIMITIVE(v)) { - ReportBadXMLName(cx, v); + ReportBadXMLName(cx, Valueify(v)); return NULL; } @@ -2783,11 +2794,15 @@ ToXMLName(JSContext *cx, jsval v, jsid *funidp) name = ATOM_TO_STRING(cx->runtime->atomState.starAtom); goto construct; } - name = js_ValueToString(cx, v); + name = js_ValueToString(cx, Valueify(v)); if (!name) return NULL; } + atomizedName = js_AtomizeString(cx, name, 0); + if (!atomizedName) + return NULL; + /* * ECMA-357 10.6.1 step 1 seems to be incorrect. The spec says: * @@ -2801,20 +2816,20 @@ ToXMLName(JSContext *cx, jsval v, jsid *funidp) * If the idea is to reject uint32 property names, then the check needs to * be stricter, to exclude hexadecimal and floating point literals. */ - if (js_IdIsIndex(STRING_TO_JSVAL(name), &index)) + if (js_IdIsIndex(ATOM_TO_JSID(atomizedName), &index)) goto bad; if (*name->chars() == '@') { name = js_NewDependentString(cx, name, 1, name->length() - 1); if (!name) return NULL; - *funidp = 0; + *funidp = JSID_VOID; return ToAttributeName(cx, STRING_TO_JSVAL(name)); } construct: v = STRING_TO_JSVAL(name); - obj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, &v); + obj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, Valueify(&v)); if (!obj) return NULL; @@ -2826,7 +2841,7 @@ out: bad: JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_XML_NAME, - js_ValueToPrintableString(cx, STRING_TO_JSVAL(name))); + js_ValueToPrintableString(cx, StringValue(name))); return NULL; } @@ -2943,7 +2958,7 @@ DeepCopy(JSContext *cx, JSXML *xml, JSObject *obj, uintN flags) copy = NULL; } } - js_LeaveLocalRootScopeWithResult(cx, (jsval) copy); + js_LeaveLocalRootScopeWithResult(cx, copy); return copy; } @@ -3170,7 +3185,7 @@ Descendants(JSContext *cx, JSXML *xml, jsval id) if (!listobj) return NULL; list = (JSXML *) listobj->getPrivate(); - if (funid) + if (!JSID_IS_VOID(funid)) return list; /* @@ -3195,7 +3210,7 @@ Descendants(JSContext *cx, JSXML *xml, jsval id) } else { ok = DescendantsHelper(cx, xml, nameqn, list); } - js_LeaveLocalRootScopeWithResult(cx, (jsval) list); + js_LeaveLocalRootScopeWithResult(cx, list); if (!ok) return NULL; list->name = NULL; @@ -3257,7 +3272,7 @@ retry: xobj = js_GetXMLObject(cx, kid); vobj = js_GetXMLObject(cx, vkid); if (!xobj || !vobj || - !js_TestXMLEquality(cx, xobj, OBJECT_TO_JSVAL(vobj), bp)) + !js_TestXMLEquality(cx, ObjectValue(*xobj), ObjectValue(*vobj), bp)) return JS_FALSE; if (!*bp) break; @@ -3305,7 +3320,7 @@ Equals(JSContext *cx, JSXML *xml, jsval v, JSBool *bp) vobj = js_GetXMLObject(cx, vxml); if (!vobj) return JS_FALSE; - return js_TestXMLEquality(cx, vobj, v, bp); + return js_TestXMLEquality(cx, ObjectValue(*vobj), Valueify(v), bp); } if (JSVAL_IS_VOID(v) && xml->xml_kids.length == 0) *bp = JS_TRUE; @@ -3376,7 +3391,7 @@ Insert(JSContext *cx, JSXML *xml, uint32 i, jsval v) } } if (!vxml) { - str = js_ValueToString(cx, v); + str = js_ValueToString(cx, Valueify(v)); if (!str) return JS_FALSE; @@ -3410,17 +3425,21 @@ Insert(JSContext *cx, JSXML *xml, uint32 i, jsval v) } static JSBool -IndexToIdVal(JSContext *cx, uint32 index, jsval *idvp) +IndexToId(JSContext *cx, uint32 index, jsid *idp) { + JSAtom *atom; JSString *str; - if (index <= JSVAL_INT_MAX) { - *idvp = INT_TO_JSVAL(index); + if (index <= JSID_INT_MAX) { + *idp = INT_TO_JSID(index); } else { str = js_NumberToString(cx, (jsdouble) index); if (!str) return JS_FALSE; - *idvp = STRING_TO_JSVAL(str); + atom = js_AtomizeString(cx, str, 0); + if (!atom) + return JS_FALSE; + *idp = ATOM_TO_JSID(atom); } return JS_TRUE; } @@ -3471,7 +3490,7 @@ Replace(JSContext *cx, JSXML *xml, uint32 i, jsval v) break; default: - str = js_ValueToString(cx, v); + str = js_ValueToString(cx, Valueify(v)); if (!str) return JS_FALSE; @@ -3632,7 +3651,7 @@ GetNamedProperty(JSContext *cx, JSXML *xml, JSObject* nameqn, JSXML *list) /* ECMA-357 9.1.1.1 XML [[Get]] and 9.2.1.1 XMLList [[Get]]. */ static JSBool -GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { JSXML *xml, *list, *kid; uint32 index; @@ -3640,7 +3659,7 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSObject *nameqn; jsid funid; - xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL); if (!xml) return true; @@ -3676,14 +3695,14 @@ GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) /* * ECMA-357 9.2.1.1/9.1.1.1 qname case. */ - nameqn = ToXMLName(cx, id, &funid); + nameqn = ToXMLName(cx, IdToJsval(id), &funid); if (!nameqn) return false; - if (funid) + if (!JSID_IS_VOID(funid)) return GetXMLFunction(cx, obj, funid, vp); jsval roots[2] = { OBJECT_TO_JSVAL(nameqn), JSVAL_NULL }; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots)); listobj = js_NewXMLObject(cx, JSXML_CLASS_LIST); if (!listobj) @@ -3736,7 +3755,7 @@ KidToString(JSContext *cx, JSXML *xml, uint32 index) kidobj = js_GetXMLObject(cx, kid); if (!kidobj) return NULL; - return js_ValueToString(cx, OBJECT_TO_JSVAL(kidobj)); + return js_ValueToString(cx, ObjectValue(*kidobj)); } /* Forward declared -- its implementation uses other statics that call it. */ @@ -3745,7 +3764,7 @@ ResolveValue(JSContext *cx, JSXML *list, JSXML **result); /* ECMA-357 9.1.1.2 XML [[Put]] and 9.2.1.2 XMLList [[Put]]. */ static JSBool -PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +PutProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { JSBool ok, primitiveAssign; enum { OBJ_ROOT, ID_ROOT, VAL_ROOT }; @@ -3758,7 +3777,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSString *left, *right, *space, *uri; JSObject *ns; - xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL); if (!xml) return JS_TRUE; @@ -3781,14 +3800,14 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) MUST_FLOW_THROUGH("out"); jsval roots[3]; roots[OBJ_ROOT] = OBJECT_TO_JSVAL(obj); - roots[ID_ROOT] = id; + roots[ID_ROOT] = IdToJsval(id); roots[VAL_ROOT] = *vp; - AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), roots); + AutoArrayRooter tvr(cx, JS_ARRAY_LENGTH(roots), Valueify(roots)); if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { /* See NOTE in spec: this variation is reserved for future use. */ - ReportBadXMLName(cx, id); + ReportBadXMLName(cx, IdToValue(id)); goto bad; } @@ -3955,7 +3974,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) if (!nameobj) goto bad; } - id = OBJECT_TO_JSVAL(nameobj); + id = OBJECT_TO_JSID(nameobj); if (parent) { /* 2(e)(i). */ @@ -4073,7 +4092,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) kidobj = js_GetXMLObject(cx, kid); if (!kidobj) goto bad; - id = ATOM_KEY(cx->runtime->atomState.starAtom); + id = ATOM_TO_JSID(cx->runtime->atomState.starAtom); ok = PutProperty(cx, kidobj, id, vp); if (!ok) goto out; @@ -4082,11 +4101,11 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) /* * ECMA-357 9.2.1.2/9.1.1.2 qname case. */ - nameqn = ToXMLName(cx, id, &funid); + nameqn = ToXMLName(cx, IdToJsval(id), &funid); if (!nameqn) goto bad; - if (funid) { - ok = js_SetProperty(cx, obj, funid, vp); + if (!JSID_IS_VOID(funid)) { + ok = js_SetProperty(cx, obj, funid, Valueify(vp)); goto out; } nameobj = nameqn; @@ -4262,7 +4281,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } /* 10-11. */ - id = JSVAL_VOID; + id = JSID_VOID; primitiveAssign = !vxml && !IS_STAR(GetLocalName(nameqn)); /* 12. */ @@ -4377,7 +4396,7 @@ out: type_error: JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_XMLLIST_PUT, - js_ValueToPrintableString(cx, id)); + js_ValueToPrintableString(cx, IdToValue(id))); bad: ok = JS_FALSE; goto out; @@ -4389,7 +4408,8 @@ ResolveValue(JSContext *cx, JSXML *list, JSXML **result) { JSXML *target, *base; JSObject *targetprop; - jsval id, tv; + jsid id; + jsval tv; if (list->xml_class != JSXML_CLASS_LIST || list->xml_kids.length != 0) { if (!js_GetXMLObject(cx, list)) @@ -4419,7 +4439,7 @@ ResolveValue(JSContext *cx, JSXML *list, JSXML **result) if (!js_GetXMLObject(cx, base)) return JS_FALSE; - id = OBJECT_TO_JSVAL(targetprop); + id = OBJECT_TO_JSID(targetprop); if (!GetProperty(cx, base->object, id, &tv)) return JS_FALSE; target = (JSXML *) JSVAL_TO_OBJECT(tv)->getPrivate(); @@ -4539,13 +4559,13 @@ HasProperty(JSContext *cx, JSObject *obj, jsval id, JSBool *found) jsid funid; xml = (JSXML *) obj->getPrivate(); - if (js_IdIsIndex(id, &i)) { + if (js_IdValIsIndex(id, &i)) { *found = HasIndexedProperty(xml, i); } else { qn = ToXMLName(cx, id, &funid); if (!qn) return JS_FALSE; - if (funid) { + if (!JSID_IS_VOID(funid)) { if (!HasFunctionProperty(cx, obj, funid, found)) return JS_FALSE; } else { @@ -4575,7 +4595,7 @@ xml_trace_vector(JSTracer *trc, JSXML **vec, uint32 len) xml = vec[i]; if (xml) { JS_SET_TRACING_INDEX(trc, "xml_vector", i); - js_CallGCMarker(trc, xml, JSTRACE_XML); + Mark(trc, xml, JSTRACE_XML); } } } @@ -4608,7 +4628,6 @@ static JSBool xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, JSProperty **propp) { - jsval v; JSBool found; JSXML *xml; uint32 i; @@ -4616,15 +4635,14 @@ xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, jsid funid; JSScopeProperty *sprop; - v = ID_TO_VALUE(id); xml = (JSXML *) obj->getPrivate(); - if (js_IdIsIndex(v, &i)) { + if (js_IdIsIndex(id, &i)) { found = HasIndexedProperty(xml, i); } else { - qn = ToXMLName(cx, v, &funid); + qn = ToXMLName(cx, IdToJsval(id), &funid); if (!qn) return JS_FALSE; - if (funid) + if (!JSID_IS_VOID(funid)) return js_LookupProperty(cx, obj, funid, objp, propp); found = HasNamedProperty(xml, qn); } @@ -4632,7 +4650,8 @@ xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, *objp = NULL; *propp = NULL; } else { - sprop = js_AddNativeProperty(cx, obj, id, GetProperty, PutProperty, + sprop = js_AddNativeProperty(cx, obj, id, + Valueify(GetProperty), Valueify(PutProperty), SPROP_INVALID_SLOT, JSPROP_ENUMERATE, 0, 0); if (!sprop) @@ -4646,40 +4665,41 @@ xml_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp, } static JSBool -xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSPropertyOp setter, uintN attrs) +xml_defineProperty(JSContext *cx, JSObject *obj, jsid id, const Value *v, + PropertyOp getter, PropertyOp setter, uintN attrs) { - if (VALUE_IS_FUNCTION(cx, value) || getter || setter || + if (IsFunctionObject(*v) || getter || setter || (attrs & JSPROP_ENUMERATE) == 0 || (attrs & (JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED))) { - return js_DefineProperty(cx, obj, id, value, getter, setter, attrs); + return js_DefineProperty(cx, obj, id, v, getter, setter, attrs); } - return PutProperty(cx, obj, ID_TO_VALUE(id), &value); + jsval tmp = Jsvalify(*v); + return PutProperty(cx, obj, id, &tmp); } static JSBool -xml_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +xml_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - if (id == JS_DEFAULT_XML_NAMESPACE_ID) { - *vp = JSVAL_VOID; + if (JSID_IS_DEFAULT_XML_NAMESPACE(id)) { + vp->setUndefined(); return JS_TRUE; } - return GetProperty(cx, obj, ID_TO_VALUE(id), vp); + return GetProperty(cx, obj, id, Jsvalify(vp)); } static JSBool -xml_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +xml_setProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - return PutProperty(cx, obj, ID_TO_VALUE(id), vp); + return PutProperty(cx, obj, id, Jsvalify(vp)); } static JSBool xml_getAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { JSBool found; - if (!HasProperty(cx, obj, ID_TO_VALUE(id), &found)) + if (!HasProperty(cx, obj, IdToJsval(id), &found)) return false; *attrsp = found ? JSPROP_ENUMERATE : 0; @@ -4690,7 +4710,7 @@ static JSBool xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) { JSBool found; - if (!HasProperty(cx, obj, ID_TO_VALUE(id), &found)) + if (!HasProperty(cx, obj, IdToJsval(id), &found)) return false; if (found) { @@ -4702,7 +4722,7 @@ xml_setAttributes(JSContext *cx, JSObject *obj, jsid id, uintN *attrsp) } static JSBool -xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) +xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval) { JSXML *xml; jsval idval; @@ -4710,12 +4730,12 @@ xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) JSObject *nameqn; jsid funid; - idval = ID_TO_VALUE(id); + idval = IdToJsval(id); xml = (JSXML *) obj->getPrivate(); - if (js_IdIsIndex(idval, &index)) { + if (js_IdIsIndex(id, &index)) { if (xml->xml_class != JSXML_CLASS_LIST) { /* See NOTE in spec: this variation is reserved for future use. */ - ReportBadXMLName(cx, id); + ReportBadXMLName(cx, IdToValue(id)); return JS_FALSE; } @@ -4725,7 +4745,7 @@ xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) nameqn = ToXMLName(cx, idval, &funid); if (!nameqn) return JS_FALSE; - if (funid) + if (!JSID_IS_VOID(funid)) return js_DeleteProperty(cx, obj, funid, rval); DeleteNamedProperty(cx, xml, nameqn, @@ -4742,18 +4762,18 @@ xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, jsval *rval) if (obj->scope()->object == obj && !js_DeleteProperty(cx, obj, id, rval)) return JS_FALSE; - *rval = JSVAL_TRUE; + rval->setBoolean(true); return JS_TRUE; } JSBool -xml_convert(JSContext *cx, JSObject *obj, JSType type, jsval *rval) +xml_convert(JSContext *cx, JSObject *obj, JSType type, Value *rval) { return js_TryMethod(cx, obj, cx->runtime->atomState.toStringAtom, 0, NULL, rval); } static JSBool -xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp) +xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, Value *statep, jsid *idp) { JSXML *xml; uint32 length, index; @@ -4766,23 +4786,23 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, case JSENUMERATE_INIT: case JSENUMERATE_INIT_ALL: if (length == 0) { - *statep = JSVAL_ZERO; + statep->setInt32(0); } else { cursor = cx->create(&xml->xml_kids); if (!cursor) return JS_FALSE; - *statep = PRIVATE_TO_JSVAL(cursor); + statep->setPrivate(cursor); } if (idp) *idp = INT_TO_JSID(length); break; case JSENUMERATE_NEXT: - if (*statep == JSVAL_ZERO) { - *statep = JSVAL_NULL; + if (statep->isInt32(0)) { + statep->setNull(); break; } - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + cursor = (JSXMLArrayCursor *) statep->toPrivate(); if (cursor && cursor->array && (index = cursor->index) < length) { *idp = INT_TO_JSID(index); cursor->index = index + 1; @@ -4791,12 +4811,12 @@ xml_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, /* FALL THROUGH */ case JSENUMERATE_DESTROY: - if (*statep != JSVAL_ZERO) { - cursor = (JSXMLArrayCursor *) JSVAL_TO_PRIVATE(*statep); + if (!statep->isInt32(0)) { + cursor = (JSXMLArrayCursor *) statep->toPrivate(); if (cursor) cx->destroy(cursor); } - *statep = JSVAL_NULL; + statep->setNull(); break; } return JS_TRUE; @@ -4809,7 +4829,7 @@ xml_typeOf(JSContext *cx, JSObject *obj) } static JSBool -xml_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +xml_hasInstance(JSContext *cx, JSObject *obj, const Value *, JSBool *bp) { return JS_TRUE; } @@ -4867,16 +4887,16 @@ again: * 11.2.2.1 Step 3(d) onward. */ JSBool -js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) +js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, Value *vp) { - JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL)); + JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL)); if (JSID_IS_OBJECT(id)) { jsid funid; if (!js_IsFunctionQName(cx, JSID_TO_OBJECT(id), &funid)) return JS_FALSE; - if (funid != 0) + if (!JSID_IS_VOID(funid)) id = funid; } @@ -4885,13 +4905,13 @@ js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp) * local value as vp, we use a proper root here. */ AutoValueRooter tvr(cx); - JSBool ok = GetXMLFunction(cx, obj, id, tvr.addr()); + JSBool ok = GetXMLFunction(cx, obj, id, Jsvalify(tvr.addr())); *vp = tvr.value(); return ok; } JSBool -js_TestXMLEquality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +js_TestXMLEquality(JSContext *cx, const Value &v1, const Value &v2, JSBool *bp) { JSXML *xml, *vxml; JSObject *vobj; @@ -4899,7 +4919,18 @@ js_TestXMLEquality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) JSString *str, *vstr; jsdouble d, d2; - JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL)); + JSObject *obj; + jsval v; + if (v1.isObject() && v1.toObject().isXML()) { + obj = &v1.toObject(); + v = Jsvalify(v2); + } else { + v = Jsvalify(v1); + obj = &v2.toObject(); + } + + JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL)); + xml = (JSXML *) obj->getPrivate(); vxml = NULL; if (!JSVAL_IS_PRIMITIVE(v)) { @@ -4922,8 +4953,8 @@ js_TestXMLEquality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) HasSimpleContent(xml))) { ok = js_EnterLocalRootScope(cx); if (ok) { - ok = (str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj))) && - (vstr = js_ValueToString(cx, v)); + ok = (str = js_ValueToString(cx, ObjectValue(*obj))) && + (vstr = js_ValueToString(cx, Valueify(v))); if (ok) *bp = js_EqualStrings(str, vstr); js_LeaveLocalRootScope(cx); @@ -4936,12 +4967,12 @@ js_TestXMLEquality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) ok = js_EnterLocalRootScope(cx); if (ok) { if (HasSimpleContent(xml)) { - ok = (str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj))) && - (vstr = js_ValueToString(cx, v)); + ok = (str = js_ValueToString(cx, ObjectValue(*obj))) && + (vstr = js_ValueToString(cx, Valueify(v))); if (ok) *bp = js_EqualStrings(str, vstr); } else if (JSVAL_IS_STRING(v) || JSVAL_IS_NUMBER(v)) { - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, ObjectValue(*obj)); if (!str) { ok = JS_FALSE; } else if (JSVAL_IS_STRING(v)) { @@ -4950,7 +4981,7 @@ js_TestXMLEquality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) ok = JS_ValueToNumber(cx, STRING_TO_JSVAL(str), &d); if (ok) { d2 = JSVAL_IS_INT(v) ? JSVAL_TO_INT(v) - : *JSVAL_TO_DOUBLE(v); + : JSVAL_TO_DOUBLE(v); *bp = JSDOUBLE_COMPARE(d, ==, d2, JS_FALSE); } } @@ -4964,13 +4995,13 @@ js_TestXMLEquality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) } JSBool -js_ConcatenateXML(JSContext *cx, JSObject *obj, jsval v, jsval *vp) +js_ConcatenateXML(JSContext *cx, JSObject *obj, JSObject *robj, Value *vp) { JSBool ok; - JSObject *listobj, *robj; + JSObject *listobj; JSXML *list, *lxml, *rxml; - JS_ASSERT(JS_InstanceOf(cx, obj, &js_XMLClass, NULL)); + JS_ASSERT(JS_InstanceOf(cx, obj, Jsvalify(&js_XMLClass), NULL)); ok = js_EnterLocalRootScope(cx); if (!ok) return JS_FALSE; @@ -4987,21 +5018,13 @@ js_ConcatenateXML(JSContext *cx, JSObject *obj, jsval v, jsval *vp) if (!ok) goto out; - if (VALUE_IS_XML(v)) { - rxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); - } else { - robj = ToXML(cx, v); - if (!robj) { - ok = JS_FALSE; - goto out; - } - rxml = (JSXML *) robj->getPrivate(); - } + JS_ASSERT(robj->isXML()); + rxml = (JSXML *) robj->getPrivate(); ok = Append(cx, list, rxml); if (!ok) goto out; - *vp = OBJECT_TO_JSVAL(listobj); + vp->setObject(*listobj); out: js_LeaveLocalRootScopeWithResult(cx, *vp); return ok; @@ -5028,17 +5051,17 @@ JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps = { }; static JSObjectOps * -xml_getObjectOps(JSContext *cx, JSClass *clasp) +xml_getObjectOps(JSContext *cx, Class *clasp) { return &js_XMLObjectOps; } -JS_FRIEND_DATA(JSClass) js_XMLClass = { +JS_FRIEND_DATA(Class) js_XMLClass = { js_XML_str, JSCLASS_HAS_PRIVATE | JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_XML), - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, xml_convert, xml_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, xml_convert, xml_finalize, xml_getObjectOps, NULL, NULL, NULL, NULL, NULL, JS_CLASS_TRACE(xml_trace), NULL }; @@ -5053,7 +5076,7 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp) JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp)); *objp = JS_THIS_OBJECT(cx, vp); - xml = (JSXML *) JS_GetInstancePrivate(cx, *objp, &js_XMLClass, vp + 2); + xml = (JSXML *) GetInstancePrivate(cx, *objp, &js_XMLClass, Valueify(vp + 2)); if (!xml || xml->xml_class != JSXML_CLASS_LIST) return xml; @@ -5079,7 +5102,7 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp) /* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */ #define XML_METHOD_PROLOG \ JSObject *obj = JS_THIS_OBJECT(cx, vp); \ - JSXML *xml = (JSXML *)JS_GetInstancePrivate(cx, obj, &js_XMLClass, vp+2); \ + JSXML *xml = (JSXML *)GetInstancePrivate(cx, obj, &js_XMLClass, Valueify(vp+2)); \ if (!xml) \ return JS_FALSE @@ -5119,7 +5142,7 @@ xml_addNamespace(JSContext *cx, uintN argc, jsval *vp) static JSBool xml_appendChild(JSContext *cx, uintN argc, jsval *vp) { - jsval name, v; + jsval v; JSObject *vobj; JSXML *vxml; @@ -5128,6 +5151,7 @@ xml_appendChild(JSContext *cx, uintN argc, jsval *vp) if (!xml) return JS_FALSE; + jsid name; if (!js_GetAnyName(cx, &name)) return JS_FALSE; @@ -5140,9 +5164,10 @@ xml_appendChild(JSContext *cx, uintN argc, jsval *vp) vxml = (JSXML *) vobj->getPrivate(); JS_ASSERT(vxml->xml_class == JSXML_CLASS_LIST); - if (!IndexToIdVal(cx, vxml->xml_kids.length, &name)) + if (!IndexToId(cx, vxml->xml_kids.length, &name)) return JS_FALSE; *vp = (argc != 0) ? vp[2] : JSVAL_VOID; + if (!PutProperty(cx, JSVAL_TO_OBJECT(v), name, vp)) return JS_FALSE; @@ -5157,7 +5182,7 @@ xml_attribute(JSContext *cx, uintN argc, jsval *vp) JSObject *qn; if (argc == 0) { - js_ReportMissingArg(cx, vp, 0); + js_ReportMissingArg(cx, Valueify(*vp), 0); return JS_FALSE; } @@ -5166,21 +5191,22 @@ xml_attribute(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; vp[2] = OBJECT_TO_JSVAL(qn); /* local root */ - return GetProperty(cx, JS_THIS_OBJECT(cx, vp), vp[2], vp); + jsid id = OBJECT_TO_JSID(qn); + return GetProperty(cx, JS_THIS_OBJECT(cx, vp), id, vp); } /* XML and XMLList */ static JSBool xml_attributes(JSContext *cx, uintN argc, jsval *vp) { - jsval name = ATOM_KEY(cx->runtime->atomState.starAtom); + jsval name = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); JSObject *qn = ToAttributeName(cx, name); if (!qn) return JS_FALSE; - name = OBJECT_TO_JSVAL(qn); - AutoValueRooter tvr(cx, name); - return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); + AutoObjectRooter tvr(cx, qn); + jsid id = OBJECT_TO_JSID(qn); + return GetProperty(cx, JS_THIS_OBJECT(cx, vp), id, vp); } static JSXML * @@ -5199,6 +5225,29 @@ xml_list_helper(JSContext *cx, JSXML *xml, jsval *rval) return list; } +static JSBool +ValueToId(JSContext *cx, jsval v, AutoIdRooter *idr) +{ + if (JSVAL_IS_INT(v)) { + jsint i = JSVAL_TO_INT(v); + if (INT_FITS_IN_JSID(i)) + *idr->addr() = INT_TO_JSID(i); + else if (!js_ValueToStringId(cx, Valueify(v), idr->addr())) + return JS_FALSE; + } else if (JSVAL_IS_STRING(v)) { + JSAtom *atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0); + if (!atom) + return JS_FALSE; + *idr->addr() = ATOM_TO_JSID(atom); + } else if (!JSVAL_IS_PRIMITIVE(v)) { + *idr->addr() = OBJECT_TO_JSID(JSVAL_TO_OBJECT(v)); + } else { + ReportBadXMLName(cx, Valueify(v)); + return JS_FALSE; + } + return JS_TRUE; +} + static JSBool xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name, jsval *rval) @@ -5210,7 +5259,7 @@ xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name, /* ECMA-357 13.4.4.6 */ JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); - if (js_IdIsIndex(name, &index)) { + if (js_IdValIsIndex(name, &index)) { if (index >= JSXML_LENGTH(xml)) { *rval = JSVAL_VOID; } else { @@ -5227,19 +5276,23 @@ xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name, return JS_TRUE; } - return GetProperty(cx, obj, name, rval); + AutoIdRooter idr(cx); + if (!ValueToId(cx, name, &idr)) + return JS_FALSE; + + return GetProperty(cx, obj, idr.id(), rval); } /* XML and XMLList */ static JSBool xml_child(JSContext *cx, uintN argc, jsval *vp) { - jsval name, v; + jsval v; JSXML *list, *vxml; JSObject *kidobj; XML_METHOD_PROLOG; - name = argc != 0 ? vp[2] : JSVAL_VOID; + jsval name = argc != 0 ? vp[2] : JSVAL_VOID; if (xml->xml_class == JSXML_CLASS_LIST) { /* ECMA-357 13.5.4.4 */ list = xml_list_helper(cx, xml, vp); @@ -5285,7 +5338,7 @@ xml_childIndex(JSContext *cx, uintN argc, jsval *vp) NON_LIST_XML_METHOD_PROLOG; parent = xml->parent; if (!parent || xml->xml_class == JSXML_CLASS_ATTRIBUTE) { - *vp = cx->runtime->NaNValue; + *vp = DOUBLE_TO_JSVAL(js_NaN); return JS_TRUE; } for (i = 0, n = JSXML_LENGTH(parent); i < n; i++) { @@ -5293,16 +5346,18 @@ xml_childIndex(JSContext *cx, uintN argc, jsval *vp) break; } JS_ASSERT(i < n); - return js_NewNumberInRootedValue(cx, i, vp); + if (i <= JSVAL_INT_MAX) + *vp = INT_TO_JSVAL(i); + else + *vp = DOUBLE_TO_JSVAL(i); + return JS_TRUE; } /* XML and XMLList */ static JSBool xml_children(JSContext *cx, uintN argc, jsval *vp) { - jsval name; - - name = ATOM_KEY(cx->runtime->atomState.starAtom); + jsid name = ATOM_TO_JSID(cx->runtime->atomState.starAtom); return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); } @@ -5337,7 +5392,7 @@ xml_comments_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval *vp) ok = JS_FALSE; v = JSVAL_NULL; } - js_LeaveLocalRootScopeWithResult(cx, v); + js_LeaveLocalRootScopeWithResult(cx, Valueify(v)); if (!ok) break; vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); @@ -5385,13 +5440,13 @@ xml_contains(JSContext *cx, uintN argc, jsval *vp) JSXMLArrayCursor cursor(&xml->xml_kids); while (JSXML *kid = (JSXML *) cursor.getNext()) { kidobj = js_GetXMLObject(cx, kid); - if (!kidobj || !js_TestXMLEquality(cx, kidobj, value, &eq)) + if (!kidobj || !js_TestXMLEquality(cx, ObjectValue(*kidobj), Valueify(value), &eq)) return JS_FALSE; if (eq) break; } } else { - if (!js_TestXMLEquality(cx, obj, value, &eq)) + if (!js_TestXMLEquality(cx, ObjectValue(*obj), Valueify(value), &eq)) return JS_FALSE; } *vp = BOOLEAN_TO_JSVAL(eq); @@ -5420,7 +5475,7 @@ xml_descendants(JSContext *cx, uintN argc, jsval *vp) JSXML *list; XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; + name = argc == 0 ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; list = Descendants(cx, xml, name); if (!list) return JS_FALSE; @@ -5461,7 +5516,7 @@ xml_elements_helper(JSContext *cx, JSObject *obj, JSXML *xml, ok = JS_FALSE; v = JSVAL_NULL; } - js_LeaveLocalRootScopeWithResult(cx, v); + js_LeaveLocalRootScopeWithResult(cx, Valueify(v)); if (!ok) break; vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); @@ -5496,13 +5551,13 @@ xml_elements(JSContext *cx, uintN argc, jsval *vp) XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; + name = (argc == 0) ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; nameqn = ToXMLName(cx, name, &funid); if (!nameqn) return JS_FALSE; vp[2] = OBJECT_TO_JSVAL(nameqn); - if (funid) + if (!JSID_IS_VOID(funid)) return xml_list_helper(cx, xml, vp) != NULL; return xml_elements_helper(cx, obj, xml, nameqn, vp); @@ -5517,7 +5572,7 @@ xml_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) JSBool found; obj = JS_THIS_OBJECT(cx, vp); - if (!JS_InstanceOf(cx, obj, &js_XMLClass, vp + 2)) + if (!InstanceOf(cx, obj, &js_XMLClass, Valueify(vp + 2))) return JS_FALSE; name = argc != 0 ? vp[2] : JSVAL_VOID; @@ -5527,7 +5582,7 @@ xml_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) *vp = JSVAL_TRUE; return JS_TRUE; } - return js_HasOwnPropertyHelper(cx, js_LookupProperty, argc, vp); + return js_HasOwnPropertyHelper(cx, js_LookupProperty, argc, Valueify(vp)); } /* XML and XMLList */ @@ -5643,7 +5698,7 @@ NamespacesToJSArray(JSContext *cx, JSXMLArray *array, jsval *rval) JSObject *ns = XMLARRAY_MEMBER(array, i, JSObject); if (!ns) continue; - tvr.setObject(ns); + tvr.set(ObjectValue(*ns)); if (!arrayobj->setProperty(cx, INT_TO_JSID(i), tvr.addr())) return false; } @@ -5731,8 +5786,11 @@ xml_length(JSContext *cx, uintN argc, jsval *vp) if (xml->xml_class != JSXML_CLASS_LIST) { *vp = JSVAL_ONE; } else { - if (!js_NewNumberInRootedValue(cx, xml->xml_kids.length, vp)) - return JS_FALSE; + uint32 l = xml->xml_kids.length; + if (l <= JSVAL_INT_MAX) + *vp = INT_TO_JSVAL(l); + else + *vp = DOUBLE_TO_JSVAL(l); } return JS_TRUE; } @@ -5769,7 +5827,7 @@ xml_namespace(JSContext *cx, uintN argc, jsval *vp) if (argc == 0) { prefix = NULL; } else { - prefix = js_ValueToString(cx, vp[2]); + prefix = js_ValueToString(cx, Valueify(vp[2])); if (!prefix) return false; vp[2] = STRING_TO_JSVAL(prefix); /* local root */ @@ -6000,7 +6058,7 @@ xml_processingInstructions_helper(JSContext *cx, JSObject *obj, JSXML *xml, ok = JS_FALSE; v = JSVAL_NULL; } - js_LeaveLocalRootScopeWithResult(cx, v); + js_LeaveLocalRootScopeWithResult(cx, Valueify(v)); if (!ok) break; vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); @@ -6039,13 +6097,13 @@ xml_processingInstructions(JSContext *cx, uintN argc, jsval *vp) XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; + name = (argc == 0) ? ATOM_TO_JSVAL(cx->runtime->atomState.starAtom) : vp[2]; nameqn = ToXMLName(cx, name, &funid); if (!nameqn) return JS_FALSE; vp[2] = OBJECT_TO_JSVAL(nameqn); - if (funid) + if (!JSID_IS_VOID(funid)) return xml_list_helper(cx, xml, vp) != NULL; return xml_processingInstructions_helper(cx, obj, xml, nameqn, vp); @@ -6070,7 +6128,7 @@ xml_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp) XML_METHOD_PROLOG; *vp = JSVAL_FALSE; - if (argc != 0 && js_IdIsIndex(vp[2], &index)) { + if (argc != 0 && js_IdValIsIndex(vp[2], &index)) { if (xml->xml_class == JSXML_CLASS_LIST) { /* 13.5.4.18. */ *vp = BOOLEAN_TO_JSVAL(index < xml->xml_kids.length); @@ -6172,8 +6230,7 @@ xml_replace(JSContext *cx, uintN argc, jsval *vp) goto done; if (argc <= 1) { - value = STRING_TO_JSVAL(ATOM_TO_STRING(cx->runtime->atomState. - typeAtoms[JSTYPE_VOID])); + value = ATOM_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); } else { value = vp[3]; vxml = VALUE_IS_XML(value) @@ -6195,7 +6252,7 @@ xml_replace(JSContext *cx, uintN argc, jsval *vp) if (!xml) return JS_FALSE; - if (argc == 0 || !js_IdIsIndex(vp[2], &index)) { + if (argc == 0 || !js_IdValIsIndex(vp[2], &index)) { /* * Call function QName per spec, not ToXMLName, to avoid attribute * names. @@ -6240,7 +6297,7 @@ xml_setChildren(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; *vp = argc != 0 ? vp[2] : JSVAL_VOID; /* local root */ - if (!PutProperty(cx, obj, ATOM_KEY(cx->runtime->atomState.starAtom), vp)) + if (!PutProperty(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.starAtom), vp)) return JS_FALSE; *vp = OBJECT_TO_JSVAL(obj); @@ -6296,8 +6353,7 @@ xml_setName(JSContext *cx, uintN argc, jsval *vp) return JS_TRUE; if (argc == 0) { - name = STRING_TO_JSVAL(ATOM_TO_STRING(cx->runtime->atomState. - typeAtoms[JSTYPE_VOID])); + name = ATOM_TO_JSVAL(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); } else { name = vp[2]; if (!JSVAL_IS_PRIMITIVE(name) && @@ -6307,7 +6363,7 @@ xml_setName(JSContext *cx, uintN argc, jsval *vp) } } - nameqn = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, &name); + nameqn = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, Valueify(&name)); if (!nameqn) return JS_FALSE; @@ -6407,7 +6463,7 @@ xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, - argc == 0 ? 0 : 1, vp + 2); + argc == 0 ? 0 : 1, Valueify(vp + 2)); if (!ns) return JS_FALSE; vp[0] = OBJECT_TO_JSVAL(ns); @@ -6415,7 +6471,7 @@ xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) qnargv[0] = vp[2] = OBJECT_TO_JSVAL(ns); qnargv[1] = OBJECT_TO_JSVAL(xml->name); - qn = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, qnargv); + qn = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, Valueify(qnargv)); if (!qn) return JS_FALSE; @@ -6467,7 +6523,7 @@ xml_text_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval *vp) ok = JS_FALSE; v = JSVAL_NULL; } - js_LeaveLocalRootScopeWithResult(cx, v); + js_LeaveLocalRootScopeWithResult(cx, Valueify(v)); if (!ok) return JS_FALSE; vxml = (JSXML *) JSVAL_TO_OBJECT(v)->getPrivate(); @@ -6525,7 +6581,7 @@ xml_toString_helper(JSContext *cx, JSXML *xml) break; } } - js_LeaveLocalRootScopeWithResult(cx, STRING_TO_JSVAL(str)); + js_LeaveLocalRootScopeWithResult(cx, str); return str; } @@ -6730,7 +6786,7 @@ XML(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) jsval v; JSXML *xml, *copy; JSObject *xobj, *vobj; - JSClass *clasp; + Class *clasp; v = argv[0]; if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) @@ -6865,9 +6921,9 @@ js_TraceXML(JSTracer *trc, JSXML *xml) if (xml->xml_targetprop) JS_CALL_OBJECT_TRACER(trc, xml->xml_targetprop, "targetprop"); } else { - js::TraceObjectVector(trc, - (JSObject **) xml->xml_namespaces.vector, - xml->xml_namespaces.length); + MarkObjectRange(trc, xml->xml_namespaces.length, + (JSObject **) xml->xml_namespaces.vector, + "xml_namespaces"); XMLArrayCursorTrace(trc, xml->xml_namespaces.cursors); if (IS_GC_MARKING_TRACER(trc)) xml->xml_namespaces.trim(); @@ -6942,32 +6998,32 @@ js_GetXMLObject(JSContext *cx, JSXML *xml) JSObject * js_InitNamespaceClass(JSContext *cx, JSObject *obj) { - return JS_InitClass(cx, obj, NULL, &js_NamespaceClass.base, Namespace, 2, + return js_InitClass(cx, obj, NULL, &js_NamespaceClass.base, Namespace, 2, namespace_props, namespace_methods, NULL, NULL); } JSObject * js_InitQNameClass(JSContext *cx, JSObject *obj) { - return JS_InitClass(cx, obj, NULL, &js_QNameClass.base, QName, 2, + return js_InitClass(cx, obj, NULL, &js_QNameClass.base, QName, 2, qname_props, qname_methods, NULL, NULL); } JSObject * js_InitAttributeNameClass(JSContext *cx, JSObject *obj) { - return JS_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2, + return js_InitClass(cx, obj, NULL, &js_AttributeNameClass, AttributeName, 2, qname_props, qname_methods, NULL, NULL); } JSObject * js_InitAnyNameClass(JSContext *cx, JSObject *obj) { - jsval v; + jsid id; - if (!js_GetAnyName(cx, &v)) + if (!js_GetAnyName(cx, &id)) return NULL; - return JSVAL_TO_OBJECT(v); + return JSID_TO_OBJECT(id); } JSObject * @@ -6985,7 +7041,7 @@ js_InitXMLClass(JSContext *cx, JSObject *obj) return NULL; /* Define the XML class constructor and prototype. */ - proto = JS_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1, + proto = js_InitClass(cx, obj, NULL, &js_XMLClass, Valueify(XML), 1, NULL, xml_methods, xml_static_props, xml_static_methods); if (!proto) @@ -7012,7 +7068,7 @@ js_InitXMLClass(JSContext *cx, JSObject *obj) JS_ASSERT(prop); sprop = (JSScopeProperty *) prop; JS_ASSERT(SPROP_HAS_VALID_SLOT(sprop, pobj->scope())); - cval = pobj->getSlotMT(cx, sprop->slot); + cval = Jsvalify(pobj->getSlotMT(cx, sprop->slot)); JS_UNLOCK_OBJ(cx, pobj); JS_ASSERT(VALUE_IS_FUNCTION(cx, cval)); @@ -7049,7 +7105,7 @@ js_InitXMLClasses(JSContext *cx, JSObject *obj) } JSBool -js_GetFunctionNamespace(JSContext *cx, jsval *vp) +js_GetFunctionNamespace(JSContext *cx, Value *vp) { JSRuntime *rt; JSObject *obj; @@ -7103,7 +7159,7 @@ js_GetFunctionNamespace(JSContext *cx, jsval *vp) } JS_UNLOCK_GC(rt); } - *vp = OBJECT_TO_JSVAL(obj); + vp->setObject(*obj); return JS_TRUE; } @@ -7133,10 +7189,10 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) obj = NULL; for (tmp = fp->scopeChain; tmp; tmp = tmp->getParent()) { - JSClass *clasp = tmp->getClass(); + Class *clasp = tmp->getClass(); if (clasp == &js_BlockClass || clasp == &js_WithClass) continue; - if (!tmp->getProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, &v)) + if (!tmp->getProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(&v))) return JS_FALSE; if (!JSVAL_IS_PRIMITIVE(v)) { *vp = v; @@ -7149,8 +7205,8 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) if (!ns) return JS_FALSE; v = OBJECT_TO_JSVAL(ns); - if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, v, JS_PropertyStub, JS_PropertyStub, - JSPROP_PERMANENT)) { + if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(v), + PropertyStub, PropertyStub, JSPROP_PERMANENT)) { return JS_FALSE; } *vp = v; @@ -7158,38 +7214,36 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) } JSBool -js_SetDefaultXMLNamespace(JSContext *cx, jsval v) +js_SetDefaultXMLNamespace(JSContext *cx, const Value &v) { - jsval argv[2]; + Value argv[2]; JSObject *ns, *varobj; JSStackFrame *fp; - argv[0] = STRING_TO_JSVAL(cx->runtime->emptyString); + argv[0].setString(cx->runtime->emptyString); argv[1] = v; ns = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, NULL, 2, argv); if (!ns) return JS_FALSE; - v = OBJECT_TO_JSVAL(ns); fp = js_GetTopStackFrame(cx); varobj = fp->varobj(cx); - if (!varobj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, v, - JS_PropertyStub, JS_PropertyStub, - JSPROP_PERMANENT)) { + if (!varobj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns), + PropertyStub, PropertyStub, JSPROP_PERMANENT)) { return JS_FALSE; } return JS_TRUE; } JSBool -js_ToAttributeName(JSContext *cx, jsval *vp) +js_ToAttributeName(JSContext *cx, Value *vp) { JSObject *qn; - qn = ToAttributeName(cx, *vp); + qn = ToAttributeName(cx, Jsvalify(*vp)); if (!qn) return JS_FALSE; - *vp = OBJECT_TO_JSVAL(qn); + vp->setObject(*qn); return JS_TRUE; } @@ -7252,21 +7306,21 @@ js_EscapeElementValue(JSContext *cx, JSString *str) } JSString * -js_ValueToXMLString(JSContext *cx, jsval v) +js_ValueToXMLString(JSContext *cx, const Value &v) { - return ToXMLString(cx, v, 0); + return ToXMLString(cx, Jsvalify(v), 0); } static JSBool anyname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - *rval = ATOM_KEY(cx->runtime->atomState.starAtom); + *rval = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); return JS_TRUE; } JSBool -js_GetAnyName(JSContext *cx, jsval *vp) +js_GetAnyName(JSContext *cx, jsid *idp) { JSRuntime *rt; JSObject *obj; @@ -7314,7 +7368,7 @@ js_GetAnyName(JSContext *cx, jsval *vp) JS_ASSERT(!obj->getParent()); } while (0); - js_LeaveLocalRootScopeWithResult(cx, OBJECT_TO_JSVAL(obj)); + js_LeaveLocalRootScopeWithResult(cx, obj); if (!ok) return JS_FALSE; @@ -7326,12 +7380,12 @@ js_GetAnyName(JSContext *cx, jsval *vp) } JS_UNLOCK_GC(rt); } - *vp = OBJECT_TO_JSVAL(obj); + *idp = OBJECT_TO_JSID(obj); return JS_TRUE; } JSBool -js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) +js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *idp) { JSObject *nameobj; jsval v; @@ -7343,12 +7397,12 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) JSProperty *prop; const char *printable; - JS_ASSERT(!JSVAL_IS_PRIMITIVE(nameval)); - nameobj = JSVAL_TO_OBJECT(nameval); + JS_ASSERT(nameval.isObject()); + nameobj = &nameval.toObject(); if (nameobj->getClass() == &js_AnyNameClass) { - v = STRING_TO_JSVAL(ATOM_TO_STRING(cx->runtime->atomState.starAtom)); + v = ATOM_TO_JSVAL(cx->runtime->atomState.starAtom); nameobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, - &v); + Valueify(&v)); if (!nameobj) return JS_FALSE; } else { @@ -7372,7 +7426,7 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) } if (target->isXML()) { - if (funid == 0) { + if (JSID_IS_VOID(funid)) { xml = (JSXML *) target->getPrivate(); found = HasNamedProperty(xml, qn); } else { @@ -7384,7 +7438,7 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) *objp = target; return JS_TRUE; } - } else if (funid != 0) { + } else if (!JSID_IS_VOID(funid)) { if (!target->lookupProperty(cx, funid, &pobj, &prop)) return JS_FALSE; if (prop) { @@ -7396,7 +7450,7 @@ js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp) } } while ((obj = obj->getParent()) != NULL); - printable = js_ValueToPrintableString(cx, OBJECT_TO_JSVAL(nameobj)); + printable = js_ValueToPrintableString(cx, ObjectValue(*nameobj)); if (printable) { JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage, NULL, @@ -7417,7 +7471,7 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) JSObject *target = obj; AutoObjectRooter tvr(cx); for (;;) { - if (!js_GetProperty(cx, target, id, vp)) + if (!js_GetProperty(cx, target, id, Valueify(vp))) return false; if (VALUE_IS_FUNCTION(cx, *vp)) return true; @@ -7436,7 +7490,7 @@ GetXMLFunction(JSContext *cx, JSObject *obj, jsid id, jsval *vp) return false; JS_ASSERT(tvr.object()); - return tvr.object()->getProperty(cx, id, vp); + return tvr.object()->getProperty(cx, id, Valueify(vp)); } static JSXML * @@ -7444,7 +7498,7 @@ GetPrivate(JSContext *cx, JSObject *obj, const char *method) { JSXML *xml; - xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, NULL); + xml = (JSXML *) GetInstancePrivate(cx, obj, &js_XMLClass, NULL); if (!xml) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_METHOD, @@ -7525,11 +7579,11 @@ xmlfilter_finalize(JSContext *cx, JSObject *obj) cx->destroy(filter); } -JSClass js_XMLFilterClass = { +Class js_XMLFilterClass = { "XMLFilter", JSCLASS_HAS_PRIVATE | JSCLASS_IS_ANONYMOUS | JSCLASS_MARK_IS_TRACE, - JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, - JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, xmlfilter_finalize, + PropertyStub, PropertyStub, PropertyStub, PropertyStub, + EnumerateStub, ResolveStub, ConvertStub, xmlfilter_finalize, NULL, NULL, NULL, NULL, NULL, NULL, JS_CLASS_TRACE(xmlfilter_trace), NULL }; @@ -7543,14 +7597,14 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized) JSXMLFilter *filter; LeaveTrace(cx); - sp = cx->regs->sp; + sp = Jsvalify(cx->regs->sp); if (!initialized) { /* * We haven't iterated yet, so initialize the filter based on the * value stored in sp[-2]. */ if (!VALUE_IS_XML(sp[-2])) { - js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, sp[-2], NULL); + js_ReportValueError(cx, JSMSG_NON_XML_FILTER, -2, Valueify(sp[-2]), NULL); return JS_FALSE; } obj = JSVAL_TO_OBJECT(sp[-2]); @@ -7603,7 +7657,7 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized) JS_ASSERT(filter->kid); /* Check if the filter expression wants to append the element. */ - if (js_ValueToBoolean(sp[-1]) && + if (js_ValueToBoolean(Valueify(sp[-1])) && !Append(cx, filter->result, filter->kid)) { return JS_FALSE; } @@ -7632,15 +7686,15 @@ js_StepXMLListFilter(JSContext *cx, JSBool initialized) } JSObject * -js_ValueToXMLObject(JSContext *cx, jsval v) +js_ValueToXMLObject(JSContext *cx, const Value &v) { - return ToXML(cx, v); + return ToXML(cx, Jsvalify(v)); } JSObject * -js_ValueToXMLListObject(JSContext *cx, jsval v) +js_ValueToXMLListObject(JSContext *cx, const Value &v) { - return ToXMLList(cx, v); + return ToXMLList(cx, Jsvalify(v)); } JSObject * diff --git a/js/src/jsxml.h b/js/src/jsxml.h index bfe5aa5778d5..4dfb3920728a 100644 --- a/js/src/jsxml.h +++ b/js/src/jsxml.h @@ -42,8 +42,6 @@ #include "jspubtd.h" #include "jsobj.h" -JS_BEGIN_EXTERN_C - extern const char js_AnyName_str[]; extern const char js_AttributeName_str[]; extern const char js_isXMLName_str[]; @@ -119,11 +117,8 @@ struct JSXMLArrayCursor #ifdef DEBUG size_t index = 0; #endif - for (JSXMLArrayCursor *cursor = this; cursor; cursor = cursor->next) { - void *root = cursor->root; - JS_SET_TRACING_INDEX(trc, "cursor_root", index++); - js_CallValueTracerIfGCThing(trc, jsval(root)); - } + for (JSXMLArrayCursor *cursor = this; cursor; cursor = cursor->next) + js::MarkGCThing(trc, cursor->root, "cursor_root", index++); } }; @@ -185,7 +180,7 @@ struct JSXML { } u; }; -JS_STATIC_ASSERT(sizeof(JSXML) % JSVAL_ALIGN == 0); +JS_STATIC_ASSERT(sizeof(JSXML) % JS_GCTHING_ALIGN == 0); /* union member shorthands */ #define xml_kids u.list.kids @@ -221,13 +216,13 @@ js_NewXMLObject(JSContext *cx, JSXMLClass xml_class); extern JSObject * js_GetXMLObject(JSContext *cx, JSXML *xml); -extern JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps; -extern JS_FRIEND_DATA(JSClass) js_XMLClass; -extern JS_FRIEND_DATA(JSExtendedClass) js_NamespaceClass; -extern JS_FRIEND_DATA(JSExtendedClass) js_QNameClass; -extern JS_FRIEND_DATA(JSClass) js_AttributeNameClass; -extern JS_FRIEND_DATA(JSClass) js_AnyNameClass; -extern JSClass js_XMLFilterClass; +extern JS_FRIEND_DATA(JSObjectOps) js_XMLObjectOps; +extern JS_FRIEND_DATA(js::Class) js_XMLClass; +extern JS_FRIEND_DATA(js::ExtendedClass) js_NamespaceClass; +extern JS_FRIEND_DATA(js::ExtendedClass) js_QNameClass; +extern JS_FRIEND_DATA(js::Class) js_AttributeNameClass; +extern JS_FRIEND_DATA(js::Class) js_AnyNameClass; +extern js::Class js_XMLFilterClass; /* * Methods to test whether an object or a value is of type "xml" (per typeof). @@ -249,12 +244,18 @@ JSObject::isNamespace() const inline bool JSObject::isQName() const { - JSClass* clasp = getClass(); + js::Class* clasp = getClass(); return clasp == &js_QNameClass.base || clasp == &js_AttributeNameClass || clasp == &js_AnyNameClass; } +static inline bool +IsXML(const js::Value &v) +{ + return v.isObject() && v.toObject().isXML(); +} + extern JSObject * js_InitNamespaceClass(JSContext *cx, JSObject *obj); @@ -274,11 +275,11 @@ extern JSObject * js_InitXMLClasses(JSContext *cx, JSObject *obj); extern JSBool -js_GetFunctionNamespace(JSContext *cx, jsval *vp); +js_GetFunctionNamespace(JSContext *cx, js::Value *vp); /* * If obj is QName corresponding to function::name, set *funidp to name's id, - * otherwise set *funidp to 0. + * otherwise set *funidp to void. */ JSBool js_IsFunctionQName(JSContext *cx, JSObject *obj, jsid *funidp); @@ -287,7 +288,7 @@ extern JSBool js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp); extern JSBool -js_SetDefaultXMLNamespace(JSContext *cx, jsval v); +js_SetDefaultXMLNamespace(JSContext *cx, const js::Value &v); /* * Return true if v is a XML QName object, or if it converts to a string that @@ -298,7 +299,7 @@ extern JSBool js_IsXMLName(JSContext *cx, jsval v); extern JSBool -js_ToAttributeName(JSContext *cx, jsval *vp); +js_ToAttributeName(JSContext *cx, js::Value *vp); extern JSString * js_EscapeAttributeValue(JSContext *cx, JSString *str, JSBool quote); @@ -311,22 +312,23 @@ extern JSString * js_EscapeElementValue(JSContext *cx, JSString *str); extern JSString * -js_ValueToXMLString(JSContext *cx, jsval v); +js_ValueToXMLString(JSContext *cx, const js::Value &v); extern JSObject * -js_ConstructXMLQNameObject(JSContext *cx, jsval nsval, jsval lnval); +js_ConstructXMLQNameObject(JSContext *cx, const js::Value & nsval, + const js::Value & lnval); extern JSBool -js_GetAnyName(JSContext *cx, jsval *vp); +js_GetAnyName(JSContext *cx, jsid *idp); /* * Note: nameval must be either QName, AttributeName, or AnyName. */ extern JSBool -js_FindXMLProperty(JSContext *cx, jsval nameval, JSObject **objp, jsid *idp); +js_FindXMLProperty(JSContext *cx, const js::Value &nameval, JSObject **objp, jsid *idp); extern JSBool -js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, jsval *vp); +js_GetXMLMethod(JSContext *cx, JSObject *obj, jsid id, js::Value *vp); extern JSBool js_GetXMLDescendants(JSContext *cx, JSObject *obj, jsval id, jsval *vp); @@ -338,10 +340,10 @@ extern JSBool js_StepXMLListFilter(JSContext *cx, JSBool initialized); extern JSObject * -js_ValueToXMLObject(JSContext *cx, jsval v); +js_ValueToXMLObject(JSContext *cx, const js::Value &v); extern JSObject * -js_ValueToXMLListObject(JSContext *cx, jsval v); +js_ValueToXMLListObject(JSContext *cx, const js::Value &v); extern JSObject * js_NewXMLSpecialObject(JSContext *cx, JSXMLClass xml_class, JSString *name, @@ -356,12 +358,12 @@ js_MakeXMLCommentString(JSContext *cx, JSString *str); extern JSString * js_MakeXMLPIString(JSContext *cx, JSString *name, JSString *str); +/* The caller must ensure that either v1 or v2 is an object. */ extern JSBool -js_TestXMLEquality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +js_TestXMLEquality(JSContext *cx, const js::Value &v1, const js::Value &v2, + JSBool *bp); extern JSBool -js_ConcatenateXML(JSContext *cx, JSObject *obj, jsval v, jsval *vp); - -JS_END_EXTERN_C +js_ConcatenateXML(JSContext *cx, JSObject *obj1, JSObject *obj2, js::Value *vp); #endif /* jsxml_h___ */ diff --git a/js/src/shell/Makefile.in b/js/src/shell/Makefile.in index 5d8bce33b72c..058b3b20a994 100644 --- a/js/src/shell/Makefile.in +++ b/js/src/shell/Makefile.in @@ -62,6 +62,12 @@ WIN32_EXE_LDFLAGS += -ENTRY:mainACRTStartup endif endif +ifeq ($(OS_ARCH),Darwin) +ifeq ($(TARGET_CPU),x86_64) +DARWIN_EXE_LDFLAGS += -pagezero_size 10000 -image_base 100000000 +endif +endif + include $(topsrcdir)/config/rules.mk ifdef MOZ_SHARK diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 5f53efbdc7ed..3cab7889ce51 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -38,6 +38,8 @@ * * ***** END LICENSE BLOCK ***** */ +#define __STDC_LIMIT_MACROS + /* * JS shell. */ @@ -89,6 +91,7 @@ #include "jsworkers.h" #include "jsobjinlines.h" +#include "jsscriptinlines.h" #ifdef XP_UNIX #include @@ -250,6 +253,13 @@ private: JSBool mThrow; }; +class IdToString : public ToString { +public: + IdToString(JSContext *cx, jsid id, JSBool aThrow = JS_FALSE) + : ToString(cx, IdToJsval(id), aThrow) + { } +}; + static char * GetLine(FILE *file, const char * prompt) { @@ -1294,7 +1304,6 @@ CountHeap(JSContext *cx, uintN argc, jsval *vp) } traceKindNames[] = { { "all", -1 }, { "object", JSTRACE_OBJECT }, - { "double", JSTRACE_DOUBLE }, { "string", JSTRACE_STRING }, #if JS_HAS_XML_SUPPORT { "xml", JSTRACE_XML }, @@ -1308,7 +1317,7 @@ CountHeap(JSContext *cx, uintN argc, jsval *vp) if (JSVAL_IS_TRACEABLE(v)) { startThing = JSVAL_TO_TRACEABLE(v); startTraceKind = JSVAL_TRACE_KIND(v); - } else if (v != JSVAL_NULL) { + } else if (!JSVAL_IS_NULL(v)) { JS_ReportError(cx, "the first argument is not null or a heap-allocated " "thing"); @@ -1382,9 +1391,9 @@ ValueToScript(JSContext *cx, jsval v) JSObject *obj = JSVAL_TO_OBJECT(v); JSClass *clasp = JS_GET_CLASS(cx, obj); - if (clasp == &js_ScriptClass) { + if (clasp == Jsvalify(&js_ScriptClass)) { script = (JSScript *) JS_GetPrivate(cx, obj); - } else if (clasp == &js_GeneratorClass.base) { + } else if (clasp == Jsvalify(&js_GeneratorClass.base)) { JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj); fun = gen->getFloatingFrame()->fun; script = FUN_SCRIPT(fun); @@ -1419,8 +1428,8 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp, v = argv[0]; intarg = 0; if (!JSVAL_IS_PRIMITIVE(v) && - (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass || - JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass)) { + (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&js_FunctionClass) || + JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&js_ScriptClass))) { script = ValueToScript(cx, v); if (!script) return JS_FALSE; @@ -1636,7 +1645,6 @@ SrcNotes(JSContext *cx, JSScript *script) case SRC_CONT2LABEL: index = js_GetSrcNoteOffset(sn, 0); JS_GET_SCRIPT_ATOM(script, NULL, index, atom); - JS_ASSERT(ATOM_IS_STRING(atom)); str = ATOM_TO_STRING(atom); fprintf(gOutFile, " atom %u (", index); js_FileEscapedString(gOutFile, str, 0); @@ -1853,6 +1861,9 @@ DisassFile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (!script) return JS_FALSE; + if (script->isEmpty()) + return JS_TRUE; + obj = JS_NewScriptObject(cx, script); if (!obj) return JS_FALSE; @@ -2020,7 +2031,7 @@ DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) jsid id; JSObject *obj2; JSProperty *prop; - jsval value; + Value value; for (i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); @@ -2046,12 +2057,12 @@ DumpStats(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (!obj->getProperty(cx, id, &value)) return JS_FALSE; } - if (!prop || !JSVAL_IS_OBJECT(value)) { + if (!prop || !value.isObjectOrNull()) { fprintf(gErrFile, "js: invalid stats argument %s\n", bytes); continue; } - obj = JSVAL_TO_OBJECT(value); + obj = value.toObjectOrNull(); if (obj) DumpScope(cx, obj, stdout); } @@ -2076,7 +2087,7 @@ DumpHeap(JSContext *cx, uintN argc, jsval *vp) fileName = NULL; if (argc > 0) { v = JS_ARGV(cx, vp)[0]; - if (v != JSVAL_NULL) { + if (!JSVAL_IS_NULL(v)) { JSString *str; str = JS_ValueToString(cx, v); @@ -2094,7 +2105,7 @@ DumpHeap(JSContext *cx, uintN argc, jsval *vp) if (JSVAL_IS_TRACEABLE(v)) { startThing = JSVAL_TO_TRACEABLE(v); startTraceKind = JSVAL_TRACE_KIND(v); - } else if (v != JSVAL_NULL) { + } else if (!JSVAL_IS_NULL(v)) { badTraceArg = "start"; goto not_traceable_arg; } @@ -2105,7 +2116,7 @@ DumpHeap(JSContext *cx, uintN argc, jsval *vp) v = JS_ARGV(cx, vp)[2]; if (JSVAL_IS_TRACEABLE(v)) { thingToFind = JSVAL_TO_TRACEABLE(v); - } else if (v != JSVAL_NULL) { + } else if (!JSVAL_IS_NULL(v)) { badTraceArg = "toFind"; goto not_traceable_arg; } @@ -2114,7 +2125,7 @@ DumpHeap(JSContext *cx, uintN argc, jsval *vp) maxDepth = (size_t)-1; if (argc > 3) { v = JS_ARGV(cx, vp)[3]; - if (v != JSVAL_NULL) { + if (!JSVAL_IS_NULL(v)) { uint32 depth; if (!JS_ValueToECMAUint32(cx, v, &depth)) @@ -2128,7 +2139,7 @@ DumpHeap(JSContext *cx, uintN argc, jsval *vp) v = JS_ARGV(cx, vp)[4]; if (JSVAL_IS_TRACEABLE(v)) { thingToIgnore = JSVAL_TO_TRACEABLE(v); - } else if (v != JSVAL_NULL) { + } else if (!JSVAL_IS_NULL(v)) { badTraceArg = "toIgnore"; goto not_traceable_arg; } @@ -2525,25 +2536,22 @@ static ComplexObject * split_get_private(JSContext *cx, JSObject *obj); static JSBool -split_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +split_addProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { ComplexObject *cpx; - jsid asId; cpx = split_get_private(cx, obj); if (!cpx) return JS_TRUE; if (!cpx->isInner && cpx->inner) { /* Make sure to define this property on the inner object. */ - if (!JS_ValueToId(cx, id, &asId)) - return JS_FALSE; - return JS_DefinePropertyById(cx, cpx->inner, asId, *vp, NULL, NULL, JSPROP_ENUMERATE); + return JS_DefinePropertyById(cx, cpx->inner, id, *vp, NULL, NULL, JSPROP_ENUMERATE); } return JS_TRUE; } static JSBool -split_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +split_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { ComplexObject *cpx; @@ -2551,22 +2559,22 @@ split_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) if (!cpx) return JS_TRUE; - if (JSVAL_IS_STRING(id) && - !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(id)), "isInner")) { + if (JSID_IS_ATOM(id) && + !strcmp(JS_GetStringBytes(JSID_TO_STRING(id)), "isInner")) { *vp = BOOLEAN_TO_JSVAL(cpx->isInner); return JS_TRUE; } if (!cpx->isInner && cpx->inner) { - if (JSVAL_IS_STRING(id)) { + if (JSID_IS_ATOM(id)) { JSString *str; - str = JSVAL_TO_STRING(id); + str = JSID_TO_STRING(id); return JS_GetUCProperty(cx, cpx->inner, JS_GetStringChars(str), JS_GetStringLength(str), vp); } - if (JSVAL_IS_INT(id)) - return JS_GetElement(cx, cpx->inner, JSVAL_TO_INT(id), vp); + if (JSID_IS_INT(id)) + return JS_GetElement(cx, cpx->inner, JSID_TO_INT(id), vp); return JS_TRUE; } @@ -2574,7 +2582,7 @@ split_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -split_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +split_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { ComplexObject *cpx; @@ -2582,15 +2590,15 @@ split_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) if (!cpx) return JS_TRUE; if (!cpx->isInner && cpx->inner) { - if (JSVAL_IS_STRING(id)) { + if (JSID_IS_ATOM(id)) { JSString *str; - str = JSVAL_TO_STRING(id); + str = JSID_TO_STRING(id); return JS_SetUCProperty(cx, cpx->inner, JS_GetStringChars(str), JS_GetStringLength(str), vp); } - if (JSVAL_IS_INT(id)) - return JS_SetElement(cx, cpx->inner, JSVAL_TO_INT(id), vp); + if (JSID_IS_INT(id)) + return JS_SetElement(cx, cpx->inner, JSID_TO_INT(id), vp); return JS_TRUE; } @@ -2598,7 +2606,7 @@ split_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -split_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +split_delProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { ComplexObject *cpx; jsid asId; @@ -2610,14 +2618,14 @@ split_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) /* Make sure to define this property on the inner object. */ if (!JS_ValueToId(cx, *vp, &asId)) return JS_FALSE; - return cpx->inner->deleteProperty(cx, asId, vp); + return cpx->inner->deleteProperty(cx, asId, Valueify(vp)); } return JS_TRUE; } static JSBool split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, - jsval *statep, jsid *idp) + jsval *statep, jsid *idp) { ComplexObject *cpx; JSObject *iterator; @@ -2636,7 +2644,7 @@ split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, *statep = OBJECT_TO_JSVAL(iterator); if (idp) - *idp = JSVAL_ZERO; + *idp = INT_TO_JSID(0); break; case JSENUMERATE_NEXT: @@ -2644,7 +2652,7 @@ split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, if (!JS_NextProperty(cx, iterator, idp)) return JS_FALSE; - if (!JSVAL_IS_VOID(*idp)) + if (!JSID_IS_VOID(*idp)) break; /* Fall through. */ @@ -2658,12 +2666,12 @@ split_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, } static JSBool -split_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp) +split_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { ComplexObject *cpx; - if (JSVAL_IS_STRING(id) && - !strcmp(JS_GetStringBytes(JSVAL_TO_STRING(id)), "isInner")) { + if (JSID_IS_ATOM(id) && + !strcmp(JS_GetStringBytes(JSID_TO_STRING(id)), "isInner")) { *objp = obj; return JS_DefineProperty(cx, obj, "isInner", JSVAL_VOID, NULL, NULL, JSPROP_SHARED); @@ -2673,13 +2681,9 @@ split_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **ob if (!cpx) return JS_TRUE; if (!cpx->isInner && cpx->inner) { - jsid asId; JSProperty *prop; - if (!JS_ValueToId(cx, id, &asId)) - return JS_FALSE; - - if (!cpx->inner->lookupProperty(cx, asId, objp, &prop)) + if (!cpx->inner->lookupProperty(cx, id, objp, &prop)) return JS_FALSE; if (prop) cpx->inner->dropProperty(cx, prop); @@ -2720,7 +2724,7 @@ split_mark(JSContext *cx, JSObject *obj, void *arg) if (!cpx->isInner && cpx->inner) { /* Mark the inner object. */ - JS_MarkGCThing(cx, cpx->inner, "ComplexObject.inner", arg); + JS_MarkGCThing(cx, OBJECT_TO_JSVAL(cpx->inner), "ComplexObject.inner", arg); } return 0; @@ -2760,7 +2764,7 @@ split_getObjectOps(JSContext *cx, JSClass *clasp) } static JSBool -split_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +split_equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); static JSObject * split_innerObject(JSContext *cx, JSObject *obj) @@ -2791,13 +2795,13 @@ static JSExtendedClass split_global_class = { }; static JSBool -split_equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +split_equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp) { *bp = JS_FALSE; - if (JSVAL_IS_PRIMITIVE(v)) + if (JSVAL_IS_PRIMITIVE(*v)) return JS_TRUE; - JSObject *obj2 = JSVAL_TO_OBJECT(v); + JSObject *obj2 = JSVAL_TO_OBJECT(*v); if (JS_GET_CLASS(cx, obj2) != &split_global_class.base) return JS_TRUE; @@ -2894,7 +2898,7 @@ sandbox_enumerate(JSContext *cx, JSObject *obj) } static JSBool -sandbox_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +sandbox_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { jsval v; @@ -2946,8 +2950,8 @@ NewSandbox(JSContext *cx, bool lazy, bool split) if (!lazy && !JS_InitStandardClasses(cx, obj)) return NULL; - AutoValueRooter root(cx, BOOLEAN_TO_JSVAL(lazy)); - if (!JS_SetProperty(cx, obj, "lazy", root.addr())) + AutoValueRooter root(cx, BooleanValue(lazy)); + if (!JS_SetProperty(cx, obj, "lazy", root.jsval_addr())) return NULL; if (split) @@ -3017,7 +3021,7 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return false; } } - return cx->compartment->wrap(cx, rval); + return cx->compartment->wrap(cx, Valueify(rval)); } static JSBool @@ -3035,7 +3039,7 @@ EvalInFrame(JSContext *cx, uintN argc, jsval *vp) JSString *str = JSVAL_TO_STRING(argv[1]); bool saveCurrent = (argc >= 3 && JSVAL_IS_BOOLEAN(argv[2])) - ? !!(JSVAL_TO_SPECIAL(argv[2])) + ? !!(JSVAL_TO_BOOLEAN(argv[2])) : false; JS_ASSERT(cx->fp); @@ -4181,7 +4185,7 @@ enum its_tinyid { }; static JSBool -its_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +its_getter(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { jsval *val = (jsval *) JS_GetPrivate(cx, obj); *vp = val ? *val : JSVAL_VOID; @@ -4189,7 +4193,7 @@ its_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -its_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +its_setter(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { jsval *val = (jsval *) JS_GetPrivate(cx, obj); if (val) { @@ -4304,12 +4308,12 @@ static JSBool its_noisy; /* whether to be noisy when finalizing it */ static JSBool its_enum_fail;/* whether to fail when enumerating it */ static JSBool -its_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +its_addProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { if (!its_noisy) return JS_TRUE; - ToString idString(cx, id); + IdToString idString(cx, id); fprintf(gOutFile, "adding its property %s,", idString.getBytes()); ToString valueString(cx, *vp); fprintf(gOutFile, " initial value %s\n", valueString.getBytes()); @@ -4317,12 +4321,12 @@ its_addProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -its_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +its_delProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { if (!its_noisy) return JS_TRUE; - ToString idString(cx, id); + IdToString idString(cx, id); fprintf(gOutFile, "deleting its property %s,", idString.getBytes()); ToString valueString(cx, *vp); fprintf(gOutFile, " initial value %s\n", valueString.getBytes()); @@ -4330,12 +4334,12 @@ its_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -its_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +its_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { if (!its_noisy) return JS_TRUE; - ToString idString(cx, id); + IdToString idString(cx, id); fprintf(gOutFile, "getting its property %s,", idString.getBytes()); ToString valueString(cx, *vp); fprintf(gOutFile, " initial value %s\n", valueString.getBytes()); @@ -4343,16 +4347,16 @@ its_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -its_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +its_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - ToString idString(cx, id); + IdToString idString(cx, id); if (its_noisy) { fprintf(gOutFile, "setting its property %s,", idString.getBytes()); ToString valueString(cx, *vp); fprintf(gOutFile, " new value %s\n", valueString.getBytes()); } - if (!JSVAL_IS_STRING(id)) + if (!JSID_IS_ATOM(id)) return JS_TRUE; if (!strcmp(idString.getBytes(), "noisy")) @@ -4385,7 +4389,7 @@ its_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, *statep = OBJECT_TO_JSVAL(iterator); if (idp) - *idp = JSVAL_ZERO; + *idp = INT_TO_JSID(0); break; case JSENUMERATE_NEXT: @@ -4398,7 +4402,7 @@ its_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, if (!JS_NextProperty(cx, iterator, idp)) return JS_FALSE; - if (!JSVAL_IS_VOID(*idp)) + if (!JSID_IS_VOID(*idp)) break; /* Fall through. */ @@ -4412,11 +4416,11 @@ its_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, } static JSBool -its_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +its_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { if (its_noisy) { - ToString idString(cx, id); + IdToString idString(cx, id); fprintf(gOutFile, "resolving its property %s, flags {%s,%s,%s}\n", idString.getBytes(), (flags & JSRESOLVE_QUALIFIED) ? "qualified" : "", @@ -4613,7 +4617,7 @@ global_enumerate(JSContext *cx, JSObject *obj) } static JSBool -global_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +global_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { #ifdef LAZY_STANDARD_CLASSES @@ -4689,13 +4693,13 @@ JSClass global_class = { }; static JSBool -env_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +env_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { /* XXX porting may be easy, but these don't seem to supply setenv by default */ #if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS int rv; - ToString idstr(cx, id, JS_TRUE); + IdToString idstr(cx, id, JS_TRUE); if (idstr.threw()) return JS_FALSE; ToString valstr(cx, *vp, JS_TRUE); @@ -4765,7 +4769,7 @@ env_enumerate(JSContext *cx, JSObject *obj) } static JSBool -env_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +env_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { JSString *valstr; @@ -4774,7 +4778,7 @@ env_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, if (flags & JSRESOLVE_ASSIGNING) return JS_TRUE; - ToString idstr(cx, id, JS_TRUE); + IdToString idstr(cx, id, JS_TRUE); if (idstr.threw()) return JS_FALSE; diff --git a/js/src/shell/jsworkers.cpp b/js/src/shell/jsworkers.cpp index 6c185ec57e6d..d6c754884d64 100644 --- a/js/src/shell/jsworkers.cpp +++ b/js/src/shell/jsworkers.cpp @@ -672,7 +672,7 @@ class Worker : public WorkerParent return !w->checkTermination(); } - static JSBool jsResolveGlobal(JSContext *cx, JSObject *obj, jsval id, uintN flags, + static JSBool jsResolveGlobal(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { JSBool resolved; @@ -870,7 +870,7 @@ class InitEvent : public Event return fail; AutoValueRooter rval(cx); - JSBool ok = JS_ExecuteScript(cx, child->getGlobal(), script, rval.addr()); + JSBool ok = JS_ExecuteScript(cx, child->getGlobal(), script, Jsvalify(rval.addr())); JS_DestroyScript(cx, script); return Result(ok); } @@ -907,7 +907,7 @@ class ErrorEvent : public Event JSString *data = NULL; jsval exc; if (JS_GetPendingException(cx, &exc)) { - AutoValueRooter tvr(cx, exc); + AutoValueRooter tvr(cx, Valueify(exc)); JS_ClearPendingException(cx); // Determine what error message to put in the error event. diff --git a/js/src/tests/ecma_3/Operators/jstests.list b/js/src/tests/ecma_3/Operators/jstests.list index 9f83014e4bf4..228b42dead49 100644 --- a/js/src/tests/ecma_3/Operators/jstests.list +++ b/js/src/tests/ecma_3/Operators/jstests.list @@ -3,4 +3,4 @@ script 11.13.1-001.js script 11.13.1-002.js script 11.4.1-001.js script 11.4.1-002.js -fails script order-01.js +script order-01.js diff --git a/js/src/tests/js1_5/GC/regress-348532.js b/js/src/tests/js1_5/GC/regress-348532.js index 93d398892c6c..e4e96388737d 100644 --- a/js/src/tests/js1_5/GC/regress-348532.js +++ b/js/src/tests/js1_5/GC/regress-348532.js @@ -63,14 +63,18 @@ function test() var recursionDepth = 0; function err() { - if (++recursionDepth == 128) - return new Error(); - return err.apply(this, arguments); + try { + return err.apply(this, arguments); + } catch (e) { + if (!(e instanceof InternalError)) + throw e; + } + return new Error(); } - // The full stack trace in error would include 128*2 copies of s exceeding + // The full stack trace in error would include 64*4 copies of s exceeding // 2^23 * 256 or 2^31 in length - var error = err(s,s); + var error = err(s,s,s,s); print(error.stack.length); diff --git a/js/src/trace-test/tests/basic/bug569651.js b/js/src/trace-test/tests/basic/bug569651.js new file mode 100644 index 000000000000..58f9c136267a --- /dev/null +++ b/js/src/trace-test/tests/basic/bug569651.js @@ -0,0 +1,3 @@ +// don't crash or assert + ++Function("switch(\"\"){case 1:case 8:}"); \ No newline at end of file diff --git a/js/src/trace-test/tests/basic/bug572229.js b/js/src/trace-test/tests/basic/bug572229.js new file mode 100644 index 000000000000..c45cea0b6c19 --- /dev/null +++ b/js/src/trace-test/tests/basic/bug572229.js @@ -0,0 +1,12 @@ +// Don't crash + +function f(o, s) { + var k = s.substr(0, 1); + var c; + for (var i = 0; i < 10; ++i) { + c = k in o; + } + return c; +} + +assertEq(f({ a: 66 }, 'abc'), true); diff --git a/js/src/trace-test/tests/basic/testIteratorReification.js b/js/src/trace-test/tests/basic/testIteratorReification.js new file mode 100644 index 000000000000..8f89672bb2b6 --- /dev/null +++ b/js/src/trace-test/tests/basic/testIteratorReification.js @@ -0,0 +1 @@ +for (b in evalcx('')) {} diff --git a/js/src/trace-test/tests/basic/testSuppressDeletedProperty.js b/js/src/trace-test/tests/basic/testSuppressDeletedProperty.js new file mode 100644 index 000000000000..a867b35d2445 --- /dev/null +++ b/js/src/trace-test/tests/basic/testSuppressDeletedProperty.js @@ -0,0 +1,8 @@ +var obj = { a:1, b:1, c:1, d:1, e:1, f:1, g:1 }; +var sum = 0; +for each (var i in obj) { + sum += i; + delete obj.f; +} + +// this isn't even implemented to work yet; just don't crash or iloop diff --git a/js/src/xpconnect/idl/nsIXPCScriptable.idl b/js/src/xpconnect/idl/nsIXPCScriptable.idl index e35e68398694..575749ac0c64 100644 --- a/js/src/xpconnect/idl/nsIXPCScriptable.idl +++ b/js/src/xpconnect/idl/nsIXPCScriptable.idl @@ -135,23 +135,23 @@ interface nsIXPCScriptable : nsISupports in JSContextPtr cx, in JSObjectPtr obj); PRBool addProperty(in nsIXPConnectWrappedNative wrapper, - in JSContextPtr cx, in JSObjectPtr obj, in jsval id, + in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in JSValPtr vp); PRBool delProperty(in nsIXPConnectWrappedNative wrapper, - in JSContextPtr cx, in JSObjectPtr obj, in jsval id, + in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in JSValPtr vp); // The returnCode should be set to NS_SUCCESS_I_DID_SOMETHING if // this method does something. PRBool getProperty(in nsIXPConnectWrappedNative wrapper, - in JSContextPtr cx, in JSObjectPtr obj, in jsval id, + in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in JSValPtr vp); // The returnCode should be set to NS_SUCCESS_I_DID_SOMETHING if // this method does something. PRBool setProperty(in nsIXPConnectWrappedNative wrapper, - in JSContextPtr cx, in JSObjectPtr obj, in jsval id, + in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in JSValPtr vp); PRBool enumerate(in nsIXPConnectWrappedNative wrapper, @@ -159,10 +159,10 @@ interface nsIXPCScriptable : nsISupports PRBool newEnumerate(in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, - in PRUint32 enum_op, in JSValPtr statep, out JSID idp); + in PRUint32 enum_op, in JSValPtr statep, out jsid idp); PRBool newResolve(in nsIXPConnectWrappedNative wrapper, - in JSContextPtr cx, in JSObjectPtr obj, in jsval id, + in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in PRUint32 flags, out JSObjectPtr objp); PRBool convert(in nsIXPConnectWrappedNative wrapper, @@ -173,7 +173,7 @@ interface nsIXPCScriptable : nsISupports in JSContextPtr cx, in JSObjectPtr obj); PRBool checkAccess(in nsIXPConnectWrappedNative wrapper, - in JSContextPtr cx, in JSObjectPtr obj, in jsval id, + in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in PRUint32 mode, in JSValPtr vp); PRBool call(in nsIXPConnectWrappedNative wrapper, diff --git a/js/src/xpconnect/idl/nsIXPCSecurityManager.idl b/js/src/xpconnect/idl/nsIXPCSecurityManager.idl index e2f0a563184e..54fece50137a 100644 --- a/js/src/xpconnect/idl/nsIXPCSecurityManager.idl +++ b/js/src/xpconnect/idl/nsIXPCSecurityManager.idl @@ -108,6 +108,6 @@ interface nsIXPCSecurityManager : nsISupports in JSObjectPtr aJSObject, in nsISupports aObj, in nsIClassInfo aClassInfo, - in jsval aName, + in jsid aName, inout voidPtr aPolicy); }; diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index dc248d64860d..f384ec58d858 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -59,15 +59,15 @@ /***************************************************************************/ -// NB: jsval is declared in nsIVariant.idl +// NB: jsval and jsid are declared in nsIVariant.idl [ptr] native JSContextPtr(JSContext); [ptr] native JSClassPtr(JSClass); [ptr] native JSObjectPtr(JSObject); [ptr] native JSValPtr(jsval); +[ptr] native JSValConstPtr(const jsval); native JSPropertyOp(JSPropertyOp); native JSEqualityOp(JSEqualityOp); - native JSID(jsid); [ptr] native voidPtrPtr(void*); [ptr] native nsScriptObjectTracerPtr(nsScriptObjectTracer); [ref] native nsCCTraversalCallbackRef(nsCycleCollectionTraversalCallback); @@ -180,8 +180,8 @@ interface nsIXPConnectWrappedNative : nsIXPConnectJSObjectHolder */ readonly attribute nsIXPConnect XPConnect; - nsIInterfaceInfo FindInterfaceWithMember(in jsval nameID); - nsIInterfaceInfo FindInterfaceWithName(in jsval nameID); + nsIInterfaceInfo FindInterfaceWithMember(in jsid nameID); + nsIInterfaceInfo FindInterfaceWithName(in jsid nameID); void debugDump(in short depth); diff --git a/js/src/xpconnect/loader/mozJSComponentLoader.cpp b/js/src/xpconnect/loader/mozJSComponentLoader.cpp index f396e8572bc3..f131abad4e60 100644 --- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp @@ -1625,7 +1625,7 @@ mozJSComponentLoader::Import(const nsACString & registryLocation) jsval *retval = nsnull; cc->GetRetValPtr(&retval); - if (*retval) + if (retval) *retval = OBJECT_TO_JSVAL(globalObj); return rv; diff --git a/js/src/xpconnect/public/nsAutoJSValHolder.h b/js/src/xpconnect/public/nsAutoJSValHolder.h index 164fad27647b..e8553374a56e 100644 --- a/js/src/xpconnect/public/nsAutoJSValHolder.h +++ b/js/src/xpconnect/public/nsAutoJSValHolder.h @@ -149,7 +149,7 @@ public: nsAutoJSValHolder &operator=(jsval aOther) { #ifdef DEBUG - if (aOther) { + if (JSVAL_IS_OBJECT(aOther) && JSVAL_TO_OBJECT(aOther)) { NS_ASSERTION(mHeld, "Not rooted!"); } #endif diff --git a/js/src/xpconnect/public/xpc_map_end.h b/js/src/xpconnect/public/xpc_map_end.h index 5bb4af0537d6..5d4e65792aaf 100644 --- a/js/src/xpconnect/public/xpc_map_end.h +++ b/js/src/xpconnect/public/xpc_map_end.h @@ -148,22 +148,22 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::PostCreate(nsIXPConnectWrappedNative *wrapper, #endif #ifndef XPC_MAP_WANT_ADDPROPERTY -NS_IMETHODIMP XPC_MAP_CLASSNAME::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsval id, jsval * vp, PRBool *_retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, PRBool *_retval) {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif #ifndef XPC_MAP_WANT_DELPROPERTY -NS_IMETHODIMP XPC_MAP_CLASSNAME::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsval id, jsval * vp, PRBool *_retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, PRBool *_retval) {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif #ifndef XPC_MAP_WANT_GETPROPERTY -NS_IMETHODIMP XPC_MAP_CLASSNAME::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsval id, jsval * vp, PRBool *_retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, PRBool *_retval) {NS_WARNING("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif #ifndef XPC_MAP_WANT_SETPROPERTY -NS_IMETHODIMP XPC_MAP_CLASSNAME::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsval id, jsval * vp, PRBool *_retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, jsval * vp, PRBool *_retval) {NS_WARNING("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif @@ -178,7 +178,7 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::Enumerate(nsIXPConnectWrappedNative *wrapper, J #endif #ifndef XPC_MAP_WANT_NEWRESOLVE -NS_IMETHODIMP XPC_MAP_CLASSNAME::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsval id, PRUint32 flags, JSObject * *objp, PRBool *_retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif @@ -193,7 +193,7 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::Finalize(nsIXPConnectWrappedNative *wrapper, JS #endif #ifndef XPC_MAP_WANT_CHECKACCESS -NS_IMETHODIMP XPC_MAP_CLASSNAME::CheckAccess(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsval id, PRUint32 mode, jsval * vp, PRBool *_retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::CheckAccess(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsid id, PRUint32 mode, jsval * vp, PRBool *_retval) {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif @@ -208,7 +208,7 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::Construct(nsIXPConnectWrappedNative *wrapper, J #endif #ifndef XPC_MAP_WANT_HASINSTANCE -NS_IMETHODIMP XPC_MAP_CLASSNAME::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsval val, PRBool *bp, PRBool *_retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, const jsval &val, PRBool *bp, PRBool *_retval) {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif @@ -218,7 +218,7 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::Trace(nsIXPConnectWrappedNative *wrapper, JSTra #endif #ifndef XPC_MAP_WANT_EQUALITY -NS_IMETHODIMP XPC_MAP_CLASSNAME::Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, jsval val, PRBool *bp) +NS_IMETHODIMP XPC_MAP_CLASSNAME::Equality(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, const jsval &val, PRBool *bp) {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif diff --git a/js/src/xpconnect/shell/xpcshell.cpp b/js/src/xpconnect/shell/xpcshell.cpp index 4ec95ce0ef99..ac01e8faebdd 100644 --- a/js/src/xpconnect/shell/xpcshell.cpp +++ b/js/src/xpconnect/shell/xpcshell.cpp @@ -156,7 +156,7 @@ JSPrincipals *gJSPrincipals = nsnull; nsAutoString *gWorkingDirectory = nsnull; static JSBool -GetLocationProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +GetLocationProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { #if (!defined(XP_WIN) && !defined(XP_UNIX)) || defined(WINCE) //XXX: your platform should really implement this @@ -870,7 +870,7 @@ JSClass global_class = { }; static JSBool -env_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +env_setProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { /* XXX porting may be easy, but these don't seem to supply setenv by default */ #if !defined XP_BEOS && !defined XP_OS2 && !defined SOLARIS @@ -878,7 +878,11 @@ env_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) const char *name, *value; int rv; - idstr = JS_ValueToString(cx, id); + jsval idval; + if (!JS_IdToValue(cx, id, &idval)) + return JS_FALSE; + + idstr = JS_ValueToString(cx, idval); valstr = JS_ValueToString(cx, *vp); if (!idstr || !valstr) return JS_FALSE; @@ -949,7 +953,7 @@ env_enumerate(JSContext *cx, JSObject *obj) } static JSBool -env_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +env_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { JSString *idstr, *valstr; @@ -958,7 +962,11 @@ env_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, if (flags & JSRESOLVE_ASSIGNING) return JS_TRUE; - idstr = JS_ValueToString(cx, id); + jsval idval; + if (!JS_IdToValue(cx, id, &idval)) + return JS_FALSE; + + idstr = JS_ValueToString(cx, idval); if (!idstr) return JS_FALSE; name = JS_GetStringBytes(idstr); @@ -1381,17 +1389,17 @@ FullTrustSecMan::CanAccess(PRUint32 aAction, nsAXPCNativeCallContext *aCallContext, JSContext * aJSContext, JSObject * aJSObject, nsISupports *aObj, nsIClassInfo *aClassInfo, - jsval aName, void * *aPolicy) + jsid aName, void * *aPolicy) { return NS_OK; } -/* [noscript] void checkPropertyAccess (in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in string aClassName, in jsval aProperty, in PRUint32 aAction); */ +/* [noscript] void checkPropertyAccess (in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in string aClassName, in jsid aProperty, in PRUint32 aAction); */ NS_IMETHODIMP FullTrustSecMan::CheckPropertyAccess(JSContext * aJSContext, JSObject * aJSObject, const char *aClassName, - jsval aProperty, PRUint32 aAction) + jsid aProperty, PRUint32 aAction) { return NS_OK; } diff --git a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp index 45876ba74dc1..03748271bfe7 100644 --- a/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCChromeObjectWrapper.cpp @@ -210,33 +210,33 @@ CanTouchProperty(JSContext *cx, JSObject *wrapperObj, jsid id, JSBool isSet, } static JSBool -XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_COW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_COW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_COW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_COW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_COW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_COW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool XPC_COW_Enumerate(JSContext *cx, JSObject *obj); static JSBool -XPC_COW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_COW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static JSBool XPC_COW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp); static JSBool -XPC_COW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, JSAccessMode mode, +XPC_COW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp); static JSBool -XPC_COW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_COW_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp); static JSObject * XPC_COW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly); @@ -290,16 +290,16 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) *vp = OBJECT_TO_JSVAL(wrapperObj); - js::AutoValueRooter exposedProps(cx, JSVAL_VOID); + js::AutoValueRooter exposedProps(cx); - if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), exposedProps.addr())) { + if (!GetExposedProperties(cx, JSVAL_TO_OBJECT(v), exposedProps.jsval_addr())) { return JS_FALSE; } if (!JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperObj, XPCWrapper::sFlagsSlot, JSVAL_ZERO) || !JS_SetReservedSlot(cx, wrapperObj, sExposedPropsSlot, - exposedProps.value())) { + exposedProps.jsval_value())) { return JS_FALSE; } @@ -323,7 +323,7 @@ ThrowException(nsresult rv, JSContext *cx) static inline JSObject * GetWrappedJSObject(JSContext *cx, JSObject *obj) { - JSClass *clasp = obj->getClass(); + JSClass *clasp = obj->getJSClass(); if (!(clasp->flags & JSCLASS_IS_EXTENDED)) { return obj; } @@ -347,7 +347,7 @@ static inline JSObject * GetWrapper(JSObject *obj) { - while (obj->getClass() != &COWClass.base) { + while (obj->getJSClass() != &COWClass.base) { obj = obj->getProto(); if (!obj) { break; @@ -473,17 +473,17 @@ RewrapForContent(JSContext *cx, JSObject *wrapperObj, jsval *vp) } static JSBool -CheckSOW(JSContext *cx, JSObject *wrapperObj, jsval idval) +CheckSOW(JSContext *cx, JSObject *wrapperObj, jsid id) { jsval flags; JS_GetReservedSlot(cx, wrapperObj, sFlagsSlot, &flags); return HAS_FLAGS(flags, FLAG_SOW) - ? SystemOnlyWrapper::AllowedToAct(cx, idval) : JS_TRUE; + ? SystemOnlyWrapper::AllowedToAct(cx, id) : JS_TRUE; } static JSBool -XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { obj = GetWrapper(obj); jsval flags; @@ -507,11 +507,9 @@ XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } - jsid interned_id; JSPropertyDescriptor desc; - if (!JS_ValueToId(cx, id, &interned_id) || - !XPCWrapper::GetPropertyAttrs(cx, obj, interned_id, JSRESOLVE_QUALIFIED, + if (!XPCWrapper::GetPropertyAttrs(cx, obj, id, JSRESOLVE_QUALIFIED, JS_TRUE, &desc)) { return JS_FALSE; } @@ -527,12 +525,12 @@ XPC_COW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } return RewrapForChrome(cx, obj, vp) && - JS_DefinePropertyById(cx, wrappedObj, interned_id, *vp, + JS_DefinePropertyById(cx, wrappedObj, id, *vp, desc.getter, desc.setter, desc.attrs); } static JSBool -XPC_COW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_COW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { if (!CheckSOW(cx, obj, id)) { return JS_FALSE; @@ -549,9 +547,7 @@ XPC_COW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } JSBool canTouch; - jsid interned_id; - if (!JS_ValueToId(cx, id, &interned_id) || - !CanTouchProperty(cx, obj, interned_id, JS_TRUE, &canTouch)) { + if (!CanTouchProperty(cx, obj, id, JS_TRUE, &canTouch)) { return JS_FALSE; } @@ -564,7 +560,7 @@ XPC_COW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -XPC_COW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, +XPC_COW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSBool isSet) { obj = GetWrapper(obj); @@ -588,19 +584,14 @@ XPC_COW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } - jsid interned_id; - if (!JS_ValueToId(cx, id, &interned_id)) { - return JS_FALSE; - } - - if (interned_id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTO) || - interned_id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTO) || + id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS)) { // No getting or setting __proto__ on my object. return ThrowException(NS_ERROR_INVALID_ARG, cx); // XXX better error message } JSBool canTouch; - if (!CanTouchProperty(cx, obj, interned_id, isSet, &canTouch)) { + if (!CanTouchProperty(cx, obj, id, isSet, &canTouch)) { return JS_FALSE; } @@ -612,9 +603,8 @@ XPC_COW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return JS_FALSE; } - JSBool ok = isSet - ? JS_SetPropertyById(cx, wrappedObj, interned_id, vp) - : JS_GetPropertyById(cx, wrappedObj, interned_id, vp); + JSBool ok = isSet ? JS_SetPropertyById(cx, wrappedObj, id, vp) + : JS_GetPropertyById(cx, wrappedObj, id, vp); if (!ok) { return JS_FALSE; } @@ -623,13 +613,13 @@ XPC_COW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } static JSBool -XPC_COW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_COW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_COW_GetOrSetProperty(cx, obj, id, vp, JS_FALSE); } static JSBool -XPC_COW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_COW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_COW_GetOrSetProperty(cx, obj, id, vp, JS_TRUE); } @@ -644,7 +634,7 @@ XPC_COW_Enumerate(JSContext *cx, JSObject *obj) return JS_TRUE; } - if (!CheckSOW(cx, obj, JSVAL_VOID)) { + if (!CheckSOW(cx, obj, JSID_VOID)) { return JS_FALSE; } @@ -657,12 +647,12 @@ XPC_COW_Enumerate(JSContext *cx, JSObject *obj) } static JSBool -XPC_COW_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, +XPC_COW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { obj = GetWrapper(obj); - if (!CheckSOW(cx, obj, idval)) { + if (!CheckSOW(cx, obj, id)) { return JS_FALSE; } @@ -678,10 +668,8 @@ XPC_COW_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, return ThrowException(NS_ERROR_FAILURE, cx); } - jsid id; JSBool canTouch; - if (!JS_ValueToId(cx, idval, &id) || - !CanTouchProperty(cx, obj, id, (flags & JSRESOLVE_ASSIGNING) != 0, + if (!CanTouchProperty(cx, obj, id, (flags & JSRESOLVE_ASSIGNING) != 0, &canTouch)) { return JS_FALSE; } @@ -716,7 +704,7 @@ XPC_COW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) return ThrowException(NS_ERROR_FAILURE, cx); } - if (!wrappedObj->getClass()->convert(cx, wrappedObj, type, vp)) { + if (!wrappedObj->getJSClass()->convert(cx, wrappedObj, type, vp)) { return JS_FALSE; } @@ -724,28 +712,26 @@ XPC_COW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) } static JSBool -XPC_COW_CheckAccess(JSContext *cx, JSObject *obj, jsval prop, JSAccessMode mode, +XPC_COW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp) { // Simply forward checkAccess to our wrapped object. It's already expecting // untrusted things to ask it about accesses. uintN junk; - jsid id; - return JS_ValueToId(cx, prop, &id) && - JS_CheckAccess(cx, GetWrappedObject(cx, obj), id, mode, vp, &junk); + return JS_CheckAccess(cx, GetWrappedObject(cx, obj), id, mode, vp, &junk); } static JSBool -XPC_COW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_COW_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { // Convert both sides to XPCWrappedNative and see if they match. - if (JSVAL_IS_PRIMITIVE(v)) { + if (JSVAL_IS_PRIMITIVE(*valp)) { *bp = JS_FALSE; return JS_TRUE; } - JSObject *test = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(v)); + JSObject *test = GetWrappedJSObject(cx, JSVAL_TO_OBJECT(*valp)); obj = GetWrappedObject(cx, obj); if (!obj) { @@ -761,8 +747,9 @@ XPC_COW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); obj = me->GetFlatJSObject(); test = other->GetFlatJSObject(); - return ((JSExtendedClass *)obj->getClass())-> - equality(cx, obj, OBJECT_TO_JSVAL(test), bp); + jsval testVal = OBJECT_TO_JSVAL(test); + return ((JSExtendedClass *)obj->getJSClass())-> + equality(cx, obj, &testVal, bp); } static JSObject * diff --git a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp index 2bac5f370d88..3ebbfb444832 100644 --- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp +++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp @@ -49,22 +49,22 @@ // accessed safely from across origins. static JSBool -XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_XOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_XOW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_XOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_XOW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_XOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_XOW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool XPC_XOW_Enumerate(JSContext *cx, JSObject *obj); static JSBool -XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static JSBool @@ -74,7 +74,7 @@ static void XPC_XOW_Finalize(JSContext *cx, JSObject *obj); static JSBool -XPC_XOW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, JSAccessMode mode, +XPC_XOW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp); static JSBool @@ -85,10 +85,10 @@ XPC_XOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool -XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); static JSBool -XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_XOW_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); static JSObject * XPC_XOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly); @@ -125,7 +125,7 @@ static inline JSObject * GetWrapper(JSObject *obj) { - while (obj->getClass() != &XPCCrossOriginWrapper::XOWClass.base) { + while (obj->getJSClass() != &XPCCrossOriginWrapper::XOWClass.base) { obj = obj->getProto(); if (!obj) { break; @@ -376,7 +376,7 @@ RewrapIfNeeded(JSContext *cx, JSObject *outerObj, jsval *vp) } XPCWrappedNative *wn = nsnull; - if (obj->getClass() == &XOWClass.base && + if (obj->getJSClass() == &XOWClass.base && outerObj->getParent() != obj->getParent()) { *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, obj)); } else if (!(wn = XPCWrappedNative::GetAndMorphWrappedNativeOfJSObject(cx, obj))) { @@ -397,7 +397,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn) JSObject *wrappedObj; if (JSVAL_IS_PRIMITIVE(*vp) || !(wrappedObj = JSVAL_TO_OBJECT(*vp)) || - wrappedObj->getClass() == &XOWClass.base) { + wrappedObj->getJSClass() == &XOWClass.base) { return JS_TRUE; } @@ -445,7 +445,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval *vp, XPCWrappedNative* wn) outerObj = map->Find(wrappedObj); if (outerObj) { - NS_ASSERTION(outerObj->getClass() == &XOWClass.base, + NS_ASSERTION(outerObj->getJSClass() == &XOWClass.base, "What crazy object are we getting here?"); *vp = OBJECT_TO_JSVAL(outerObj); @@ -491,7 +491,7 @@ XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool -IsValFrame(JSObject *obj, jsval v, XPCWrappedNative *wn) +IsValFrame(JSObject *obj, jsid id, XPCWrappedNative *wn) { // Fast path for the common case. if (obj->getClass()->name[0] != 'W') { @@ -509,11 +509,11 @@ IsValFrame(JSObject *obj, jsval v, XPCWrappedNative *wn) return JS_FALSE; } - if (JSVAL_IS_INT(v)) { - col->Item(JSVAL_TO_INT(v), getter_AddRefs(domwin)); + if (JSID_IS_INT(id)) { + col->Item(JSID_TO_INT(id), getter_AddRefs(domwin)); } else { nsAutoString str(reinterpret_cast - (JS_GetStringChars(JSVAL_TO_STRING(v)))); + (JS_GetStringChars(JSID_TO_STRING(id)))); col->NamedItem(str, getter_AddRefs(domwin)); } @@ -590,7 +590,7 @@ WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp) } JSObject *wrappedObj = JSVAL_TO_OBJECT(*vp); - JSClass *clasp = wrappedObj->getClass(); + JSClass *clasp = wrappedObj->getJSClass(); if (ClassNeedsXOW(clasp->name)) { return WrapObject(cx, JS_GetGlobalForObject(cx, outerObj), vp); } @@ -607,7 +607,7 @@ WrapSameOriginProp(JSContext *cx, JSObject *outerObj, jsval *vp) } static JSBool -XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { // All AddProperty needs to do is pass on addProperty requests to // same-origin objects, and throw for all else. @@ -620,7 +620,7 @@ XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) if (!JSVAL_IS_PRIMITIVE(*vp)) { JSObject *addedObj = JSVAL_TO_OBJECT(*vp); - if (addedObj->getClass() == &XOWClass.base && + if (addedObj->getJSClass() == &XOWClass.base && addedObj->getParent() != obj->getParent()) { *vp = OBJECT_TO_JSVAL(GetWrappedObject(cx, addedObj)); if (!WrapObject(cx, obj->getParent(), vp, nsnull)) { @@ -654,7 +654,7 @@ XPC_XOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -XPC_XOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_XOW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { @@ -675,10 +675,10 @@ XPC_XOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, +XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSBool isSet) { - if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { return JS_TRUE; } @@ -746,22 +746,14 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, JSObject *proto = nsnull; // Initialize this to quiet GCC. JSBool checkProto = - (isSet && id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTO)); + (isSet && id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTO)); if (checkProto) { proto = wrappedObj->getProto(); } - // Same origin, pass this request along as though nothing interesting - // happened. - jsid asId; - - if (!JS_ValueToId(cx, id, &asId)) { - return JS_FALSE; - } - JSBool ok = isSet - ? JS_SetPropertyById(cx, wrappedObj, asId, vp) - : JS_GetPropertyById(cx, wrappedObj, asId, vp); + ? JS_SetPropertyById(cx, wrappedObj, id, vp) + : JS_GetPropertyById(cx, wrappedObj, id, vp); if (!ok) { return JS_FALSE; } @@ -798,13 +790,13 @@ XPC_XOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } static JSBool -XPC_XOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_XOW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_XOW_GetOrSetProperty(cx, obj, id, vp, JS_FALSE); } static JSBool -XPC_XOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_XOW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_XOW_GetOrSetProperty(cx, obj, id, vp, JS_TRUE); } @@ -850,7 +842,7 @@ XPC_XOW_Enumerate(JSContext *cx, JSObject *obj) static JSObject * GetUXPCObject(JSContext *cx, JSObject *obj) { - NS_ASSERTION(obj->getClass() == &XOWClass.base, "wrong object"); + NS_ASSERTION(obj->getJSClass() == &XOWClass.base, "wrong object"); jsval v; if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &v)) { @@ -875,7 +867,7 @@ GetUXPCObject(JSContext *cx, JSObject *obj) return nsnull; } - js::AutoValueRooter tvr(cx, uxpco); + js::AutoObjectRooter tvr(cx, uxpco); jsval wrappedObj, parentScope; if (!JS_GetReservedSlot(cx, obj, sWrappedObjSlot, &wrappedObj) || @@ -898,7 +890,7 @@ GetUXPCObject(JSContext *cx, JSObject *obj) } static JSBool -XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { obj = GetWrapper(obj); @@ -958,7 +950,7 @@ XPC_XOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, return JS_FALSE; } - if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { jsval oldSlotVal; if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &oldSlotVal) || !JS_SetReservedSlot(cx, obj, sFlagsSlot, @@ -1020,7 +1012,7 @@ XPC_XOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) return JS_FALSE; } - if (!wrappedObj->getClass()->convert(cx, wrappedObj, type, vp)) { + if (!wrappedObj->getJSClass()->convert(cx, wrappedObj, type, vp)) { return JS_FALSE; } @@ -1068,16 +1060,14 @@ XPC_XOW_Finalize(JSContext *cx, JSObject *obj) } static JSBool -XPC_XOW_CheckAccess(JSContext *cx, JSObject *obj, jsval prop, JSAccessMode mode, +XPC_XOW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp) { // Simply forward checkAccess to our wrapped object. It's already expecting // untrusted things to ask it about accesses. uintN junk; - jsid id; - return JS_ValueToId(cx, prop, &id) && - JS_CheckAccess(cx, GetWrappedObject(cx, obj), id, mode, vp, &junk); + return JS_CheckAccess(cx, GetWrappedObject(cx, obj), id, mode, vp, &junk); } static JSBool @@ -1139,7 +1129,7 @@ XPC_XOW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { JSObject *iface = GetWrappedObject(cx, obj); @@ -1157,7 +1147,7 @@ XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) return JS_FALSE; } - JSClass *clasp = iface->getClass(); + JSClass *clasp = iface->getJSClass(); *bp = JS_FALSE; if (!clasp->hasInstance) { @@ -1165,7 +1155,8 @@ XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) } // Prematurely unwrap the left hand side. - if (!JSVAL_IS_PRIMITIVE(v)) { + jsval v = *valp; + if (!JSVAL_IS_PRIMITIVE(*valp)) { JSObject *test = JSVAL_TO_OBJECT(v); // GetWrappedObject does an instanceof check. @@ -1175,12 +1166,14 @@ XPC_XOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) } } - return clasp->hasInstance(cx, iface, v, bp); + return clasp->hasInstance(cx, iface, &v, bp); } static JSBool -XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_XOW_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { + jsval v = *valp; + // Convert both sides to XPCWrappedNative and see if they match. if (JSVAL_IS_PRIMITIVE(v)) { *bp = JS_FALSE; @@ -1188,7 +1181,7 @@ XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) } JSObject *test = JSVAL_TO_OBJECT(v); - if (test->getClass() == &XOWClass.base) { + if (test->getJSClass() == &XOWClass.base) { if (!JS_GetReservedSlot(cx, test, sWrappedObjSlot, &v)) { return JS_FALSE; } @@ -1215,8 +1208,9 @@ XPC_XOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) XPCWrappedNative *me = XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj); obj = me->GetFlatJSObject(); test = other->GetFlatJSObject(); - return ((JSExtendedClass *)obj->getClass())-> - equality(cx, obj, OBJECT_TO_JSVAL(test), bp); + jsval testVal = OBJECT_TO_JSVAL(test); + return ((JSExtendedClass *)obj->getJSClass())-> + equality(cx, obj, &testVal, bp); } static JSObject * @@ -1307,7 +1301,7 @@ XPC_XOW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } rv = ssm->CheckPropertyAccess(cx, wrappedObj, wrappedObj->getClass()->name, - GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING), + GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING), nsIXPCSecurityManager::ACCESS_GET_PROPERTY); } if (NS_FAILED(rv)) { diff --git a/js/src/xpconnect/src/XPCDispConvert.cpp b/js/src/xpconnect/src/XPCDispConvert.cpp index 87b9464b1e06..726eb0de802d 100644 --- a/js/src/xpconnect/src/XPCDispConvert.cpp +++ b/js/src/xpconnect/src/XPCDispConvert.cpp @@ -309,7 +309,7 @@ JSBool XPCDispConvert::JSToCOM(XPCCallContext& ccx, case VT_R8: { varDest->vt = VT_R8; - varDest->dblVal = *JSVAL_TO_DOUBLE(src); + varDest->dblVal = JSVAL_TO_DOUBLE(src); } break; case VT_EMPTY: diff --git a/js/src/xpconnect/src/XPCDispInlines.h b/js/src/xpconnect/src/XPCDispInlines.h index 191068a76194..02fe287f7e7f 100644 --- a/js/src/xpconnect/src/XPCDispInlines.h +++ b/js/src/xpconnect/src/XPCDispInlines.h @@ -211,13 +211,13 @@ PRBool XPCDispInterface::Member::IsParameterizedProperty() const } inline -jsval XPCDispInterface::Member::GetName() const +jsid XPCDispInterface::Member::GetName() const { return mName; } inline -void XPCDispInterface::Member::SetName(jsval name) +void XPCDispInterface::Member::SetName(jsid name) { mName = name; } @@ -310,7 +310,7 @@ void XPCDispInterface::SetJSObject(JSObject* jsobj) } inline -const XPCDispInterface::Member* XPCDispInterface::FindMember(jsval name) const +const XPCDispInterface::Member* XPCDispInterface::FindMember(jsid name) const { // Iterate backwards to save time const Member* member = mMembers + mMemberCount; @@ -635,17 +635,16 @@ jschar * xpc_JSString2String(JSContext * cx, jsval val, PRUint32 * len = 0) } /** - * Converts a jsval that is a string to a PRUnichar * + * Converts a JSString * to a PRUnichar * * @param cx a JS context - * @param val the JS value to vbe converted + * @param str the JSString to be converted * @param length optional pointer to a variable to hold the length * @return a PRUnichar buffer (Does not need to be freed) */ inline -PRUnichar* xpc_JSString2PRUnichar(XPCCallContext& ccx, jsval val, +PRUnichar* xpc_JSString2PRUnichar(XPCCallContext& ccx, JSString* str, size_t* length = nsnull) { - JSString* str = JS_ValueToString(ccx, val); if(!str) return nsnull; if(length) diff --git a/js/src/xpconnect/src/XPCDispInterface.cpp b/js/src/xpconnect/src/XPCDispInterface.cpp index da4847f09f62..b047e04fb207 100644 --- a/js/src/xpconnect/src/XPCDispInterface.cpp +++ b/js/src/xpconnect/src/XPCDispInterface.cpp @@ -190,7 +190,7 @@ PRBool InitializeMember(JSContext * cx, ITypeInfo * pTypeInfo, pInfo = new (pInfo) XPCDispInterface::Member; if(!pInfo) return PR_FALSE; - pInfo->SetName(STRING_TO_JSVAL(str)); + pInfo->SetName(INTERNED_STRING_TO_JSID(str)); pInfo->ResetType(); ConvertInvokeKind(pFuncDesc->invkind, *pInfo); pInfo->SetTypeInfo(pFuncDesc->memid, pTypeInfo, pFuncDesc); @@ -283,25 +283,25 @@ PRBool XPCDispInterface::InspectIDispatch(JSContext * cx, ITypeInfo * pTypeInfo, * @param ccx an XPConnect call context * @param lhr the PRUnichar string to be compared * @param lhsLength the length of the PRUnichar string - * @param rhs the JS value that is the other string to compare + * @param rhs the jsid that is the other string to compare * @return true if the strings are equal */ inline -PRBool CaseInsensitiveCompare(XPCCallContext& ccx, const PRUnichar* lhs, size_t lhsLength, jsval rhs) +PRBool CaseInsensitiveCompare(XPCCallContext& ccx, const PRUnichar* lhs, size_t lhsLength, jsid rhs) { if(lhsLength == 0) return PR_FALSE; size_t rhsLength; - PRUnichar* rhsString = xpc_JSString2PRUnichar(ccx, rhs, &rhsLength); + PRUnichar* rhsString = xpc_JSString2PRUnichar(ccx, JSID_TO_STRING(rhs), &rhsLength); return rhsString && lhsLength == rhsLength && _wcsnicmp(lhs, rhsString, lhsLength) == 0; } -const XPCDispInterface::Member* XPCDispInterface::FindMemberCI(XPCCallContext& ccx, jsval name) const +const XPCDispInterface::Member* XPCDispInterface::FindMemberCI(XPCCallContext& ccx, jsid name) const { size_t nameLength; - PRUnichar* sName = xpc_JSString2PRUnichar(ccx, name, &nameLength); + PRUnichar* sName = xpc_JSString2PRUnichar(ccx, JSID_TO_STRING(name), &nameLength); if(!sName) return nsnull; // Iterate backwards over the members array (more efficient) @@ -357,7 +357,7 @@ JSBool XPCDispInterface::Member::GetValue(XPCCallContext& ccx, } JSFunction *fun = JS_NewFunction(cx, callback, argc, flags, nsnull, - JS_GetStringBytes(JSVAL_TO_STRING(mName))); + JS_GetStringBytes(JSID_TO_STRING(mName))); if(!fun) return JS_FALSE; @@ -366,7 +366,7 @@ JSBool XPCDispInterface::Member::GetValue(XPCCallContext& ccx, return JS_FALSE; // Store ourselves and our native interface within the JSObject - if(!JS_SetReservedSlot(ccx, funobj, 0, PRIVATE_TO_JSVAL(this))) + if(!JS_SetReservedSlot(ccx, funobj, 0, PRIVATE_TO_JSVAL((void *) this))) return JS_FALSE; if(!JS_SetReservedSlot(ccx, funobj, 1, PRIVATE_TO_JSVAL(iface))) diff --git a/js/src/xpconnect/src/XPCDispObject.cpp b/js/src/xpconnect/src/XPCDispObject.cpp index f55dc6c6915f..a91ac25c85bb 100644 --- a/js/src/xpconnect/src/XPCDispObject.cpp +++ b/js/src/xpconnect/src/XPCDispObject.cpp @@ -308,7 +308,7 @@ JSBool XPCDispObject::Invoke(XPCCallContext & ccx, CallMode mode) NS_ERROR("bad value"); return JS_FALSE; } - jsval name = member->GetName(); + jsid name = member->GetName(); nsIXPCSecurityManager* sm = xpcc->GetAppropriateSecurityManager(secFlag); XPCWrappedNative* wrapper = ccx.GetWrapper(); @@ -400,12 +400,12 @@ JSBool GetMember(XPCCallContext& ccx, JSObject* funobj, XPCNativeInterface*& ifa jsval val; if(!JS_GetReservedSlot(ccx, funobj, 1, &val)) return JS_FALSE; - if(!JSVAL_IS_INT(val)) + if(!JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(val)) return JS_FALSE; iface = reinterpret_cast(JSVAL_TO_PRIVATE(val)); if(!JS_GetReservedSlot(ccx, funobj, 0, &val)) return JS_FALSE; - if(!JSVAL_IS_INT(val)) + if(!JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(val)) return JS_FALSE; member = reinterpret_cast(JSVAL_TO_PRIVATE(val)); return JS_TRUE; @@ -443,7 +443,7 @@ XPC_IDispatch_CallMethod(JSContext* cx, JSObject* obj, uintN argc, { NS_ASSERTION(JS_TypeOfValue(cx, argv[-2]) == JSTYPE_FUNCTION, "bad function"); JSObject* funobj = JSVAL_TO_OBJECT(argv[-2]); - XPCCallContext ccx(JS_CALLER, cx, obj, funobj, 0, argc, argv, vp); + XPCCallContext ccx(JS_CALLER, cx, obj, funobj, INT_TO_JSID(0), argc, argv, vp); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); ccx.SetArgsAndResultPtr(argc, argv, vp); diff --git a/js/src/xpconnect/src/XPCDispPrivate.h b/js/src/xpconnect/src/XPCDispPrivate.h index e82fb19785b0..15800b121c4f 100644 --- a/js/src/xpconnect/src/XPCDispPrivate.h +++ b/js/src/xpconnect/src/XPCDispPrivate.h @@ -786,10 +786,10 @@ public: */ PRBool IsFunction() const; /** - * Returns the name of the method as a jsval - * @return the name of the method as a jsval + * Returns the name of the method as a jsid + * @return the name of the method as a jsid */ - jsval GetName() const; + jsid GetName() const; /** * Returns the function object as a value for the method * @param ccx an XPConnect call context @@ -822,7 +822,7 @@ public: * Sets the name of the method * @param name the name to assign */ - void SetName(jsval name); + void SetName(jsid name); /** * Marks the member as a getter. * Both MakeGetter and MakeSetter can be called, making it a setter/getter @@ -881,7 +881,7 @@ public: }; PRUint16 mType; jsval mVal; // Mutable - jsval mName; // Mutable + jsid mName; // Mutable CComPtr mTypeInfo; FUNCDESC* mFuncDesc; // We own this FUNCDESC* mGetterFuncDesc; // We own this @@ -915,7 +915,7 @@ public: * @param name the name of the member to be returned * @return pointer to the member found, nsnull if not found */ - const Member * FindMember(jsval name) const; + const Member * FindMember(jsid name) const; /** * Looksup a member ignoring case * TODO: We should look at performance issues concerning this @@ -923,7 +923,7 @@ public: * @param name The name of the member * @return A pointer to a member or nsnull if not found */ - const Member* FindMemberCI(XPCCallContext& ccx, jsval name) const; + const Member* FindMemberCI(XPCCallContext& ccx, jsid name) const; /** * Returns a member via index * @param index the index of the parameter @@ -1150,7 +1150,7 @@ public: * @param resolved a pointer to a JSBool, set to true if properly resolved */ static JSBool DefineProperty(XPCCallContext & ccx, - JSObject *obj, jsval idval, + JSObject *obj, jsid id, XPCWrappedNative* wrapperToReflectInterfaceNames, uintN propFlags, JSBool* resolved); /** diff --git a/js/src/xpconnect/src/XPCDispTearOff.cpp b/js/src/xpconnect/src/XPCDispTearOff.cpp index 60d38ed23787..ad93a2ab7022 100644 --- a/js/src/xpconnect/src/XPCDispTearOff.cpp +++ b/js/src/xpconnect/src/XPCDispTearOff.cpp @@ -386,7 +386,7 @@ STDMETHODIMP XPCDispatchTearOff::Invoke(DISPID dispIdMember, REFIID riid, goto pre_call_clean_up; } - sp = stackbase = args.getvp(); + sp = stackbase = Jsvalify(args.getvp()); // this is a function call, so push function and 'this' *sp++ = fval; @@ -441,7 +441,7 @@ pre_call_clean_up: if(!JSVAL_IS_PRIMITIVE(fval)) { - success = js_Invoke(cx, args, 0); + success = js::InvokeFriendAPI(cx, args, 0); result = stackbase[0]; } else diff --git a/js/src/xpconnect/src/XPCDispTypeInfo.cpp b/js/src/xpconnect/src/XPCDispTypeInfo.cpp index 2a2f9de43910..f573bb1ecd21 100644 --- a/js/src/xpconnect/src/XPCDispTypeInfo.cpp +++ b/js/src/xpconnect/src/XPCDispTypeInfo.cpp @@ -347,7 +347,7 @@ STDMETHODIMP XPCDispTypeInfo::GetDocumentation( return E_FAIL; XPCCallContext ccx(NATIVE_CALLER); - PRUnichar * chars = xpc_JSString2PRUnichar(ccx, mIDArray->Item(ccx, index)); + PRUnichar * chars = xpc_JSString2PRUnichar(ccx, JSVAL_TO_STRING(mIDArray->Item(ccx, index))); if(!chars) { return E_FAIL; diff --git a/js/src/xpconnect/src/XPCIDispatchExtension.cpp b/js/src/xpconnect/src/XPCIDispatchExtension.cpp index 22d5d294bf98..a75644258f24 100644 --- a/js/src/xpconnect/src/XPCIDispatchExtension.cpp +++ b/js/src/xpconnect/src/XPCIDispatchExtension.cpp @@ -43,12 +43,10 @@ static const char* const IDISPATCH_NAME = "IDispatch"; PRBool XPCIDispatchExtension::mIsEnabled = PR_TRUE; JSBool XPCIDispatchExtension::DefineProperty(XPCCallContext & ccx, - JSObject *obj, jsval idval, + JSObject *obj, jsid id, XPCWrappedNative* wrapperToReflectInterfaceNames, uintN propFlags, JSBool* resolved) { - if(!JSVAL_IS_STRING(idval)) - return JS_FALSE; // Look up the native interface for IDispatch and then find a tearoff XPCNativeInterface* iface = XPCNativeInterface::GetNewOrUsed(ccx, "IDispatch"); @@ -61,14 +59,14 @@ JSBool XPCIDispatchExtension::DefineProperty(XPCCallContext & ccx, if(to == nsnull) return JS_FALSE; // Look up the member in the interface - const XPCDispInterface::Member * member = to->GetIDispatchInfo()->FindMember(idval); + const XPCDispInterface::Member * member = to->GetIDispatchInfo()->FindMember(id); if(!member) { // IDispatch is case insensitive, so if we don't find a case sensitive // match, we'll try a more expensive case-insensisitive search // TODO: We need to create cleaner solution that doesn't create // multiple properties of different case on the JS Object - member = to->GetIDispatchInfo()->FindMemberCI(ccx, idval); + member = to->GetIDispatchInfo()->FindMemberCI(ccx, id); if(!member) return JS_FALSE; } @@ -82,16 +80,14 @@ JSBool XPCIDispatchExtension::DefineProperty(XPCCallContext & ccx, JSObject* funobj = xpc_CloneJSFunction(ccx, JSVAL_TO_OBJECT(funval), obj); if(!funobj) return JS_FALSE; - jsid id; // If this is a function or a parameterized property if(member->IsFunction() || member->IsParameterizedProperty()) { // define the function on the object - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; - return JS_ValueToId(ccx, idval, &id) && - JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(funobj), + return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(funobj), nsnull, nsnull, propFlags); } // Define the property on the object @@ -109,11 +105,10 @@ JSBool XPCIDispatchExtension::DefineProperty(XPCCallContext & ccx, { setter = js_GetterOnlyPropertyStub; } - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; - return JS_ValueToId(ccx, idval, &id) && - JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, getter, setter, + return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, getter, setter, propFlags); } @@ -140,7 +135,7 @@ JSBool XPCIDispatchExtension::Enumerate(XPCCallContext& ccx, JSObject* obj, for(PRUint32 index = 0; index < members; ++index) { const XPCDispInterface::Member & member = pInfo->GetMember(index); - jsval name = member.GetName(); + jsid name = member.GetName(); if(!xpc_ForcePropertyResolve(ccx, obj, name)) return JS_FALSE; } diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index d7608dc98f52..67eb6d5030d6 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -44,22 +44,22 @@ #include "jsdbgapi.h" static JSBool -XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_NW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_NW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_NW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_NW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_NW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_NW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool XPC_NW_Enumerate(JSContext *cx, JSObject *obj); static JSBool -XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static JSBool @@ -69,7 +69,7 @@ static void XPC_NW_Finalize(JSContext *cx, JSObject *obj); static JSBool -XPC_NW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, +XPC_NW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp); static JSBool @@ -81,13 +81,13 @@ XPC_NW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool -XPC_NW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_NW_HasInstance(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp); static void XPC_NW_Trace(JSTracer *trc, JSObject *obj); static JSBool -XPC_NW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_NW_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp); static JSObject * XPC_NW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly); @@ -289,7 +289,7 @@ ThrowException(nsresult ex, JSContext *cx) static inline JSBool EnsureLegalActivity(JSContext *cx, JSObject *obj, - jsval id = JSVAL_VOID, PRUint32 accessType = 0) + jsid id = JSID_VOID, PRUint32 accessType = 0) { nsIScriptSecurityManager *ssm = GetSecurityManager(); if (!ssm) { @@ -336,7 +336,7 @@ EnsureLegalActivity(JSContext *cx, JSObject *obj, } JSObject* flatObj; - if (!JSVAL_IS_VOID(id) && + if (!JSID_IS_VOID(id) && (accessType & (sSecMgrSetProp | sSecMgrGetProp)) && (flatObj = wn->GetFlatJSObject())) { rv = ssm->CheckPropertyAccess(cx, flatObj, @@ -383,13 +383,11 @@ EnsureLegalActivity(JSContext *cx, JSObject *obj, } static JSBool -XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - jsid idAsId; JSPropertyDescriptor desc; - if (!JS_ValueToId(cx, id, &idAsId) || - !JS_GetPropertyDescriptorById(cx, obj, idAsId, JSRESOLVE_QUALIFIED, + if (!JS_GetPropertyDescriptorById(cx, obj, id, JSRESOLVE_QUALIFIED, &desc)) { return JS_FALSE; } @@ -416,7 +414,7 @@ XPC_NW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -XPC_NW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_NW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return EnsureLegalActivity(cx, obj); } @@ -496,12 +494,12 @@ GetwrappedJSObject(JSContext *cx, JSObject *obj, jsval *vp) } static JSBool -XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, +XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSBool aIsSet) { // We don't deal with the following properties here. - if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE) || - id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTOTYPE) || + id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { return JS_TRUE; } @@ -527,7 +525,7 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, JSObject *nativeObj = wrappedNative->GetFlatJSObject(); if (!aIsSet && - id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) { + id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) { return GetwrappedJSObject(cx, nativeObj, vp); } @@ -536,13 +534,13 @@ XPC_NW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } static JSBool -XPC_NW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_NW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_NW_GetOrSetProperty(cx, obj, id, vp, PR_FALSE); } static JSBool -XPC_NW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_NW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_NW_GetOrSetProperty(cx, obj, id, vp, PR_TRUE); } @@ -570,18 +568,18 @@ XPC_NW_Enumerate(JSContext *cx, JSObject *obj) } static JSBool -XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_NW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { // No need to preserve on sets of wrappedJSObject or toString, since callers // couldn't get at those values anyway. Also, we always deal with // wrappedJSObject and toString before looking at our scriptable hooks, so no // need to mess with our flags yet. - if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) { return JS_TRUE; } - if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { *objp = obj; // See the comment in WrapFunction for why we create this function @@ -646,7 +644,7 @@ XPC_NW_Finalize(JSContext *cx, JSObject *obj) } static JSBool -XPC_NW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, +XPC_NW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp) { // Prevent setting __proto__ on an XPCNativeWrapper @@ -669,7 +667,7 @@ XPC_NW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, JSObject *wrapperJSObject = wrappedNative->GetFlatJSObject(); - JSClass *clazz = wrapperJSObject->getClass(); + JSClass *clazz = wrapperJSObject->getJSClass(); return !clazz->checkAccess || clazz->checkAccess(cx, wrapperJSObject, id, mode, vp); } @@ -731,7 +729,7 @@ XPC_NW_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -XPC_NW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_NW_HasInstance(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { return JS_TRUE; } @@ -886,7 +884,7 @@ XPC_NW_Trace(JSTracer *trc, JSObject *obj) } static JSBool -XPC_NW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_NW_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { NS_ASSERTION(XPCNativeWrapper::IsNativeWrapper(obj), "Uh, we should only ever be called for XPCNativeWrapper " @@ -896,6 +894,7 @@ XPC_NW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) return JS_FALSE; } + jsval v = *valp; if (JSVAL_IS_PRIMITIVE(v)) { *bp = JS_FALSE; @@ -965,7 +964,7 @@ XPC_NW_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } if (!EnsureLegalActivity(cx, obj, - GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING), + GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING), sSecMgrGetProp)) { return JS_FALSE; } diff --git a/js/src/xpconnect/src/XPCNativeWrapper.h b/js/src/xpconnect/src/XPCNativeWrapper.h index 851c7acbb3fb..9c5ff2b654d3 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.h +++ b/js/src/xpconnect/src/XPCNativeWrapper.h @@ -68,7 +68,7 @@ IsNativeWrapperClass(JSClass *clazz) inline PRBool IsNativeWrapper(JSObject *obj) { - return IsNativeWrapperClass(obj->getClass()); + return IsNativeWrapperClass(obj->getJSClass()); } JSBool diff --git a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp index 3fb7fab9a765..d7fe3c8e1ae2 100644 --- a/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp +++ b/js/src/xpconnect/src/XPCSafeJSObjectWrapper.cpp @@ -45,22 +45,22 @@ #include "nsJSPrincipals.h" static JSBool -XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_SJOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_SJOW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_SJOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_SJOW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool XPC_SJOW_Enumerate(JSContext *cx, JSObject *obj); static JSBool -XPC_SJOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_SJOW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static JSBool @@ -70,7 +70,7 @@ static void XPC_SJOW_Finalize(JSContext *cx, JSObject *obj); static JSBool -XPC_SJOW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, JSAccessMode mode, +XPC_SJOW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp); static JSBool @@ -86,7 +86,7 @@ XPC_SJOW_Create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); static JSBool -XPC_SJOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_SJOW_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); static JSObject * XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly); @@ -179,7 +179,7 @@ CanCallerAccess(JSContext *cx, JSObject *wrapperObj, JSObject *unsafeObj) jsval flags; JS_GetReservedSlot(cx, wrapperObj, sFlagsSlot, &flags); if (HAS_FLAGS(flags, FLAG_SOW) && - !SystemOnlyWrapper::CheckFilename(cx, JSVAL_VOID, fp)) { + !SystemOnlyWrapper::CheckFilename(cx, JSID_VOID, fp)) { return JS_FALSE; } } @@ -233,7 +233,7 @@ FindObjectPrincipals(JSContext *cx, JSObject *safeObj, JSObject *innerObj) static inline JSObject * FindSafeObject(JSObject *obj) { - while (obj->getClass() != &SJOWClass.base) { + while (obj->getJSClass() != &SJOWClass.base) { obj = obj->getProto(); if (!obj) { @@ -446,7 +446,7 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval) // parent we pass in here, the construct hook will ensure we get // the right parent for the wrapper. JSObject *safeObj = JSVAL_TO_OBJECT(*rval); - if (safeObj->getClass() == &SJOWClass.base && + if (safeObj->getJSClass() == &SJOWClass.base && JS_GetGlobalForObject(cx, obj) != JS_GetGlobalForObject(cx, safeObj)) { // Check to see if the new object we just wrapped is accessible // from the unsafe object we got the new object through. If not, @@ -510,12 +510,12 @@ WrapJSValue(JSContext *cx, JSObject *obj, jsval val, jsval *rval) } static JSBool -XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { // The constructor and toString properties needs to live on the safe // wrapper. - if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR) || - id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR) || + id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { return JS_TRUE; } @@ -555,7 +555,7 @@ XPC_SJOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_SJOW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { JSObject *unsafeObj = GetUnsafeObject(cx, obj); if (!unsafeObj) { @@ -613,17 +613,17 @@ public: private: JSContext *cx; JSRegExpStatics statics; - js::AutoValueRooter tvr; + js::AutoStringRooter tvr; uint32 options; JSStackFrame *fp; }; static JSBool -XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, +XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSBool aIsSet) { // We resolve toString to a function in our resolve hook. - if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { return JS_TRUE; } @@ -652,11 +652,6 @@ XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return JS_FALSE; } - jsid interned_id; - if (!JS_ValueToId(cx, id, &interned_id)) { - return JS_FALSE; - } - if (aIsSet && !JSVAL_IS_PRIMITIVE(*vp) && !RewrapObject(cx, JS_GetGlobalForObject(cx, unsafeObj), @@ -665,10 +660,8 @@ XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } JSBool ok = aIsSet - ? js_SetPropertyByIdWithFakeFrame(cx, unsafeObj, scopeFun, - interned_id, vp) - : js_GetPropertyByIdWithFakeFrame(cx, unsafeObj, scopeFun, - interned_id, vp); + ? js_SetPropertyByIdWithFakeFrame(cx, unsafeObj, scopeFun, id, vp) + : js_GetPropertyByIdWithFakeFrame(cx, unsafeObj, scopeFun, id, vp); if (!ok) { return JS_FALSE; } @@ -678,13 +671,13 @@ XPC_SJOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } static JSBool -XPC_SJOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_SJOW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_SJOW_GetOrSetProperty(cx, obj, id, vp, PR_FALSE); } static JSBool -XPC_SJOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_SJOW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_SJOW_GetOrSetProperty(cx, obj, id, vp, PR_TRUE); } @@ -722,7 +715,7 @@ XPC_SJOW_Enumerate(JSContext *cx, JSObject *obj) } static JSBool -XPC_SJOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_SJOW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { obj = FindSafeObject(obj); @@ -742,7 +735,7 @@ XPC_SJOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, } // Resolve toString specially. - if (id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_TO_STRING)) { *objp = obj; return JS_DefineFunction(cx, obj, "toString", XPC_SJOW_toString, 0, 0) != nsnull; @@ -772,7 +765,7 @@ XPC_SJOW_Finalize(JSContext *cx, JSObject *obj) } static JSBool -XPC_SJOW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, +XPC_SJOW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp) { // Prevent setting __proto__ on an XPCSafeJSObjectWrapper @@ -799,7 +792,7 @@ XPC_SJOW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, return JS_FALSE; } - JSClass *clazz = unsafeObj->getClass(); + JSClass *clazz = unsafeObj->getJSClass(); return !clazz->checkAccess || clazz->checkAccess(cx, unsafeObj, id, mode, vp); } @@ -986,14 +979,14 @@ XPC_SJOW_Create(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -XPC_SJOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_SJOW_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { - if (JSVAL_IS_PRIMITIVE(v)) { + if (JSVAL_IS_PRIMITIVE(*valp)) { *bp = JS_FALSE; } else { JSObject *unsafeObj = GetUnsafeObject(cx, obj); - JSObject *other = JSVAL_TO_OBJECT(v); + JSObject *other = JSVAL_TO_OBJECT(*valp); JSObject *otherUnsafe = GetUnsafeObject(cx, other); // An object is equal to a SJOW if: @@ -1050,7 +1043,7 @@ XPC_SJOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoObjectRooter tvr(cx, wrapperIter); // Initialize the wrapper. return XPCWrapper::CreateIteratorObj(cx, wrapperIter, obj, unsafeObj, diff --git a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp index 2aca022ff880..279c6153c18a 100644 --- a/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp +++ b/js/src/xpconnect/src/XPCSystemOnlyWrapper.cpp @@ -48,36 +48,36 @@ // be safely injected into untrusted code. static JSBool -XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_SOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_SOW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_SOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_SOW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -XPC_SOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +XPC_SOW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool XPC_SOW_Enumerate(JSContext *cx, JSObject *obj); static JSBool -XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static JSBool XPC_SOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp); static JSBool -XPC_SOW_CheckAccess(JSContext *cx, JSObject *obj, jsval id, JSAccessMode mode, +XPC_SOW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp); static JSBool -XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp); static JSBool -XPC_SOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_SOW_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp); static JSObject * XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly); @@ -139,7 +139,7 @@ WrapObject(JSContext *cx, JSObject *parent, jsval v, jsval *vp) } *vp = OBJECT_TO_JSVAL(wrapperObj); - js::AutoValueRooter tvr(cx, *vp); + js::AutoObjectRooter tvr(cx, wrapperObj); if (!JS_SetReservedSlot(cx, wrapperObj, sWrappedObjSlot, v) || !JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, JSVAL_ZERO)) { @@ -154,7 +154,7 @@ MakeSOW(JSContext *cx, JSObject *obj) { #ifdef DEBUG { - JSClass *clasp = obj->getClass(); + JSClass *clasp = obj->getJSClass(); NS_ASSERTION(clasp != &SystemOnlyWrapper::SOWClass.base && clasp != &XPCCrossOriginWrapper::XOWClass.base, "bad call"); @@ -170,7 +170,7 @@ MakeSOW(JSContext *cx, JSObject *obj) // If you change this code, change also nsContentUtils::CanAccessNativeAnon()! JSBool -AllowedToAct(JSContext *cx, jsval idval) +AllowedToAct(JSContext *cx, jsid id) { // TODO bug 508928: Refactor this with the XOW security checking code. nsIScriptSecurityManager *ssm = GetSecurityManager(); @@ -220,12 +220,13 @@ AllowedToAct(JSContext *cx, jsval idval) return JS_TRUE; } - if (JSVAL_IS_VOID(idval)) { + if (JSID_IS_VOID(id)) { ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx); } else { // TODO Localize me? - JSString *str = JS_ValueToString(cx, idval); - if (str) { + jsval idval; + JSString *str; + if (JS_IdToValue(cx, id, &idval) && (str = JS_ValueToString(cx, idval))) { JS_ReportError(cx, "Permission denied to access property '%hs' from a non-chrome context", JS_GetStringChars(str)); } @@ -235,7 +236,7 @@ AllowedToAct(JSContext *cx, jsval idval) } JSBool -CheckFilename(JSContext *cx, jsval idval, JSStackFrame *fp) +CheckFilename(JSContext *cx, jsid id, JSStackFrame *fp) { const char *filename; if (fp && @@ -244,12 +245,12 @@ CheckFilename(JSContext *cx, jsval idval, JSStackFrame *fp) return JS_TRUE; } - if (JSVAL_IS_VOID(idval)) { + if (JSID_IS_VOID(id)) { ThrowException(NS_ERROR_XPC_SECURITY_MANAGER_VETO, cx); } else { - // TODO Localize me? - JSString *str = JS_ValueToString(cx, idval); - if (str) { + jsval idval; + JSString *str; + if (JS_IdToValue(cx, id, &idval) && (str = JS_ValueToString(cx, idval))) { JS_ReportError(cx, "Permission denied to access property '%hs' from a non-chrome context", JS_GetStringChars(str)); } @@ -267,7 +268,7 @@ using namespace SystemOnlyWrapper; static inline JSObject * GetWrappedJSObject(JSContext *cx, JSObject *obj) { - JSClass *clasp = obj->getClass(); + JSClass *clasp = obj->getJSClass(); if (!(clasp->flags & JSCLASS_IS_EXTENDED)) { return obj; } @@ -285,7 +286,7 @@ static inline JSObject * GetWrapper(JSObject *obj) { - while (obj->getClass() != &SOWClass.base) { + while (obj->getJSClass() != &SOWClass.base) { obj = obj->getProto(); if (!obj) { break; @@ -306,7 +307,7 @@ static JSBool XPC_SOW_FunctionWrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - if (!AllowedToAct(cx, JSVAL_VOID)) { + if (!AllowedToAct(cx, JSID_VOID)) { return JS_FALSE; } @@ -404,7 +405,7 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObject *wrapperObj, jsval *vp) return XPC_SOW_WrapFunction(cx, wrapperObj, obj, vp); } - if (obj->getClass() == &SOWClass.base) { + if (obj->getJSClass() == &SOWClass.base) { // We are extra careful about content-polluted wrappers here. I don't know // if it's possible to reach them through objects that we wrap, but figuring // that out is more expensive (and harder) than simply checking and @@ -427,9 +428,9 @@ XPC_SOW_RewrapValue(JSContext *cx, JSObject *wrapperObj, jsval *vp) } static JSBool -XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - NS_ASSERTION(obj->getClass() == &SOWClass.base, "Wrong object"); + NS_ASSERTION(obj->getJSClass() == &SOWClass.base, "Wrong object"); jsval resolving; if (!JS_GetReservedSlot(cx, obj, sFlagsSlot, &resolving)) { @@ -454,7 +455,7 @@ XPC_SOW_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -XPC_SOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_SOW_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { JSObject *wrappedObj = GetWrappedObject(cx, obj); if (!wrappedObj) { @@ -469,7 +470,7 @@ XPC_SOW_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, +XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp, JSBool isSet) { obj = GetWrapper(obj); @@ -488,19 +489,14 @@ XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, return ThrowException(NS_ERROR_ILLEGAL_VALUE, cx); } - if (isSet && id == GetRTStringByIndex(cx, XPCJSRuntime::IDX_PROTO)) { + if (isSet && id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTO)) { // No setting __proto__ on my object. return ThrowException(NS_ERROR_INVALID_ARG, cx); // XXX better error message } - jsid interned_id; - if (!JS_ValueToId(cx, id, &interned_id)) { - return JS_FALSE; - } - JSBool ok = isSet - ? JS_SetPropertyById(cx, wrappedObj, interned_id, vp) - : JS_GetPropertyById(cx, wrappedObj, interned_id, vp); + ? JS_SetPropertyById(cx, wrappedObj, id, vp) + : JS_GetPropertyById(cx, wrappedObj, id, vp); if (!ok) { return JS_FALSE; } @@ -509,13 +505,13 @@ XPC_SOW_GetOrSetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp, } static JSBool -XPC_SOW_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_SOW_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_SOW_GetOrSetProperty(cx, obj, id, vp, JS_FALSE); } static JSBool -XPC_SOW_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +XPC_SOW_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return XPC_SOW_GetOrSetProperty(cx, obj, id, vp, JS_TRUE); } @@ -530,7 +526,7 @@ XPC_SOW_Enumerate(JSContext *cx, JSObject *obj) return JS_TRUE; } - if (!AllowedToAct(cx, JSVAL_VOID)) { + if (!AllowedToAct(cx, JSID_VOID)) { return JS_FALSE; } @@ -538,7 +534,7 @@ XPC_SOW_Enumerate(JSContext *cx, JSObject *obj) } static JSBool -XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { obj = GetWrapper(obj); @@ -560,7 +556,7 @@ XPC_SOW_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, static JSBool XPC_SOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) { - if (!AllowedToAct(cx, JSVAL_VOID)) { + if (!AllowedToAct(cx, JSID_VOID)) { return JS_FALSE; } @@ -577,11 +573,11 @@ XPC_SOW_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) return JS_TRUE; } - return wrappedObj->getClass()->convert(cx, wrappedObj, type, vp); + return wrappedObj->getJSClass()->convert(cx, wrappedObj, type, vp); } static JSBool -XPC_SOW_CheckAccess(JSContext *cx, JSObject *obj, jsval prop, JSAccessMode mode, +XPC_SOW_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp) { // Simply forward checkAccess to our wrapped object. It's already expecting @@ -594,15 +590,13 @@ XPC_SOW_CheckAccess(JSContext *cx, JSObject *obj, jsval prop, JSAccessMode mode, } uintN junk; - jsid id; - return JS_ValueToId(cx, prop, &id) && - JS_CheckAccess(cx, wrappedObj, id, mode, vp, &junk); + return JS_CheckAccess(cx, wrappedObj, id, mode, vp, &junk); } static JSBool -XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { - if (!AllowedToAct(cx, JSVAL_VOID)) { + if (!AllowedToAct(cx, JSID_VOID)) { return JS_FALSE; } @@ -612,7 +606,7 @@ XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) return JS_TRUE; } - JSClass *clasp = iface->getClass(); + JSClass *clasp = iface->getJSClass(); *bp = JS_FALSE; if (!clasp->hasInstance) { @@ -622,6 +616,7 @@ XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) // Prematurely unwrap the left hand side. This isn't necessary, but could be // faster than waiting until XPCWrappedNative::GetWrappedNativeOfJSObject to // do it. + jsval v = *valp; if (!JSVAL_IS_PRIMITIVE(v)) { JSObject *test = JSVAL_TO_OBJECT(v); @@ -632,13 +627,14 @@ XPC_SOW_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) } } - return clasp->hasInstance(cx, iface, v, bp); + return clasp->hasInstance(cx, iface, &v, bp); } static JSBool -XPC_SOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_SOW_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { // Delegate to our wrapped object. + jsval v = *valp; if (JSVAL_IS_PRIMITIVE(v)) { *bp = JS_FALSE; return JS_TRUE; @@ -658,20 +654,22 @@ XPC_SOW_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) if (lhs) { // Delegate to our wrapped object if we can. - JSClass *clasp = lhs->getClass(); + JSClass *clasp = lhs->getJSClass(); if (clasp->flags & JSCLASS_IS_EXTENDED) { JSExtendedClass *xclasp = (JSExtendedClass *) clasp; // NB: JSExtendedClass.equality is a required field. - return xclasp->equality(cx, lhs, OBJECT_TO_JSVAL(rhs), bp); + jsval rhsVal = OBJECT_TO_JSVAL(rhs); + return xclasp->equality(cx, lhs, &rhsVal, bp); } } // We know rhs is non-null. - JSClass *clasp = rhs->getClass(); + JSClass *clasp = rhs->getJSClass(); if (clasp->flags & JSCLASS_IS_EXTENDED) { JSExtendedClass *xclasp = (JSExtendedClass *) clasp; // NB: JSExtendedClass.equality is a required field. - return xclasp->equality(cx, rhs, OBJECT_TO_JSVAL(lhs), bp); + jsval lhsVal = OBJECT_TO_JSVAL(lhs); + return xclasp->equality(cx, rhs, &lhsVal, bp); } *bp = JS_FALSE; @@ -693,7 +691,7 @@ XPC_SOW_Iterator(JSContext *cx, JSObject *obj, JSBool keysonly) return nsnull; } - js::AutoValueRooter tvr(cx, OBJECT_TO_JSVAL(wrapperIter)); + js::AutoObjectRooter tvr(cx, wrapperIter); // Initialize our SOW. jsval v = OBJECT_TO_JSVAL(wrappedObj); diff --git a/js/src/xpconnect/src/XPCWrapper.cpp b/js/src/xpconnect/src/XPCWrapper.cpp index 388a984cc283..ba536d33000a 100644 --- a/js/src/xpconnect/src/XPCWrapper.cpp +++ b/js/src/xpconnect/src/XPCWrapper.cpp @@ -60,7 +60,7 @@ const PRUint32 sSecMgrGetProp = nsIXPCSecurityManager::ACCESS_GET_PROPERTY; JSObject * Unwrap(JSContext *cx, JSObject *wrapper) { - JSClass *clasp = wrapper->getClass(); + JSClass *clasp = wrapper->getJSClass(); if (clasp == &XPCCrossOriginWrapper::XOWClass.base) { return UnwrapXOW(cx, wrapper); } @@ -351,7 +351,7 @@ CreateIteratorObj(JSContext *cx, JSObject *tempWrapper, // call enumerate, and then re-set the prototype. As we do this, we have // to protec the temporary wrapper from garbage collection. - js::AutoValueRooter tvr(cx, tempWrapper); + js::AutoObjectRooter tvr(cx, tempWrapper); if (!JS_SetPrototype(cx, iterObj, wrapperObj) || !XPCWrapper::Enumerate(cx, iterObj, wrapperObj) || !JS_SetPrototype(cx, iterObj, tempWrapper)) { @@ -400,7 +400,7 @@ CreateSimpleIterator(JSContext *cx, JSObject *scope, JSBool keysonly, return nsnull; } - js::AutoValueRooter tvr(cx, iterObj); + js::AutoObjectRooter tvr(cx, iterObj); if (!propertyContainer) { if (!JS_SetReservedSlot(cx, iterObj, 0, PRIVATE_TO_JSVAL(nsnull)) || !JS_SetReservedSlot(cx, iterObj, 1, JSVAL_ZERO) || @@ -427,15 +427,10 @@ CreateSimpleIterator(JSContext *cx, JSObject *scope, JSBool keysonly, JSBool AddProperty(JSContext *cx, JSObject *wrapperObj, JSBool wantGetterSetter, - JSObject *innerObj, jsval id, jsval *vp) + JSObject *innerObj, jsid id, jsval *vp) { - jsid interned_id; - if (!::JS_ValueToId(cx, id, &interned_id)) { - return JS_FALSE; - } - JSPropertyDescriptor desc; - if (!GetPropertyAttrs(cx, wrapperObj, interned_id, JSRESOLVE_QUALIFIED, + if (!GetPropertyAttrs(cx, wrapperObj, id, JSRESOLVE_QUALIFIED, wantGetterSetter, &desc)) { return JS_FALSE; } @@ -443,26 +438,26 @@ AddProperty(JSContext *cx, JSObject *wrapperObj, JSBool wantGetterSetter, NS_ASSERTION(desc.obj == wrapperObj, "What weird wrapper are we using?"); - return JS_DefinePropertyById(cx, innerObj, interned_id, *vp, + return JS_DefinePropertyById(cx, innerObj, id, *vp, desc.getter, desc.setter, desc.attrs); } JSBool -DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - if (JSVAL_IS_STRING(id)) { - JSString *str = JSVAL_TO_STRING(id); + if (JSID_IS_STRING(id)) { + JSString *str = JSID_TO_STRING(id); jschar *chars = ::JS_GetStringChars(str); size_t length = ::JS_GetStringLength(str); return ::JS_DeleteUCProperty2(cx, obj, chars, length, vp); } - if (!JSVAL_IS_INT(id)) { + if (!JSID_IS_INT(id)) { return DoThrowException(NS_ERROR_NOT_IMPLEMENTED, cx); } - return ::JS_DeleteElement2(cx, obj, JSVAL_TO_INT(id), vp); + return ::JS_DeleteElement2(cx, obj, JSID_TO_INT(id), vp); } JSBool @@ -514,15 +509,10 @@ Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj) JSBool NewResolve(JSContext *cx, JSObject *wrapperObj, JSBool wantDetails, - JSObject *innerObj, jsval id, uintN flags, JSObject **objp) + JSObject *innerObj, jsid id, uintN flags, JSObject **objp) { - jsid interned_id; - if (!::JS_ValueToId(cx, id, &interned_id)) { - return JS_FALSE; - } - JSPropertyDescriptor desc; - if (!GetPropertyAttrs(cx, innerObj, interned_id, flags, wantDetails, &desc)) { + if (!GetPropertyAttrs(cx, innerObj, id, flags, wantDetails, &desc)) { return JS_FALSE; } @@ -541,7 +531,7 @@ NewResolve(JSContext *cx, JSObject *wrapperObj, JSBool wantDetails, return JS_FALSE; } - JSBool ok = JS_DefinePropertyById(cx, wrapperObj, interned_id, desc.value, + JSBool ok = JS_DefinePropertyById(cx, wrapperObj, id, desc.value, desc.getter, desc.setter, desc.attrs); JS_SetReservedSlot(cx, wrapperObj, sFlagsSlot, oldFlags); @@ -556,7 +546,7 @@ NewResolve(JSContext *cx, JSObject *wrapperObj, JSBool wantDetails, JSBool ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj, XPCWrappedNative *wn, - jsval id, uintN flags, JSObject **objp, + jsid id, uintN flags, JSObject **objp, JSBool isNativeWrapper) { // This will do verification and the method lookup for us. @@ -565,7 +555,7 @@ ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, // For "constructor" we don't want to call into the resolve hooks on the // wrapped native, since that would give the wrong constructor. if (NATIVE_HAS_FLAG(wn, WantNewResolve) && - id != GetRTStringByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)) { + id != GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)) { // Mark ourselves as resolving so our AddProperty hook can do the // right thing here. @@ -628,7 +618,7 @@ ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, } } - if (!JSVAL_IS_STRING(id)) { + if (!JSID_IS_STRING(id)) { // A non-string id is being resolved. Won't be found here, return // early. @@ -665,7 +655,7 @@ ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, return JS_TRUE; } - JSString *str = JSVAL_TO_STRING(id); + JSString *str = JSID_TO_STRING(id); if (!str) { return DoThrowException(NS_ERROR_UNEXPECTED, cx); } @@ -739,9 +729,7 @@ ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, return JS_FALSE; } - if (!::JS_DefineUCProperty(cx, wrapperObj, ::JS_GetStringChars(str), - ::JS_GetStringLength(str), v, getter, setter, - attrs)) { + if (!::JS_DefinePropertyById(cx, wrapperObj, id, v, getter, setter, attrs)) { return JS_FALSE; } @@ -758,7 +746,7 @@ ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, JSBool GetOrSetNativeProperty(JSContext *cx, JSObject *obj, XPCWrappedNative *wrappedNative, - jsval id, jsval *vp, JSBool aIsSet, + jsid id, jsval *vp, JSBool aIsSet, JSBool isNativeWrapper) { // This will do verification and the method lookup for us. @@ -806,7 +794,7 @@ GetOrSetNativeProperty(JSContext *cx, JSObject *obj, } } - if (!JSVAL_IS_STRING(id)) { + if (!JSID_IS_STRING(id)) { // Not going to be found here return JS_TRUE; } @@ -918,14 +906,10 @@ NativeToString(JSContext *cx, XPCWrappedNative *wrappedNative, XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance(); jsid id = rt->GetStringID(XPCJSRuntime::IDX_TO_STRING); - jsval idAsVal; - if (!::JS_IdToValue(cx, id, &idAsVal)) { - return JS_FALSE; - } // Someone is trying to call toString on our wrapped object. JSObject *wn_obj = wrappedNative->GetFlatJSObject(); - XPCCallContext ccx(JS_CALLER, cx, wn_obj, nsnull, idAsVal); + XPCCallContext ccx(JS_CALLER, cx, wn_obj, nsnull, id); if (!ccx.IsValid()) { // Shouldn't really happen. return DoThrowException(NS_ERROR_FAILURE, cx); diff --git a/js/src/xpconnect/src/XPCWrapper.h b/js/src/xpconnect/src/XPCWrapper.h index d4214b628617..0143574de6fc 100644 --- a/js/src/xpconnect/src/XPCWrapper.h +++ b/js/src/xpconnect/src/XPCWrapper.h @@ -155,10 +155,10 @@ MakeSOW(JSContext *cx, JSObject *obj); // Used by UnwrapSOW below. JSBool -AllowedToAct(JSContext *cx, jsval idval); +AllowedToAct(JSContext *cx, jsid id); JSBool -CheckFilename(JSContext *cx, jsval idval, JSStackFrame *fp); +CheckFilename(JSContext *cx, jsid id, JSStackFrame *fp); } @@ -321,7 +321,7 @@ MaybePreserveWrapper(JSContext *cx, XPCWrappedNative *wn, uintN flags) inline JSBool IsSecurityWrapper(JSObject *wrapper) { - JSClass *clasp = wrapper->getClass(); + JSClass *clasp = wrapper->getJSClass(); return (clasp->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*)clasp)->wrappedObject; } @@ -345,7 +345,7 @@ Unwrap(JSContext *cx, JSObject *wrapper); inline JSObject * UnwrapGeneric(JSContext *cx, const JSExtendedClass *xclasp, JSObject *wrapper) { - if (wrapper->getClass() != &xclasp->base) { + if (wrapper->getJSClass() != &xclasp->base) { return nsnull; } @@ -370,7 +370,7 @@ UnwrapSOW(JSContext *cx, JSObject *wrapper) return nsnull; } - if (!SystemOnlyWrapper::AllowedToAct(cx, JSVAL_VOID)) { + if (!SystemOnlyWrapper::AllowedToAct(cx, JSID_VOID)) { JS_ClearPendingException(cx); wrapper = nsnull; } @@ -485,13 +485,13 @@ CreateSimpleIterator(JSContext *cx, JSObject *scope, JSBool keysonly, JSBool AddProperty(JSContext *cx, JSObject *wrapperObj, JSBool wantGetterSetter, JSObject *innerObj, - jsval id, jsval *vp); + jsid id, jsval *vp); /** * Called for the common part of deleting a property from obj. */ JSBool -DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); /** * Called to enumerate the properties of |innerObj| onto |wrapperObj|. @@ -510,7 +510,7 @@ Enumerate(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj); */ JSBool NewResolve(JSContext *cx, JSObject *wrapperObj, JSBool preserveVal, - JSObject *innerObj, jsval id, uintN flags, JSObject **objp); + JSObject *innerObj, jsid id, uintN flags, JSObject **objp); /** * Resolve a native property named id from innerObj onto wrapperObj. The @@ -520,7 +520,7 @@ NewResolve(JSContext *cx, JSObject *wrapperObj, JSBool preserveVal, JSBool ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, JSObject *innerObj, XPCWrappedNative *wn, - jsval id, uintN flags, JSObject **objp, + jsid id, uintN flags, JSObject **objp, JSBool isNativeWrapper); /** @@ -531,7 +531,7 @@ ResolveNativeProperty(JSContext *cx, JSObject *wrapperObj, JSBool GetOrSetNativeProperty(JSContext *cx, JSObject *obj, XPCWrappedNative *wrappedNative, - jsval id, jsval *vp, JSBool aIsSet, + jsid id, jsval *vp, JSBool aIsSet, JSBool isNativeWrapper); /** diff --git a/js/src/xpconnect/src/dom_quickstubs.qsconf b/js/src/xpconnect/src/dom_quickstubs.qsconf index 11c62c04bc05..d6c04beb5a74 100644 --- a/js/src/xpconnect/src/dom_quickstubs.qsconf +++ b/js/src/xpconnect/src/dom_quickstubs.qsconf @@ -394,7 +394,7 @@ members = [ # dom/interfaces/views 'nsIDOMDocumentView.defaultView', - + # dom/interfaces/xbl - None. # dom/interfaces/xpath diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index b3c1fa80ad70..d9281e446edc 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -673,7 +673,7 @@ NoteJSChild(JSTracer *trc, void *thing, uint32 kind) #endif tracer->cb.NoteScriptChild(nsIProgrammingLanguage::JAVASCRIPT, thing); } - else if(kind != JSTRACE_DOUBLE && kind != JSTRACE_STRING) + else if(kind != JSTRACE_STRING) { JS_TraceChildren(trc, thing, kind); } @@ -716,7 +716,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) if(traceKind == JSTRACE_OBJECT) { obj = static_cast(p); - clazz = obj->getClass(); + clazz = obj->getJSClass(); if(clazz == &XPC_WN_Tearoff_JSClass) { @@ -766,7 +766,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) if(traceKind == JSTRACE_OBJECT) { JSObject *obj = static_cast(p); - JSClass *clazz = obj->getClass(); + JSClass *clazz = obj->getJSClass(); if(XPCNativeWrapper::IsNativeWrapperClass(clazz)) { XPCWrappedNative* wn; @@ -826,7 +826,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) JS_snprintf(name, sizeof(name), "JS Object (%s - %s)", clazz->name, si->GetJSClass()->name); } - else if(clazz == &js_ScriptClass) + else if(clazz == Jsvalify(&js_ScriptClass)) { JSScript* script = (JSScript*) xpc_GetJSPrivate(obj); if(script->filename) @@ -840,7 +840,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) JS_snprintf(name, sizeof(name), "JS Object (Script)"); } } - else if(clazz == &js_FunctionClass) + else if(clazz == Jsvalify(&js_FunctionClass)) { JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj); JSString* str = JS_GetFunctionId(fun); @@ -867,7 +867,6 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) { static const char trace_types[JSTRACE_LIMIT][7] = { "Object", - "Double", "String", "Xml" }; @@ -1141,7 +1140,7 @@ NS_IMETHODIMP nsXPConnect::InitClassesForOuterObject(JSContext * aJSContext, JSO } static JSBool -TempGlobalResolve(JSContext *aJSContext, JSObject *obj, jsval id) +TempGlobalResolve(JSContext *aJSContext, JSObject *obj, jsid id) { JSBool resolved; return JS_ResolveStandardClass(aJSContext, obj, id, &resolved); @@ -1938,7 +1937,7 @@ nsXPConnect::RestoreWrappedNativePrototype(JSContext * aJSContext, if(NS_FAILED(rv)) return UnexpectedFailure(rv); - if(!IS_PROTO_CLASS(protoJSObject->getClass())) + if(!IS_PROTO_CLASS(protoJSObject->getJSClass())) return UnexpectedFailure(NS_ERROR_INVALID_ARG); XPCWrappedNativeScope* scope = @@ -2378,10 +2377,10 @@ nsXPConnect::VariantToJS(JSContext* ctx, JSObject* scope, nsIVariant* value, jsv /* nsIVariant JSToVariant (in JSContextPtr ctx, in jsval value); */ NS_IMETHODIMP -nsXPConnect::JSToVariant(JSContext* ctx, jsval value, nsIVariant** _retval) +nsXPConnect::JSToVariant(JSContext* ctx, const jsval &value, nsIVariant** _retval) { NS_PRECONDITION(ctx, "bad param"); - NS_PRECONDITION(value, "bad param"); + NS_PRECONDITION(value != JSVAL_NULL, "bad param"); NS_PRECONDITION(_retval, "bad param"); XPCCallContext ccx(NATIVE_CALLER, ctx); @@ -2839,11 +2838,11 @@ JS_EXPORT_API(void) DumpJSObject(JSObject* obj) JS_EXPORT_API(void) DumpJSValue(jsval val) { - printf("Dumping 0x%p. Value tag is %u.\n", (void *) val, (PRUint32) JSVAL_TAG(val)); + printf("Dumping 0x%llu.\n", (long long) JSVAL_BITS(val)); if(JSVAL_IS_NULL(val)) { printf("Value is null\n"); } - else if(JSVAL_IS_OBJECT(val)) { + else if(JSVAL_IS_OBJECT(val) || JSVAL_IS_NULL(val)) { printf("Value is an object\n"); JSObject* obj = JSVAL_TO_OBJECT(val); DumpJSObject(obj); @@ -2853,7 +2852,7 @@ JS_EXPORT_API(void) DumpJSValue(jsval val) if(JSVAL_IS_INT(val)) printf("Integer %i\n", JSVAL_TO_INT(val)); else if(JSVAL_IS_DOUBLE(val)) - printf("Floating-point value %f\n", *JSVAL_TO_DOUBLE(val)); + printf("Floating-point value %f\n", JSVAL_TO_DOUBLE(val)); } else if(JSVAL_IS_STRING(val)) { printf("Value is a string: "); diff --git a/js/src/xpconnect/src/qsgen.py b/js/src/xpconnect/src/qsgen.py index 3f145ac098aa..c1818a9d4fc9 100644 --- a/js/src/xpconnect/src/qsgen.py +++ b/js/src/xpconnect/src/qsgen.py @@ -560,7 +560,7 @@ def writeArgumentUnboxing(f, i, name, type, haveCcx, optional, rvdeclared, f.write(" if (NS_FAILED(rv)) {\n") if isSetter: f.write(" xpc_qsThrowBadSetterValue(" - "cx, rv, JSVAL_TO_OBJECT(*tvr.addr()), id);\n") + "cx, rv, JSVAL_TO_OBJECT(*tvr.jsval_addr()), id);\n") elif haveCcx: f.write(" xpc_qsThrowBadArgWithCcx(ccx, rv, %d);\n" % i) else: @@ -747,7 +747,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): signature = "static JSBool\n" if isAttr: # JSPropertyOp signature. - signature += "%s(JSContext *cx, JSObject *obj, jsval id,%s jsval *vp)\n" + signature += "%s(JSContext *cx, JSObject *obj, jsid id,%s jsval *vp)\n" else: # JSFastNative. signature += "%s(JSContext *cx, uintN argc,%s jsval *vp)\n" @@ -857,7 +857,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): pthisval = 'vp' elif isSetter: f.write(" js::AutoValueRooter tvr(cx);\n") - pthisval = 'tvr.addr()' + pthisval = 'tvr.jsval_addr()' else: pthisval = '&vp[1]' # as above, ok to overwrite vp[1] @@ -986,7 +986,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): if isGetter: thisval = '*vp' else: - thisval = '*tvr.addr()' + thisval = '*tvr.jsval_addr()' f.write(" return xpc_qsThrowGetterSetterFailed(cx, rv, " + "JSVAL_TO_OBJECT(%s), id);\n" % thisval) @@ -1006,7 +1006,7 @@ def writeQuickStub(f, customMethodCalls, member, stubName, isSetter=False): # Only these types can be returned (note: no strings); # if the type isn't one of these, then defaultTraceType is used traceReturnTypeMap = { - 'void': ("jsval ", "JSVAL", "JSVAL_VOID"), + 'void': ("uint32 ", "UINT32", "0"), 'boolean': ("JSBool ", "BOOL", "JS_FALSE"), 'short': ("int32 ", "INT32", "0"), 'unsigned short': ("uint32 ", "UINT32", "0"), @@ -1015,41 +1015,60 @@ traceReturnTypeMap = { 'float': ("jsdouble ", "DOUBLE", "0"), 'double': ("jsdouble ", "DOUBLE", "0"), 'octet': ("uint32 ", "UINT32", "0"), - 'jsval': ("jsval ", "JSVAL", "JSVAL_VOID") + '[astring]': ("JSString *", "STRING_OR_NULL", "nsnull"), + '[domstring]': ("JSString *", "STRING_OR_NULL", "nsnull"), + '[cstring]': ("JSString *", "STRING_OR_NULL", "nsnull"), + 'string': ("JSString *", "STRING_OR_NULL", "nsnull"), + 'wstring': ("JSString *", "STRING_OR_NULL", "nsnull") } # This list extends the above list, but includes types that # are valid for arguments only, namely strings. -traceTypeMap = traceReturnTypeMap.copy() -traceTypeMap.update({ - '[astring]': ("JSString *", "STRING", "nsnull"), - '[domstring]': ("JSString *", "STRING", "nsnull"), - '[cstring]': ("JSString *", "STRING", "nsnull"), - 'string': ("JSString *", "STRING", "nsnull"), - 'wstring': ("JSString *", "STRING", "nsnull"), +traceParamTypeMap = traceReturnTypeMap.copy() +traceParamTypeMap.update({ + 'void': ("uint32 ", "UINT32"), + 'boolean': ("JSBool ", "BOOL"), + 'short': ("int32 ", "INT32"), + 'unsigned short': ("uint32 ", "UINT32"), + 'long': ("int32 ", "INT32"), + 'unsigned long': ("uint32 ", "UINT32"), + 'float': ("jsdouble ", "DOUBLE"), + 'double': ("jsdouble ", "DOUBLE"), + 'octet': ("uint32 ", "UINT32"), + '[astring]': ("JSString *", "STRING"), + '[domstring]': ("JSString *", "STRING"), + '[cstring]': ("JSString *", "STRING"), + 'string': ("JSString *", "STRING"), + 'wstring': ("JSString *", "STRING"), }) -defaultTraceType = ("jsval ", "JSVAL", "JSVAL_VOID") +defaultReturnTraceType = ("JSObject *", "OBJECT_OR_NULL", "nsnull") +defaultParamTraceType = ("js::ValueArgType ", "VALUE") -def getTraceType(type): +def getTraceParamType(type): + assert type is not '[jsval]' type = getBuiltinOrNativeTypeName(type) - return traceTypeMap.get(type, defaultTraceType)[0] + return traceParamTypeMap.get(type, defaultParamTraceType)[0] def getTraceReturnType(type): + assert type is not '[jsval]' type = getBuiltinOrNativeTypeName(type) - return traceReturnTypeMap.get(type, defaultTraceType)[0] + return traceReturnTypeMap.get(type, defaultReturnTraceType)[0] -def getTraceInfoType(type): +def getTraceInfoParamType(type): + assert type is not '[jsval]' type = getBuiltinOrNativeTypeName(type) - return traceTypeMap.get(type, defaultTraceType)[1] + return traceParamTypeMap.get(type, defaultParamTraceType)[1] def getTraceInfoReturnType(type): + assert type is not '[jsval]' type = getBuiltinOrNativeTypeName(type) - return traceReturnTypeMap.get(type, defaultTraceType)[1] + return traceReturnTypeMap.get(type, defaultReturnTraceType)[1] def getTraceInfoDefaultReturn(type): + assert type is not '[jsval]' type = getBuiltinOrNativeTypeName(type) - return traceTypeMap.get(type, defaultTraceType)[2] + return traceReturnTypeMap.get(type, defaultReturnTraceType)[2] def getFailureString(retval, indent): assert indent > 0 @@ -1120,7 +1139,7 @@ def writeTraceableArgumentConversion(f, member, i, name, type, haveCcx, assert haveCcx template = ( " nsCOMPtr ${name}(already_AddRefed(" - "XPCVariant::newVariant(ccx, ${argVal})));\n" + "XPCVariant::newVariant(ccx, js::Jsvalify(js::ValueArgToConstRef(${argVal})))));\n" " if (!${name}) {\n") f.write(substitute(template, params)) writeFailure(f, getTraceInfoDefaultReturn(member.realtype), 2) @@ -1134,7 +1153,7 @@ def writeTraceableArgumentConversion(f, member, i, name, type, haveCcx, f.write(" %s *%s;\n" % (type.name, name)) f.write(" xpc_qsSelfRef %sref;\n" % name) f.write(" rv = xpc_qsUnwrapArg<%s>(" - "cx, %s, &%s, &%sref.ptr, &vp.array[%d]);\n" + "cx, js::Jsvalify(js::ValueArgToConstRef(%s)), &%s, &%sref.ptr, &vp.array[%d]);\n" % (type.name, argVal, name, name, 2 + i)) f.write(" if (NS_FAILED(rv)) {\n") if haveCcx: @@ -1154,7 +1173,7 @@ def writeTraceableArgumentConversion(f, member, i, name, type, haveCcx, traceableResultConvTemplates = { 'void': - " return JSVAL_VOID;\n", + " return 0;\n", 'octet': " return uint32(result);\n", 'short': @@ -1172,21 +1191,20 @@ traceableResultConvTemplates = { 'double': " return jsdouble(result);\n", '[domstring]': - " jsval rval;\n" - " if (!xpc_qsStringToJsval(cx, result, &rval)) {\n" + " JSString *rval;\n" + " if (!xpc_qsStringToJsstring(cx, result, &rval)) {\n" " JS_ReportOutOfMemory(cx);\n${errorStr}" " return rval;\n", '[astring]': - " jsval rval;\n" - " if (!xpc_qsStringToJsval(cx, result, &rval)) {\n" + " JSString *rval;\n" + " if (!xpc_qsStringToJsstring(cx, result, &rval)) {\n" " JS_ReportOutOfMemory(cx);\n${errorStr}" - " return rval;\n", - '[jsval]': - " return vp.array[0];\n" + " return rval;\n" } def writeTraceableResultConv(f, type): typeName = getBuiltinOrNativeTypeName(type) + assert typeName is not '[jsval]' if typeName is not None: template = traceableResultConvTemplates.get(typeName) if template is not None: @@ -1206,7 +1224,7 @@ def writeTraceableResultConv(f, type): % (type.name, type.name)) f.write(" if (!ok) {\n"); writeFailure(f, getTraceInfoDefaultReturn(type), 2) - f.write(" return vp.array[0];\n") + f.write(" return JSVAL_TO_OBJECT(vp.array[0]);\n") return warn("Unable to convert result of type %s" % typeName) @@ -1242,8 +1260,8 @@ def writeTraceableQuickStub(f, customMethodCalls, member, stubName): f.write(", JSObject *callee") traceInfo["params"].append("CALLEE") for i, param in enumerate(member.params): - f.write(", %s_arg%d" % (getTraceType(param.realtype), i)) - traceInfo["params"].append(getTraceInfoType(param.realtype)) + f.write(", %s_arg%d" % (getTraceParamType(param.realtype), i)) + traceInfo["params"].append(getTraceInfoParamType(param.realtype)) f.write(")\n{\n"); f.write(" XPC_QS_ASSERT_CONTEXT_OK(cx);\n") diff --git a/js/src/xpconnect/src/xpccallcontext.cpp b/js/src/xpconnect/src/xpccallcontext.cpp index 8f44659c0cb0..616bace2003b 100644 --- a/js/src/xpconnect/src/xpccallcontext.cpp +++ b/js/src/xpconnect/src/xpccallcontext.cpp @@ -43,13 +43,13 @@ #include "xpcprivate.h" XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, - JSContext* cx /* = nsnull */, - JSObject* obj /* = nsnull */, - JSObject* funobj /* = nsnull */, - jsval name /* = 0 */, - uintN argc /* = NO_ARGS */, - jsval *argv /* = nsnull */, - jsval *rval /* = nsnull */) + JSContext* cx /* = nsnull */, + JSObject* obj /* = nsnull */, + JSObject* funobj /* = nsnull */, + jsid name /* = JSID_VOID */, + uintN argc /* = NO_ARGS */, + jsval *argv /* = nsnull */, + jsval *rval /* = nsnull */) : mState(INIT_FAILED), mXPC(nsXPConnect::GetXPConnect()), mThreadData(nsnull), @@ -84,7 +84,7 @@ XPCCallContext::XPCCallContext(XPCContext::LangType callerLanguage, mTearOff(tearOff), mCallee(nsnull) { - Init(callerLanguage, callBeginRequest, obj, nsnull, JS_FALSE, 0, NO_ARGS, + Init(callerLanguage, callBeginRequest, obj, nsnull, JS_FALSE, JSID_VOID, NO_ARGS, nsnull, nsnull); } @@ -94,7 +94,7 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage, JSObject* obj, JSObject* funobj, JSBool getWrappedNative, - jsval name, + jsid name, uintN argc, jsval *argv, jsval *rval) @@ -220,7 +220,7 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage, mFlattenedJSObject = mCurrentJSObject; } - if(name) + if(!JSID_IS_VOID(name)) SetName(name); if(argc != NO_ARGS) @@ -230,7 +230,7 @@ XPCCallContext::Init(XPCContext::LangType callerLanguage, } void -XPCCallContext::SetName(jsval name) +XPCCallContext::SetName(jsid name) { CHECK_STATE(HAVE_OBJECT); diff --git a/js/src/xpconnect/src/xpccomponents.cpp b/js/src/xpconnect/src/xpccomponents.cpp index 36239fee56c7..7fa081f1d01d 100644 --- a/js/src/xpconnect/src/xpccomponents.cpp +++ b/js/src/xpconnect/src/xpccomponents.cpp @@ -276,7 +276,7 @@ nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative *wrapper, *statep = PRIVATE_TO_JSVAL(e); if(idp) - *idp = JSVAL_ZERO; // indicate that we don't know the count + *idp = INT_TO_JSID(0); // indicate that we don't know the count return NS_OK; } case JSENUMERATE_NEXT: @@ -331,14 +331,14 @@ nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsXPCComponents_Interfaces::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, PRUint32 flags, + jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) { const char* name = nsnull; if(mManager && - JSVAL_IS_STRING(id) && - nsnull != (name = JS_GetStringBytes(JSVAL_TO_STRING(id))) && + JSID_IS_STRING(id) && + nsnull != (name = JS_GetStringBytes(JSID_TO_STRING(id))) && name[0] != '{') // we only allow interfaces by name here { nsCOMPtr info; @@ -364,11 +364,8 @@ nsXPCComponents_Interfaces::NewResolve(nsIXPConnectWrappedNative *wrapper, JSObject* idobj; if(holder && NS_SUCCEEDED(holder->GetJSObject(&idobj))) { - jsid idid; - *objp = obj; - *_retval = JS_ValueToId(cx, id, &idid) && - JS_DefinePropertyById(cx, obj, idid, + *_retval = JS_DefinePropertyById(cx, obj, id, OBJECT_TO_JSVAL(idobj), nsnull, nsnull, JSPROP_ENUMERATE | @@ -606,7 +603,7 @@ nsXPCComponents_InterfacesByID::NewEnumerate(nsIXPConnectWrappedNative *wrapper, *statep = PRIVATE_TO_JSVAL(e); if(idp) - *idp = JSVAL_ZERO; // indicate that we don't know the count + *idp = INT_TO_JSID(0); // indicate that we don't know the count return NS_OK; } case JSENUMERATE_NEXT: @@ -666,15 +663,15 @@ nsXPCComponents_InterfacesByID::NewEnumerate(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsXPCComponents_InterfacesByID::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, PRUint32 flags, + jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) { const jschar* name = nsnull; if(mManager && - JSVAL_IS_STRING(id) && - 38 == JS_GetStringLength(JSVAL_TO_STRING(id)) && - nsnull != (name = JS_GetStringChars(JSVAL_TO_STRING(id)))) + JSID_IS_STRING(id) && + 38 == JS_GetStringLength(JSID_TO_STRING(id)) && + nsnull != (name = JS_GetStringChars(JSID_TO_STRING(id)))) { nsID iid; if (!iid.Parse(NS_ConvertUTF16toUTF8(reinterpret_cast @@ -705,11 +702,9 @@ nsXPCComponents_InterfacesByID::NewResolve(nsIXPConnectWrappedNative *wrapper, JSObject* idobj; if(holder && NS_SUCCEEDED(holder->GetJSObject(&idobj))) { - jsid idid; - *objp = obj; - *_retval = JS_ValueToId(cx, id, &idid) && - JS_DefinePropertyById(cx, obj, idid, + *_retval = + JS_DefinePropertyById(cx, obj, id, OBJECT_TO_JSVAL(idobj), nsnull, nsnull, JSPROP_ENUMERATE | @@ -929,7 +924,7 @@ nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative *wrapper, *statep = PRIVATE_TO_JSVAL(e); if(idp) - *idp = JSVAL_ZERO; // indicate that we don't know the count + *idp = INT_TO_JSID(0); // indicate that we don't know the count return NS_OK; } case JSENUMERATE_NEXT: @@ -972,14 +967,14 @@ nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsXPCComponents_Classes::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, PRUint32 flags, + jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) { const char* name = nsnull; - if(JSVAL_IS_STRING(id) && - nsnull != (name = JS_GetStringBytes(JSVAL_TO_STRING(id))) && + if(JSID_IS_STRING(id) && + nsnull != (name = JS_GetStringBytes(JSID_TO_STRING(id))) && name[0] != '{') // we only allow contractids here { nsCOMPtr nsid = @@ -999,11 +994,8 @@ nsXPCComponents_Classes::NewResolve(nsIXPConnectWrappedNative *wrapper, JSObject* idobj; if(holder && NS_SUCCEEDED(holder->GetJSObject(&idobj))) { - jsid idid; - *objp = obj; - *_retval = JS_ValueToId(cx, id, &idid) && - JS_DefinePropertyById(cx, obj, idid, + *_retval = JS_DefinePropertyById(cx, obj, id, OBJECT_TO_JSVAL(idobj), nsnull, nsnull, JSPROP_ENUMERATE | @@ -1183,7 +1175,7 @@ nsXPCComponents_ClassesByID::NewEnumerate(nsIXPConnectWrappedNative *wrapper, *statep = PRIVATE_TO_JSVAL(e); if(idp) - *idp = JSVAL_ZERO; // indicate that we don't know the count + *idp = INT_TO_JSID(0); // indicate that we don't know the count return NS_OK; } case JSENUMERATE_NEXT: @@ -1244,13 +1236,13 @@ IsRegisteredCLSID(const char* str) NS_IMETHODIMP nsXPCComponents_ClassesByID::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, PRUint32 flags, + jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) { const char* name = nsnull; - if(JSVAL_IS_STRING(id) && - nsnull != (name = JS_GetStringBytes(JSVAL_TO_STRING(id))) && + if(JSID_IS_STRING(id) && + nsnull != (name = JS_GetStringBytes(JSID_TO_STRING(id))) && name[0] == '{' && IsRegisteredCLSID(name)) // we only allow canonical CLSIDs here { @@ -1271,11 +1263,8 @@ nsXPCComponents_ClassesByID::NewResolve(nsIXPConnectWrappedNative *wrapper, JSObject* idobj; if(holder && NS_SUCCEEDED(holder->GetJSObject(&idobj))) { - jsid idid; - *objp = obj; - *_retval = JS_ValueToId(cx, id, &idid) && - JS_DefinePropertyById(cx, obj, idid, + *_retval = JS_DefinePropertyById(cx, obj, id, OBJECT_TO_JSVAL(idobj), nsnull, nsnull, JSPROP_ENUMERATE | @@ -1448,7 +1437,7 @@ nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative *wrapper, case JSENUMERATE_INIT_ALL: { if(idp) - *idp = INT_TO_JSVAL(nsXPCException::GetNSResultCount()); + *idp = INT_TO_JSID(nsXPCException::GetNSResultCount()); void** space = (void**) new char[sizeof(void*)]; *space = nsnull; @@ -1482,13 +1471,13 @@ nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsXPCComponents_Results::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, PRUint32 flags, + jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) { const char* name = nsnull; - if(JSVAL_IS_STRING(id) && - nsnull != (name = JS_GetStringBytes(JSVAL_TO_STRING(id)))) + if(JSID_IS_STRING(id) && + nsnull != (name = JS_GetStringBytes(JSID_TO_STRING(id)))) { const char* rv_name; void* iter = nsnull; @@ -1497,13 +1486,11 @@ nsXPCComponents_Results::NewResolve(nsIXPConnectWrappedNative *wrapper, { if(!strcmp(name, rv_name)) { - jsid idid; jsval val; *objp = obj; if(!JS_NewNumberValue(cx, (jsdouble)rv, &val) || - !JS_ValueToId(cx, id, &idid) || - !JS_DefinePropertyById(cx, obj, idid, val, + !JS_DefinePropertyById(cx, obj, id, val, nsnull, nsnull, JSPROP_ENUMERATE | JSPROP_READONLY | @@ -1738,7 +1725,7 @@ nsXPCComponents_ID::CallOrConstruct(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsXPCComponents_ID::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval val, PRBool *bp, PRBool *_retval) + const jsval &val, PRBool *bp, PRBool *_retval) { if(bp) *bp = JSValIsInterfaceOfType(cx, val, NS_GET_IID(nsIJSID)); @@ -2014,7 +2001,7 @@ nsXPCComponents_Exception::CallOrConstruct(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsXPCComponents_Exception::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval val, PRBool *bp, + const jsval &val, PRBool *bp, PRBool *_retval) { if(bp) @@ -2644,7 +2631,7 @@ nsXPCComponents_Constructor::CallOrConstruct(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsXPCComponents_Constructor::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval val, PRBool *bp, + const jsval &val, PRBool *bp, PRBool *_retval) { if(bp) @@ -2839,7 +2826,7 @@ nsXPCComponents_Utils::LookupMethod() // XPCWrappedNative. This means no deep wrapping, unfortunately, but we // can't keep track of both the underlying function and the // XPCNativeWrapper at once in a single parent slot... - XPCCallContext inner_cc(JS_CALLER, cx, obj, nsnull, argv[1]); + XPCCallContext inner_cc(JS_CALLER, cx, obj, nsnull, name_id); // was our jsobject really a wrapped native at all? XPCWrappedNative* wrapper = inner_cc.GetWrapper(); @@ -3115,19 +3102,14 @@ sandbox_enumerate(JSContext *cx, JSObject *obj) } static JSBool -sandbox_getProto(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +sandbox_getProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - jsid id; - if (!JS_ValueToId(cx, idval, &id)) { - return JS_FALSE; - } - uintN attrs; return JS_CheckAccess(cx, obj, id, JSACC_PROTO, vp, &attrs); } static JSBool -sandbox_setProto(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +sandbox_setProto(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { if (!JSVAL_IS_OBJECT(*vp)) { return JS_TRUE; @@ -3135,7 +3117,7 @@ sandbox_setProto(JSContext *cx, JSObject *obj, jsval id, jsval *vp) JSObject *pobj = JSVAL_TO_OBJECT(*vp); if (pobj) { - if (pobj->getClass() == &XPCCrossOriginWrapper::XOWClass.base && + if (pobj->getJSClass() == &XPCCrossOriginWrapper::XOWClass.base && !XPCWrapper::RewrapObject(cx, obj, pobj, XPCWrapper::XPCNW_EXPLICIT, vp)) { return JS_FALSE; @@ -3146,21 +3128,16 @@ sandbox_setProto(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -sandbox_resolve(JSContext *cx, JSObject *obj, jsval idval) +sandbox_resolve(JSContext *cx, JSObject *obj, jsid id) { JSBool resolved; - if (!JS_ResolveStandardClass(cx, obj, idval, &resolved)) { + if (!JS_ResolveStandardClass(cx, obj, id, &resolved)) { return JS_FALSE; } if (resolved) { return JS_TRUE; } - jsid id; - if (!JS_ValueToId(cx, idval, &id)) { - return JS_FALSE; - } - if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_PROTO)) { return JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, sandbox_getProto, sandbox_setProto, JSPROP_SHARED); @@ -3274,7 +3251,7 @@ xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop) JSPRINCIPALS_DROP(cx, jsPrincipals); if (!sandbox) return NS_ERROR_XPC_UNEXPECTED; - js::AutoValueRooter tvr(cx, sandbox); + js::AutoObjectRooter tvr(cx, sandbox); { JSAutoCrossCompartmentCall ac; @@ -3602,7 +3579,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, #endif sandbox = XPCWrapper::UnsafeUnwrapSecurityWrapper(cx, sandbox); - if (!sandbox || sandbox->getClass() != &SandboxClass) { + if (!sandbox || sandbox->getJSClass() != &SandboxClass) { return NS_ERROR_INVALID_ARG; } @@ -4111,28 +4088,22 @@ nsXPCComponents::GetManager(nsIComponentManager * *aManager) NS_IMETHODIMP nsXPCComponents::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, PRUint32 flags, + jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) { XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); if(!rt) return NS_ERROR_FAILURE; - jsid idid; uintN attrs = 0; - if(id == rt->GetStringJSVal(XPCJSRuntime::IDX_LAST_RESULT)) - { - idid = rt->GetStringID(XPCJSRuntime::IDX_LAST_RESULT); + if(id == rt->GetStringID(XPCJSRuntime::IDX_LAST_RESULT)) attrs = JSPROP_READONLY; - } - else if(id == rt->GetStringJSVal(XPCJSRuntime::IDX_RETURN_CODE)) - idid = rt->GetStringID(XPCJSRuntime::IDX_RETURN_CODE); - else + else if(id != rt->GetStringID(XPCJSRuntime::IDX_RETURN_CODE)) return NS_OK; *objp = obj; - *_retval = JS_DefinePropertyById(cx, obj, idid, JSVAL_VOID, nsnull, nsnull, + *_retval = JS_DefinePropertyById(cx, obj, id, JSVAL_VOID, nsnull, nsnull, JSPROP_ENUMERATE | JSPROP_PERMANENT | attrs); return NS_OK; @@ -4142,7 +4113,7 @@ nsXPCComponents::NewResolve(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsXPCComponents::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, jsval * vp, PRBool *_retval) + jsid id, jsval * vp, PRBool *_retval) { XPCContext* xpcc = XPCContext::GetXPCContext(cx); if(!xpcc) @@ -4151,12 +4122,12 @@ nsXPCComponents::GetProperty(nsIXPConnectWrappedNative *wrapper, PRBool doResult = JS_FALSE; nsresult res; XPCJSRuntime* rt = xpcc->GetRuntime(); - if(id == rt->GetStringJSVal(XPCJSRuntime::IDX_LAST_RESULT)) + if(id == rt->GetStringID(XPCJSRuntime::IDX_LAST_RESULT)) { res = xpcc->GetLastResult(); doResult = JS_TRUE; } - else if(id == rt->GetStringJSVal(XPCJSRuntime::IDX_RETURN_CODE)) + else if(id == rt->GetStringID(XPCJSRuntime::IDX_RETURN_CODE)) { res = xpcc->GetPendingResult(); doResult = JS_TRUE; @@ -4173,10 +4144,10 @@ nsXPCComponents::GetProperty(nsIXPConnectWrappedNative *wrapper, return rv; } -/* PRBool setProperty (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsval id, in JSValPtr vp); */ +/* PRBool setProperty (in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsid id, in JSValPtr vp); */ NS_IMETHODIMP nsXPCComponents::SetProperty(nsIXPConnectWrappedNative *wrapper, - JSContext * cx, JSObject * obj, jsval id, + JSContext * cx, JSObject * obj, jsid id, jsval * vp, PRBool *_retval) { XPCContext* xpcc = XPCContext::GetXPCContext(cx); @@ -4187,7 +4158,7 @@ nsXPCComponents::SetProperty(nsIXPConnectWrappedNative *wrapper, if(!rt) return NS_ERROR_FAILURE; - if(id == rt->GetStringJSVal(XPCJSRuntime::IDX_RETURN_CODE)) + if(id == rt->GetStringID(XPCJSRuntime::IDX_RETURN_CODE)) { nsresult rv; if(JS_ValueToECMAUint32(cx, *vp, (uint32*)&rv)) diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index 9fc2f8009547..408e0c8515e2 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -153,7 +153,7 @@ XPCConvert::IsMethodReflectable(const XPTMethodDescriptor& info) JSBool XPCConvert::GetISupportsFromJSObject(JSObject* obj, nsISupports** iface) { - JSClass* jsclass = obj->getClass(); + JSClass* jsclass = obj->getJSClass(); NS_ASSERTION(jsclass, "obj has no class"); if(jsclass && (jsclass->flags & JSCLASS_HAS_PRIVATE) && @@ -202,13 +202,9 @@ XPCConvert::RemoveXPCOMUCStringFinalizer() } -#define FIT_32(cx,i,d) (INT_FITS_IN_JSVAL(i) \ - ? *d = INT_TO_JSVAL(i), JS_TRUE \ - : JS_NewDoubleValue(cx, i, d)) - -#define FIT_U32(cx,i,d) ((i) <= JSVAL_INT_MAX \ - ? *d = INT_TO_JSVAL(i), JS_TRUE \ - : JS_NewDoubleValue(cx, i, d)) +#define FIT_U32(i) ((i) <= JSVAL_INT_MAX \ + ? INT_TO_JSVAL(i) \ + : DOUBLE_TO_JSVAL(i)) /* * Support for 64 bit conversions where 'long long' not supported. @@ -252,19 +248,17 @@ XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s, switch(type.TagPart()) { - case nsXPTType::T_I8 : *d = INT_TO_JSVAL((int32)*((int8*)s)); break; - case nsXPTType::T_I16 : *d = INT_TO_JSVAL((int32)*((int16*)s)); break; - case nsXPTType::T_I32 : return FIT_32(cx,*((int32*)s),d); - case nsXPTType::T_I64 : - return JS_NewNumberValue(cx, INT64_TO_DOUBLE(*((int64*)s)), d); - case nsXPTType::T_U8 : *d = INT_TO_JSVAL((int32)*((uint8*)s)); break; - case nsXPTType::T_U16 : *d = INT_TO_JSVAL((int32)*((uint16*)s)); break; - case nsXPTType::T_U32 : return FIT_U32(cx,*((uint32*)s),d); - case nsXPTType::T_U64 : - return JS_NewNumberValue(cx, UINT64_TO_DOUBLE(*((uint64*)s)), d); - case nsXPTType::T_FLOAT : return JS_NewNumberValue(cx, *((float*)s), d); - case nsXPTType::T_DOUBLE: return JS_NewNumberValue(cx, *((double*)s), d); - case nsXPTType::T_BOOL : *d = *((PRBool*)s)?JSVAL_TRUE:JSVAL_FALSE; break; + case nsXPTType::T_I8 : *d = INT_TO_JSVAL((int32)*((int8*)s)); break; + case nsXPTType::T_I16 : *d = INT_TO_JSVAL((int32)*((int16*)s)); break; + case nsXPTType::T_I32 : *d = INT_TO_JSVAL(*((int32*)s)); break; + case nsXPTType::T_I64 : *d = DOUBLE_TO_JSVAL(INT64_TO_DOUBLE(*((int64*)s))); break; + case nsXPTType::T_U8 : *d = INT_TO_JSVAL((int32)*((uint8*)s)); break; + case nsXPTType::T_U16 : *d = INT_TO_JSVAL((int32)*((uint16*)s)); break; + case nsXPTType::T_U32 : *d = FIT_U32(*((uint32*)s)); break; + case nsXPTType::T_U64 : *d = DOUBLE_TO_JSVAL(UINT64_TO_DOUBLE(*((uint64*)s))); break; + case nsXPTType::T_FLOAT : *d = DOUBLE_TO_JSVAL(*((float*)s)); break; + case nsXPTType::T_DOUBLE: *d = DOUBLE_TO_JSVAL(*((double*)s)); break; + case nsXPTType::T_BOOL : *d = BOOLEAN_TO_JSVAL(*((PRBool*)s)); break; case nsXPTType::T_CHAR : { char* p = (char*)s; @@ -294,7 +288,8 @@ XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s, } case nsXPTType::T_JSVAL : - *d = *((jsval*)s); + JS_STATIC_ASSERT(sizeof(jsval) <= sizeof(uint64)); + *d = **((jsval**)s); break; default: @@ -336,7 +331,7 @@ XPCConvert::NativeData2JS(XPCLazyCallContext& lccx, jsval* d, const void* s, if(!p->IsVoid()) { jsval str = XPCStringConvert::ReadableToJSVal(cx, *p); - if(!str) + if(JSVAL_IS_NULL(str)) return JS_FALSE; *d = str; @@ -624,8 +619,16 @@ XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s, break; } case nsXPTType::T_JSVAL : - *((jsval*)d) = s; - break; + { + NS_ASSERTION(useAllocator,"trying to convert a jsval to const jsval & without allocator : this would leak"); + + // The C++ type is (const jsval &), which here means (jsval *). + jsval *buf = new jsval(s); + if (!buf) + return JS_FALSE; + *((jsval**)d) = buf; + break; + } default: if(!type.IsPointer()) { @@ -1602,7 +1605,7 @@ public: ~AutoExceptionRestorer() { - JS_SetPendingException(mContext, tvr.value()); + JS_SetPendingException(mContext, tvr.jsval_value()); } private: @@ -1738,7 +1741,7 @@ XPCConvert::JSValToXPCException(XPCCallContext& ccx, } else { - number = *(JSVAL_TO_DOUBLE(s)); + number = JSVAL_TO_DOUBLE(s); if(number > 0.0 && number < (double)0xffffffff && 0.0 == fmod(number,1)) @@ -2261,7 +2264,7 @@ XPCConvert::JSStringWithSize2Native(XPCCallContext& ccx, void* d, jsval s, JSBool useAllocator, uintN* pErr) { - NS_PRECONDITION(s, "bad param"); + NS_PRECONDITION(!JSVAL_IS_NULL(s), "bad param"); NS_PRECONDITION(d, "bad param"); JSContext* cx = ccx.GetJSContext(); diff --git a/js/src/xpconnect/src/xpcinlines.h b/js/src/xpconnect/src/xpcinlines.h index 046f07fa957c..5cba71ae302e 100644 --- a/js/src/xpconnect/src/xpcinlines.h +++ b/js/src/xpconnect/src/xpcinlines.h @@ -257,7 +257,7 @@ XPCCallContext::HasInterfaceAndMember() const ); } -inline jsval +inline jsid XPCCallContext::GetName() const { CHECK_STATE(HAVE_NAME); @@ -307,15 +307,15 @@ XPCCallContext::SetRetVal(jsval val) *mRetVal = val; } -inline jsval +inline jsid XPCCallContext::GetResolveName() const { CHECK_STATE(HAVE_CONTEXT); return mThreadData->GetResolveName(); } -inline jsval -XPCCallContext::SetResolveName(jsval name) +inline jsid +XPCCallContext::SetResolveName(jsid name) { CHECK_STATE(HAVE_CONTEXT); return mThreadData->SetResolveName(name); @@ -396,7 +396,7 @@ XPCNativeInterface::GetNameString() const } inline XPCNativeMember* -XPCNativeInterface::FindMember(jsval name) const +XPCNativeInterface::FindMember(jsid name) const { const XPCNativeMember* member = mMembers; for(int i = (int) mMemberCount; i > 0; i--, member++) @@ -424,7 +424,7 @@ XPCNativeInterface::DealWithDyingGCThings(JSContext* cx, XPCJSRuntime* rt) /***************************************************************************/ inline JSBool -XPCNativeSet::FindMember(jsval name, XPCNativeMember** pMember, +XPCNativeSet::FindMember(jsid name, XPCNativeMember** pMember, PRUint16* pInterfaceIndex) const { XPCNativeInterface* const * iface; @@ -462,7 +462,7 @@ XPCNativeSet::FindMember(jsval name, XPCNativeMember** pMember, } inline JSBool -XPCNativeSet::FindMember(jsval name, XPCNativeMember** pMember, +XPCNativeSet::FindMember(jsid name, XPCNativeMember** pMember, XPCNativeInterface** pInterface) const { PRUint16 index; @@ -473,7 +473,7 @@ XPCNativeSet::FindMember(jsval name, XPCNativeMember** pMember, } inline JSBool -XPCNativeSet::FindMember(jsval name, +XPCNativeSet::FindMember(jsid name, XPCNativeMember** pMember, XPCNativeInterface** pInterface, XPCNativeSet* protoSet, @@ -501,7 +501,7 @@ XPCNativeSet::FindMember(jsval name, } inline XPCNativeInterface* -XPCNativeSet::FindNamedInterface(jsval name) const +XPCNativeSet::FindNamedInterface(jsid name) const { XPCNativeInterface* const * pp = mInterfaces; @@ -717,13 +717,11 @@ XPCWrappedNative::SweepTearOffs() /***************************************************************************/ inline JSBool -xpc_ForcePropertyResolve(JSContext* cx, JSObject* obj, jsval idval) +xpc_ForcePropertyResolve(JSContext* cx, JSObject* obj, jsid id) { jsval prop; - jsid id; - if(!JS_ValueToId(cx, idval, &id) || - !JS_LookupPropertyById(cx, obj, id, &prop)) + if(!JS_LookupPropertyById(cx, obj, id, &prop)) return JS_FALSE; return JS_TRUE; } @@ -776,7 +774,7 @@ GetRTIdByIndex(JSContext *cx, uintN index) inline jsval GetRTStringByIndex(JSContext *cx, uintN index) { - return ID_TO_VALUE(GetRTIdByIndex(cx, index)); + return STRING_TO_JSVAL(JSID_TO_STRING(GetRTIdByIndex(cx, index))); } inline diff --git a/js/src/xpconnect/src/xpcjsid.cpp b/js/src/xpconnect/src/xpcjsid.cpp index a2c10b32762f..7f4783ae34e1 100644 --- a/js/src/xpconnect/src/xpcjsid.cpp +++ b/js/src/xpconnect/src/xpcjsid.cpp @@ -429,7 +429,7 @@ nsJSIID::NewID(nsIInterfaceInfo* aInfo) NS_IMETHODIMP nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, PRUint32 flags, + jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) { XPCCallContext ccx(JS_CALLER, cx); @@ -451,12 +451,8 @@ nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper, if(!member->GetConstantValue(ccx, iface, &val)) return NS_ERROR_OUT_OF_MEMORY; - jsid idid; - if(!JS_ValueToId(cx, id, &idid)) - return NS_ERROR_OUT_OF_MEMORY; - *objp = obj; - *_retval = JS_DefinePropertyById(cx, obj, idid, val, nsnull, nsnull, + *_retval = JS_DefinePropertyById(cx, obj, id, val, nsnull, nsnull, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); } @@ -500,7 +496,7 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsJSIID::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval val, PRBool *bp, PRBool *_retval) + const jsval &val, PRBool *bp, PRBool *_retval) { *bp = JS_FALSE; nsresult rv = NS_OK; @@ -875,7 +871,7 @@ nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper, // 'push' a call context and call on it XPCCallContext ccx(JS_CALLER, cx, obj, nsnull, - rt->GetStringJSVal(XPCJSRuntime::IDX_CREATE_INSTANCE), + rt->GetStringID(XPCJSRuntime::IDX_CREATE_INSTANCE), argc, argv, vp); *_retval = XPCWrappedNative::CallMethod(ccx); @@ -886,7 +882,7 @@ nsJSCID::Construct(nsIXPConnectWrappedNative *wrapper, NS_IMETHODIMP nsJSCID::HasInstance(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval val, PRBool *bp, PRBool *_retval) + const jsval &val, PRBool *bp, PRBool *_retval) { *bp = JS_FALSE; nsresult rv = NS_OK; diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index 6faeb3e60c50..487b04fdaf7e 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -1121,7 +1121,7 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect) DOM_InitInterfaces(); // these jsids filled in later when we have a JSContext to work with. - mStrIDs[0] = 0; + mStrIDs[0] = JSID_VOID; mJSRuntime = JS_NewRuntime(32L * 1024L * 1024L); // pref ? if(mJSRuntime) @@ -1197,7 +1197,7 @@ XPCJSRuntime::OnJSContextNew(JSContext *cx) // if it is our first context then we need to generate our string ids JSBool ok = JS_TRUE; - if(!mStrIDs[0]) + if(JSID_IS_VOID(mStrIDs[0])) { JS_SetGCParameterForThread(cx, JSGC_MAX_CODE_CACHE_BYTES, 16 * 1024 * 1024); JSAutoRequest ar(cx); @@ -1206,7 +1206,7 @@ XPCJSRuntime::OnJSContextNew(JSContext *cx) JSString* str = JS_InternString(cx, mStrings[i]); if(!str || !JS_ValueToId(cx, STRING_TO_JSVAL(str), &mStrIDs[i])) { - mStrIDs[0] = 0; + mStrIDs[0] = JSID_VOID; ok = JS_FALSE; break; } diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index a061ef827659..20893cb70a10 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -260,6 +260,8 @@ extern const char XPC_XPCONNECT_CONTRACTID[]; #define WRAPPER_SLOTS (JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1)) +#define INVALID_OBJECT ((JSObject *)1) + /***************************************************************************/ // Auto locking support class... @@ -941,7 +943,7 @@ public: JSContext* cx = nsnull, JSObject* obj = nsnull, JSObject* funobj = nsnull, - jsval id = 0, + jsid id = JSID_VOID, uintN argc = NO_ARGS, jsval *argv = nsnull, jsval *rval = nsnull); @@ -979,7 +981,7 @@ public: inline XPCNativeInterface* GetInterface() const ; inline XPCNativeMember* GetMember() const ; inline JSBool HasInterfaceAndMember() const ; - inline jsval GetName() const ; + inline jsid GetName() const ; inline JSBool GetStaticMemberIsLocal() const ; inline uintN GetArgc() const ; inline jsval* GetArgv() const ; @@ -992,8 +994,8 @@ public: inline JSBool GetDestroyJSContextInDestructor() const; inline void SetDestroyJSContextInDestructor(JSBool b); - inline jsval GetResolveName() const; - inline jsval SetResolveName(jsval name); + inline jsid GetResolveName() const; + inline jsid SetResolveName(jsid name); inline XPCWrappedNative* GetResolvingWrapper() const; inline XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w); @@ -1003,7 +1005,7 @@ public: inline JSObject* GetCallee() const; inline void SetCallee(JSObject* callee); - void SetName(jsval name); + void SetName(jsid name); void SetArgsAndResultPtr(uintN argc, jsval *argv, jsval *rval); void SetCallInfo(XPCNativeInterface* iface, XPCNativeMember* member, JSBool isSetter); @@ -1046,7 +1048,7 @@ private: JSObject* obj, JSObject* funobj, JSBool getWrappedNative, - jsval name, + jsid name, uintN argc, jsval *argv, jsval *rval); @@ -1101,7 +1103,7 @@ private: XPCNativeInterface* mInterface; XPCNativeMember* mMember; - jsval mName; + jsid mName; JSBool mStaticMemberIsLocal; uintN mArgc; @@ -1275,7 +1277,7 @@ extern JSClass XPC_WN_Tearoff_JSClass; extern JSClass XPC_WN_NoHelper_Proto_JSClass; extern JSBool -XPC_WN_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp); +XPC_WN_Equality(JSContext *cx, JSObject *obj, const jsval *v, JSBool *bp); extern JSObjectOps * XPC_WN_Proto_GetObjectOps(JSContext *cx, JSClass *clazz); @@ -1328,10 +1330,10 @@ DebugCheckWrapperClass(JSObject* obj) // Only use these macros if IS_WRAPPER_CLASS(obj->getClass()) is true. #define IS_WN_WRAPPER_OBJECT(obj) \ (DebugCheckWrapperClass(obj) && \ - JSVAL_IS_VOID(obj->getSlot(JSSLOT_START(obj->getClass())))) + obj->getSlot(JSSLOT_START(obj->getClass())).isUndefined()) #define IS_SLIM_WRAPPER_OBJECT(obj) \ (DebugCheckWrapperClass(obj) && \ - !JSVAL_IS_VOID(obj->getSlot(JSSLOT_START(obj->getClass())))) + !obj->getSlot(JSSLOT_START(obj->getClass())).isUndefined()) // Use these macros if IS_WRAPPER_CLASS(obj->getClass()) might be false. // Avoid calling them if IS_WRAPPER_CLASS(obj->getClass()) can only be @@ -1548,7 +1550,7 @@ public: XPCNativeInterface** pInterface, XPCNativeMember** pMember); - jsval GetName() const {return mName;} + jsid GetName() const {return mName;} PRUint16 GetIndex() const {return mIndex;} @@ -1578,7 +1580,7 @@ public: {return IsAttribute() && !IsWritableAttribute();} - void SetName(jsval a) {mName = a;} + void SetName(jsid a) {mName = a;} void SetMethod(PRUint16 index) {mVal = JSVAL_NULL; mFlags = METHOD; mIndex = index;} @@ -1615,7 +1617,7 @@ private: private: // our only data... - jsval mName; + jsid mName; jsval mVal; PRUint16 mIndex; PRUint16 mFlags; @@ -1639,11 +1641,11 @@ public: static XPCNativeInterface* GetISupports(XPCCallContext& ccx); inline nsIInterfaceInfo* GetInterfaceInfo() const {return mInfo.get();} - inline jsval GetName() const {return mName;} + inline jsid GetName() const {return mName;} inline const nsIID* GetIID() const; inline const char* GetNameString() const; - inline XPCNativeMember* FindMember(jsval name) const; + inline XPCNativeMember* FindMember(jsid name) const; inline JSBool HasAncestor(const nsIID* iid) const; @@ -1677,7 +1679,7 @@ protected: nsIInterfaceInfo* aInfo); XPCNativeInterface(); // not implemented - XPCNativeInterface(nsIInterfaceInfo* aInfo, jsval aName) + XPCNativeInterface(nsIInterfaceInfo* aInfo, jsid aName) : mInfo(aInfo), mName(aName), mMemberCount(0) {MOZ_COUNT_CTOR(XPCNativeInterface);} ~XPCNativeInterface() {MOZ_COUNT_DTOR(XPCNativeInterface);} @@ -1689,7 +1691,7 @@ protected: private: nsCOMPtr mInfo; - jsval mName; + jsid mName; PRUint16 mMemberCount; XPCNativeMember mMembers[1]; // always last - object sized for array }; @@ -1760,13 +1762,13 @@ public: static void ClearCacheEntryForClassInfo(nsIClassInfo* classInfo); - inline JSBool FindMember(jsval name, XPCNativeMember** pMember, + inline JSBool FindMember(jsid name, XPCNativeMember** pMember, PRUint16* pInterfaceIndex) const; - inline JSBool FindMember(jsval name, XPCNativeMember** pMember, + inline JSBool FindMember(jsid name, XPCNativeMember** pMember, XPCNativeInterface** pInterface) const; - inline JSBool FindMember(jsval name, + inline JSBool FindMember(jsid name, XPCNativeMember** pMember, XPCNativeInterface** pInterface, XPCNativeSet* protoSet, @@ -1778,7 +1780,7 @@ public: inline XPCNativeInterface* FindInterfaceWithIID(const nsIID& iid) const; - inline XPCNativeInterface* FindNamedInterface(jsval name) const; + inline XPCNativeInterface* FindNamedInterface(jsid name) const; PRUint16 GetMemberCount() const {return mMemberCount;} PRUint16 GetInterfaceCount() const @@ -2247,8 +2249,8 @@ extern JSBool MorphSlimWrapper(JSContext *cx, JSObject *obj); static inline XPCWrappedNativeProto* GetSlimWrapperProto(JSObject *obj) { - jsval v = obj->getSlot(JSSLOT_START(obj->getClass())); - return static_cast(JSVAL_TO_PRIVATE(v)); + const js::Value &v = obj->getSlot(JSSLOT_START(obj->getClass())); + return static_cast(v.toPrivate()); } @@ -2535,12 +2537,12 @@ public: HandlePossibleNameCaseError(XPCCallContext& ccx, XPCNativeSet* set, XPCNativeInterface* iface, - jsval name); + jsid name); static void HandlePossibleNameCaseError(JSContext* cx, XPCNativeSet* set, XPCNativeInterface* iface, - jsval name); + jsid name); #define HANDLE_POSSIBLE_NAME_CASE_ERROR(context, set, iface, name) \ XPCWrappedNative::HandlePossibleNameCaseError(context, set, iface, name) @@ -2592,8 +2594,8 @@ public: // needs us alive and whole. Do not let our mFlatJSObject go away. // This is the only time we should be tracing our mFlatJSObject, // normally somebody else is doing that. Be careful not to trace the - // bogus JSVAL_ONE value we can have during init, though. - if(mFlatJSObject && mFlatJSObject != (JSObject*)JSVAL_ONE) + // bogus INVALID_OBJECT value we can have during init, though. + if(mFlatJSObject && mFlatJSObject != INVALID_OBJECT) { JS_CALL_OBJECT_TRACER(trc, mFlatJSObject, "XPCWrappedNative::mFlatJSObject"); @@ -2630,7 +2632,7 @@ public: JSObject* GetWrapper() { - return (JSObject *) JSVAL_CLRTAG(mWrapperWord); + return (JSObject *) (mWrapperWord & (size_t)~(size_t)FLAG_MASK); } void SetWrapper(JSObject *obj) { @@ -2681,7 +2683,9 @@ private: NEEDS_COW = JS_BIT(1), NEEDS_XOW = JS_BIT(2), - LAST_FLAG = NEEDS_XOW + LAST_FLAG = NEEDS_XOW, + + FLAG_MASK = 0x7 }; protected: @@ -3558,9 +3562,9 @@ public: XPCCallContext* SetCallContext(XPCCallContext* ccx) {XPCCallContext* old = mCallContext; mCallContext = ccx; return old;} - jsval GetResolveName() const {return mResolveName;} - jsval SetResolveName(jsval name) - {jsval old = mResolveName; mResolveName = name; return old;} + jsid GetResolveName() const {return mResolveName;} + jsid SetResolveName(jsid name) + {jsid old = mResolveName; mResolveName = name; return old;} XPCWrappedNative* GetResolvingWrapper() const {return mResolvingWrapper;} XPCWrappedNative* SetResolvingWrapper(XPCWrappedNative* w) @@ -3605,7 +3609,7 @@ private: XPCJSContextStack* mJSContextStack; XPCPerThreadData* mNextThread; XPCCallContext* mCallContext; - jsval mResolveName; + jsid mResolveName; XPCWrappedNative* mResolvingWrapper; nsIExceptionManager* mExceptionManager; @@ -3897,7 +3901,7 @@ private: class NS_STACK_CLASS AutoResolveName { public: - AutoResolveName(XPCCallContext& ccx, jsval name + AutoResolveName(XPCCallContext& ccx, jsid name MOZILLA_GUARD_OBJECT_NOTIFIER_PARAM) : mTLS(ccx.GetThreadData()), mOld(mTLS->SetResolveName(name)), @@ -3907,7 +3911,7 @@ public: ~AutoResolveName() { #ifdef DEBUG - jsval old = + jsid old = #endif mTLS->SetResolveName(mOld); NS_ASSERTION(old == mCheck, "Bad Nesting!"); @@ -3915,8 +3919,8 @@ public: private: XPCPerThreadData* mTLS; - jsval mOld; - jsval mCheck; + jsid mOld; + jsid mCheck; MOZILLA_DECL_USE_GUARD_OBJECT_NOTIFIER }; @@ -3925,7 +3929,7 @@ class XPCMarkableJSVal { public: XPCMarkableJSVal(jsval val) : mVal(val), mValPtr(&mVal) {} - XPCMarkableJSVal(jsval *pval) : mVal(0), mValPtr(pval) {} + XPCMarkableJSVal(jsval *pval) : mVal(JSVAL_VOID), mValPtr(pval) {} ~XPCMarkableJSVal() {} void Mark() {} void TraceJS(JSTracer* trc) @@ -4274,7 +4278,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source, // Inlined utilities. inline JSBool -xpc_ForcePropertyResolve(JSContext* cx, JSObject* obj, jsval idval); +xpc_ForcePropertyResolve(JSContext* cx, JSObject* obj, jsid id); inline jsid GetRTIdByIndex(JSContext *cx, uintN index); diff --git a/js/src/xpconnect/src/xpcquickstubs.cpp b/js/src/xpconnect/src/xpcquickstubs.cpp index 72268233d0cc..ef2e28aede80 100644 --- a/js/src/xpconnect/src/xpcquickstubs.cpp +++ b/js/src/xpconnect/src/xpcquickstubs.cpp @@ -140,8 +140,11 @@ PropertyOpForwarder(JSContext *cx, uintN argc, jsval *vp) return JS_FALSE; jsval argval = (argc > 0) ? JS_ARGV(cx, vp)[0] : JSVAL_VOID; + jsid id; + if (!JS_ValueToId(cx, argval, &id)) + return JS_FALSE; JS_SET_RVAL(cx, vp, argval); - return (*popp)(cx, obj, v, vp); + return (*popp)(cx, obj, id, vp); } static void @@ -293,10 +296,10 @@ LookupGetterOrSetter(JSContext *cx, JSBool wantGetter, uintN argc, jsval *vp) ? JS_GetStringBytes(JSVAL_TO_STRING(idval)) : nsnull; if(!name || - !IS_PROTO_CLASS(desc.obj->getClass()) || + !IS_PROTO_CLASS(desc.obj->getJSClass()) || (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) || !(desc.getter || desc.setter) || - desc.setter == desc.obj->getClass()->setProperty) + desc.setter == desc.obj->getJSClass()->setProperty) { JS_SET_RVAL(cx, vp, JSVAL_VOID); return JS_TRUE; @@ -339,7 +342,8 @@ DefineGetterOrSetter(JSContext *cx, uintN argc, JSBool wantGetter, jsval *vp) JSObject *obj = JS_THIS_OBJECT(cx, vp); if (!obj) return JS_FALSE; - JSFastNative forward = wantGetter ? js_obj_defineGetter : js_obj_defineSetter; + JSFastNative forward = wantGetter ? Jsvalify(js_obj_defineGetter) + : Jsvalify(js_obj_defineSetter); jsval id = (argc >= 1) ? JS_ARGV(cx, vp)[0] : JSVAL_VOID; if(!JSVAL_IS_STRING(id)) return forward(cx, argc, vp); @@ -359,7 +363,7 @@ DefineGetterOrSetter(JSContext *cx, uintN argc, JSBool wantGetter, jsval *vp) if(!obj2 || (attrs & (JSPROP_GETTER | JSPROP_SETTER)) || !(getter || setter) || - !IS_PROTO_CLASS(obj2->getClass())) + !IS_PROTO_CLASS(obj2->getJSClass())) return forward(cx, argc, vp); // Reify the getter and setter... @@ -489,7 +493,7 @@ xpc_qsThrow(JSContext *cx, nsresult rv) */ static void GetMemberInfo(JSObject *obj, - jsval memberId, + jsid memberId, const char **ifaceName, const char **memberName) { @@ -500,8 +504,8 @@ GetMemberInfo(JSObject *obj, // but this code often produces a more specific error message, e.g. *ifaceName = "Unknown"; - NS_ASSERTION(IS_WRAPPER_CLASS(obj->getClass()) || - obj->getClass() == &XPC_WN_Tearoff_JSClass, + NS_ASSERTION(IS_WRAPPER_CLASS(obj->getJSClass()) || + obj->getJSClass() == &XPC_WN_Tearoff_JSClass, "obj must be a wrapper"); XPCWrappedNativeProto *proto; if(IS_SLIM_WRAPPER(obj)) @@ -526,8 +530,8 @@ GetMemberInfo(JSObject *obj, } } - *memberName = (JSVAL_IS_STRING(memberId) - ? JS_GetStringBytes(JSVAL_TO_STRING(memberId)) + *memberName = (JSID_IS_STRING(memberId) + ? JS_GetStringBytes(JSID_TO_STRING(memberId)) : "unknown"); } @@ -541,7 +545,7 @@ GetMethodInfo(JSContext *cx, NS_ASSERTION(JS_ObjectIsFunction(cx, funobj), "JSFastNative callee should be Function object"); JSString *str = JS_GetFunctionId((JSFunction *) JS_GetPrivate(cx, funobj)); - jsval methodId = str ? STRING_TO_JSVAL(str) : JSVAL_NULL; + jsid methodId = str ? INTERNED_STRING_TO_JSID(str) : JSID_VOID; GetMemberInfo(JSVAL_TO_OBJECT(vp[1]), methodId, ifaceName, memberName); } @@ -595,7 +599,7 @@ ThrowCallFailed(JSContext *cx, nsresult rv, JSBool xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, JSObject *obj, - jsval memberId) + jsid memberId) { const char *ifaceName, *memberName; GetMemberInfo(obj, memberId, &ifaceName, &memberName); @@ -668,7 +672,7 @@ xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, uintN paramnum, void xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, - JSObject *obj, jsval propId) + JSObject *obj, jsid propId) { const char *ifaceName, *memberName; GetMemberInfo(obj, propId, &ifaceName, &memberName); @@ -676,7 +680,7 @@ xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, } JSBool -xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { return JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT | @@ -1068,12 +1072,29 @@ xpc_qsStringToJsval(JSContext *cx, const nsAString &str, jsval *rval) } jsval jsstr = XPCStringConvert::ReadableToJSVal(cx, str); - if(!jsstr) + if(JSVAL_IS_NULL(jsstr)) return JS_FALSE; *rval = jsstr; return JS_TRUE; } +JSBool +xpc_qsStringToJsstring(JSContext *cx, const nsAString &str, JSString **rval) +{ + // From the T_DOMSTRING case in XPCConvert::NativeData2JS. + if(str.IsVoid()) + { + *rval = nsnull; + return JS_TRUE; + } + + jsval jsstr = XPCStringConvert::ReadableToJSVal(cx, str); + if(JSVAL_IS_NULL(jsstr)) + return JS_FALSE; + *rval = JSVAL_TO_STRING(jsstr); + return JS_TRUE; +} + JSBool xpc_qsXPCOMObjectToJsval(XPCLazyCallContext &lccx, nsISupports *p, nsWrapperCache *cache, const nsIID *iid, diff --git a/js/src/xpconnect/src/xpcquickstubs.h b/js/src/xpconnect/src/xpcquickstubs.h index 4740d4689019..b8a401e4619c 100644 --- a/js/src/xpconnect/src/xpcquickstubs.h +++ b/js/src/xpconnect/src/xpcquickstubs.h @@ -100,7 +100,7 @@ xpc_qsThrow(JSContext *cx, nsresult rv); */ JSBool xpc_qsThrowGetterSetterFailed(JSContext *cx, nsresult rv, - JSObject *obj, jsval memberId); + JSObject *obj, jsid memberId); /** * Fail after an XPCOM method returned rv. @@ -140,34 +140,29 @@ xpc_qsThrowBadArgWithDetails(JSContext *cx, nsresult rv, uintN paramnum, */ void xpc_qsThrowBadSetterValue(JSContext *cx, nsresult rv, JSObject *obj, - jsval propId); + jsid propId); JSBool -xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +xpc_qsGetterOnlyPropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp); /* Functions for converting values between COM and JS. */ inline JSBool xpc_qsInt32ToJsval(JSContext *cx, PRInt32 i, jsval *rv) { - if(INT_FITS_IN_JSVAL(i)) - { - *rv = INT_TO_JSVAL(i); - return JS_TRUE; - } - return JS_NewDoubleValue(cx, i, rv); + *rv = INT_TO_JSVAL(i); + return JS_TRUE; } inline JSBool xpc_qsUint32ToJsval(JSContext *cx, PRUint32 u, jsval *rv) { if(u <= JSVAL_INT_MAX) - { *rv = INT_TO_JSVAL(u); - return JS_TRUE; - } - return JS_NewDoubleValue(cx, u, rv); + else + *rv = DOUBLE_TO_JSVAL(u); + return JS_TRUE; } #ifdef HAVE_LONG_LONG @@ -351,6 +346,10 @@ xpc_qsJsvalToWcharStr(JSContext *cx, jsval v, jsval *pval, PRUnichar **pstr); JSBool xpc_qsStringToJsval(JSContext *cx, const nsAString &str, jsval *rval); +/** Convert an nsAString to JSString, returning JS_TRUE on success. */ +JSBool +xpc_qsStringToJsstring(JSContext *cx, const nsAString &str, JSString **rval); + nsresult getWrapper(JSContext *cx, JSObject *obj, diff --git a/js/src/xpconnect/src/xpcruntimesvc.cpp b/js/src/xpconnect/src/xpcruntimesvc.cpp index 870c527532d3..f3c9bbdff1d9 100644 --- a/js/src/xpconnect/src/xpcruntimesvc.cpp +++ b/js/src/xpconnect/src/xpcruntimesvc.cpp @@ -69,7 +69,7 @@ NS_IMPL_THREADSAFE_RELEASE(BackstagePass) NS_IMETHODIMP BackstagePass::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext * cx, JSObject * obj, - jsval id, PRUint32 flags, + jsid id, PRUint32 flags, JSObject * *objp, PRBool *_retval) { JSBool resolved; diff --git a/js/src/xpconnect/src/xpcstring.cpp b/js/src/xpconnect/src/xpcstring.cpp index f5a86846bab2..027f6effab7f 100644 --- a/js/src/xpconnect/src/xpcstring.cpp +++ b/js/src/xpconnect/src/xpcstring.cpp @@ -86,8 +86,7 @@ XPCStringConvert::ReadableToJSVal(JSContext *cx, JSAtom *atom; if (length == 0 && (atom = cx->runtime->atomState.emptyAtom)) { - NS_ASSERTION(ATOM_IS_STRING(atom), "What kind of atom is this?"); - return ATOM_KEY(atom); + return ATOM_TO_JSVAL(atom); } nsStringBuffer *buf = nsStringBuffer::FromString(readable); diff --git a/js/src/xpconnect/src/xpcthreadcontext.cpp b/js/src/xpconnect/src/xpcthreadcontext.cpp index 76cee9012cee..41fd5dedc66a 100644 --- a/js/src/xpconnect/src/xpcthreadcontext.cpp +++ b/js/src/xpconnect/src/xpcthreadcontext.cpp @@ -189,7 +189,7 @@ XPCJSContextStack::DEBUG_StackHasJSContext(JSContext* aJSContext) #endif static JSBool -SafeGlobalResolve(JSContext *cx, JSObject *obj, jsval id) +SafeGlobalResolve(JSContext *cx, JSObject *obj, jsid id) { JSBool resolved; return JS_ResolveStandardClass(cx, obj, id, &resolved); @@ -331,7 +331,7 @@ XPCPerThreadData::XPCPerThreadData() : mJSContextStack(new XPCJSContextStack()), mNextThread(nsnull), mCallContext(nsnull), - mResolveName(0), + mResolveName(JSID_VOID), mResolvingWrapper(nsnull), mExceptionManager(nsnull), mException(nsnull), diff --git a/js/src/xpconnect/src/xpcthrower.cpp b/js/src/xpconnect/src/xpcthrower.cpp index 3ee85b9c5786..dd8b21fafcb1 100644 --- a/js/src/xpconnect/src/xpcthrower.cpp +++ b/js/src/xpconnect/src/xpcthrower.cpp @@ -189,9 +189,9 @@ XPCThrower::Verbosify(XPCCallContext& ccx, { XPCDispInterface::Member * member = reinterpret_cast(ccx.GetIDispatchMember()); - if(member && JSVAL_IS_STRING(member->GetName())) + if(member && JSID_IS_STRING(member->GetName())) { - name = JS_GetStringBytes(JSVAL_TO_STRING(member->GetName())); + name = JS_GetStringBytes(JSID_TO_STRING(member->GetName())); } else name = "Unknown"; diff --git a/js/src/xpconnect/src/xpcvariant.cpp b/js/src/xpconnect/src/xpcvariant.cpp index aff534006317..74b7555418e3 100644 --- a/js/src/xpconnect/src/xpcvariant.cpp +++ b/js/src/xpconnect/src/xpcvariant.cpp @@ -88,7 +88,7 @@ XPCTraceableVariant::~XPCTraceableVariant() if(!JSVAL_IS_STRING(mJSVal)) nsVariant::Cleanup(&mData); - if(!JSVAL_IS_NULL(mJSVal)) + if (!JSVAL_IS_NULL(mJSVal)) RemoveFromRootSet(nsXPConnect::GetRuntimeInstance()->GetJSRuntime()); } @@ -303,7 +303,7 @@ JSBool XPCVariant::InitializeData(XPCCallContext& ccx) JSVAL_TO_INT(mJSVal))); if(JSVAL_IS_DOUBLE(mJSVal)) return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData, - *JSVAL_TO_DOUBLE(mJSVal))); + JSVAL_TO_DOUBLE(mJSVal))); if(JSVAL_IS_BOOLEAN(mJSVal)) return NS_SUCCEEDED(nsVariant::SetFromBool(&mData, JSVAL_TO_BOOLEAN(mJSVal))); diff --git a/js/src/xpconnect/src/xpcwrappedjs.cpp b/js/src/xpconnect/src/xpcwrappedjs.cpp index 87af0758be4b..c25ce29947f2 100644 --- a/js/src/xpconnect/src/xpcwrappedjs.cpp +++ b/js/src/xpconnect/src/xpcwrappedjs.cpp @@ -621,7 +621,7 @@ nsXPCWrappedJS::GetProperty(const nsAString & name, nsIVariant **_retval) return NS_ERROR_UNEXPECTED; jsval jsstr = XPCStringConvert::ReadableToJSVal(ccx, name); - if(!jsstr) + if(JSVAL_IS_NULL(jsstr)) return NS_ERROR_OUT_OF_MEMORY; return nsXPCWrappedJSClass:: diff --git a/js/src/xpconnect/src/xpcwrappedjsclass.cpp b/js/src/xpconnect/src/xpcwrappedjsclass.cpp index c128e0605246..a36ca758187d 100644 --- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp +++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp @@ -357,7 +357,7 @@ nsXPCWrappedJSClass::CallQueryInterfaceOnJSObject(XPCCallContext& ccx, { // JS often throws an nsresult. if(JSVAL_IS_DOUBLE(jsexception)) - rv = (nsresult)(*JSVAL_TO_DOUBLE(jsexception)); + rv = (nsresult)(JSVAL_TO_DOUBLE(jsexception)); else rv = (nsresult)(JSVAL_TO_INT(jsexception)); @@ -1470,7 +1470,7 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWrappedJS* wrapper, uint16 methodIndex, goto pre_call_clean_up; } - sp = stackbase = args.getvp(); + sp = stackbase = Jsvalify(args.getvp()); // this is a function call, so push function and 'this' if(invokeCall) @@ -1677,6 +1677,7 @@ pre_call_clean_up: JS_ClearPendingException(cx); + /* On success, the return value is placed in |*stackbase|. */ /* On success, the return value is placed in |*stackbase|. */ if(XPT_MD_IS_GETTER(info->flags)) success = JS_GetProperty(cx, obj, name, stackbase); @@ -1686,7 +1687,7 @@ pre_call_clean_up: { if(!JSVAL_IS_PRIMITIVE(fval)) { - success = js_Invoke(cx, args, 0); + success = js::InvokeFriendAPI(cx, args, 0); } else { diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index 0eb5b6ff9734..d06ba6d3e202 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -854,11 +854,10 @@ XPCWrappedNative::XPCWrappedNative(already_AddRefed aIdentity, XPCWrappedNativeProto* aProto) : mMaybeProto(aProto), mSet(aProto->GetSet()), - mFlatJSObject((JSObject*)JSVAL_ONE), // non-null to pass IsValid() test + mFlatJSObject(INVALID_OBJECT), // non-null to pass IsValid() test mScriptableInfo(nsnull), mWrapperWord(0) { - PR_STATIC_ASSERT(LAST_FLAG & JSVAL_TAGMASK); mIdentity = aIdentity.get(); NS_ASSERTION(mMaybeProto, "bad ctor param"); @@ -874,7 +873,7 @@ XPCWrappedNative::XPCWrappedNative(already_AddRefed aIdentity, : mMaybeScope(TagScope(aScope)), mSet(aSet), - mFlatJSObject((JSObject*)JSVAL_ONE), // non-null to pass IsValid() test + mFlatJSObject(INVALID_OBJECT), // non-null to pass IsValid() test mScriptableInfo(nsnull), mWrapperWord(0) { @@ -1682,7 +1681,7 @@ XPCWrappedNative::GetWrappedNativeOfJSObject(JSContext* cx, JSObject* funObjParent = funobj->getParent(); NS_ASSERTION(funObjParent, "funobj has no parent"); - JSClass* funObjParentClass = funObjParent->getClass(); + JSClass* funObjParentClass = funObjParent->getJSClass(); if(IS_PROTO_CLASS(funObjParentClass)) { @@ -1713,7 +1712,7 @@ XPCWrappedNative::GetWrappedNativeOfJSObject(JSContext* cx, { // this is on two lines to make the compiler happy given the goto. JSClass* clazz; - clazz = cur->getClass(); + clazz = cur->getJSClass(); if(IS_WRAPPER_CLASS(clazz)) { @@ -1770,7 +1769,7 @@ return_tearoff: // If we didn't find a wrapper using the given funobj and obj, try // again with obj's outer object, if it's got one. - JSClass *clazz = obj->getClass(); + JSClass *clazz = obj->getJSClass(); if((clazz->flags & JSCLASS_IS_EXTENDED) && ((JSExtendedClass*)clazz)->outerObject) @@ -2402,19 +2401,23 @@ CallMethodHelper::~CallMethodHelper() // always free the array itself nsMemory::Free(p); } - else if(dp->IsValAllocated()) - nsMemory::Free(p); - else if(dp->IsValInterface()) - ((nsISupports*)p)->Release(); - else if(dp->IsValDOMString()) - mCallContext.DeleteString((nsAString*)p); - else if(dp->IsValUTF8String()) - delete (nsCString*) p; - else if(dp->IsValCString()) - delete (nsCString*) p; - else if(dp->IsValJSRoot()) - JS_RemoveValueRoot(mCallContext, (jsval*)dp->ptr); - } + else + { + if(dp->IsValJSRoot()) + JS_RemoveValueRoot(mCallContext, (jsval*)dp->ptr); + + if(dp->IsValAllocated()) + nsMemory::Free(p); + else if(dp->IsValInterface()) + ((nsISupports*)p)->Release(); + else if(dp->IsValDOMString()) + mCallContext.DeleteString((nsAString*)p); + else if(dp->IsValUTF8String()) + delete (nsCString*) p; + else if(dp->IsValCString()) + delete (nsCString*) p; + } + } } } @@ -2794,11 +2797,13 @@ CallMethodHelper::ConvertIndependentParams(JSBool* foundDependentParam) } else { - jsval *rootp = (jsval *)&dp->val.p; + JS_STATIC_ASSERT(sizeof(jsval) <= sizeof(uint64)); + jsval *rootp = (jsval *)&dp->val.u64; dp->ptr = rootp; *rootp = JSVAL_VOID; if (!JS_AddValueRoot(mCallContext, rootp)) return JS_FALSE; + dp->SetValIsJSRoot(); } } @@ -2879,6 +2884,11 @@ CallMethodHelper::ConvertIndependentParams(JSBool* foundDependentParam) useAllocator = JS_TRUE; break; } + } else { + if (type_tag == nsXPTType::T_JSVAL) { + dp->SetValIsAllocated(); + useAllocator = JS_TRUE; + } } // Do this *after* the above because in the case where we have a @@ -3121,7 +3131,7 @@ NS_IMETHODIMP XPCWrappedNative::GetXPConnect(nsIXPConnect * *aXPConnect) } /* XPCNativeInterface FindInterfaceWithMember (in jsval name); */ -NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithMember(jsval name, nsIInterfaceInfo * *_retval) +NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithMember(jsid name, nsIInterfaceInfo * *_retval) { XPCNativeInterface* iface; XPCNativeMember* member; @@ -3138,7 +3148,7 @@ NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithMember(jsval name, nsIInterface } /* XPCNativeInterface FindInterfaceWithName (in jsval name); */ -NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithName(jsval name, nsIInterfaceInfo * *_retval) +NS_IMETHODIMP XPCWrappedNative::FindInterfaceWithName(jsid name, nsIInterfaceInfo * *_retval) { XPCNativeInterface* iface = GetSet()->FindNamedInterface(name); if(iface) @@ -3334,7 +3344,7 @@ void XPCWrappedNative::HandlePossibleNameCaseError(JSContext* cx, XPCNativeSet* set, XPCNativeInterface* iface, - jsval name) + jsid name) { XPCCallContext ccx(JS_CALLER, cx); HandlePossibleNameCaseError(ccx, set, iface, name); @@ -3345,71 +3355,9 @@ void XPCWrappedNative::HandlePossibleNameCaseError(XPCCallContext& ccx, XPCNativeSet* set, XPCNativeInterface* iface, - jsval name) + jsid name) { - if(!ccx.IsValid()) - return; - - JSString* oldJSStr; - JSString* newJSStr; - PRUnichar* oldStr; - PRUnichar* newStr; - XPCNativeMember* member; - XPCNativeInterface* localIface; - - /* PRUnichar->char->PRUnichar hack is to avoid pulling in i18n code. */ - if(JSVAL_IS_STRING(name) && - nsnull != (oldJSStr = JSVAL_TO_STRING(name)) && - nsnull != (oldStr = (PRUnichar*) JS_GetStringChars(oldJSStr)) && - oldStr[0] != 0 && - oldStr[0] >> 8 == 0 && - nsCRT::IsUpper((char)oldStr[0]) && - nsnull != (newStr = nsCRT::strdup(oldStr))) - { - newStr[0] = (PRUnichar) nsCRT::ToLower((char)newStr[0]); - newJSStr = JS_NewUCStringCopyZ(ccx, (const jschar*)newStr); - nsCRT::free(newStr); - if(newJSStr && (set ? - set->FindMember(STRING_TO_JSVAL(newJSStr), &member, &localIface) : - NS_PTR_TO_INT32(iface->FindMember(STRING_TO_JSVAL(newJSStr))))) - { - // found it! - const char* ifaceName = set ? - localIface->GetNameString() : - iface->GetNameString(); - const char* goodName = JS_GetStringBytes(newJSStr); - const char* badName = JS_GetStringBytes(oldJSStr); - char* locationStr = nsnull; - - nsIException* e = nsnull; - nsXPCException::NewException("", NS_OK, nsnull, nsnull, &e); - - if(e) - { - nsresult rv; - nsCOMPtr loc = nsnull; - rv = e->GetLocation(getter_AddRefs(loc)); - if(NS_SUCCEEDED(rv) && loc) { - loc->ToString(&locationStr); // failure here leaves it nsnull. - } - } - - if(locationStr && ifaceName && goodName && badName ) - { - printf("**************************************************\n" - "ERROR: JS code at [%s]\n" - "tried to access nonexistent property called\n" - "\'%s\' on interface of type \'%s\'.\n" - "That interface does however have a property called\n" - "\'%s\'. Did you mean to access that lowercase property?\n" - "Please fix the JS code as appropriate.\n" - "**************************************************\n", - locationStr, badName, ifaceName, goodName); - } - if(locationStr) - nsMemory::Free(locationStr); - } - } + // TODO: remove this all more thoroughly. } #endif diff --git a/js/src/xpconnect/src/xpcwrappednativeinfo.cpp b/js/src/xpconnect/src/xpcwrappednativeinfo.cpp index 519927b1de9c..f9ee870a572f 100644 --- a/js/src/xpconnect/src/xpcwrappednativeinfo.cpp +++ b/js/src/xpconnect/src/xpcwrappednativeinfo.cpp @@ -98,7 +98,8 @@ XPCNativeMember::GetCallInfo(XPCCallContext& ccx, if(!JS_GetReservedSlot(ccx, funobj, 0, &ifaceVal) || !JS_GetReservedSlot(ccx, funobj, 1, &memberVal) || - !JSVAL_IS_INT(ifaceVal) || !JSVAL_IS_INT(memberVal)) + !JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(ifaceVal) || + !JSVAL_IS_UNDERLYING_TYPE_OF_PRIVATE(memberVal)) { return JS_FALSE; } @@ -367,8 +368,8 @@ XPCNativeInterface::NewInstance(XPCCallContext& ccx, PRUint16 realTotalCount = 0; XPCNativeMember* cur; JSString* str; - jsval name; - jsval interfaceName; + jsid name; + jsid interfaceName; // XXX Investigate lazy init? This is a problem given the // 'placement new' scheme - we need to at least know how big to make @@ -432,7 +433,7 @@ XPCNativeInterface::NewInstance(XPCCallContext& ccx, failed = JS_TRUE; break; } - name = STRING_TO_JSVAL(str); + name = INTERNED_STRING_TO_JSID(str); if(info->IsSetter()) { @@ -476,7 +477,7 @@ XPCNativeInterface::NewInstance(XPCCallContext& ccx, failed = JS_TRUE; break; } - name = STRING_TO_JSVAL(str); + name = INTERNED_STRING_TO_JSID(str); // XXX need better way to find dups //NS_ASSERTION(!LookupMemberByID(name),"duplicate method/constant name"); @@ -495,7 +496,7 @@ XPCNativeInterface::NewInstance(XPCCallContext& ccx, { failed = JS_TRUE; } - interfaceName = STRING_TO_JSVAL(str); + interfaceName = INTERNED_STRING_TO_JSID(str); } if(!failed) @@ -537,7 +538,7 @@ const char* XPCNativeInterface::GetMemberName(XPCCallContext& ccx, const XPCNativeMember* member) const { - return JS_GetStringBytes(JSVAL_TO_STRING(member->GetName())); + return JS_GetStringBytes(JSID_TO_STRING(member->GetName())); } void diff --git a/js/src/xpconnect/src/xpcwrappednativejsops.cpp b/js/src/xpconnect/src/xpcwrappednativejsops.cpp index 647aae532801..b1081c885cb8 100644 --- a/js/src/xpconnect/src/xpcwrappednativejsops.cpp +++ b/js/src/xpconnect/src/xpcwrappednativejsops.cpp @@ -73,27 +73,6 @@ static JSBool Throw(uintN errNum, JSContext* cx) return Throw(NS_ERROR_XPC_HAS_BEEN_SHUTDOWN, cx); \ PR_END_MACRO -// We rely on the engine only giving us jsval ids that are actually the -// self-same jsvals that are in the atom table (that is, if the id represents -// a string). So, we assert by converting the jsval to an id and then back -// to a jsval and comparing pointers. If the engine ever breaks this promise -// then we will scream. -#ifdef DEBUG -#define CHECK_IDVAL(cx, idval) \ - PR_BEGIN_MACRO \ - if(JSVAL_IS_STRING(idval)) \ - { \ - jsid d_id; \ - jsval d_val; \ - NS_ASSERTION(JS_ValueToId(cx, idval, &d_id), "JS_ValueToId failed!");\ - NS_ASSERTION(JS_IdToValue(cx, d_id, &d_val), "JS_IdToValue failed!");\ - NS_ASSERTION(d_val == idval, "id differs from id in atom table!"); \ - } \ - PR_END_MACRO -#else -#define CHECK_IDVAL(cx, idval) ((void)0) -#endif - /***************************************************************************/ static JSBool @@ -162,7 +141,7 @@ XPC_WN_Shared_ToString(JSContext *cx, JSObject *obj, } XPCCallContext ccx(JS_CALLER, cx, obj); - ccx.SetName(ccx.GetRuntime()->GetStringJSVal(XPCJSRuntime::IDX_TO_STRING)); + ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING)); ccx.SetArgsAndResultPtr(argc, argv, vp); return ToStringGuts(ccx); } @@ -257,8 +236,8 @@ XPC_WN_DoubleWrappedGetter(JSContext *cx, JSObject *obj, if(iface) { - jsval idval = ccx.GetRuntime()-> - GetStringJSVal(XPCJSRuntime::IDX_WRAPPED_JSOBJECT); + jsid id = ccx.GetRuntime()-> + GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT); ccx.SetCallInfo(iface, iface->GetMemberAt(1), JS_FALSE); if(NS_FAILED(sm-> @@ -266,7 +245,7 @@ XPC_WN_DoubleWrappedGetter(JSContext *cx, JSObject *obj, &ccx, ccx, ccx.GetFlattenedJSObject(), wrapper->GetIdentityObject(), - wrapper->GetClassInfo(), idval, + wrapper->GetClassInfo(), id, wrapper->GetSecurityInfoAddr()))) { // The SecurityManager should have set an exception. @@ -290,7 +269,7 @@ XPC_WN_DoubleWrappedGetter(JSContext *cx, JSObject *obj, static JSBool DefinePropertyIfFound(XPCCallContext& ccx, - JSObject *obj, jsval idval, + JSObject *obj, jsid id, XPCNativeSet* set, XPCNativeInterface* iface, XPCNativeMember* member, @@ -305,33 +284,32 @@ DefinePropertyIfFound(XPCCallContext& ccx, XPCJSRuntime* rt = ccx.GetRuntime(); JSBool found; const char* name; - jsid id; if(set) { if(iface) found = JS_TRUE; else - found = set->FindMember(idval, &member, &iface); + found = set->FindMember(id, &member, &iface); } else - found = (nsnull != (member = iface->FindMember(idval))); + found = (nsnull != (member = iface->FindMember(id))); if(!found) { - HANDLE_POSSIBLE_NAME_CASE_ERROR(ccx, set, iface, idval); + HANDLE_POSSIBLE_NAME_CASE_ERROR(ccx, set, iface, id); if(reflectToStringAndToSource) { JSNative call; - if(idval == rt->GetStringJSVal(XPCJSRuntime::IDX_TO_STRING)) + if(id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING)) { call = XPC_WN_Shared_ToString; name = rt->GetStringName(XPCJSRuntime::IDX_TO_STRING); id = rt->GetStringID(XPCJSRuntime::IDX_TO_STRING); } - else if(idval == rt->GetStringJSVal(XPCJSRuntime::IDX_TO_SOURCE)) + else if(id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE)) { call = XPC_WN_Shared_ToSource; name = rt->GetStringName(XPCJSRuntime::IDX_TO_SOURCE); @@ -350,7 +328,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, return JS_FALSE; } - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; return JS_DefinePropertyById(ccx, obj, id, @@ -370,19 +348,18 @@ DefinePropertyIfFound(XPCCallContext& ccx, XPCWrappedNativeTearOff* to; JSObject* jso; - if(JSVAL_IS_STRING(idval) && - nsnull != (name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) && + if(JSID_IS_STRING(id) && + nsnull != (name = JS_GetStringBytes(JSID_TO_STRING(id))) && (iface2 = XPCNativeInterface::GetNewOrUsed(ccx, name), iface2) && nsnull != (to = wrapperToReflectInterfaceNames-> FindTearOff(ccx, iface2, JS_TRUE)) && nsnull != (jso = to->GetJSObject())) { - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; - return JS_ValueToId(ccx, idval, &id) && - JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), + return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), nsnull, nsnull, propFlags & ~JSPROP_ENUMERATE); } @@ -390,7 +367,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, // This *might* be a double wrapped JSObject if(wrapperToReflectDoubleWrap && - idval == rt->GetStringJSVal(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) && + id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT) && GetDoubleWrappedJSObject(ccx, wrapperToReflectDoubleWrap)) { // We build and add a getter function. @@ -414,7 +391,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, propFlags |= JSPROP_GETTER; propFlags &= ~JSPROP_ENUMERATE; - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, @@ -427,7 +404,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, // Check to see if there's an IDispatch tearoff if(wrapperToReflectInterfaceNames && XPCIDispatchExtension::DefineProperty(ccx, obj, - idval, wrapperToReflectInterfaceNames, propFlags, resolved)) + id, wrapperToReflectInterfaceNames, propFlags, resolved)) return JS_TRUE; #endif @@ -449,11 +426,10 @@ DefinePropertyIfFound(XPCCallContext& ccx, if(!jso) return JS_FALSE; - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; - return JS_ValueToId(ccx, idval, &id) && - JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), + return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), nsnull, nsnull, propFlags & ~JSPROP_ENUMERATE); } @@ -465,20 +441,19 @@ DefinePropertyIfFound(XPCCallContext& ccx, if(member->IsConstant()) { jsval val; - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; return member->GetConstantValue(ccx, iface, &val) && - JS_ValueToId(ccx, idval, &id) && JS_DefinePropertyById(ccx, obj, id, val, nsnull, nsnull, propFlags); } - if(idval == rt->GetStringJSVal(XPCJSRuntime::IDX_TO_STRING) || - idval == rt->GetStringJSVal(XPCJSRuntime::IDX_TO_SOURCE) || + if(id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) || + id == rt->GetStringID(XPCJSRuntime::IDX_TO_SOURCE) || (scriptableInfo && scriptableInfo->GetFlags().DontEnumQueryInterface() && - idval == rt->GetStringJSVal(XPCJSRuntime::IDX_QUERY_INTERFACE))) + id == rt->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE))) propFlags &= ~JSPROP_ENUMERATE; jsval funval; @@ -498,11 +473,10 @@ DefinePropertyIfFound(XPCCallContext& ccx, if(member->IsMethod()) { - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; - return JS_ValueToId(ccx, idval, &id) && - JS_DefinePropertyById(ccx, obj, id, funval, nsnull, nsnull, + return JS_DefinePropertyById(ccx, obj, id, funval, nsnull, nsnull, propFlags); } @@ -525,12 +499,11 @@ DefinePropertyIfFound(XPCCallContext& ccx, setter = js_GetterOnlyPropertyStub; } - AutoResolveName arn(ccx, idval); + AutoResolveName arn(ccx, id); if(resolved) *resolved = JS_TRUE; - return JS_ValueToId(ccx, idval, &id) && - JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, getter, setter, + return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, getter, setter, propFlags); } @@ -538,25 +511,22 @@ DefinePropertyIfFound(XPCCallContext& ccx, /***************************************************************************/ static JSBool -XPC_WN_OnlyIWrite_PropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +XPC_WN_OnlyIWrite_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - CHECK_IDVAL(cx, idval); - - XPCCallContext ccx(JS_CALLER, cx, obj, nsnull, idval); + XPCCallContext ccx(JS_CALLER, cx, obj, nsnull, id); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); // Allow only XPConnect to add the property - if(ccx.GetResolveName() == idval) + if(ccx.GetResolveName() == id) return JS_TRUE; return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); } static JSBool -XPC_WN_CannotModifyPropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +XPC_WN_CannotModifyPropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - CHECK_IDVAL(cx, idval); return Throw(NS_ERROR_XPC_CANT_MODIFY_PROP_ON_WN, cx); } @@ -599,7 +569,7 @@ XPC_WN_Shared_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) case JSTYPE_VOID: case JSTYPE_STRING: { - ccx.SetName(ccx.GetRuntime()->GetStringJSVal(XPCJSRuntime::IDX_TO_STRING)); + ccx.SetName(ccx.GetRuntime()->GetStringID(XPCJSRuntime::IDX_TO_STRING)); ccx.SetArgsAndResultPtr(0, nsnull, vp); XPCNativeMember* member = ccx.GetMember(); @@ -656,7 +626,7 @@ XPC_WN_Shared_Enumerate(JSContext *cx, JSObject *obj) for(PRUint16 k = 0; k < member_count; k++) { XPCNativeMember* member = iface->GetMemberAt(k); - jsval name = member->GetName(); + jsid name = member->GetName(); // Skip if this member is going to come from the proto. PRUint16 index; @@ -773,12 +743,10 @@ XPC_WN_Shared_Trace(JSTracer *trc, JSObject *obj) } static JSBool -XPC_WN_NoHelper_Resolve(JSContext *cx, JSObject *obj, jsval idval) +XPC_WN_NoHelper_Resolve(JSContext *cx, JSObject *obj, jsid id) { - CHECK_IDVAL(cx, idval); - MORPH_SLIM_WRAPPER(cx, obj); - XPCCallContext ccx(JS_CALLER, cx, obj, nsnull, idval); + XPCCallContext ccx(JS_CALLER, cx, obj, nsnull, id); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -790,7 +758,7 @@ XPC_WN_NoHelper_Resolve(JSContext *cx, JSObject *obj, jsval idval) if(ccx.GetInterface() && !ccx.GetStaticMemberIsLocal()) return JS_TRUE; - return DefinePropertyIfFound(ccx, obj, idval, + return DefinePropertyIfFound(ccx, obj, id, set, nsnull, nsnull, wrapper->GetScope(), JS_TRUE, wrapper, wrapper, nsnull, JSPROP_ENUMERATE | @@ -822,8 +790,9 @@ XPC_GetIdentityObject(JSContext *cx, JSObject *obj) } JSBool -XPC_WN_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_WN_Equality(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { + jsval v = *valp; *bp = JS_FALSE; JSObject *obj2; @@ -846,7 +815,7 @@ XPC_WN_Equality(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) return Throw(rv, cx); if(!*bp && !JSVAL_IS_PRIMITIVE(v) && - JSVAL_TO_OBJECT(v)->getClass() == &XPCSafeJSObjectWrapper::SJOWClass.base) + JSVAL_TO_OBJECT(v)->getJSClass() == &XPCSafeJSObjectWrapper::SJOWClass.base) { v = OBJECT_TO_JSVAL(XPCSafeJSObjectWrapper::GetUnsafeObject(cx, JSVAL_TO_OBJECT(v))); @@ -986,10 +955,8 @@ JSExtendedClass XPC_WN_NoHelper_JSClass = { /***************************************************************************/ static JSBool -XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - CHECK_IDVAL(cx, idval); - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); @@ -1031,34 +998,34 @@ XPC_WN_MaybeResolvingPropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsv return retval; static JSBool -XPC_WN_Helper_AddProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +XPC_WN_Helper_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { PRE_HELPER_STUB - AddProperty(wrapper, cx, obj, idval, vp, &retval); + AddProperty(wrapper, cx, obj, id, vp, &retval); POST_HELPER_STUB } static JSBool -XPC_WN_Helper_DelProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +XPC_WN_Helper_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { PRE_HELPER_STUB - DelProperty(wrapper, cx, obj, idval, vp, &retval); + DelProperty(wrapper, cx, obj, id, vp, &retval); POST_HELPER_STUB } static JSBool -XPC_WN_Helper_GetProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +XPC_WN_Helper_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { PRE_HELPER_STUB - GetProperty(wrapper, cx, obj, idval, vp, &retval); + GetProperty(wrapper, cx, obj, id, vp, &retval); POST_HELPER_STUB } static JSBool -XPC_WN_Helper_SetProperty(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +XPC_WN_Helper_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { PRE_HELPER_STUB - SetProperty(wrapper, cx, obj, idval, vp, &retval); + SetProperty(wrapper, cx, obj, id, vp, &retval); POST_HELPER_STUB } @@ -1072,12 +1039,11 @@ XPC_WN_Helper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) } static JSBool -XPC_WN_Helper_CheckAccess(JSContext *cx, JSObject *obj, jsval idval, +XPC_WN_Helper_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp) { - CHECK_IDVAL(cx, idval); PRE_HELPER_STUB - CheckAccess(wrapper, cx, obj, idval, mode, vp, &retval); + CheckAccess(wrapper, cx, obj, id, mode, vp, &retval); POST_HELPER_STUB } @@ -1087,7 +1053,7 @@ XPC_WN_Helper_Call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, { // this is a hack to get the obj of the actual object not the object // that JS thinks is the 'this' (which it passes as 'obj'). - if(!(obj = (JSObject*)argv[-2])) + if(!(obj = JSVAL_TO_OBJECT(argv[-2]))) return JS_FALSE; SLIM_LOG_WILL_MORPH(cx, obj); @@ -1102,7 +1068,7 @@ XPC_WN_Helper_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, { // this is a hack to get the obj of the actual object not the object // that JS thinks is the 'this' (which it passes as 'obj'). - if(!(obj = (JSObject*)argv[-2])) + if(!(obj = JSVAL_TO_OBJECT(argv[-2]))) return JS_FALSE; SLIM_LOG_WILL_MORPH(cx, obj); @@ -1112,11 +1078,11 @@ XPC_WN_Helper_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -XPC_WN_Helper_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp) +XPC_WN_Helper_HasInstance(JSContext *cx, JSObject *obj, const jsval *valp, JSBool *bp) { SLIM_LOG_WILL_MORPH(cx, obj); PRE_HELPER_STUB_NO_SLIM - HasInstance(wrapper, cx, obj, v, bp, &retval); + HasInstance(wrapper, cx, obj, *valp, bp, &retval); POST_HELPER_STUB } @@ -1165,11 +1131,9 @@ XPC_WN_Helper_Trace(JSTracer *trc, JSObject *obj) } static JSBool -XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, +XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { - CHECK_IDVAL(cx, idval); - nsresult rv = NS_OK; JSBool retval = JS_TRUE; JSObject* obj2FromScriptable = nsnull; @@ -1184,7 +1148,7 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, !si->GetFlags().AllowPropModsDuringResolve(), "We don't support these flags for slim wrappers!"); - rv = si->GetCallback()->NewResolve(nsnull, cx, obj, idval, flags, + rv = si->GetCallback()->NewResolve(nsnull, cx, obj, id, flags, &obj2FromScriptable, &retval); if(NS_FAILED(rv)) return Throw(rv, cx); @@ -1199,7 +1163,7 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); - jsval old = ccx.SetResolveName(idval); + jsid old = ccx.SetResolveName(id); XPCNativeScriptableInfo* si = wrapper->GetScriptableInfo(); if(si && si->GetFlags().WantNewResolve()) @@ -1210,7 +1174,7 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, if(allowPropMods) oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper); - rv = si->GetCallback()->NewResolve(wrapper, cx, obj, idval, flags, + rv = si->GetCallback()->NewResolve(wrapper, cx, obj, id, flags, &obj2FromScriptable, &retval); if(allowPropMods) @@ -1218,7 +1182,7 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, } old = ccx.SetResolveName(old); - NS_ASSERTION(old == idval, "bad nest"); + NS_ASSERTION(old == id, "bad nest"); if(NS_FAILED(rv)) { @@ -1241,7 +1205,7 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, XPCNativeInterface* iface; JSBool IsLocal; - if(set->FindMember(idval, &member, &iface, protoSet, &IsLocal) && + if(set->FindMember(id, &member, &iface, protoSet, &IsLocal) && IsLocal) { XPCWrappedNative* oldResolvingWrapper; @@ -1258,7 +1222,7 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, JSBool resolved; oldResolvingWrapper = ccx.SetResolvingWrapper(wrapper); - retval = DefinePropertyIfFound(ccx, obj, idval, + retval = DefinePropertyIfFound(ccx, obj, id, set, iface, member, wrapper->GetScope(), JS_FALSE, @@ -1276,7 +1240,7 @@ XPC_WN_Helper_NewResolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags, /***************************************************************************/ -extern "C" JS_IMPORT_DATA(JSObjectOps) js_ObjectOps; +extern JS_IMPORT_DATA(JSObjectOps) js_ObjectOps; static JSObjectOps XPC_WN_WithCall_JSOps; static JSObjectOps XPC_WN_NoCall_JSOps; @@ -1320,14 +1284,14 @@ static JSBool XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp) { - JSClass *clazz = obj->getClass(); + JSClass *clazz = obj->getJSClass(); if(!IS_WRAPPER_CLASS(clazz) || clazz == &XPC_WN_NoHelper_JSClass.base) { // obj must be a prototype object or a wrapper w/o a // helper. Short circuit this call to // js_ObjectOps.enumerate(). - return js_ObjectOps.enumerate(cx, obj, enum_op, statep, idp); + return js_ObjectOps.enumerate(cx, obj, enum_op, js::Valueify(statep), idp); } MORPH_SLIM_WRAPPER(cx, obj); @@ -1400,7 +1364,7 @@ XPC_WN_JSOp_Enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, // else call js_ObjectOps.enumerate... - return js_ObjectOps.enumerate(cx, obj, enum_op, statep, idp); + return js_ObjectOps.enumerate(cx, obj, enum_op, js::Valueify(statep), idp); } static JSType @@ -1543,7 +1507,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) JSStackFrame *fp; nsIPrincipal *principal = secMan->GetCxSubjectPrincipalAndFrame(cx, &fp); - js::AutoValueRooter retval(cx, obj); + js::AutoValueRooter retval(cx, js::ObjectValue(*obj)); if(principal && fp) { @@ -1560,7 +1524,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } nsresult rv = xpc->GetWrapperForObject(cx, obj, scope, principal, flags, - retval.addr()); + retval.jsval_addr()); if(NS_FAILED(rv)) { XPCThrower::Throw(rv, cx); @@ -1568,7 +1532,7 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JSObject *obj) } } - return JSVAL_TO_OBJECT(retval.value()); + return JSVAL_TO_OBJECT(retval.jsval_value()); } JSObjectOps * @@ -1588,7 +1552,7 @@ JSBool xpc_InitWrappedNativeJSOps() if(!XPC_WN_NoCall_JSOps.lookupProperty) { memcpy(&XPC_WN_NoCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps)); - XPC_WN_NoCall_JSOps.enumerate = XPC_WN_JSOp_Enumerate; + XPC_WN_NoCall_JSOps.enumerate = js::Valueify(XPC_WN_JSOp_Enumerate); XPC_WN_NoCall_JSOps.call = nsnull; XPC_WN_NoCall_JSOps.construct = nsnull; XPC_WN_NoCall_JSOps.typeOf = XPC_WN_JSOp_TypeOf_Object; @@ -1596,7 +1560,7 @@ JSBool xpc_InitWrappedNativeJSOps() XPC_WN_NoCall_JSOps.thisObject = XPC_WN_JSOp_ThisObject; memcpy(&XPC_WN_WithCall_JSOps, &js_ObjectOps, sizeof(JSObjectOps)); - XPC_WN_WithCall_JSOps.enumerate = XPC_WN_JSOp_Enumerate; + XPC_WN_WithCall_JSOps.enumerate = js::Valueify(XPC_WN_JSOp_Enumerate); XPC_WN_WithCall_JSOps.typeOf = XPC_WN_JSOp_TypeOf_Function; XPC_WN_WithCall_JSOps.clear = XPC_WN_JSOp_Clear; XPC_WN_WithCall_JSOps.thisObject = XPC_WN_JSOp_ThisObject; @@ -1783,7 +1747,7 @@ XPC_WN_CallMethod(JSContext *cx, JSObject *obj, if(IS_SLIM_WRAPPER(obj) && !MorphSlimWrapper(cx, obj)) return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); - XPCCallContext ccx(JS_CALLER, cx, obj, funobj, 0, argc, argv, vp); + XPCCallContext ccx(JS_CALLER, cx, obj, funobj, JSID_VOID, argc, argv, vp); XPCWrappedNative* wrapper = ccx.GetWrapper(); THROW_AND_RETURN_IF_BAD_WRAPPER(cx, wrapper); @@ -1916,10 +1880,8 @@ XPC_WN_Shared_Proto_Trace(JSTracer *trc, JSObject *obj) /*****************************************************/ static JSBool -XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, JSObject *obj, jsval idval) +XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, JSObject *obj, jsid id) { - CHECK_IDVAL(cx, idval); - NS_ASSERTION( JS_InstanceOf(cx, obj, &XPC_WN_ModsAllowed_WithCall_Proto_JSClass, nsnull) || @@ -1940,7 +1902,7 @@ XPC_WN_ModsAllowed_Proto_Resolve(JSContext *cx, JSObject *obj, jsval idval) uintN enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ? 0 : JSPROP_ENUMERATE; - return DefinePropertyIfFound(ccx, obj, idval, + return DefinePropertyIfFound(ccx, obj, id, self->GetSet(), nsnull, nsnull, self->GetScope(), JS_TRUE, nsnull, nsnull, si, @@ -2029,10 +1991,8 @@ JSClass XPC_WN_ModsAllowed_NoCall_Proto_JSClass = { /***************************************************************************/ static JSBool -XPC_WN_OnlyIWrite_Proto_PropertyStub(JSContext *cx, JSObject *obj, jsval idval, jsval *vp) +XPC_WN_OnlyIWrite_Proto_PropertyStub(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { - CHECK_IDVAL(cx, idval); - NS_ASSERTION( JS_InstanceOf(cx, obj, &XPC_WN_NoMods_WithCall_Proto_JSClass, nsnull) || JS_InstanceOf(cx, obj, &XPC_WN_NoMods_NoCall_Proto_JSClass, nsnull), @@ -2048,17 +2008,15 @@ XPC_WN_OnlyIWrite_Proto_PropertyStub(JSContext *cx, JSObject *obj, jsval idval, return JS_FALSE; // Allow XPConnect to add the property only - if(ccx.GetResolveName() == idval) + if(ccx.GetResolveName() == id) return JS_TRUE; return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); } static JSBool -XPC_WN_NoMods_Proto_Resolve(JSContext *cx, JSObject *obj, jsval idval) +XPC_WN_NoMods_Proto_Resolve(JSContext *cx, JSObject *obj, jsid id) { - CHECK_IDVAL(cx, idval); - NS_ASSERTION( JS_InstanceOf(cx, obj, &XPC_WN_NoMods_WithCall_Proto_JSClass, nsnull) || JS_InstanceOf(cx, obj, &XPC_WN_NoMods_NoCall_Proto_JSClass, nsnull), @@ -2077,7 +2035,7 @@ XPC_WN_NoMods_Proto_Resolve(JSContext *cx, JSObject *obj, jsval idval) uintN enumFlag = (si && si->GetFlags().DontEnumStaticProps()) ? 0 : JSPROP_ENUMERATE; - return DefinePropertyIfFound(ccx, obj, idval, + return DefinePropertyIfFound(ccx, obj, id, self->GetSet(), nsnull, nsnull, self->GetScope(), JS_TRUE, nsnull, nsnull, si, @@ -2163,10 +2121,8 @@ XPC_WN_TearOff_Enumerate(JSContext *cx, JSObject *obj) } static JSBool -XPC_WN_TearOff_Resolve(JSContext *cx, JSObject *obj, jsval idval) +XPC_WN_TearOff_Resolve(JSContext *cx, JSObject *obj, jsid id) { - CHECK_IDVAL(cx, idval); - MORPH_SLIM_WRAPPER(cx, obj); XPCCallContext ccx(JS_CALLER, cx, obj); XPCWrappedNative* wrapper = ccx.GetWrapper(); @@ -2178,7 +2134,7 @@ XPC_WN_TearOff_Resolve(JSContext *cx, JSObject *obj, jsval idval) if(!to || nsnull == (iface = to->GetInterface())) return Throw(NS_ERROR_XPC_BAD_OP_ON_WN_PROTO, cx); - return DefinePropertyIfFound(ccx, obj, idval, nsnull, iface, nsnull, + return DefinePropertyIfFound(ccx, obj, id, nsnull, iface, nsnull, wrapper->GetScope(), JS_TRUE, nsnull, nsnull, nsnull, JSPROP_READONLY | diff --git a/js/src/xpconnect/src/xpcwrappednativescope.cpp b/js/src/xpconnect/src/xpcwrappednativescope.cpp index 95d27680d8bf..bbbdac320bc6 100644 --- a/js/src/xpconnect/src/xpcwrappednativescope.cpp +++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp @@ -241,7 +241,7 @@ XPCWrappedNativeScope::SetGlobal(XPCCallContext& ccx, JSObject* aGlobal) mScriptObjectPrincipal = nsnull; // Now init our script object principal, if the new global has one - const JSClass* jsClass = aGlobal->getClass(); + const JSClass* jsClass = aGlobal->getJSClass(); if(!(~jsClass->flags & (JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS))) { @@ -720,7 +720,7 @@ XPCWrappedNativeScope* GetScopeOfObject(JSObject* obj) { nsISupports* supports; - JSClass* clazz = obj->getClass(); + JSClass* clazz = obj->getJSClass(); JSBool isWrapper = IS_WRAPPER_CLASS(clazz); if(isWrapper && IS_SLIM_WRAPPER_OBJECT(obj)) diff --git a/js/src/xpconnect/tests/TestXPC.cpp b/js/src/xpconnect/tests/TestXPC.cpp index 73e68143f240..ed1850bfd7e3 100644 --- a/js/src/xpconnect/tests/TestXPC.cpp +++ b/js/src/xpconnect/tests/TestXPC.cpp @@ -283,9 +283,9 @@ MySecMan::CanGetService(JSContext * aJSContext, const nsCID & aCID) } } -/* void CanAccess (in PRUint32 aAction, in nsIXPCNativeCallContext aCallContext, in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in nsISupports aObj, in nsIClassInfo aClassInfo, in jsval aName, inout voidPtr aPolicy); */ +/* void CanAccess (in PRUint32 aAction, in nsIXPCNativeCallContext aCallContext, in JSContextPtr aJSContext, in JSObjectPtr aJSObject, in nsISupports aObj, in nsIClassInfo aClassInfo, in jsid aName, inout voidPtr aPolicy); */ NS_IMETHODIMP -MySecMan::CanAccess(PRUint32 aAction, nsAXPCNativeCallContext *aCallContext, JSContext * aJSContext, JSObject * aJSObject, nsISupports *aObj, nsIClassInfo *aClassInfo, jsval aName, void * *aPolicy) +MySecMan::CanAccess(PRUint32 aAction, nsAXPCNativeCallContext *aCallContext, JSContext * aJSContext, JSObject * aJSObject, nsISupports *aObj, nsIClassInfo *aClassInfo, jsid aName, void * *aPolicy) { switch(mMode) { diff --git a/js/src/xpconnect/wrappers/AccessCheck.cpp b/js/src/xpconnect/wrappers/AccessCheck.cpp index 546e171dffbb..bdd9c504dc0f 100644 --- a/js/src/xpconnect/wrappers/AccessCheck.cpp +++ b/js/src/xpconnect/wrappers/AccessCheck.cpp @@ -241,10 +241,15 @@ AccessCheck::needsSystemOnlyWrapper(JSObject *obj) void AccessCheck::deny(JSContext *cx, jsid id) { - if (id == JSVAL_VOID) { + if (id == JSID_VOID) { JS_ReportError(cx, "Permission denied to access object"); } else { - JSString *str = JS_ValueToString(cx, id); + jsval idval; + if (!JS_IdToValue(cx, id, &idval)) + return; + JSString *str = JS_ValueToString(cx, idval); + if (!str) + return; JS_ReportError(cx, "Permission denied to access property '%hs'", str); } } @@ -268,7 +273,7 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, bool set return true; // Allow } - if (id == JSVAL_VOID) { + if (id == JSID_VOID) { // This will force the caller to call us back for individual property accesses. perm = PermitPropertyAccess; return true; diff --git a/js/src/xpconnect/wrappers/FilteringWrapper.cpp b/js/src/xpconnect/wrappers/FilteringWrapper.cpp index ade00c90acca..96f071129d1b 100644 --- a/js/src/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/src/xpconnect/wrappers/FilteringWrapper.cpp @@ -66,7 +66,7 @@ static const Permission DenyAccess = JSWrapper::DenyAccess; template static bool -Filter(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +Filter(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { size_t w = 0; for (size_t n = 0; n < props.length(); ++n) { @@ -98,7 +98,7 @@ CheckAndReport(JSContext *cx, JSObject *wrapper, jsid id, bool set, Permission & template bool -FilteringWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +FilteringWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { return Base::getOwnPropertyNames(cx, wrapper, props) && Filter(cx, wrapper, props); @@ -106,7 +106,7 @@ FilteringWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wra template bool -FilteringWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +FilteringWrapper::enumerate(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { return Base::enumerate(cx, wrapper, props) && Filter(cx, wrapper, props); @@ -114,7 +114,7 @@ FilteringWrapper::enumerate(JSContext *cx, JSObject *wrapper, Auto template bool -FilteringWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoValueVector &props) +FilteringWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, AutoIdVector &props) { return Base::enumerateOwn(cx, wrapper, props) && Filter(cx, wrapper, props); @@ -122,7 +122,7 @@ FilteringWrapper::enumerateOwn(JSContext *cx, JSObject *wrapper, A template bool -FilteringWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, jsval *vp) +FilteringWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp) { // We refuse to trigger the iterator hook across chrome wrappers because // we don't know how to censor custom iterator objects. Instead we trigger @@ -136,7 +136,7 @@ bool FilteringWrapper::enter(JSContext *cx, JSObject *wrapper, jsid id, bool set) { Permission perm; - return CheckAndReport(cx, wrapper, JSVAL_VOID, set, perm) && + return CheckAndReport(cx, wrapper, JSID_VOID, set, perm) && Base::enter(cx, wrapper, id, set); } diff --git a/js/src/xpconnect/wrappers/FilteringWrapper.h b/js/src/xpconnect/wrappers/FilteringWrapper.h index 316cd704d883..11ecc9222a8c 100644 --- a/js/src/xpconnect/wrappers/FilteringWrapper.h +++ b/js/src/xpconnect/wrappers/FilteringWrapper.h @@ -48,10 +48,10 @@ class FilteringWrapper : public Base { FilteringWrapper(uintN flags); virtual ~FilteringWrapper(); - virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props); - virtual bool enumerate(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props); - virtual bool enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoValueVector &props); - virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, jsval *vp); + virtual bool getOwnPropertyNames(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual bool enumerate(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual bool enumerateOwn(JSContext *cx, JSObject *wrapper, js::AutoIdVector &props); + virtual bool iterate(JSContext *cx, JSObject *proxy, uintN flags, js::Value *vp); virtual bool enter(JSContext *cx, JSObject *wrapper, jsid id, bool set); diff --git a/js/src/xpconnect/wrappers/XrayWrapper.cpp b/js/src/xpconnect/wrappers/XrayWrapper.cpp index f6129437b380..17743713999f 100644 --- a/js/src/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/src/xpconnect/wrappers/XrayWrapper.cpp @@ -92,8 +92,8 @@ GetWrappedNative(JSObject *obj) static JSObject * GetWrappedNativeObjectFromHolder(JSObject *holder) { - NS_ASSERTION(holder->getClass() == &HolderClass, "expected a native property holder object"); - return JSVAL_TO_OBJECT(holder->getSlot(JSSLOT_WN_OBJ)); + NS_ASSERTION(holder->getJSClass() == &HolderClass, "expected a native property holder object"); + return holder->getSlot(JSSLOT_WN_OBJ).toObjectOrNull(); } // Some DOM objects have shared properties that don't have an explicit @@ -136,11 +136,11 @@ holder_set(JSContext *cx, JSObject *obj, jsid id, jsval *vp) } static bool -ResolveNativeProperty(JSContext *cx, JSObject *holder, jsval id, bool set, JSPropertyDescriptor *desc) +ResolveNativeProperty(JSContext *cx, JSObject *holder, jsid id, bool set, JSPropertyDescriptor *desc) { desc->obj = NULL; - NS_ASSERTION(holder->getClass() == &HolderClass, "expected a native property holder object"); + NS_ASSERTION(holder->getJSClass() == &HolderClass, "expected a native property holder object"); JSObject *wnObject = GetWrappedNativeObjectFromHolder(holder); XPCWrappedNative *wn = GetWrappedNative(wnObject); @@ -200,7 +200,7 @@ ResolveNativeProperty(JSContext *cx, JSObject *holder, jsval id, bool set, JSPro JS_ReportError(cx, "Failed to clone function object for native getter/setter"); return false; } - desc->getter = CastAsPropertyOp(JSVAL_TO_OBJECT(fval)); + desc->getter = CastAsJSPropertyOp(JSVAL_TO_OBJECT(fval)); desc->attrs |= JSPROP_GETTER; if (member->IsWritableAttribute()) { desc->setter = desc->getter;; @@ -269,9 +269,11 @@ wrappedJSObject_getter(JSContext *cx, JSObject *holder, jsid id, jsval *vp) template bool -XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc) +XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc_in) { - if (id == XPCJSRuntime::IDX_WRAPPED_JSOBJECT) { + JSPropertyDescriptor *desc = Jsvalify(desc_in); + + if (id == nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) { desc->obj = wrapper; desc->attrs = JSPROP_ENUMERATE|JSPROP_SHARED; desc->getter = wrappedJSObject_getter; @@ -280,7 +282,7 @@ XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid desc->value = JSVAL_VOID; return true; } - if (!Base::getPropertyDescriptor(cx, wrapper, id, desc)) { + if (!Base::getPropertyDescriptor(cx, wrapper, id, desc_in)) { return false; } if (desc->obj) @@ -290,7 +292,7 @@ XrayWrapper::getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid template bool -XrayWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, JSPropertyDescriptor *desc) +XrayWrapper::getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, PropertyDescriptor *desc) { return getPropertyDescriptor(cx, wrapper, id, desc); } diff --git a/js/src/xpconnect/wrappers/XrayWrapper.h b/js/src/xpconnect/wrappers/XrayWrapper.h index 2d65050671fd..8f4645a2e201 100644 --- a/js/src/xpconnect/wrappers/XrayWrapper.h +++ b/js/src/xpconnect/wrappers/XrayWrapper.h @@ -54,9 +54,9 @@ class XrayWrapper : public Base { virtual ~XrayWrapper(); virtual bool getPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc); + js::PropertyDescriptor *desc); virtual bool getOwnPropertyDescriptor(JSContext *cx, JSObject *wrapper, jsid id, - JSPropertyDescriptor *desc); + js::PropertyDescriptor *desc); virtual bool has(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); virtual bool hasOwn(JSContext *cx, JSObject *wrapper, jsid id, bool *bp); diff --git a/modules/plugin/base/src/nsJSNPRuntime.cpp b/modules/plugin/base/src/nsJSNPRuntime.cpp index f058290c915e..cad76332939f 100644 --- a/modules/plugin/base/src/nsJSNPRuntime.cpp +++ b/modules/plugin/base/src/nsJSNPRuntime.cpp @@ -145,23 +145,23 @@ NPClass nsJSObjWrapper::sJSObjWrapperNPClass = }; static JSBool -NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool -NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp); +NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp); static JSBool NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp); static JSBool -NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); static JSBool @@ -180,7 +180,7 @@ NPObjWrapper_Construct(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, static JSBool CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject *npobj, - jsval id, NPVariant* getPropertyResult, jsval *vp); + jsid id, NPVariant* getPropertyResult, jsval *vp); static JSClass sNPObjectJSWrapperClass = { @@ -197,7 +197,7 @@ static JSClass sNPObjectJSWrapperClass = typedef struct NPObjectMemberPrivate { JSObject *npobjWrapper; jsval fieldValue; - jsval methodName; + NPIdentifier methodName; NPP npp; } NPObjectMemberPrivate; @@ -457,7 +457,7 @@ JSValToNPVariant(NPP npp, JSContext *cx, jsval val, NPVariant *variant) } else if (JSVAL_IS_INT(val)) { INT32_TO_NPVARIANT(JSVAL_TO_INT(val), *variant); } else if (JSVAL_IS_DOUBLE(val)) { - DOUBLE_TO_NPVARIANT(*JSVAL_TO_DOUBLE(val), *variant); + DOUBLE_TO_NPVARIANT(JSVAL_TO_DOUBLE(val), *variant); } else if (JSVAL_IS_STRING(val)) { JSString *jsstr = JSVAL_TO_STRING(val); nsDependentString str((PRUnichar *)::JS_GetStringChars(jsstr), @@ -598,25 +598,23 @@ nsJSObjWrapper::NP_Invalidate(NPObject *npobj) } 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"); + NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n"); - return ::JS_GetElement(cx, obj, JSVAL_TO_INT(id), rval); + 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); @@ -639,7 +637,7 @@ nsJSObjWrapper::NP_HasMethod(NPObject *npobj, NPIdentifier identifier) 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)); @@ -672,7 +670,7 @@ doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args, 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; @@ -742,7 +740,7 @@ 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; } @@ -754,13 +752,13 @@ 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); @@ -777,22 +775,21 @@ nsJSObjWrapper::NP_HasProperty(NPObject *npobj, NPIdentifier identifier) } 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"); + NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n"); - ok = ::JS_HasElement(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &found); + ok = ::JS_HasElement(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &found); } return ok && found; @@ -800,7 +797,7 @@ nsJSObjWrapper::NP_HasProperty(NPObject *npobj, NPIdentifier identifier) // static bool -nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier identifier, +nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier id, NPVariant *result) { NPP npp = NPPStack::Peek(); @@ -824,13 +821,13 @@ nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier identifier, 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(); @@ -848,7 +845,6 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier, } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; - jsval id = (jsval)identifier; JSBool ok = JS_FALSE; AutoCXPusher pusher(cx); @@ -856,17 +852,17 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier, AutoJSExceptionReporter reporter(cx); jsval v = NPVariantToJSVal(npp, cx, value); - js::AutoValueRooter tvr(cx, v); + 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"); + NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n"); - ok = ::JS_SetElement(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &v); + ok = ::JS_SetElement(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &v); } // return ok == JS_TRUE to quiet down compiler warning, even if @@ -876,7 +872,7 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier identifier, // static bool -nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier identifier) +nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier id) { NPP npp = NPPStack::Peek(); JSContext *cx = GetJSContext(npp); @@ -893,7 +889,6 @@ nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier identifier) } nsJSObjWrapper *npjsobj = (nsJSObjWrapper *)npobj; - jsval id = (jsval)identifier; JSBool ok = JS_FALSE; AutoCXPusher pusher(cx); @@ -901,13 +896,13 @@ nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier identifier) 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) { + if (ok && deleted == JSVAL_TRUE) { // FIXME: See bug 425823, we shouldn't need to do this, and once // that bug is fixed we can remove this code. @@ -923,16 +918,16 @@ nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier identifier) } } } else { - NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n"); + NS_ASSERTION(NPIdentifierIsInt(id), "id must be either string or int!\n"); - ok = ::JS_DeleteElement2(cx, npjsobj->mJSObj, JSVAL_TO_INT(id), &deleted); + ok = ::JS_DeleteElement2(cx, npjsobj->mJSObj, NPIdentifierToInt(id), &deleted); - if (ok && deleted) { + if (ok && deleted == JSVAL_TRUE) { // 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 @@ -950,13 +945,13 @@ nsJSObjWrapper::NP_RemoveProperty(NPObject *npobj, NPIdentifier identifier) //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) { @@ -982,8 +977,8 @@ nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **identifier, } *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); @@ -995,26 +990,29 @@ nsJSObjWrapper::NP_Enumerate(NPObject *npobj, NPIdentifier **identifier, 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); @@ -1027,8 +1025,7 @@ 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); } @@ -1188,7 +1185,7 @@ GetNPObject(JSContext *cx, JSObject *obj) // Does not actually add a property because this is always followed by a // SetProperty call. static JSBool -NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { NPObject *npobj = GetNPObject(cx, obj); @@ -1205,7 +1202,8 @@ NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) PluginDestructionGuard pdg(LookupNPP(npobj)); - JSBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id); + NPIdentifier identifier = JSIdToNPIdentifier(id); + JSBool hasProperty = npobj->_class->hasProperty(npobj, identifier); if (!ReportExceptionIfPending(cx)) return JS_FALSE; @@ -1214,7 +1212,7 @@ NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) // 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; @@ -1228,7 +1226,7 @@ NPObjWrapper_AddProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { NPObject *npobj = GetNPObject(cx, obj); @@ -1241,8 +1239,10 @@ NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) PluginDestructionGuard pdg(LookupNPP(npobj)); + NPIdentifier identifier = JSIdToNPIdentifier(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; @@ -1250,14 +1250,14 @@ NPObjWrapper_DelProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) 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) +NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { NPObject *npobj = GetNPObject(cx, obj); @@ -1280,8 +1280,10 @@ NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) PluginDestructionGuard pdg(npp); + NPIdentifier identifier = JSIdToNPIdentifier(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; @@ -1299,7 +1301,7 @@ NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) 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; @@ -1314,7 +1316,7 @@ NPObjWrapper_SetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } static JSBool -NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) +NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { NPObject *npobj = GetNPObject(cx, obj); @@ -1341,6 +1343,8 @@ NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) NPVariant npv; VOID_TO_NPVARIANT(npv); + NPIdentifier identifier = JSIdToNPIdentifier(id); + #ifdef MOZ_IPC if (NPObjectIsOutOfProcessProxy(npobj)) { PluginScriptableObjectParent* actor = @@ -1350,7 +1354,7 @@ NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) 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) @@ -1375,11 +1379,11 @@ NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } #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; @@ -1388,7 +1392,7 @@ NPObjWrapper_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp) 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); @@ -1488,10 +1492,10 @@ CallNPMethodInternal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (npobj->_class->invoke) { JSFunction *fun = (JSFunction *)::JS_GetPrivate(cx, funobj); - jsval method = STRING_TO_JSVAL(::JS_GetFunctionId(fun)); + JSString *name = ::JS_GetFunctionId(fun); + NPIdentifier id = StringToNPIdentifier(name); - ok = npobj->_class->invoke(npobj, (NPIdentifier)method, npargs, argc, - &v); + ok = npobj->_class->invoke(npobj, id, npargs, argc, &v); } else { ok = JS_FALSE; @@ -1601,7 +1605,7 @@ NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, state->index = 0; *statep = PRIVATE_TO_JSVAL(state); if (idp) { - *idp = INT_TO_JSVAL(length); + *idp = INT_TO_JSID(length); } break; @@ -1611,7 +1615,8 @@ NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, enum_value = state->value; length = state->length; if (state->index != length) { - return ::JS_ValueToId(cx, (jsval)enum_value[state->index++], idp); + *idp = NPIdentifierToJSId(enum_value[state->index++]); + return JS_TRUE; } // FALL THROUGH @@ -1630,7 +1635,7 @@ NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, } static JSBool -NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, +NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp) { NPObject *npobj = GetNPObject(cx, obj); @@ -1644,21 +1649,23 @@ NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, PluginDestructionGuard pdg(LookupNPP(npobj)); - PRBool hasProperty = npobj->_class->hasProperty(npobj, (NPIdentifier)id); + NPIdentifier identifier = JSIdToNPIdentifier(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); + if (JSID_IS_STRING(id)) { + JSString *str = JSID_TO_STRING(id); ok = ::JS_DefineUCProperty(cx, obj, ::JS_GetStringChars(str), ::JS_GetStringLength(str), JSVAL_VOID, nsnull, nsnull, JSPROP_ENUMERATE); } else { - ok = ::JS_DefineElement(cx, obj, JSVAL_TO_INT(id), JSVAL_VOID, nsnull, + ok = ::JS_DefineElement(cx, obj, JSID_TO_INT(id), JSVAL_VOID, nsnull, nsnull, JSPROP_ENUMERATE); } @@ -1671,20 +1678,23 @@ NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, 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); + if (JSID_IS_STRING(id)) { + str = JSID_TO_STRING(id); } else { - NS_ASSERTION(JSVAL_IS_INT(id), "id must be either string or int!\n"); + NS_ASSERTION(JSID_IS_INT(id), "id must be either string or int!\n"); - str = ::JS_ValueToString(cx, id); + jsval idval; + if (!JS_IdToValue(cx, id, &idval)) + return JS_FALSE; + str = ::JS_ValueToString(cx, idval); if (!str) { // OOM. The JS engine throws exceptions for us in this case. @@ -2111,7 +2121,7 @@ LookupNPP(NPObject *npobj) JSBool CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj, - jsval id, NPVariant* getPropertyResult, jsval *vp) + jsid id, NPVariant* getPropertyResult, jsval *vp) { NS_ENSURE_TRUE(vp, JS_FALSE); @@ -2142,6 +2152,8 @@ CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj, ::JS_SetPrivate(cx, memobj, (void *)memberPrivate); + NPIdentifier identifier = JSIdToNPIdentifier(id); + jsval fieldValue; NPVariant npv; NPBool hasProperty; @@ -2154,7 +2166,7 @@ CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj, 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); @@ -2179,7 +2191,7 @@ CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj, memberPrivate->npobjWrapper = obj; memberPrivate->fieldValue = fieldValue; - memberPrivate->methodName = id; + memberPrivate->methodName = identifier; memberPrivate->npp = npp; ::JS_RemoveValueRoot(cx, vp); @@ -2278,9 +2290,10 @@ NPObjectMember_Call(JSContext *cx, JSObject *obj, } } + NPVariant npv; JSBool ok; - ok = npobj->_class->invoke(npobj, (NPIdentifier)memberPrivate->methodName, + ok = npobj->_class->invoke(npobj, memberPrivate->methodName, npargs, argc, &npv); // Release arguments. @@ -2320,7 +2333,7 @@ NPObjectMember_Mark(JSContext *cx, JSObject *obj, void *arg) return 0; if (!JSVAL_IS_PRIMITIVE(memberPrivate->fieldValue)) { - ::JS_MarkGCThing(cx, JSVAL_TO_OBJECT(memberPrivate->fieldValue), + ::JS_MarkGCThing(cx, memberPrivate->fieldValue, "NPObject Member => fieldValue", arg); } @@ -2328,7 +2341,7 @@ NPObjectMember_Mark(JSContext *cx, JSObject *obj, void *arg) // NPObject, so make sure to mark the NPObject wrapper to keep the // NPObject alive as long as this NPObjectMember is alive. if (memberPrivate->npobjWrapper) { - ::JS_MarkGCThing(cx, memberPrivate->npobjWrapper, + ::JS_MarkGCThing(cx, OBJECT_TO_JSVAL(memberPrivate->npobjWrapper), "NPObject Member => npobjWrapper", arg); } diff --git a/modules/plugin/base/src/nsNPAPIPlugin.cpp b/modules/plugin/base/src/nsNPAPIPlugin.cpp index b7a29c8ced24..9696dce63472 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.cpp +++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp @@ -694,7 +694,7 @@ doGetIdentifier(JSContext *cx, const NPUTF8* name) if (!str) return NULL; - return (NPIdentifier)STRING_TO_JSVAL(str); + return StringToNPIdentifier(str); } #if defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_WINCE) @@ -1357,25 +1357,23 @@ _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), @@ -1383,29 +1381,27 @@ _utf8fromidentifier(NPIdentifier identifier) } 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 diff --git a/modules/plugin/base/src/nsNPAPIPlugin.h b/modules/plugin/base/src/nsNPAPIPlugin.h index ad375649869b..5a043dfaaa7e 100644 --- a/modules/plugin/base/src/nsNPAPIPlugin.h +++ b/modules/plugin/base/src/nsNPAPIPlugin.h @@ -43,6 +43,8 @@ #include "npfunctions.h" #include "nsPluginHost.h" +#include "jsapi.h" + #include "mozilla/PluginLibrary.h" /* @@ -114,6 +116,72 @@ 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. + +JS_STATIC_ASSERT(sizeof(NPIdentifier) == sizeof(jsid)); + +static inline jsid +NPIdentifierToJSId(NPIdentifier id) +{ + jsid tmp; + JSID_BITS(tmp) = (size_t)id; + return tmp; +} + +static inline NPIdentifier +JSIdToNPIdentifier(jsid id) +{ + return (NPIdentifier)JSID_BITS(id); +} + +static inline bool +NPIdentifierIsString(NPIdentifier id) +{ + return JSID_IS_STRING(NPIdentifierToJSId(id)); +} + +static inline JSString * +NPIdentifierToString(NPIdentifier id) +{ + return JSID_TO_STRING(NPIdentifierToJSId(id)); +} + +static inline NPIdentifier +StringToNPIdentifier(JSString *str) +{ + return JSIdToNPIdentifier(INTERNED_STRING_TO_JSID(str)); +} + +static inline bool +NPIdentifierIsInt(NPIdentifier id) +{ + return JSID_IS_INT(NPIdentifierToJSId(id)); +} + +static inline jsint +NPIdentifierToInt(NPIdentifier id) +{ + return JSID_TO_INT(NPIdentifierToJSId(id)); +} + +static inline NPIdentifier +IntToNPIdentifier(jsint i) +{ + return JSIdToNPIdentifier(INT_TO_JSID(i)); +} + +static inline bool +NPIdentifierIsVoid(NPIdentifier id) +{ + return JSID_IS_VOID(NPIdentifierToJSId(id)); +} + +#define NPIdentifier_VOID (JSIdToNPIdentifier(JSID_VOID)) + NPObject* NP_CALLBACK _getwindowobject(NPP npp); diff --git a/storage/src/mozStorageAsyncStatementJSHelper.cpp b/storage/src/mozStorageAsyncStatementJSHelper.cpp index 688877fb165f..33f495134502 100644 --- a/storage/src/mozStorageAsyncStatementJSHelper.cpp +++ b/storage/src/mozStorageAsyncStatementJSHelper.cpp @@ -116,11 +116,11 @@ NS_IMETHODIMP AsyncStatementJSHelper::GetProperty(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, jsval *_result, PRBool *_retval) { - if (!JSVAL_IS_STRING(aId)) + if (!JSID_IS_STRING(aId)) return NS_OK; // Cast to async via mozI* since direct from nsISupports is ambiguous. @@ -136,7 +136,7 @@ AsyncStatementJSHelper::GetProperty(nsIXPConnectWrappedNative *aWrapper, } #endif - const char *propName = ::JS_GetStringBytes(JSVAL_TO_STRING(aId)); + const char *propName = ::JS_GetStringBytes(JSID_TO_STRING(aId)); if (::strcmp(propName, "params") == 0) return getParams(stmt, aCtx, aScopeObj, _result); diff --git a/storage/src/mozStorageAsyncStatementParams.cpp b/storage/src/mozStorageAsyncStatementParams.cpp index b6d93f38309c..f7fb708a4a67 100644 --- a/storage/src/mozStorageAsyncStatementParams.cpp +++ b/storage/src/mozStorageAsyncStatementParams.cpp @@ -80,23 +80,23 @@ AsyncStatementParams::SetProperty( nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, jsval *_vp, PRBool *_retval ) { NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); - if (JSVAL_IS_INT(aId)) { - int idx = JSVAL_TO_INT(aId); + if (JSID_IS_INT(aId)) { + int idx = JSID_TO_INT(aId); nsCOMPtr variant(convertJSValToVariant(aCtx, *_vp)); NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED); nsresult rv = mStatement->BindByIndex(idx, variant); NS_ENSURE_SUCCESS(rv, rv); } - else if (JSVAL_IS_STRING(aId)) { - JSString *str = JSVAL_TO_STRING(aId); + else if (JSID_IS_STRING(aId)) { + JSString *str = JSID_TO_STRING(aId); NS_ConvertUTF16toUTF8 name(reinterpret_cast (::JS_GetStringChars(str)), ::JS_GetStringLength(str)); @@ -119,7 +119,7 @@ AsyncStatementParams::NewResolve( nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, PRUint32 aFlags, JSObject **_objp, PRBool *_retval @@ -131,16 +131,16 @@ AsyncStatementParams::NewResolve( bool resolved = false; PRBool ok = PR_TRUE; - if (JSVAL_IS_INT(aId)) { - PRUint32 idx = JSVAL_TO_INT(aId); + if (JSID_IS_INT(aId)) { + PRUint32 idx = JSID_TO_INT(aId); // All indexes are good because we don't know how many parameters there // really are. ok = ::JS_DefineElement(aCtx, aScopeObj, idx, JSVAL_VOID, nsnull, nsnull, 0); resolved = true; } - else if (JSVAL_IS_STRING(aId)) { - JSString *str = JSVAL_TO_STRING(aId); + else if (JSID_IS_STRING(aId)) { + JSString *str = JSID_TO_STRING(aId); jschar *nameChars = ::JS_GetStringChars(str); size_t nameLength = ::JS_GetStringLength(str); diff --git a/storage/src/mozStoragePrivateHelpers.cpp b/storage/src/mozStoragePrivateHelpers.cpp index 215b26efdebb..0640fcf71e3d 100644 --- a/storage/src/mozStoragePrivateHelpers.cpp +++ b/storage/src/mozStoragePrivateHelpers.cpp @@ -147,7 +147,7 @@ convertJSValToVariant( return new IntegerVariant(JSVAL_TO_INT(aValue)); if (JSVAL_IS_DOUBLE(aValue)) - return new FloatVariant(*JSVAL_TO_DOUBLE(aValue)); + return new FloatVariant(JSVAL_TO_DOUBLE(aValue)); if (JSVAL_IS_STRING(aValue)) { JSString *str = JSVAL_TO_STRING(aValue); diff --git a/storage/src/mozStorageStatementJSHelper.cpp b/storage/src/mozStorageStatementJSHelper.cpp index d8b3948f6488..24551a64df05 100644 --- a/storage/src/mozStorageStatementJSHelper.cpp +++ b/storage/src/mozStorageStatementJSHelper.cpp @@ -205,11 +205,11 @@ NS_IMETHODIMP StatementJSHelper::GetProperty(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, jsval *_result, PRBool *_retval) { - if (!JSVAL_IS_STRING(aId)) + if (!JSID_IS_STRING(aId)) return NS_OK; #ifdef DEBUG @@ -224,7 +224,7 @@ StatementJSHelper::GetProperty(nsIXPConnectWrappedNative *aWrapper, static_cast(aWrapper->Native()) ); - const char *propName = ::JS_GetStringBytes(JSVAL_TO_STRING(aId)); + const char *propName = ::JS_GetStringBytes(JSID_TO_STRING(aId)); if (::strcmp(propName, "row") == 0) return getRow(stmt, aCtx, aScopeObj, _result); @@ -239,15 +239,15 @@ NS_IMETHODIMP StatementJSHelper::NewResolve(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, PRUint32 aFlags, JSObject **_objp, PRBool *_retval) { - if (!JSVAL_IS_STRING(aId)) + if (!JSID_IS_STRING(aId)) return NS_OK; - const char *name = ::JS_GetStringBytes(JSVAL_TO_STRING(aId)); + const char *name = ::JS_GetStringBytes(JSID_TO_STRING(aId)); if (::strcmp(name, "step") == 0) { *_retval = ::JS_DefineFunction(aCtx, aScopeObj, "step", (JSNative)stepFunc, 0, JSFUN_FAST_NATIVE) != nsnull; diff --git a/storage/src/mozStorageStatementParams.cpp b/storage/src/mozStorageStatementParams.cpp index 0ff489151884..48a0c3c94c56 100644 --- a/storage/src/mozStorageStatementParams.cpp +++ b/storage/src/mozStorageStatementParams.cpp @@ -79,22 +79,22 @@ NS_IMETHODIMP StatementParams::SetProperty(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, jsval *_vp, PRBool *_retval) { NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); - if (JSVAL_IS_INT(aId)) { - int idx = JSVAL_TO_INT(aId); + if (JSID_IS_INT(aId)) { + int idx = JSID_TO_INT(aId); nsCOMPtr variant(convertJSValToVariant(aCtx, *_vp)); NS_ENSURE_TRUE(variant, NS_ERROR_UNEXPECTED); nsresult rv = mStatement->BindByIndex(idx, variant); NS_ENSURE_SUCCESS(rv, rv); } - else if (JSVAL_IS_STRING(aId)) { - JSString *str = JSVAL_TO_STRING(aId); + else if (JSID_IS_STRING(aId)) { + JSString *str = JSID_TO_STRING(aId); NS_ConvertUTF16toUTF8 name(reinterpret_cast (::JS_GetStringChars(str)), ::JS_GetStringLength(str)); @@ -133,7 +133,7 @@ StatementParams::NewEnumerate(nsIXPConnectWrappedNative *aWrapper, // And set our length, if needed. if (_idp) - *_idp = INT_TO_JSVAL(mParamCount); + *_idp = INT_TO_JSID(mParamCount); break; } @@ -185,7 +185,7 @@ NS_IMETHODIMP StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, PRUint32 aFlags, JSObject **_objp, PRBool *_retval) @@ -197,8 +197,8 @@ StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, bool resolved = false; PRBool ok = PR_TRUE; - if (JSVAL_IS_INT(aId)) { - PRUint32 idx = JSVAL_TO_INT(aId); + if (JSID_IS_INT(aId)) { + PRUint32 idx = JSID_TO_INT(aId); // Ensure that our index is within range. We do not care about the // prototype chain being checked here. @@ -209,8 +209,8 @@ StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, nsnull, JSPROP_ENUMERATE); resolved = true; } - else if (JSVAL_IS_STRING(aId)) { - JSString *str = JSVAL_TO_STRING(aId); + else if (JSID_IS_STRING(aId)) { + JSString *str = JSID_TO_STRING(aId); jschar *nameChars = ::JS_GetStringChars(str); size_t nameLength = ::JS_GetStringLength(str); diff --git a/storage/src/mozStorageStatementRow.cpp b/storage/src/mozStorageStatementRow.cpp index 892e56f54fd9..3d6ad5d82d17 100644 --- a/storage/src/mozStorageStatementRow.cpp +++ b/storage/src/mozStorageStatementRow.cpp @@ -78,14 +78,14 @@ NS_IMETHODIMP StatementRow::GetProperty(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, jsval *_vp, PRBool *_retval) { NS_ENSURE_TRUE(mStatement, NS_ERROR_NOT_INITIALIZED); - if (JSVAL_IS_STRING(aId)) { - nsDependentCString jsid(::JS_GetStringBytes(JSVAL_TO_STRING(aId))); + if (JSID_IS_STRING(aId)) { + nsDependentCString jsid(::JS_GetStringBytes(JSID_TO_STRING(aId))); PRUint32 idx; nsresult rv = mStatement->GetColumnIndex(jsid, &idx); @@ -152,7 +152,7 @@ NS_IMETHODIMP StatementRow::NewResolve(nsIXPConnectWrappedNative *aWrapper, JSContext *aCtx, JSObject *aScopeObj, - jsval aId, + jsid aId, PRUint32 aFlags, JSObject **_objp, PRBool *_retval) @@ -161,8 +161,8 @@ StatementRow::NewResolve(nsIXPConnectWrappedNative *aWrapper, // We do not throw at any point after this because we want to allow the // prototype chain to be checked for the property. - if (JSVAL_IS_STRING(aId)) { - JSString *str = JSVAL_TO_STRING(aId); + if (JSID_IS_STRING(aId)) { + JSString *str = JSID_TO_STRING(aId); nsDependentCString name(::JS_GetStringBytes(str)); PRUint32 idx; diff --git a/xpcom/base/nsrootidl.idl b/xpcom/base/nsrootidl.idl index 36cddf1c200e..219685cab377 100644 --- a/xpcom/base/nsrootidl.idl +++ b/xpcom/base/nsrootidl.idl @@ -119,7 +119,8 @@ typedef unsigned long size_t; [ref, astring] native AStringRef(ignored); [ptr, astring] native AStringPtr(ignored); -[jsval] native jsval(jsval); +[ref, jsval] native jsval(jsval); + native jsid(jsid); %{C++ /* diff --git a/xpcom/typelib/xpidl/xpidl.h b/xpcom/typelib/xpidl/xpidl.h index 7a2f1322a334..3e9f065215d6 100644 --- a/xpcom/typelib/xpidl/xpidl.h +++ b/xpcom/typelib/xpidl/xpidl.h @@ -221,12 +221,6 @@ xpidl_parse_iid(nsID *id, const char *str); (IDL_NODE_UP(node) && \ IDL_NODE_TYPE(IDL_NODE_UP(node)) == IDLN_NATIVE) -/* is this type output in the form " *"? */ -#define STARRED_TYPE(node) (IDL_NODE_TYPE(node) == IDLN_TYPE_STRING || \ - IDL_NODE_TYPE(node) == IDLN_TYPE_WIDE_STRING || \ - (IDL_NODE_TYPE(node) == IDLN_IDENT && \ - UP_IS_AGGREGATE(node))) - #define DIPPER_TYPE(node) \ (NULL != IDL_tree_property_get(node, "domstring") || \ NULL != IDL_tree_property_get(node, "utf8string") || \ diff --git a/xpcom/typelib/xpidl/xpidl_header.c b/xpcom/typelib/xpidl/xpidl_header.c index f808cf9b4803..1e30398fc015 100644 --- a/xpcom/typelib/xpidl/xpidl_header.c +++ b/xpcom/typelib/xpidl/xpidl_header.c @@ -638,14 +638,35 @@ list(TreeState *state) return TRUE; } +typedef enum write_type_mode { + WT_PLAIN, // for use with typedef; also with NS_IMETHOD_() or NS_IMETHODIMP_() + WT_IN, // [in] param or setter + WT_OUT // [out] param, [inout] param, or getter +} write_type_mode; + static gboolean -write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile) +write_type(IDL_tree type_tree, write_type_mode mode, gboolean force_const, FILE *outfile) { + gboolean starred; + if (!type_tree) { fputs("void", outfile); return TRUE; } + /* In parameters for string, reference, and dipper types get const. */ + if (force_const || + (mode == WT_IN && + (IDL_NODE_TYPE(type_tree) == IDLN_TYPE_STRING || + IDL_NODE_TYPE(type_tree) == IDLN_TYPE_WIDE_STRING || + IDL_tree_property_get(type_tree, "nsid") || + IDL_tree_property_get(type_tree, "jsval") || + DIPPER_TYPE(type_tree)))) + { + fputs("const ", outfile); + } + + starred = FALSE; switch (IDL_NODE_TYPE(type_tree)) { case IDLN_TYPE_INTEGER: { gboolean sign = IDL_TYPE_INTEGER(type_tree).f_signed; @@ -674,9 +695,11 @@ write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile) break; case IDLN_TYPE_WIDE_STRING: fputs("PRUnichar *", outfile); + starred = TRUE; break; case IDLN_TYPE_STRING: fputs("char *", outfile); + starred = TRUE; break; case IDLN_TYPE_BOOLEAN: fputs("PRBool", outfile); @@ -712,19 +735,29 @@ write_type(IDL_tree type_tree, gboolean is_out, FILE *outfile) } if (IDL_tree_property_get(type_tree, "ptr")) { fputs(" *", outfile); + starred = TRUE; } else if (IDL_tree_property_get(type_tree, "ref")) { - fputs(" &", outfile); + if (mode == WT_IN || DIPPER_TYPE(type_tree)) { + fputs(" &", outfile); + } } } else { fputs(IDL_IDENT(type_tree).str, outfile); } - if (UP_IS_AGGREGATE(type_tree)) + if (UP_IS_AGGREGATE(type_tree)) { fputs(" *", outfile); + starred = TRUE; + } break; default: fprintf(outfile, "unknown_type_%d", IDL_NODE_TYPE(type_tree)); break; } + + if (!starred) + fputc(' ', outfile); + if (mode == WT_OUT && !DIPPER_TYPE(type_tree)) + fputc('*', outfile); return TRUE; } @@ -784,26 +817,12 @@ write_attr_accessor(IDL_tree attr_tree, FILE * outfile, fputs("cx, ", outfile); } if (mode == AS_DECL || mode == AS_IMPL) { - /* Setters for string, wstring, nsid, domstring, utf8string, - * cstring and astring get const. - */ - if (!getter && - (IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_STRING || - IDL_NODE_TYPE(ATTR_TYPE_DECL(attr_tree)) == IDLN_TYPE_WIDE_STRING || - IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "nsid") || - IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "domstring") || - IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "utf8string") || - IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "cstring") || - IDL_tree_property_get(ATTR_TYPE_DECL(attr_tree), "astring"))) - { - fputs("const ", outfile); - } - - if (!write_type(ATTR_TYPE_DECL(attr_tree), getter, outfile)) + if (!write_type(ATTR_TYPE_DECL(attr_tree), + getter ? WT_OUT : WT_IN, + FALSE, + outfile)) { return FALSE; - fprintf(outfile, "%s%s", - (STARRED_TYPE(attr_tree) ? "" : " "), - (getter && !DIPPER_TYPE(ATTR_TYPE_DECL(attr_tree)))? "*" : ""); + } } fprintf(outfile, "a%c%s)", toupper(attrname[0]), attrname + 1); return TRUE; @@ -915,7 +934,7 @@ do_typedef(TreeState *state) printlist(state->file, doc_comments); fputs("typedef ", state->file); - if (!write_type(type, FALSE, state->file)) + if (!write_type(type, WT_PLAIN, FALSE, state->file)) return FALSE; fputs(" ", state->file); @@ -936,7 +955,7 @@ do_typedef(TreeState *state) printlist(state->file, doc_comments); fputs("typedef ", state->file); - if (!write_type(type, FALSE, state->file)) + if (!write_type(type, WT_PLAIN, FALSE, state->file)) return FALSE; fputs(" ", state->file); fputs(IDL_IDENT(IDL_LIST(dcls).data).str, state->file); @@ -958,43 +977,16 @@ static gboolean write_param(IDL_tree param_tree, FILE *outfile) { IDL_tree param_type_spec = IDL_PARAM_DCL(param_tree).param_type_spec; - gboolean is_in = IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN; - /* in string, wstring, nsid, domstring, utf8string, cstring and - * astring any explicitly marked [const] are const - */ + write_type_mode mode = + (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_IN) ? WT_IN : WT_OUT; + IDL_tree sd = IDL_PARAM_DCL(param_tree).simple_declarator; + gboolean force_const = + (mode == WT_IN && IDL_tree_property_get(sd, "const")) || + (mode == WT_OUT && IDL_tree_property_get(sd, "shared")); - if (is_in && - (IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_STRING || - IDL_NODE_TYPE(param_type_spec) == IDLN_TYPE_WIDE_STRING || - IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, - "const") || - IDL_tree_property_get(param_type_spec, "nsid") || - IDL_tree_property_get(param_type_spec, "domstring") || - IDL_tree_property_get(param_type_spec, "utf8string") || - IDL_tree_property_get(param_type_spec, "cstring") || - IDL_tree_property_get(param_type_spec, "astring"))) { - fputs("const ", outfile); - } - else if (IDL_PARAM_DCL(param_tree).attr == IDL_PARAM_OUT && - IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, - "shared")) { - fputs("const ", outfile); - } - - if (!write_type(param_type_spec, !is_in, outfile)) + if (!write_type(param_type_spec, mode, force_const, outfile)) return FALSE; - /* unless the type ended in a *, add a space */ - if (!STARRED_TYPE(param_type_spec)) - fputc(' ', outfile); - - /* out and inout params get a bonus '*' (unless this is type that has a - * 'dipper' class that is passed in to receive 'out' data) - */ - if (IDL_PARAM_DCL(param_tree).attr != IDL_PARAM_IN && - !DIPPER_TYPE(param_type_spec)) { - fputc('*', outfile); - } /* arrays get a bonus * too */ /* XXX Should this be a leading '*' or a trailing "[]" ?*/ if (IDL_tree_property_get(IDL_PARAM_DCL(param_tree).simple_declarator, @@ -1060,7 +1052,7 @@ write_method_signature(IDL_tree method_tree, FILE *outfile, int mode, if (op_notxpcom) { fputs("NS_IMETHOD_(", outfile); - if (!write_type(op->op_type_spec, FALSE, outfile)) + if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile)) return FALSE; fputc(')', outfile); } else { @@ -1071,7 +1063,7 @@ write_method_signature(IDL_tree method_tree, FILE *outfile, int mode, else if (mode == AS_IMPL) { if (op_notxpcom) { fputs("NS_IMETHODIMP_(", outfile); - if (!write_type(op->op_type_spec, FALSE, outfile)) + if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile)) return FALSE; fputc(')', outfile); } else {