--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -712,17 +712,17 @@ static JSBool
return JS_FALSE;
}
JSTrapStatus
jsd_TrapHandler(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval,
void *closure)
{
- JSDExecHook* jsdhook = (JSDExecHook*) JSVAL_TO_PRIVATE(((jsval)closure));
+ JSDExecHook* jsdhook = (JSDExecHook*)closure;
JSD_ExecutionHookProc hook;
void* hookData;
JSDContext* jsdc;
JSDScript* jsdscript;
JSD_LOCK();
if( NULL == (jsdc = jsd_JSDContextForJSContext(cx)) ||
@@ -795,17 +795,17 @@ jsd_SetExecutionHook(JSDContext*
}
jsdhook->jsdscript = jsdscript;
jsdhook->pc = pc;
jsdhook->hook = hook;
jsdhook->callerdata = callerdata;
if( ! JS_SetTrap(jsdc->dumbContext, jsdscript->script,
(jsbytecode*)pc, jsd_TrapHandler,
- (void*) PRIVATE_TO_JSVAL(jsdhook)) )
+ PRIVATE_TO_JSVAL(jsdhook)) )
{
free(jsdhook);
JSD_UNLOCK();
return JS_FALSE;
}
JS_APPEND_LINK(&jsdhook->links, &jsdscript->hooks);
JSD_UNLOCK();
--- a/js/jsd/jsd_val.c
+++ b/js/jsd/jsd_val.c
@@ -201,20 +201,19 @@ jsd_GetValueInt(JSDContext* jsdc, JSDVal
if(!JSVAL_IS_INT(val))
return 0;
return JSVAL_TO_INT(val);
}
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_PTR_TO_DOUBLE_PTR(&jsdval->val);
}
JSString*
jsd_GetValueString(JSDContext* jsdc, JSDValue* jsdval)
{
JSContext* cx = jsdc->dumbContext;
JSExceptionState* exceptionState;
@@ -337,24 +336,24 @@ static JSDProperty* _newProperty(JSDCont
if(!(jsdprop = (JSDProperty*) calloc(1, sizeof(JSDProperty))))
return NULL;
JS_INIT_CLIST(&jsdprop->links);
jsdprop->nref = 1;
jsdprop->flags = pd->flags | additionalFlags;
jsdprop->slot = pd->slot;
- if(!(jsdprop->name = jsd_NewValue(jsdc, pd->id)))
+ if(!(jsdprop->name = jsd_NewValue(jsdc, JSID_TO_JSVAL(pd->id))))
goto new_prop_fail;
if(!(jsdprop->val = jsd_NewValue(jsdc, pd->value)))
goto new_prop_fail;
if((jsdprop->flags & JSDPD_ALIAS) &&
- !(jsdprop->alias = jsd_NewValue(jsdc, pd->alias)))
+ !(jsdprop->alias = jsd_NewValue(jsdc, JSID_TO_JSVAL(pd->alias))))
goto new_prop_fail;
return jsdprop;
new_prop_fail:
jsd_DropProperty(jsdc, jsdprop);
return NULL;
}
@@ -487,17 +486,17 @@ jsd_GetValueProperty(JSDContext* jsdc, J
JSDProperty* jsdprop;
JSDProperty* iter = NULL;
JSObject* obj;
uintN attrs = 0;
JSBool found;
JSPropertyDesc pd;
const jschar * nameChars;
size_t nameLen;
- jsval val;
+ jsval val, nameval;
if(!jsd_IsValueObject(jsdc, jsdval))
return NULL;
/* If we already have the prop, then return it */
while(NULL != (jsdprop = jsd_IterateProperties(jsdc, jsdval, &iter)))
{
JSString* propName = jsd_GetValueString(jsdc, jsdprop->name);
@@ -543,18 +542,21 @@ jsd_GetValueProperty(JSDContext* jsdc, J
}
else
{
pd.value = val;
}
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, &pd.id))
+ return NULL;
+ pd.slot = pd.spare = 0;
+ pd.alias = JSID_NULL;
pd.flags |= (attrs & JSPROP_ENUMERATE) ? JSPD_ENUMERATE : 0
| (attrs & JSPROP_READONLY) ? JSPD_READONLY : 0
| (attrs & JSPROP_PERMANENT) ? JSPD_PERMANENT : 0;
return _newProperty(jsdc, &pd, JSDPD_HINTED);
}
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -33,18 +33,16 @@
* 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 ***** */
#include "jsdbgapi.h"
-#include "jscntxt.h"
-#include "jsfun.h"
#include "jsd_xpc.h"
#include "nsIXPConnect.h"
#include "nsIGenericFactory.h"
#include "nsIServiceManager.h"
#include "nsIScriptGlobalObject.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
@@ -1009,26 +1007,27 @@ jsdScript::CreatePPLineMap()
JSAutoRequest ar(cx);
JSObject *obj = JS_NewObject(cx, NULL, NULL, NULL);
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
JSScript *script;
PRUint32 baseLine;
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)
return nsnull;
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);
if (!fun || !(script = JS_GetFunctionScript(cx, fun)))
return nsnull;
baseLine = 3;
} else {
JSString *jsstr = JS_DecompileScript (cx, JSD_GetJSScript(mCx, mScript),
@@ -1227,60 +1226,55 @@ jsdScript::GetParameterNames(PRUint32* c
if (!cx) {
NS_WARNING("No default context !?");
return NS_ERROR_FAILURE;
}
JSFunction *fun = JSD_GetJSFunction (mCx, mScript);
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<PRUnichar**>(NS_Alloc(fun->nargs * sizeof(PRUnichar*)));
+ static_cast<PRUnichar**>(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<PRUnichar*>(JS_GetStringChars(str)),
JS_GetStringLength(str));
if (!ret[i]) {
NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(i, ret);
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
}
}
- 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;
}
NS_IMETHODIMP
jsdScript::GetFunctionObject(jsdIValue **_rval)
{
JSFunction *fun = JSD_GetJSFunction(mCx, mScript);
@@ -1479,18 +1473,17 @@ jsdScript::IsLineExecutable(PRUint32 aLi
return NS_OK;
}
NS_IMETHODIMP
jsdScript::SetBreakpoint(PRUint32 aPC)
{
ASSERT_VALID_EPHEMERAL;
jsuword pc = mFirstPC + aPC;
- JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc,
- reinterpret_cast<void *>(PRIVATE_TO_JSVAL(NULL)));
+ JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL);
return NS_OK;
}
NS_IMETHODIMP
jsdScript::ClearBreakpoint(PRUint32 aPC)
{
ASSERT_VALID_EPHEMERAL;
jsuword pc = mFirstPC + aPC;
@@ -1984,17 +1977,17 @@ jsdStackFrame::Eval (const nsAString &by
mStackFrameInfo,
char_bytes, bytes.Length(),
PromiseFlatCString(fileName).get(),
line, &jv);
if (!*_rval) {
if (JS_IsExceptionPending(cx))
JS_GetPendingException (cx, &jv);
else
- jv = 0;
+ jv = JSVAL_NULL;
}
JS_RestoreExceptionState (cx, estate);
#ifdef DEBUG
JSContext* poppedCX;
rv = stack->Pop(&poppedCX);
NS_ASSERTION(NS_SUCCEEDED(rv) && poppedCX == cx, "bad pop");
@@ -2431,18 +2424,18 @@ jsdService::SetInitAtStartup (PRBool sta
if (mInitAtStartup == triUnknown) {
/* side effect sets mInitAtStartup */
rv = GetInitAtStartup(nsnull);
if (NS_FAILED(rv))
return rv;
}
- if (state && mInitAtStartup == triYes ||
- !state && mInitAtStartup == triNo) {
+ if ((state && mInitAtStartup == triYes) ||
+ (!state && mInitAtStartup == triNo)) {
/* already in the requested state */
return NS_OK;
}
nsCOMPtr<nsICategoryManager>
categoryManager(do_GetService(NS_CATMAN_CTRID, &rv));
if (NS_FAILED(rv))
return rv;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -33,16 +33,18 @@
* 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 ***** */
+#define __STDC_LIMIT_MACROS
+
/*
* JavaScript API.
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "jstypes.h"
@@ -92,59 +94,54 @@
#include "jscntxtinlines.h"
#if JS_HAS_XML_SUPPORT
#include "jsxml.h"
#endif
using namespace js;
+/* Assumed by IS_SAME_JSVAL */
+JS_STATIC_ASSERT(sizeof(JSBool) == sizeof(int32));
+
#ifdef HAVE_VA_LIST_AS_ARRAY
#define JS_ADDRESSOF_VA_LIST(ap) ((va_list *)(ap))
#else
#define JS_ADDRESSOF_VA_LIST(ap) (&(ap))
#endif
#if defined(JS_THREADSAFE)
#define CHECK_REQUEST(cx) \
JS_ASSERT((cx)->requestDepth || (cx)->thread == (cx)->runtime->gcThread)
#else
#define CHECK_REQUEST(cx) ((void)0)
#endif
-/* Check that we can cast JSObject* as jsval without tag bit manipulations. */
-JS_STATIC_ASSERT(JSVAL_OBJECT == 0);
-
-/* 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);
-
JS_PUBLIC_API(int64)
JS_Now()
{
return PRMJ_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)
JS_GetEmptyStringValue(JSContext *cx)
{
return STRING_TO_JSVAL(cx->runtime->emptyString);
}
@@ -198,32 +195,32 @@ JS_ConvertArgumentsVA(JSContext *cx, uin
if (isspace(c))
continue;
if (c == '/') {
required = JS_FALSE;
continue;
}
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);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_MORE_ARGS_NEEDED,
JS_GetFunctionName(fun), numBuf,
(argc == 1) ? "" : "s");
}
return JS_FALSE;
}
break;
}
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 *)))
return JS_FALSE;
break;
case 'i':
if (!JS_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
return JS_FALSE;
@@ -243,17 +240,17 @@ JS_ConvertArgumentsVA(JSContext *cx, uin
case 'I':
if (!JS_ValueToNumber(cx, *sp, &d))
return JS_FALSE;
*va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
break;
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);
if (c == 's') {
const char *bytes = js_GetStringBytes(cx, str);
if (!bytes)
return JS_FALSE;
*va_arg(ap, const char **) = bytes;
@@ -262,23 +259,25 @@ JS_ConvertArgumentsVA(JSContext *cx, uin
if (!chars)
return JS_FALSE;
*va_arg(ap, const jschar **) = chars;
} else {
*va_arg(ap, JSString **) = str;
}
break;
case 'o':
- if (!js_ValueToObject(cx, *sp, &obj))
+ {
+ Value objv;
+ if (!js_ValueToObjectOrNull(cx, Valueify(*sp), Valueify(sp)))
return JS_FALSE;
- *sp = OBJECT_TO_JSVAL(obj);
- *va_arg(ap, JSObject **) = obj;
+ *va_arg(ap, JSObject **) = JSVAL_TO_OBJECT(*sp);
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);
*va_arg(ap, JSFunction **) = GET_FUNCTION_PRIVATE(cx, obj);
break;
case 'v':
*va_arg(ap, jsval *) = *sp;
break;
@@ -346,51 +345,45 @@ JS_RemoveArgumentFormatter(JSContext *cx
}
JS_PUBLIC_API(JSBool)
JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
{
JSBool ok;
JSObject *obj;
JSString *str;
- jsdouble d, *dp;
+ jsdouble d;
CHECK_REQUEST(cx);
switch (type) {
case JSTYPE_VOID:
*vp = JSVAL_VOID;
ok = JS_TRUE;
break;
case JSTYPE_OBJECT:
- ok = js_ValueToObject(cx, v, &obj);
- if (ok)
- *vp = OBJECT_TO_JSVAL(obj);
+ ok = js_ValueToObjectOrNull(cx, Valueify(v), Valueify(vp));
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];
JS_snprintf(numBuf, sizeof numBuf, "%d", (int)type);
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_TYPE,
numBuf);
ok = JS_FALSE;
break;
@@ -398,148 +391,133 @@ JS_ConvertValue(JSContext *cx, jsval v,
}
return ok;
}
JS_PUBLIC_API(JSBool)
JS_ValueToObject(JSContext *cx, jsval v, JSObject **objp)
{
CHECK_REQUEST(cx);
- return js_ValueToObject(cx, v, objp);
+ Value objv;
+ return js_ValueToObjectOrNull(cx, Valueify(v), &objv);
+ *objp = objv.asObjectOrNull();
}
JS_PUBLIC_API(JSFunction *)
JS_ValueToFunction(JSContext *cx, jsval v)
{
CHECK_REQUEST(cx);
- return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
+ return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
}
JS_PUBLIC_API(JSFunction *)
JS_ValueToConstructor(JSContext *cx, jsval v)
{
CHECK_REQUEST(cx);
- return js_ValueToFunction(cx, &v, JSV2F_SEARCH_STACK);
+ return js_ValueToFunction(cx, Valueify(&v), JSV2F_SEARCH_STACK);
}
JS_PUBLIC_API(JSString *)
JS_ValueToString(JSContext *cx, jsval v)
{
CHECK_REQUEST(cx);
- return js_ValueToString(cx, v);
+ return js_ValueToString(cx, Valueify(v));
}
JS_PUBLIC_API(JSString *)
JS_ValueToSource(JSContext *cx, jsval v)
{
CHECK_REQUEST(cx);
- return js_ValueToSource(cx, v);
+ return js_ValueToSource(cx, Valueify(v));
}
JS_PUBLIC_API(JSBool)
JS_ValueToNumber(JSContext *cx, jsval v, jsdouble *dp)
{
CHECK_REQUEST(cx);
- AutoValueRooter tvr(cx, v);
- return ValueToNumber(cx, v, dp);
+ AutoValueRooter tvr(cx, Valueify(v));
+ return ValueToNumber(cx, tvr.addr(), dp);
}
JS_PUBLIC_API(JSBool)
JS_DoubleIsInt32(jsdouble d, jsint *ip)
{
- return JSDOUBLE_IS_INT(d, *ip);
+ return JSDOUBLE_IS_INT32(d, *ip);
}
JS_PUBLIC_API(JSBool)
JS_ValueToECMAInt32(JSContext *cx, jsval v, int32 *ip)
{
CHECK_REQUEST(cx);
- AutoValueRooter tvr(cx, v);
- return ValueToECMAInt32(cx, v, (int32_t *)ip);
+ AutoValueRooter tvr(cx, Valueify(v));
+ return ValueToECMAInt32(cx, tvr.addr(), (int32_t *)ip);
}
JS_PUBLIC_API(JSBool)
JS_ValueToECMAUint32(JSContext *cx, jsval v, uint32 *ip)
{
CHECK_REQUEST(cx);
- AutoValueRooter tvr(cx, v);
- return ValueToECMAUint32(cx, v, (uint32_t *)ip);
+ AutoValueRooter tvr(cx, Valueify(v));
+ return ValueToECMAUint32(cx, tvr.addr(), (uint32_t *)ip);
}
JS_PUBLIC_API(JSBool)
JS_ValueToInt32(JSContext *cx, jsval v, int32 *ip)
{
CHECK_REQUEST(cx);
- AutoValueRooter tvr(cx, v);
- return ValueToInt32(cx, v, (int32_t *)ip);
+ AutoValueRooter tvr(cx, Valueify(v));
+ return ValueToInt32(cx, tvr.addr(), (int32_t *)ip);
}
JS_PUBLIC_API(JSBool)
JS_ValueToUint16(JSContext *cx, jsval v, uint16 *ip)
{
CHECK_REQUEST(cx);
- AutoValueRooter tvr(cx, v);
- return ValueToUint16(cx, v, (uint16_t *)ip);
+ AutoValueRooter tvr(cx, Valueify(v));
+ return ValueToUint16(cx, tvr.addr(), (uint16_t *)ip);
}
JS_PUBLIC_API(JSBool)
JS_ValueToBoolean(JSContext *cx, jsval v, JSBool *bp)
{
CHECK_REQUEST(cx);
- *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);
- 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 *)
JS_GetTypeName(JSContext *cx, JSType type)
{
if ((uintN)type >= (uintN)JSTYPE_LIMIT)
return NULL;
return JS_TYPE_STR(type);
}
JS_PUBLIC_API(JSBool)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval 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)
{
- return js_SameValue(v1, v2, cx);
+ return SameValue(cx, Valueify(v1), Valueify(v2));
}
/************************************************************************/
/*
* Has a new runtime ever been created? This flag is used to detect unsafe
* changes to js_CStringsAreUTF8 after a runtime has been created, and to
* ensure that "first checks" on runtime creation are run only once.
@@ -677,31 +655,16 @@ JS_NewRuntime(uint32 maxbytes)
if (*fmt == '{' && isdigit(fmt[1])) \
++numfmtspecs; \
} \
JS_ASSERT(count == numfmtspecs); \
JS_END_MACRO;
#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 */
void *mem = js_calloc(sizeof(JSRuntime));
if (!mem)
return NULL;
@@ -1143,35 +1106,35 @@ js_InitFunctionAndObjectClasses(JSContex
JSObject *ctor;
ctor = JS_GetConstructor(cx, fun_proto);
if (!ctor) {
fun_proto = NULL;
goto out;
}
obj->defineProperty(cx, ATOM_TO_JSID(CLASS_ATOM(cx, Function)),
- OBJECT_TO_JSVAL(ctor), 0, 0, 0);
+ FunObjValue(*ctor), 0, 0, 0);
}
/* Initialize the object class next so Object.prototype works. */
if (!js_GetClassPrototype(cx, obj, JSProto_Object, &obj_proto)) {
fun_proto = NULL;
goto out;
}
if (!obj_proto)
obj_proto = js_InitObjectClass(cx, obj);
if (!obj_proto) {
fun_proto = NULL;
goto out;
}
/* Function.prototype and the global object delegate to Object.prototype. */
- fun_proto->setProto(obj_proto);
+ fun_proto->setProto(NonFunObjPtr(*obj_proto));
if (!obj->getProto())
- obj->setProto(obj_proto);
+ obj->setProto(NonFunObjPtr(*obj_proto));
out:
/* If resolving, remove the other entry (Object or Function) from table. */
JS_DHashTableOperate(table, &key, JS_DHASH_REMOVE);
if (!resolving) {
/* If not resolving, remove the first entry added above, for Object. */
JS_ASSERT(key.id == \
ATOM_TO_JSID(rt->atomState.classAtoms[JSProto_Function]));
@@ -1187,18 +1150,18 @@ JS_PUBLIC_API(JSBool)
JS_InitStandardClasses(JSContext *cx, JSObject *obj)
{
JSAtom *atom;
CHECK_REQUEST(cx);
/* Define a top-level property 'undefined' with the undefined value. */
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), sUndefinedValue,
+ PropertyStub, PropertyStub,
JSPROP_PERMANENT | JSPROP_READONLY)) {
return JS_FALSE;
}
/* Function and Object require cooperative bootstrapping magic. */
if (!js_InitFunctionAndObjectClasses(cx, obj))
return JS_FALSE;
@@ -1229,17 +1192,17 @@ JS_InitStandardClasses(JSContext *cx, JS
#define EAGER_ATOM_AND_CLASP(name) EAGER_CLASS_ATOM(name), CLASP(name)
#define EAGER_ATOM_AND_XCLASP(name) EAGER_CLASS_ATOM(name), XCLASP(name)
#define LAZY_ATOM(name) ATOM_OFFSET(lazy.name), js_##name##_str
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 *
StdNameToAtom(JSContext *cx, JSStdName *stdn)
{
size_t offset;
JSAtom *atom;
const char *name;
@@ -1395,18 +1358,18 @@ JS_ResolveStandardClass(JSContext *cx, J
return JS_TRUE;
idstr = JSVAL_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), sUndefinedValue,
+ PropertyStub, PropertyStub,
JSPROP_PERMANENT | JSPROP_READONLY);
}
/* Try for class constructors/prototypes named by well-known atoms. */
stdnm = NULL;
for (i = 0; standard_class_atoms[i].init; i++) {
atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
if (idstr == ATOM_TO_STRING(atom)) {
@@ -1486,18 +1449,18 @@ JS_EnumerateStandardClasses(JSContext *c
uintN i;
CHECK_REQUEST(cx);
rt = cx->runtime;
/* 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), sUndefinedValue,
+ PropertyStub, PropertyStub,
JSPROP_PERMANENT | JSPROP_READONLY)) {
return JS_FALSE;
}
/* Initialize any classes that have not been resolved yet. */
for (i = 0; standard_class_atoms[i].init; i++) {
atom = OFFSET_TO_ATOM(rt, standard_class_atoms[i].atomOffset);
if (!AlreadyHasOwnProperty(cx, obj, atom) &&
@@ -1661,34 +1624,35 @@ JS_GetScopeChain(JSContext *cx)
* acting as a stand-in.
*/
JSObject *obj = cx->globalObject;
if (!obj) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INACTIVE);
return NULL;
}
- OBJ_TO_INNER_OBJECT(cx, obj);
+ Innerize(cx, &obj);
return obj;
}
return js_GetScopeChain(cx, fp);
}
JS_PUBLIC_API(JSObject *)
JS_GetGlobalForObject(JSContext *cx, JSObject *obj)
{
return obj->getGlobal();
}
JS_PUBLIC_API(jsval)
JS_ComputeThis(JSContext *cx, jsval *vp)
{
- if (!js_ComputeThis(cx, vp + 2))
+ Value *thisvp;
+ if (!ComputeThisValueFromVp(cx, Valueify(vp), &thisvp))
return JSVAL_NULL;
- return vp[1];
+ return Jsvalify(*thisvp);
}
JS_PUBLIC_API(void *)
JS_malloc(JSContext *cx, size_t nbytes)
{
return cx->malloc(nbytes);
}
@@ -1718,75 +1682,115 @@ JS_strdup(JSContext *cx, const char *s)
n = strlen(s) + 1;
p = cx->malloc(n);
if (!p)
return NULL;
return (char *)memcpy(p, s, n);
}
-JS_PUBLIC_API(jsdouble *)
-JS_NewDouble(JSContext *cx, jsdouble d)
+#undef JS_AddRoot
+
+JS_PUBLIC_API(JSBool)
+JS_AddValueRoot(JSContext *cx, js::Value *vp)
{
CHECK_REQUEST(cx);
- return js_NewWeaklyRootedDouble(cx, d);
+ return js_AddRoot(cx, vp, NULL);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddStringRoot(JSContext *cx, JSString **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, NULL);
}
JS_PUBLIC_API(JSBool)
-JS_NewDoubleValue(JSContext *cx, jsdouble d, jsval *rval)
-{
- jsdouble *dp;
-
+JS_AddObjectRoot(JSContext *cx, JSObject **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, NULL);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedValueRoot(JSContext *cx, js::Value *vp, const char *name)
+{
CHECK_REQUEST(cx);
- dp = js_NewWeaklyRootedDouble(cx, d);
- if (!dp)
- return JS_FALSE;
- *rval = DOUBLE_TO_JSVAL(dp);
- return JS_TRUE;
+ return js_AddRoot(cx, vp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedStringRoot(JSContext *cx, JSString **rp, const char *name)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedObjectRoot(JSContext *cx, JSObject **rp, const char *name)
+{
+ CHECK_REQUEST(cx);
+ return js_AddGCThingRoot(cx, (void **)rp, name);
}
JS_PUBLIC_API(JSBool)
-JS_NewNumberValue(JSContext *cx, jsdouble d, jsval *rval)
+JS_AddNamedValueRootRT(JSRuntime *rt, js::Value *vp, const char *name)
+{
+ return js_AddRootRT(rt, vp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedStringRootRT(JSRuntime *rt, JSString **rp, const char *name)
+{
+ return js_AddGCThingRootRT(rt, (void **)rp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_AddNamedObjectRootRT(JSRuntime *rt, JSObject **rp, const char *name)
+{
+ return js_AddGCThingRootRT(rt, (void **)rp, name);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_RemoveValueRoot(JSContext *cx, js::Value *vp)
{
CHECK_REQUEST(cx);
- return js_NewWeaklyRootedNumber(cx, d, rval);
-}
-
-#undef JS_AddRoot
-JS_PUBLIC_API(JSBool)
-JS_AddRoot(JSContext *cx, void *rp)
-{
- CHECK_REQUEST(cx);
- return js_AddRoot(cx, rp, NULL);
+ return js_RemoveRoot(cx->runtime, (void *)vp);
}
JS_PUBLIC_API(JSBool)
-JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name)
-{
- return js_AddRootRT(rt, rp, name);
+JS_RemoveStringRoot(JSContext *cx, JSString **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_RemoveRoot(cx->runtime, (void *)rp);
+}
+
+JS_PUBLIC_API(JSBool)
+JS_RemoveObjectRoot(JSContext *cx, JSObject **rp)
+{
+ CHECK_REQUEST(cx);
+ return js_RemoveRoot(cx->runtime, (void *)rp);
}
JS_PUBLIC_API(JSBool)
-JS_RemoveRoot(JSContext *cx, void *rp)
-{
- CHECK_REQUEST(cx);
- return js_RemoveRoot(cx->runtime, rp);
+JS_RemoveValueRootRT(JSRuntime *rt, js::Value *vp)
+{
+ return js_RemoveRoot(rt, (void *)vp);
}
JS_PUBLIC_API(JSBool)
-JS_RemoveRootRT(JSRuntime *rt, void *rp)
-{
- return js_RemoveRoot(rt, rp);
+JS_RemoveStringRootRT(JSRuntime *rt, JSString **rp)
+{
+ return js_RemoveRoot(rt, (void *)rp);
}
JS_PUBLIC_API(JSBool)
-JS_AddNamedRoot(JSContext *cx, void *rp, const char *name)
-{
- CHECK_REQUEST(cx);
- return js_AddRoot(cx, rp, name);
+JS_RemoveObjectRootRT(JSRuntime *rt, JSObject **rp)
+{
+ return js_RemoveRoot(rt, (void *)rp);
}
JS_PUBLIC_API(void)
JS_ClearNewbornRoots(JSContext *cx)
{
JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
}
@@ -1803,31 +1807,31 @@ JS_LeaveLocalRootScope(JSContext *cx)
CHECK_REQUEST(cx);
js_LeaveLocalRootScope(cx);
}
JS_PUBLIC_API(void)
JS_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
{
CHECK_REQUEST(cx);
- js_LeaveLocalRootScopeWithResult(cx, rval);
+ js_LeaveLocalRootScopeWithResult(cx, Valueify(rval));
}
JS_PUBLIC_API(void)
JS_ForgetLocalRoot(JSContext *cx, void *thing)
{
CHECK_REQUEST(cx);
- js_ForgetLocalRoot(cx, (jsval) thing);
+ js_ForgetLocalRoot(cx, thing);
}
#ifdef DEBUG
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);
}
#endif /* DEBUG */
JS_PUBLIC_API(uint32)
@@ -1883,17 +1887,17 @@ JS_TraceRuntime(JSTracer *trc)
LeaveTrace(trc->context);
js_TraceRuntime(trc, allAtoms);
}
JS_PUBLIC_API(void)
JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
{
- js_CallGCMarker(trc, thing, kind);
+ CallGCMarker(trc, thing, kind);
}
#ifdef DEBUG
#ifdef HAVE_XPCONNECT
#include "dump_xpc.h"
#endif
@@ -1906,17 +1910,17 @@ JS_PrintTraceThingInfo(char *buf, size_t
if (bufsize == 0)
return;
switch (kind) {
case JSTRACE_OBJECT:
{
JSObject *obj = (JSObject *)thing;
- JSClass *clasp = obj->getClass();
+ Class *clasp = obj->getClass();
name = clasp->name;
#ifdef HAVE_XPCONNECT
if (clasp->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) {
void *privateThing = obj->getPrivate();
if (privateThing) {
const char *xpcClassName = GetXPCObjectClassName(privateThing);
if (xpcClassName)
@@ -1958,17 +1962,17 @@ JS_PrintTraceThingInfo(char *buf, size_t
if (details && bufsize > 2) {
*buf++ = ' ';
bufsize--;
switch (kind) {
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) {
JS_snprintf(buf, bufsize, "<newborn>");
} else if (FUN_OBJECT(fun) != obj) {
JS_snprintf(buf, bufsize, "%p", fun);
} else {
if (fun->atom && ATOM_IS_STRING(fun->atom))
@@ -2262,31 +2266,31 @@ JS_DumpHeap(JSContext *cx, FILE *fp, voi
JS_ASSERT(depth == 1);
JS_DHashTableFinish(&dtrc.visited);
return dtrc.ok;
}
#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;
trc = (JSTracer *)arg;
if (!trc)
trc = cx->runtime->gcMarkingTracer;
else
JS_ASSERT(trc == cx->runtime->gcMarkingTracer);
#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);
+ CallGCMarkerIfGCThing(trc, Valueify(v));
}
extern JS_PUBLIC_API(JSBool)
JS_IsGCMarkingTracer(JSTracer *trc)
{
return IS_GC_MARKING_TRACER(trc);
}
@@ -2524,128 +2528,113 @@ JS_SetScriptStackQuota(JSContext *cx, si
/************************************************************************/
JS_PUBLIC_API(void)
JS_DestroyIdArray(JSContext *cx, JSIdArray *ida)
{
cx->free(ida);
}
-JS_PUBLIC_API(JSBool)
-JS_ValueToId(JSContext *cx, jsval v, jsid *idp)
+JS_PUBLIC_API(jsval)
+JSID_TO_JSVAL(jsid id)
{
CHECK_REQUEST(cx);
- 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 Jsvalify(IdToValue(id));
+}
+
+JS_PUBLIC_API(JSBool)
+JS_ValueToId(JSContext *cx, const jsval *vp, jsid *idp)
+{
+ CHECK_REQUEST(cx);
+ return ValueToId(cx, Valueify(*vp), idp);
}
JS_PUBLIC_API(JSBool)
JS_IdToValue(JSContext *cx, jsid id, jsval *vp)
{
CHECK_REQUEST(cx);
- *vp = ID_TO_VALUE(id);
+ *vp = Jsvalify(IdToValue(id));
return JS_TRUE;
}
-JS_PUBLIC_API(JSBool)
-JS_PropertyStub(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+namespace js {
+
+JSBool
+PropertyStub(JSContext *cx, JSObject *obj, jsid id, Value *vp)
{
return JS_TRUE;
}
-JS_PUBLIC_API(JSBool)
-JS_EnumerateStub(JSContext *cx, JSObject *obj)
+JSBool
+EnumerateStub(JSContext *cx, JSObject *obj)
{
return JS_TRUE;
}
-JS_PUBLIC_API(JSBool)
-JS_ResolveStub(JSContext *cx, JSObject *obj, jsval id)
+JSBool
+ResolveStub(JSContext *cx, JSObject *obj, jsid id)
{
return JS_TRUE;
}
-JS_PUBLIC_API(JSBool)
-JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
+JSBool
+ConvertStub(JSContext *cx, JSObject *obj, JSType type, Value *vp)
{
return js_TryValueOf(cx, obj, type, vp);
}
-JS_PUBLIC_API(void)
-JS_FinalizeStub(JSContext *cx, JSObject *obj)
-{
-}
+void
+FinalizeStub(JSContext *cx, JSObject *obj)
+{}
+
+} /* namespace js */
+
+JS_PUBLIC_DATA(JSPropertyOp) JS_PropertyStub = Jsvalify(PropertyStub);
+JS_PUBLIC_DATA(JSEnumerateOp) JS_EnumerateStub = EnumerateStub;
+JS_PUBLIC_DATA(JSResolveOp) JS_ResolveStub = ResolveStub;
+JS_PUBLIC_DATA(JSConvertOp) JS_ConvertStub = Jsvalify(ConvertStub);
+JS_PUBLIC_DATA(JSFinalizeOp) JS_FinalizeStub = FinalizeStub;
JS_PUBLIC_API(JSObject *)
JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto,
JSClass *clasp, JSNative constructor, uintN nargs,
JSPropertySpec *ps, JSFunctionSpec *fs,
JSPropertySpec *static_ps, JSFunctionSpec *static_fs)
{
CHECK_REQUEST(cx);
- 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);
}
#ifdef JS_THREADSAFE
JS_PUBLIC_API(JSClass *)
JS_GetClass(JSContext *cx, JSObject *obj)
{
return 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);
- 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)
{
- return js_HasInstance(cx, obj, v, bp);
+ return js_HasInstance(cx, obj, Valueify(&v), bp);
}
JS_PUBLIC_API(void *)
JS_GetPrivate(JSContext *cx, JSObject *obj)
{
return obj->getPrivate();
}
@@ -2655,17 +2644,17 @@ JS_SetPrivate(JSContext *cx, JSObject *o
obj->setPrivate(data);
return true;
}
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();
}
JS_PUBLIC_API(JSObject *)
JS_GetPrototype(JSContext *cx, JSObject *obj)
{
JSObject *proto;
@@ -2692,73 +2681,76 @@ JS_GetParent(JSContext *cx, JSObject *ob
/* Beware ref to dead object (we may be called from obj's finalizer). */
return parent && parent->map ? parent : NULL;
}
JS_PUBLIC_API(JSBool)
JS_SetParent(JSContext *cx, JSObject *obj, JSObject *parent)
{
CHECK_REQUEST(cx);
+ JS_ASSERT(!parent->isFunction() &&
+ "Functions may not be set as the parents of objects.");
return js_SetProtoOrParent(cx, obj, JSSLOT_PARENT, parent, JS_FALSE);
}
JS_PUBLIC_API(JSObject *)
JS_GetConstructor(JSContext *cx, JSObject *proto)
{
- jsval cval;
+ Value cval;
CHECK_REQUEST(cx);
{
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
if (!proto->getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.constructorAtom), &cval))
return NULL;
}
- if (!VALUE_IS_FUNCTION(cx, cval)) {
+ if (!cval.isFunObj()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NO_CONSTRUCTOR,
proto->getClass()->name);
return NULL;
}
- return JSVAL_TO_OBJECT(cval);
+ return &cval.asFunObj();
}
JS_PUBLIC_API(JSBool)
JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
{
JS_ASSERT(JSID_IS_OBJECT(obj));
*idp = OBJECT_TO_JSID(obj);
return JS_TRUE;
}
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);
+ Class *clasp = Valueify(jsclasp);
if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */
return js_NewObject(cx, clasp, proto, parent);
}
JS_PUBLIC_API(JSObject *)
-JS_NewObjectWithGivenProto(JSContext *cx, JSClass *clasp, JSObject *proto,
+JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto,
JSObject *parent)
{
CHECK_REQUEST(cx);
+ Class *clasp = Valueify(jsclasp);
if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */
return js_NewObjectWithGivenProto(cx, clasp, proto, parent);
}
JS_PUBLIC_API(JSBool)
JS_SealObject(JSContext *cx, JSObject *obj, JSBool deep)
{
JSScope *scope;
JSIdArray *ida;
uint32 nslots, i;
- jsval v;
if (obj->isDenseArray() && !js_MakeArraySlow(cx, obj))
return JS_FALSE;
if (!obj->isNative()) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_CANT_SEAL_OBJECT,
obj->getClass()->name);
@@ -2798,63 +2790,66 @@ JS_SealObject(JSContext *cx, JSObject *o
/* If we are not sealing an entire object graph, we're done. */
if (!deep)
return JS_TRUE;
/* 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.asObject(), deep))
return JS_FALSE;
}
return JS_TRUE;
}
JS_PUBLIC_API(JSObject *)
-JS_ConstructObject(JSContext *cx, JSClass *clasp, JSObject *proto,
+JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto,
JSObject *parent)
{
CHECK_REQUEST(cx);
+ 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);
+ 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
-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)
{
if (flags != 0 && obj->isNative()) {
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
- return !!js_DefineNativeProperty(cx, obj, id, value, getter, setter,
- attrs, flags, tinyid, NULL);
+ return !!js_DefineNativeProperty(cx, obj, id, value,
+ getter, setter, attrs, flags,
+ tinyid, NULL);
}
return obj->defineProperty(cx, id, value, getter, setter, attrs);
}
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;
JSAtom *atom;
if (attrs & JSPROP_INDEX) {
id = INT_TO_JSID(intptr_t(name));
atom = NULL;
@@ -2868,65 +2863,62 @@ DefineProperty(JSContext *cx, JSObject *
return DefinePropertyById(cx, obj, id, value, getter, setter, attrs,
flags, tinyid);
}
#define AUTO_NAMELEN(s,n) (((n) == (size_t)-1) ? js_strlen(s) : (n))
static JSBool
DefineUCProperty(JSContext *cx, JSObject *obj,
- const jschar *name, size_t namelen, jsval value,
- JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
+ const jschar *name, size_t namelen, const Value &value,
+ PropertyOp getter, PropertyOp setter, uintN attrs,
uintN flags, intN tinyid)
{
JSAtom *atom;
atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
if (!atom)
return JS_FALSE;
if (flags != 0 && obj->isNative()) {
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
- return !!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
- getter, setter, attrs, flags, tinyid,
- NULL);
+ return !!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom),
+ value, getter, setter, attrs,
+ flags, tinyid, NULL);
}
- return obj->defineProperty(cx, ATOM_TO_JSID(atom), value, getter, setter, attrs);
+ return obj->defineProperty(cx, ATOM_TO_JSID(atom), value, getter,
+ setter, attrs);
}
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);
+ Class *clasp = Valueify(jsclasp);
if (!clasp)
clasp = &js_ObjectClass; /* default class is Object */
- nobj = js_NewObject(cx, clasp, proto, obj);
+ JSObject *nobj = js_NewObject(cx, clasp, proto, obj);
if (!nobj)
return NULL;
- if (!DefineProperty(cx, obj, name, OBJECT_TO_JSVAL(nobj), NULL, NULL, attrs,
+ if (!DefineProperty(cx, obj, name, Value(nobj), NULL, NULL, attrs,
0, 0)) {
return NULL;
}
return nobj;
}
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(cds->dval);
attrs = cds->flags;
if (!attrs)
attrs = JSPROP_READONLY | JSPROP_PERMANENT;
ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
if (!ok)
break;
}
return ok;
@@ -2934,57 +2926,62 @@ JS_DefineConstDoubles(JSContext *cx, JSO
JS_PUBLIC_API(JSBool)
JS_DefineProperties(JSContext *cx, JSObject *obj, JSPropertySpec *ps)
{
JSBool ok;
CHECK_REQUEST(cx);
for (ok = JS_TRUE; ps->name; ps++) {
- ok = DefineProperty(cx, obj, ps->name, JSVAL_VOID,
- ps->getter, ps->setter, ps->flags,
+ ok = DefineProperty(cx, obj, ps->name, sUndefinedValue,
+ Valueify(ps->getter), Valueify(ps->setter), ps->flags,
JSScopeProperty::HAS_SHORTID, ps->tinyid);
if (!ok)
break;
}
return ok;
}
JS_PUBLIC_API(JSBool)
JS_DefineProperty(JSContext *cx, JSObject *obj, const char *name, jsval value,
JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
{
CHECK_REQUEST(cx);
- 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_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
{
CHECK_REQUEST(cx);
- 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_DefinePropertyWithTinyId(JSContext *cx, JSObject *obj, const char *name,
int8 tinyid, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs)
{
CHECK_REQUEST(cx);
- 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);
}
JS_PUBLIC_API(JSBool)
JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp)
{
CHECK_REQUEST(cx);
- return js_DefineOwnProperty(cx, obj, id, descriptor, bp);
+ return js_DefineOwnProperty(cx, obj, id, Valueify(descriptor), bp);
}
static JSBool
LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSObject **objp, JSProperty **propp)
{
JSAutoResolveFlags rf(cx, flags);
id = js_CheckForStringIndex(id);
@@ -3051,44 +3048,45 @@ JS_AliasProperty(JSContext *cx, JSObject
!= NULL);
}
obj->dropProperty(cx, prop);
return ok;
}
static JSBool
LookupResult(JSContext *cx, JSObject *obj, JSObject *obj2, JSProperty *prop,
- jsval *vp)
+ Value *vp)
{
if (!prop) {
/* XXX bad API: no way to tell "not defined" from "void value" */
- *vp = JSVAL_VOID;
+ vp->setUndefined();
return JS_TRUE;
}
JSBool ok = JS_TRUE;
if (obj2->isNative()) {
JSScopeProperty *sprop = (JSScopeProperty *) prop;
if (sprop->isMethod()) {
AutoScopePropertyRooter root(cx, sprop);
JS_UNLOCK_OBJ(cx, obj2);
- *vp = sprop->methodValue();
+ vp->copy(sprop->methodValue());
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->copy(obj->lockedGetSlot(sprop->slot));
+ else
+ vp->setBoolean(true);
} else if (obj2->isDenseArray()) {
ok = js_GetDenseArrayElementValue(cx, obj2, prop, vp);
} else {
/* XXX bad API: no way to return "defined but value unknown" */
- *vp = JSVAL_TRUE;
+ vp->setBoolean(true);
}
obj2->dropProperty(cx, prop);
return ok;
}
static JSBool
GetPropertyAttributesById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSBool own, JSPropertyDescriptor *desc)
@@ -3113,21 +3111,22 @@ GetPropertyAttributesById(JSContext *cx,
desc->obj = obj2;
ok = obj2->getAttributes(cx, id, prop, &desc->attrs);
if (ok) {
if (obj2->isNative()) {
JSScopeProperty *sprop = (JSScopeProperty *) prop;
- desc->getter = sprop->getter();
- desc->setter = sprop->setter();
- desc->value = SPROP_HAS_VALID_SLOT(sprop, obj2->scope())
- ? obj2->lockedGetSlot(sprop->slot)
- : JSVAL_VOID;
+ desc->getter = Jsvalify(sprop->getter());
+ desc->setter = Jsvalify(sprop->setter());
+ if (SPROP_HAS_VALID_SLOT(sprop, obj2->scope()))
+ Valueify(desc->value).copy(obj2->lockedGetSlot(sprop->slot));
+ else
+ Valueify(desc->value).setUndefined();
} else {
desc->getter = NULL;
desc->setter = NULL;
desc->value = JSVAL_VOID;
}
}
obj2->dropProperty(cx, prop);
return ok;
@@ -3329,28 +3328,28 @@ JS_HasPropertyById(JSContext *cx, JSObje
JS_PUBLIC_API(JSBool)
JS_LookupProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
{
JSObject *obj2;
JSProperty *prop;
CHECK_REQUEST(cx);
return LookupProperty(cx, obj, name, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
- LookupResult(cx, obj, obj2, prop, vp);
+ LookupResult(cx, obj, obj2, prop, Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
JSObject *obj2;
JSProperty *prop;
CHECK_REQUEST(cx);
return LookupPropertyById(cx, obj, id, JSRESOLVE_QUALIFIED, &obj2, &prop) &&
- LookupResult(cx, obj, obj2, prop, vp);
+ LookupResult(cx, obj, obj2, prop, Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_LookupPropertyWithFlags(JSContext *cx, JSObject *obj, const char *name,
uintN flags, jsval *vp)
{
JSAtom *atom;
JSObject *obj2;
@@ -3368,64 +3367,64 @@ JS_LookupPropertyWithFlagsById(JSContext
JSBool ok;
JSProperty *prop;
CHECK_REQUEST(cx);
ok = obj->isNative()
? js_LookupPropertyWithFlags(cx, obj, id, flags, objp, &prop) >= 0
: obj->lookupProperty(cx, id, objp, &prop);
if (ok)
- ok = LookupResult(cx, obj, *objp, prop, vp);
+ ok = LookupResult(cx, obj, *objp, prop, Valueify(vp));
return ok;
}
JS_PUBLIC_API(JSBool)
JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
JSPropertyDescriptor *desc)
{
CHECK_REQUEST(cx);
return GetPropertyAttributesById(cx, obj, id, flags, JS_FALSE, desc);
}
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));
}
JS_PUBLIC_API(JSBool)
JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, jsval *vp)
{
JSAtom *atom;
CHECK_REQUEST(cx);
atom = js_Atomize(cx, name, strlen(name), 0);
if (!atom)
return JS_FALSE;
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
- return obj->getProperty(cx, ATOM_TO_JSID(atom), vp);
+ return obj->getProperty(cx, ATOM_TO_JSID(atom), Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
CHECK_REQUEST(cx);
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
- return obj->getProperty(cx, id, vp);
+ return obj->getProperty(cx, id, Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_GetMethodById(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
jsval *vp)
{
CHECK_REQUEST(cx);
- 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;
return JS_TRUE;
}
JS_PUBLIC_API(JSBool)
JS_GetMethod(JSContext *cx, JSObject *obj, const char *name, JSObject **objp,
@@ -3445,25 +3444,25 @@ JS_SetProperty(JSContext *cx, JSObject *
JSAtom *atom;
CHECK_REQUEST(cx);
atom = js_Atomize(cx, name, strlen(name), 0);
if (!atom)
return JS_FALSE;
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
- return obj->setProperty(cx, ATOM_TO_JSID(atom), vp);
+ return obj->setProperty(cx, ATOM_TO_JSID(atom), Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
{
CHECK_REQUEST(cx);
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
- return obj->setProperty(cx, id, vp);
+ return obj->setProperty(cx, id, Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_DeleteProperty(JSContext *cx, JSObject *obj, const char *name)
{
jsval junk;
return JS_DeleteProperty2(cx, obj, name, &junk);
@@ -3476,43 +3475,44 @@ JS_DeleteProperty2(JSContext *cx, JSObje
JSAtom *atom;
CHECK_REQUEST(cx);
atom = js_Atomize(cx, name, strlen(name), 0);
if (!atom)
return JS_FALSE;
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
- return obj->deleteProperty(cx, ATOM_TO_JSID(atom), rval);
+ return obj->deleteProperty(cx, ATOM_TO_JSID(atom), Valueify(rval));
}
JS_PUBLIC_API(JSBool)
JS_DeletePropertyById(JSContext *cx, JSObject *obj, jsid id)
{
jsval junk;
return JS_DeletePropertyById2(cx, obj, id, &junk);
}
JS_PUBLIC_API(JSBool)
JS_DeletePropertyById2(JSContext *cx, JSObject *obj, jsid id, jsval *rval)
{
CHECK_REQUEST(cx);
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
- return obj->deleteProperty(cx, id, rval);
+ return obj->deleteProperty(cx, id, Valueify(rval));
}
JS_PUBLIC_API(JSBool)
JS_DefineUCProperty(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs)
{
CHECK_REQUEST(cx);
- return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
+ return DefineUCProperty(cx, obj, name, namelen, Valueify(value),
+ Valueify(getter), Valueify(setter),
attrs, 0, 0);
}
JS_PUBLIC_API(JSBool)
JS_GetUCPropertyAttributes(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen,
uintN *attrsp, JSBool *foundp)
{
@@ -3549,17 +3549,18 @@ JS_SetUCPropertyAttributes(JSContext *cx
JS_PUBLIC_API(JSBool)
JS_DefineUCPropertyWithTinyId(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen,
int8 tinyid, jsval value,
JSPropertyOp getter, JSPropertyOp setter,
uintN attrs)
{
CHECK_REQUEST(cx);
- return DefineUCProperty(cx, obj, name, namelen, value, getter, setter,
+ return DefineUCProperty(cx, obj, name, namelen, Valueify(value),
+ Valueify(getter), Valueify(setter),
attrs, JSScopeProperty::HAS_SHORTID, tinyid);
}
JS_PUBLIC_API(JSBool)
JS_AlreadyHasOwnUCProperty(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen,
JSBool *foundp)
{
@@ -3599,73 +3600,73 @@ JS_LookupUCProperty(JSContext *cx, JSObj
jsval *vp)
{
JSObject *obj2;
JSProperty *prop;
CHECK_REQUEST(cx);
return LookupUCProperty(cx, obj, name, namelen, JSRESOLVE_QUALIFIED,
&obj2, &prop) &&
- LookupResult(cx, obj, obj2, prop, vp);
+ LookupResult(cx, obj, obj2, prop, Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_GetUCProperty(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen,
jsval *vp)
{
JSAtom *atom;
CHECK_REQUEST(cx);
atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
if (!atom)
return JS_FALSE;
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
- return obj->getProperty(cx, ATOM_TO_JSID(atom), vp);
+ return obj->getProperty(cx, ATOM_TO_JSID(atom), Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_SetUCProperty(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen,
jsval *vp)
{
JSAtom *atom;
CHECK_REQUEST(cx);
atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
if (!atom)
return JS_FALSE;
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
- return obj->setProperty(cx, ATOM_TO_JSID(atom), vp);
+ return obj->setProperty(cx, ATOM_TO_JSID(atom), Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_DeleteUCProperty2(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen,
jsval *rval)
{
JSAtom *atom;
CHECK_REQUEST(cx);
atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
if (!atom)
return JS_FALSE;
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
- return obj->deleteProperty(cx, ATOM_TO_JSID(atom), rval);
+ return obj->deleteProperty(cx, ATOM_TO_JSID(atom), Valueify(rval));
}
JS_PUBLIC_API(JSObject *)
JS_NewArrayObject(JSContext *cx, jsint length, jsval *vector)
{
CHECK_REQUEST(cx);
/* NB: jsuint cast does ToUint32. */
- return js_NewArrayObject(cx, (jsuint)length, vector);
+ return js_NewArrayObject(cx, (jsuint)length, Valueify(vector));
}
JS_PUBLIC_API(JSBool)
JS_IsArrayObject(JSContext *cx, JSObject *obj)
{
return js_GetWrappedObject(cx, obj)->isArray();
}
@@ -3692,17 +3693,18 @@ JS_HasArrayLength(JSContext *cx, JSObjec
JS_PUBLIC_API(JSBool)
JS_DefineElement(JSContext *cx, JSObject *obj, jsint index, jsval value,
JSPropertyOp getter, JSPropertyOp setter, uintN attrs)
{
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_DECLARING);
CHECK_REQUEST(cx);
- return obj->defineProperty(cx, INT_TO_JSID(index), value, getter, setter, attrs);
+ return obj->defineProperty(cx, INT_TO_JSID(index), Valueify(value),
+ Valueify(getter), Valueify(setter), attrs);
}
JS_PUBLIC_API(JSBool)
JS_AliasElement(JSContext *cx, JSObject *obj, const char *name, jsint alias)
{
JSObject *obj2;
JSProperty *prop;
JSScopeProperty *sprop;
@@ -3763,52 +3765,52 @@ JS_PUBLIC_API(JSBool)
JS_LookupElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
{
JSObject *obj2;
JSProperty *prop;
CHECK_REQUEST(cx);
return LookupPropertyById(cx, obj, INT_TO_JSID(index), JSRESOLVE_QUALIFIED,
&obj2, &prop) &&
- LookupResult(cx, obj, obj2, prop, vp);
+ LookupResult(cx, obj, obj2, prop, Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_GetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
{
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
CHECK_REQUEST(cx);
- return obj->getProperty(cx, INT_TO_JSID(index), vp);
+ return obj->getProperty(cx, INT_TO_JSID(index), Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
{
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
CHECK_REQUEST(cx);
- return obj->setProperty(cx, INT_TO_JSID(index), vp);
+ return obj->setProperty(cx, INT_TO_JSID(index), Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_DeleteElement(JSContext *cx, JSObject *obj, jsint index)
{
jsval junk;
return JS_DeleteElement2(cx, obj, index, &junk);
}
JS_PUBLIC_API(JSBool)
JS_DeleteElement2(JSContext *cx, JSObject *obj, jsint index, jsval *rval)
{
JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED);
CHECK_REQUEST(cx);
- return obj->deleteProperty(cx, INT_TO_JSID(index), rval);
+ return obj->deleteProperty(cx, INT_TO_JSID(index), Valueify(rval));
}
JS_PUBLIC_API(void)
JS_ClearScope(JSContext *cx, JSObject *obj)
{
CHECK_REQUEST(cx);
if (obj->map->ops->clear)
@@ -3824,50 +3826,50 @@ JS_ClearScope(JSContext *cx, JSObject *o
}
JS_PUBLIC_API(JSIdArray *)
JS_Enumerate(JSContext *cx, JSObject *obj)
{
jsint i, n;
jsid id;
JSIdArray *ida;
- jsval *vector;
+ jsid *vector;
CHECK_REQUEST(cx);
ida = NULL;
AutoEnumStateRooter iterState(cx, obj);
/* Get the number of properties to enumerate. */
- jsval num_properties;
+ jsid num_properties;
if (!obj->enumerate(cx, JSENUMERATE_INIT, iterState.addr(), &num_properties))
goto error;
- if (!JSVAL_IS_INT(num_properties)) {
+ if (!JSID_IS_INT(num_properties)) {
JS_ASSERT(0);
goto error;
}
/* Grow as needed if we don't know the exact amount ahead of time. */
- n = JSVAL_TO_INT(num_properties);
+ n = JSID_TO_INT(num_properties);
if (n <= 0)
n = 8;
/* Create an array of jsids large enough to hold all the properties */
ida = NewIdArray(cx, n);
if (!ida)
goto error;
i = 0;
vector = &ida->vector[0];
for (;;) {
if (!obj->enumerate(cx, JSENUMERATE_NEXT, iterState.addr(), &id))
goto error;
/* No more jsid's to enumerate ? */
- if (iterState.state() == JSVAL_NULL)
+ if (iterState.state().isNull())
break;
if (i == ida->length) {
ida = SetIdArrayLength(cx, ida, ida->length * 2);
if (!ida)
goto error;
vector = &ida->vector[0];
}
@@ -3893,47 +3895,47 @@ JS_STATIC_ASSERT(JSSLOT_ITER_INDEX < JS_
static void
prop_iter_finalize(JSContext *cx, JSObject *obj)
{
void *pdata = obj->getPrivate();
if (!pdata)
return;
- if (JSVAL_TO_INT(obj->fslots[JSSLOT_ITER_INDEX]) >= 0) {
+ if (obj->fslots[JSSLOT_ITER_INDEX].asInt32() >= 0) {
/* Non-native case: destroy the ida enumerated when obj was created. */
JSIdArray *ida = (JSIdArray *) pdata;
JS_DestroyIdArray(cx, ida);
}
}
static void
prop_iter_trace(JSTracer *trc, JSObject *obj)
{
void *pdata = obj->getPrivate();
if (!pdata)
return;
- if (JSVAL_TO_INT(obj->fslots[JSSLOT_ITER_INDEX]) < 0) {
+ if (obj->fslots[JSSLOT_ITER_INDEX].asInt32() < 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]);
}
}
-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
};
JS_PUBLIC_API(JSObject *)
JS_NewPropertyIterator(JSContext *cx, JSObject *obj)
{
JSObject *iterobj;
@@ -3954,96 +3956,96 @@ JS_NewPropertyIterator(JSContext *cx, JS
index = -1;
} else {
/*
* Non-native case: enumerate a JSIdArray and keep it via private.
*
* 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;
pdata = ida;
index = ida->length;
}
/* 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;
}
JS_PUBLIC_API(JSBool)
JS_NextProperty(JSContext *cx, JSObject *iterobj, jsid *idp)
{
jsint i;
JSObject *obj;
JSScope *scope;
JSScopeProperty *sprop;
JSIdArray *ida;
CHECK_REQUEST(cx);
- i = JSVAL_TO_INT(iterobj->fslots[JSSLOT_ITER_INDEX]);
+ i = iterobj->fslots[JSSLOT_ITER_INDEX].asInt32();
if (i < 0) {
/* Native case: private data is a property tree node pointer. */
obj = iterobj->getParent();
JS_ASSERT(obj->isNative());
scope = obj->scope();
sprop = (JSScopeProperty *) iterobj->getPrivate();
/*
* If the next property mapped by scope in the property tree ancestor
* line is not enumerable, or it's an alias, skip it and keep on trying
* to find an enumerable property that is still in scope.
*/
while (sprop && (!sprop->enumerable() || sprop->isAlias()))
sprop = sprop->parent;
if (!sprop) {
- *idp = JSVAL_VOID;
+ *idp = JSID_VOID;
} else {
iterobj->setPrivate(sprop->parent);
*idp = sprop->id;
}
} else {
/* Non-native case: use the ida enumerated when iterobj was created. */
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, Value(i));
}
}
return JS_TRUE;
}
JS_PUBLIC_API(JSBool)
JS_CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode,
jsval *vp, uintN *attrsp)
{
CHECK_REQUEST(cx);
- return obj->checkAccess(cx, id, mode, vp, attrsp);
+ return obj->checkAccess(cx, id, mode, Valueify(vp), attrsp);
}
JS_PUBLIC_API(JSBool)
JS_GetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval *vp)
{
CHECK_REQUEST(cx);
- return js_GetReservedSlot(cx, obj, index, vp);
+ return js_GetReservedSlot(cx, obj, index, Valueify(vp));
}
JS_PUBLIC_API(JSBool)
JS_SetReservedSlot(JSContext *cx, JSObject *obj, uint32 index, jsval v)
{
CHECK_REQUEST(cx);
- return js_SetReservedSlot(cx, obj, index, v);
+ return js_SetReservedSlot(cx, obj, index, Valueify(v));
}
#ifdef JS_THREADSAFE
JS_PUBLIC_API(jsrefcount)
JS_HoldPrincipals(JSContext *cx, JSPrincipals *principals)
{
return JS_ATOMIC_INCREMENT(&principals->refcount);
}
@@ -4102,17 +4104,17 @@ JS_NewFunction(JSContext *cx, JSNative n
if (!name) {
atom = NULL;
} else {
atom = js_Atomize(cx, name, strlen(name), 0);
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 *)
JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent)
{
CHECK_REQUEST(cx);
if (!parent) {
if (cx->fp)
@@ -4122,17 +4124,17 @@ JS_CloneFunctionObject(JSContext *cx, JS
JS_ASSERT(parent);
}
if (funobj->getClass() != &js_FunctionClass) {
/*
* 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(funobj);
js_ReportIsNotFunction(cx, &v, 0);
return NULL;
}
JSFunction *fun = GET_FUNCTION_PRIVATE(cx, funobj);
JSObject *clone = CloneFunctionObject(cx, fun, parent);
if (!clone)
return NULL;
@@ -4152,17 +4154,17 @@ JS_CloneFunctionObject(JSContext *cx, JS
if (FUN_FLAT_CLOSURE(fun)) {
JS_ASSERT(funobj->dslots);
if (!js_EnsureReservedSlots(cx, clone,
fun->countInterpretedReservedSlots())) {
return NULL;
}
JSUpvarArray *uva = fun->u.i.script->upvars();
- JS_ASSERT(uva->length <= size_t(clone->dslots[-1]));
+ JS_ASSERT(uva->length <= clone->dslotLength());
void *mark = JS_ARENA_MARK(&cx->tempPool);
jsuword *names = js_GetLocalNameArray(cx, fun, &cx->tempPool);
if (!names)
return NULL;
uint32 i = 0, n = uva->length;
for (; i < n; i++) {
@@ -4226,136 +4228,132 @@ JS_GetFunctionArity(JSFunction *fun)
JS_PUBLIC_API(JSBool)
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)
-{
- jsval fsv;
+js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, Value *vp)
+{
+ Value fsv;
JSFunctionSpec *fs;
- JSObject *tmp;
- JSFastNative native;
-
- if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(*vp), 0, &fsv))
+ FastNative native;
+
+ if (!js_GetReservedSlot(cx, &vp->asObject(), 0, &fsv))
return JS_FALSE;
- fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
+ fs = (JSFunctionSpec *) fsv.asPrivateVoidPtr();
JS_ASSERT((~fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == 0);
/*
* We know that vp[2] is valid because JS_DefineFunctions, which is our
* only (indirect) referrer, defined us as requiring at least one argument
* (notice how it passes fs->nargs + 1 as the next-to-last argument to
* JS_DefineFunction).
*/
- 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], &vp[2]))
return JS_FALSE;
- vp[2] = OBJECT_TO_JSVAL(tmp);
}
/*
* Copy all actual (argc) arguments down over our |this| parameter, vp[1],
* which is almost always the class constructor object, e.g. Array. Then
* call the corresponding prototype native method with our first argument
* passed as |this|.
*/
memmove(vp + 1, vp + 2, argc * sizeof(jsval));
/*
* 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;
/*
* Protect against argc underflowing. By calling js_ComputeThis, we made
* it as if the static was called with one parameter, the explicit |this|
* object.
*/
if (argc != 0) {
/* 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
:
#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)
-{
- jsval fsv;
+ uintN argc, Value *argv, Value *rval)
+{
+ Value fsv;
JSFunctionSpec *fs;
- JSObject *tmp;
-
- if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv))
+
+ if (!js_GetReservedSlot(cx, &argv[-2].asObject(), 0, &fsv))
return JS_FALSE;
- fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv);
+ fs = (JSFunctionSpec *) fsv.asPrivateVoidPtr();
JS_ASSERT((fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) ==
JSFUN_GENERIC_NATIVE);
/*
* We know that argv[0] is valid because JS_DefineFunctions, which is our
* only (indirect) referrer, defined us as requiring at least one argument
* (notice how it passes fs->nargs + 1 as the next-to-last argument to
* JS_DefineFunction).
*/
- 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], &argv[0]))
return JS_FALSE;
- argv[0] = OBJECT_TO_JSVAL(tmp);
}
/*
* Copy all actual (argc) arguments down over our |this| parameter,
* argv[-1], which is almost always the class constructor object, e.g.
* Array. Then call the corresponding prototype native method with our
* first argument passed as |this|.
*/
memmove(argv - 1, argv, argc * sizeof(jsval));
/*
* 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_GetTopStackFrame(cx)->thisv.copy(argv[-1]);
JS_ASSERT(cx->fp->argv == argv);
/*
* Protect against argc underflowing. By calling js_ComputeThis, we made
* it as if the static was called with one parameter, the explicit |this|
* object.
*/
if (argc != 0) {
/* 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].asObject(), argc, Jsvalify(argv), Jsvalify(rval));
}
JS_END_EXTERN_C
JS_PUBLIC_API(JSBool)
JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs)
{
uintN flags;
JSObject *ctor;
@@ -4375,30 +4373,31 @@ JS_DefineFunctions(JSContext *cx, JSObje
ctor = JS_GetConstructor(cx, obj);
if (!ctor)
return JS_FALSE;
}
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)
return JS_FALSE;
fun->u.n.extra = (uint16)fs->extra;
/*
* 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;
+ priv.setPrivateVoidPtr(fs);
+ if (!js_SetReservedSlot(cx, FUN_OBJECT(fun), 0, priv))
return JS_FALSE;
}
JS_ASSERT(!(flags & JSFUN_FAST_NATIVE) ||
(uint16)(fs->extra >> 16) <= fs->nargs);
fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags);
if (!fun)
return JS_FALSE;
@@ -4412,31 +4411,31 @@ JS_DefineFunction(JSContext *cx, JSObjec
uintN nargs, uintN attrs)
{
JSAtom *atom;
CHECK_REQUEST(cx);
atom = js_Atomize(cx, name, strlen(name), 0);
if (!atom)
return NULL;
- return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
+ return js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs);
}
JS_PUBLIC_API(JSFunction *)
JS_DefineUCFunction(JSContext *cx, JSObject *obj,
const jschar *name, size_t namelen, JSNative call,
uintN nargs, uintN attrs)
{
JSAtom *atom;
CHECK_REQUEST(cx);
atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
if (!atom)
return NULL;
- return js_DefineFunction(cx, obj, atom, call, nargs, attrs);
+ return js_DefineFunction(cx, obj, atom, Valueify(call), nargs, attrs);
}
JS_PUBLIC_API(JSScript *)
JS_CompileScript(JSContext *cx, JSObject *obj,
const char *bytes, size_t length,
const char *filename, uintN lineno)
{
jschar *chars;
@@ -4484,17 +4483,17 @@ JS_CompileUCScript(JSContext *cx, JSObje
JS_BEGIN_MACRO \
if (!(result) && !((cx)->options & JSOPTION_DONT_REPORT_UNCAUGHT)) \
js_ReportUncaughtException(cx); \
JS_END_MACRO
#define LAST_FRAME_CHECKS(cx,result) \
JS_BEGIN_MACRO \
if (!JS_IsRunning(cx)) { \
- (cx)->weakRoots.lastInternalResult = JSVAL_NULL; \
+ (cx)->weakRoots.lastInternalResult = NULL; \
LAST_FRAME_EXCEPTION_CHECK(cx, result); \
} \
JS_END_MACRO
#define JS_OPTIONS_TO_TCFLAGS(cx) \
((((cx)->options & JSOPTION_COMPILE_N_GO) ? TCF_COMPILE_N_GO : 0) | \
(((cx)->options & JSOPTION_NO_SCRIPT_RVAL) ? TCF_NO_SCRIPT_RVAL : 0))
@@ -4721,17 +4720,17 @@ JS_CompileUCFunctionForPrincipals(JSCont
goto out2;
}
}
fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, obj, funAtom);
if (!fun)
goto out2;
{
- AutoValueRooter tvr(cx, FUN_OBJECT(fun));
+ AutoObjectRooter tvr(cx, FUN_OBJECT(fun));
MUST_FLOW_THROUGH("out");
for (i = 0; i < nargs; i++) {
argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0);
if (!argAtom) {
fun = NULL;
goto out;
}
@@ -4743,17 +4742,18 @@ JS_CompileUCFunctionForPrincipals(JSCont
if (!JSCompiler::compileFunctionBody(cx, fun, principals,
chars, length, filename, lineno)) {
fun = NULL;
goto out;
}
if (obj && funAtom &&
- !obj->defineProperty(cx, ATOM_TO_JSID(funAtom), OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
+ !obj->defineProperty(cx, ATOM_TO_JSID(funAtom),
+ FunObjValue(*FUN_OBJECT(fun)),
NULL, NULL, JSPROP_ENUMERATE)) {
fun = NULL;
}
#ifdef JS_SCOPE_DEPTH_METER
if (fun && obj) {
JSObject *pobj = obj;
uintN depth = 1;
@@ -4816,17 +4816,17 @@ JS_DecompileFunctionBody(JSContext *cx,
}
JS_PUBLIC_API(JSBool)
JS_ExecuteScript(JSContext *cx, JSObject *obj, JSScript *script, jsval *rval)
{
JSBool ok;
CHECK_REQUEST(cx);
- 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;
}
/* Ancient uintN nbytes is part of API/ABI, so use size_t length local. */
JS_PUBLIC_API(JSBool)
JS_EvaluateScript(JSContext *cx, JSObject *obj,
const char *bytes, uintN nbytes,
@@ -4894,59 +4894,60 @@ JS_EvaluateUCScriptForPrincipals(JSConte
!rval
? TCF_COMPILE_N_GO | TCF_NO_SCRIPT_RVAL
: TCF_COMPILE_N_GO,
chars, length, NULL, filename, lineno);
if (!script) {
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;
}
JS_PUBLIC_API(JSBool)
JS_CallFunction(JSContext *cx, JSObject *obj, JSFunction *fun, uintN argc,
jsval *argv, jsval *rval)
{
JSBool ok;
CHECK_REQUEST(cx);
- ok = js_InternalCall(cx, obj, OBJECT_TO_JSVAL(FUN_OBJECT(fun)), argc, argv,
- rval);
+ ok = InternalCall(cx, obj, FunObjValue(*FUN_OBJECT(fun)), argc,
+ Valueify(argv), Valueify(rval));
LAST_FRAME_CHECKS(cx, ok);
return ok;
}
JS_PUBLIC_API(JSBool)
JS_CallFunctionName(JSContext *cx, JSObject *obj, const char *name, uintN argc,
jsval *argv, jsval *rval)
{
CHECK_REQUEST(cx);
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;
}
JS_PUBLIC_API(JSBool)
JS_CallFunctionValue(JSContext *cx, JSObject *obj, jsval fval, uintN argc,
jsval *argv, jsval *rval)
{
JSBool ok;
CHECK_REQUEST(cx);
- ok = js_InternalCall(cx, obj, fval, argc, argv, rval);
+ ok = InternalCall(cx, obj, Valueify(fval), argc, Valueify(argv), Valueify(rval));
LAST_FRAME_CHECKS(cx, ok);
return ok;
}
JS_PUBLIC_API(JSObject *)
JS_New(JSContext *cx, JSObject *ctor, uintN argc, jsval *argv)
{
CHECK_REQUEST(cx);
@@ -4954,23 +4955,23 @@ JS_New(JSContext *cx, JSObject *ctor, ui
// 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
// of object to create, create it, and clamp the return value to an object,
// among other details. js_InvokeConstructor does the hard work.
InvokeArgsGuard args;
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();
+ SetObject(&vp[0], ctor);
+ vp[1].setNull();
memcpy(vp + 2, argv, argc * sizeof(jsval));
- JSBool ok = js_InvokeConstructor(cx, args, JS_TRUE);
- JSObject *obj = ok ? JSVAL_TO_OBJECT(vp[0]) : NULL;
+ JSBool ok = InvokeConstructor(cx, args, JS_TRUE);
+ JSObject *obj = ok ? vp[0].asObjectOrNull() : NULL;
LAST_FRAME_CHECKS(cx, ok);
return obj;
}
JS_PUBLIC_API(JSOperationCallback)
JS_SetOperationCallback(JSContext *cx, JSOperationCallback callback)
{
@@ -5573,33 +5574,33 @@ JS_IsExceptionPending(JSContext *cx)
}
JS_PUBLIC_API(JSBool)
JS_GetPendingException(JSContext *cx, jsval *vp)
{
CHECK_REQUEST(cx);
if (!cx->throwing)
return JS_FALSE;
- *vp = cx->exception;
+ Valueify(vp)->copy(cx->exception);
return JS_TRUE;
}
JS_PUBLIC_API(void)
JS_SetPendingException(JSContext *cx, jsval v)
{
CHECK_REQUEST(cx);
cx->throwing = JS_TRUE;
- cx->exception = v;
+ cx->exception.copy(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)
JS_ReportPendingException(JSContext *cx)
{
JSBool ok;
JSPackedBool save;
@@ -5628,17 +5629,17 @@ JS_SaveExceptionState(JSContext *cx)
{
JSExceptionState *state;
CHECK_REQUEST(cx);
state = (JSExceptionState *) cx->malloc(sizeof(JSExceptionState));
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;
}
JS_PUBLIC_API(void)
JS_RestoreExceptionState(JSContext *cx, JSExceptionState *state)
{
CHECK_REQUEST(cx);
@@ -5652,17 +5653,17 @@ JS_RestoreExceptionState(JSContext *cx,
}
JS_PUBLIC_API(void)
JS_DropExceptionState(JSContext *cx, JSExceptionState *state)
{
CHECK_REQUEST(cx);
if (state) {
if (state->throwing && JSVAL_IS_GCTHING(state->exception))
- JS_RemoveRoot(cx, &state->exception);
+ js_RemoveRoot(cx->runtime, &state->exception);
cx->free(state);
}
}
JS_PUBLIC_API(JSErrorReport *)
JS_ErrorFromException(JSContext *cx, jsval v)
{
CHECK_REQUEST(cx);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -46,237 +46,277 @@
#include <stddef.h>
#include <stdio.h>
#include "js-config.h"
#include "jspubtd.h"
#include "jsutil.h"
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, initialized on startup. */
+extern jsval JSVAL_NULL;
+extern jsval JSVAL_ZERO;
+extern jsval JSVAL_ONE;
+extern jsval JSVAL_FALSE;
+extern jsval JSVAL_TRUE;
+extern jsval JSVAL_VOID;
/*
- * Well-known JS values. The extern'd variables are initialized when the
- * first JSContext is created by JS_NewContext (see below).
+ * Exact value equality, corresponding to == on old word-sized jsvals.
+ *
+ * To have simple byte-equality we would need the keep all sizeof(Data) bytes
+ * of data in a well-defined state for every type. On 32-bit systems, this
+ * isn't true for non-doubles. On 64-bit systems, this isn't true for undefined
+ * and booleans.
+ *
+ * N.B. it is much faster to use specific queries like JSVAL_IS_NULL than
+ * IS_SAME_JSVAL(v, JSVAL_NULL).
*/
-#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.
- *
- * 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.
- */
-#define JSVAL_TO_SPECIAL(v) ((JSBool) ((v) >> JSVAL_TAGBITS))
-#define SPECIAL_TO_JSVAL(b) \
- JSVAL_SETTAG((jsval) (b) << JSVAL_TAGBITS, JSVAL_SPECIAL)
+inline JSBool
+IS_SAME_JSVAL(const jsval *lval, const jsval *rval)
+{
+ JSValueMaskType lmask = lval->mask, rmask = rval->mask;
+ jsval_data ldata = lval->data, rdata = rval->data;
+
+ JSBool sameType = lmask == rmask;
+ JSBool noPayload = (lmask & (JSVAL_UNDEFINED_MASK |
+ JSVAL_MAGIC_MASK)) != 0;
+ JSBool firstWordEqual = ldata.bits.first == rdata.bits.first;
+ JSBool secondWordEqual = ldata.bits.second == rdata.bits.second;
+
+ /* N.B. JSVAL_NULL_MASK == 0. */
+#if JS_BITS_PER_WORD == 32
+ JSBool noSecondWord = (lmask == 0) |
+ ((lmask & (JSVAL_INT32_MASK |
+ JSVAL_BOOLEAN_MASK |
+ JSVAL_STRING_MASK |
+ JSVAL_NONFUNOBJ_MASK |
+ JSVAL_FUNOBJ_MASK)) != 0);
+#elif JS_BITS_PER_WORD == 64
+ JSBool noSecondWord = (lmask & JSVAL_INT32_MASK |
+ JSVAL_BOOLEAN_MASK)
+#else
+# error "Unsupported word size"
+#endif
+
+ return sameType &
+ (noPayload | (firstWordEqual & (secondWordEqual | noSecondWord)));
+}
/* Predicates for type testing. */
+
static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_OBJECT(jsval v)
+JSVAL_IS_NULL(jsval v)
{
- return JSVAL_TAG(v) == JSVAL_OBJECT;
+ return v.mask == JSVAL_NULL_MASK;
+}
+
+static JS_ALWAYS_INLINE JSBool
+JSVAL_IS_VOID(jsval v)
+{
+ return v.mask == JSVAL_UNDEFINED_MASK;
}
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_INT(jsval v)
{
- return v & JSVAL_INT;
+ return v.mask == JSVAL_INT32_MASK;
+}
+
+static JS_ALWAYS_INLINE jsint
+JSVAL_TO_INT(jsval v)
+{
+ JS_ASSERT(JSVAL_IS_INT(v));
+ return v.data.i32;
+}
+
+#define JSVAL_INT_BITS 32
+#define JSVAL_INT_MIN ((jsint)0x80000000)
+#define JSVAL_INT_MAX ((jsint)0x7fffffff)
+
+static JS_ALWAYS_INLINE bool
+INT_FITS_IN_JSVAL(jsint i)
+{
+ return JS_TRUE;
+}
+
+static JS_ALWAYS_INLINE jsval
+INT_TO_JSVAL(int32 i)
+{
+ jsval v;
+ v.mask = JSVAL_INT32_MASK;
+ v.data.i32 = i;
+ return v;
}
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_DOUBLE(jsval v)
{
- return JSVAL_TAG(v) == JSVAL_DOUBLE;
+ return v.mask == JSVAL_DOUBLE_MASK;
+}
+
+static JS_ALWAYS_INLINE jsdouble
+JSVAL_TO_DOUBLE(jsval v)
+{
+ JS_ASSERT(JSVAL_IS_DOUBLE(v));
+ return v.data.dbl;
+}
+
+static JS_ALWAYS_INLINE jsval
+DOUBLE_TO_JSVAL(jsdouble d)
+{
+ jsval v;
+ v.mask = JSVAL_DOUBLE_MASK;
+ v.data.dbl = d;
+ return v;
}
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_NUMBER(jsval v)
{
- return JSVAL_IS_INT(v) || JSVAL_IS_DOUBLE(v);
+ return v.mask & (JSVAL_INT32_MASK | JSVAL_DOUBLE_MASK);
}
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_STRING(jsval v)
{
- return JSVAL_TAG(v) == JSVAL_STRING;
+ return v.mask == JSVAL_STRING_MASK;
+}
+
+static JS_ALWAYS_INLINE JSString *
+JSVAL_TO_STRING(jsval v)
+{
+ JS_ASSERT(JSVAL_IS_STRING(v));
+ return v.data.str;
}
+static JS_ALWAYS_INLINE jsval
+STRING_TO_JSVAL(JSString *str)
+{
+ jsval v;
+ v.mask = JSVAL_STRING_MASK;
+ v.data.str = str;
+ return v;
+}
+
+/*
+ * N.B. These functions use the older meaning of "object" as "object or null".
+ * This is not a problem if code only works with jsvals or only works with
+ * js::Value, but if both uses are mixed, it is important not to get confused
+ * by the two meanings. For example, JSVAL_IS_OBJECT(v) does not imply
+ * v.isObject().
+ */
static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_SPECIAL(jsval v)
+JSVAL_IS_OBJECT(jsval v)
+{
+ return !(v.mask & ~(JSVAL_FUNOBJ_MASK | JSVAL_NONFUNOBJ_MASK));
+}
+
+static JS_ALWAYS_INLINE JSObject *
+JSVAL_TO_OBJECT(jsval v)
{
- return JSVAL_TAG(v) == JSVAL_SPECIAL;
+ JS_ASSERT(JSVAL_IS_OBJECT(v));
+ return v.data.obj;
+}
+
+static JS_ALWAYS_INLINE jsval
+OBJECT_TO_JSVAL(JSObject *obj)
+{
+ extern JS_PUBLIC_API(JSBool)
+ JS_ObjectIsFunction(JSContext *cx, JSObject *obj);
+
+ jsval v;
+ if (!obj)
+ v.mask = JSVAL_NULL_MASK;
+ else if (JS_ObjectIsFunction(NULL, obj))
+ v.mask = JSVAL_FUNOBJ_MASK;
+ else
+ v.mask = JSVAL_NONFUNOBJ_MASK;
+ v.data.obj = obj;
+ return v;
}
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_BOOLEAN(jsval v)
{
- return (v & ~((jsval)1 << JSVAL_TAGBITS)) == JSVAL_SPECIAL;
+ return v.mask == JSVAL_BOOLEAN_MASK;
}
static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_NULL(jsval v)
+JSVAL_TO_BOOLEAN(jsval v)
{
- return v == JSVAL_NULL;
+ JS_ASSERT(JSVAL_IS_BOOLEAN(v));
+ return v.data.boo;
+}
+
+static JS_ALWAYS_INLINE jsval
+BOOLEAN_TO_JSVAL(JSBool b)
+{
+ jsval v;
+ v.data.boo = b;
+ v.mask = JSVAL_BOOLEAN_MASK;
+ return v;
}
static JS_ALWAYS_INLINE JSBool
-JSVAL_IS_VOID(jsval v)
+JSVAL_IS_TRUE(jsval v)
{
- return v == JSVAL_VOID;
+ return v.mask == JSVAL_BOOLEAN_MASK && v.data.boo == JS_TRUE;
+}
+
+static JS_ALWAYS_INLINE JSBool
+JSVAL_IS_FALSE(jsval v)
+{
+ return v.mask == JSVAL_BOOLEAN_MASK && v.data.boo == JS_FALSE;
}
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_PRIMITIVE(jsval v)
{
- return !JSVAL_IS_OBJECT(v) || JSVAL_IS_NULL(v);
+ return !(v.mask & (JSVAL_NONFUNOBJ_MASK | JSVAL_FUNOBJ_MASK));
}
-/* Objects, strings, and doubles are GC'ed. */
static JS_ALWAYS_INLINE JSBool
JSVAL_IS_GCTHING(jsval v)
{
- return !(v & JSVAL_INT) && JSVAL_TAG(v) != JSVAL_SPECIAL;
+ return v.mask & (JSVAL_STRING_MASK | JSVAL_NONFUNOBJ_MASK |
+ JSVAL_FUNOBJ_MASK);
}
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 *
-JSVAL_TO_DOUBLE(jsval v)
-{
- JS_ASSERT(JSVAL_IS_DOUBLE(v));
- return (jsdouble *) JSVAL_TO_GCTHING(v);
-}
-
-static JS_ALWAYS_INLINE JSString *
-JSVAL_TO_STRING(jsval v)
-{
- JS_ASSERT(JSVAL_IS_STRING(v));
- return (JSString *) JSVAL_TO_GCTHING(v);
+ return v.data.ptr;
}
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)
+PRIVATE_TO_JSVAL(void *ptr)
{
- JS_ASSERT(((jsword) dp & JSVAL_TAGMASK) == 0);
- return JSVAL_SETTAG((jsval) dp, JSVAL_DOUBLE);
+ jsval v;
+ v.mask = JSVAL_INT32_MASK;
+ v.data.ptr = ptr;
+ return v;
}
-static JS_ALWAYS_INLINE jsval
-STRING_TO_JSVAL(JSString *str)
+static JS_ALWAYS_INLINE void *
+JSVAL_TO_PRIVATE(jsval v)
{
- return JSVAL_SETTAG((jsval) str, JSVAL_STRING);
+ JS_ASSERT(v.mask == JSVAL_INT32_MASK);
+ return v.data.ptr;
}
/* 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)) \
: JS_TRUE)
#define JSVAL_UNLOCK(cx,v) (JSVAL_IS_GCTHING(v) \
? 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)(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 */
#define JSPROP_PERMANENT 0x04 /* property cannot be deleted */
#define JSPROP_GETTER 0x10 /* property holds getter function */
#define JSPROP_SETTER 0x20 /* property holds setter function */
#define JSPROP_SHARED 0x40 /* don't allocate a value slot for this
property; don't copy the property on
@@ -793,17 +833,17 @@ JS_InitStandardClasses(JSContext *cx, JS
* as usual for JSBool result-typed API entry points.
*
* This API can be called directly from a global object class's resolve op,
* to define standard classes lazily. The class's enumerate op should call
* JS_EnumerateStandardClasses(cx, obj), to define eagerly during for..in
* 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)
JS_EnumerateStandardClasses(JSContext *cx, JSObject *obj);
/*
* Enumerate any already-resolved standard class ids into ida, or into a new
* JSIdArray if ida is null. Return the augmented array on success, null on
@@ -855,17 +895,17 @@ JS_InitCTypesClass(JSContext *cx, JSObje
*
* WARNING: These are not (yet) mandatory macros, but new code outside of the
* engine should use them. In the Mozilla 2.0 milestone their definitions may
* change incompatibly.
*/
#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))
extern JS_PUBLIC_API(jsval)
JS_ComputeThis(JSContext *cx, jsval *vp);
extern JS_PUBLIC_API(void *)
@@ -878,61 +918,92 @@ extern JS_PUBLIC_API(void)
JS_free(JSContext *cx, void *p);
extern JS_PUBLIC_API(void)
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);
-
/*
- * A JS GC root is a pointer to a JSObject *, JSString *, or jsdouble * that
- * itself points into the GC heap (more recently, we support this extension:
- * a root may be a pointer to a jsval v for which JSVAL_IS_GCTHING(v) is true).
+ * A GC root is a pointer to a jsval, JSObject *, or JSString * that itself
+ * points into the GC heap. JS_AddValueRoot takes pointers to jsvals and
+ * JS_AddGCThingRoot takes pointers to a JSObject * or JString *.
+ *
+ * Note that, since JS_Add*Root stores the address of a (jsval, JSString *, or
+ * JSObject *) variable, that variable must be alive until JS_RemoveRoot is
+ * called to remove that variable. For example, after writing:
*
- * Therefore, you never pass JSObject *obj to JS_AddRoot(cx, obj). You always
- * call JS_AddRoot(cx, &obj), passing obj by reference. And later, before obj
- * or the structure it is embedded within goes out of scope or is freed, you
- * must call JS_RemoveRoot(cx, &obj).
+ * jsval v;
+ * JS_AddNamedRootedValue(cx, &v, "name");
+ *
+ * the caller must perform
+ *
+ * JS_RemoveRootedValue(cx, &v);
+ *
+ * before 'v' goes out of scope.
*
* Also, use JS_AddNamedRoot(cx, &structPtr->memberObj, "structPtr->memberObj")
* in preference to JS_AddRoot(cx, &structPtr->memberObj), in order to identify
* roots by their source callsites. This way, you can find the callsite while
* debugging if you should fail to do JS_RemoveRoot(cx, &structPtr->memberObj)
* before freeing structPtr's memory.
*/
extern JS_PUBLIC_API(JSBool)
-JS_AddRoot(JSContext *cx, void *rp);
+JS_AddValueRoot(JSContext *cx, js::Value *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddStringRoot(JSContext *cx, JSString **rp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddObjectRoot(JSContext *cx, JSObject **rp);
#ifdef NAME_ALL_GC_ROOTS
#define JS_DEFINE_TO_TOKEN(def) #def
#define JS_DEFINE_TO_STRING(def) JS_DEFINE_TO_TOKEN(def)
-#define JS_AddRoot(cx,rp) JS_AddNamedRoot((cx), (rp), (__FILE__ ":" JS_TOKEN_TO_STRING(__LINE__))
+#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__))
#endif
extern JS_PUBLIC_API(JSBool)
-JS_AddNamedRoot(JSContext *cx, void *rp, const char *name);
+JS_AddNamedValueRoot(JSContext *cx, js::Value *vp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+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_AddNamedValueRootRT(JSRuntime *rt, js::Value *vp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_AddNamedStringRootRT(JSRuntime *rt, JSString **rp, const char *name);
extern JS_PUBLIC_API(JSBool)
-JS_AddNamedRootRT(JSRuntime *rt, void *rp, const char *name);
+JS_AddNamedObjectRootRT(JSRuntime *rt, JSObject **rp, const char *name);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveValueRoot(JSContext *cx, js::Value *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveStringRoot(JSContext *cx, JSString **rp);
extern JS_PUBLIC_API(JSBool)
-JS_RemoveRoot(JSContext *cx, void *rp);
+JS_RemoveObjectRoot(JSContext *cx, JSObject **rp);
extern JS_PUBLIC_API(JSBool)
-JS_RemoveRootRT(JSRuntime *rt, void *rp);
+JS_RemoveValueRootRT(JSRuntime *rt, js::Value *vp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveStringRootRT(JSRuntime *rt, JSString **rp);
+
+extern JS_PUBLIC_API(JSBool)
+JS_RemoveObjectRootRT(JSRuntime *rt, JSObject **rp);
/*
* The last GC thing of each type (object, string, double, external string
* types) created on a given context is kept alive until another thing of the
* same type is created, using a newborn root in the context. These newborn
* roots help native code protect newly-created GC-things from GC invocations
* activated before those things can be rooted using local or global roots.
*
@@ -958,17 +1029,17 @@ JS_ClearNewbornRoots(JSContext *cx);
* and JS_RemoveRoot to manage global roots temporarily.
*
* Instead, calling JS_EnterLocalRootScope and JS_LeaveLocalRootScope around
* the body of the native hook causes the engine to allocate a local root for
* each newborn created in between the two API calls, using a local root stack
* associated with cx. For example:
*
* JSBool
- * my_GetProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
+ * my_GetProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
* {
* JSBool ok;
*
* if (!JS_EnterLocalRootScope(cx))
* return JS_FALSE;
* ok = my_GetPropertyBody(cx, obj, id, vp);
* JS_LeaveLocalRootScope(cx);
* return ok;
@@ -1035,20 +1106,25 @@ class JSAutoLocalRootScope {
static void *operator new(size_t) CPP_THROW_NEW { return 0; };
static void operator delete(void *, size_t) { };
#endif
};
JS_BEGIN_EXTERN_C
#endif
+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
/*
* Call JS_MapGCRoots to map the GC's roots table using map(rp, name, data).
* The root is pointed at by rp; if the root is unnamed, name is null; data is
* supplied from the third parameter to JS_MapGCRoots.
*
@@ -1058,24 +1134,28 @@ JS_DumpNamedRoots(JSRuntime *rt,
* constants are flags; you can OR them together.
*
* This function acquires and releases rt's GC lock around the mapping of the
* roots table, so the map function should run to completion in as few cycles
* as possible. Of course, map cannot call JS_GC, JS_MaybeGC, JS_BeginRequest,
* 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 */
#define JS_MAP_GCROOT_STOP 1 /* stop mapping entries */
#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);
extern JS_PUBLIC_API(JSBool)
JS_LockGCThing(JSContext *cx, void *thing);
extern JS_PUBLIC_API(JSBool)
@@ -1097,42 +1177,58 @@ JS_UnlockGCThingRT(JSRuntime *rt, void *
extern JS_PUBLIC_API(void)
JS_SetExtraGCRoots(JSRuntime *rt, JSTraceDataOp traceOp, void *data);
/*
* For implementors of JSMarkOp. All new code should implement JSTraceOp
* 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
* enumerate all references to traceable things reachable via a property or
* other strong ref identified for debugging purposes by name or index or
* a naming callback.
*
* By definition references to traceable things include non-null pointers
* to JSObject, JSString and jsdouble and corresponding jsvals.
*
* See the JSTraceOp typedef in jspubtd.h.
*/
/* 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)
+{
+ /* Depend on the value representation */
+ return v.mask & (JSVAL_STRING_MASK | JSVAL_NONFUNOBJ_MASK |
+ JSVAL_FUNOBJ_MASK);
+}
+
+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)
+{
+ /* Depend on the value representation */
+ return (uint32)(v.mask == JSVAL_STRING_MASK);
+}
struct JSTracer {
JSContext *context;
JSTraceCallback callback;
JSTraceNamePrinter debugPrinter;
const void *debugPrintArg;
size_t debugPrintIndex;
};
@@ -1376,17 +1472,17 @@ JS_AddExternalStringFinalizer(JSStringFi
* before calling this function. Otherwise, string data will be leaked by the
* GC, for want of a finalizer to call.
*/
extern JS_PUBLIC_API(intN)
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 *)
JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type);
/*
* Returns the external-string finalizer index for this string, or -1 if it is
* an "internal" (native to JS engine) string.
@@ -1557,30 +1653,21 @@ JS_IdToValue(JSContext *cx, jsid id, jsv
*/
#define JSRESOLVE_QUALIFIED 0x01 /* resolve a qualified property id */
#define JSRESOLVE_ASSIGNING 0x02 /* resolve on the left of assignment */
#define JSRESOLVE_DETECTING 0x04 /* 'if (o.p)...' or '(o.p) ?...:...' */
#define JSRESOLVE_DECLARING 0x08 /* var, const, or function prolog op */
#define JSRESOLVE_CLASSNAME 0x10 /* class name used when constructing */
#define JSRESOLVE_WITH 0x20 /* resolve inside a with statement */
-extern JS_PUBLIC_API(JSBool)
-JS_PropertyStub(JSContext *cx, JSObject *obj, jsval 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);
-
-extern JS_PUBLIC_API(JSBool)
-JS_ConvertStub(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
-
-extern JS_PUBLIC_API(void)
-JS_FinalizeStub(JSContext *cx, JSObject *obj);
+extern JS_PUBLIC_DATA(JSPropertyOp) JS_PropertyStub;
+extern JS_PUBLIC_DATA(JSEnumerateOp) JS_EnumerateStub;
+extern JS_PUBLIC_DATA(JSResolveOp) JS_ResolveStub;
+extern JS_PUBLIC_DATA(JSConvertOp) JS_ConvertStub;
+extern JS_PUBLIC_DATA(JSFinalizeOp) JS_FinalizeStub;
struct JSConstDoubleSpec {
jsdouble dval;
const char *name;
uint8 flags;
uint8 spare[3];
};
@@ -2847,9 +2934,738 @@ JS_ClearContextThread(JSContext *cx);
#ifdef JS_GC_ZEAL
extern JS_PUBLIC_API(void)
JS_SetGCZeal(JSContext *cx, uint8 zeal);
#endif
JS_END_EXTERN_C
+/************************************************************************/
+
+#ifdef __cplusplus
+
+/*
+ * Spanky new C++ API
+ */
+
+namespace js {
+
+/*
+ * An ObjPtr is a restriction of a Value (below) to the three types: null,
+ * non-function object and function object. ObjPtr is useful when code
+ * conceptually is working with a JSObject*, but wants to avoid unnecessarily
+ * querying obj->isFunction() by passing around the type tag as well. Also,
+ * ObjPtr provides syntactic sugar so that it behaves more like a JSObject*.
+ *
+ * N.B. ObjPtr is not layout compatible with Value: on 32-bit systems, it does
+ * not need the extra 2 words needed by Value.
+ */
+class ObjPtr
+{
+ protected:
+ typedef JSValueMaskType MaskType;
+
+ static const MaskType NullMask = JSVAL_NULL_MASK;
+ static const MaskType NonFunObjMask = JSVAL_NONFUNOBJ_MASK;
+ static const MaskType FunObjMask = JSVAL_FUNOBJ_MASK;
+
+ static const MaskType ObjectMask = NonFunObjMask | FunObjMask;
+
+ MaskType mask;
+ JSObject *obj;
+
+ private:
+ friend class Value;
+ explicit ObjPtr(MaskType m, JSObject *o) : mask(m), obj(o) {}
+
+ public:
+ /* Constructors */
+
+ /* N.B. defualt construction yields a ObjPtr in an undefined state. */
+ ObjPtr() {}
+
+ /*
+ * To construct a null pointer, use NullObjPtr. To construct pointers to
+ * objects statically known to be, or not to be, function objects, use
+ * FunObjPtr, NonFunObjPtr.
+ */
+
+ /* Accessors */
+
+ bool isNull() const {
+ return mask == NullMask;
+ }
+
+ bool isFunObj() const {
+ return mask == FunObjMask;
+ }
+
+ JSObject &asFunObj() const {
+ JS_ASSERT(isFunObj());
+ return *obj;
+ }
+
+ bool isNonFunObj() const {
+ return mask == NonFunObjMask;
+ }
+
+ JSObject &asNonFunObj() const {
+ JS_ASSERT(isNonFunObj());
+ return *obj;
+ }
+
+ bool isObject() const {
+ JS_ASSERT((mask != NullMask) == bool(mask & ObjectMask));
+ return mask != NullMask;
+ }
+
+ operator JSObject *() const {
+ return obj;
+ }
+
+ JSObject *operator->() const {
+ JS_ASSERT(isObject());
+ return obj;
+ }
+
+ JSObject &operator*() const {
+ JS_ASSERT(isObject());
+ return *obj;
+ }
+
+ /* Assignment */
+
+ void setNull() {
+ mask = NullMask;
+ obj = NULL;
+ }
+
+ void setFunObj(JSObject &o) {
+ JS_ASSERT(JS_ObjectIsFunction(NULL, &o));
+ mask = FunObjMask;
+ obj = &o;
+ }
+
+ void setNonFunObj(JSObject &o) {
+ JS_ASSERT(!JS_ObjectIsFunction(NULL, &o));
+ mask = NonFunObjMask;
+ obj = &o;
+ }
+
+ void setNonFunObjOrNull(JSObject *o) {
+ if (o) {
+ JS_ASSERT(!JS_ObjectIsFunction(NULL, o));
+ mask = NonFunObjMask;
+ obj = o;
+ } else {
+ mask = NullMask;
+ obj = o;
+ }
+ }
+};
+
+inline bool operator==(ObjPtr lhs, ObjPtr rhs) { return lhs == rhs; }
+inline bool operator==(ObjPtr lhs, JSObject *rhs) { return lhs == rhs; }
+inline bool operator==(JSObject *lhs, ObjPtr rhs) { return lhs == rhs; }
+inline bool operator!=(ObjPtr lhs, ObjPtr rhs) { return !(lhs == rhs); }
+inline bool operator!=(ObjPtr lhs, JSObject *rhs) { return !(lhs == rhs); }
+inline bool operator!=(JSObject *lhs, ObjPtr rhs) { return !(lhs == rhs); }
+
+/*
+ * These types are intended to be used like:
+ *
+ * ObjPtr p = NullObjPtr();
+ * void f1(ObjPtr);
+ * f1(FunObjPtr(funobj));
+ */
+
+struct NullObjPtr : ObjPtr
+{
+ explicit NullObjPtr() {
+ mask = NullMask;
+ obj = NULL;
+ }
+};
+
+struct FunObjPtr : ObjPtr
+{
+ explicit FunObjPtr(JSObject &o) {
+ JS_ASSERT(JS_ObjectIsFunction(NULL, &o));
+ mask = FunObjMask;
+ obj = &o;
+ }
+};
+
+struct NonFunObjPtr : ObjPtr
+{
+ explicit NonFunObjPtr(JSObject &o) {
+ JS_ASSERT(!JS_ObjectIsFunction(NULL, &o));
+ mask = NonFunObjMask;
+ obj = &o;
+ }
+};
+
+struct NonFunObjOrNullPtr : ObjPtr
+{
+ explicit NonFunObjOrNullPtr(JSObject *o) {
+ if (o) {
+ JS_ASSERT(!JS_ObjectIsFunction(NULL, o));
+ mask = NonFunObjMask;
+ obj = o;
+ } else {
+ mask = NullMask;
+ obj = NULL;
+ }
+ }
+};
+
+/* TODO: this can be removed when copying is implicit/public. */
+class ExplicitlyConstructedValue;
+
+/*
+ * While there is a single representation for values, there are two declared
+ * types for dealing with these values: jsval and js::Value. jsval allows a
+ * high-degree of source compatibility with the old word-sized boxed value
+ * representation. js::Value is a new C++-only type and more accurately
+ * reflects the current, unboxed value representation. As these two types are
+ * layout-compatible, pointers to jsval and js::Value are interchangeable and
+ * may be cast safely and canonically using js::Jsvalify and js::asValue.
+ */
+class Value
+{
+ /*
+ * Generally, we'd like to keep the exact representation encapsulated so
+ * that it may be tweaked in the future. Engine internals that need to
+ * break this encapsulation should be listed as friends below. Also see
+ * uses of public jsval members in jsapi.h/jspubtd.h.
+ */
+ friend bool StrictlyEqual(JSContext *, const Value &, const Value &);
+ friend bool Interpret(JSContext *); /* grep "value representation" */
+ friend bool PrimitiveThisTest(JSFunction *, const Value &);
+ friend class PrimitiveValue;
+
+ protected:
+ /* Type masks */
+ typedef JSValueMaskType MaskType;
+ static const MaskType NullMask = JSVAL_NULL_MASK;
+ static const MaskType UndefinedMask = JSVAL_UNDEFINED_MASK;
+ static const MaskType Int32Mask = JSVAL_INT32_MASK;
+ static const MaskType DoubleMask = JSVAL_DOUBLE_MASK;
+ static const MaskType StringMask = JSVAL_STRING_MASK;
+ static const MaskType NonFunObjMask = JSVAL_NONFUNOBJ_MASK;
+ static const MaskType FunObjMask = JSVAL_FUNOBJ_MASK;
+ static const MaskType BooleanMask = JSVAL_BOOLEAN_MASK;
+ static const MaskType MagicMask = JSVAL_MAGIC_MASK;
+
+ /* Standard collections of types. */
+ static const MaskType NumberMask = Int32Mask | DoubleMask;
+ static const MaskType ObjectMask = NonFunObjMask | FunObjMask;
+ static const MaskType GCThingMask = ObjectMask | StringMask;
+
+ static bool isSingleton(MaskType m) { return !(m & ~UndefinedMask); }
+ static bool isObjectOrNull(MaskType m) { return !(m & ~ObjectMask); }
+
+ union Data
+ {
+ int32 i32;
+ uint32 u32;
+ double dbl;
+ JSString *str;
+ JSObject *obj;
+ void *ptr;
+ JSBool boo;
+#ifdef DEBUG
+ JSWhyMagic why;
+#endif
+ struct { int32 first; int32 second; } bits;
+ };
+
+ MaskType mask;
+ JS_INSERT_VALUE_PADDING()
+ Data data;
+
+ friend class AssertLayoutCompatible;
+
+ /*
+ * To copy, use explicit copy().
+ *
+ * XXX This may be made public later, right now its just being used to
+ * identify unnecessary copying.
+ */
+ Value &operator=(const Value &);
+
+ public:
+ /* XXX: this can be removed when copying is public/implicit */
+ inline Value(const ExplicitlyConstructedValue &v);
+
+ /*
+ * Constructors
+ *
+ * To construct a null value, use NullValue. To construct pointers to
+ * objects statically known to be, or not to be, function objects, use
+ * FunObjValue, NonFunObjValue.
+ */
+
+ /* N.B. default construction yields a Value in an undefined state. */
+ Value() {}
+
+ /* XXX: 'explicit' can be removed when copying is public/implicit */
+ explicit Value(const Value &v)
+ : mask(v.mask), data(v.data)
+ {}
+
+ explicit Value(int32 i32) {
+ mask = Int32Mask;
+ data.i32 = i32;
+ }
+
+ explicit Value(double dbl) {
+ mask = DoubleMask;
+ data.dbl = dbl;
+ }
+
+ Value(JSString *str) {
+ mask = StringMask;
+ data.str = str;
+ }
+
+ explicit Value(bool b) {
+ mask = BooleanMask;
+ data.boo = b;
+ }
+
+ explicit Value(JSWhyMagic why) {
+ mask = MagicMask;
+#ifdef DEBUG
+ data.why = why;
+#endif
+ }
+
+ Value(ObjPtr ptr) {
+ mask = ptr.mask;
+ data.obj = ptr.obj;
+ }
+
+ /* Mutators */
+
+ void setNull() {
+ mask = NullMask;
+ data.obj = NULL;
+ }
+
+ void setUndefined() {
+ /* N.B. data is undefined. */
+ mask = UndefinedMask;
+ }
+
+ void setInt32(int32 i) {
+ mask = Int32Mask;
+ data.i32 = i;
+ }
+
+ int32_t &asInt32Ref() {
+ JS_ASSERT(isInt32());
+ return data.i32;
+ }
+
+ void setDouble(double d) {
+ JS_ASSERT(size_t(&data.dbl) % sizeof(double) == 0);
+ mask = DoubleMask;
+ data.dbl = d;
+ }
+
+ double &asDoubleRef() {
+ JS_ASSERT(size_t(&data.dbl) % sizeof(double) == 0);
+ JS_ASSERT(isDouble());
+ return data.dbl;
+ }
+
+ void setString(JSString *str) {
+ mask = StringMask;
+ data.str = str;
+ }
+
+ void setBoolean(bool b) {
+ mask = BooleanMask;
+ data.boo = b;
+ }
+
+ void setMagic(JSWhyMagic why) {
+ mask = MagicMask;
+#ifdef DEBUG
+ data.why = why;
+#endif
+ }
+
+ void setFunObj(JSObject &o) {
+ JS_ASSERT(JS_ObjectIsFunction(NULL, &o));
+ mask = FunObjMask;
+ data.obj = &o;
+ }
+
+ void setNonFunObj(JSObject &o) {
+ JS_ASSERT(!JS_ObjectIsFunction(NULL, &o));
+ mask = NonFunObjMask;
+ data.obj = &o;
+ }
+
+ void setNonFunObjOrNull(JSObject *o) {
+ if (o) {
+ mask = NonFunObjMask;
+ data.obj = o;
+ } else {
+ mask = NullMask;
+ data.obj = NULL;
+ }
+ }
+
+ /* Mutators */
+
+ /* XXX: to be removed when copying is implicit/public */
+ void copy(ObjPtr ptr) {
+ data.obj = ptr.obj;
+ mask = ptr.mask;
+ }
+
+ /* XXX: to be removed when copying is implicit/public */
+ void copy(const Value &v) {
+ data = v.data;
+ mask = v.mask;
+ }
+
+ void swap(Value &rhs) {
+ MaskType m = mask;
+ mask = rhs.mask;
+ rhs.mask = m;
+ Data d = data;
+ data = rhs.data;
+ rhs.data = d;
+ }
+
+ /* Accessors */
+
+ bool isUndefined() const {
+ return mask == UndefinedMask;
+ }
+
+ bool isNull() const {
+ return mask == NullMask;
+ }
+
+ bool isNullOrUndefined() const {
+ return isSingleton(mask);
+ }
+
+ bool isInt32() const {
+ return mask == Int32Mask;
+ }
+
+ int32 asInt32() const {
+ JS_ASSERT(isInt32());
+ return data.i32;
+ }
+
+ bool isDouble() const {
+ return mask == DoubleMask;
+ }
+
+ double asDouble() const {
+ JS_ASSERT(size_t(&data.dbl) % sizeof(double) == 0);
+ return data.dbl;
+ }
+
+ bool isNumber() const {
+ return bool(mask & NumberMask);
+ }
+
+ double asNumber() const {
+ JS_ASSERT(isNumber());
+ return isDouble() ? asDouble() : double(asInt32());
+ }
+
+ bool isString() const {
+ return mask == StringMask;
+ }
+
+ JSString *asString() const {
+ JS_ASSERT(isString());
+ return data.str;
+ }
+
+ bool isNonFunObj() const {
+ return mask == NonFunObjMask;
+ }
+
+ JSObject &asNonFunObj() const {
+ JS_ASSERT(isNonFunObj());
+ return *data.obj;
+ }
+
+ bool isFunObj() const {
+ return mask == FunObjMask;
+ }
+
+ JSObject &asFunObj() const {
+ JS_ASSERT(isFunObj());
+ return *data.obj;
+ }
+
+ bool isObject() const {
+ return bool(mask & ObjectMask);
+ }
+
+ bool isPrimitive() const {
+ return !isObject();
+ }
+
+ JSObject &asObject() const {
+ JS_ASSERT(isObject());
+ return *data.obj;
+ }
+
+ bool isObjectOrNull() const {
+ return isObjectOrNull(mask);
+ }
+
+ JSObject *asObjectOrNull() const {
+ JS_ASSERT(isObjectOrNull());
+ return data.obj;
+ }
+
+ ObjPtr asObjPtr() const {
+ JS_ASSERT(isObjectOrNull());
+ return ObjPtr(mask, data.obj);
+ }
+
+ bool isGCThing() const {
+ return bool(mask & GCThingMask);
+ }
+
+ void *asGCThing() const {
+ JS_ASSERT(isGCThing());
+ return data.ptr;
+ }
+
+ int32 traceKind() const {
+ JS_ASSERT(isGCThing());
+ return mask == StringMask;
+ }
+
+ bool isBoolean() const {
+ return mask == BooleanMask;
+ }
+
+ bool asBoolean() const {
+ JS_ASSERT(isBoolean());
+ return data.boo;
+ }
+
+ bool isMagic() const {
+ return mask == MagicMask;
+ }
+
+ bool isMagic(JSWhyMagic why) const {
+ JS_ASSERT_IF(mask == MagicMask, data.why == why);
+ return isMagic();
+ }
+
+ JSWhyMagic whyMagic() const {
+ JS_ASSERT(mask == MagicMask);
+ return data.why;
+ }
+
+ /* See IS_SAME_JSVAL. */
+ bool isSame(const Value &v) const;
+
+ /*
+ * 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 valid type of Int32 and are thus GC-safe.
+ */
+
+ void setPrivateVoidPtr(void *p) {
+ mask = Int32Mask;
+ data.ptr = p;
+ }
+
+ void *asPrivateVoidPtr() const {
+ JS_ASSERT(mask == Int32Mask);
+ return data.ptr;
+ }
+
+ void setPrivateUint32(uint32 u) {
+ mask = Int32Mask;
+ data.u32 = u;
+ }
+
+ uint32 asPrivateUint32() const {
+ JS_ASSERT(mask == Int32Mask);
+ return data.u32;
+ }
+
+ uint32 &asPrivateUint32Ref() {
+ JS_ASSERT(mask == Int32Mask);
+ return data.u32;
+ }
+};
+
+/*
+ * These types are intended to be used like:
+ *
+ * Value v = NullValue();
+ * void f1(Value);
+ * f1(FunObjValue(funobj));
+ */
+
+/* TODO: this hackiness will be removed once copying is public/implicit */
+struct ExplicitlyConstructedValue : Value {};
+
+JS_ALWAYS_INLINE
+Value::Value(const ExplicitlyConstructedValue &v)
+ : mask(v.mask), data(v.data)
+{}
+
+struct NullValue : ExplicitlyConstructedValue
+{
+ explicit NullValue() {
+ mask = NullMask;
+ data.obj = NULL;
+ }
+};
+
+struct UndefinedValue : ExplicitlyConstructedValue
+{
+ explicit UndefinedValue() {
+ mask = UndefinedMask;
+ }
+};
+
+struct FunObjValue : ExplicitlyConstructedValue
+{
+ explicit FunObjValue(JSObject &o) {
+ JS_ASSERT(JS_ObjectIsFunction(NULL, &o));
+ mask = FunObjMask;
+ data.obj = &o;
+ }
+};
+
+struct NonFunObjValue : ExplicitlyConstructedValue
+{
+ explicit NonFunObjValue(JSObject &o) {
+ JS_ASSERT(JS_ObjectIsFunction(NULL, &o));
+ mask = NonFunObjMask;
+ data.obj = &o;
+ }
+};
+
+struct NonFunObjOrNullValue : ExplicitlyConstructedValue
+{
+ explicit NonFunObjOrNullValue(JSObject *o) {
+ if (o) {
+ JS_ASSERT(JS_ObjectIsFunction(NULL, o));
+ mask = NonFunObjMask;
+ data.obj = o;
+ } else {
+ mask = NullMask;
+ data.obj = NULL;
+ }
+ }
+};
+
+struct AssertLayoutCompatible
+{
+ JS_STATIC_ASSERT(sizeof(jsval) == 16);
+ JS_STATIC_ASSERT(sizeof(Value::MaskType) == 4);
+ JS_STATIC_ASSERT(sizeof(Value::Data) == 8);
+ JS_STATIC_ASSERT(offsetof(jsval, mask) == 0);
+ JS_STATIC_ASSERT(offsetof(jsval, mask) == offsetof(Value, mask));
+ JS_STATIC_ASSERT(sizeof(Value) == sizeof(jsval));
+ JS_STATIC_ASSERT(sizeof(Value::Data) == sizeof(((jsval *)0)->data));
+ JS_STATIC_ASSERT(offsetof(Value, data) == offsetof(jsval, data));
+ JS_STATIC_ASSERT(sizeof(Value::MaskType) == sizeof(JSValueMaskType));
+ JS_STATIC_ASSERT(sizeof(Value::MaskType) == sizeof(((jsval *)0)->mask));
+ JS_STATIC_ASSERT(offsetof(Value, mask) == offsetof(jsval, mask));
+ JS_STATIC_ASSERT(sizeof(NullValue) == sizeof(Value));
+ JS_STATIC_ASSERT(sizeof(UndefinedValue) == sizeof(Value));
+ JS_STATIC_ASSERT(sizeof(FunObjValue) == sizeof(Value));
+ JS_STATIC_ASSERT(sizeof(NonFunObjValue) == sizeof(Value));
+};
+
+/*
+ * As asserted above, js::Value and jsval are layout equivalent. To provide
+ * widespread casting, the following safe casts are provided.
+ */
+static JS_ALWAYS_INLINE jsval * Jsvalify(Value *v) { return (jsval *)v; }
+static JS_ALWAYS_INLINE const jsval * Jsvalify(const Value *v) { return (const jsval *)v; }
+static JS_ALWAYS_INLINE jsval & Jsvalify(Value &v) { return (jsval &)v; }
+static JS_ALWAYS_INLINE const jsval & Jsvalify(const Value &v) { return (const jsval &)v; }
+static JS_ALWAYS_INLINE Value * Valueify(jsval *v) { return (Value *)v; }
+static JS_ALWAYS_INLINE const Value * Valueify(const jsval *v) { return (const Value *)v; }
+static JS_ALWAYS_INLINE Value & Valueify(jsval &v) { return (Value &)v; }
+static JS_ALWAYS_INLINE const Value & Valueify(const jsval &v) { return (const Value &)v; }
+
+/*
+ * N.B. It is more efficient to use setNull/isNull/setUndefined/isUndefined
+ * than to copy/compare these global values.
+ */
+extern const Value sNullValue;
+extern const Value sUndefinedValue;
+extern const ObjPtr sNullObjPtr;
+
+/*
+ * js::Class is layout compatible and thus
+ */
+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;
+ JSReserveSlotsOp reserveSlots;
+};
+
+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(sizeof(JSExtendedClass) == sizeof(ExtendedClass));
+
+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; }
+
+} /* namespace js */
+#endif /* __cplusplus */
+
#endif /* jsapi_h___ */
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -33,32 +33,34 @@
* 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 ***** */
+#define __STDC_LIMIT_MACROS
+
/*
* JS array class.
*
* Array objects begin as "dense" arrays, optimized for index-only property
* access over a vector of slots (obj->dslots) with high load factor. Array
* methods optimize for denseness by testing that the object's class is
* &js_ArrayClass, and can then directly manipulate the slots for efficiency.
*
* We track these pieces of metadata for arrays in dense mode:
* - the array's length property as a uint32, in JSSLOT_ARRAY_LENGTH,
* - the number of indices that are filled (non-holes), in JSSLOT_ARRAY_COUNT,
* - the net number of slots starting at dslots (capacity), in dslots[-1] if
* dslots is non-NULL.
*
- * 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
* array_length_setter for an explanation of how the first, most surprising
* case may occur.
*
* Arrays are converted to use js_SlowArrayClass when any of these conditions
* are met:
@@ -121,58 +123,53 @@ INDEX_TOO_BIG(jsuint index)
return index > JS_BIT(29) - 1;
}
#define INDEX_TOO_SPARSE(array, index) \
(INDEX_TOO_BIG(index) || \
((index) > js_DenseArrayCapacity(array) && (index) >= MIN_SPARSE_INDEX && \
(index) > ((array)->getArrayCount() + 1) * 4))
-JS_STATIC_ASSERT(sizeof(JSScopeProperty) > 4 * sizeof(jsval));
-
#define ENSURE_SLOW_ARRAY(cx, obj) \
(obj->getClass() == &js_SlowArrayClass || js_MakeArraySlow(cx, obj))
/*
* Determine if the id represents an array index or an XML property index.
*
* An id is an array index according to ECMA by (15.4):
*
* "Array objects give special treatment to a certain class of property names.
* A property name P (in the form of a string value) is an array index if and
* only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
* 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.
*/
JSBool
-js_IdIsIndex(jsval id, jsuint *indexp)
+js_IdIsIndex(jsid id, jsuint *indexp)
{
- JSString *str;
- jschar *cp;
-
- if (JSVAL_IS_INT(id)) {
+ if (JSID_IS_INT(id)) {
jsint i;
- i = JSVAL_TO_INT(id);
+ i = JSID_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))
+ if (!JSID_IS_ATOM(id))
return JS_FALSE;
- str = JSVAL_TO_STRING(id);
- cp = str->chars();
+ JSString *str = ATOM_TO_STRING(JSID_TO_ATOM(id));
+ jschar *cp = str->chars();
if (JS7_ISDEC(*cp) && str->length() < sizeof(MAXSTR)) {
jsuint index = JS7_UNDEC(*cp++);
jsuint oldIndex = 0;
jsuint c = 0;
if (index != 0) {
while (JS7_ISDEC(*cp)) {
oldIndex = index;
c = JS7_UNDEC(*cp);
@@ -189,99 +186,101 @@ js_IdIsIndex(jsval id, jsuint *indexp)
*indexp = index;
return JS_TRUE;
}
}
return JS_FALSE;
}
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->asInt32();
if (i < 0)
goto error;
return (jsuint) i;
}
jsdouble d;
- if (!ValueToNumber(cx, *vp, &d))
+ if (!ValueToNumber(cx, vp, &d))
goto error;
if (JSDOUBLE_IS_NaN(d))
goto error;
+ jsuint length;
length = (jsuint) d;
if (d != (jsdouble) length)
goto error;
return length;
error:
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_ARRAY_LENGTH);
- *vp = JSVAL_NULL;
+ vp->setNull();
return 0;
}
JSBool
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
{
if (obj->isArray()) {
*lengthp = obj->getArrayLength();
return true;
}
if (obj->isArguments() && !IsOverriddenArgsLength(obj)) {
*lengthp = GetArgsLength(obj);
return true;
}
- AutoValueRooter tvr(cx, JSVAL_NULL);
+ AutoValueRooter tvr(cx, NullValue());
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().asInt32())); /* jsuint cast does ToUint32 */
return true;
}
JS_STATIC_ASSERT(sizeof(jsuint) == sizeof(uint32_t));
- return ValueToECMAUint32(cx, tvr.value(), (uint32_t *)lengthp);
+ return ValueToECMAUint32(cx, tvr.addr(), (uint32_t *)lengthp);
}
-static JSBool
-IndexToValue(JSContext *cx, jsdouble index, jsval *vp)
+static inline void
+IndexToValue(JSContext *cx, jsdouble index, Value *vp)
{
- return js_NewWeaklyRootedNumber(cx, index, vp);
+ int32_t i;
+ if (JSDOUBLE_IS_INT32(index, i))
+ vp->setInt32(i);
+ else
+ vp->setDouble(index);
}
JSBool JS_FASTCALL
js_IndexToId(JSContext *cx, jsuint index, jsid *idp)
{
JSString *str;
if (index <= JSVAL_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, Value(str), idp);
}
static JSBool
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);
start = JS_ARRAY_END(buf);
do {
--start;
@@ -298,59 +297,59 @@ BigIndexToId(JSContext *cx, JSObject *ob
* in any case.
*/
if (!createAtom &&
((clasp = obj->getClass()) == &js_SlowArrayClass ||
clasp == &js_ArgumentsClass ||
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 {
atom = js_AtomizeChars(cx, start, JS_ARRAY_END(buf) - start, 0);
if (!atom)
return JS_FALSE;
}
*idp = ATOM_TO_JSID(atom);
return JS_TRUE;
}
static JSBool
ResizeSlots(JSContext *cx, JSObject *obj, uint32 oldlen, uint32 newlen,
bool initializeAllSlots = true)
{
- jsval *slots, *newslots;
+ Value *slots, *newslots;
if (newlen == 0) {
if (obj->dslots) {
cx->free(obj->dslots - 1);
obj->dslots = NULL;
}
return JS_TRUE;
}
if (newlen > MAX_DSLOTS_LENGTH) {
js_ReportAllocationOverflow(cx);
return JS_FALSE;
}
slots = obj->dslots ? obj->dslots - 1 : NULL;
- newslots = (jsval *) cx->realloc(slots, (size_t(newlen) + 1) * sizeof(jsval));
+ newslots = (Value *) cx->realloc(slots, (size_t(newlen) + 1) * sizeof(Value));
if (!newslots)
return JS_FALSE;
obj->dslots = newslots + 1;
js_SetDenseArrayCapacity(obj, newlen);
if (initializeAllSlots) {
for (slots = obj->dslots + oldlen; slots < obj->dslots + newlen; slots++)
- *slots = JSVAL_HOLE;
+ slots->setMagic(JS_ARRAY_HOLE);
}
return JS_TRUE;
}
/*
* When a dense array with CAPACITY_DOUBLING_MAX or fewer slots needs to grow,
* double its capacity, to push() N elements in amortized O(N) time.
@@ -359,17 +358,17 @@ ResizeSlots(JSContext *cx, JSObject *obj
* with a higher constant factor, and we waste less space.
*/
#define CAPACITY_DOUBLING_MAX (1024 * 1024)
/*
* 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).
*/
-#define CAPACITY_CHUNK (1024 * 1024 / sizeof(jsval))
+#define CAPACITY_CHUNK (1024 * 1024 / sizeof(Value))
static JSBool
EnsureCapacity(JSContext *cx, JSObject *obj, uint32 newcap,
bool initializeAllSlots = true)
{
uint32 oldcap = js_DenseArrayCapacity(obj);
if (newcap > oldcap) {
@@ -393,206 +392,204 @@ EnsureCapacity(JSContext *cx, JSObject *
else if (actualCapacity < ARRAY_CAPACITY_MIN)
actualCapacity = ARRAY_CAPACITY_MIN;
if (!ResizeSlots(cx, obj, oldcap, actualCapacity, initializeAllSlots))
return JS_FALSE;
if (!initializeAllSlots) {
/*
* Initialize the slots caller didn't actually ask for.
*/
- for (jsval *slots = obj->dslots + newcap;
+ for (Value *slots = obj->dslots + newcap;
slots < obj->dslots + actualCapacity;
slots++) {
- *slots = JSVAL_HOLE;
+ slots->setMagic(JS_ARRAY_HOLE);
}
}
}
return JS_TRUE;
}
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, Value(index), idp);
}
static bool
IndexToId(JSContext* cx, JSObject* obj, jsdouble index, JSBool* hole, jsid* idp,
JSBool createAtom = JS_FALSE)
{
if (index <= JSVAL_INT_MAX) {
*idp = INT_TO_JSID(int(index));
return JS_TRUE;
}
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;
}
return ReallyBigIndexToId(cx, index, idp);
}
/*
* If the property at the given index exists, get its value into location
* pointed by vp and set *hole to false. Otherwise set *hole to true and *vp
* to JSVAL_VOID. This function assumes that the location pointed by vp is
* properly rooted and can be used as GC-protected storage for temporaries.
*/
static JSBool
GetArrayElement(JSContext *cx, JSObject *obj, jsdouble index, JSBool *hole,
- jsval *vp)
+ Value *vp)
{
JS_ASSERT(index >= 0);
+ Value *vp2;
if (obj->isDenseArray() && index < js_DenseArrayCapacity(obj) &&
- (*vp = obj->dslots[jsuint(index)]) != JSVAL_HOLE) {
+ !(vp2 = &obj->dslots[jsuint(index)])->isMagic(JS_ARRAY_HOLE)) {
+ vp->copy(*vp2);
*hole = JS_FALSE;
return JS_TRUE;
}
AutoIdRooter idr(cx);
*hole = JS_FALSE;
if (!IndexToId(cx, obj, index, hole, idr.addr()))
return JS_FALSE;
if (*hole) {
- *vp = JSVAL_VOID;
+ vp->setUndefined();
return JS_TRUE;
}
JSObject *obj2;
JSProperty *prop;
if (!obj->lookupProperty(cx, idr.id(), &obj2, &prop))
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))
return JS_FALSE;
*hole = JS_FALSE;
}
return JS_TRUE;
}
/*
* 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);
if (obj->isDenseArray()) {
/* Predicted/prefetched code should favor the remains-dense case. */
if (index <= jsuint(-1)) {
jsuint idx = jsuint(index);
if (!INDEX_TOO_SPARSE(obj, idx)) {
JS_ASSERT(idx + 1 > idx);
if (!EnsureCapacity(cx, obj, idx + 1))
return JS_FALSE;
if (idx >= obj->getArrayLength())
obj->setArrayLength(idx + 1);
- if (obj->dslots[idx] == JSVAL_HOLE)
+ if (obj->dslots[idx].isMagic(JS_ARRAY_HOLE))
obj->incArrayCountBy(1);
- obj->dslots[idx] = v;
+ obj->dslots[idx].copy(v);
return JS_TRUE;
}
}
if (!js_MakeArraySlow(cx, obj))
return JS_FALSE;
}
AutoIdRooter idr(cx);
if (!IndexToId(cx, obj, index, NULL, idr.addr(), JS_TRUE))
return JS_FALSE;
- JS_ASSERT(!JSVAL_IS_VOID(idr.id()));
-
- return obj->setProperty(cx, idr.id(), &v);
+ JS_ASSERT(!JSID_IS_VOID(idr.id()));
+
+ Value tmp;
+ tmp.copy(v);
+ return obj->setProperty(cx, idr.id(), &tmp);
}
static JSBool
DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index)
{
JS_ASSERT(index >= 0);
if (obj->isDenseArray()) {
if (index <= jsuint(-1)) {
jsuint idx = jsuint(index);
if (!INDEX_TOO_SPARSE(obj, idx) && idx < js_DenseArrayCapacity(obj)) {
- if (obj->dslots[idx] != JSVAL_HOLE)
+ if (!obj->dslots[idx].isMagic(JS_ARRAY_HOLE))
obj->decArrayCountBy(1);
- obj->dslots[idx] = JSVAL_HOLE;
+ obj->dslots[idx].setMagic(JS_ARRAY_HOLE);
return JS_TRUE;
}
}
return JS_TRUE;
}
AutoIdRooter idr(cx);
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);
}
/*
* When hole is true, delete the property at the given index. Otherwise set
* its value to v assuming v is rooted.
*/
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);
}
JSBool
js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length)
{
- jsval v;
+ Value v;
jsid id;
- if (!IndexToValue(cx, length, &v))
- return JS_FALSE;
+ IndexToValue(cx, length, &v);
id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
return obj->setProperty(cx, id, &v);
}
JSBool
js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
{
JSErrorReporter older = JS_SetErrorReporter(cx, NULL);
- AutoValueRooter tvr(cx, JSVAL_NULL);
+ AutoValueRooter tvr(cx, NullValue());
jsid id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
JSBool ok = obj->getProperty(cx, id, tvr.addr());
JS_SetErrorReporter(cx, older);
if (!ok)
return false;
*lengthp = ValueIsLength(cx, tvr.addr());
- return !JSVAL_IS_NULL(tvr.value());
+ return !tvr.value().isNull();
}
JSBool
js_IsArrayLike(JSContext *cx, JSObject *obj, JSBool *answerp, jsuint *lengthp)
{
JSObject *wrappedObj = js_GetWrappedObject(cx, obj);
*answerp = wrappedObj->isArguments() || wrappedObj->isArray();
@@ -611,48 +608,48 @@ js_IsArrayLike(JSContext *cx, JSObject *
*
* Since SpiderMonkey supports cross-class prototype-based delegation, we have
* to be careful about the length getter and setter being called on an object
* not of Array class. For the getter, we search obj's prototype chain for the
* array that caused this getter to be invoked. In the setter case to overcome
* 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()) {
+ IndexToValue(cx, obj->getArrayLength(), vp);
+ 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);
return obj->defineProperty(cx, lengthId, *vp, NULL, NULL, JSPROP_ENUMERATE);
}
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;
-
+ IndexToValue(cx, newlen, vp);
if (oldlen < newlen) {
obj->setArrayLength(newlen);
return true;
}
if (obj->isDenseArray()) {
/* Don't reallocate if we're not actually shrinking our slots. */
jsuint capacity = js_DenseArrayCapacity(obj);
@@ -672,23 +669,23 @@ array_length_setter(JSContext *cx, JSObj
* correspond to indexes in the half-open range [newlen, oldlen). See
* bug 322135.
*/
JSObject *iter = JS_NewPropertyIterator(cx, obj);
if (!iter)
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)) {
return false;
}
}
}
@@ -705,17 +702,17 @@ IsDenseArrayId(JSContext *cx, JSObject *
{
JS_ASSERT(obj->isDenseArray());
uint32 i;
return id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom) ||
(js_IdIsIndex(id, &i) &&
obj->getArrayLength() != 0 &&
i < js_DenseArrayCapacity(obj) &&
- obj->dslots[i] != JSVAL_HOLE);
+ !obj->dslots[i].isMagic(JS_ARRAY_HOLE));
}
static JSBool
array_lookupProperty(JSContext *cx, JSObject *obj, jsid id, JSObject **objp,
JSProperty **propp)
{
if (!obj->isDenseArray())
return js_LookupProperty(cx, obj, id, objp, propp);
@@ -738,94 +735,98 @@ array_lookupProperty(JSContext *cx, JSOb
static void
array_dropProperty(JSContext *cx, JSObject *obj, JSProperty *prop)
{
JS_ASSERT(IsDenseArrayId(cx, obj, (jsid) prop));
}
JSBool
js_GetDenseArrayElementValue(JSContext *cx, JSObject *obj, JSProperty *prop,
- jsval *vp)
+ Value *vp)
{
jsid id = (jsid) prop;
JS_ASSERT(IsDenseArrayId(cx, obj, id));
uint32 i;
if (!js_IdIsIndex(id, &i)) {
JS_ASSERT(id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom));
- return IndexToValue(cx, obj->getArrayLength(), vp);
+ IndexToValue(cx, obj->getArrayLength(), vp);
+ return JS_TRUE;
}
- *vp = obj->dslots[i];
+ vp->copy(obj->dslots[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 (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
+ IndexToValue(cx, obj->getArrayLength(), vp);
+ return JS_TRUE;
+ }
if (id == ATOM_TO_JSID(cx->runtime->atomState.protoAtom)) {
- *vp = OBJECT_TO_JSVAL(obj->getProto());
+ vp->copy(obj->getProtoValue());
return JS_TRUE;
}
if (!obj->isDenseArray())
return js_GetProperty(cx, obj, id, vp);
- if (!js_IdIsIndex(ID_TO_VALUE(id), &i) || i >= js_DenseArrayCapacity(obj) ||
- obj->dslots[i] == JSVAL_HOLE) {
+ if (!js_IdIsIndex(id, &i) || i >= js_DenseArrayCapacity(obj) ||
+ obj->dslots[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;
if (prop) {
if (obj2->isNative()) {
sprop = (JSScopeProperty *) prop;
if (!js_NativeGet(cx, obj, obj2, sprop, JSGET_METHOD_BARRIER, vp))
return JS_FALSE;
}
obj2->dropProperty(cx, prop);
}
return JS_TRUE;
}
- *vp = obj->dslots[i];
+ vp->copy(obj->dslots[i]);
return JS_TRUE;
}
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;
if (!js_IdIsIndex(id, &index))
return JS_TRUE;
length = obj->getArrayLength();
if (index >= length)
obj->setArrayLength(index + 1);
return JS_TRUE;
}
-static JSBool
+/* XXX gal's patch is making this go away. */
+JSBool
slowarray_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
- jsval *statep, jsid *idp);
+ Value *statep, jsid *idp);
static JSType
array_typeOf(JSContext *cx, JSObject *obj)
{
return JSTYPE_OBJECT;
}
/* The same as js_ObjectOps except for the .enumerate and .call hooks. */
@@ -838,23 +839,23 @@ static JSObjectOps js_SlowArrayObjectOps
slowarray_enumerate, js_CheckAccess,
array_typeOf, js_TraceObject,
NULL, NATIVE_DROP_PROPERTY,
NULL, js_Construct,
js_HasInstance, js_Clear
};
static JSObjectOps *
-slowarray_getObjectOps(JSContext *cx, JSClass *clasp)
+slowarray_getObjectOps(JSContext *cx, Class *clasp)
{
return &js_SlowArrayObjectOps;
}
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))
return array_length_setter(cx, obj, id, vp);
if (!obj->isDenseArray())
return js_SetProperty(cx, obj, id, vp);
@@ -865,19 +866,19 @@ array_setProperty(JSContext *cx, JSObjec
return js_SetProperty(cx, obj, id, vp);
}
if (!EnsureCapacity(cx, obj, i + 1))
return JS_FALSE;
if (i >= obj->getArrayLength())
obj->setArrayLength(i + 1);
- if (obj->dslots[i] == JSVAL_HOLE)
+ if (obj->dslots[i].isMagic(JS_ARRAY_HOLE))
obj->incArrayCountBy(1);
- obj->dslots[i] = *vp;
+ obj->dslots[i].copy(*vp);
return JS_TRUE;
}
JSBool
js_PrototypeHasIndexedProperties(JSContext *cx, JSObject *obj)
{
/*
* Walk up the prototype chain and see if this indexed element already
@@ -896,22 +897,22 @@ js_PrototypeHasIndexedProperties(JSConte
return JS_TRUE;
}
return JS_FALSE;
}
#ifdef JS_TRACER
static inline JSBool FASTCALL
-dense_grow(JSContext* cx, JSObject* obj, jsint i, jsval v)
+dense_grow(JSContext* cx, JSObject* obj, jsint i, const jsval &v)
{
/*
* 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(Value) != sizeof(uint32)));
if (MAX_DSLOTS_LENGTH > MAX_DSLOTS_LENGTH32) {
/*
* Have to check for negative values bleeding through on 64-bit machines only,
* since we can't allocate large enough arrays for this on 32-bit machines.
*/
if (i < 0)
return JS_FALSE;
}
@@ -934,17 +935,17 @@ dense_grow(JSContext* cx, JSObject* obj,
}
obj->dslots[u] = 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, const jsval &v)
{
JS_ASSERT(obj->isDenseArray());
return dense_grow(cx, obj, i, v);
}
JS_DEFINE_CALLINFO_4(extern, BOOL, js_Array_dense_setelem, CONTEXT, OBJECT, INT32, JSVAL, 0,
nanojit::ACC_STORE_ANY)
JSBool FASTCALL
@@ -983,33 +984,35 @@ js_Array_dense_setelem_double(JSContext*
return dense_grow(cx, obj, i, v);
}
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))
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;
+ tmp.copy(*value);
+ return array_setProperty(cx, obj, id, &tmp);
}
static JSBool
array_getAttributes(JSContext *cx, JSObject *obj, jsid id, JSProperty *prop,
uintN *attrsp)
{
*attrsp = id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)
? JSPROP_PERMANENT : JSPROP_ENUMERATE;
@@ -1021,227 +1024,60 @@ array_setAttributes(JSContext *cx, JSObj
uintN *attrsp)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_CANT_SET_ARRAY_ATTRS);
return JS_FALSE;
}
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;
+ rval->setBoolean(false);
return JS_TRUE;
}
if (js_IdIsIndex(id, &i) && i < js_DenseArrayCapacity(obj) &&
- obj->dslots[i] != JSVAL_HOLE) {
+ !obj->dslots[i].isMagic(JS_ARRAY_HOLE)) {
obj->decArrayCountBy(1);
- obj->dslots[i] = JSVAL_HOLE;
+ obj->dslots[i].setMagic(JS_ARRAY_HOLE);
}
- *rval = JSVAL_TRUE;
+ rval->setBoolean(true);
return JS_TRUE;
}
-/*
- * JSObjectOps.enumerate implementation.
- *
- * For a fast array, JSENUMERATE_INIT captures in the enumeration state both
- * the length of the array and the bitmap indicating the positions of holes in
- * the array. This ensures that adding or deleting array elements does not
- * affect the sequence of indexes JSENUMERATE_NEXT returns.
- *
- * For a common case of an array without holes, to represent the state we pack
- * the (nextEnumerationIndex, arrayLength) pair as a pseudo-boolean jsval.
- * This is possible when length <= PACKED_UINT_PAIR_BITS. For arrays with
- * greater length or holes we allocate the JSIndexIterState structure and
- * store it as an int-tagged private pointer jsval. For a slow array we
- * delegate the enumeration implementation to js_Enumerate in
- * slowarray_enumerate.
- *
- * Array mutations can turn a fast array into a slow one after the enumeration
- * starts. When this happens, slowarray_enumerate receives a state created
- * when the array was fast. To distinguish such fast state from a slow state,
- * which is an int-tagged pointer that js_Enumerate creates, we set not one
- * but two lowest bits when tagging a JSIndexIterState pointer -- see
- * INDEX_ITER_TAG usage below. Thus, when slowarray_enumerate receives a state
- * tagged with JSVAL_SPECIAL or with two lowest bits set, it knows that this
- * is a fast state so it calls array_enumerate to continue enumerating the
- * indexes present in the original fast array.
- */
-
-#define PACKED_UINT_PAIR_BITS 14
-#define PACKED_UINT_PAIR_MASK JS_BITMASK(PACKED_UINT_PAIR_BITS)
-
-#define UINT_PAIR_TO_SPECIAL_JSVAL(i,j) \
- (JS_ASSERT((uint32) (i) <= PACKED_UINT_PAIR_MASK), \
- JS_ASSERT((uint32) (j) <= PACKED_UINT_PAIR_MASK), \
- ((jsval) (i) << (PACKED_UINT_PAIR_BITS + JSVAL_TAGBITS)) | \
- ((jsval) (j) << (JSVAL_TAGBITS)) | \
- (jsval) JSVAL_SPECIAL)
-
-#define SPECIAL_JSVAL_TO_UINT_PAIR(v,i,j) \
- (JS_ASSERT(JSVAL_IS_SPECIAL(v)), \
- (i) = (uint32) ((v) >> (PACKED_UINT_PAIR_BITS + JSVAL_TAGBITS)), \
- (j) = (uint32) ((v) >> JSVAL_TAGBITS) & PACKED_UINT_PAIR_MASK, \
- JS_ASSERT((i) <= PACKED_UINT_PAIR_MASK))
-
-JS_STATIC_ASSERT(PACKED_UINT_PAIR_BITS * 2 + JSVAL_TAGBITS <= JS_BITS_PER_WORD);
-
-typedef struct JSIndexIterState {
- uint32 index;
- uint32 length;
- JSBool hasHoles;
-
- /*
- * Variable-length bitmap representing array's holes. It must not be
- * accessed when hasHoles is false.
- */
- jsbitmap holes[1];
-} JSIndexIterState;
-
-#define INDEX_ITER_TAG 3
-
-JS_STATIC_ASSERT(JSVAL_INT == 1);
-
-static JSBool
-array_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
- jsval *statep, jsid *idp)
-{
- uint32 capacity, i;
- JSIndexIterState *ii;
-
- switch (enum_op) {
- case JSENUMERATE_INIT:
- JS_ASSERT(obj->isDenseArray());
- capacity = js_DenseArrayCapacity(obj);
- if (idp)
- *idp = INT_TO_JSVAL(obj->getArrayCount());
- ii = NULL;
- for (i = 0; i != capacity; ++i) {
- if (obj->dslots[i] == JSVAL_HOLE) {
- if (!ii) {
- ii = (JSIndexIterState *)
- cx->malloc(offsetof(JSIndexIterState, holes) +
- JS_BITMAP_SIZE(capacity));
- if (!ii)
- return JS_FALSE;
- ii->hasHoles = JS_TRUE;
- memset(ii->holes, 0, JS_BITMAP_SIZE(capacity));
- }
- JS_SET_BIT(ii->holes, i);
- }
- }
- if (!ii) {
- /* Array has no holes. */
- if (capacity <= PACKED_UINT_PAIR_MASK) {
- *statep = UINT_PAIR_TO_SPECIAL_JSVAL(0, capacity);
- break;
- }
- ii = (JSIndexIterState *)
- cx->malloc(offsetof(JSIndexIterState, holes));
- if (!ii)
- return JS_FALSE;
- ii->hasHoles = JS_FALSE;
- }
- ii->index = 0;
- ii->length = capacity;
- *statep = (jsval) ii | INDEX_ITER_TAG;
- JS_ASSERT(*statep & JSVAL_INT);
- break;
-
- case JSENUMERATE_NEXT:
- if (JSVAL_IS_SPECIAL(*statep)) {
- SPECIAL_JSVAL_TO_UINT_PAIR(*statep, i, capacity);
- if (i != capacity) {
- *idp = INT_TO_JSID(i);
- *statep = UINT_PAIR_TO_SPECIAL_JSVAL(i + 1, capacity);
- break;
- }
- } else {
- JS_ASSERT((*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG);
- ii = (JSIndexIterState *) (*statep & ~INDEX_ITER_TAG);
- i = ii->index;
- if (i != ii->length) {
- /* Skip holes if any. */
- if (ii->hasHoles) {
- while (JS_TEST_BIT(ii->holes, i) && ++i != ii->length)
- continue;
- }
- if (i != ii->length) {
- ii->index = i + 1;
- return js_IndexToId(cx, i, idp);
- }
- }
- }
- /* FALL THROUGH */
-
- case JSENUMERATE_DESTROY:
- if (!JSVAL_IS_SPECIAL(*statep)) {
- JS_ASSERT((*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG);
- ii = (JSIndexIterState *) (*statep & ~INDEX_ITER_TAG);
- cx->free(ii);
- }
- *statep = JSVAL_NULL;
- break;
- }
- return JS_TRUE;
-}
-
-static JSBool
-slowarray_enumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op,
- jsval *statep, jsid *idp)
-{
- JSBool ok;
-
- /* Are we continuing an enumeration that started when we were dense? */
- if (enum_op != JSENUMERATE_INIT) {
- if (JSVAL_IS_SPECIAL(*statep) ||
- (*statep & INDEX_ITER_TAG) == INDEX_ITER_TAG) {
- return array_enumerate(cx, obj, enum_op, statep, idp);
- }
- JS_ASSERT((*statep & INDEX_ITER_TAG) == JSVAL_INT);
- }
- ok = js_Enumerate(cx, obj, enum_op, statep, idp);
- JS_ASSERT(*statep == JSVAL_NULL || (*statep & INDEX_ITER_TAG) == JSVAL_INT);
- return ok;
-}
+/* XXX gal's patch is making this go away. */
+JSBool
+array_enumerate(JSContext *cx, JSObject *, JSIterateOp, Value *, jsid *);
static void
array_finalize(JSContext *cx, JSObject *obj)
{
if (obj->dslots)
cx->free(obj->dslots - 1);
obj->dslots = NULL;
}
static void
array_trace(JSTracer *trc, JSObject *obj)
{
- uint32 capacity;
- size_t i;
- jsval v;
-
JS_ASSERT(obj->isDenseArray());
obj->traceProtoAndParent(trc);
- capacity = js_DenseArrayCapacity(obj);
- for (i = 0; i < capacity; i++) {
- v = obj->dslots[i];
- if (JSVAL_IS_TRACEABLE(v)) {
- JS_SET_TRACING_INDEX(trc, "array_dslots", i);
- js_CallGCMarker(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
- }
+ uint32 capacity = js_DenseArrayCapacity(obj);
+ for (size_t i = 0; i < capacity; i++) {
+ JS_SET_TRACING_INDEX(trc, "array_dslots", i);
+ CallGCMarkerIfGCThing(trc, obj->dslots[i]);
}
}
extern JSObjectOps js_ArrayObjectOps;
static const JSObjectMap SharedArrayMap(&js_ArrayObjectOps, JSObjectMap::SHAPELESS);
JSObjectOps js_ArrayObjectOps = {
@@ -1253,40 +1089,40 @@ JSObjectOps js_ArrayObjectOps = {
array_enumerate, js_CheckAccess,
array_typeOf, array_trace,
NULL, array_dropProperty,
NULL, NULL,
js_HasInstance, NULL
};
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(2) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Array) |
JSCLASS_NEW_ENUMERATE,
- 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_getObjectOps, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL
+ slowarray_addProperty, PropertyStub, PropertyStub, PropertyStub,
+ EnumerateStub, ResolveStub, js_TryValueOf, NULL,
+ slowarray_getObjectOps, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL
};
/*
* Convert an array object from fast-and-dense to slow-and-flexible.
*/
JSBool
js_MakeArraySlow(JSContext *cx, JSObject *obj)
{
@@ -1309,31 +1145,31 @@ js_MakeArraySlow(JSContext *cx, JSObject
JSScope *scope = JSScope::create(cx, &js_SlowArrayObjectOps, &js_SlowArrayClass, obj,
emptyShape);
if (!scope)
return JS_FALSE;
uint32 capacity = js_DenseArrayCapacity(obj);
if (capacity) {
scope->freeslot = obj->numSlots() + JS_INITIAL_NSLOTS;
- obj->dslots[-1] = JS_INITIAL_NSLOTS + capacity;
+ obj->dslots[-1].setPrivateUint32(JS_INITIAL_NSLOTS + capacity);
} else {
scope->freeslot = obj->numSlots();
}
/* Create new properties pointing to existing values in dslots */
for (uint32 i = 0; i < capacity; i++) {
jsid id;
JSScopeProperty *sprop;
if (!JS_ValueToId(cx, INT_TO_JSVAL(i), &id))
goto out_bad;
- if (obj->dslots[i] == JSVAL_HOLE) {
- obj->dslots[i] = JSVAL_VOID;
+ if (obj->dslots[i].isMagic(JS_ARRAY_HOLE)) {
+ obj->dslots[i].setUndefined();
continue;
}
sprop = scope->addDataProperty(cx, id, JS_INITIAL_NSLOTS + i,
JSPROP_ENUMERATE);
if (!sprop)
goto out_bad;
}
@@ -1341,50 +1177,46 @@ js_MakeArraySlow(JSContext *cx, JSObject
/*
* Render our formerly-reserved count property GC-safe. We do not need to
* make the length slot GC-safe because it is the private slot (this is
* statically asserted within JSObject) where the implementation can store
* an arbitrary value.
*/
JS_ASSERT(js_SlowArrayClass.flags & JSCLASS_HAS_PRIVATE);
obj->voidDenseArrayCount();
-
- /* Make sure we preserve any flags borrowing bits in classword. */
- obj->classword ^= (jsuword) &js_ArrayClass;
- obj->classword |= (jsuword) &js_SlowArrayClass;
-
+ obj->changeClassToSlowArray();
obj->map = scope;
return JS_TRUE;
out_bad:
scope->destroy(cx);
return JS_FALSE;
}
/* 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 = ComputeThisObjectFromVp(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;
}
/* Find joins or cycles in the reachable object graph. */
jschar *sharpchars;
JSHashEntry *he = js_EnterSharpObject(cx, obj, NULL, &sharpchars);
if (!he)
return false;
@@ -1438,17 +1270,17 @@ array_toSource(JSContext *cx, uintN argc
JSString *str;
if (hole) {
str = cx->runtime->emptyString;
} else {
str = js_ValueToSource(cx, *vp);
if (!str)
goto out;
}
- *vp = STRING_TO_JSVAL(str);
+ vp->setString(str);
const jschar *chars;
size_t charlen;
str->getCharsAndLength(chars, charlen);
/* Append element to buffer. */
if (!cb.append(chars, charlen))
goto out;
if (index + 1 != length) {
@@ -1474,17 +1306,17 @@ array_toSource(JSContext *cx, uintN argc
if (!initiallySharp)
js_LeaveSharpObject(cx, NULL);
return ok;
}
#endif
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);
/*
* Use HashTable entry as the cycle indicator. On first visit, create the
* entry, and, when leaving, remove the entry.
*/
typedef js::HashSet<JSObject *> ObjSet;
@@ -1494,21 +1326,21 @@ array_toString_sub(JSContext *cx, JSObje
/* Not in hash table, so not a cycle. */
if (!cx->busyArrays.add(hashp, obj)) {
JS_ReportOutOfMemory(cx);
return false;
}
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");
bool ok = false;
/* Get characters to use for the separator. */
static const jschar comma = ',';
const jschar *sep;
@@ -1534,26 +1366,23 @@ array_toString_sub(JSContext *cx, JSObje
/* Use rval to locally root each element value. */
JSBool hole;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, index, &hole, rval)) {
goto out;
}
/* 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, rval))
goto out;
- *rval = OBJECT_TO_JSVAL(robj);
JSAtom *atom = cx->runtime->atomState.toLocaleStringAtom;
- if (!js_TryMethod(cx, robj, atom, 0, NULL, rval))
+ if (!js_TryMethod(cx, rval->asObjectOrNull(), atom, 0, NULL, rval))
goto out;
}
if (!js_ValueToCharBuffer(cx, *rval, cb))
goto out;
}
/* Append the separator. */
@@ -1573,39 +1402,35 @@ array_toString_sub(JSContext *cx, JSObje
if (genBefore == cx->busyArrays.generation())
cx->busyArrays.remove(hashp);
else
cx->busyArrays.remove(obj);
return ok;
}
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 = ComputeThisObjectFromVp(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;
}
return array_toString_sub(cx, obj, JS_FALSE, NULL, 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 = ComputeThisObjectFromVp(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;
}
/*
* Passing comma here as the separator. Need a way to get a
* locale-specific version.
*/
return array_toString_sub(cx, obj, JS_TRUE, NULL, vp);
@@ -1617,17 +1442,17 @@ enum TargetElementsType {
};
enum SourceVectorType {
SourceVectorAllValues,
SourceVectorMayContainHoles
};
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);
/*
* Optimize for dense arrays so long as adding the given set of elements
* wouldn't otherwise make the array slow.
*/
@@ -1656,96 +1481,92 @@ InitArrayElements(JSContext *cx, JSObjec
jsuint newlen = start + count;
JS_ASSERT(jsdouble(start) + count == jsdouble(newlen));
if (!EnsureCapacity(cx, obj, newlen))
return JS_FALSE;
if (newlen > obj->getArrayLength())
obj->setArrayLength(newlen);
- JS_ASSERT(count < size_t(-1) / sizeof(jsval));
+ JS_ASSERT(count < size_t(-1) / sizeof(Value));
if (targetType == TargetElementsMayContainValues) {
jsuint valueCount = 0;
for (jsuint i = 0; i < count; i++) {
- if (obj->dslots[start + i] != JSVAL_HOLE)
+ if (!obj->dslots[start + i].isMagic(JS_ARRAY_HOLE))
valueCount++;
}
JS_ASSERT(obj->getArrayCount() >= valueCount);
obj->decArrayCountBy(valueCount);
}
- memcpy(obj->dslots + start, vector, sizeof(jsval) * count);
+ memcpy(obj->dslots + start, vector, sizeof(Value) * count);
if (vectorType == SourceVectorAllValues) {
obj->incArrayCountBy(count);
} else {
jsuint valueCount = 0;
for (jsuint i = 0; i < count; i++) {
- if (obj->dslots[start + i] != JSVAL_HOLE)
+ if (!obj->dslots[start + i].isMagic(JS_ARRAY_HOLE))
valueCount++;
}
obj->incArrayCountBy(valueCount);
}
- JS_ASSERT_IF(count != 0, obj->dslots[newlen - 1] != JSVAL_HOLE);
+ JS_ASSERT_IF(count != 0, !obj->dslots[newlen - 1].isMagic());
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++)) {
return JS_FALSE;
}
}
if (vector == end)
return JS_TRUE;
/* Finish out any remaining elements past the max array index. */
if (obj->isDenseArray() && !ENSURE_SLOW_ARRAY(cx, obj))
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(double(MAXINDEX));
do {
- tmp[1] = *vector++;
- if (!js_ValueToStringId(cx, tmp[0], idr.addr()) ||
- !obj->setProperty(cx, idr.id(), &tmp[1])) {
+ tvr.addr()->copy(*vector++);
+ if (!js_ValueToStringId(cx, idval, idr.addr()) ||
+ !obj->setProperty(cx, idr.id(), tvr.addr())) {
return JS_FALSE;
}
- *dp += 1;
+ idval.asDoubleRef() += 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());
obj->setArrayLength(length);
if (vector) {
if (!EnsureCapacity(cx, obj, length))
return JS_FALSE;
jsuint count = length;
if (!holey) {
- memcpy(obj->dslots, vector, length * sizeof (jsval));
+ memcpy(obj->dslots, 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->dslots[i] = vector[i];
+ obj->dslots[i].copy(vector[i]);
}
}
obj->setArrayCount(count);
} else {
obj->setArrayCount(0);
}
return JS_TRUE;
}
@@ -1773,41 +1594,39 @@ Array_p_toString(JSContext* cx, JSObject
return JSVAL_TO_STRING(tvr.value());
}
#endif
/*
* 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 = ComputeThisObjectFromVp(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 = ComputeThisObjectFromVp(cx, vp);
if (!obj || !js_GetLengthProperty(cx, obj, &len))
return JS_FALSE;
- *vp = OBJECT_TO_JSVAL(obj);
+ SetObject(vp, *obj);
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj)) {
/* An empty array or an array with no elements is already reversed. */
if (len == 0 || !obj->dslots)
return JS_TRUE;
/*
* It's actually surprisingly complicated to reverse an array due to the
@@ -1816,23 +1635,20 @@ array_reverse(JSContext *cx, uintN argc,
* be a common operation than other array mass-mutation methods, so for
* now just take a probably-small memory hit (in the absence of too many
* holes in the array at its start) and ensure that the capacity is
* sufficient to hold all the elements in the array if it were full.
*/
if (!EnsureCapacity(cx, obj, len))
return JS_FALSE;
- jsval* lo = &obj->dslots[0];
- jsval* hi = &obj->dslots[len - 1];
- for (; lo < hi; lo++, hi--) {
- jsval tmp = *lo;
- *lo = *hi;
- *hi = tmp;
- }
+ Value* lo = &obj->dslots[0];
+ Value* hi = &obj->dslots[len - 1];
+ for (; lo < hi; lo++, hi--)
+ lo->swap(*hi);
/*
* Per ECMA-262, don't update the length of the array, even if the new
* array has trailing holes (and thus the original array began with
* holes).
*/
return JS_TRUE;
}
@@ -1843,58 +1659,58 @@ array_reverse(JSContext *cx, uintN argc,
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, i, &hole, tvr.addr()) ||
!GetArrayElement(cx, obj, len - i - 1, &hole2, vp) ||
!SetOrDeleteArrayElement(cx, obj, len - i - 1, hole, tvr.value()) ||
!SetOrDeleteArrayElement(cx, obj, i, hole2, *vp)) {
return false;
}
}
- *vp = OBJECT_TO_JSVAL(obj);
+ JS_ASSERT(obj == &vp->asObject());
return true;
}
typedef struct MSortArgs {
size_t elsize;
JSComparator cmp;
void *arg;
- JSBool fastcopy;
+ JSBool isValue;
} MSortArgs;
/* Helper function for js_MergeSort. */
static JSBool
MergeArrays(MSortArgs *msa, void *src, void *dest, size_t run1, size_t run2)
{
void *arg, *a, *b, *c;
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;
/* Copy runs already in sorted order. */
b = (char *)src + run1 * elsize;
a = (char *)b - elsize;
CALL_CMP(a, b);
if (cmp_result <= 0) {
memcpy(dest, src, runtotal * elsize);
return JS_TRUE;
}
#define COPY_ONE(p,q,n) \
- (fastcopy ? (void)(*(jsval*)(p) = *(jsval*)(q)) : (void)memcpy(p, q, n))
+ (isValue ? (((Value*)p)->copy(*((Value*)q))) : (void)memcpy(p, q, n))
a = src;
c = dest;
for (; runtotal != 0; runtotal--) {
JSBool from_a = run2 == 0;
if (!from_a && run1 != 0) {
CALL_CMP(a,b);
from_a = cmp_result <= 0;
@@ -1916,31 +1732,28 @@ MergeArrays(MSortArgs *msa, void *src, v
return JS_TRUE;
}
/*
* 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, JSBool isValue)
{
void *swap, *vec1, *vec2;
MSortArgs msa;
size_t i, j, lo, hi, run;
- JSBool fastcopy;
int cmp_result;
/* 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 ? (((Value*)p)->copy(*(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
/*
* Apply insertion sort to small chunks to reduce the number of merge
* passes needed.
*/
@@ -1968,17 +1781,17 @@ js_MergeSort(void *src, size_t nel, size
}
}
#undef CALL_CMP
#undef COPY_ONE
msa.elsize = elsize;
msa.cmp = cmp;
msa.arg = arg;
- msa.fastcopy = fastcopy;
+ msa.isValue = isValue;
vec1 = src;
vec2 = tmp;
for (run = INS_SORT_INT; run < nel; run *= 2) {
for (lo = 0; lo < nel; lo += 2 * run) {
hi = lo + run;
if (hi >= nel) {
memcpy((char *)vec2 + lo * elsize, (char *)vec1 + lo * elsize,
@@ -1999,53 +1812,53 @@ js_MergeSort(void *src, size_t nel, size
memcpy(src, tmp, nel * elsize);
return JS_TRUE;
}
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)
{}
};
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;
/*
* 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;
- *sp++ = ca->fval;
- *sp++ = JSVAL_NULL;
- *sp++ = av;
- *sp++ = bv;
-
- if (!js_Invoke(cx, ca->args, 0))
+ Value *invokevp = ca->args.getvp();
+ Value *sp = invokevp;
+ sp++->copy(ca->fval);
+ sp++->setNull();
+ sp++->copy(*av);
+ sp++->copy(*bv);
+
+ if (!Invoke(cx, ca->args, 0))
return JS_FALSE;
jsdouble cmp;
- if (!ValueToNumber(cx, *invokevp, &cmp))
+ if (!ValueToNumber(cx, invokevp, &cmp))
return JS_FALSE;
/* Clamp cmp to -1, 0, 1. */
*result = 0;
if (!JSDOUBLE_IS_NaN(cmp) && cmp != 0)
*result = cmp > 0 ? 1 : -1;
/*
@@ -2064,97 +1877,89 @@ static inline JS_IGNORE_STACK JSComparat
comparator_stack_cast(JSRedComparator func)
{
return 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;
-
- JS_ASSERT(JSVAL_IS_STRING(av));
- JS_ASSERT(JSVAL_IS_STRING(bv));
+ const Value *av = (const Value *)a, *bv = (const Value *)b;
+
+ 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->asString(), bv->asString());
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 */
+ fval.copy(argv[0]); /* non-default compare function */
} else {
- fval = JSVAL_NULL;
+ fval.setNull();
}
- JSObject *obj = JS_THIS_OBJECT(cx, vp);
+ JSObject *obj = ComputeThisObjectFromVp(cx, vp);
if (!obj || !js_GetLengthProperty(cx, obj, &len))
return false;
if (len == 0) {
- *vp = OBJECT_TO_JSVAL(obj);
+ SetObject(vp, *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;
}
#endif
/*
* Initialize vec as a root. We will clear elements of vec one by
* one while increasing the rooted amount of vec when we know that the
* property at the corresponding index exists and its value must be rooted.
*
* 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);
/*
* By ECMA 262, 15.4.4.11, a property that does not exist (which we
* call a "hole") is always greater than an existing property with
* value undefined and that is always greater than any other property.
@@ -2166,138 +1971,137 @@ array_sort(JSContext *cx, uintN argc, js
newlen = 0;
bool allStrings = true;
for (i = 0; i < len; i++) {
if (!JS_CHECK_OPERATION_LIMIT(cx))
return false;
/* 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;
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;
}
if (newlen == 0)
return true; /* The array has only holes and undefs. */
/*
* 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;
+ Value *mergesort_tmp = vec + newlen;
PodZero(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
* prior to sorting. But we also need the space for the original
* 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
* the rooted scratch space for newlen elements at the tail, we
* can use it to rearrange and convert to strings first and try
* realloc only when we know that we successfully converted all
* 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;
}
#endif
/*
* Rearrange and string-convert the elements of the vector from
* the tail here and, after sorting, move the results back
* starting from the start to prevent overwrite the existing
* elements.
*/
i = newlen;
do {
--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);
- vec[2 * i + 1] = v;
+ vec[2 * i].setString(str);
+ vec[2 * i + 1].copy(v);
} 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);
+ PodZero(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, true)) {
return false;
}
if (!allStrings) {
/*
* We want to make the following loop fast and to unroot the
* cached results of toString invocations before the operation
* callback has a chance to run the GC. For this reason we do
* not call JS_CHECK_OPERATION_LIMIT in the loop.
*/
i = 0;
do {
- vec[i] = vec[2 * i + 1];
+ vec[i].copy(vec[2 * i + 1]);
} while (++i != newlen);
}
} else {
LeaveTrace(cx);
CompareArgs ca(cx, fval);
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, true)) {
return false;
}
}
/*
* We no longer need to root the scratch space for the merge sort, so
* unroot it now to make the job of a potential GC under
* InitArrayElements easier.
@@ -2307,73 +2111,77 @@ array_sort(JSContext *cx, uintN argc, js
SourceVectorAllValues)) {
return false;
}
}
/* 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++, sUndefinedValue)) {
return false;
+ }
}
/* Re-create any holes that sorted to the end of the array. */
while (len > newlen) {
if (!JS_CHECK_OPERATION_LIMIT(cx) || !DeleteArrayElement(cx, obj, --len))
return JS_FALSE;
}
- *vp = OBJECT_TO_JSVAL(obj);
+ SetObject(vp, *obj);
return true;
}
/*
* 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;
if (!js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
if (!InitArrayElements(cx, obj, length, argc, argv, TargetElementsMayContainValues,
SourceVectorAllValues)) {
return JS_FALSE;
}
/* Per ECMA-262, return the new array length. */
jsdouble newlength = length + jsdouble(argc);
- if (!IndexToValue(cx, newlength, rval))
- return JS_FALSE;
+ IndexToValue(cx, newlength, rval);
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 (!js_MakeArraySlow(cx, obj))
return JS_FALSE;
- return array_push_slowly(cx, obj, 1, &v, rval);
+ Value tmp;
+ tmp.copy(v);
+ return array_push_slowly(cx, obj, 1, &tmp, rval);
}
if (!EnsureCapacity(cx, obj, length + 1))
return JS_FALSE;
obj->setArrayLength(length + 1);
- JS_ASSERT(obj->dslots[length] == JSVAL_HOLE);
+ JS_ASSERT(obj->dslots[length].isMagic(JS_ARRAY_HOLE));
obj->incArrayCountBy(1);
- obj->dslots[length] = v;
- return IndexToValue(cx, obj->getArrayLength(), rval);
+ obj->dslots[length].copy(v);
+ IndexToValue(cx, obj->getArrayLength(), rval);
+ return JS_TRUE;
}
JSBool JS_FASTCALL
-js_ArrayCompPush(JSContext *cx, JSObject *obj, jsval v)
+js_ArrayCompPush(JSContext *cx, JSObject *obj, const Value &v)
{
JS_ASSERT(obj->isDenseArray());
uint32_t length = obj->getArrayLength();
JS_ASSERT(length <= js_DenseArrayCapacity(obj));
if (length == js_DenseArrayCapacity(obj)) {
if (length > JS_ARGS_LENGTH_MAX) {
JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
@@ -2381,17 +2189,17 @@ js_ArrayCompPush(JSContext *cx, JSObject
return JS_FALSE;
}
if (!EnsureCapacity(cx, obj, length + 1))
return JS_FALSE;
}
obj->setArrayLength(length + 1);
obj->incArrayCountBy(1);
- obj->dslots[length] = v;
+ obj->dslots[length].copy(v);
return JS_TRUE;
}
JS_DEFINE_CALLINFO_3(extern, BOOL, js_ArrayCompPush, CONTEXT, OBJECT, JSVAL, 0,
nanojit::ACC_STORE_ANY)
#ifdef JS_TRACER
static jsval FASTCALL
Array_p_push1(JSContext* cx, JSObject* obj, jsval v)
@@ -2403,61 +2211,59 @@ Array_p_push1(JSContext* cx, JSObject* o
return tvr.value();
}
SetBuiltinError(cx);
return JSVAL_VOID;
}
#endif
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 = ComputeThisObjectFromVp(cx, vp);
if (!obj)
return JS_FALSE;
if (argc != 1 || !obj->isDenseArray())
return array_push_slowly(cx, obj, argc, vp + 2, vp);
return array_push1_dense(cx, obj, vp[2], 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;
if (!js_GetLengthProperty(cx, obj, &index))
return JS_FALSE;
if (index == 0) {
- *vp = JSVAL_VOID;
+ vp->setUndefined();
} else {
index--;
/* Get the to-be-deleted property's value into vp. */
if (!GetArrayElement(cx, obj, index, &hole, vp))
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index))
return JS_FALSE;
}
return js_SetLengthProperty(cx, obj, index);
}
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--;
if (!GetArrayElement(cx, obj, index, &hole, vp))
return JS_FALSE;
if (!hole && !DeleteArrayElement(cx, obj, index))
return JS_FALSE;
obj->setArrayLength(index);
@@ -2475,61 +2281,58 @@ Array_p_pop(JSContext* cx, JSObject* obj
return tvr.value();
}
SetBuiltinError(cx);
return JSVAL_VOID;
}
#endif
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 = ComputeThisObjectFromVp(cx, vp);
if (!obj)
return JS_FALSE;
if (obj->isDenseArray())
return array_pop_dense(cx, obj, vp);
return array_pop_slowly(cx, obj, 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 = ComputeThisObjectFromVp(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 < js_DenseArrayCapacity(obj)) {
if (JS_LIKELY(obj->dslots != NULL)) {
- *vp = obj->dslots[0];
- if (*vp == JSVAL_HOLE)
- *vp = JSVAL_VOID;
+ vp->copy(obj->dslots[0]);
+ if (vp->isMagic(JS_ARRAY_HOLE))
+ vp->setUndefined();
else
obj->decArrayCountBy(1);
- memmove(obj->dslots, obj->dslots + 1, length * sizeof(jsval));
- obj->dslots[length] = JSVAL_HOLE;
+ memmove(obj->dslots, obj->dslots + 1, length * sizeof(Value));
+ obj->dslots[length].setMagic(JS_ARRAY_HOLE);
} else {
/*
* We don't need to modify the indexed properties of an empty array
* with an explicitly set non-zero length when shift() is called on
* it, but note fallthrough to reduce the length by one.
*/
JS_ASSERT(obj->getArrayCount() == 0);
- *vp = JSVAL_VOID;
+ vp->setUndefined();
}
} else {
/* Get the to-be-deleted property's value into vp ASAP. */
if (!GetArrayElement(cx, obj, 0, &hole, vp))
return JS_FALSE;
/* Slide down the array above the first element. */
AutoValueRooter tvr(cx);
@@ -2545,40 +2348,39 @@ array_shift(JSContext *cx, uintN argc, j
if (!hole && !DeleteArrayElement(cx, obj, length))
return JS_FALSE;
}
}
return js_SetLengthProperty(cx, obj, length);
}
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 = ComputeThisObjectFromVp(cx, vp);
if (!obj || !js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
newlen = length;
if (argc > 0) {
/* Slide up the array to make room for argc at the bottom. */
argv = JS_ARGV(cx, vp);
if (length > 0) {
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
!INDEX_TOO_SPARSE(obj, unsigned(newlen + argc))) {
JS_ASSERT(newlen + argc == length + argc);
if (!EnsureCapacity(cx, obj, length + argc))
return JS_FALSE;
- memmove(obj->dslots + argc, obj->dslots, length * sizeof(jsval));
+ memmove(obj->dslots + argc, obj->dslots, length * sizeof(Value));
for (uint32 i = 0; i < argc; i++)
- obj->dslots[i] = JSVAL_HOLE;
+ obj->dslots[i].setMagic(JS_ARRAY_HOLE);
} else {
last = length;
jsdouble upperIndex = last + argc;
AutoValueRooter tvr(cx);
do {
--last, --upperIndex;
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
@@ -2594,50 +2396,48 @@ array_unshift(JSContext *cx, uintN argc,
return JS_FALSE;
newlen += argc;
if (!js_SetLengthProperty(cx, obj, newlen))
return JS_FALSE;
}
/* Follow Perl by returning the new array length. */
- return IndexToValue(cx, newlen, vp);
+ IndexToValue(cx, newlen, vp);
+ 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
* that splice always returns an array value, even when given no
* 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->setNonFunObj(*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 = ComputeThisObjectFromVp(cx, vp);
if (!obj || !js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
/* Convert the first argument into a starting index. */
jsdouble d;
- if (!ValueToNumber(cx, *argv, &d))
+ if (!ValueToNumber(cx, argv, &d))
return JS_FALSE;
d = js_DoubleToInteger(d);
if (d < 0) {
d += length;
if (d < 0)
d = 0;
} else if (d > length) {
d = length;
@@ -2647,30 +2447,30 @@ array_splice(JSContext *cx, uintN argc,
argv++;
/* Convert the second argument from a count into a fencepost index. */
delta = length - begin;
if (argc == 0) {
count = delta;
end = length;
} else {
- if (!ValueToNumber(cx, *argv, &d))
+ if (!ValueToNumber(cx, argv, &d))
return JS_FALSE;
d = js_DoubleToInteger(d);
if (d < 0)
d = 0;
else if (d > delta)
d = delta;
count = (jsuint)d;
end = begin + count;
argc--;
argv++;
}
- AutoValueRooter tvr(cx, JSVAL_NULL);
+ AutoValueRooter tvr(cx, NullValue());
/* If there are elements to remove, put them into the return value. */
if (count > 0) {
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
!js_PrototypeHasIndexedProperties(cx, obj2) &&
end <= js_DenseArrayCapacity(obj)) {
if (!InitArrayObject(cx, obj2, count, obj->dslots + begin,
obj->getArrayCount() != obj->getArrayLength())) {
@@ -2694,26 +2494,26 @@ array_splice(JSContext *cx, uintN argc,
}
/* Find the direction (up or down) to copy and make way for argv. */
if (argc > count) {
delta = (jsuint)argc - count;
last = length;
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
length <= js_DenseArrayCapacity(obj) &&
- (length == 0 || obj->dslots[length - 1] != JSVAL_HOLE)) {
+ (length == 0 || !obj->dslots[length - 1].isMagic(JS_ARRAY_HOLE))) {
if (!EnsureCapacity(cx, obj, length + delta))
return JS_FALSE;
/* (uint) end could be 0, so we can't use a vanilla >= test. */
while (last-- > end) {
- jsval srcval = obj->dslots[last];
- jsval* dest = &obj->dslots[last + delta];
- if (*dest == JSVAL_HOLE && srcval != JSVAL_HOLE)
+ const Value &src = obj->dslots[last];
+ Value &dst = obj->dslots[last + delta];
+ if (dst.isMagic(JS_ARRAY_HOLE) && !src.isMagic(JS_ARRAY_HOLE))
obj->incArrayCountBy(1);
- *dest = srcval;
+ dst.copy(src);
}
obj->setArrayLength(obj->getArrayLength() + delta);
} else {
/* (uint) end could be 0, so we can't use a vanilla >= test. */
while (last-- > end) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, last + delta, hole, tvr.value())) {
@@ -2723,21 +2523,21 @@ array_splice(JSContext *cx, uintN argc,
}
length += delta;
} else if (argc < count) {
delta = count - (jsuint)argc;
if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
length <= js_DenseArrayCapacity(obj)) {
/* (uint) end could be 0, so we can't use a vanilla >= test. */
for (last = end; last < length; last++) {
- jsval srcval = obj->dslots[last];
- jsval* dest = &obj->dslots[last - delta];
- if (*dest == JSVAL_HOLE && srcval != JSVAL_HOLE)
+ const Value &src = obj->dslots[last];
+ Value &dst = obj->dslots[last - delta];
+ if (dst.isMagic(JS_ARRAY_HOLE) && !src.isMagic(JS_ARRAY_HOLE))
obj->incArrayCountBy(1);
- *dest = srcval;
+ dst.copy(src);
}
} else {
for (last = end; last < length; last++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, last, &hole, tvr.addr()) ||
!SetOrDeleteArrayElement(cx, obj, last - delta, hole, tvr.value())) {
return JS_FALSE;
}
@@ -2754,79 +2554,75 @@ array_splice(JSContext *cx, uintN argc,
SourceVectorAllValues) &&
js_SetLengthProperty(cx, obj, length);
}
/*
* 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 = ComputeThisObjectFromVp(cx, vp);
+ JSObject *nobj;
+ jsuint length;
if (aobj->isDenseArray()) {
/*
* Clone aobj but pass the minimum of its length and capacity, to
* handle a = [1,2,3]; a.length = 10000 "dense" cases efficiently. In
* such a case we'll pass 8 (not 3) due to ARRAY_CAPACITY_MIN, which
* will cause nobj to be over-allocated to 16. But in the normal case
* where length is <= capacity, nobj and aobj will have the same
* capacity.
*/
length = aobj->getArrayLength();
jsuint capacity = js_DenseArrayCapacity(aobj);
nobj = js_NewArrayObject(cx, JS_MIN(length, capacity), aobj->dslots,
aobj->getArrayCount() != length);
if (!nobj)
return JS_FALSE;
nobj->setArrayLength(length);
- *vp = OBJECT_TO_JSVAL(nobj);
+ vp->setNonFunObj(*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->setNonFunObj(*nobj);
length = 0;
}
- AutoValueRooter tvr(cx, JSVAL_NULL);
+ AutoValueRooter tvr(cx, NullValue());
/* 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.asObject();
wobj = js_GetWrappedObject(cx, aobj);
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;
}
/*
* Per ECMA 262, 15.4.4.4, step 9, ignore non-existent
* properties.
@@ -2845,47 +2641,47 @@ array_concat(JSContext *cx, uintN argc,
return false;
length++;
}
return js_SetLengthProperty(cx, nobj, length);
}
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 = ComputeThisObjectFromVp(cx, vp);
if (!obj || !js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
begin = 0;
end = length;
if (argc > 0) {
jsdouble d;
- if (!ValueToNumber(cx, argv[0], &d))
+ if (!ValueToNumber(cx, &argv[0], &d))
return JS_FALSE;
d = js_DoubleToInteger(d);
if (d < 0) {
d += length;
if (d < 0)
d = 0;
} else if (d > length) {
d = length;
}
begin = (jsuint)d;
if (argc > 1) {
- if (!ValueToNumber(cx, argv[1], &d))
+ if (!ValueToNumber(cx, &argv[1], &d))
return JS_FALSE;
d = js_DoubleToInteger(d);
if (d < 0) {
d += length;
if (d < 0)
d = 0;
} else if (d > length) {
d = length;
@@ -2898,25 +2694,25 @@ array_slice(JSContext *cx, uintN argc, j
begin = end;
if (obj->isDenseArray() && end <= js_DenseArrayCapacity(obj) &&
!js_PrototypeHasIndexedProperties(cx, obj)) {
nobj = js_NewArrayObject(cx, end - begin, obj->dslots + begin,
obj->getArrayCount() != obj->getArrayLength());
if (!nobj)
return JS_FALSE;
- *vp = OBJECT_TO_JSVAL(nobj);
+ vp->setNonFunObj(*nobj);
return JS_TRUE;
}
/* Create a new Array object and root it using *vp. */
nobj = js_NewArrayObject(cx, 0, NULL);
if (!nobj)
return JS_FALSE;
- *vp = OBJECT_TO_JSVAL(nobj);
+ vp->setNonFunObj(*nobj);
AutoValueRooter tvr(cx);
for (slot = begin; slot < end; slot++) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!GetArrayElement(cx, obj, slot, &hole, tvr.addr())) {
return JS_FALSE;
}
if (!hole && !SetArrayElement(cx, nobj, slot - begin, tvr.value()))
@@ -2924,38 +2720,37 @@ array_slice(JSContext *cx, uintN argc, j
}
return js_SetLengthProperty(cx, nobj, end - begin);
}
#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 = ComputeThisObjectFromVp(cx, vp);
if (!obj || !js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
if (length == 0)
goto not_found;
if (argc <= 1) {
i = isLast ? length - 1 : 0;
- tosearch = (argc != 0) ? vp[2] : JSVAL_VOID;
+ tosearch.copy((argc != 0) ? vp[2] : sUndefinedValue);
} else {
jsdouble start;
- tosearch = vp[2];
- if (!ValueToNumber(cx, vp[3], &start))
+ tosearch.copy(vp[2]);
+ if (!ValueToNumber(cx, &vp[3], &start))
return JS_FALSE;
start = js_DoubleToInteger(start);
if (start < 0) {
start += length;
if (start < 0) {
if (isLast)
goto not_found;
i = 0;
@@ -2979,36 +2774,38 @@ array_indexOfHelper(JSContext *cx, JSBoo
direction = 1;
}
for (;;) {
if (!JS_CHECK_OPERATION_LIMIT(cx) ||
!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)) {
+ Uint32ToValue(i, vp);
+ 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);
}
/* Order is important; extras that take a predicate funarg must follow MAP. */
typedef enum ArrayExtraMode {
FOREACH,
REDUCE,
@@ -3017,32 +2814,32 @@ typedef enum ArrayExtraMode {
FILTER,
SOME,
EVERY
} 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 = ComputeThisObjectFromVp(cx, vp);
jsuint length;
if (!obj || !js_GetLengthProperty(cx, obj, &length))
return JS_FALSE;
/*
* First, get or compute our callee, so that we error out consistently
* 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;
/*
* Set our initial return condition, used for zero-length array cases
* (and pre-size our map return to match our known length, for all cases).
*/
@@ -3060,17 +2857,17 @@ array_extra(JSContext *cx, ArrayExtraMod
/* FALL THROUGH */
case REDUCE:
if (length == 0 && argc == 1) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_EMPTY_ARRAY_REDUCE);
return JS_FALSE;
}
if (argc >= 2) {
- *vp = argv[1];
+ vp->copy(argv[1]);
} else {
JSBool hole;
do {
if (!GetArrayElement(cx, obj, start, &hole, vp))
return JS_FALSE;
start += step;
} while (hole && start != end);
@@ -3082,37 +2879,37 @@ array_extra(JSContext *cx, ArrayExtraMod
}
break;
case MAP:
case FILTER:
newlen = (mode == MAP) ? length : 0;
newarr = js_NewArrayObject(cx, newlen, NULL);
if (!newarr)
return JS_FALSE;
- *vp = OBJECT_TO_JSVAL(newarr);
+ vp->setNonFunObj(*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;
}
if (length == 0)
return JS_TRUE;
JSObject *thisp;
if (argc > 1 && !REDUCE_MODE(mode)) {
- if (!js_ValueToObject(cx, argv[1], &thisp))
+ if (!js_ValueToObjectOrNull(cx, argv[1], &argv[1]))
return JS_FALSE;
- argv[1] = OBJECT_TO_JSVAL(thisp);
+ thisp = argv[1].asObjectOrNull();
} else {
thisp = NULL;
}
/*
* For all but REDUCE, we call with 3 args (value, index, array). REDUCE
* requires 4 args (accum, value, index, array).
*/
@@ -3121,151 +2918,154 @@ array_extra(JSContext *cx, ArrayExtraMod
InvokeArgsGuard args;
if (!cx->stack().pushInvokeArgs(cx, argc, args))
return JS_FALSE;
MUST_FLOW_THROUGH("out");
JSBool ok = JS_TRUE;
JSBool cond;
- jsval *invokevp = args.getvp();
-
+ Value *invokevp = args.getvp();
+
+ Value calleev(callable);
+ Value thisv(thisp);
+ Value objv(obj);
AutoValueRooter tvr(cx);
for (jsint i = start; i != end; i += step) {
JSBool hole;
ok = JS_CHECK_OPERATION_LIMIT(cx) &&
- GetArrayElement(cx, obj, i, &hole, tvr.addr());
+ GetArrayElement(cx, &objv.asObject(), i, &hole, tvr.addr());
if (!ok)
goto out;
if (hole)
continue;
/*
* Push callable and 'this', then args. We must do this for every
* iteration around the loop since js_Invoke uses invokevp[0] for return
* 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++->copy(calleev);
+ sp++->copy(thisv);
if (REDUCE_MODE(mode))
- *sp++ = *vp;
- *sp++ = tvr.value();
- *sp++ = INT_TO_JSVAL(i);
- *sp++ = OBJECT_TO_JSVAL(obj);
+ sp++->copy(*vp);
+ sp++->copy(tvr.value());
+ sp++->setInt32(i);
+ sp++->copy(objv);
/* Do the call. */
- ok = js_Invoke(cx, args, 0);
+ ok = Invoke(cx, args, 0);
if (!ok)
break;
if (mode > MAP)
cond = js_ValueToBoolean(*invokevp);
#ifdef __GNUC__ /* quell GCC overwarning */
else
cond = JS_FALSE;
#endif
switch (mode) {
case FOREACH:
break;
case REDUCE:
case REDUCE_RIGHT:
- *vp = *invokevp;
+ vp->copy(*invokevp);
break;
case MAP:
ok = SetArrayElement(cx, newarr, i, *invokevp);
if (!ok)
goto out;
break;
case FILTER:
if (!cond)
break;
/* The filter passed *args.getvp(), so push it onto our result. */
ok = SetArrayElement(cx, newarr, newlen++, tvr.value());
if (!ok)
goto out;
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;
}
}
out:
if (ok && mode == FILTER)
ok = js_SetLengthProperty(cx, newarr, newlen);
return ok;
}
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);
}
#endif
static JSBool
-array_isArray(JSContext *cx, uintN argc, jsval *vp)
+array_isArray(JSContext *cx, uintN argc, Value *vp)
{
- *vp = BOOLEAN_TO_JSVAL(argc > 0 &&
- !JSVAL_IS_PRIMITIVE(vp[2]) &&
- js_GetWrappedObject(cx, JSVAL_TO_OBJECT(vp[2]))->isArray());
+ vp->setBoolean(argc > 0 &&
+ vp[2].isObject() &&
+ js_GetWrappedObject(cx, &vp[2].asObject())->isArray());
return JS_TRUE;
}
static JSPropertySpec array_props[] = {
{js_length_str, -1, JSPROP_SHARED | JSPROP_PERMANENT,
- array_length_getter, array_length_setter},
+ Jsvalify(array_length_getter), Jsvalify(array_length_setter)},
{0,0,0,0,0}
};
JS_DEFINE_TRCINFO_1(array_toString,
(2, (static, STRING_FAIL, Array_p_toString, CONTEXT, THIS, 0, nanojit::ACC_STORE_ANY)))
JS_DEFINE_TRCINFO_1(array_join,
(3, (static, STRING_FAIL, Array_p_join, CONTEXT, THIS, STRING, 0, nanojit::ACC_STORE_ANY)))
JS_DEFINE_TRCINFO_1(array_push,
@@ -3310,41 +3110,41 @@ static JSFunctionSpec array_methods[] =
};
static JSFunctionSpec array_static_methods[] = {
JS_FN("isArray", array_isArray, 1,0),
JS_FS_END
};
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 = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
if (!obj)
return JS_FALSE;
- *rval = OBJECT_TO_JSVAL(obj);
+ rval->setNonFunObj(*obj);
}
if (argc == 0) {
length = 0;
vector = NULL;
} 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;
}
return InitArrayObject(cx, obj, length, vector);
}
JSObject* JS_FASTCALL
js_NewEmptyArray(JSContext* cx, JSObject* proto)
@@ -3352,23 +3152,22 @@ js_NewEmptyArray(JSContext* cx, JSObject
JS_ASSERT(proto->isArray());
JSObject* obj = js_NewGCObject(cx);
if (!obj)
return NULL;
/* Initialize all fields of JSObject. */
obj->map = const_cast<JSObjectMap *>(&SharedArrayMap);
- obj->classword = jsuword(&js_ArrayClass);
- obj->setProto(proto);
+ obj->initArrayClass();
+ obj->setProto(NonFunObjPtr(*proto));
obj->setParent(proto->getParent());
obj->setArrayLength(0);
- obj->setArrayCount(0);
- obj->voidArrayUnused();
+ obj->voidDenseArrayCount();
obj->dslots = NULL;
return obj;
}
#ifdef JS_TRACER
JS_DEFINE_CALLINFO_2(extern, OBJECT, js_NewEmptyArray, CONTEXT, OBJECT, 0, nanojit::ACC_STORE_ANY)
#endif
JSObject* JS_FASTCALL
@@ -3401,40 +3200,40 @@ js_NewArrayWithSlots(JSContext* cx, JSOb
#ifdef JS_TRACER
JS_DEFINE_CALLINFO_3(extern, OBJECT, js_NewArrayWithSlots, CONTEXT, OBJECT, UINT32, 0,
nanojit::ACC_STORE_ANY)
#endif
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,
array_props, array_methods, NULL, array_static_methods);
/* Initialize the Array prototype object so it gets a length property. */
if (!proto || !InitArrayObject(cx, proto, 0, NULL))
return NULL;
return proto;
}
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 = js_NewObject(cx, &js_ArrayClass, NULL, NULL);
if (!obj)
return NULL;
/*
* If this fails, the global object was not initialized and its class does
* not have JSCLASS_IS_GLOBAL.
*/
JS_ASSERT(obj->getProto());
{
- AutoValueRooter tvr(cx, obj);
+ AutoObjectRooter tvr(cx, obj);
if (!InitArrayObject(cx, obj, length, vector, holey))
obj = NULL;
}
/* Set/clear newborn root, in case we lost it. */
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
return obj;
}
@@ -3445,17 +3244,17 @@ js_NewSlowArrayObject(JSContext *cx)
JSObject *obj = js_NewObject(cx, &js_SlowArrayClass, NULL, NULL);
if (obj)
obj->setArrayLength(0);
return obj;
}
#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;
for (i = 0; i < argc; i++) {
char *bytes;
bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, argv[i],
@@ -3493,24 +3292,24 @@ js_CoerceArrayToCanvasImageData(JSObject
return JS_FALSE;
length = obj->getArrayLength();
if (length < offset + count)
return JS_FALSE;
JSUint8 *dp = dest;
for (uintN i = offset; i < offset+count; i++) {
- jsval v = obj->dslots[i];
- if (JSVAL_IS_INT(v)) {
- jsint vi = JSVAL_TO_INT(v);
+ const Value &v = obj->dslots[i];
+ if (v.isInt32()) {
+ jsint vi = v.asInt32();
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.asDouble();
if (!(vd >= 0)) /* Not < so that NaN coerces to 0 */
*dp++ = 0;
else if (vd > 255)
*dp++ = 255;
else {
jsdouble toTruncate = vd + 0.5;
JSUint8 val = JSUint8(toTruncate);
@@ -3537,23 +3336,23 @@ js_CoerceArrayToCanvasImageData(JSObject
return JS_FALSE;
}
}
return JS_TRUE;
}
JS_FRIEND_API(JSObject *)
-js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector)
+js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, Value **vector)
{
JSObject *obj = js_NewArrayObject(cx, capacity, NULL);
if (!obj)
return NULL;
- AutoValueRooter tvr(cx, obj);
+ AutoObjectRooter tvr(cx, obj);
if (!EnsureCapacity(cx, obj, capacity, JS_FALSE))
obj = NULL;
/* Set/clear newborn root, in case we lost it. */
cx->weakRoots.finalizableNewborns[FINALIZE_OBJECT] = obj;
if (!obj)
return NULL;
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -41,24 +41,22 @@
#define jsarray_h___
/*
* JS Array interface.
*/
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jsobj.h"
-JS_BEGIN_EXTERN_C
-
#define ARRAY_CAPACITY_MIN 7
extern JSBool
-js_IdIsIndex(jsval id, jsuint *indexp);
+js_IdIsIndex(jsid id, jsuint *indexp);
-extern JSClass js_ArrayClass, js_SlowArrayClass;
+extern js::Class js_ArrayClass, js_SlowArrayClass;
inline bool
JSObject::isDenseArray() const
{
return getClass() == &js_ArrayClass;
}
inline bool
@@ -107,38 +105,38 @@ js_InitContextBusyArrayTable(JSContext *
/*
* Creates a new array with the given length and proto (NB: NULL is not
* translated to Array.prototype), with len slots preallocated.
*/
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 *
js_NewSlowArrayObject(JSContext *cx);
extern JSBool
js_MakeArraySlow(JSContext *cx, JSObject *obj);
static JS_INLINE uint32
js_DenseArrayCapacity(JSObject *obj)
{
JS_ASSERT(obj->isDenseArray());
- return obj->dslots ? (uint32) obj->dslots[-1] : 0;
+ return obj->dslots ? obj->dslotLength() : 0;
}
static JS_INLINE void
js_SetDenseArrayCapacity(JSObject *obj, uint32 capacity)
{
JS_ASSERT(obj->isDenseArray());
JS_ASSERT(obj->dslots);
- obj->dslots[-1] = (jsval) capacity;
+ obj->dslots[-1].setPrivateUint32(capacity);
}
extern JSBool
js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp);
extern JSBool
js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length);
@@ -162,31 +160,33 @@ js_IsArrayLike(JSContext *cx, JSObject *
* JS-specific merge sort function.
*/
typedef JSBool (*JSComparator)(void *arg, const void *a, const void *b,
int *result);
/*
* 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, bool isValue);
#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);
+js_ArrayCompPush(JSContext *cx, JSObject *obj, const js::Value &v);
/*
* Fast dense-array-to-buffer conversion for use by canvas.
*
* If the array is a dense array, fill [offset..offset+count] values into
* destination, assuming that types are consistent. Return JS_TRUE if
* successful, otherwise JS_FALSE -- note that the destination buffer may be
* modified even if JS_FALSE is returned (e.g. due to finding an inappropriate
@@ -206,31 +206,29 @@ js_CoerceArrayToCanvasImageData(JSObject
JSBool
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::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
* given capacity. Non-null return value means allocation of the internal
* buffer for a capacity of at least |capacity| succeeded. A pointer to the
* first element of this internal buffer is returned in the |vector| out
* parameter. The caller promises to fill in the first |capacity| values
* starting from that pointer immediately after this function returns and
* 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|.
*/
JS_FRIEND_API(JSObject *)
-js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, jsval **vector);
-
-JS_END_EXTERN_C
+js_NewArrayObjectWithCapacity(JSContext *cx, jsuint capacity, js::Value **vector);
#endif /* jsarray_h___ */
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -32,16 +32,18 @@
* 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 ***** */
+#define __STDC_LIMIT_MACROS
+
/*
* JS atom table.
*/
#include <stdlib.h>
#include <string.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsutil.h" /* Added by JSIFY */
@@ -53,17 +55,23 @@
#include "jscntxt.h"
#include "jsgc.h"
#include "jslock.h"
#include "jsnum.h"
#include "jsparse.h"
#include "jsscan.h"
#include "jsstr.h"
#include "jsversion.h"
+#include "jsxml.h"
+
#include "jsstrinlines.h"
+#include "jsatominlines.h"
+#include "jsobjinlines.h"
+
+using namespace js;
/*
* ATOM_HASH assumes that JSHashNumber is 32-bit even on 64-bit systems.
*/
JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
JS_STATIC_ASSERT(sizeof(JSAtom *) == JS_BYTES_PER_WORD);
/*
@@ -80,17 +88,17 @@ JS_STATIC_ASSERT(ATOM_OFFSET_LIMIT % siz
JS_STATIC_ASSERT(1 * sizeof(JSAtom *) ==
offsetof(JSAtomState, booleanAtoms) - ATOM_OFFSET_START);
JS_STATIC_ASSERT((1 + 2) * sizeof(JSAtom *) ==
offsetof(JSAtomState, typeAtoms) - ATOM_OFFSET_START);
const char *
js_AtomToPrintableString(JSContext *cx, JSAtom *atom)
{
- return js_ValueToPrintableString(cx, ATOM_KEY(atom));
+ return js_ValueToPrintableString(cx, Value(ATOM_TO_STRING(atom)));
}
#define JS_PROTO(name,code,init) const char js_##name##_str[] = #name;
#include "jsproto.tbl"
#undef JS_PROTO
/*
* String constants for common atoms defined in JSAtomState starting from
@@ -264,22 +272,22 @@ const char js_current_str[] = "
/*
* 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.
*/
typedef struct JSAtomHashEntry {
JSDHashEntryHdr hdr;
- jsuword keyAndFlags;
+ jsboxedword keyAndFlags;
} 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 < JSBOXEDWORD_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))
#define ATOM_ENTRY_FLAGS(entry) \
@@ -531,18 +539,18 @@ js_locked_atom_tracer(JSDHashTable *tabl
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
JSTracer *trc = (JSTracer *)arg;
if (entry->keyAndFlags == 0) {
/* Ignore uninitialized entries during tracing. */
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);
+ CallGCMarker(trc, ATOM_ENTRY_KEY(entry),
+ IS_STRING_TABLE(table) ? JSTRACE_STRING : JSTRACE_DOUBLE);
return JS_DHASH_NEXT;
}
static JSDHashOperator
js_pinned_atom_tracer(JSDHashTable *table, JSDHashEntryHdr *hdr,
uint32 number, void *arg)
{
JSAtomHashEntry *entry = TO_ATOM_ENTRY(hdr);
@@ -551,17 +559,17 @@ js_pinned_atom_tracer(JSDHashTable *tabl
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);
+ CallGCMarker(trc, ATOM_ENTRY_KEY(entry), JSTRACE_STRING);
}
return JS_DHASH_NEXT;
}
void
js_TraceAtomState(JSTracer *trc, JSBool allAtoms)
{
JSRuntime *rt = trc->context->runtime;
@@ -614,30 +622,30 @@ js_SweepAtomState(JSContext *cx)
JSAtom *
js_AtomizeDouble(JSContext *cx, jsdouble d)
{
JSAtomState *state;
JSDHashTable *table;
JSAtomHashEntry *entry;
uint32 gen;
jsdouble *key;
- jsval v;
+ jsboxedword w;
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);
+ key = js_NewWeaklyRootedDoubleAtom(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,
@@ -647,49 +655,49 @@ js_AtomizeDouble(JSContext *cx, jsdouble
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;
+ w = DOUBLE_TO_JSBOXEDWORD((jsdouble *)ATOM_ENTRY_KEY(entry));
+ cx->weakRoots.lastAtom = (JSAtom *)w;
JS_UNLOCK(cx, &state->lock);
- return (JSAtom *)v;
+ return (JSAtom *)w;
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;
JSString *key;
uint32 gen;
JS_ASSERT(!(flags & ~(ATOM_PINNED|ATOM_INTERNED|ATOM_TMPSTR|ATOM_NOCOPY)));
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));
}
/*
* Here we know that JSString::intStringTable covers only 256 (or at least
* not 1000 or more) chars. We rely on order here to resolve the unit vs.
* int string atom identity issue by giving priority to unit strings for
* '0' through '9' (see JSString::intString in jsstrinlines.h).
*/
@@ -700,17 +708,17 @@ js_AtomizeString(JSContext *cx, JSString
if ('1' <= chars[0] && chars[0] <= '9' &&
'0' <= chars[1] && chars[1] <= '9' &&
(length == 2 || ('0' <= chars[2] && chars[2] <= '9'))) {
jsint i = (chars[0] - '0') * 10 + chars[1] - '0';
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));
}
}
state = &cx->runtime->atomState;
table = &state->stringAtoms;
JS_LOCK(cx, &state->lock);
entry = TO_ATOM_ENTRY(JS_DHashTableOperate(table, str, JS_DHASH_ADD));
@@ -770,20 +778,20 @@ js_AtomizeString(JSContext *cx, JSString
}
INIT_ATOM_ENTRY(entry, key);
key->flatSetAtomized();
}
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);
JS_ReportOutOfMemory(cx);
return NULL;
}
JSAtom *
@@ -837,49 +845,49 @@ js_GetExistingStringAtom(JSContext *cx,
{
JSString str, *str2;
JSAtomState *state;
JSDHashEntryHdr *hdr;
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);
state = &cx->runtime->atomState;
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))
: NULL;
JS_UNLOCK(cx, &state->lock);
- return str2 ? (JSAtom *)STRING_TO_JSVAL(str2) : NULL;
+ return str2 ? STRING_TO_ATOM(str2) : NULL;
}
JSBool
-js_AtomizePrimitiveValue(JSContext *cx, jsval v, JSAtom **atomp)
+js_AtomizePrimitiveValue(JSContext *cx, jsboxedword w, JSAtom **atomp)
{
JSAtom *atom;
- if (JSVAL_IS_STRING(v)) {
- atom = js_AtomizeString(cx, JSVAL_TO_STRING(v), 0);
+ if (JSBOXEDWORD_IS_STRING(w)) {
+ atom = js_AtomizeString(cx, JSBOXEDWORD_TO_STRING(w), 0);
if (!atom)
return JS_FALSE;
- } else if (JSVAL_IS_DOUBLE(v)) {
- atom = js_AtomizeDouble(cx, *JSVAL_TO_DOUBLE(v));
+ } else if (JSBOXEDWORD_IS_DOUBLE(w)) {
+ atom = js_AtomizeDouble(cx, *JSBOXEDWORD_TO_DOUBLE(w));
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;
+ JS_ASSERT(JSBOXEDWORD_IS_INT(w) || JSBOXEDWORD_IS_BOOLEAN(w) ||
+ JSBOXEDWORD_IS_NULL(w) || JSBOXEDWORD_IS_VOID(w));
+ atom = (JSAtom *)w;
}
*atomp = atom;
return JS_TRUE;
}
#ifdef DEBUG
static JSDHashOperator
@@ -1260,8 +1268,101 @@ js_InitAtomMap(JSContext *cx, JSAtomMap
JS_HashTableEnumerateEntries(al->table, js_map_atom, vector);
} else {
do {
vector[ALE_INDEX(ale)] = ALE_ATOM(ale);
} while ((ale = ALE_NEXT(ale)) != NULL);
}
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.asObject());
+ return true;
+ }
+
+ if (!js_IsFunctionQName(cx, &idval.asObject(), idp))
+ return JS_FALSE;
+ if (*idp != 0)
+ 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.asObject();
+ *idp = OBJECT_TO_JSID(&idobj);
+ SetObject(vp, idobj);
+ return true;
+ }
+
+ if (!js_IsFunctionQName(cx, &idval.asObject(), idp))
+ return JS_FALSE;
+ if (*idp != 0) {
+ vp->copy(IdToValue(*idp));
+ return true;
+ }
+
+ if (js_ValueToStringId(cx, idval, idp)) {
+ vp->setString(ATOM_TO_STRING(JSID_TO_ATOM(*idp)));
+ return true;
+ }
+ return false;
+}
+#endif
+
+namespace js {
+
+bool
+ValueToId(JSContext *cx, const Value *vp, jsid *idp)
+{
+ int32_t i;
+ if (ValueFitsInInt32(*vp, &i) && INT32_FITS_IN_JSID(i)) {
+ *idp = INT_TO_JSID(i);
+ return true;
+ }
+
+#if JS_HAS_XML_SUPPORT
+ if (vp->isObject()) {
+ Class *clasp = vp->asObject().getClass();
+ if (JS_UNLIKELY(clasp == &js_QNameClass.base ||
+ clasp == &js_AttributeNameClass ||
+ clasp == &js_AnyNameClass)) {
+ *idp = OBJECT_TO_JSID(&vp->asObject());
+ return true;
+ }
+ }
+#endif
+
+ return js_ValueToStringId(cx, *vp, idp);
+}
+
+/*
+ * Normally, js::Value should not be passed by value, but this function should
+ * only be used on cold paths, so ease of use wins out.
+ */
+Value
+IdToValue(jsid id)
+{
+ ExplicitlyConstructedValue v;
+ if (JSID_IS_INT(id))
+ v.setInt32(JSID_TO_INT(id));
+ else if (JSID_IS_ATOM(id))
+ v.setString(ATOM_TO_STRING(JSID_TO_ATOM(id)));
+ else if (JSID_IS_NULL(id))
+ v.setNull();
+ else
+ SetObject(&v, *JSID_TO_OBJECT(id));
+ return v;
+}
+
+} /* namespace js */
--- a/js/src/jsatom.h
+++ b/js/src/jsatom.h
@@ -47,28 +47,28 @@
#include "jstypes.h"
#include "jshash.h" /* Added by JSIFY */
#include "jsdhash.h"
#include "jsapi.h"
#include "jsprvtd.h"
#include "jspubtd.h"
#include "jslock.h"
-JS_BEGIN_EXTERN_C
-
#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 ATOM_KEY(atom) ((jsboxedword)(atom))
+#define ATOM_IS_DOUBLE(atom) JSBOXEDWORD_IS_DOUBLE(ATOM_KEY(atom))
+#define ATOM_TO_DOUBLE(atom) JSBOXEDWORD_TO_DOUBLE(ATOM_KEY(atom))
+#define ATOM_IS_STRING(atom) JSBOXEDWORD_IS_STRING(ATOM_KEY(atom))
+#define ATOM_TO_STRING(atom) JSBOXEDWORD_TO_STRING(ATOM_KEY(atom))
+#define STRING_TO_ATOM(str) (JS_ASSERT(str->isAtomized()), \
+ (JSAtom *)STRING_TO_JSBOXEDWORD(str))
#if JS_BYTES_PER_WORD == 4
# define ATOM_HASH(atom) ((JSHashNumber)(atom) >> 2)
#elif JS_BYTES_PER_WORD == 8
# define ATOM_HASH(atom) (((JSHashNumber)(jsuword)(atom) >> 3) ^ \
(JSHashNumber)((jsuword)(atom) >> 32))
#else
# error "Unsupported configuration"
@@ -83,17 +83,17 @@ extern const char *
js_AtomToPrintableString(JSContext *cx, JSAtom *atom);
struct JSAtomListElement {
JSHashEntry entry;
};
#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)
/*
* In an upvars list, ALE_DEFN(ale)->resolve() is the outermost definition the
* name may reference. If a with block or a function that calls eval encloses
* the use, the name may end up referring to something else at runtime.
*/
#define ALE_DEFN(ale) ((JSDefinition *) (ale)->entry.value)
@@ -114,18 +114,16 @@ struct JSAtomListElement {
* or AME alternatives.
*/
struct JSAtomSet {
JSHashEntry *list; /* literals indexed for mapping */
JSHashTable *table; /* hash table if list gets too long */
jsuint count; /* count of indexed literals */
};
-#ifdef __cplusplus
-
struct JSAtomList : public JSAtomSet
{
#ifdef DEBUG
const JSAtomSet* set; /* asserted null in mutating methods */
#endif
JSAtomList() {
list = NULL; table = NULL; count = 0;
@@ -193,18 +191,16 @@ class JSAtomListIterator {
void reset() {
next = (JSAtomListElement *) list->list;
index = 0;
}
JSAtomListElement* operator ()();
};
-#endif /* __cplusplus */
-
struct JSAtomMap {
JSAtom **vector; /* array of ptrs to indexed atoms */
jsatomid length; /* count of (to-be-)indexed atoms */
};
struct JSAtomState {
JSDHashTable stringAtoms; /* hash table with shared strings */
JSDHashTable doubleAtoms; /* hash table with shared doubles */
@@ -480,28 +476,48 @@ js_AtomizeChars(JSContext *cx, const jsc
*/
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);
+js_AtomizePrimitiveValue(JSContext *cx, jsboxedword w, JSAtom **atomp);
#ifdef DEBUG
extern JS_FRIEND_API(void)
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
* the list and map->vector must point to pre-allocated memory.
*/
extern void
js_InitAtomMap(JSContext *cx, JSAtomMap *map, JSAtomList *al);
-JS_END_EXTERN_C
+namespace js {
+
+Value
+IdToValue(jsid id);
+
+bool
+ValueToId(JSContext *cx, const Value &v, jsid *idp);
+
+} /* namespace js */
#endif /* jsatom_h___ */
--- a/js/src/jsatominlines.h
+++ b/js/src/jsatominlines.h
@@ -41,55 +41,103 @@
#define jsatominlines_h___
#include "jsatom.h"
#include "jsnum.h"
/*
* 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;
/*
* Optimize for the common case where v is an already-atomized string. The
* comment in jsstr.h before JSString::flatSetAtomized explains why this is
* thread-safe. The extra rooting via lastAtom (which would otherwise be
* 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.asString();
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_Int32ToId(JSContext* cx, int32 index, jsid* id)
{
- if (INT_FITS_IN_JSVAL(index)) {
+ if (INT32_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::Value(str), id);
+}
+
+inline bool
+js_InternNonIntElementId(JSContext *cx, JSObject *obj, const js::Value &idval,
+ jsid *idp)
+{
+ JS_ASSERT_IF(idval.isInt32(), !INT32_FITS_IN_JSID(idval.asInt32()));
+
+#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_IF(idval.isInt32(), !INT32_FITS_IN_JSID(idval.asInt32()));
+
+#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;
}
#endif /* jsatominlines_h___ */
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -32,16 +32,18 @@
* 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 ***** */
+#define __STDC_LIMIT_MACROS
+
/*
* JS boolean implementation.
*/
#include "jstypes.h"
#include "jsstdint.h"
#include "jsutil.h" /* Added by JSIFY */
#include "jsapi.h"
#include "jsatom.h"
@@ -49,116 +51,112 @@
#include "jscntxt.h"
#include "jsversion.h"
#include "jslock.h"
#include "jsnum.h"
#include "jsobj.h"
#include "jsstr.h"
#include "jsvector.h"
+#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));
+using namespace js;
-JSClass js_BooleanClass = {
+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
};
#if JS_HAS_TOSOURCE
#include "jsprf.h"
static JSBool
-bool_toSource(JSContext *cx, uintN argc, jsval *vp)
+bool_toSource(JSContext *cx, uintN argc, Value *vp)
{
- jsval v;
+ Value v;
char buf[32];
JSString *str;
if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &v))
return JS_FALSE;
- JS_ASSERT(JSVAL_IS_BOOLEAN(v));
+ JS_ASSERT(v.isBoolean());
JS_snprintf(buf, sizeof buf, "(new %s(%s))",
js_BooleanClass.name,
- JS_BOOLEAN_STR(JSVAL_TO_BOOLEAN(v)));
+ JS_BOOLEAN_STR(v.asBoolean()));
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;
+ Value v;
JSAtom *atom;
JSString *str;
if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &v))
return JS_FALSE;
- JS_ASSERT(JSVAL_IS_BOOLEAN(v));
- atom = cx->runtime->atomState.booleanAtoms[JSVAL_TO_BOOLEAN(v) ? 1 : 0];
+ JS_ASSERT(v.isBoolean());
+ atom = cx->runtime->atomState.booleanAtoms[v.asBoolean() ? 1 : 0];
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);
}
static JSFunctionSpec boolean_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, bool_toSource, 0, JSFUN_THISP_BOOLEAN),
#endif
JS_FN(js_toString_str, bool_toString, 0, JSFUN_THISP_BOOLEAN),
JS_FN(js_valueOf_str, bool_valueOf, 0, JSFUN_THISP_BOOLEAN),
JS_FN(js_toJSON_str, bool_valueOf, 0, JSFUN_THISP_BOOLEAN),
JS_FS_END
};
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;
+ rval->copy(bval);
else
- obj->fslots[JSSLOT_PRIMITIVE_THIS] = bval;
+ obj->fslots[JSSLOT_PRIMITIVE_THIS].copy(bval);
return true;
}
JSObject *
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->fslots[JSSLOT_PRIMITIVE_THIS] = JSVAL_FALSE;
+ proto->fslots[JSSLOT_PRIMITIVE_THIS].setBoolean(false);
return proto;
}
JSString *
js_BooleanToString(JSContext *cx, JSBool b)
{
return ATOM_TO_STRING(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]);
}
@@ -166,27 +164,27 @@ js_BooleanToString(JSContext *cx, JSBool
/* This function implements E-262-3 section 9.8, toString. */
JSBool
js_BooleanToCharBuffer(JSContext *cx, JSBool b, JSCharBuffer &cb)
{
return b ? js_AppendLiteral(cb, "true") : js_AppendLiteral(cb, "false");
}
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.asString()->length() != 0;
+ if (v.isInt32())
+ return v.asInt32() != 0;
+ if (v.isDouble()) {
jsdouble d;
- d = *JSVAL_TO_DOUBLE(v);
+ d = v.asDouble();
return !JSDOUBLE_IS_NaN(d) && d != 0;
}
- JS_ASSERT(JSVAL_IS_BOOLEAN(v));
- return JSVAL_TO_BOOLEAN(v);
+ JS_ASSERT(v.isBoolean());
+ return v.asBoolean();
}
--- a/js/src/jsbool.h
+++ b/js/src/jsbool.h
@@ -40,45 +40,23 @@
#ifndef jsbool_h___
#define jsbool_h___
/*
* JS boolean interface.
*/
#include "jsapi.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;
extern JSObject *
js_InitBooleanClass(JSContext *cx, JSObject *obj);
extern JSString *
js_BooleanToString(JSContext *cx, JSBool b);
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___ */
--- a/js/src/jsbuiltins.h
+++ b/js/src/jsbuiltins.h
@@ -217,17 +217,17 @@ struct ClosureVarInfo;
#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_CONSTRUCTOR_RETRY _JS_CTYPE(JSObject *, _JS_PTR, --, --, FAIL_NULL | \
JSTN_CONSTRUCTOR)
#define _JS_CTYPE_REGEXP _JS_CTYPE(JSObject *, _JS_PTR, "","r", INFALLIBLE)
#define _JS_CTYPE_SCOPEPROP _JS_CTYPE(JSScopeProperty *, _JS_PTR, --, --, INFALLIBLE)
#define _JS_CTYPE_INTERPSTATE _JS_CTYPE(InterpState *, _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)
#define _JS_EXPAND(tokens) tokens
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -33,16 +33,18 @@
* 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 ***** */
+#define __STDC_LIMIT_MACROS
+
/*
* JS execution context.
*/
#include <new>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "jstypes.h"
@@ -99,17 +101,17 @@ MarkLocalRoots(JSTracer *trc, JSLocalRoo
#ifdef DEBUG
JS_REQUIRES_STACK bool
CallStack::contains(const JSStackFrame *fp) const
{
JS_ASSERT(inContext());
JSStackFrame *start;
JSStackFrame *stop;
if (isSuspended()) {
- start = suspendedFrame;
+ start = suspendedFrame();
stop = initialFrame->down;
} else {
start = cx->fp;
stop = cx->activeCallStack()->initialFrame->down;
}
for (JSStackFrame *f = start; f != stop; f = f->down) {
if (f == fp)
return true;
@@ -124,74 +126,74 @@ StackSpace::init()
void *p;
#ifdef XP_WIN
p = VirtualAlloc(NULL, sCapacityBytes, MEM_RESERVE, PAGE_READWRITE);
if (!p)
return false;
void *check = VirtualAlloc(p, sCommitBytes, MEM_COMMIT, PAGE_READWRITE);
if (p != check)
return false;
- base = reinterpret_cast<jsval *>(p);
+ base = reinterpret_cast<Value *>(p);
commitEnd = base + sCommitVals;
end = base + sCapacityVals;
#else
JS_ASSERT(sCapacityBytes % getpagesize() == 0);
p = mmap(NULL, sCapacityBytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED)
return false;
- base = reinterpret_cast<jsval *>(p);
+ base = reinterpret_cast<Value *>(p);
end = base + sCapacityVals;
#endif
return true;
}
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);
#else
munmap(base, sCapacityBytes);
#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) % sCommitVals == 0);
do {
newCommit += sCommitVals;
JS_ASSERT((end - newCommit) >= 0);
} while(newCommit < request);
/* Cast safe because sCapacityBytes is small. */
- int32 size = (int32)(newCommit - commitEnd) * sizeof(jsval);
+ int32 size = (int32)(newCommit - commitEnd) * sizeof(Value);
if (!VirtualAlloc(commitEnd, size, MEM_COMMIT, PAGE_READWRITE))
return false;
commitEnd = newCommit;
return true;
}
#endif
JS_REQUIRES_STACK void
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()) {
/* Mark slots/args trailing off callstack. */
JS_ASSERT(end == cs->getInitialArgEnd());
TraceValues(trc, cs->getInitialArgBegin(), cs->getInitialArgEnd(), "stack");
} else {
/* This may be the only pointer to the initialVarObj. */
if (cs->getInitialVarObj())
@@ -214,24 +216,24 @@ StackSpace::mark(JSTracer *trc)
}
end = cs->previousCallStackEnd();
}
}
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 = ValuesPerCallStack + vplen;
if (!ensureSpace(cx, start, nvals))
return false;
- jsval *vp = start + ValuesPerCallStack;
- jsval *vpend = vp + vplen;
- memset(vp, 0, vplen * sizeof(jsval)); /* Init so GC-safe on exit. */
+ Value *vp = start + ValuesPerCallStack;
+ Value *vpend = vp + vplen;
+ memset(vp, 0, vplen * sizeof(*vp)); /* Init so GC-safe on exit. */
CallStack *cs = new(start) CallStack;
cs->setInitialArgEnd(vpend);
cs->setPreviousInThread(currentCallStack);
currentCallStack = cs;
ag.cx = cx;
ag.cs = cs;
@@ -259,26 +261,26 @@ InvokeFrameGuard::InvokeFrameGuard()
*/
bool
StackSpace::getInvokeFrame(JSContext *cx, const InvokeArgsGuard &ag,
uintN nmissing, uintN nslots,
InvokeFrameGuard &fg) const
{
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 + ValuesPerStackFrame + nslots;
if (!ensureSpace(cx, start, nvals))
return false;
fg.fp = reinterpret_cast<JSStackFrame *>(start + nmissing);
return true;
}
JS_ASSERT(isCurrent(cx) && currentCallStack->isActive());
- jsval *start = cx->regs->sp;
+ Value *start = cx->regs->sp;
ptrdiff_t nvals = nmissing + ValuesPerCallStack + ValuesPerStackFrame + nslots;
if (!ensureSpace(cx, start, nvals))
return false;
fg.cs = new(start + nmissing) CallStack;
fg.fp = reinterpret_cast<JSStackFrame *>(fg.cs + 1);
return true;
}
@@ -337,17 +339,17 @@ ExecuteFrameGuard::~ExecuteFrameGuard()
* To maintain a 1 to 0..1 relationship between callstacks and js_Interpret
* activations, we push a callstack even if it wasn't otherwise necessary.
*/
JS_REQUIRES_STACK bool
StackSpace::getExecuteFrame(JSContext *cx, JSStackFrame *down,
uintN vplen, uintN nslots,
ExecuteFrameGuard &fg) const
{
- jsval *start = firstUnused();
+ Value *start = firstUnused();
ptrdiff_t nvals = ValuesPerCallStack + vplen + ValuesPerStackFrame + nslots;
if (!ensureSpace(cx, start, nvals))
return false;
fg.cs = new(start) CallStack;
fg.vp = start + ValuesPerCallStack;
fg.fp = reinterpret_cast<JSStackFrame *>(fg.vp + vplen);
fg.down = down;
@@ -373,17 +375,17 @@ StackSpace::popExecuteFrame(JSContext *c
JS_ASSERT(isCurrent(cx) && cx->hasActiveCallStack());
cx->popCallStackAndFrame();
currentCallStack = currentCallStack->getPreviousInThread();
}
JS_REQUIRES_STACK void
StackSpace::getSynthesizedSlowNativeFrame(JSContext *cx, CallStack *&cs, JSStackFrame *&fp)
{
- jsval *start = firstUnused();
+ Value *start = firstUnused();
JS_ASSERT(size_t(end - start) >= ValuesPerCallStack + ValuesPerStackFrame);
cs = new(start) CallStack;
fp = reinterpret_cast<JSStackFrame *>(cs + 1);
}
JS_REQUIRES_STACK void
StackSpace::pushSynthesizedSlowNativeFrame(JSContext *cx, CallStack *cs, JSStackFrame *fp,
JSFrameRegs ®s)
@@ -407,26 +409,26 @@ StackSpace::popSynthesizedSlowNativeFram
currentCallStack = currentCallStack->getPreviousInThread();
}
/*
* When a pair of down-linked stack frames are in the same callstack, the
* 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;
}
JS_REQUIRES_STACK
FrameRegsIter::FrameRegsIter(JSContext *cx)
{
curcs = cx->getCurrentCallStack();
@@ -1346,17 +1348,17 @@ js_WaitForGC(JSRuntime *rt)
#endif
static JSDHashNumber
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)) >> JSBOXEDWORD_TAGBITS) ^ key->id;
}
JS_PUBLIC_API(JSBool)
resolving_MatchEntry(JSDHashTable *table,
const JSDHashEntryHdr *hdr,
const void *ptr)
{
const JSResolvingEntry *entry = (const JSResolvingEntry *)hdr;
@@ -1463,25 +1465,25 @@ js_EnterLocalRootScope(JSContext *cx)
lrs->rootCount = 0;
lrs->topChunk = &lrs->firstChunk;
lrs->firstChunk.down = NULL;
td->gcFreeLists.moveTo(&lrs->gcFreeLists);
td->localRootStack = lrs;
}
/* Push lrs->scopeMark to save it for restore when leaving. */
- int mark = js_PushLocalRoot(cx, lrs, INT_TO_JSVAL(lrs->scopeMark));
+ int mark = js_PushLocalRoot(cx, lrs, (void *)lrs->scopeMark);
if (mark < 0)
return JS_FALSE;
lrs->scopeMark = (uint32) mark;
return true;
}
void
-js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
+js_LeaveLocalRootScopeWithResult(JSContext *cx, const Value &rval)
{
JSLocalRootStack *lrs;
uint32 mark, m, n;
JSLocalRootChunk *lrc;
/* Defend against buggy native callers. */
lrs = JS_THREAD_DATA(cx)->localRootStack;
JS_ASSERT(lrs && lrs->rootCount != 0);
@@ -1507,28 +1509,28 @@ js_LeaveLocalRootScopeWithResult(JSConte
/*
* Pop the scope, restoring lrs->scopeMark. If rval is a GC-thing, push
* it on the caller's scope, or store it in lastInternalResult if we are
* leaving the outermost scope. We don't need to allocate a new lrc
* because we can overwrite the old mark's slot with rval.
*/
lrc = lrs->topChunk;
m = mark & JSLRS_CHUNK_MASK;
- lrs->scopeMark = (uint32) JSVAL_TO_INT(lrc->roots[m]);
- if (JSVAL_IS_GCTHING(rval) && !JSVAL_IS_NULL(rval)) {
+ lrs->scopeMark = (uint32) lrc->roots[m];
+ if (rval.isGCThing()) {
if (mark == 0) {
- cx->weakRoots.lastInternalResult = rval;
+ cx->weakRoots.lastInternalResult = rval.asGCThing();
} else {
/*
* Increment m to avoid the "else if (m == 0)" case below. If
* rval is not a GC-thing, that case would take care of freeing
* any chunk that contained only the old mark. Since rval *is*
* a GC-thing here, we want to reuse that old mark's slot.
*/
- lrc->roots[m++] = rval;
+ lrc->roots[m++] = rval.asGCThing();
++mark;
}
}
lrs->rootCount = (uint32) mark;
/*
* Free the stack eagerly, risking malloc churn. The alternative would
* require an lrs->entryCount member, maintained by Enter and Leave, and
@@ -1546,76 +1548,71 @@ js_LeaveLocalRootScopeWithResult(JSConte
js_free(lrs);
} else if (m == 0) {
lrs->topChunk = lrc->down;
js_free(lrc);
}
}
void
-js_ForgetLocalRoot(JSContext *cx, jsval v)
+js_ForgetLocalRoot(JSContext *cx, void *thing)
{
- JSLocalRootStack *lrs;
- uint32 i, j, m, n, mark;
- JSLocalRootChunk *lrc, *lrc2;
- jsval top;
-
- lrs = JS_THREAD_DATA(cx)->localRootStack;
+ JSLocalRootStack *lrs = JS_THREAD_DATA(cx)->localRootStack;
JS_ASSERT(lrs && lrs->rootCount);
if (!lrs || lrs->rootCount == 0)
return;
/* Prepare to pop the top-most value from the stack. */
- n = lrs->rootCount - 1;
- m = n & JSLRS_CHUNK_MASK;
- lrc = lrs->topChunk;
- top = lrc->roots[m];
+ uint32 n = lrs->rootCount - 1;
+ uint32 m = n & JSLRS_CHUNK_MASK;
+ JSLocalRootChunk *lrc = lrs->topChunk;
+ void *top = lrc->roots[m];
/* Be paranoid about calls on an empty scope. */
- mark = lrs->scopeMark;
+ uint32 mark = lrs->scopeMark;
JS_ASSERT(mark < n);
if (mark >= n)
return;
- /* If v was not the last root pushed in the top scope, find it. */
- if (top != v) {
- /* Search downward in case v was recently pushed. */
- i = n;
- j = m;
- lrc2 = lrc;
+ /* If thing was not the last root pushed in the top scope, find it. */
+ if (top != thing) {
+ /* Search downward in case thing was recently pushed. */
+ uint32 i = n;
+ uint32 j = m;
+ JSLocalRootChunk *lrc2 = lrc;
while (--i > mark) {
if (j == 0)
lrc2 = lrc2->down;
j = i & JSLRS_CHUNK_MASK;
- if (lrc2->roots[j] == v)
+ if (lrc2->roots[j] == thing)
break;
}
/* If we didn't find v in this scope, assert and bail out. */
JS_ASSERT(i != mark);
if (i == mark)
return;
/* Swap top and v so common tail code can pop v. */
lrc2->roots[j] = top;
}
/* Pop the last value from the stack. */
- lrc->roots[m] = JSVAL_NULL;
+ lrc->roots[m] = NULL;
lrs->rootCount = n;
if (m == 0) {
JS_ASSERT(n != 0);
JS_ASSERT(lrc != &lrs->firstChunk);
lrs->topChunk = lrc->down;
cx->free(lrc);
}
}
int
-js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v)
+js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, void *thing)
{
uint32 n, m;
JSLocalRootChunk *lrc;
n = lrs->rootCount;
m = n & JSLRS_CHUNK_MASK;
if (n == 0 || m != 0) {
/*
@@ -1638,45 +1635,42 @@ js_PushLocalRoot(JSContext *cx, JSLocalR
if (!lrc) {
js_ReportOutOfMemory(cx);
return -1;
}
lrc->down = lrs->topChunk;
lrs->topChunk = lrc;
}
lrs->rootCount = n + 1;
- lrc->roots[m] = v;
+ lrc->roots[m] = thing;
return (int) n;
}
static void
MarkLocalRoots(JSTracer *trc, JSLocalRootStack *lrs)
{
- uint32 n, m, mark;
- JSLocalRootChunk *lrc;
- jsval v;
-
- n = lrs->rootCount;
+ uint32 n = lrs->rootCount;
if (n == 0)
return;
- mark = lrs->scopeMark;
- lrc = lrs->topChunk;
+ uint32 mark = lrs->scopeMark;
+ JSLocalRootChunk *lrc = lrs->topChunk;
do {
+ uint32 m;
while (--n > mark) {
m = n & JSLRS_CHUNK_MASK;
- v = lrc->roots[m];
- JS_ASSERT(JSVAL_IS_GCTHING(v) && v != JSVAL_NULL);
+ void *thing = lrc->roots[m];
+ JS_ASSERT(thing != NULL);
JS_SET_TRACING_INDEX(trc, "local_root", n);
- js_CallValueTracerIfGCThing(trc, v);
+ CallGCMarkerForGCThing(trc, thing);
if (m == 0)
lrc = lrc->down;
}
m = n & JSLRS_CHUNK_MASK;
- mark = JSVAL_TO_INT(lrc->roots[m]);
+ mark = (uint32)lrc->roots[m];
if (m == 0)
lrc = lrc->down;
} while (n != 0);
JS_ASSERT(!lrc);
}
static void
ReportError(JSContext *cx, const char *message, JSErrorReport *reportp,
@@ -2109,82 +2103,83 @@ js_ReportErrorAgain(JSContext *cx, const
void
js_ReportIsNotDefined(JSContext *cx, const char *name)
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, 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 = js_DecompileValueGenerator(cx, spindex, Jsvalify(&v), fallback);
if (!bytes)
return JS_FALSE;
if (strcmp(bytes, js_undefined_str) == 0 ||
strcmp(bytes, js_null_str) == 0) {
ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
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,
js_null_str, NULL);
}
cx->free(bytes);
return ok;
}
void
-js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg)
+js_ReportMissingArg(JSContext *cx, const Value &v, uintN arg)
{
char argbuf[11];
char *bytes;
JSAtom *atom;
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,
+ if (v.isFunObj()) {
+ atom = GET_FUNCTION_PRIVATE(cx, &v.asFunObj())->atom;
+ bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK,
+ Jsvalify(&v),
ATOM_TO_STRING(atom));
if (!bytes)
return;
}
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_MISSING_FUN_ARG, argbuf,
bytes ? bytes : "");
cx->free(bytes);
}
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;
JSBool ok;
JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
- bytes = js_DecompileValueGenerator(cx, spindex, v, fallback);
+ bytes = js_DecompileValueGenerator(cx, spindex, Jsvalify(&v), fallback);
if (!bytes)
return JS_FALSE;
ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
NULL, errorNumber, bytes, arg1, arg2);
cx->free(bytes);
return ok;
}
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -280,72 +280,81 @@ class CallStack
CallStack *previousInContext;
/* Link for StackSpace callstack stack mentioned in StackSpace comment. */
CallStack *previousInThread;
/* The first frame executed in this callstack. null iff cx is null */
JSStackFrame *initialFrame;
- /* If this callstack is suspended, the top of the callstack. */
- JSStackFrame *suspendedFrame;
+ /*
+ * Two values packed together to get sizeof(Value) alignment.
+ * suspendedFrame: if this callstack is suspended, the top of the callstack.
+ * saved: if this callstack is suspended, whether it is also saved.
+ */
+ AlignedPtrAndFlag<JSStackFrame> suspendedFrameAndSaved;
/* If this callstack is suspended, |cx->regs| when it was suspended. */
JSFrameRegs *suspendedRegs;
- /* This callstack was suspended by JS_SaveFrameChain. */
- bool saved;
-
/* End of arguments before the first frame. See StackSpace comment. */
- jsval *initialArgEnd;
+ js::Value *initialArgEnd;
/* The varobj on entry to initialFrame. */
JSObject *initialVarObj;
+ JSStackFrame *suspendedFrame() const {
+ return suspendedFrameAndSaved.ptr();
+ }
+
+ bool saved() const {
+ return suspendedFrameAndSaved.flag();
+ }
+
public:
CallStack()
: cx(NULL), previousInContext(NULL), previousInThread(NULL),
- initialFrame(NULL), suspendedFrame(NULL), saved(false),
+ initialFrame(NULL), suspendedFrameAndSaved(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);
}
/* The three mutually exclusive states of a callstack */
bool inContext() const {
JS_ASSERT(!!cx == !!initialFrame);
- JS_ASSERT_IF(!initialFrame, !suspendedFrame && !saved);
+ JS_ASSERT_IF(!initialFrame, !suspendedFrame() && !saved());
return cx;
}
bool isActive() const {
- JS_ASSERT_IF(suspendedFrame, inContext());
- return initialFrame && !suspendedFrame;
+ JS_ASSERT_IF(suspendedFrame(), inContext());
+ return initialFrame && !suspendedFrame();
}
bool isSuspended() const {
- JS_ASSERT_IF(!suspendedFrame, !saved);
- JS_ASSERT_IF(suspendedFrame, inContext());
- return suspendedFrame;
+ JS_ASSERT_IF(!suspendedFrame(), !saved());
+ JS_ASSERT_IF(suspendedFrame(), inContext());
+ return !!suspendedFrame();
}
/* Substate of suspended, queryable in any state. */
bool isSaved() const {
- JS_ASSERT_IF(saved, isSuspended());
- return saved;
+ JS_ASSERT_IF(saved(), isSuspended());
+ return saved();
}
/* Transitioning between inContext <--> isActive */
void joinContext(JSContext *cx, JSStackFrame *f) {
JS_ASSERT(!inContext());
this->cx = cx;
initialFrame = f;
@@ -360,47 +369,47 @@ class CallStack
JSContext *maybeContext() const {
return cx;
}
/* Transitioning between isActive <--> isSuspended */
void suspend(JSStackFrame *fp, JSFrameRegs *regs) {
JS_ASSERT(fp && isActive() && contains(fp));
- suspendedFrame = fp;
+ suspendedFrameAndSaved.set(fp, false);
suspendedRegs = regs;
}
void resume() {
- JS_ASSERT(suspendedFrame);
- suspendedFrame = NULL;
+ JS_ASSERT(suspendedFrame());
+ suspendedFrameAndSaved.set(NULL, false);
}
/* When isSuspended, transitioning isSaved <--> !isSaved */
void save(JSStackFrame *fp, JSFrameRegs *regs) {
- JS_ASSERT(!saved);
+ JS_ASSERT(!saved());
suspend(fp, regs);
- saved = true;
+ suspendedFrameAndSaved.setFlag();
}
void restore() {
- JS_ASSERT(saved);
- saved = false;
+ JS_ASSERT(saved());
+ suspendedFrameAndSaved.unsetFlag();
resume();
}
/* 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;
}
/* Data available when inContext */
JSStackFrame *getInitialFrame() const {
JS_ASSERT(inContext());
@@ -408,25 +417,25 @@ class CallStack
}
inline JSStackFrame *getCurrentFrame() const;
/* Data available when isSuspended. */
JSStackFrame *getSuspendedFrame() const {
JS_ASSERT(isSuspended());
- return suspendedFrame;
+ return suspendedFrame();
}
JSFrameRegs *getSuspendedRegs() const {
JS_ASSERT(isSuspended());
return suspendedRegs;
}
- jsval *getSuspendedSP() const {
+ js::Value *getSuspendedSP() const {
JS_ASSERT(isSuspended());
return suspendedRegs->sp;
}
/* JSContext / js::StackSpace bookkeeping. */
void setPreviousInContext(CallStack *cs) {
previousInContext = cs;
@@ -455,36 +464,36 @@ class CallStack
}
#ifdef DEBUG
JS_REQUIRES_STACK bool contains(const JSStackFrame *fp) const;
#endif
};
-JS_STATIC_ASSERT(sizeof(CallStack) % sizeof(jsval) == 0);
-static const size_t ValuesPerCallStack = sizeof(CallStack) / sizeof(jsval);
+JS_STATIC_ASSERT(sizeof(CallStack) % sizeof(Value) == 0);
+static const size_t ValuesPerCallStack = sizeof(CallStack) / sizeof(Value);
/*
* 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.
*/
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; }
};
/* See StackSpace::pushInvokeFrame. */
class InvokeFrameGuard
{
friend class StackSpace;
JSContext *cx; /* null implies nothing pushed */
@@ -497,23 +506,23 @@ class InvokeFrameGuard
};
/* See StackSpace::pushExecuteFrame. */
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; }
};
/*
* Thread stack layout
*
* Each JSThreadData has one associated StackSpace object which allocates all
* callstacks for the thread. StackSpace performs all such allocations in a
@@ -532,17 +541,17 @@ class ExecuteFrameGuard
* initial frame current frame ------. if regs,
* .------------. | | regs->sp
* | V V V
* |callstack| slots |frame| slots |frame| slots |frame| slots|
* | ^ | ^ |
* ? <----' `----------' `----------'
*
* Moreover, the bytes between a callstack and its first frame and between two
- * adjacent frames in a callstack are GC-able jsvals. If the current frame's
+ * adjacent frames in a callstack are GC-able Values. If the current frame's
* regs pointer is null (e.g., native frame), there are no final slots.
*
* 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
* by subsequent initial frame pushes/pops...).
*
* initialArgEnd
* .---------.
@@ -565,56 +574,56 @@ class ExecuteFrameGuard
* Since different contexts can arbitrarily interleave execution in a single
* thread, these stacks are different enough that a callstack needs both
* "previousInThread" and "previousInContext". (Not completely different; there
* is an order-preserving injection from each context's callstack-ordering to
* that of the context's thread.)
*/
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;
JS_REQUIRES_STACK void popExecuteFrame(JSContext *cx);
/* Return a pointer to the first unused slot. */
JS_REQUIRES_STACK
- inline jsval *firstUnused() const;
+ inline Value *firstUnused() const;
#ifdef DEBUG
inline bool isCurrent(JSContext *cx) const;
CallStack *getCurrentCallStack() const { return currentCallStack; }
#endif
/*
* Return whether nvals can be allocated from the top of the stack.
* 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 sCapacityVals = 512 * 1024;
- static const size_t sCapacityBytes = sCapacityVals * sizeof(jsval);
+ static const size_t sCapacityBytes = sCapacityVals * sizeof(Value);
static const size_t sCommitVals = 16 * 1024;
- static const size_t sCommitBytes = sCommitVals * sizeof(jsval);
+ static const size_t sCommitBytes = sCommitVals * sizeof(Value);
JS_STATIC_ASSERT(sCapacityVals % sCommitVals == 0);
/* Kept as a member of JSThreadData; cannot use constructor/destructor. */
bool init();
void finish();
#ifdef DEBUG
@@ -689,17 +698,17 @@ class StackSpace
void pushExecuteFrame(JSContext *cx, ExecuteFrameGuard &fg,
JSFrameRegs ®s, JSObject *initialVarObj);
/*
* Since RAII cannot be used for inline frames, callers must manually
* call pushInlineFrame/popInlineFrame.
*/
JS_REQUIRES_STACK
- inline JSStackFrame *getInlineFrame(JSContext *cx, jsval *sp,
+ inline JSStackFrame *getInlineFrame(JSContext *cx, Value *sp,
uintN nmissing, uintN nslots) const;
JS_REQUIRES_STACK
void pushInlineFrame(JSContext *cx, JSStackFrame *fp, jsbytecode *pc,
JSStackFrame *newfp);
JS_REQUIRES_STACK
inline void popInlineFrame(JSContext *cx, JSStackFrame *up, JSStackFrame *down);
@@ -732,27 +741,27 @@ class StackSpace
* Usage:
* for (FrameRegsIter i(cx); !i.done(); ++i)
* ... i.fp() ... i.sp() ... i.pc()
*/
class FrameRegsIter
{
CallStack *curcs;
JSStackFrame *curfp;
- jsval *cursp;
+ Value *cursp;
jsbytecode *curpc;
public:
JS_REQUIRES_STACK FrameRegsIter(JSContext *cx);
bool done() const { return curfp == NULL; }
FrameRegsIter &operator++();
JSStackFrame *fp() const { return curfp; }
- jsval *sp() const { return cursp; }
+ Value *sp() const { return cursp; }
jsbytecode *pc() const { return curpc; }
};
/* Holds the number of recording attemps for an address. */
typedef HashMap<jsbytecode*,
size_t,
DefaultHasher<jsbytecode*>,
SystemAllocPolicy> RecordAttemptMap;
@@ -918,17 +927,17 @@ struct JSFunctionMeter {
struct JSLocalRootChunk;
#define JSLRS_CHUNK_SHIFT 8
#define JSLRS_CHUNK_SIZE JS_BIT(JSLRS_CHUNK_SHIFT)
#define JSLRS_CHUNK_MASK JS_BITMASK(JSLRS_CHUNK_SHIFT)
struct JSLocalRootChunk {
- jsval roots[JSLRS_CHUNK_SIZE];
+ void *roots[JSLRS_CHUNK_SIZE];
JSLocalRootChunk *down;
};
struct JSLocalRootStack {
uint32 scopeMark;
uint32 rootCount;
JSLocalRootChunk *topChunk;
JSLocalRootChunk firstChunk;
@@ -1136,22 +1145,34 @@ struct JSClassProtoCache {
GlobalAndProto entries[JSProto_LIMIT - JSProto_Object];
#ifdef __GNUC__
# pragma GCC visibility push(default)
#endif
friend JSBool js_GetClassPrototype(JSContext *cx, JSObject *scope,
JSProtoKey protoKey, JSObject **protop,
- JSClass *clasp);
+ js::Class *clasp);
#ifdef __GNUC__
# pragma GCC visibility pop
#endif
};
+struct JSRootInfo {
+ JSRootInfo() {}
+ JSRootInfo(const char *name, JSGCRootType type) : name(name), type(type) {}
+ const char *name;
+ JSGCRootType type;
+};
+
+typedef js::HashMap<void *,
+ JSRootInfo,
+ js::DefaultHasher<void *>,
+ js::SystemAllocPolicy> JSRootedValueMap;
+
struct JSRuntime {
/* Runtime state, synchronized by the stateChange/gcLock condvar/lock. */
JSRuntimeState state;
/* Context create/destroy callback. */
JSContextCallback cxCallback;
/*
@@ -1167,17 +1188,17 @@ struct JSRuntime {
* trace-JITted code that reads it.
*/
uint32 protoHazardShape;
/* Garbage collector state, used by jsgc.c. */
JSGCChunkInfo *gcChunkList;
JSGCArenaList gcArenaList[FINALIZE_LIMIT];
JSGCDoubleArenaList gcDoubleArenaList;
- JSDHashTable gcRootsHash;
+ JSRootedValueMap gcRootsHash;
JSDHashTable gcLocksHash;
jsrefcount gcKeepAtoms;
size_t gcBytes;
size_t gcLastBytes;
size_t gcMaxBytes;
size_t gcMaxMallocBytes;
uint32 gcEmptyArenaPoolLifespan;
uint32 gcLevel;
@@ -1244,19 +1265,19 @@ struct JSRuntime {
* Used to serialize cycle checks when setting __proto__ or __parent__ by
* requesting the GC handle the required cycle detection. If the GC hasn't
* been poked, it won't scan for garbage. This member is protected by
* rt->gcLock.
*/
JSSetSlotRequest *setSlotRequests;
/* 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;
JSString *emptyString;
/*
* Builtin functions, lazily created and held for use by the trace recorder.
*
@@ -1635,33 +1656,33 @@ struct JSContext
uint32 options; /* see jsapi.h for JSOPTION_* */
/* Locale specific callbacks for string conversion. */
JSLocaleCallbacks *localeCallbacks;
/*
* 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;
/*
* True if generating an error, to prevent runaway recursion.
* NB: generatingError packs with insideGCMarkCallback and throwing below.
*/
JSPackedBool generatingError;
/* Flag to indicate that we run inside gcCallback(cx, JSGC_MARK_END). */
JSPackedBool insideGCMarkCallback;
/* 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;
/* Quota on the size of arenas used to compile and execute scripts. */
size_t scriptStackQuota;
/* Data shared by threads in an address space. */
@@ -1675,17 +1696,17 @@ struct JSContext
* Currently executing frame's regs, set by stack operations.
* |fp != NULL| iff |regs != NULL| (although regs->pc can be NULL)
*/
JS_REQUIRES_STACK
JSFrameRegs *regs;
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) {
this->fp = fp;
}
void setCurrentRegs(JSFrameRegs *regs) {
this->regs = regs;
@@ -2029,18 +2050,18 @@ struct JSContext
void purge();
js::StackSpace &stack() const {
return JS_THREAD_DATA(this)->stackSpace;
}
#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*/) {}
#endif
private:
/*
@@ -2119,17 +2140,17 @@ class AutoGCRooter {
# pragma GCC visibility pop
#endif
protected:
AutoGCRooter * const down;
/*
* 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.
*/
ptrdiff_t tag;
JSContext * const context;
@@ -2166,66 +2187,67 @@ class AutoSaveWeakRoots : private AutoGC
JSWeakRoots savedRoots;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
/* FIXME(bug 332648): Move this into a public header. */
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(v)
+ : 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.copy(v);
+ JS_GUARD_OBJECT_NOTIFIER_INIT;
+ }
AutoValueRooter(JSContext *cx, JSString *str
JS_GUARD_OBJECT_NOTIFIER_PARAM)
- : AutoGCRooter(cx, JSVAL), val(STRING_TO_JSVAL(str))
+ : AutoGCRooter(cx, JSVAL), val(str)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
- AutoValueRooter(JSContext *cx, JSObject *obj
- JS_GUARD_OBJECT_NOTIFIER_PARAM)
- : AutoGCRooter(cx, JSVAL), val(OBJECT_TO_JSVAL(obj))
- {
- JS_GUARD_OBJECT_NOTIFIER_INIT;
- }
-
- void setObject(JSObject *obj) {
- JS_ASSERT(tag == JSVAL);
- val = OBJECT_TO_JSVAL(obj);
- }
+ /*
+ * 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 setString(JSString *str) {
JS_ASSERT(tag == JSVAL);
JS_ASSERT(str);
- val = STRING_TO_JSVAL(str);
+ val.setString(str);
}
- void setDouble(jsdouble *dp) {
+ void setDouble(jsdouble d) {
JS_ASSERT(tag == JSVAL);
- JS_ASSERT(dp);
- val = DOUBLE_TO_JSVAL(dp);
+ JS_ASSERT(d);
+ val.setDouble(d);
}
- jsval value() const {
+ const Value &value() const {
JS_ASSERT(tag == JSVAL);
return val;
}
- jsval *addr() {
+ Value *addr() {
JS_ASSERT(tag == JSVAL);
return &val;
}
friend void AutoGCRooter::trace(JSTracer *trc);
private:
- jsval val;
+ Value val;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoObjectRooter : private AutoGCRooter {
public:
AutoObjectRooter(JSContext *cx, JSObject *obj = NULL
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, OBJECT), obj(obj)
@@ -2249,35 +2271,35 @@ class AutoObjectRooter : private AutoGCR
private:
JSObject *obj;
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)
{
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);
private:
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
class AutoScopePropertyRooter : private AutoGCRooter {
@@ -2380,47 +2402,47 @@ class AutoIdArray : private AutoGCRooter
};
/* The auto-root for enumeration object and its state. */
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
obj->enumerate(context, JSENUMERATE_DESTROY, &stateValue, 0);
JS_ASSERT(ok);
}
}
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) {
JS_CALL_OBJECT_TRACER(trc, obj, "js::AutoEnumStateRooter.obj");
js_MarkEnumeratorState(trc, obj, stateValue);
}
JSObject * const obj;
private:
- jsval stateValue;
+ Value stateValue;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
#ifdef JS_HAS_XML_SUPPORT
class AutoXMLRooter : private AutoGCRooter {
public:
AutoXMLRooter(JSContext *cx, JSXML *xml)
: AutoGCRooter(cx, XML), xml(xml)
@@ -2619,48 +2641,43 @@ js_WaitForGC(JSRuntime *rt);
#else /* !JS_THREADSAFE */
# define js_WaitForGC(rt) ((void) 0)
#endif
/*
- * JSClass.resolve and watchpoint recursion damping machinery.
+ * Class.resolve and watchpoint recursion damping machinery.
*/
extern JSBool
js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
JSResolvingEntry **entryp);
extern void
js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
JSResolvingEntry *entry, uint32 generation);
/*
* Local root set management.
- *
- * NB: the jsval parameters below may be properly tagged jsvals, or GC-thing
- * pointers cast to (jsval). This relies on JSObject's tag being zero, but
- * on the up side it lets us push int-jsval-encoded scopeMark values on the
- * local root stack.
*/
extern JSBool
js_EnterLocalRootScope(JSContext *cx);
#define js_LeaveLocalRootScope(cx) \
- js_LeaveLocalRootScopeWithResult(cx, JSVAL_NULL)
+ js_LeaveLocalRootScopeWithResult(cx, sNullValue)
extern void
-js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval);
+js_LeaveLocalRootScopeWithResult(JSContext *cx, const js::Value &rval);
extern void
-js_ForgetLocalRoot(JSContext *cx, jsval v);
+js_ForgetLocalRoot(JSContext *cx, void *thing);
extern int
-js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v);
+js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, void *thing);
/*
* Report an exception, which is currently realized as a printf-style format
* string and its arguments.
*/
typedef enum JSErrNum {
#define MSG_DEF(name, number, count, exception, format) \
name = number,
@@ -2722,30 +2739,30 @@ js_ReportErrorAgain(JSContext *cx, const
extern void
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
* the first argument for the error message. If the error message has less
* then 3 arguments, use null for arg1 or arg2.
*/
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) \
((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
spindex, v, fallback, NULL, NULL))
#define js_ReportValueError2(cx,errorNumber,spindex,v,fallback,arg1) \
((void)js_ReportValueErrorFlags(cx, JSREPORT_ERROR, errorNumber, \
@@ -2820,17 +2837,17 @@ LeaveTrace(JSContext *cx)
if (JS_ON_TRACE(cx))
DeepBail(cx);
#endif
}
static JS_INLINE void
LeaveTraceIfGlobalObject(JSContext *cx, JSObject *obj)
{
- if (!obj->fslots[JSSLOT_PARENT])
+ if (obj->fslots[JSSLOT_PARENT].isNull())
LeaveTrace(cx);
}
static JS_INLINE JSBool
CanLeaveTrace(JSContext *cx)
{
JS_ASSERT(JS_ON_TRACE(cx));
#ifdef JS_TRACER
@@ -2911,43 +2928,43 @@ class AutoValueVector : private AutoGCRo
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: AutoGCRooter(cx, VECTOR), vector(cx)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
}
size_t length() const { return vector.length(); }
- bool push(jsval v) { return vector.append(v); }
- bool push(JSString *str) { return push(STRING_TO_JSVAL(str)); }
- bool push(JSObject *obj) { return push(OBJECT_TO_JSVAL(obj)); }
- bool push(jsdouble *dp) { return push(DOUBLE_TO_JSVAL(dp)); }
+ bool push(const js::Value &v) { return vector.append(v); }
+ bool push(JSString *str) { return push(str); }
+ bool push(JSObject *obj) { return push(obj); }
+ bool push(jsdouble d) { return push(d); }
void pop() { vector.popBack(); }
bool resize(size_t newLength) {
if (!vector.resize(newLength))
return false;
return true;
}
bool reserve(size_t newLength) {
return vector.reserve(newLength);
}
- jsval &operator[](size_t i) { return vector[i]; }
- jsval operator[](size_t i) const { return vector[i]; }
-
- const jsval *buffer() const { return vector.begin(); }
- jsval *buffer() { return vector.begin(); }
+ const js::Value &operator[](size_t i) { return vector[i]; }
+ const js::Value &operator[](size_t i) const { return vector[i]; }
+
+ const js::Value *buffer() const { return vector.begin(); }
+ const js::Value *buffer() { return vector.begin(); }
friend void AutoGCRooter::trace(JSTracer *trc);
private:
- Vector<jsval, 8> vector;
+ Vector<js::Value, 8> vector;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};
}
#ifdef _MSC_VER
#pragma warning(pop)
#pragma warning(pop)
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -50,17 +50,17 @@ namespace js {
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
CallStack::getCurrentFrame() const
{
JS_ASSERT(inContext());
return isSuspended() ? getSuspendedFrame() : cx->fp;
}
-JS_REQUIRES_STACK inline jsval *
+JS_REQUIRES_STACK inline Value *
StackSpace::firstUnused() const
{
CallStack *ccs = currentCallStack;
if (!ccs)
return base;
if (JSContext *cx = ccs->maybeContext()) {
if (!ccs->isSuspended())
return cx->regs->sp;
@@ -77,17 +77,17 @@ StackSpace::isCurrent(JSContext *cx) con
JS_ASSERT(cx == currentCallStack->maybeContext());
JS_ASSERT(cx->getCurrentCallStack() == currentCallStack);
JS_ASSERT(cx->callStackInSync());
return true;
}
#endif
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
JS_ASSERT(from <= commitEnd);
if (commitEnd - from >= nvals)
return true;
if (end - from < nvals) {
if (maybecx)
@@ -115,24 +115,24 @@ StackSpace::ensureEnoughSpaceToEnterTrac
{
#ifdef XP_WIN
return ensureSpace(NULL, firstUnused(), sMaxJSValsNeededForTrace);
#endif
return end - firstUnused() > sMaxJSValsNeededForTrace;
}
JS_ALWAYS_INLINE void
-StackSpace::popInvokeArgs(JSContext *cx, jsval *vp)
+StackSpace::popInvokeArgs(JSContext *cx, Value *vp)
{
JS_ASSERT(!currentCallStack->inContext());
currentCallStack = currentCallStack->getPreviousInThread();
}
JS_REQUIRES_STACK JS_ALWAYS_INLINE JSStackFrame *
-StackSpace::getInlineFrame(JSContext *cx, jsval *sp,
+StackSpace::getInlineFrame(JSContext *cx, Value *sp,
uintN nmissing, uintN nslots) const
{
JS_ASSERT(isCurrent(cx) && cx->hasActiveCallStack());
JS_ASSERT(cx->regs->sp == sp);
ptrdiff_t nvals = nmissing + ValuesPerStackFrame + nslots;
if (!ensureSpace(cx, sp, nvals))
return NULL;
@@ -177,33 +177,33 @@ StackSpace::popInlineFrame(JSContext *cx
* issues, force InvokeArgsGuard members inline:
*/
JS_ALWAYS_INLINE
InvokeArgsGuard::InvokeArgsGuard()
: cx(NULL), cs(NULL), vp(NULL)
{}
JS_ALWAYS_INLINE
-InvokeArgsGuard::InvokeArgsGuard(jsval *vp, uintN argc)
+InvokeArgsGuard::InvokeArgsGuard(Value *vp, uintN argc)
: cx(NULL), cs(NULL), vp(vp), argc(argc)
{}
JS_ALWAYS_INLINE
InvokeArgsGuard::~InvokeArgsGuard()
{
if (!cs)
return;
JS_ASSERT(cs == cx->stack().getCurrentCallStack());
cx->stack().popInvokeArgs(cx, vp);
}
void
AutoIdArray::trace(JSTracer *trc) {
JS_ASSERT(tag == IDARRAY);
- js::TraceValues(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
+ TraceIds(trc, idArray->length, idArray->vector, "JSAutoIdArray.idArray");
}
class AutoNamespaces : protected AutoGCRooter {
protected:
AutoNamespaces(JSContext *cx) : AutoGCRooter(cx, NAMESPACES) {
}
friend void AutoGCRooter::trace(JSTracer *trc);
@@ -213,17 +213,17 @@ class AutoNamespaces : protected AutoGCR
};
inline void
AutoGCRooter::trace(JSTracer *trc)
{
switch (tag) {
case JSVAL:
JS_SET_TRACING_NAME(trc, "js::AutoValueRooter.val");
- js_CallValueTracerIfGCThing(trc, static_cast<AutoValueRooter *>(this)->val);
+ CallGCMarkerIfGCThing(trc, static_cast<AutoValueRooter *>(this)->val);
return;
case SPROP:
static_cast<AutoScopePropertyRooter *>(this)->sprop->trace(trc);
return;
case WEAKROOTS:
static_cast<AutoSaveWeakRoots *>(this)->savedRoots.mark(trc);
@@ -239,29 +239,32 @@ AutoGCRooter::trace(JSTracer *trc)
return;
case ENUMERATOR:
static_cast<AutoEnumStateRooter *>(this)->trace(trc);
return;
case IDARRAY: {
JSIdArray *ida = static_cast<AutoIdArray *>(this)->idArray;
- TraceValues(trc, ida->length, ida->vector, "js::AutoIdArray.idArray");
+ TraceIds(trc, ida->length, ida->vector, "js::AutoIdArray.idArray");
return;
}
case DESCRIPTORS: {
PropertyDescriptorArray &descriptors =
static_cast<AutoDescriptorArray *>(this)->descriptors;
for (size_t i = 0, len = descriptors.length(); i < len; i++) {
PropertyDescriptor &desc = descriptors[i];
- 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_SET_TRACING_NAME(trc, "PropertyDescriptor::value");
+ CallGCMarkerIfGCThing(trc, desc.value);
+ JS_SET_TRACING_NAME(trc, "PropertyDescriptor::get");
+ CallGCMarkerIfGCThing(trc, desc.get);
+ JS_SET_TRACING_NAME(trc, "PropertyDescriptor::set");
+ CallGCMarkerIfGCThing(trc, desc.set);
js_TraceId(trc, desc.id);
}
return;
}
case NAMESPACES: {
JSXMLArray &array = static_cast<AutoNamespaces *>(this)->array;
TraceObjectVector(trc, reinterpret_cast<JSObject **>(array.vector), array.length);
@@ -271,31 +274,31 @@ AutoGCRooter::trace(JSTracer *trc)
case XML:
js_TraceXML(trc, static_cast<AutoXMLRooter *>(this)->xml);
return;
case OBJECT:
if (JSObject *obj = static_cast<AutoObjectRooter *>(this)->obj) {
JS_SET_TRACING_NAME(trc, "js::AutoObjectRooter.obj");
- js_CallGCMarker(trc, obj, JSTRACE_OBJECT);
+ CallGCMarker(trc, obj, JSTRACE_OBJECT);
}
return;
case ID:
JS_SET_TRACING_NAME(trc, "js::AutoIdRooter.val");
- js_CallValueTracerIfGCThing(trc, static_cast<AutoIdRooter *>(this)->idval);
+ CallGCMarkerIfGCThing(trc, static_cast<AutoIdRooter *>(this)->idval);
return;
case VECTOR: {
- js::Vector<jsval, 8> &vector = static_cast<js::AutoValueVector *>(this)->vector;
- js::TraceValues(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector");
+ Vector<Value, 8> &vector = static_cast<AutoValueVector *>(this)->vector;
+ TraceValues(trc, vector.length(), vector.begin(), "js::AutoValueVector.vector");
return;
}
}
JS_ASSERT(tag >= 0);
TraceValues(trc, tag, static_cast<AutoArrayRooter *>(this)->array, "js::AutoArrayRooter.array");
}
-}
+} /* namespace js */
#endif /* jscntxtinlines_h___ */
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -33,16 +33,19 @@
* 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 ***** */
+
+#define __STDC_LIMIT_MACROS
+
/*
* JS date methods.
*/
/*
* "For example, OS/360 devotes 26 bytes of the permanently
* resident date-turnover routine to the proper handling of
* December 31 on leap years (when it is Day 366). That
@@ -66,16 +69,18 @@
#include "jsbuiltins.h"
#include "jscntxt.h"
#include "jsdate.h"
#include "jsinterp.h"
#include "jsnum.h"
#include "jsobj.h"
#include "jsstr.h"
+#include "jsobjinlines.h"
+
using namespace js;
/*
* The JS 'Date' object is patterned after the Java 'Date' object.
* Here is an script:
*
* today = new Date();
*
@@ -494,22 +499,22 @@ msFromTime(jsdouble t)
* We use the first reseved slot to store UTC time, and the second for caching
* the local time. The initial value of the cache entry is NaN.
*/
const uint32 JSSLOT_UTC_TIME = JSSLOT_PRIVATE;
const uint32 JSSLOT_LOCAL_TIME = JSSLOT_PRIVATE + 1;
const uint32 DATE_RESERVED_SLOTS = 2;
-JSClass js_DateClass = {
+Class js_DateClass = {
js_Date_str,
JSCLASS_HAS_RESERVED_SLOTS(DATE_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
};
/* for use by date_parse */
static const char* wtb[] = {
"am", "pm",
"monday", "tuesday", "wednesday", "thursday", "friday",
@@ -578,26 +583,26 @@ date_msecFromDate(jsdouble year, jsdoubl
result = MakeDate(day, msec_time);
return result;
}
/* compute the time in msec (unclipped) from the given args */
#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];
jsdouble msec_time;
for (loop = 0; loop < MAXARGS; loop++) {
if (loop < argc) {
jsdouble d;
- if (!ValueToNumber(cx, argv[loop], &d))
+ if (!ValueToNumber(cx, &argv[loop], &d))
return JS_FALSE;
/* return NaN if any arg is not finite */
if (!JSDOUBLE_IS_FINITE(d)) {
*rval = js_NaN;
return JS_TRUE;
}
array[loop] = js_DoubleToInteger(d);
} else {
@@ -618,26 +623,27 @@ date_msecFromArgs(JSContext *cx, uintN a
*rval = msec_time;
return JS_TRUE;
}
/*
* 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;
if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time))
return JS_FALSE;
msec_time = TIMECLIP(msec_time);
- return js_NewNumberInRootedValue(cx, msec_time, vp);
+ vp->setDouble(msec_time);
+ return JS_TRUE;
}
/*
* Read and convert decimal digits from s[*i] into *result
* while *i < limit.
*
* Succeed if any digits are converted. Advance *i only
* as digits are consumed.
@@ -1154,414 +1160,433 @@ date_parseString(JSString *str, jsdouble
syntax:
/* syntax error */
*result = 0;
return JS_FALSE;
}
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)) {
- *vp = cx->runtime->NaNValue;
+ vp->setDouble(js_NaN);
return true;
}
result = TIMECLIP(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(result);
+ return true;
}
static inline jsdouble
NowAsMillis()
{
return (jsdouble) (PRMJ_Now() / PRMJ_USEC_PER_MSEC);
}
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
static jsdouble FASTCALL
date_now_tn(JSContext*)
{
return NowAsMillis();
}
#endif
/*
* Get UTC time from the date object. Returns false if the object is not
* 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->fslots[JSSLOT_UTC_TIME]);
+ *dp = obj->fslots[JSSLOT_UTC_TIME].asDouble();
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->fslots[JSSLOT_LOCAL_TIME] = cx->runtime->NaNValue;
- obj->fslots[JSSLOT_UTC_TIME] = cx->runtime->NaNValue;
+ obj->fslots[JSSLOT_LOCAL_TIME].setDouble(js_NaN);
+ obj->fslots[JSSLOT_UTC_TIME].setDouble(js_NaN);
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->fslots[JSSLOT_LOCAL_TIME] = cx->runtime->NaNValue;
- if (!js_NewDoubleInRootedValue(cx, t, &obj->fslots[JSSLOT_UTC_TIME]))
- return false;
+ obj->fslots[JSSLOT_LOCAL_TIME].setDouble(js_NaN);
+ obj->fslots[JSSLOT_UTC_TIME].setDouble(t);
if (vp)
- *vp = obj->fslots[JSSLOT_UTC_TIME];
+ vp->setDouble(t);
return true;
}
/*
* Get the local time, cache it if necessary. If UTC time is not finite
* (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->fslots[JSSLOT_LOCAL_TIME];
- jsdouble result = *JSVAL_TO_DOUBLE(*slotp);
+ Value &slot = obj->fslots[JSSLOT_LOCAL_TIME];
+ jsdouble result = slot.asDouble();
if (JSDOUBLE_IS_NaN(result)) {
- result = *JSVAL_TO_DOUBLE(obj->fslots[JSSLOT_UTC_TIME]);
+ result = obj->fslots[JSSLOT_UTC_TIME].asDouble();
/* if result is NaN, it couldn't be finite. */
if (JSDOUBLE_IS_FINITE(result))
result = LocalTime(result);
- if (!js_NewDoubleInRootedValue(cx, result, slotp))
- return false;
+ slot.setDouble(result);
}
*dp = result;
return true;
}
/*
* 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, ComputeThisObjectFromVp(cx, vp), vp, &result))
+ return JS_FALSE;
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result)) {
result = YearFromTime(result);
/* Follow ECMA-262 to the letter, contrary to IE JScript. */
if (!fullyear)
result -= 1900;
}
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = YearFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = MonthFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = MonthFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = DateFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = DateFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = WeekDay(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = WeekDay(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = HourFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = HourFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = MinFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = MinFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = SecFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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, ComputeThisObjectFromVp(cx, vp), vp, &result))
return JS_FALSE;
if (JSDOUBLE_IS_FINITE(result))
result = msFromTime(result);
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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 = ComputeThisObjectFromVp(cx, vp);
if (!GetUTCTime(cx, obj, vp, &utctime))
return JS_FALSE;
if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime))
return JS_FALSE;
/*
* Return the time zone offset in minutes for the current locale that is
* appropriate for this time. This value would be a constant except for
* daylight savings time.
*/
result = (utctime - localtime) / msPerMinute;
- return js_NewNumberInRootedValue(cx, result, vp);
+ vp->setDouble(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 = ComputeThisObjectFromVp(cx, vp);
+ if (!InstanceOf(cx, obj, &js_DateClass, vp + 2))
return false;
if (argc == 0) {
SetDateToNaN(cx, obj, vp);
return true;
}
jsdouble result;
- if (!ValueToNumber(cx, vp[2], &result))
+ if (!ValueToNumber(cx, &vp[2], &result))
return false;
return SetUTCTime(cx, obj, TIMECLIP(result), 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;
jsdouble lorutime; /* Local or UTC version of *date */
jsdouble msec_time;
jsdouble result;
- obj = JS_THIS_OBJECT(cx, vp);
+ obj = ComputeThisObjectFromVp(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->setDouble(result);
+ return true;
+ }
/*
* Satisfy the ECMA rule that if a function is called with
* fewer arguments than the specified formal arguments, the
* remaining arguments are set to undefined. Seems like all
* the Date.setWhatever functions in ECMA are only varargs
* beyond the first argument; this should be set to undefined
* if it's not given. This means that "d = new Date();
@@ -1572,17 +1597,17 @@ date_makeTime(JSContext *cx, uintN maxar
return true;
}
if (argc > maxargs)
argc = maxargs; /* clamp argc */
JS_ASSERT(argc <= 4);
argv = vp + 2;
for (i = 0; i < argc; i++) {
- if (!ValueToNumber(cx, argv[i], &args[i]))
+ if (!ValueToNumber(cx, &argv[i], &args[i]))
return false;
if (!JSDOUBLE_IS_FINITE(args[i])) {
SetDateToNaN(cx, obj, vp);
return true;
}
args[i] = js_DoubleToInteger(args[i]);
}
@@ -1622,103 +1647,105 @@ date_makeTime(JSContext *cx, uintN maxar
result = UTC(result);
/* fprintf(stderr, "%f\n", result); */
return SetUTCTime(cx, obj, TIMECLIP(result), 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_s