Bug 683361, part 2 - use CallArgs more (r=waldo)
authorLuke Wagner <luke@mozilla.com>
Thu, 08 Sep 2011 21:02:26 -0700
changeset 77741 7061ce46859a1bf9c2d087f817f563f3edcfd291
parent 77740 dbe064b3a6595de93fa7ae6bf6212e1989443ecd
child 77742 3d106932a45fbb3a7bfe3ea479f76157e5d79c05
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewerswaldo
bugs683361
milestone10.0a1
Bug 683361, part 2 - use CallArgs more (r=waldo)
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsbool.cpp
js/src/jscntxtinlines.h
js/src/jsdate.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsfun.h
js/src/jsfuninlines.h
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsregexp.cpp
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/jsweakmap.cpp
js/src/jsxml.cpp
js/src/vm/Debugger.cpp
js/src/vm/Stack-inl.h
js/src/vm/Stack.cpp
js/src/vm/Stack.h
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2908,17 +2908,17 @@ JS_InstanceOf(JSContext *cx, JSObject *o
 #ifdef DEBUG
     if (argv) {
         assertSameCompartment(cx, obj);
         assertSameCompartment(cx, JSValueArray(argv - 2, 2));
     }
 #endif
     if (!obj || obj->getJSClass() != clasp) {
         if (argv)
-            ReportIncompatibleMethod(cx, argv - 2, Valueify(clasp));
+            ReportIncompatibleMethod(cx, CallReceiverFromArgv(argv), Valueify(clasp));
         return false;
     }
     return true;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_HasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
 {
@@ -5056,17 +5056,17 @@ JS_New(JSContext *cx, JSObject *ctor, ui
     // of object to create, create it, and clamp the return value to an object,
     // among other details. InvokeConstructor does the hard work.
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return NULL;
 
     args.calleev().setObject(*ctor);
     args.thisv().setNull();
-    memcpy(args.argv(), argv, argc * sizeof(jsval));
+    memcpy(args.array(), argv, argc * sizeof(jsval));
 
     if (!InvokeConstructor(cx, args))
         return NULL;
 
     if (!args.rval().isObject()) {
         /*
          * Although constructors may return primitives (via proxies), this
          * API is asking for an object, so we report an error.
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -1433,21 +1433,22 @@ class ArraySharpDetector
     }
 };
 
 static JSBool
 array_toSource(JSContext *cx, uintN argc, Value *vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (!obj->isArray()) {
-        ReportIncompatibleMethod(cx, vp, &ArrayClass);
+        ReportIncompatibleMethod(cx, args, &ArrayClass);
         return false;
     }
 
     ArraySharpDetector detector(cx);
     if (!detector.init(obj))
         return false;
 
     StringBuffer sb(cx);
@@ -1511,17 +1512,17 @@ array_toSource(JSContext *cx, uintN argc
     if (!sb.append(']'))
         return false;
 
   make_string:
     JSString *str = sb.finishString();
     if (!str)
         return false;
 
-    JS_SET_RVAL(cx, vp, StringValue(str));
+    args.rval().setString(str);
     return true;
 }
 #endif
 
 class AutoArrayCycleDetector
 {
     JSContext *cx;
     JSObject *obj;
--- a/js/src/jsbool.cpp
+++ b/js/src/jsbool.cpp
@@ -77,54 +77,56 @@ Class js::BooleanClass = {
 };
 
 #if JS_HAS_TOSOURCE
 #include "jsprf.h"
 
 static JSBool
 bool_toSource(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     bool b;
-    if (!GetPrimitiveThis(cx, vp, &b))
+    if (!GetPrimitiveThis(cx, args, &b))
         return false;
 
     char buf[32];
     JS_snprintf(buf, sizeof buf, "(new Boolean(%s))", JS_BOOLEAN_STR(b));
     JSString *str = JS_NewStringCopyZ(cx, buf);
     if (!str)
         return false;
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 #endif
 
 static JSBool
 bool_toString(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     bool b;
-    if (!GetPrimitiveThis(cx, vp, &b))
+    if (!GetPrimitiveThis(cx, args, &b))
         return false;
 
-    JSAtom *atom = cx->runtime->atomState.booleanAtoms[b ? 1 : 0];
-    JSString *str = atom;
-    if (!str)
-        return JS_FALSE;
-    vp->setString(str);
-    return JS_TRUE;
+    args.rval().setString(cx->runtime->atomState.booleanAtoms[b ? 1 : 0]);
+    return true;
 }
 
 static JSBool
 bool_valueOf(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     bool b;
-    if (!GetPrimitiveThis(cx, vp, &b))
+    if (!GetPrimitiveThis(cx, args, &b))
         return false;
 
-    vp->setBoolean(b);
-    return JS_TRUE;
+    args.rval().setBoolean(b);
+    return true;
 }
 
 static JSFunctionSpec boolean_methods[] = {
 #if JS_HAS_TOSOURCE
     JS_FN(js_toSource_str,  bool_toSource,  0, 0),
 #endif
     JS_FN(js_toString_str,  bool_toString,  0, 0),
     JS_FN(js_valueOf_str,   bool_valueOf,   0, 0),
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -288,17 +288,17 @@ assertSameCompartment(JSContext *cx, T1 
 STATIC_PRECONDITION_ASSUME(ubound(args.argv_) >= argc)
 JS_ALWAYS_INLINE bool
 CallJSNative(JSContext *cx, Native native, const CallArgs &args)
 {
 #ifdef DEBUG
     JSBool alreadyThrowing = cx->isExceptionPending();
 #endif
     assertSameCompartment(cx, args);
-    JSBool ok = native(cx, args.argc(), args.base());
+    bool ok = native(cx, args.length(), args.base());
     if (ok) {
         assertSameCompartment(cx, args.rval());
         JS_ASSERT_IF(!alreadyThrowing, !cx->isExceptionPending());
     }
     return ok;
 }
 
 extern JSBool CallOrConstructBoundFunction(JSContext *, uintN, js::Value *);
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -587,26 +587,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, Value *argv, jsdouble *rval)
+date_msecFromArgs(JSContext *cx, CallArgs args, double *rval)
 {
     uintN loop;
     jsdouble array[MAXARGS];
     jsdouble msec_time;
 
     for (loop = 0; loop < MAXARGS; loop++) {
-        if (loop < argc) {
+        if (loop < args.length()) {
             jsdouble d;
-            if (!ToNumber(cx, argv[loop], &d))
+            if (!ToNumber(cx, args[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 {
@@ -629,24 +629,25 @@ date_msecFromArgs(JSContext *cx, uintN a
 }
 
 /*
  * See ECMA 15.9.4.[3-10];
  */
 static JSBool
 date_UTC(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble msec_time;
-
-    if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time))
+    if (!date_msecFromArgs(cx, args, &msec_time))
         return JS_FALSE;
 
     msec_time = TIMECLIP(msec_time);
 
-    vp->setNumber(msec_time);
+    args.rval().setNumber(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
@@ -1219,21 +1220,20 @@ date_now_tn(JSContext*)
 }
 #endif
 
 /*
  * Get UTC time from the date object. Returns false if the object is not
  * Date type.
  */
 static JSBool
-GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp)
+GetUTCTime(JSContext *cx, JSObject *obj, CallReceiver call, jsdouble *dp)
 {
     if (!obj->isDate()) {
-        if (vp)
-            ReportIncompatibleMethod(cx, vp, &DateClass);
+        ReportIncompatibleMethod(cx, call, &DateClass);
         return false;
     }
     *dp = obj->getDateUTCTime().toNumber();
     return true;
 }
 
 /*
  * Set UTC time to a given time and invalidate cached local time.
@@ -1398,423 +1398,453 @@ FillLocalTimes(JSContext *cx, JSObject *
     jsint hours = (yearSeconds / (60 * 60)) % 24;
 
     obj->setSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS, Int32Value(hours));
 
     return true;
 }
 
 /* Cache the local times in obj, if necessary. */
-static inline JSBool
-GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = NULL)
+static inline bool
+GetAndCacheLocalTime(JSContext *cx, JSObject *obj)
 {
-    if (!obj)
-        return false;
-    if (!obj->isDate()) {
-        if (vp)
-            ReportIncompatibleMethod(cx, vp, &DateClass);
-        return false;
-    }
+    JS_ASSERT(obj->isDate());
 
     /* If the local time is undefined, we need to fill in the cached values. */
     if (obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).isUndefined()) {
         if (!FillLocalTimes(cx, obj))
             return false;
     }
-
-    if (time)
-        *time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble();
-
     return true;
 }
 
 static inline bool
-GetThisUTCTime(JSContext *cx, Value *vp, jsdouble *dp)
+GetAndCacheLocalTime(JSContext *cx, JSObject *obj, CallArgs args)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    if (!obj->isDate()) {
+        ReportIncompatibleMethod(cx, args, &DateClass);
+        return false;
+    }
+
+    return GetAndCacheLocalTime(cx, obj);
+}
+
+static inline bool
+GetAndCacheLocalTime(JSContext *cx, JSObject *obj, double *time)
+{
+    if (!obj || !GetAndCacheLocalTime(cx, obj))
+        return false;
+
+    *time = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_TIME).toDouble();
+    return true;
+}
+
+static inline bool
+GetThisUTCTime(JSContext *cx, CallReceiver call, jsdouble *dp)
+{
+    JSObject *obj = ToObject(cx, &call.thisv());
     if (!obj)
         return false;
-    return GetUTCTime(cx, obj, vp, dp);
+    return GetUTCTime(cx, obj, call, dp);
 }
 
 /*
  * See ECMA 15.9.5.4 thru 15.9.5.23
  */
 static JSBool
 date_getTime(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble result;
-    if (!GetThisUTCTime(cx, vp, &result))
+    if (!GetThisUTCTime(cx, args, &result))
         return false;
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return true;
 }
 
 static JSBool
 date_getYear(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetAndCacheLocalTime(cx, obj, vp))
+    if (!GetAndCacheLocalTime(cx, obj, args))
         return false;
 
     Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
     if (yearVal.isInt32()) {
         /* Follow ECMA-262 to the letter, contrary to IE JScript. */
         jsint year = yearVal.toInt32() - 1900;
-        vp->setInt32(year);
+        args.rval().setInt32(year);
     } else {
-        *vp = yearVal;
+        args.rval() = yearVal;
     }
 
     return true;
 }
 
 static JSBool
 date_getFullYear(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetAndCacheLocalTime(cx, obj, vp))
+    if (!GetAndCacheLocalTime(cx, obj, args))
         return JS_FALSE;
 
-    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
+    args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
     return JS_TRUE;
 }
 
 static JSBool
 date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble result;
-    if (!GetThisUTCTime(cx, vp, &result))
+    if (!GetThisUTCTime(cx, args, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = YearFromTime(result);
 
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return true;
 }
 
 static JSBool
 date_getMonth(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetAndCacheLocalTime(cx, obj, vp))
+    if (!GetAndCacheLocalTime(cx, obj, args))
         return false;
 
-    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
+    args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
     return true;
 }
 
 static JSBool
 date_getUTCMonth(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble result;
-    if (!GetThisUTCTime(cx, vp, &result))
+    if (!GetThisUTCTime(cx, args, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = MonthFromTime(result);
 
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return true;
 }
 
 static JSBool
 date_getDate(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetAndCacheLocalTime(cx, obj, vp))
+    if (!GetAndCacheLocalTime(cx, obj, args))
         return false;
 
-    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
+    args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
     return true;
 }
 
 static JSBool
 date_getUTCDate(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble result;
-    if (!GetThisUTCTime(cx, vp, &result))
+    if (!GetThisUTCTime(cx, args, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = DateFromTime(result);
 
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return true;
 }
 
 static JSBool
 date_getDay(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetAndCacheLocalTime(cx, obj, vp))
+    if (!GetAndCacheLocalTime(cx, obj, args))
         return false;
 
-    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
+    args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
     return true;
 }
 
 static JSBool
 date_getUTCDay(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble result;
-    if (!GetThisUTCTime(cx, vp, &result))
+    if (!GetThisUTCTime(cx, args, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = WeekDay(result);
 
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return true;
 }
 
 static JSBool
 date_getHours(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetAndCacheLocalTime(cx, obj, vp))
+    if (!GetAndCacheLocalTime(cx, obj, args))
         return false;
 
-    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
+    args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
     return true;
 }
 
 static JSBool
 date_getUTCHours(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble result;
-    if (!GetThisUTCTime(cx, vp, &result))
+    if (!GetThisUTCTime(cx, args, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = HourFromTime(result);
 
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return JS_TRUE;
 }
 
 static JSBool
 date_getMinutes(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetAndCacheLocalTime(cx, obj, vp))
+    if (!GetAndCacheLocalTime(cx, obj, args))
         return false;
 
-    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
+    args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
     return true;
 }
 
 static JSBool
 date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble result;
-    if (!GetThisUTCTime(cx, vp, &result))
+    if (!GetThisUTCTime(cx, args, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = MinFromTime(result);
 
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return true;
 }
 
 /* Date.getSeconds is mapped to getUTCSeconds */
 
 static JSBool
 date_getUTCSeconds(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetAndCacheLocalTime(cx, obj, vp))
+    if (!GetAndCacheLocalTime(cx, obj, args))
         return false;
 
-    *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
+    args.rval() = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
     return true;
 }
 
 /* Date.getMilliseconds is mapped to getUTCMilliseconds */
 
 static JSBool
 date_getUTCMilliseconds(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble result;
-    if (!GetThisUTCTime(cx, vp, &result))
+    if (!GetThisUTCTime(cx, args, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = msFromTime(result);
 
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return true;
 }
 
 static JSBool
 date_getTimezoneOffset(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     jsdouble utctime;
-    if (!GetUTCTime(cx, obj, vp, &utctime))
+    if (!GetUTCTime(cx, obj, args, &utctime))
         return false;
 
     jsdouble localtime;
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime))
+    if (!GetAndCacheLocalTime(cx, obj, &localtime))
         return 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.
      */
     jsdouble result = (utctime - localtime) / msPerMinute;
-    vp->setNumber(result);
+    args.rval().setNumber(result);
     return true;
 }
 
 static JSBool
 date_setTime(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     if (!obj->isDate()) {
-        ReportIncompatibleMethod(cx, vp, &DateClass);
+        ReportIncompatibleMethod(cx, args, &DateClass);
         return false;
     }
 
-    if (argc == 0) {
-        SetDateToNaN(cx, obj, vp);
+    if (args.length() == 0) {
+        SetDateToNaN(cx, obj, &args.rval());
         return true;
     }
 
     jsdouble result;
-    if (!ToNumber(cx, vp[2], &result))
+    if (!ToNumber(cx, args[0], &result))
         return false;
 
-    return SetUTCTime(cx, obj, TIMECLIP(result), vp);
+    return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
 }
 
 static JSBool
 date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp)
 {
-    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;
-
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetUTCTime(cx, obj, vp, &result))
+    double result;
+    if (!GetUTCTime(cx, obj, args, &result))
         return false;
 
     /* just return NaN if the date is already NaN */
     if (!JSDOUBLE_IS_FINITE(result)) {
-        vp->setNumber(result);
+        args.rval().setNumber(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();
      * d.setMilliseconds()" returns NaN.  Blech.
      */
-    if (argc == 0) {
-        SetDateToNaN(cx, obj, vp);
+    if (args.length() == 0) {
+        SetDateToNaN(cx, obj, &args.rval());
         return true;
     }
-    if (argc > maxargs)
-        argc = maxargs;  /* clamp argc */
-    JS_ASSERT(argc <= 4);
-
-    argv = vp + 2;
-    for (i = 0; i < argc; i++) {
-        if (!ToNumber(cx, argv[i], &args[i]))
+
+    uintN numNums = Min(args.length(), maxargs);
+    JS_ASSERT(numNums <= 4);
+    double nums[4];
+    for (uintN i = 0; i < numNums; i++) {
+        if (!ToNumber(cx, args[i], &nums[i]))
             return false;
-        if (!JSDOUBLE_IS_FINITE(args[i])) {
-            SetDateToNaN(cx, obj, vp);
+        if (!JSDOUBLE_IS_FINITE(nums[i])) {
+            SetDateToNaN(cx, obj, &args.rval());
             return true;
         }
-        args[i] = js_DoubleToInteger(args[i]);
+        nums[i] = js_DoubleToInteger(nums[i]);
     }
 
+    double lorutime;  /* Local or UTC version of *date */
     if (local)
         lorutime = LocalTime(result, cx);
     else
         lorutime = result;
 
-    argp = args;
-    stop = argp + argc;
+    double *argp = nums;
+    double *stop = argp + numNums;
+    double hour;
     if (maxargs >= 4 && argp < stop)
         hour = *argp++;
     else
         hour = HourFromTime(lorutime);
 
+    double min;
     if (maxargs >= 3 && argp < stop)
         min = *argp++;
     else
         min = MinFromTime(lorutime);
 
+    double sec;
     if (maxargs >= 2 && argp < stop)
         sec = *argp++;
     else
         sec = SecFromTime(lorutime);
 
+    double msec;
     if (maxargs >= 1 && argp < stop)
         msec = *argp;
     else
         msec = msFromTime(lorutime);
 
-    msec_time = MakeTime(hour, min, sec, msec);
+    double msec_time = MakeTime(hour, min, sec, msec);
     result = MakeDate(Day(lorutime), msec_time);
 
-/*     fprintf(stderr, "%f\n", result); */
-
     if (local)
         result = UTC(result, cx);
 
-/*     fprintf(stderr, "%f\n", result); */
-
-    return SetUTCTime(cx, obj, TIMECLIP(result), vp);
+    return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
 }
 
 static JSBool
 date_setMilliseconds(JSContext *cx, uintN argc, Value *vp)
 {
     return date_makeTime(cx, 1, JS_TRUE, argc, vp);
 }
 
@@ -1858,86 +1888,86 @@ static JSBool
 date_setUTCHours(JSContext *cx, uintN argc, Value *vp)
 {
     return date_makeTime(cx, 4, JS_FALSE, argc, vp);
 }
 
 static JSBool
 date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, Value *vp)
 {
-    Value *argv;
-    uintN i;
-    jsdouble lorutime; /* local or UTC version of *date */
-    jsdouble args[3], *argp, *stop;
-    jsdouble year, month, day;
-    jsdouble result;
-
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    if (!GetUTCTime(cx, obj, vp, &result))
+    double result;
+    if (!GetUTCTime(cx, obj, args, &result))
         return false;
 
     /* see complaint about ECMA in date_MakeTime */
-    if (argc == 0) {
-        SetDateToNaN(cx, obj, vp);
+    if (args.length() == 0) {
+        SetDateToNaN(cx, obj, &args.rval());
         return true;
     }
-    if (argc > maxargs)
-        argc = maxargs;   /* clamp argc */
-    JS_ASSERT(1 <= argc && argc <= 3);
-
-    argv = vp + 2;
-    for (i = 0; i < argc; i++) {
-        if (!ToNumber(cx, argv[i], &args[i]))
+
+    uintN numNums = Min(args.length(), maxargs);
+    JS_ASSERT(1 <= numNums && numNums <= 3);
+    double nums[3];
+    for (uintN i = 0; i < numNums; i++) {
+        if (!ToNumber(cx, args[i], &nums[i]))
             return JS_FALSE;
-        if (!JSDOUBLE_IS_FINITE(args[i])) {
-            SetDateToNaN(cx, obj, vp);
+        if (!JSDOUBLE_IS_FINITE(nums[i])) {
+            SetDateToNaN(cx, obj, &args.rval());
             return true;
         }
-        args[i] = js_DoubleToInteger(args[i]);
+        nums[i] = js_DoubleToInteger(nums[i]);
     }
 
-    /* return NaN if date is NaN and we're not setting the year,
-     * If we are, use 0 as the time. */
+    /*
+     * return NaN if date is NaN and we're not setting the year, If we are, use
+     * 0 as the time.
+     */
+    double lorutime; /* local or UTC version of *date */
     if (!(JSDOUBLE_IS_FINITE(result))) {
         if (maxargs < 3) {
-            vp->setDouble(result);
+            args.rval().setDouble(result);
             return true;
         }
         lorutime = +0.;
     } else {
         lorutime = local ? LocalTime(result, cx) : result;
     }
 
-    argp = args;
-    stop = argp + argc;
+    double *argp = nums;
+    double *stop = argp + numNums;
+    double year;
     if (maxargs >= 3 && argp < stop)
         year = *argp++;
     else
         year = YearFromTime(lorutime);
 
+    double month;
     if (maxargs >= 2 && argp < stop)
         month = *argp++;
     else
         month = MonthFromTime(lorutime);
 
+    double day;
     if (maxargs >= 1 && argp < stop)
         day = *argp++;
     else
         day = DateFromTime(lorutime);
 
     day = MakeDay(year, month, day); /* day within year */
     result = MakeDate(day, TimeWithinDay(lorutime));
 
     if (local)
         result = UTC(result, cx);
 
-    return SetUTCTime(cx, obj, TIMECLIP(result), vp);
+    return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
 }
 
 static JSBool
 date_setDate(JSContext *cx, uintN argc, Value *vp)
 {
     return date_makeDate(cx, 1, JS_TRUE, argc, vp);
 }
 
@@ -1969,47 +1999,48 @@ static JSBool
 date_setUTCFullYear(JSContext *cx, uintN argc, Value *vp)
 {
     return date_makeDate(cx, 3, JS_FALSE, argc, vp);
 }
 
 static JSBool
 date_setYear(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     jsdouble result;
-    if (!GetUTCTime(cx, obj, vp, &result))
+    if (!GetUTCTime(cx, obj, args, &result))
         return false;
 
-    if (argc == 0) {
+    if (args.length() == 0) {
         /* Call this only after GetUTCTime has verified that obj is Date. */
-        SetDateToNaN(cx, obj, vp);
+        SetDateToNaN(cx, obj, &args.rval());
         return true;
     }
 
     jsdouble year;
-    if (!ToNumber(cx, vp[2], &year))
+    if (!ToNumber(cx, args[0], &year))
         return false;
     if (!JSDOUBLE_IS_FINITE(year)) {
-        SetDateToNaN(cx, obj, vp);
+        SetDateToNaN(cx, obj, &args.rval());
         return true;
     }
     year = js_DoubleToInteger(year);
     if (year >= 0 && year <= 99)
         year += 1900;
 
     jsdouble t = JSDOUBLE_IS_FINITE(result) ? LocalTime(result, cx) : +0.0;
     jsdouble day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
     result = MakeDate(day, TimeWithinDay(t));
     result = UTC(result, cx);
 
-    return SetUTCTime(cx, obj, TIMECLIP(result), vp);
+    return SetUTCTime(cx, obj, TIMECLIP(result), &args.rval());
 }
 
 /* constants for toString, toUTCString */
 static char js_NaN_date_str[] = "Invalid Date";
 static const char* days[] =
 {
    "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
 };
@@ -2043,21 +2074,21 @@ print_iso_string(char* buf, size_t size,
                 DateFromTime(utctime),
                 HourFromTime(utctime),
                 MinFromTime(utctime),
                 SecFromTime(utctime),
                 msFromTime(utctime));
 }
 
 static JSBool
-date_utc_format(JSContext *cx, Value *vp,
+date_utc_format(JSContext *cx, CallReceiver call,
                 void (*printFunc)(char*, size_t, jsdouble))
 {
     jsdouble utctime;
-    if (!GetThisUTCTime(cx, vp, &utctime))
+    if (!GetThisUTCTime(cx, call, &utctime))
         return false;
 
     char buf[100];
     if (!JSDOUBLE_IS_FINITE(utctime)) {
         if (printFunc == print_iso_string) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INVALID_DATE);
             return false;
         }
@@ -2065,30 +2096,30 @@ date_utc_format(JSContext *cx, Value *vp
         JS_snprintf(buf, sizeof buf, js_NaN_date_str);
     } else {
         (*printFunc)(buf, sizeof buf, utctime);
     }
 
     JSString *str = JS_NewStringCopyZ(cx, buf);
     if (!str)
         return false;
-    vp->setString(str);
+    call.rval().setString(str);
     return true;
 }
 
 static JSBool
 date_toGMTString(JSContext *cx, uintN argc, Value *vp)
 {
-    return date_utc_format(cx, vp, print_gmt_string);
+    return date_utc_format(cx, CallReceiverFromVp(vp), print_gmt_string);
 }
 
 static JSBool
 date_toISOString(JSContext *cx, uintN argc, Value *vp)
 {
-    return date_utc_format(cx, vp, print_iso_string);
+    return date_utc_format(cx, CallReceiverFromVp(vp), print_iso_string);
 }
 
 /* ES5 15.9.5.44. */
 static JSBool
 date_toJSON(JSContext *cx, uintN argc, Value *vp)
 {
     /* Step 1. */
     JSObject *obj = ToObject(cx, &vp[1]);
@@ -2156,17 +2187,17 @@ new_explode(jsdouble timeval, PRMJTime *
 }
 
 typedef enum formatspec {
     FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
 } formatspec;
 
 /* helper function */
 static JSBool
-date_format(JSContext *cx, jsdouble date, formatspec format, Value *rval)
+date_format(JSContext *cx, jsdouble date, formatspec format, CallReceiver call)
 {
     char buf[100];
     JSString *str;
     char tzbuf[100];
     JSBool usetz;
     size_t i, tzlen;
     PRMJTime split;
 
@@ -2264,44 +2295,44 @@ date_format(JSContext *cx, jsdouble date
                         usetz ? tzbuf : "");
             break;
         }
     }
 
     str = JS_NewStringCopyZ(cx, buf);
     if (!str)
         return JS_FALSE;
-    rval->setString(str);
+    call.rval().setString(str);
     return JS_TRUE;
 }
 
 static JSBool
-date_toLocaleHelper(JSContext *cx, JSObject *obj, const char *format, Value *vp)
+date_toLocaleHelper(JSContext *cx, JSObject *obj, const char *format, CallReceiver call)
 {
     char buf[100];
     JSString *str;
     PRMJTime split;
     jsdouble utctime;
 
-    if (!GetUTCTime(cx, obj, vp, &utctime))
+    if (!GetUTCTime(cx, obj, call, &utctime))
         return false;
 
     if (!JSDOUBLE_IS_FINITE(utctime)) {
         JS_snprintf(buf, sizeof buf, js_NaN_date_str);
     } else {
         intN result_len;
         jsdouble local = LocalTime(utctime, cx);
         new_explode(local, &split, cx);
 
         /* let PRMJTime format it.       */
         result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
 
         /* If it failed, default to toString. */
         if (result_len == 0)
-            return date_format(cx, utctime, FORMATSPEC_FULL, vp);
+            return date_format(cx, utctime, FORMATSPEC_FULL, call);
 
         /* Hacked check against undesired 2-digit year 00/00/00 form. */
         if (strcmp(format, "%x") == 0 && result_len >= 6 &&
             /* Format %x means use OS settings, which may have 2-digit yr, so
                hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
             !isdigit(buf[result_len - 3]) &&
             isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
             /* ...but not if starts with 4-digit year, like 2022/3/11. */
@@ -2309,123 +2340,133 @@ date_toLocaleHelper(JSContext *cx, JSObj
               isdigit(buf[2]) && isdigit(buf[3]))) {
             JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
                         "%d", js_DateGetYear(cx, obj));
         }
 
     }
 
     if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
-        return cx->localeCallbacks->localeToUnicode(cx, buf, vp);
+        return cx->localeCallbacks->localeToUnicode(cx, buf, &call.rval());
 
     str = JS_NewStringCopyZ(cx, buf);
     if (!str)
         return false;
-    vp->setString(str);
+    call.rval().setString(str);
     return true;
 }
 
 static JSBool
 date_toLocaleString(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     /*
      * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
      * with msvc; '%#c' requests that a full year be used in the result string.
      */
     return date_toLocaleHelper(cx, obj,
 #if defined(_WIN32) && !defined(__MWERKS__)
                                    "%#c"
 #else
                                    "%c"
 #endif
-                               , vp);
+                               , args);
 }
 
 static JSBool
 date_toLocaleDateString(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
     /*
      * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
      * with msvc; '%#x' requests that a full year be used in the result string.
      */
     return date_toLocaleHelper(cx, obj,
 #if defined(_WIN32) && !defined(__MWERKS__)
                                    "%#x"
 #else
                                    "%x"
 #endif
-                               , vp);
+                               , args);
 }
 
 static JSBool
 date_toLocaleTimeString(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    return date_toLocaleHelper(cx, obj, "%X", vp);
+    return date_toLocaleHelper(cx, obj, "%X", args);
 }
 
 static JSBool
 date_toLocaleFormat(JSContext *cx, uintN argc, Value *vp)
 {
     if (argc == 0)
         return date_toLocaleString(cx, argc, vp);
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
 
-    JSString *fmt = js_ValueToString(cx, vp[2]);
+    JSString *fmt = js_ValueToString(cx, args[0]);
     if (!fmt)
         return false;
-    vp[2].setString(fmt);
+    args[0].setString(fmt);
     JSAutoByteString fmtbytes(cx, fmt);
     if (!fmtbytes)
         return false;
 
-    return date_toLocaleHelper(cx, obj, fmtbytes.ptr(), vp);
+    return date_toLocaleHelper(cx, obj, fmtbytes.ptr(), args);
 }
 
 static JSBool
 date_toTimeString(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble utctime;
-    if (!GetThisUTCTime(cx, vp, &utctime))
+    if (!GetThisUTCTime(cx, args, &utctime))
         return false;
-    return date_format(cx, utctime, FORMATSPEC_TIME, vp);
+    return date_format(cx, utctime, FORMATSPEC_TIME, args);
 }
 
 static JSBool
 date_toDateString(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble utctime;
-    if (!GetThisUTCTime(cx, vp, &utctime))
+    if (!GetThisUTCTime(cx, args, &utctime))
         return false;
-    return date_format(cx, utctime, FORMATSPEC_DATE, vp);
+    return date_format(cx, utctime, FORMATSPEC_DATE, args);
 }
 
 #if JS_HAS_TOSOURCE
 #include <string.h>
 #include "jsnum.h"
 
 static JSBool
 date_toSource(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble utctime;
-    if (!GetThisUTCTime(cx, vp, &utctime))
+    if (!GetThisUTCTime(cx, args, &utctime))
         return false;
 
     ToCStringBuf cbuf;
     char *numStr = NumberToCString(cx, &cbuf, utctime);
     if (!numStr) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
@@ -2435,29 +2476,31 @@ date_toSource(JSContext *cx, uintN argc,
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
     JSString *str = JS_NewStringCopyZ(cx, bytes);
     cx->free_(bytes);
     if (!str)
         return false;
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 #endif
 
 static JSBool
 date_toString(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     jsdouble utctime;
-    if (!GetThisUTCTime(cx, vp, &utctime))
+    if (!GetThisUTCTime(cx, args, &utctime))
         return false;
 
-    return date_format(cx, utctime, FORMATSPEC_FULL, vp);
+    return date_format(cx, utctime, FORMATSPEC_FULL, args);
 }
 
 static JSBool
 date_valueOf(JSContext *cx, uintN argc, Value *vp)
 {
     /*
      * It is an error to call date_valueOf on a non-date object, but we don't
      * need to check for that explicitly here because every path calls
@@ -2548,64 +2591,64 @@ static JSFunctionSpec date_methods[] = {
     JS_FN(js_toString_str,       date_toString,           0,0),
     JS_FN(js_valueOf_str,        date_valueOf,            0,0),
     JS_FS_END
 };
 
 JSBool
 js_Date(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Date called as function. */
-    if (!IsConstructing(vp))
-        return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, vp);
-
-    Value *argv = vp + 2;
+    if (!IsConstructing(args))
+        return date_format(cx, NowAsMillis(), FORMATSPEC_FULL, args);
 
     /* Date called as constructor. */
     jsdouble d;
-    if (argc == 0) {
+    if (args.length() == 0) {
         d = NowAsMillis();
-    } else if (argc == 1) {
-        if (!argv[0].isString()) {
+    } else if (args.length() == 1) {
+        if (!args[0].isString()) {
             /* the argument is a millisecond number */
-            if (!ToNumber(cx, argv[0], &d))
+            if (!ToNumber(cx, args[0], &d))
                 return false;
             d = TIMECLIP(d);
         } else {
             /* the argument is a string; parse it. */
-            JSString *str = js_ValueToString(cx, argv[0]);
+            JSString *str = js_ValueToString(cx, args[0]);
             if (!str)
                 return false;
-            argv[0].setString(str);
+            args[0].setString(str);
             JSLinearString *linearStr = str->ensureLinear(cx);
             if (!linearStr)
                 return false;
 
             if (!date_parseString(linearStr, &d, cx))
                 d = js_NaN;
             else
                 d = TIMECLIP(d);
         }
     } else {
         jsdouble msec_time;
-        if (!date_msecFromArgs(cx, argc, argv, &msec_time))
+        if (!date_msecFromArgs(cx, args, &msec_time))
             return false;
 
         if (JSDOUBLE_IS_FINITE(msec_time)) {
             msec_time = UTC(msec_time, cx);
             msec_time = TIMECLIP(msec_time);
         }
         d = msec_time;
     }
 
     JSObject *obj = js_NewDateObjectMsec(cx, d);
     if (!obj)
         return false;
-    vp->setObject(*obj);
-
+
+    args.rval().setObject(*obj);
     return true;
 }
 
 JSObject *
 js_InitDateClass(JSContext *cx, JSObject *obj)
 {
     JS_ASSERT(obj->isNative());
 
@@ -2677,104 +2720,101 @@ js_NewDateObject(JSContext* cx, int year
     msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
     obj = js_NewDateObjectMsec(cx, UTC(msec_time, cx));
     return obj;
 }
 
 JS_FRIEND_API(JSBool)
 js_DateIsValid(JSContext *cx, JSObject* obj)
 {
-    jsdouble utctime;
-    return GetUTCTime(cx, obj, NULL, &utctime) && !JSDOUBLE_IS_NaN(utctime);
+    return obj->isDate() && !JSDOUBLE_IS_NaN(obj->getDateUTCTime().toNumber());
 }
 
 JS_FRIEND_API(int)
 js_DateGetYear(JSContext *cx, JSObject* obj)
 {
     jsdouble localtime;
 
     /* Preserve legacy API behavior of returning 0 for invalid dates. */
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
+    if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
         JSDOUBLE_IS_NaN(localtime)) {
         return 0;
     }
 
     return (int) YearFromTime(localtime);
 }
 
 JS_FRIEND_API(int)
 js_DateGetMonth(JSContext *cx, JSObject* obj)
 {
     jsdouble localtime;
 
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
+    if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
         JSDOUBLE_IS_NaN(localtime)) {
         return 0;
     }
 
     return (int) MonthFromTime(localtime);
 }
 
 JS_FRIEND_API(int)
 js_DateGetDate(JSContext *cx, JSObject* obj)
 {
     jsdouble localtime;
 
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
+    if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
         JSDOUBLE_IS_NaN(localtime)) {
         return 0;
     }
 
     return (int) DateFromTime(localtime);
 }
 
 JS_FRIEND_API(int)
 js_DateGetHours(JSContext *cx, JSObject* obj)
 {
     jsdouble localtime;
 
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
+    if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
         JSDOUBLE_IS_NaN(localtime)) {
         return 0;
     }
 
     return (int) HourFromTime(localtime);
 }
 
 JS_FRIEND_API(int)
 js_DateGetMinutes(JSContext *cx, JSObject* obj)
 {
     jsdouble localtime;
 
-    if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
+    if (!GetAndCacheLocalTime(cx, obj, &localtime) ||
         JSDOUBLE_IS_NaN(localtime)) {
         return 0;
     }
 
     return (int) MinFromTime(localtime);
 }
 
 JS_FRIEND_API(int)
 js_DateGetSeconds(JSContext *cx, JSObject* obj)
 {
-    jsdouble utctime;
-
-    if (!GetUTCTime(cx, obj, NULL, &utctime) || JSDOUBLE_IS_NaN(utctime))
+    if (!obj->isDate()) 
         return 0;
-
+    
+    double utctime = obj->getDateUTCTime().toNumber();
+    if (JSDOUBLE_IS_NaN(utctime))
+        return 0;
     return (int) SecFromTime(utctime);
 }
 
 JS_FRIEND_API(jsdouble)
 js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
 {
-    jsdouble utctime;
-    if (!GetUTCTime(cx, obj, NULL, &utctime))
-        return 0;
-    return utctime;
+    return obj->isDate() ? obj->getDateUTCTime().toNumber() : 0;
 }
 
 #ifdef JS_THREADSAFE
 #include "prinrval.h"
 
 JS_FRIEND_API(uint32)
 js_IntervalNow()
 {
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -721,50 +721,50 @@ Exception(JSContext *cx, uintN argc, Val
 
     JSObject *errProto = &protov.toObject();
     JSObject *obj = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent());
     if (!obj)
         return false;
 
     /* Set the 'message' property. */
     JSString *message;
-    if (args.argc() != 0 && !args[0].isUndefined()) {
+    if (args.length() != 0 && !args[0].isUndefined()) {
         message = js_ValueToString(cx, args[0]);
         if (!message)
             return false;
         args[0].setString(message);
     } else {
         message = NULL;
     }
 
     /* Find the scripted caller. */
     FrameRegsIter iter(cx);
     while (!iter.done() && !iter.fp()->isScriptFrame())
         ++iter;
 
     /* Set the 'fileName' property. */
     JSString *filename;
-    if (args.argc() > 1) {
+    if (args.length() > 1) {
         filename = js_ValueToString(cx, args[1]);
         if (!filename)
             return false;
         args[1].setString(filename);
     } else {
         if (!iter.done()) {
             filename = FilenameToString(cx, iter.fp()->script()->filename);
             if (!filename)
                 return false;
         } else {
             filename = cx->runtime->emptyString;
         }
     }
 
     /* Set the 'lineNumber' property. */
     uint32_t lineno;
-    if (args.argc() > 2) {
+    if (args.length() > 2) {
         if (!ValueToECMAUint32(cx, args[2], &lineno))
             return false;
     } else {
         lineno = iter.done() ? 0 : js_FramePCToLineNumber(cx, iter.fp(), iter.pc());
     }
 
     intN exnType = args.callee().getReservedSlot(JSSLOT_ERROR_EXNTYPE).toInt32();
     if (!InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType))
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -1796,17 +1796,17 @@ fun_toSource(JSContext *cx, uintN argc, 
 #endif
 
 JSBool
 js_fun_call(JSContext *cx, uintN argc, Value *vp)
 {
     Value fval = vp[1];
 
     if (!js_IsCallable(fval)) {
-        ReportIncompatibleMethod(cx, vp, &FunctionClass);
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
         return false;
     }
 
     Value *argv = vp + 2;
     Value thisv;
     if (argc == 0) {
         thisv.setUndefined();
     } else {
@@ -1819,31 +1819,31 @@ js_fun_call(JSContext *cx, uintN argc, V
     /* Allocate stack space for fval, obj, and the args. */
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return JS_FALSE;
 
     /* Push fval, thisv, and the args. */
     args.calleev() = fval;
     args.thisv() = thisv;
-    memcpy(args.argv(), argv, argc * sizeof *argv);
+    memcpy(args.array(), argv, argc * sizeof *argv);
 
     bool ok = Invoke(cx, args);
     *vp = args.rval();
     return ok;
 }
 
 /* ES5 15.3.4.3 */
 JSBool
 js_fun_apply(JSContext *cx, uintN argc, Value *vp)
 {
     /* Step 1. */
     Value fval = vp[1];
     if (!js_IsCallable(fval)) {
-        ReportIncompatibleMethod(cx, vp, &FunctionClass);
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &FunctionClass);
         return false;
     }
 
     /* Step 2. */
     if (argc < 2 || vp[3].isNullOrUndefined())
         return js_fun_call(cx, (argc > 0) ? 1 : 0, vp);
 
     /* N.B. Changes need to be propagated to stubs::SplatApplyArgs. */
@@ -1873,17 +1873,17 @@ js_fun_apply(JSContext *cx, uintN argc, 
     if (!cx->stack.pushInvokeArgs(cx, length, &args))
         return false;
 
     /* Push fval, obj, and aobj's elements as args. */
     args.calleev() = fval;
     args.thisv() = vp[2];
 
     /* Steps 7-8. */
-    if (!GetElements(cx, aobj, length, args.argv()))
+    if (!GetElements(cx, aobj, length, args.array()))
         return false;
 
     /* Step 9. */
     if (!Invoke(cx, args))
         return false;
     *vp = args.rval();
     return true;
 }
@@ -1988,17 +1988,17 @@ CallOrConstructBoundFunction(JSContext *
 
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc + argslen, &args))
         return false;
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 4. */
     for (uintN i = 0; i < argslen; i++)
         args[i] = obj->getBoundFunctionArgument(i);
-    memcpy(args.argv() + argslen, vp + 2, argc * sizeof(Value));
+    memcpy(args.array() + argslen, vp + 2, argc * sizeof(Value));
 
     /* 15.3.4.5.1, 15.3.4.5.2 step 5. */
     args.calleev().setObject(*target);
 
     if (!constructing)
         args.thisv() = boundThis;
 
     if (constructing ? !InvokeConstructor(cx, args) : !Invoke(cx, args))
@@ -2033,33 +2033,35 @@ fun_isGenerator(JSContext *cx, uintN arg
     return true;
 }
 #endif
 
 /* ES5 15.3.4.5. */
 static JSBool
 fun_bind(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     /* Step 1. */
-    Value &thisv = vp[1];
+    Value &thisv = args.thisv();
 
     /* Step 2. */
     if (!js_IsCallable(thisv)) {
-        ReportIncompatibleMethod(cx, vp, &FunctionClass);
+        ReportIncompatibleMethod(cx, args, &FunctionClass);
         return false;
     }
 
     JSObject *target = &thisv.toObject();
 
     /* Step 3. */
-    Value *args = NULL;
+    Value *boundArgs = NULL;
     uintN argslen = 0;
-    if (argc > 1) {
-        args = vp + 3;
-        argslen = argc - 1;
+    if (args.length() > 1) {
+        boundArgs = args.array() + 1;
+        argslen = args.length() - 1;
     }
 
     /* Steps 15-16. */
     uintN length = 0;
     if (target->isFunction()) {
         uintN nargs = target->getFunctionPrivate()->nargs;
         if (nargs > argslen)
             length = nargs - argslen;
@@ -2071,25 +2073,25 @@ fun_bind(JSContext *cx, uintN argc, Valu
     /* NB: Bound functions abuse |parent| to store their target. */
     JSObject *funobj =
         js_NewFunction(cx, NULL, CallOrConstructBoundFunction, length,
                        JSFUN_CONSTRUCTOR, target, name);
     if (!funobj)
         return false;
 
     /* Steps 7-9. */
-    Value thisArg = argc >= 1 ? vp[2] : UndefinedValue();
-    if (!funobj->initBoundFunction(cx, thisArg, args, argslen))
+    Value thisArg = args.length() >= 1 ? args[0] : UndefinedValue();
+    if (!funobj->initBoundFunction(cx, thisArg, boundArgs, argslen))
         return false;
 
     /* Steps 17, 19-21 are handled by fun_resolve. */
     /* Step 18 is the default for new functions. */
 
     /* Step 22. */
-    vp->setObject(*funobj);
+    args.rval().setObject(*funobj);
     return true;
 }
 
 /*
  * Report "malformed formal parameter" iff no illegal char or similar scanner
  * error was already reported.
  */
 static bool
@@ -2116,49 +2118,48 @@ JSFunctionSpec function_methods[] = {
     JS_FN("isGenerator",     fun_isGenerator,0,0),
 #endif
     JS_FS_END
 };
 
 JSBool
 Function(JSContext *cx, uintN argc, Value *vp)
 {
-    CallArgs call = CallArgsFromVp(argc, vp);
+    CallArgs args = CallArgsFromVp(argc, vp);
 
     /* Block this call if security callbacks forbid it. */
-    GlobalObject *global = call.callee().getGlobal();
+    GlobalObject *global = args.callee().getGlobal();
     if (!global->isRuntimeCodeGenEnabled(cx)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
         return false;
     }
 
     Bindings bindings(cx);
     uintN lineno;
     const char *filename = CurrentScriptFileAndLine(cx, &lineno);
 
-    Value *argv = call.argv();
-    uintN n = argc ? argc - 1 : 0;
+    uintN n = args.length() ? args.length() - 1 : 0;
     if (n > 0) {
         /*
          * Collect the function-argument arguments into one string, separated
          * by commas, then make a tokenstream from that string, and scan it to
          * get the arguments.  We need to throw the full scanner at the
          * problem, because the argument string can legitimately contain
          * comments and linefeeds.  XXX It might be better to concatenate
          * everything up into a function definition and pass it to the
          * compiler, but doing it this way is less of a delta from the old
          * code.  See ECMA 15.3.2.1.
          */
         size_t args_length = 0;
         for (uintN i = 0; i < n; i++) {
             /* Collect the lengths for all the function-argument arguments. */
-            JSString *arg = js_ValueToString(cx, argv[i]);
+            JSString *arg = js_ValueToString(cx, args[i]);
             if (!arg)
                 return false;
-            argv[i].setString(arg);
+            args[i].setString(arg);
 
             /*
              * Check for overflow.  The < test works because the maximum
              * JSString length fits in 2 fewer bits than size_t has.
              */
             size_t old_args_length = args_length;
             args_length = old_args_length + arg->length();
             if (args_length < old_args_length) {
@@ -2188,17 +2189,17 @@ Function(JSContext *cx, uintN argc, Valu
             return false;
         }
         jschar *collected_args = cp;
 
         /*
          * Concatenate the arguments into the new string, separated by commas.
          */
         for (uintN i = 0; i < n; i++) {
-            JSString *arg = argv[i].toString();
+            JSString *arg = args[i].toString();
             size_t arg_length = arg->length();
             const jschar *arg_chars = arg->getChars(cx);
             if (!arg_chars)
                 return false;
             (void) js_strncpy(cp, arg_chars, arg_length);
             cp += arg_length;
 
             /* Add separating comma or terminating 0. */
@@ -2257,18 +2258,18 @@ Function(JSContext *cx, uintN argc, Valu
             }
         }
     }
 
     JS::Anchor<JSString *> strAnchor(NULL);
     const jschar *chars;
     size_t length;
 
-    if (argc) {
-        JSString *str = js_ValueToString(cx, argv[argc - 1]);
+    if (args.length()) {
+        JSString *str = js_ValueToString(cx, args[args.length() - 1]);
         if (!str)
             return false;
         strAnchor.set(str);
         chars = str->getChars(cx);
         length = str->length();
     } else {
         chars = cx->runtime->emptyString->chars();
         length = 0;
@@ -2280,21 +2281,21 @@ Function(JSContext *cx, uintN argc, Valu
      * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
      * and so would a call to f from another top-level's script or function.
      */
     JSFunction *fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
                                      global, cx->runtime->atomState.anonymousAtom);
     if (!fun)
         return false;
 
-    JSPrincipals *principals = PrincipalsForCompiledCode(call, cx);
+    JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
     bool ok = Compiler::compileFunctionBody(cx, fun, principals, &bindings,
                                             chars, length, filename, lineno,
                                             cx->findVersion());
-    call.rval().setObject(*fun);
+    args.rval().setObject(*fun);
     return ok;
 }
 
 bool
 IsBuiltinFunctionConstructor(JSFunction *fun)
 {
     return fun->maybeNative() == Function;
 }
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -367,16 +367,19 @@ IsConstructing(const Value *vp)
         JS_ASSERT((fun->flags & JSFUN_CONSTRUCTOR) != 0);
     } else {
         JS_ASSERT(callee->getClass()->construct != NULL);
     }
 #endif
     return vp[1].isMagic();
 }
 
+inline bool
+IsConstructing(CallReceiver call);
+
 static JS_ALWAYS_INLINE bool
 IsConstructing_PossiblyWithGivenThisObject(const Value *vp, JSObject **ctorThis)
 {
 #ifdef DEBUG
     JSObject *callee = &JS_CALLEE(cx, vp).toObject();
     if (callee->isFunction()) {
         JSFunction *fun = callee->getFunctionPrivate();
         JS_ASSERT((fun->flags & JSFUN_CONSTRUCTOR) != 0);
--- a/js/src/jsfuninlines.h
+++ b/js/src/jsfuninlines.h
@@ -39,16 +39,22 @@
 
 #ifndef jsfuninlines_h___
 #define jsfuninlines_h___
 
 #include "jsfun.h"
 #include "jsscript.h"
 
 inline bool
+js::IsConstructing(CallReceiver call)
+{
+    return IsConstructing(call.base());
+}
+
+inline bool
 JSFunction::inStrictMode() const
 {
     return script()->strictModeCode;
 }
 
 inline void
 JSFunction::setJoinable()
 {
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -4880,17 +4880,17 @@ TypeMonitorCallSlow(JSContext *cx, JSObj
         TypeScript::SetThis(cx, script, args.thisv());
 
     /*
      * Add constraints going up to the minimum of the actual and formal count.
      * If there are more actuals than formals the later values can only be
      * accessed through the arguments object, which is monitored.
      */
     unsigned arg = 0;
-    for (; arg < args.argc() && arg < nargs; arg++)
+    for (; arg < args.length() && arg < nargs; arg++)
         TypeScript::SetArgument(cx, script, arg, args[arg]);
 
     /* Watch for fewer actuals than formals to the call. */
     for (; arg < nargs; arg++)
         TypeScript::SetArgument(cx, script, arg, UndefinedValue());
 }
 
 static inline bool
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -398,35 +398,35 @@ CallThisObjectHook(JSContext *cx, JSObje
     JSObject *thisp = obj->thisObject(cx);
     if (!thisp)
         return NULL;
     argv[-1].setObject(*thisp);
     return thisp;
 }
 
 void
-js::ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp)
-{
-    Value &thisv = vp[1];
+js::ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp)
+{
+    Value &thisv = call.thisv();
 
 #ifdef DEBUG
     if (thisv.isObject()) {
         JS_ASSERT(thisv.toObject().getClass() != clasp);
     } else if (thisv.isString()) {
         JS_ASSERT(clasp != &StringClass);
     } else if (thisv.isNumber()) {
         JS_ASSERT(clasp != &NumberClass);
     } else if (thisv.isBoolean()) {
         JS_ASSERT(clasp != &BooleanClass);
     } else {
         JS_ASSERT(thisv.isUndefined() || thisv.isNull());
     }
 #endif
 
-    if (JSFunction *fun = js_ValueToFunction(cx, &vp[0], 0)) {
+    if (JSFunction *fun = js_ValueToFunction(cx, &call.calleev(), 0)) {
         JSAutoByteString funNameBytes;
         if (const char *funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO,
                                  clasp->name, funName, InformalValueTypeName(thisv));
         }
     }
 }
 
@@ -616,20 +616,19 @@ js::RunScript(JSContext *cx, JSScript *s
 
 /*
  * Find a function reference and its 'this' value implicit first parameter
  * under argc arguments on cx's stack, and call the function.  Push missing
  * required arguments, allocate declared local variables, and pop everything
  * when done.  Then push the return value.
  */
 bool
-js::InvokeKernel(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct)
-{
-    CallArgs args = argsRef;
-    JS_ASSERT(args.argc() <= StackSpace::ARGS_LENGTH_MAX);
+js::InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct)
+{
+    JS_ASSERT(args.length() <= StackSpace::ARGS_LENGTH_MAX);
 
     JS_ASSERT(!cx->compartment->activeAnalysis);
 
     /* MaybeConstruct is a subset of InitialFrameFlags */
     InitialFrameFlags initial = (InitialFrameFlags) construct;
 
     if (args.calleev().isPrimitive()) {
         js_ReportIsNotFunction(cx, &args.calleev(), ToReportFlags(initial));
@@ -638,17 +637,17 @@ js::InvokeKernel(JSContext *cx, const Ca
 
     JSObject &callee = args.callee();
     Class *clasp = callee.getClass();
 
     /* Invoke non-functions. */
     if (JS_UNLIKELY(clasp != &FunctionClass)) {
 #if JS_HAS_NO_SUCH_METHOD
         if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
-            return NoSuchMethod(cx, args.argc(), args.base());
+            return NoSuchMethod(cx, args.length(), args.base());
 #endif
         JS_ASSERT_IF(construct, !clasp->construct);
         if (!clasp->call) {
             js_ReportIsNotFunction(cx, &args.calleev(), ToReportFlags(initial));
             return false;
         }
         return CallJSNative(cx, clasp->call, args);
     }
@@ -688,17 +687,17 @@ js::Invoke(JSContext *cx, const Value &t
            Value *rval)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
     args.calleev() = fval;
     args.thisv() = thisv;
-    memcpy(args.argv(), argv, argc * sizeof(Value));
+    memcpy(args.array(), argv, argc * sizeof(Value));
 
     if (args.thisv().isObject()) {
         /*
          * We must call the thisObject hook in case we are not called from the
          * interpreter, where a prior bytecode has computed an appropriate
          * |this| already.
          */
         JSObject *thisp = args.thisv().toObject().thisObject(cx);
@@ -718,17 +717,17 @@ bool
 js::InvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, Value *rval)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return false;
 
     args.calleev() = fval;
     args.thisv().setMagic(JS_THIS_POISON);
-    memcpy(args.argv(), argv, argc * sizeof(Value));
+    memcpy(args.array(), argv, argc * sizeof(Value));
 
     if (!InvokeConstructor(cx, args))
         return false;
 
     *rval = args.rval();
     return true;
 }
 
@@ -1139,17 +1138,17 @@ js::InvokeConstructorWithGivenThis(JSCon
                                    uintN argc, Value *argv, Value *rval)
 {
     InvokeArgsGuard args;
     if (!cx->stack.pushInvokeArgs(cx, argc, &args))
         return JS_FALSE;
 
     args.calleev() = fval;
     /* Initialize args.thisv on all paths below. */
-    memcpy(args.argv(), argv, argc * sizeof(Value));
+    memcpy(args.array(), argv, argc * sizeof(Value));
 
     /* Handle the fast-constructor cases before calling the general case. */
     JSObject &callee = fval.toObject();
     Class *clasp = callee.getClass();
     JSFunction *fun;
     bool ok;
     if (clasp == &FunctionClass && (fun = callee.getFunctionPrivate())->isConstructor()) {
         args.thisv().setMagicWithObjectOrNullPayload(thisobj);
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -74,28 +74,28 @@ GetScopeChain(JSContext *cx, StackFrame 
 extern JSObject *
 GetScopeChainFast(JSContext *cx, StackFrame *fp, JSOp op, size_t oplen);
 
 /*
  * Report an error that the this value passed as |this| in the given arguments
  * vector is not compatible with the specified class.
  */
 void
-ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp);
+ReportIncompatibleMethod(JSContext *cx, CallReceiver call, Class *clasp);
 
 /*
  * Given a context and a vector of [callee, this, args...] for a function
  * whose JSFUN_PRIMITIVE_THIS flag is set, set |*v| to the primitive value
  * of |this|. If |this| is an object, insist that it be an instance of the
  * appropriate wrapper class for T, and set |*v| to its private slot value.
  * If |this| is a primitive, unbox it into |*v| if it's of the required
  * type, and throw an error otherwise.
  */
 template <typename T>
-bool GetPrimitiveThis(JSContext *cx, Value *vp, T *v);
+bool GetPrimitiveThis(JSContext *cx, CallReceiver call, T *v);
 
 /*
  * ScriptPrologue/ScriptEpilogue must be called in pairs. ScriptPrologue
  * must be called before the script executes. ScriptEpilogue must be called
  * after the script returns or exits via exception.
  */
 
 inline bool
@@ -149,17 +149,17 @@ enum MaybeConstruct {
 };
 
 /*
  * InvokeKernel assumes that the given args have been pushed on the top of the
  * VM stack. Additionally, if 'args' is contained in a CallArgsList, that they
  * have already been marked 'active'.
  */
 extern bool
-InvokeKernel(JSContext *cx, const CallArgs &args, MaybeConstruct construct = NO_CONSTRUCT);
+InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct = NO_CONSTRUCT);
 
 /*
  * Invoke assumes that 'args' has been pushed (via ContextStack::pushInvokeArgs)
  * and is currently at the top of the VM stack.
  */
 inline bool
 Invoke(JSContext *cx, InvokeArgsGuard &args, MaybeConstruct construct = NO_CONSTRUCT)
 {
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -98,32 +98,32 @@ class PrimitiveBehavior<double> {
     static inline double extract(const Value &v) { return v.toNumber(); }
     static inline Class *getClass() { return &NumberClass; }
 };
 
 } // namespace detail
 
 template <typename T>
 inline bool
-GetPrimitiveThis(JSContext *cx, Value *vp, T *v)
+GetPrimitiveThis(JSContext *cx, CallReceiver call, T *v)
 {
     typedef detail::PrimitiveBehavior<T> Behavior;
 
-    const Value &thisv = vp[1];
+    const Value &thisv = call.thisv();
     if (Behavior::isType(thisv)) {
         *v = Behavior::extract(thisv);
         return true;
     }
 
     if (thisv.isObject() && thisv.toObject().getClass() == Behavior::getClass()) {
         *v = Behavior::extract(thisv.toObject().getPrimitiveThis());
         return true;
     }
 
-    ReportIncompatibleMethod(cx, vp, Behavior::getClass());
+    ReportIncompatibleMethod(cx, call, Behavior::getClass());
     return false;
 }
 
 /*
  * Compute the implicit |this| parameter for a call expression where the callee
  * funval was resolved from an unqualified name reference to a property on obj
  * (an object on the scope chain).
  *
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -710,31 +710,32 @@ js_ThrowStopIteration(JSContext *cx)
     if (js_FindClassObject(cx, NULL, JSProto_StopIteration, &v))
         cx->setPendingException(v);
     return JS_FALSE;
 }
 
 static JSBool
 iterator_next(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (!obj->isIterator()) {
-        ReportIncompatibleMethod(cx, vp, &IteratorClass);
+        ReportIncompatibleMethod(cx, args, &IteratorClass);
         return false;
     }
 
-    if (!js_IteratorMore(cx, obj, vp))
+    if (!js_IteratorMore(cx, obj, &args.rval()))
         return false;
-    if (!vp->toBoolean()) {
+    if (!args.rval().toBoolean()) {
         js_ThrowStopIteration(cx);
         return false;
     }
-    return js_IteratorNext(cx, obj, vp);
+    return js_IteratorNext(cx, obj, &args.rval());
 }
 
 #define JSPROP_ROPERM   (JSPROP_READONLY | JSPROP_PERMANENT)
 
 static JSFunctionSpec iterator_methods[] = {
     JS_FN(js_next_str,      iterator_next,  0,JSPROP_ROPERM),
     JS_FS_END
 };
@@ -1338,72 +1339,73 @@ CloseGenerator(JSContext *cx, JSObject *
 /*
  * Common subroutine of generator_(next|send|throw|close) methods.
  */
 static JSBool
 generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc)
 {
     LeaveTrace(cx);
 
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
-        return JS_FALSE;
+        return false;
     if (!obj->isGenerator()) {
-        ReportIncompatibleMethod(cx, vp, &GeneratorClass);
-        return JS_FALSE;
+        ReportIncompatibleMethod(cx, args, &GeneratorClass);
+        return false;
     }
 
     JSGenerator *gen = (JSGenerator *) obj->getPrivate();
     if (!gen) {
         /* This happens when obj is the generator prototype. See bug 352885. */
         goto closed_generator;
     }
 
     if (gen->state == JSGEN_NEWBORN) {
         switch (op) {
           case JSGENOP_NEXT:
           case JSGENOP_THROW:
             break;
 
           case JSGENOP_SEND:
-            if (argc >= 1 && !vp[2].isUndefined()) {
+            if (args.length() >= 1 && !args[0].isUndefined()) {
                 js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND,
-                                    JSDVG_SEARCH_STACK, vp[2], NULL);
-                return JS_FALSE;
+                                    JSDVG_SEARCH_STACK, args[0], NULL);
+                return false;
             }
             break;
 
           default:
             JS_ASSERT(op == JSGENOP_CLOSE);
             gen->state = JSGEN_CLOSED;
-            JS_SET_RVAL(cx, vp, UndefinedValue());
-            return JS_TRUE;
+            args.rval().setUndefined();
+            return true;
         }
     } else if (gen->state == JSGEN_CLOSED) {
       closed_generator:
         switch (op) {
           case JSGENOP_NEXT:
           case JSGENOP_SEND:
             return js_ThrowStopIteration(cx);
           case JSGENOP_THROW:
-            cx->setPendingException(argc >= 1 ? vp[2] : UndefinedValue());
-            return JS_FALSE;
+            cx->setPendingException(args.length() >= 1 ? args[0] : UndefinedValue());
+            return false;
           default:
             JS_ASSERT(op == JSGENOP_CLOSE);
-            JS_SET_RVAL(cx, vp, UndefinedValue());
-            return JS_TRUE;
+            args.rval().setUndefined();
+            return true;
         }
     }
 
-    bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && argc != 0);
-    if (!SendToGenerator(cx, op, obj, gen, undef ? vp[2] : UndefinedValue()))
-        return JS_FALSE;
+    bool undef = ((op == JSGENOP_SEND || op == JSGENOP_THROW) && args.length() != 0);
+    if (!SendToGenerator(cx, op, obj, gen, undef ? args[0] : UndefinedValue()))
+        return false;
 
-    JS_SET_RVAL(cx, vp, gen->floatingFrame()->returnValue());
-    return JS_TRUE;
+    args.rval() = gen->floatingFrame()->returnValue();
+    return true;
 }
 
 static JSBool
 generator_send(JSContext *cx, uintN argc, Value *vp)
 {
     return generator_op(cx, JSGENOP_SEND, vp, argc);
 }
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -597,33 +597,35 @@ Number(JSContext *cx, uintN argc, Value 
     vp->setObject(*obj);
     return true;
 }
 
 #if JS_HAS_TOSOURCE
 static JSBool
 num_toSource(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     double d;
-    if (!GetPrimitiveThis(cx, vp, &d))
+    if (!GetPrimitiveThis(cx, args, &d))
         return false;
 
     ToCStringBuf cbuf;
     char *numStr = NumberToCString(cx, &cbuf, d);
     if (!numStr) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
 
     char buf[64];
     JS_snprintf(buf, sizeof buf, "(new %s(%s))", NumberClass.name, numStr);
     JSString *str = js_NewStringCopyZ(cx, buf);
     if (!str)
         return false;
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 #endif
 
 ToCStringBuf::ToCStringBuf() :dbuf(NULL)
 {
     JS_STATIC_ASSERT(sbufSize >= DTOSTR_STANDARD_BUFFER_SIZE);
 }
@@ -708,39 +710,41 @@ IntToCString(ToCStringBuf *cbuf, jsint i
 }
 
 static JSString * JS_FASTCALL
 js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base);
 
 static JSBool
 num_toString(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     double d;
-    if (!GetPrimitiveThis(cx, vp, &d))
+    if (!GetPrimitiveThis(cx, args, &d))
         return false;
 
     int32 base = 10;
-    if (argc != 0 && !vp[2].isUndefined()) {
+    if (args.length() != 0 && !args[0].isUndefined()) {
         jsdouble d2;
-        if (!ToInteger(cx, vp[2], &d2))
+        if (!ToInteger(cx, args[0], &d2))
             return false;
 
         if (d2 < 2 || d2 > 36) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_RADIX);
             return false;
         }
 
         base = int32(d2);
     }
     JSString *str = js_NumberToStringWithBase(cx, d, base);
     if (!str) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
-    vp->setString(str);
+    args.rval().setString(str);
     return JS_TRUE;
 }
 
 static JSBool
 num_toLocaleString(JSContext *cx, uintN argc, Value *vp)
 {
     size_t thousandsLength, decimalLength;
     const char *numGrouping, *tmpGroup;
@@ -856,46 +860,48 @@ num_toLocaleString(JSContext *cx, uintN 
 
     vp->setString(str);
     return JS_TRUE;
 }
 
 JSBool
 js_num_valueOf(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     double d;
-    if (!GetPrimitiveThis(cx, vp, &d))
+    if (!GetPrimitiveThis(cx, args, &d))
         return false;
 
-    vp->setNumber(d);
+    args.rval().setNumber(d);
     return true;
 }
 
 
 #define MAX_PRECISION 100
 
 static JSBool
 num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode,
        jsint precisionMin, jsint precisionMax, jsint precisionOffset,
-       uintN argc, Value *vp)
+       CallArgs args)
 {
     /* Use MAX_PRECISION+1 because precisionOffset can be 1. */
     char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)];
     char *numStr;
 
     double d;
-    if (!GetPrimitiveThis(cx, vp, &d))
+    if (!GetPrimitiveThis(cx, args, &d))
         return false;
 
     double precision;
-    if (argc == 0) {
+    if (args.length() == 0) {
         precision = 0.0;
         oneArgMode = zeroArgMode;
     } else {
-        if (!ToInteger(cx, vp[2], &precision))
+        if (!ToInteger(cx, args[0], &precision))
             return false;
         if (precision < precisionMin || precision > precisionMax) {
             ToCStringBuf cbuf;
             numStr = IntToCString(&cbuf, jsint(precision));
             JS_ASSERT(numStr);
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_PRECISION_RANGE, numStr);
             return JS_FALSE;
         }
@@ -905,45 +911,45 @@ num_to(JSContext *cx, JSDToStrMode zeroA
                        oneArgMode, (jsint)precision + precisionOffset, d);
     if (!numStr) {
         JS_ReportOutOfMemory(cx);
         return JS_FALSE;
     }
     JSString *str = js_NewStringCopyZ(cx, numStr);
     if (!str)
         return JS_FALSE;
-    vp->setString(str);
+    args.rval().setString(str);
     return JS_TRUE;
 }
 
 /*
  * In the following three implementations, we allow a larger range of precision
  * than ECMA requires; this is permitted by ECMA-262.
  */
 static JSBool
 num_toFixed(JSContext *cx, uintN argc, Value *vp)
 {
     return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0,
-                  argc, vp);
+                  CallArgsFromVp(argc, vp));
 }
 
 static JSBool
 num_toExponential(JSContext *cx, uintN argc, Value *vp)
 {
     return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1,
-                  argc, vp);
+                  CallArgsFromVp(argc, vp));
 }
 
 static JSBool
 num_toPrecision(JSContext *cx, uintN argc, Value *vp)
 {
     if (argc == 0 || vp[2].isUndefined())
         return num_toString(cx, 0, vp);
     return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0,
-                  argc, vp);
+                  CallArgsFromVp(argc, vp));
 }
 
 #ifdef JS_TRACER
 
 JS_DEFINE_TRCINFO_2(num_toString,
     (2, (extern, STRING_RETRY, js_NumberToString,         CONTEXT, THIS_DOUBLE,
          1, nanojit::ACCSET_NONE)),
     (3, (static, STRING_RETRY, js_NumberToStringWithBase, CONTEXT, THIS_DOUBLE, INT32,
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1146,37 +1146,37 @@ enum EvalType { DIRECT_EVAL = EXECUTE_DI
  * Evaluate call.argv[2], if it is a string, in the context of the given calling
  * frame, with the provided scope chain, with the semantics of either a direct
  * or indirect eval (see ES5 10.4.2).  If this is an indirect eval, scopeobj
  * must be a global object.
  *
  * On success, store the completion value in call.rval and return true.
  */
 static bool
-EvalKernel(JSContext *cx, const CallArgs &call, EvalType evalType, StackFrame *caller,
+EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, StackFrame *caller,
            JSObject &scopeobj)
 {
     JS_ASSERT((evalType == INDIRECT_EVAL) == (caller == NULL));
     AssertInnerizedScopeChain(cx, scopeobj);
 
     if (!scopeobj.getGlobal()->isRuntimeCodeGenEnabled(cx)) {
         JS_ReportError(cx, "call to eval() blocked by CSP");
         return false;
     }
 
     /* ES5 15.1.2.1 step 1. */
-    if (call.argc() < 1) {
-        call.rval().setUndefined();
+    if (args.length() < 1) {
+        args.rval().setUndefined();
         return true;
     }
-    if (!call[0].isString()) {
-        call.rval() = call[0];
+    if (!args[0].isString()) {
+        args.rval() = args[0];
         return true;
     }
-    JSString *str = call[0].toString();
+    JSString *str = args[0].toString();
 
     /* ES5 15.1.2.1 steps 2-8. */
 
     /*
      * Per ES5, indirect eval runs in the global scope. (eval is specified this
      * way so that the compiler can make assumptions about what bindings may or
      * may not exist in the current frame if it doesn't see 'eval'.)
      */
@@ -1194,17 +1194,17 @@ EvalKernel(JSContext *cx, const CallArgs
             return false;
         thisv = caller->thisValue();
 
 #ifdef DEBUG
         jsbytecode *callerPC = caller->pcQuadratic(cx);
         JS_ASSERT(callerPC && js_GetOpcode(cx, caller->script(), callerPC) == JSOP_EVAL);
 #endif
     } else {
-        JS_ASSERT(call.callee().getGlobal() == &scopeobj);
+        JS_ASSERT(args.callee().getGlobal() == &scopeobj);
         staticLevel = 0;
 
         /* Use the global as 'this', modulo outerization. */
         JSObject *thisobj = scopeobj.thisObject(cx);
         if (!thisobj)
             return false;
         thisv = ObjectValue(*thisobj);
     }
@@ -1245,25 +1245,25 @@ EvalKernel(JSContext *cx, const CallArgs
             if (cp == end) {
                 JSONParser parser(cx, chars + 1, length - 2,
                                   JSONParser::StrictJSON, JSONParser::NoError);
                 Value tmp;
                 if (!parser.parse(&tmp))
                     return false;
                 if (tmp.isUndefined())
                     break;
-                call.rval() = tmp;
+                args.rval() = tmp;
                 return true;
             }
         }
     }
 
     EvalScriptGuard esg(cx, linearStr);
 
-    JSPrincipals *principals = PrincipalsForCompiledCode(call, cx);
+    JSPrincipals *principals = PrincipalsForCompiledCode(args, cx);
 
     if (evalType == DIRECT_EVAL && caller->isNonEvalFunctionFrame())
         esg.lookupInEvalCache(caller, staticLevel, principals, scopeobj);
 
     if (!esg.foundScript()) {
         uintN lineno;
         const char *filename = CurrentScriptFileAndLine(cx, &lineno,
                                                         evalType == DIRECT_EVAL
@@ -1275,28 +1275,28 @@ EvalKernel(JSContext *cx, const CallArgs
                                                      cx->findVersion(), linearStr, staticLevel);
         if (!compiled)
             return false;
 
         esg.setNewScript(compiled);
     }
 
     return ExecuteKernel(cx, esg.script(), scopeobj, thisv, ExecuteType(evalType),
-                         NULL /* evalInFrame */, &call.rval());
+                         NULL /* evalInFrame */, &args.rval());
 }
 
 /*
  * We once supported a second argument to eval to use as the scope chain
  * when evaluating the code string.  Warn when such uses are seen so that
  * authors will know that support for eval(s, o) has been removed.
  */
 static inline bool
-WarnOnTooManyArgs(JSContext *cx, const CallArgs &call)
-{
-    if (call.argc() > 1) {
+WarnOnTooManyArgs(JSContext *cx, const CallArgs &args)
+{
+    if (args.length() > 1) {
         if (JSScript *script = cx->stack.currentScript()) {
             if (!script->warnedAboutTwoArgumentEval) {
                 static const char TWO_ARGUMENT_WARNING[] =
                     "Support for eval(code, scopeObject) has been removed. "
                     "Use |with (scopeObject) eval(code);| instead.";
                 if (!JS_ReportWarning(cx, TWO_ARGUMENT_WARNING))
                     return false;
                 script->warnedAboutTwoArgumentEval = true;
@@ -1317,54 +1317,54 @@ namespace js {
 /*
  * ES5 15.1.2.1.
  *
  * NB: This method handles only indirect eval.
  */
 JSBool
 eval(JSContext *cx, uintN argc, Value *vp)
 {
-    CallArgs call = CallArgsFromVp(argc, vp);
-    return WarnOnTooManyArgs(cx, call) &&
-           EvalKernel(cx, call, INDIRECT_EVAL, NULL, *call.callee().getGlobal());
+    CallArgs args = CallArgsFromVp(argc, vp);
+    return WarnOnTooManyArgs(cx, args) &&
+           EvalKernel(cx, args, INDIRECT_EVAL, NULL, *args.callee().getGlobal());
 }
 
 bool
-DirectEval(JSContext *cx, const CallArgs &call)
+DirectEval(JSContext *cx, const CallArgs &args)
 {
     /* Direct eval can assume it was called from an interpreted frame. */
     StackFrame *caller = cx->fp();
     JS_ASSERT(caller->isScriptFrame());
-    JS_ASSERT(IsBuiltinEvalForScope(&caller->scopeChain(), call.calleev()));
+    JS_ASSERT(IsBuiltinEvalForScope(&caller->scopeChain(), args.calleev()));
     JS_ASSERT(js_GetOpcode(cx, cx->fp()->script(), cx->regs().pc) == JSOP_EVAL);
 
-    AutoFunctionCallProbe callProbe(cx, call.callee().getFunctionPrivate(), caller->script());
+    AutoFunctionCallProbe callProbe(cx, args.callee().getFunctionPrivate(), caller->script());
 
     JSObject *scopeChain =
         GetScopeChainFast(cx, caller, JSOP_EVAL, JSOP_EVAL_LENGTH + JSOP_LINENO_LENGTH);
 
     return scopeChain &&
-           WarnOnTooManyArgs(cx, call) &&
-           EvalKernel(cx, call, DIRECT_EVAL, caller, *scopeChain);
+           WarnOnTooManyArgs(cx, args) &&
+           EvalKernel(cx, args, DIRECT_EVAL, caller, *scopeChain);
 }
 
 bool
 IsBuiltinEvalForScope(JSObject *scopeChain, const Value &v)
 {
     return scopeChain->getGlobal()->getOriginalEval() == v;
 }
 
 bool
 IsAnyBuiltinEval(JSFunction *fun)
 {
     return fun->maybeNative() == eval;
 }
 
 JSPrincipals *
-PrincipalsForCompiledCode(const CallArgs &call, JSContext *cx)
+PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx)
 {
     JS_ASSERT(IsAnyBuiltinEval(call.callee().getFunctionPrivate()) ||
               IsBuiltinFunctionConstructor(call.callee().getFunctionPrivate()));
 
     /*
      * To compute the principals of the compiled eval/Function code, we simply
      * use the callee's principals. To see why the caller's principals are
      * ignored, consider first that, in the capability-model we assume, the
@@ -1605,77 +1605,77 @@ js_PropertyIsEnumerable(JSContext *cx, J
 const char js_defineGetter_str[] = "__defineGetter__";
 const char js_defineSetter_str[] = "__defineSetter__";
 const char js_lookupGetter_str[] = "__lookupGetter__";
 const char js_lookupSetter_str[] = "__lookupSetter__";
 
 JS_FRIEND_API(JSBool)
 js_obj_defineGetter(JSContext *cx, uintN argc, Value *vp)
 {
-    CallArgs call = CallArgsFromVp(argc, vp);
-    if (!BoxNonStrictThis(cx, call))
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (!BoxNonStrictThis(cx, args))
         return false;
-    JSObject *obj = &call.thisv().toObject();
-
-    if (argc <= 1 || !js_IsCallable(call[1])) {
+    JSObject *obj = &args.thisv().toObject();
+
+    if (args.length() <= 1 || !js_IsCallable(args[1])) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BAD_GETTER_OR_SETTER,
                              js_getter_str);
         return JS_FALSE;
     }
-    PropertyOp getter = CastAsPropertyOp(&call[1].toObject());
+    PropertyOp getter = CastAsPropertyOp(&args[1].toObject());
 
     jsid id;
-    if (!ValueToId(cx, call[0], &id))
+    if (!ValueToId(cx, args[0], &id))
         return JS_FALSE;
     if (!CheckRedeclaration(cx, obj, id, JSPROP_GETTER))
         return JS_FALSE;
     /*
      * Getters and setters are just like watchpoints from an access
      * control point of view.
      */
     Value junk;
     uintN attrs;
     if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs))
         return JS_FALSE;
-    call.rval().setUndefined();
+    args.rval().setUndefined();
     return obj->defineProperty(cx, id, UndefinedValue(), getter, JS_StrictPropertyStub,
                                JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED);
 }
 
 JS_FRIEND_API(JSBool)
 js_obj_defineSetter(JSContext *cx, uintN argc, Value *vp)
 {
-    CallArgs call = CallArgsFromVp(argc, vp);
-    if (!BoxNonStrictThis(cx, call))
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (!BoxNonStrictThis(cx, args))
         return false;
-    JSObject *obj = &call.thisv().toObject();
-
-    if (argc <= 1 || !js_IsCallable(call[1])) {
+    JSObject *obj = &args.thisv().toObject();
+
+    if (args.length() <= 1 || !js_IsCallable(args[1])) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                              JSMSG_BAD_GETTER_OR_SETTER,
                              js_setter_str);
         return JS_FALSE;
     }
-    StrictPropertyOp setter = CastAsStrictPropertyOp(&call[1].toObject());
+    StrictPropertyOp setter = CastAsStrictPropertyOp(&args[1].toObject());
 
     jsid id;
-    if (!ValueToId(cx, call[0], &id))
+    if (!ValueToId(cx, args[0], &id))
         return JS_FALSE;
     if (!CheckRedeclaration(cx, obj, id, JSPROP_SETTER))
         return JS_FALSE;
     /*
      * Getters and setters are just like watchpoints from an access
      * control point of view.
      */
     Value junk;
     uintN attrs;
     if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs))
         return JS_FALSE;
-    call.rval().setUndefined();
+    args.rval().setUndefined();
     return obj->defineProperty(cx, id, UndefinedValue(), JS_PropertyStub, setter,
                                JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED);
 }
 
 static JSBool
 obj_lookupGetter(JSContext *cx, uintN argc, Value *vp)
 {
     jsid id;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -2204,35 +2204,35 @@ extern JSString *
 obj_toStringHelper(JSContext *cx, JSObject *obj);
 
 extern JSBool
 eval(JSContext *cx, uintN argc, Value *vp);
 
 /*
  * Performs a direct eval for the given arguments, which must correspond to the
  * currently-executing stack frame, which must be a script frame. On completion
- * the result is returned in call.rval.
+ * the result is returned in args.rval.
  */
 extern JS_REQUIRES_STACK bool
-DirectEval(JSContext *cx, const CallArgs &call);
+DirectEval(JSContext *cx, const CallArgs &args);
 
 /*
  * True iff |v| is the built-in eval function for the global object that
  * corresponds to |scopeChain|.
  */
 extern bool
 IsBuiltinEvalForScope(JSObject *scopeChain, const js::Value &v);
 
 /* True iff fun is a built-in eval function. */
 extern bool
 IsAnyBuiltinEval(JSFunction *fun);
 
 /* 'call' should be for the eval/Function native invocation. */
 extern JSPrincipals *
-PrincipalsForCompiledCode(const CallArgs &call, JSContext *cx);
+PrincipalsForCompiledCode(const CallReceiver &call, JSContext *cx);
 
 extern JSObject *
 NonNullObject(JSContext *cx, const Value &v);
 
 extern const char *
 InformalValueTypeName(const Value &v);
 }
 
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -517,21 +517,16 @@ Class js::RegExpClass = {
 
 /*
  * RegExp instance methods.
  */
 
 JSBool
 js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp)
 {
-    if (!obj->isRegExp()) {
-        ReportIncompatibleMethod(cx, vp, &RegExpClass);
-        return false;
-    }
-
     RegExp *re = RegExp::extractFrom(obj);
     if (!re) {
         *vp = StringValue(cx->runtime->emptyString);
         return true;
     }
 
     JSLinearString *src = re->getSource();
     StringBuffer sb(cx);
@@ -559,20 +554,26 @@ js_regexp_toString(JSContext *cx, JSObje
         return false;
     *vp = StringValue(str);
     return true;
 }
 
 static JSBool
 regexp_toString(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
-    return js_regexp_toString(cx, obj, vp);
+    if (!obj->isRegExp()) {
+        ReportIncompatibleMethod(cx, args, &RegExpClass);
+        return false;
+    }
+
+    return js_regexp_toString(cx, obj, &args.rval());
 }
 
 /*
  * Return:
  * - The original if no escaping need be performed.
  * - A new string if escaping need be performed.
  * - NULL on error.
  */
@@ -633,37 +634,38 @@ enum ExecType { RegExpExec, RegExpTest }
  *
  * RegExp.prototype.test doesn't need to create a results array, and we use
  * |execType| to perform this optimization.
  */
 static JSBool
 ExecuteRegExp(JSContext *cx, ExecType execType, uintN argc, Value *vp)
 {
     /* Step 1. */
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (!obj->isRegExp()) {
-        ReportIncompatibleMethod(cx, vp, &RegExpClass);
+        ReportIncompatibleMethod(cx, args, &RegExpClass);
         return false;
     }
 
     RegExp *re = RegExp::extractFrom(obj);
     if (!re)
         return true;
 
     /*
      * Code execution under this call could swap out the guts of |obj|, so we
      * have to take a defensive refcount here.
      */
     AutoRefCount<RegExp> arc(cx, NeedsIncRef<RegExp>(re));
     RegExpStatics *res = cx->regExpStatics();
 
     /* Step 2. */
-    JSString *input = js_ValueToString(cx, argc > 0 ?  vp[2] : UndefinedValue());    
+    JSString *input = js_ValueToString(cx, args.length() > 0 ?  args[0] : UndefinedValue());    
     if (!input)
         return false;
     
     /* Step 3. */
     size_t length = input->length();
 
     /* Step 4. */
     const Value &lastIndex = obj->getRegExpLastIndex();
@@ -675,28 +677,28 @@ ExecuteRegExp(JSContext *cx, ExecType ex
 
     /* Steps 6-7 (with sticky extension). */
     if (!re->global() && !re->sticky())
         i = 0;
 
     /* Step 9a. */
     if (i < 0 || i > length) {
         obj->zeroRegExpLastIndex();
-        *vp = NullValue();
+        args.rval() = NullValue();
         return true;
     }
 
     /* Steps 8-21. */
     size_t lastIndexInt(i);
-    if (!re->execute(cx, res, input, &lastIndexInt, execType == RegExpTest, vp))
+    if (!re->execute(cx, res, input, &lastIndexInt, execType == RegExpTest, &args.rval()))
         return false;
 
     /* Step 11 (with sticky extension). */
-    if (re->global() || (!vp->isNull() && re->sticky())) {
-        if (vp->isNull())
+    if (re->global() || (!args.rval().isNull() && re->sticky())) {
+        if (args.rval().isNull())
             obj->zeroRegExpLastIndex();
         else
             obj->setRegExpLastIndex(lastIndexInt);
     }
 
     return true;
 }
 
@@ -783,25 +785,25 @@ CompileRegExpAndSwap(JSContext *cx, JSOb
         return false;
 
     return SwapRegExpInternals(cx, obj, rval, escapedSourceStr, flags);
 }
 
 static JSBool
 regexp_compile(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (!obj->isRegExp()) {
-        ReportIncompatibleMethod(cx, vp, &RegExpClass);
+        ReportIncompatibleMethod(cx, args, &RegExpClass);
         return false;
     }
-
-    return CompileRegExpAndSwap(cx, obj, argc, JS_ARGV(cx, vp), &JS_RVAL(cx, vp));
+    return CompileRegExpAndSwap(cx, obj, args.length(), args.array(), &args.rval());
 }
 
 static JSBool
 regexp_construct(JSContext *cx, uintN argc, Value *vp)
 {
     Value *argv = JS_ARGV(cx, vp);
 
     if (!IsConstructing(vp)) {
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -452,18 +452,20 @@ str_quote(JSContext *cx, uintN argc, Val
         return false;
     vp->setString(str);
     return true;
 }
 
 static JSBool
 str_toSource(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     JSString *str;
-    if (!GetPrimitiveThis(cx, vp, &str))
+    if (!GetPrimitiveThis(cx, args, &str))
         return false;
 
     str = js_QuoteString(cx, str, '"');
     if (!str)
         return false;
 
     char buf[16];
     size_t j = JS_snprintf(buf, sizeof buf, "(new String(");
@@ -488,29 +490,31 @@ str_toSource(JSContext *cx, uintN argc, 
     t[i++] = ')';
     t[i] = 0;
 
     str = js_NewString(cx, t, n);
     if (!str) {
         cx->free_(t);
         return false;
     }
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 
 #endif /* JS_HAS_TOSOURCE */
 
 JSBool
 js_str_toString(JSContext *cx, uintN argc, Value *vp)
 {
+    CallArgs args = CallArgsFromVp(argc, vp);
+
     JSString *str;
-    if (!GetPrimitiveThis(cx, vp, &str))
+    if (!GetPrimitiveThis(cx, args, &str))
         return false;
-    vp->setString(str);
+    args.rval().setString(str);
     return true;
 }
 
 /*
  * Java-like string native methods.
  */
  
 JS_ALWAYS_INLINE bool
@@ -2082,17 +2086,17 @@ str_replace_flat_lambda(JSContext *cx, u
     static const uint32 lambdaArgc = 3;
     if (!cx->stack.pushInvokeArgs(cx, lambdaArgc, &rdata.args))
         return false;
 
     CallArgs &args = rdata.args;
     args.calleev().setObject(*rdata.lambda);
     args.thisv().setUndefined();
 
-    Value *sp = args.argv();
+    Value *sp = args.array();
     sp[0].setString(matchStr);
     sp[1].setInt32(fm.match());
     sp[2].setString(rdata.str);
 
     if (!Invoke(cx, rdata.args))
         return false;
 
     JSString *repstr = js_ValueToString(cx, args.rval());
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1378,48 +1378,48 @@ class TypedArrayTemplate
         /* (obj, byteOffset, length) */
         return createTypedArrayWithOffsetLength(cx, dataObj, byteOffset, length);
     }
 
     /* subarray(start[, end]) */
     static JSBool
     fun_subarray(JSContext *cx, uintN argc, Value *vp)
     {
-        JSObject *obj = ToObject(cx, &vp[1]);
+        CallArgs args = CallArgsFromVp(argc, vp);
+        JSObject *obj = ToObject(cx, &args.thisv());
         if (!obj)
             return false;
 
         if (obj->getClass() != fastClass()) {
             // someone tried to apply this subarray() to the wrong class
-            ReportIncompatibleMethod(cx, vp, fastClass());
+            ReportIncompatibleMethod(cx, args, fastClass());
             return false;
         }
 
         JSObject *tarray = getTypedArray(obj);
         if (!tarray)
             return true;
 
         // these are the default values
         int32_t begin = 0, end = getLength(tarray);
         int32_t length = int32(getLength(tarray));
 
-        if (argc > 0) {
-            Value *argv = JS_ARGV(cx, vp);
-            if (!ValueToInt32(cx, argv[0], &begin))
+        if (args.length() > 0) {
+            if (!ValueToInt32(cx, args[0], &begin))
                 return false;
             if (begin < 0) {
                 begin += length;
                 if (begin < 0)
                     begin = 0;
             } else if (begin > length) {
                 begin = length;
             }
 
-            if (argc > 1) {
-                if (!ValueToInt32(cx, argv[1], &end))
+            if (args.length() > 1) {
+                if (!ValueToInt32(cx, args[1], &end))
                     return false;
                 if (end < 0) {
                     end += length;
                     if (end < 0)
                         end = 0;
                 } else if (end > length) {
                     end = length;
                 }
@@ -1427,64 +1427,64 @@ class TypedArrayTemplate
         }
 
         if (begin > end)
             begin = end;
 
         JSObject *nobj = createSubarray(cx, tarray, begin, end);
         if (!nobj)
             return false;
-        vp->setObject(*nobj);
+        args.rval().setObject(*nobj);
         return true;
     }
 
     /* set(array[, offset]) */
     static JSBool
     fun_set(JSContext *cx, uintN argc, Value *vp)
     {
-        JSObject *obj = ToObject(cx, &vp[1]);
+        CallArgs args = CallArgsFromVp(argc, vp);
+        JSObject *obj = ToObject(cx, &args.thisv());
         if (!obj)
             return false;
 
         if (obj->getClass() != fastClass()) {
             // someone tried to apply this set() to the wrong class
-            ReportIncompatibleMethod(cx, vp, fastClass());
+            ReportIncompatibleMethod(cx, args, fastClass());
             return false;
         }
 
         JSObject *tarray = getTypedArray(obj);
         if (!tarray)
             return true;
 
         // these are the default values
         int32_t off = 0;
 
-        Value *argv = JS_ARGV(cx, vp);
-        if (argc > 1) {
-            if (!ValueToInt32(cx, argv[1], &off))
+        if (args.length() > 1) {
+            if (!ValueToInt32(cx, args[1], &off))
                 return false;
 
             if (off < 0 || uint32_t(off) > getLength(tarray)) {
                 // the given offset is bogus
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
         }
 
         uint32 offset(off);
 
         // first arg must be either a typed array or a JS array
-        if (argc == 0 || !argv[0].isObject()) {
+        if (args.length() == 0 || !args[0].isObject()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                  JSMSG_TYPED_ARRAY_BAD_ARGS);
             return false;
         }
 
-        JSObject *arg0 = argv[0].toObjectOrNull();
+        JSObject *arg0 = args[0].toObjectOrNull();
         if (js_IsTypedArray(arg0)) {
             JSObject *src = TypedArray::getTypedArray(arg0);
             if (!src ||
                 getLength(src) > getLength(tarray) - offset)
             {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
@@ -1503,17 +1503,17 @@ class TypedArrayTemplate
                                      JSMSG_TYPED_ARRAY_BAD_ARGS);
                 return false;
             }
 
             if (!copyFromArray(cx, obj, arg0, len, offset))
                 return false;
         }
 
-        vp->setUndefined();
+        args.rval().setUndefined();
         return true;
     }
 
   public:
     static JSObject *
     createTypedArrayWithOffsetLength(JSContext *cx, JSObject *other,
                                      int32 byteOffsetInt, int32 lengthInt)
     {
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -97,138 +97,142 @@ NonNullObject(JSContext *cx, Value *vp)
         return NULL;
     }
     return &vp->toObject();
 }
 
 static JSBool
 WeakMap_has(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (!obj->isWeakMap()) {
-        ReportIncompatibleMethod(cx, vp, &WeakMapClass);
+        ReportIncompatibleMethod(cx, args, &WeakMapClass);
         return false;
     }
-    if (argc < 1) {
+    if (args.length() < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "WeakMap.has", "0", "s");
         return false;
     }
-    JSObject *key = NonNullObject(cx, &vp[2]);
+    JSObject *key = NonNullObject(cx, &args[0]);
     if (!key)
         return false;
     ObjectValueMap *map = GetObjectMap(obj);
     if (map) {
         ObjectValueMap::Ptr ptr = map->lookup(key);
         if (ptr) {
-            *vp = BooleanValue(true);
+            args.rval() = BooleanValue(true);
             return true;
         }
     }
 
-    *vp = BooleanValue(false);
+    args.rval() = BooleanValue(false);
     return true;
 }
 
 static JSBool
 WeakMap_get(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (!obj->isWeakMap()) {
-        ReportIncompatibleMethod(cx, vp, &WeakMapClass);
+        ReportIncompatibleMethod(cx, args, &WeakMapClass);
         return false;
     }
-    if (argc < 1) {
+    if (args.length() < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "WeakMap.get", "0", "s");
         return false;
     }
-    JSObject *key = NonNullObject(cx, &vp[2]);
+    JSObject *key = NonNullObject(cx, &args[0]);
     if (!key)
         return false;
     ObjectValueMap *map = GetObjectMap(obj);
     if (map) {
         ObjectValueMap::Ptr ptr = map->lookup(key);
         if (ptr) {
-            *vp = ptr->value;
+            args.rval() = ptr->value;
             return true;
         }
     }
 
-    *vp = (argc > 1) ? vp[3] : UndefinedValue();
+    args.rval() = (args.length() > 1) ? args[1] : UndefinedValue();
     return true;
 }
 
 static JSBool
 WeakMap_delete(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (!obj->isWeakMap()) {
-        ReportIncompatibleMethod(cx, vp, &WeakMapClass);
+        ReportIncompatibleMethod(cx, args, &WeakMapClass);
         return false;
     }
-    if (argc < 1) {
+    if (args.length() < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "WeakMap.delete", "0", "s");
         return false;
     }
-    JSObject *key = NonNullObject(cx, &vp[2]);
+    JSObject *key = NonNullObject(cx, &args[0]);
     if (!key)
         return false;
     ObjectValueMap *map = GetObjectMap(obj);
     if (map) {
         ObjectValueMap::Ptr ptr = map->lookup(key);
         if (ptr) {
             map->remove(ptr);
-            *vp = BooleanValue(true);
+            args.rval() = BooleanValue(true);
             return true;
         }
     }
 
-    *vp = BooleanValue(false);
+    args.rval() = BooleanValue(false);
     return true;
 }
 
 static JSBool
 WeakMap_set(JSContext *cx, uintN argc, Value *vp)
 {
-    JSObject *obj = ToObject(cx, &vp[1]);
+    CallArgs args = CallArgsFromVp(argc, vp);
+    JSObject *obj = ToObject(cx, &args.thisv());
     if (!obj)
         return false;
     if (!obj->isWeakMap()) {
-        ReportIncompatibleMethod(cx, vp, &WeakMapClass);
+        ReportIncompatibleMethod(cx, args, &WeakMapClass);
         return false;
     }
-    if (argc < 1) {
+    if (args.length() < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "WeakMap.set", "0", "s");
         return false;
     }
-    JSObject *key = NonNullObject(cx, &vp[2]);
+    JSObject *key = NonNullObject(cx, &args[0]);
     if (!key)
         return false;
-    Value value = (argc > 1) ? vp[3] : UndefinedValue();
+    Value value = (args.length() > 1) ? args[1] : UndefinedValue();
 
     ObjectValueMap *map = GetObjectMap(obj);
     if (!map) {
         map = cx->new_<ObjectValueMap>(cx);
         if (!map->init()) {
             cx->delete_(map);
             goto out_of_memory;
         }
         obj->setPrivate(map);
     }
 
-    *vp = UndefinedValue();
+    args.thisv() = UndefinedValue();
     if (!map->put(key, value))
         goto out_of_memory;
     return true;
 
   out_of_memory:
     JS_ReportOutOfMemory(cx);
     return false;
 }
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -248,17 +248,17 @@ static JSPropertySpec namespace_props[] 
 
 static JSBool
 namespace_toString(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return JS_FALSE;
     if (!obj->isNamespace()) {
-        ReportIncompatibleMethod(cx, vp, &NamespaceClass);
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &NamespaceClass);
         return JS_FALSE;
     }
     *vp = obj->getNameURIVal();
     return JS_TRUE;
 }
 
 static JSFunctionSpec namespace_methods[] = {
     JS_FN(js_toString_str,  namespace_toString,        0,0),
@@ -443,17 +443,17 @@ ConvertQNameToString(JSContext *cx, JSOb
 static JSBool
 qname_toString(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!obj->isQName()) {
-        ReportIncompatibleMethod(cx, vp, &QNameClass);
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &QNameClass);
         return false;
     }
 
     JSString *str = ConvertQNameToString(cx, obj);
     if (!str)
         return false;
 
     vp->setString(str);
@@ -5326,17 +5326,17 @@ StartNonListXMLMethod(JSContext *cx, jsv
 
     JS_ASSERT(!JSVAL_IS_PRIMITIVE(*vp));
     JS_ASSERT(JSVAL_TO_OBJECT(*vp)->isFunction());
 
     *objp = ToObject(cx, &vp[1]);
     if (!*objp)
         return NULL;
     if (!(*objp)->isXML()) {
-        ReportIncompatibleMethod(cx, vp, &XMLClass);
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);
         return NULL;
     }
     xml = (JSXML *) (*objp)->getPrivate();
     if (!xml || xml->xml_class != JSXML_CLASS_LIST)
         return xml;
 
     if (xml->xml_kids.length == 1) {
         xml = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML);
@@ -5360,17 +5360,17 @@ StartNonListXMLMethod(JSContext *cx, jsv
 }
 
 /* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */
 #define XML_METHOD_PROLOG                                                     \
     JSObject *obj = ToObject(cx, &vp[1]);                                     \
     if (!obj)                                                                 \
         return JS_FALSE;                                                      \
     if (!obj->isXML()) {                                                      \
-        ReportIncompatibleMethod(cx, vp, &XMLClass);                          \
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);      \
         return JS_FALSE;                                                      \
     }                                                                         \
     JSXML *xml = (JSXML *)obj->getPrivate();                                  \
     if (!xml)                                                                 \
         return JS_FALSE
 
 #define NON_LIST_XML_METHOD_PROLOG                                            \
     JSObject *obj;                                                            \
@@ -5847,17 +5847,17 @@ xml_hasOwnProperty(JSContext *cx, uintN 
 {
     jsval name;
     JSBool found;
 
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return JS_FALSE;
     if (!obj->isXML()) {
-        ReportIncompatibleMethod(cx, vp, &XMLClass);
+        ReportIncompatibleMethod(cx, CallReceiverFromVp(vp), &XMLClass);
         return JS_FALSE;
     }
 
     name = argc != 0 ? vp[2] : JSVAL_VOID;
     if (!HasProperty(cx, obj, name, &found))
         return JS_FALSE;
     if (found) {
         *vp = JSVAL_TRUE;
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -3559,17 +3559,17 @@ ApplyOrCall(JSContext *cx, uintN argc, V
                 return false;
             callArgc = uintN(JS_MIN(callArgc, StackSpace::ARGS_LENGTH_MAX));
             if (!argv.growBy(callArgc) || !GetElements(cx, argsobj, callArgc, argv.begin()))
                 return false;
             callArgv = argv.begin();
         }
     } else {
         callArgc = argc > 0 ? uintN(JS_MIN(argc - 1, StackSpace::ARGS_LENGTH_MAX)) : 0;
-        callArgv = args.argv() + 1;
+        callArgv = args.array() + 1;
     }
     for (uintN i = 0; i < callArgc; i++) {
         if (!dbg->unwrapDebuggeeValue(cx, &callArgv[i]))
             return false;
     }
 
     /*
      * Enter the debuggee compartment and rewrap all input value for that compartment.
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -494,25 +494,25 @@ ContextStack::getCallFrame(JSContext *cx
     Value *firstUnused = args.end();
     JS_ASSERT(firstUnused == space().firstUnused());
 
     /* Include extra space to satisfy the method-jit stackLimit invariant. */
     uintN nvals = VALUES_PER_STACK_FRAME + script->nslots + StackSpace::STACK_JIT_EXTRA;
 
     /* Maintain layout invariant: &formalArgs[0] == ((Value *)fp) - nformal. */
 
-    if (args.argc() == nformal) {
+    if (args.length() == nformal) {
         if (!space().ensureSpace(cx, report, firstUnused, nvals))
             return NULL;
         return reinterpret_cast<StackFrame *>(firstUnused);
     }
 
-    if (args.argc() < nformal) {
+    if (args.length() < nformal) {
         *flags = StackFrame::Flags(*flags | StackFrame::UNDERFLOW_ARGS);
-        uintN nmissing = nformal - args.argc();
+        uintN nmissing = nformal - args.length();
         if (!space().ensureSpace(cx, report, firstUnused, nmissing + nvals))
             return NULL;
         SetValueRangeToUndefined(firstUnused, nmissing);
         return reinterpret_cast<StackFrame *>(firstUnused + nmissing);
     }
 
     *flags = StackFrame::Flags(*flags | StackFrame::OVERFLOW_ARGS);
     uintN ncopy = 2 + nformal;
@@ -536,17 +536,17 @@ ContextStack::pushInlineFrame(JSContext 
     JS_ASSERT(fun->script() == script);
 
     StackFrame::Flags flags = ToFrameFlags(initial);
     StackFrame *fp = getCallFrame(cx, REPORT_ERROR, args, fun, script, &flags);
     if (!fp)
         return false;
 
     /* Initialize frame, locals, regs. */
-    fp->initCallFrame(cx, callee, fun, script, args.argc(), flags);
+    fp->initCallFrame(cx, callee, fun, script, args.length(), flags);
 
     /*
      * N.B. regs may differ from the active registers, if the parent is about
      * to repoint the active registers to regs. See UncachedInlineCall.
      */
     regs.prepareToRun(*fp, script);
     return true;
 }
@@ -573,17 +573,17 @@ ContextStack::getFixupFrame(JSContext *c
 
     StackFrame::Flags flags = ToFrameFlags(initial);
     StackFrame *fp = getCallFrame(cx, report, args, fun, script, &flags);
     if (!fp)
         return NULL;
 
     /* Do not init late prologue or regs; this is done by jit code. */
     fp->initJitFrameCallerHalf(cx->fp(), flags, ncode);
-    fp->initJitFrameEarlyPrologue(fun, args.argc());
+    fp->initJitFrameEarlyPrologue(fun, args.length());
 
     *stackLimit = space().conservativeEnd_;
     return fp;
 }
 
 JS_ALWAYS_INLINE void
 ContextStack::popInlineFrame(FrameRegs &regs)
 {
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -228,18 +228,18 @@ StackSegment::contains(const FrameRegs *
 
 bool
 StackSegment::contains(const CallArgsList *call) const
 {
     if (!call || !calls_)
         return false;
 
     /* NB: this depends on the continuity of segments in memory. */
-    Value *vp = call->argv();
-    bool ret = vp > slotsBegin() && vp <= calls_->argv();
+    Value *vp = call->array();
+    bool ret = vp > slotsBegin() && vp <= calls_->array();
 
     /*
      * :XXX: Disabled. Including this check changes the asymptotic complexity
      * of code which calls this function.
      */
 #if 0
 #ifdef DEBUG
     bool found = false;
@@ -683,17 +683,17 @@ ContextStack::pushInvokeFrame(JSContext 
     JSFunction *fun = callee.getFunctionPrivate();
     JSScript *script = fun->script();
 
     StackFrame::Flags flags = ToFrameFlags(initial);
     StackFrame *fp = getCallFrame(cx, REPORT_ERROR, args, fun, script, &flags);
     if (!fp)
         return false;
 
-    fp->initCallFrame(cx, callee, fun, script, args.argc(), flags);
+    fp->initCallFrame(cx, callee, fun, script, args.length(), flags);
     ifg->regs_.prepareToRun(*fp, script);
 
     ifg->prevRegs_ = seg_->pushRegs(ifg->regs_);
     JS_ASSERT(space().firstUnused() == ifg->regs_.sp);
     ifg->setPushed(*this);
     return true;
 }
 
@@ -1008,17 +1008,17 @@ StackIter::settleOnNewState()
             JS_ASSERT_IF(containsCall, &seg_->calls() == calls_);
             settleOnNewSegment();
         }
 
         /*
          * In case of both a scripted frame and call record, use linear memory
          * ordering to decide which was the most recent.
          */
-        if (containsFrame && (!containsCall || (Value *)fp_ >= calls_->argv())) {
+        if (containsFrame && (!containsCall || (Value *)fp_ >= calls_->array())) {
             /* Nobody wants to see dummy frames. */
             if (fp_->isDummyFrame()) {
                 popFrame();
                 continue;
             }
 
             /*
              * As an optimization, there is no CallArgsList element pushed for
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -234,18 +234,18 @@ class CallArgs : public CallReceiver
 {
   protected:
     uintN argc_;
   public:
     friend CallArgs CallArgsFromVp(uintN, Value *);
     friend CallArgs CallArgsFromArgv(uintN, Value *);
     friend CallArgs CallArgsFromSp(uintN, Value *);
     Value &operator[](unsigned i) const { JS_ASSERT(i < argc_); return argv_[i]; }
-    Value *argv() const { return argv_; }
-    uintN argc() const { return argc_; }
+    Value *array() const { return argv_; }
+    uintN length() const { return argc_; }
     Value *end() const { return argv_ + argc_; }
 };
 
 JS_ALWAYS_INLINE CallArgs
 CallArgsFromArgv(uintN argc, Value *argv)
 {
     CallArgs args;
     args.clearUsedRval();
@@ -1383,21 +1383,21 @@ class StackSegment
         return *calls_;
     }
 
     CallArgsList *maybeCalls() const {
         return calls_;
     }
 
     Value *callArgv() const {
-        return calls_->argv();
+        return calls_->array();
     }
 
     Value *maybeCallArgv() const {
-        return calls_ ? calls_->argv() : NULL;
+        return calls_ ? calls_->array() : NULL;
     }
 
     StackSegment *prevInContext() const {
         return prevInContext_;
     }
 
     StackSegment *prevInMemory() const {
         return prevInMemory_;