From 18ee45583c3f5d0292cdbbf7274f86a2b030d8c1 Mon Sep 17 00:00:00 2001 From: "brendan%mozilla.org" Date: Sat, 21 Jul 2007 21:39:42 +0000 Subject: [PATCH] Fast natives and related optimizations (385393, r=igor). git-svn-id: svn://10.0.0.236/trunk@230576 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/src/js.c | 111 ++--- mozilla/js/src/jsapi.c | 99 ++++- mozilla/js/src/jsapi.h | 61 ++- mozilla/js/src/jsarray.c | 472 ++++++++++++--------- mozilla/js/src/jsarray.h | 2 + mozilla/js/src/jsatom.h | 1 - mozilla/js/src/jsbool.c | 53 +-- mozilla/js/src/jscntxt.c | 8 + mozilla/js/src/jscntxt.h | 9 +- mozilla/js/src/jsdate.c | 574 +++++++++++++------------- mozilla/js/src/jsdbgapi.c | 20 +- mozilla/js/src/jsdbgapi.h | 3 + mozilla/js/src/jsemit.c | 20 +- mozilla/js/src/jsexn.c | 72 ++-- mozilla/js/src/jsfun.c | 151 +++---- mozilla/js/src/jsfun.h | 21 +- mozilla/js/src/jsgc.c | 8 +- mozilla/js/src/jsinterp.c | 726 +++++++++++++++++++------------- mozilla/js/src/jsinterp.h | 14 + mozilla/js/src/jsiter.c | 85 ++-- mozilla/js/src/jsnum.c | 168 ++++---- mozilla/js/src/jsobj.c | 183 +++++---- mozilla/js/src/jsobj.h | 27 +- mozilla/js/src/jsopcode.c | 24 +- mozilla/js/src/jsopcode.tbl | 11 +- mozilla/js/src/jsparse.c | 2 +- mozilla/js/src/jspubtd.h | 6 + mozilla/js/src/jsregexp.c | 67 +-- mozilla/js/src/jsregexp.h | 3 +- mozilla/js/src/jsscript.c | 119 +++--- mozilla/js/src/jsstr.c | 798 ++++++++++++++++++++---------------- mozilla/js/src/jsstr.h | 16 + mozilla/js/src/jsxml.c | 656 ++++++++++++++--------------- 33 files changed, 2567 insertions(+), 2023 deletions(-) diff --git a/mozilla/js/src/js.c b/mozilla/js/src/js.c index 004e0605fee..7526b062f6d 100644 --- a/mozilla/js/src/js.c +++ b/mozilla/js/src/js.c @@ -625,7 +625,7 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Provides a hook for scripts to read a line from stdin. */ static JSBool -ReadLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +ReadLine(JSContext *cx, uintN argc, jsval *vp) { #define BUFSIZE 256 FILE *from; @@ -669,7 +669,7 @@ ReadLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) /* Treat the empty string specially. */ if (buflength == 0) { - *rval = feof(from) ? JSVAL_NULL : JS_GetEmptyStringValue(cx); + *vp = feof(from) ? JSVAL_NULL : JS_GetEmptyStringValue(cx); JS_free(cx, buf); return JS_TRUE; } @@ -693,7 +693,7 @@ ReadLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } @@ -730,7 +730,7 @@ Quit(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +GC(JSContext *cx, uintN argc, jsval *vp) { JSRuntime *rt; uint32 preBytes; @@ -750,18 +750,20 @@ GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #ifdef JS_GCMETER js_DumpGCStats(rt, stdout); #endif + *vp = JSVAL_VOID; return JS_TRUE; } #ifdef JS_GC_ZEAL static JSBool -GCZeal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +GCZeal(JSContext *cx, uintN argc, jsval *vp) { uintN zeal; - if (!JS_ValueToECMAUint32(cx, argv[0], &zeal)) + if (!JS_ValueToECMAUint32(cx, vp[2], &zeal)) return JS_FALSE; JS_SetGCZeal(cx, zeal); + *vp = JSVAL_VOID; return JS_TRUE; } #endif /* JS_GC_ZEAL */ @@ -1030,7 +1032,7 @@ SrcNotes(JSContext *cx, JSScript *script) index = js_GetSrcNoteOffset(sn, 0); JS_GET_SCRIPT_OBJECT(script, index, obj); - fun = (JSFunction *)JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT); bytes = str ? JS_GetStringBytes(str) : "N/A"; fprintf(gOutFile, " function %u (%s)", index, bytes); @@ -1619,13 +1621,14 @@ ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #endif static JSBool -BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +BuildDate(JSContext *cx, uintN argc, jsval *vp) { char version[20] = "\n"; #if JS_VERSION < 150 sprintf(version, " for version %d\n", JS_VERSION); #endif fprintf(gOutFile, "built on %s at %s%s", __DATE__, __TIME__, version); + *vp = JSVAL_VOID; return JS_TRUE; } @@ -1639,17 +1642,18 @@ Clear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -Intern(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +Intern(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - str = JS_ValueToString(cx, argv[0]); + str = JS_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; if (!JS_InternUCStringN(cx, JS_GetStringChars(str), JS_GetStringLength(str))) { return JS_FALSE; } + *vp = JSVAL_VOID; return JS_TRUE; } @@ -1690,7 +1694,7 @@ Seal(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -GetPDA(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +GetPDA(JSContext *cx, uintN argc, jsval *vp) { JSObject *vobj, *aobj, *pdobj; JSBool ok; @@ -1699,7 +1703,7 @@ GetPDA(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) uint32 i; jsval v; - if (!JS_ValueToObject(cx, argv[0], &vobj)) + if (!JS_ValueToObject(cx, vp[2], &vobj)) return JS_FALSE; if (!vobj) return JS_TRUE; @@ -1707,7 +1711,7 @@ GetPDA(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) aobj = JS_NewArrayObject(cx, 0, NULL); if (!aobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(aobj); + *vp = OBJECT_TO_JSVAL(aobj); ok = JS_GetPropertyDescArray(cx, vobj, &pda); if (!ok) @@ -1740,25 +1744,25 @@ GetPDA(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -GetSLX(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +GetSLX(JSContext *cx, uintN argc, jsval *vp) { JSScript *script; - script = ValueToScript(cx, argv[0]); + script = ValueToScript(cx, vp[2]); if (!script) return JS_FALSE; - *rval = INT_TO_JSVAL(js_GetScriptLineExtent(script)); + *vp = INT_TO_JSVAL(js_GetScriptLineExtent(script)); return JS_TRUE; } static JSBool -ToInt32(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +ToInt32(JSContext *cx, uintN argc, jsval *vp) { int32 i; - if (!JS_ValueToInt32(cx, argv[0], &i)) + if (!JS_ValueToInt32(cx, vp[2], &i)) return JS_FALSE; - return JS_NewNumberValue(cx, i, rval); + return JS_NewNumberValue(cx, i, vp); } static JSBool @@ -2224,49 +2228,50 @@ out: return ok; } +/* We use a mix of JS_FS and JS_FN to test both kinds of natives. */ static JSFunctionSpec shell_functions[] = { - {"version", Version, 0,0,0}, - {"options", Options, 0,0,0}, - {"load", Load, 1,0,0}, - {"readline", ReadLine, 0,0,0}, - {"print", Print, 0,0,0}, - {"help", Help, 0,0,0}, - {"quit", Quit, 0,0,0}, - {"gc", GC, 0,0,0}, + JS_FS("version", Version, 0,0,0), + JS_FS("options", Options, 0,0,0), + JS_FS("load", Load, 1,0,0), + JS_FN("readline", ReadLine, 0,0,0,0), + JS_FS("print", Print, 0,0,0), + JS_FS("help", Help, 0,0,0), + JS_FS("quit", Quit, 0,0,0), + JS_FN("gc", GC, 0,0,0,0), #ifdef JS_GC_ZEAL - {"gczeal", GCZeal, 1,0,0}, + JS_FN("gczeal", GCZeal, 1,1,0,0), #endif - {"trap", Trap, 3,0,0}, - {"untrap", Untrap, 2,0,0}, - {"line2pc", LineToPC, 0,0,0}, - {"pc2line", PCToLine, 0,0,0}, - {"stringsAreUTF8", StringsAreUTF8, 0,0,0}, - {"testUTF8", TestUTF8, 1,0,0}, - {"throwError", ThrowError, 0,0,0}, + JS_FS("trap", Trap, 3,0,0), + JS_FS("untrap", Untrap, 2,0,0), + JS_FS("line2pc", LineToPC, 0,0,0), + JS_FS("pc2line", PCToLine, 0,0,0), + JS_FS("stringsAreUTF8", StringsAreUTF8, 0,0,0), + JS_FS("testUTF8", TestUTF8, 1,0,0), + JS_FS("throwError", ThrowError, 0,0,0), #ifdef DEBUG - {"dis", Disassemble, 1,0,0}, - {"dissrc", DisassWithSrc, 1,0,0}, - {"dumpHeap", DumpHeap, 5,0,0}, - {"notes", Notes, 1,0,0}, - {"tracing", Tracing, 0,0,0}, - {"stats", DumpStats, 1,0,0}, + JS_FS("dis", Disassemble, 1,0,0), + JS_FS("dissrc", DisassWithSrc, 1,0,0), + JS_FS("dumpHeap", DumpHeap, 5,0,0), + JS_FS("notes", Notes, 1,0,0), + JS_FS("tracing", Tracing, 0,0,0), + JS_FS("stats", DumpStats, 1,0,0), #endif #ifdef TEST_EXPORT - {"xport", DoExport, 2,0,0}, + JS_FS("xport", DoExport, 2,0,0), #endif #ifdef TEST_CVTARGS - {"cvtargs", ConvertArgs, 0,0,12}, + JS_FS("cvtargs", ConvertArgs, 0,0,12), #endif - {"build", BuildDate, 0,0,0}, - {"clear", Clear, 0,0,0}, - {"intern", Intern, 1,0,0}, - {"clone", Clone, 1,0,0}, - {"seal", Seal, 1,0,1}, - {"getpda", GetPDA, 1,0,0}, - {"getslx", GetSLX, 1,0,0}, - {"toint32", ToInt32, 1,0,0}, - {"evalcx", EvalInContext, 1,0,0}, - {NULL,NULL,0,0,0} + JS_FN("build", BuildDate, 0,0,0,0), + JS_FS("clear", Clear, 0,0,0), + JS_FN("intern", Intern, 1,1,0,0), + JS_FS("clone", Clone, 1,0,0), + JS_FS("seal", Seal, 1,0,1), + JS_FN("getpda", GetPDA, 1,1,0,0), + JS_FN("getslx", GetSLX, 1,1,0,0), + JS_FN("toint32", ToInt32, 1,1,0,0), + JS_FS("evalcx", EvalInContext, 1,0,0), + JS_FS_END }; /* NOTE: These must be kept in sync with the above. */ diff --git a/mozilla/js/src/jsapi.c b/mozilla/js/src/jsapi.c index 8c9003c5020..46140c38624 100644 --- a/mozilla/js/src/jsapi.c +++ b/mozilla/js/src/jsapi.c @@ -4106,6 +4106,65 @@ JS_ObjectIsFunction(JSContext *cx, JSObject *obj) return OBJ_GET_CLASS(cx, obj) == &js_FunctionClass; } +JS_STATIC_DLL_CALLBACK(JSBool) +js_generic_fast_native_method_dispatcher(JSContext *cx, uintN argc, jsval *vp) +{ + jsval fsv; + JSFunctionSpec *fs; + JSObject *tmp; + JSStackFrame *fp; + + if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(*vp), 0, &fsv)) + return JS_FALSE; + fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv); + JS_ASSERT((~fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == 0); + + /* + * We know that vp[2] is valid because JS_DefineFunctions, which is our + * only (indirect) referrer, defined us as requiring at least one argument + * (notice how it passes fs->nargs + 1 as the next-to-last argument to + * JS_DefineFunction). + */ + if (JSVAL_IS_PRIMITIVE(vp[2])) { + /* + * Make sure that this is an object or null, as required by the generic + * functions. + */ + if (!js_ValueToObject(cx, vp[2], &tmp)) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(tmp); + } + + /* + * Copy all actual (argc) arguments down over our |this| parameter, vp[1], + * which is almost always the class constructor object, e.g. Array. Then + * call the corresponding prototype native method with our first argument + * passed as |this|. + */ + memmove(vp + 1, vp + 2, argc * sizeof(jsval)); + + /* + * Follow Function.prototype.apply and .call by using the global object as + * the 'this' param if no args. + */ + fp = cx->fp; + JS_ASSERT((fp->flags & JSFRAME_IN_FAST_CALL) || fp->argv == vp + 2); + if (!js_ComputeThis(cx, vp + 2)) + return JS_FALSE; + if (!(fp->flags & JSFRAME_IN_FAST_CALL)) + fp->thisp = JSVAL_TO_OBJECT(vp[1]); + + /* + * Protect against argc underflowing. By calling js_ComputeThis, we made + * it as if the static was called with one parameter, the explicit |this| + * object. + */ + if (argc != 0) + --argc; + + return ((JSFastNative) fs->call)(cx, argc, vp); +} + JS_STATIC_DLL_CALLBACK(JSBool) js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) @@ -4114,9 +4173,13 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, JSFunctionSpec *fs; JSObject *tmp; + JS_ASSERT(!(cx->fp->flags & JSFRAME_IN_FAST_CALL)); + if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(argv[-2]), 0, &fsv)) return JS_FALSE; fs = (JSFunctionSpec *) JSVAL_TO_PRIVATE(fsv); + JS_ASSERT((fs->flags & (JSFUN_FAST_NATIVE | JSFUN_GENERIC_NATIVE)) == + JSFUN_GENERIC_NATIVE); /* * We know that argv[0] is valid because JS_DefineFunctions, which is our @@ -4135,12 +4198,12 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, } /* - * Copy all actual (argc) and required but missing (fs->nargs + 1 - argc) - * args down over our |this| parameter, argv[-1], which is almost always - * the class constructor object, e.g. Array. Then call the corresponding - * prototype native method with our first argument passed as |this|. + * Copy all actual (argc) arguments down over our |this| parameter, + * argv[-1], which is almost always the class constructor object, e.g. + * Array. Then call the corresponding prototype native method with our + * first argument passed as |this|. */ - memmove(argv - 1, argv, JS_MAX(fs->nargs + 1U, argc) * sizeof(jsval)); + memmove(argv - 1, argv, argc * sizeof(jsval)); /* * Follow Function.prototype.apply and .call by using the global object as @@ -4152,13 +4215,14 @@ js_generic_native_method_dispatcher(JSContext *cx, JSObject *obj, cx->fp->thisp = JSVAL_TO_OBJECT(argv[-1]); /* - * Protect against argc - 1 underflowing below. By calling js_ComputeThis, - * we made it as if the static was called with one parameter. + * Protect against argc underflowing. By calling js_ComputeThis, we made + * it as if the static was called with one parameter, the explicit |this| + * object. */ - if (argc == 0) - argc = 1; + if (argc != 0) + --argc; - return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc - 1, argv, rval); + return fs->call(cx, JSVAL_TO_OBJECT(argv[-1]), argc, argv, rval); } JS_PUBLIC_API(JSBool) @@ -4171,9 +4235,6 @@ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) CHECK_REQUEST(cx); ctor = NULL; for (; fs->name; fs++) { - - /* High bits of fs->extra are reserved. */ - JS_ASSERT((fs->extra & 0xFFFF0000) == 0); flags = fs->flags; /* @@ -4189,11 +4250,15 @@ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) flags &= ~JSFUN_GENERIC_NATIVE; fun = JS_DefineFunction(cx, ctor, fs->name, - js_generic_native_method_dispatcher, + (flags & JSFUN_FAST_NATIVE) + ? (JSNative) + js_generic_fast_native_method_dispatcher + : js_generic_native_method_dispatcher, fs->nargs + 1, flags); if (!fun) return JS_FALSE; fun->u.n.extra = (uint16)fs->extra; + fun->u.n.minargs = (uint16)(fs->extra >> 16); /* * As jsapi.h notes, fs must point to storage that lives as long @@ -4203,10 +4268,13 @@ JS_DefineFunctions(JSContext *cx, JSObject *obj, JSFunctionSpec *fs) return JS_FALSE; } + JS_ASSERT(!(flags & JSFUN_FAST_NATIVE) || + (uint16)(fs->extra >> 16) <= fs->nargs); fun = JS_DefineFunction(cx, obj, fs->name, fs->call, fs->nargs, flags); if (!fun) return JS_FALSE; fun->u.n.extra = (uint16)fs->extra; + fun->u.n.minargs = (uint16)(fs->extra >> 16); } return JS_TRUE; } @@ -4867,6 +4935,7 @@ JS_IsRunning(JSContext *cx) JS_PUBLIC_API(JSBool) JS_IsConstructing(JSContext *cx) { + JS_ASSERT(!cx->fp || !(cx->fp->flags & JSFRAME_IN_FAST_CALL)); return cx->fp && (cx->fp->flags & JSFRAME_CONSTRUCTING); } @@ -4876,6 +4945,7 @@ JS_IsAssigning(JSContext *cx) JSStackFrame *fp; jsbytecode *pc; + JS_ASSERT(!cx->fp || !(cx->fp->flags & JSFRAME_IN_FAST_CALL)); for (fp = cx->fp; fp && !fp->script; fp = fp->down) continue; if (!fp || !(pc = fp->pc)) @@ -4901,6 +4971,7 @@ JS_SaveFrameChain(JSContext *cx) if (!fp) return fp; + JS_ASSERT(!(fp->flags & JSFRAME_IN_FAST_CALL)); JS_ASSERT(!fp->dormantNext); fp->dormantNext = cx->dormantFrameChain; cx->dormantFrameChain = fp; diff --git a/mozilla/js/src/jsapi.h b/mozilla/js/src/jsapi.h index 4aebf93cdbd..2d04c324117 100644 --- a/mozilla/js/src/jsapi.h +++ b/mozilla/js/src/jsapi.h @@ -180,7 +180,9 @@ JS_BEGIN_EXTERN_C #define JSFUN_THISP_BOOLEAN 0x0400 /* |this| may be a primitive boolean */ #define JSFUN_THISP_PRIMITIVE 0x0700 /* |this| may be any primitive value */ -#define JSFUN_FLAGS_MASK 0x07f8 /* overlay JSFUN_* attributes -- +#define JSFUN_FAST_NATIVE 0x0800 /* JSFastNative needs no JSStackFrame */ + +#define JSFUN_FLAGS_MASK 0x0ff8 /* overlay JSFUN_* attributes -- note that bit #15 is used internally to flag interpreted functions */ @@ -642,6 +644,29 @@ JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, extern JS_PUBLIC_API(JSObject *) JS_GetScopeChain(JSContext *cx); +/* + * Macros to hide interpreter stack layout details from a JSFastNative using + * its jsval *vp parameter. The stack layout underlying invocation can't change + * without breaking source and binary compatibility (argv[-2] is well-known to + * be the callee jsval, and argv[-1] is as well known to be |this|). + * + * NB: there is an anti-dependency between JS_CALLEE and JS_SET_RVAL: native + * methods that may inspect their callee must defer setting their return value + * until after any such possible inspection. Otherwise the return value will be + * inspected instead of the callee function object. + * + * WARNING: These are not (yet) mandatory macros, but new code outside of the + * engine should use them. In the Mozilla 2.0 milestone their definitions may + * change incompatibly. + */ +#define JS_CALLEE(cx,vp) ((vp)[0]) +#define JS_ARGV_CALLEE(argv) ((argv)[-2]) +#define JS_THIS(cx,vp) ((vp)[1]) +#define JS_THIS_OBJECT(cx,vp) ((JSObject *) JS_THIS(cx,vp)) +#define JS_ARGV(cx,vp) ((vp) + 2) +#define JS_RVAL(cx,vp) (*(vp)) +#define JS_SET_RVAL(cx,vp,v) (*(vp) = (v)) + extern JS_PUBLIC_API(void *) JS_malloc(JSContext *cx, size_t nbytes); @@ -1375,13 +1400,39 @@ struct JSFunctionSpec { #else uint16 nargs; uint16 flags; - uint32 extra; /* extra & 0xFFFF: - number of arg slots for local GC roots - extra >> 16: - reserved, must be zero */ + + /* + * extra & 0xFFFF: number of arg slots for local GC roots; + * extra >> 16: reserved, must be zero. + */ + uint32 extra; #endif }; +/* + * Terminating sentinel initializer to put at the end of a JSFunctionSpec array + * that's passed to JS_DefineFunctions or JS_InitClass. + */ +#define JS_FS_END JS_FS(NULL,NULL,0,0,0) + +/* + * Initializer macro for a row in a JSFunctionSpec array. This is the original + * kind of native function specifier initializer. Use JS_FN ("fast native", see + * JSFastNative in jspubtd.h) for all functions that do not need a stack frame + * when activated. + */ +#define JS_FS(name,call,nargs,flags,extra) \ + {name, call, nargs, flags, extra} + +/* + * "Fast native" initializer macro for a JSFunctionSpec array element. Use this + * in preference to JS_FS if the native in question does not need its own stack + * frame when activated. + */ +#define JS_FN(name,fastcall,minargs,nargs,flags,extra) \ + {name, (JSNative)(fastcall), nargs, (flags) | JSFUN_FAST_NATIVE, \ + (minargs) << 16 | (uint16)(extra)} + extern JS_PUBLIC_API(JSObject *) JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, JSClass *clasp, JSNative constructor, uintN nargs, diff --git a/mozilla/js/src/jsarray.c b/mozilla/js/src/jsarray.c index 637e04e8ceb..ae8911ae362 100644 --- a/mozilla/js/src/jsarray.c +++ b/mozilla/js/src/jsarray.c @@ -378,26 +378,30 @@ js_IsArrayLike(JSContext *cx, JSObject *obj, JSBool *answerp, jsuint *lengthp) } /* - * This get function is specific to Array.prototype.length and other array - * instance length properties. It calls back through the class get function - * in case some magic happens there (see call_getProperty in jsfun.c). + * The 'length' property of all native Array instances is a shared permanent + * property of Array.prototype, so it appears to be a direct property of each + * array instance delegating to that Array.prototype. It accesses the private + * slot reserved by js_ArrayClass. */ static JSBool array_length_getter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { - return OBJ_GET_CLASS(cx, obj)->getProperty(cx, obj, id, vp); + *vp = (OBJ_GET_CLASS(cx, obj) == &js_ArrayClass) + ? STOBJ_GET_SLOT(obj, JSSLOT_ARRAY_LENGTH) + : JSVAL_ZERO; + return JS_TRUE; } static JSBool array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { jsuint newlen, oldlen, gap, index; - jsid id2; jsval junk; JSObject *iter; JSTempValueRooter tvr; JSBool ok; + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass); if (!ValueIsLength(cx, *vp, &newlen)) return JS_FALSE; if (!js_GetLengthProperty(cx, obj, &oldlen)) @@ -416,7 +420,7 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) * We are going to remove a lot of indexes in a presumably sparse * array. So instead of looping through indexes between newlen and * oldlen, we iterate through all properties and remove those that - * correspond to indexes from the [newlen, oldlen) range. + * correspond to indexes in the half-open range [newlen, oldlen). * See bug 322135. */ iter = JS_NewPropertyIterator(cx, obj); @@ -428,13 +432,13 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) gap = oldlen - newlen; for (;;) { ok = (JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && - JS_NextProperty(cx, iter, &id2)); + JS_NextProperty(cx, iter, &id)); if (!ok) break; - if (id2 == JSVAL_VOID) + if (id == JSVAL_VOID) break; - if (js_IdIsIndex(id2, &index) && index - newlen < gap) { - ok = OBJ_DELETE_PROPERTY(cx, obj, id2, &junk); + if (js_IdIsIndex(id, &index) && index - newlen < gap) { + ok = OBJ_DELETE_PROPERTY(cx, obj, id, &junk); if (!ok) break; } @@ -444,7 +448,10 @@ array_length_setter(JSContext *cx, JSObject *obj, jsval id, jsval *vp) return JS_FALSE; } } - return IndexToValue(cx, newlen, vp); + if (!IndexToValue(cx, newlen, vp)) + return JS_FALSE; + STOBJ_SET_SLOT(obj, JSSLOT_ARRAY_LENGTH, *vp); + return JS_TRUE; } static JSBool @@ -471,7 +478,7 @@ array_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) JSClass js_ArrayClass = { "Array", - JSCLASS_HAS_CACHED_PROTO(JSProto_Array), + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array), array_addProperty, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, array_convert, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS @@ -704,36 +711,42 @@ array_join_sub(JSContext *cx, JSObject *obj, enum ArrayToStringOp op, #if JS_HAS_TOSOURCE static JSBool -array_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_toSource(JSContext *cx, uintN argc, jsval *vp) { - if (!JS_InstanceOf(cx, obj, &js_ArrayClass, argv)) + JSObject *obj; + + obj = JSVAL_TO_OBJECT(vp[1]); + if (!JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) return JS_FALSE; - return array_join_sub(cx, obj, TO_SOURCE, NULL, rval); + return array_join_sub(cx, obj, TO_SOURCE, NULL, vp); } #endif static JSBool -array_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_toString(JSContext *cx, uintN argc, jsval *vp) { - if (!JS_InstanceOf(cx, obj, &js_ArrayClass, argv)) + JSObject *obj; + + obj = JSVAL_TO_OBJECT(vp[1]); + if (!JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) return JS_FALSE; - return array_join_sub(cx, obj, TO_STRING, NULL, rval); + return array_join_sub(cx, obj, TO_STRING, NULL, vp); } static JSBool -array_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_toLocaleString(JSContext *cx, uintN argc, jsval *vp) { - if (!JS_InstanceOf(cx, obj, &js_ArrayClass, argv)) + JSObject *obj; + + obj = JSVAL_TO_OBJECT(vp[1]); + if (!JS_InstanceOf(cx, obj, &js_ArrayClass, vp + 2)) return JS_FALSE; /* * Passing comma here as the separator. Need a way to get a * locale-specific version. */ - return array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, rval); + return array_join_sub(cx, obj, TO_LOCALE_STRING, NULL, vp); } static JSBool @@ -753,49 +766,42 @@ static JSBool InitArrayObject(JSContext *cx, JSObject *obj, jsuint length, jsval *vector) { jsval v; - jsid id; + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass); if (!IndexToValue(cx, length, &v)) return JS_FALSE; - id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom); - if (!OBJ_DEFINE_PROPERTY(cx, obj, id, v, - array_length_getter, array_length_setter, - JSPROP_PERMANENT, - NULL)) { - return JS_FALSE; - } - if (!vector) - return JS_TRUE; - return InitArrayElements(cx, obj, 0, length, vector); + STOBJ_SET_SLOT(obj, JSSLOT_ARRAY_LENGTH, v); + return !vector || InitArrayElements(cx, obj, 0, length, vector); } /* * Perl-inspired join, reverse, and sort. */ static JSBool -array_join(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +array_join(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - if (JSVAL_IS_VOID(argv[0])) { + if (JSVAL_IS_VOID(vp[2])) { str = NULL; } else { - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); + vp[2] = STRING_TO_JSVAL(str); } - return array_join_sub(cx, obj, TO_STRING, str, rval); + return array_join_sub(cx, JS_THIS_OBJECT(cx, vp), TO_STRING, str, vp); } static JSBool -array_reverse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_reverse(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; + jsval *argv, *tmproot, *tmproot2; jsuint len, half, i; JSBool hole, hole2; - jsval *tmproot, *tmproot2; + obj = JS_THIS_OBJECT(cx, vp); if (!js_GetLengthProperty(cx, obj, &len)) return JS_FALSE; @@ -803,6 +809,7 @@ array_reverse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, * Use argv[argc] and argv[argc + 1] as local roots to hold temporarily * array elements for GC-safe swap. */ + argv = JS_ARGV(cx, vp); tmproot = argv + argc; tmproot2 = argv + argc + 1; half = len / 2; @@ -815,7 +822,7 @@ array_reverse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; } } - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } @@ -1068,9 +1075,10 @@ sort_compare_strings(void *arg, const void *a, const void *b, int *result) JS_STATIC_ASSERT(JSVAL_NULL == 0); static JSBool -array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +array_sort(JSContext *cx, uintN argc, jsval *vp) { - jsval fval, *vec, *mergesort_tmp; + jsval *argv, fval, *vec, *mergesort_tmp; + JSObject *obj; CompareArgs ca; jsuint len, newlen, i, undefs; JSTempValueRooter tvr; @@ -1082,6 +1090,7 @@ array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) */ JSBool all_strings; + argv = JS_ARGV(cx, vp); if (argc > 0) { if (JSVAL_IS_PRIMITIVE(argv[0])) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, @@ -1095,10 +1104,11 @@ array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) all_strings = JS_TRUE; /* check for all string values */ } + obj = JS_THIS_OBJECT(cx, vp); if (!js_GetLengthProperty(cx, obj, &len)) return JS_FALSE; if (len == 0) { - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } @@ -1224,7 +1234,7 @@ array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_FALSE; } } - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } @@ -1232,35 +1242,71 @@ array_sort(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Perl-inspired push, pop, shift, unshift, and splice methods. */ static JSBool -array_push(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +slow_array_push(JSContext *cx, JSObject *obj, uintN argc, jsval *vp) { jsuint length, newlength; if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; newlength = length + argc; - if (!InitArrayElements(cx, obj, length, newlength, argv)) + if (!InitArrayElements(cx, obj, length, newlength, vp + 2)) return JS_FALSE; /* Per ECMA-262, return the new array length. */ - if (!IndexToValue(cx, newlength, rval)) + if (!IndexToValue(cx, newlength, vp)) return JS_FALSE; return js_SetLengthProperty(cx, obj, newlength); } static JSBool -array_pop(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +array_push(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; + jsval v; + + /* Insist on one argument and obj of the expected class. */ + obj = JSVAL_TO_OBJECT(vp[1]); + if (argc != 1 || OBJ_GET_CLASS(cx, obj) != &js_ArrayClass) + return slow_array_push(cx, obj, argc, vp); + + /* Beware 'length' int to double jsval overflow. */ + v = STOBJ_GET_SLOT(obj, JSSLOT_ARRAY_LENGTH); + if (!(v & JSVAL_INT) || v == INT_TO_JSVAL(JSVAL_INT_MAX)) + return slow_array_push(cx, obj, argc, vp); + + /* + * Ok, we can optimize to define a new property identified by the + * current value of 'length'. We know no such property exists, + * because if one did, then js_ArrayClass.addProperty would have + * increased the value of 'length' to one greater than this index + * (proof by contradiction). + */ + if (!js_DefineNativeProperty(cx, obj, INT_JSVAL_TO_JSID(v), vp[2], + NULL, NULL, JSPROP_ENUMERATE, 0, 0, + NULL)) { + return JS_FALSE; + } + v += 2; + JS_ASSERT(STOBJ_GET_SLOT(obj, JSSLOT_ARRAY_LENGTH) == v); + *vp = v; + return JS_TRUE; +} + +JSBool +array_pop(JSContext *cx, uintN argc, jsval *vp) +{ + JSObject *obj; jsuint index; JSBool hole; + obj = JS_THIS_OBJECT(cx, vp); if (!js_GetLengthProperty(cx, obj, &index)) return JS_FALSE; if (index > 0) { index--; - /* Get the to-be-deleted property's value into rval. */ - if (!GetArrayElement(cx, obj, index, &hole, rval)) + /* Get the to-be-deleted property's value into vp. */ + if (!GetArrayElement(cx, obj, index, &hole, vp)) return JS_FALSE; if (!hole && !DeleteArrayElement(cx, obj, index)) return JS_FALSE; @@ -1269,29 +1315,32 @@ array_pop(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -array_shift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +array_shift(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; jsuint length, i; JSBool hole; + obj = JS_THIS_OBJECT(cx, vp); if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; if (length == 0) { - *rval = JSVAL_VOID; + *vp = JSVAL_VOID; } else { length--; - /* Get the to-be-deleted property's value into rval ASAP. */ - if (!GetArrayElement(cx, obj, 0, &hole, rval)) + /* Get the to-be-deleted property's value into vp ASAP. */ + if (!GetArrayElement(cx, obj, 0, &hole, vp)) return JS_FALSE; /* - * Slide down the array above the first element. + * Slide down the array above the first element, using our stack-local + * GC root at vp[2]. */ for (i = 0; i != length; i++) { if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || - !GetArrayElement(cx, obj, i + 1, &hole, &argv[0]) || - !SetOrDeleteArrayElement(cx, obj, i, hole, argv[0])) { + !GetArrayElement(cx, obj, i + 1, &hole, &vp[2]) || + !SetOrDeleteArrayElement(cx, obj, i, hole, vp[2])) { return JS_FALSE; } } @@ -1304,25 +1353,28 @@ array_shift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -array_unshift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_unshift(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; + jsval *argv, *localroot; jsuint length, last; - jsval *vp; JSBool hole; + obj = JS_THIS_OBJECT(cx, vp); if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; if (argc > 0) { /* Slide up the array to make room for argc at the bottom. */ + argv = JS_ARGV(cx, vp); if (length > 0) { last = length; - vp = argv + argc; /* local root */ + localroot = argv + argc; do { --last; if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || - !GetArrayElement(cx, obj, last, &hole, vp) || - !SetOrDeleteArrayElement(cx, obj, last + argc, hole, *vp)) { + !GetArrayElement(cx, obj, last, &hole, localroot) || + !SetOrDeleteArrayElement(cx, obj, last + argc, hole, + *localroot)) { return JS_FALSE; } } while (last != 0); @@ -1338,25 +1390,28 @@ array_unshift(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } /* Follow Perl by returning the new array length. */ - return IndexToValue(cx, length, rval); + return IndexToValue(cx, length, vp); } static JSBool -array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +array_splice(JSContext *cx, uintN argc, jsval *vp) { - jsval *vp; + jsval *argv, *localroot; + JSObject *obj; jsuint length, begin, end, count, delta, last; jsdouble d; JSBool hole; JSObject *obj2; /* - * Nothing to do if no args. Otherwise point vp at our one explicit local - * root and get length. + * Nothing to do if no args. Otherwise point localroot at our single + * stack-local root and get length. */ if (argc == 0) return JS_TRUE; - vp = argv + argc; + argv = JS_ARGV(cx, vp); + localroot = argv + argc; + obj = JS_THIS_OBJECT(cx, vp); if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; @@ -1404,18 +1459,18 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) obj2 = js_NewArrayObject(cx, 0, NULL); if (!obj2) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj2); + *vp = OBJECT_TO_JSVAL(obj2); /* If there are elements to remove, put them into the return value. */ if (count > 0) { for (last = begin; last < end; last++) { if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || - !GetArrayElement(cx, obj, last, &hole, vp)) { + !GetArrayElement(cx, obj, last, &hole, localroot)) { return JS_FALSE; } - /* Copy *vp to new array unless it's a hole. */ - if (!hole && !SetArrayElement(cx, obj2, last - begin, *vp)) + /* Copy *localroot to new array unless it's a hole. */ + if (!hole && !SetArrayElement(cx, obj2, last - begin, *localroot)) return JS_FALSE; } @@ -1430,8 +1485,9 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) /* (uint) end could be 0, so can't use vanilla >= test */ while (last-- > end) { if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || - !GetArrayElement(cx, obj, last, &hole, vp) || - !SetOrDeleteArrayElement(cx, obj, last + delta, hole, *vp)) { + !GetArrayElement(cx, obj, last, &hole, localroot) || + !SetOrDeleteArrayElement(cx, obj, last + delta, hole, + *localroot)) { return JS_FALSE; } } @@ -1440,8 +1496,9 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) delta = count - (jsuint)argc; for (last = end; last < length; last++) { if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || - !GetArrayElement(cx, obj, last, &hole, vp) || - !SetOrDeleteArrayElement(cx, obj, last - delta, hole, *vp)) { + !GetArrayElement(cx, obj, last, &hole, localroot) || + !SetOrDeleteArrayElement(cx, obj, last - delta, hole, + *localroot)) { return JS_FALSE; } } @@ -1460,26 +1517,27 @@ array_splice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Python-esque sequence operations. */ static JSBool -array_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +array_concat(JSContext *cx, uintN argc, jsval *vp) { - jsval *vp, v; + jsval *argv, *localroot, v; JSObject *nobj, *aobj; jsuint length, alength, slot; uintN i; JSBool hole; /* Hoist the explicit local root address computation. */ - vp = argv + argc; + argv = JS_ARGV(cx, vp); + localroot = argv + argc; - /* Treat obj as the first argument; see ECMA 15.4.4.4. */ + /* Treat our |this| object as the first argument; see ECMA 15.4.4.4. */ --argv; - JS_ASSERT(obj == JSVAL_TO_OBJECT(argv[0])); + JS_ASSERT(JS_THIS_OBJECT(cx, vp) == JSVAL_TO_OBJECT(argv[0])); - /* Create a new Array object and store it in the rval local root. */ + /* Create a new Array object and root it using *vp. */ nobj = js_NewArrayObject(cx, 0, NULL); if (!nobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(nobj); + *vp = OBJECT_TO_JSVAL(nobj); /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */ length = 0; @@ -1493,14 +1551,14 @@ array_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (!OBJ_GET_PROPERTY(cx, aobj, ATOM_TO_JSID(cx->runtime->atomState .lengthAtom), - vp)) { + localroot)) { return JS_FALSE; } - if (!ValueIsLength(cx, *vp, &alength)) + if (!ValueIsLength(cx, *localroot, &alength)) return JS_FALSE; for (slot = 0; slot < alength; slot++) { if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || - !GetArrayElement(cx, aobj, slot, &hole, vp)) { + !GetArrayElement(cx, aobj, slot, &hole, localroot)) { return JS_FALSE; } @@ -1508,8 +1566,10 @@ array_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Per ECMA 262, 15.4.4.4, step 9, ignore non-existent * properties. */ - if (!hole && !SetArrayElement(cx, nobj, length + slot, *vp)) + if (!hole && + !SetArrayElement(cx, nobj, length + slot, *localroot)) { return JS_FALSE; + } } length += alength; continue; @@ -1525,23 +1585,25 @@ array_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -array_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +array_slice(JSContext *cx, uintN argc, jsval *vp) { - jsval *vp; - JSObject *nobj; + jsval *argv, *localroot; + JSObject *nobj, *obj; jsuint length, begin, end, slot; jsdouble d; JSBool hole; /* Hoist the explicit local root address computation. */ - vp = argv + argc; + argv = JS_ARGV(cx, vp); + localroot = argv + argc; - /* Create a new Array object and store it in the rval local root. */ + /* Create a new Array object and root it using *vp. */ nobj = js_NewArrayObject(cx, 0, NULL); if (!nobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(nobj); + *vp = OBJECT_TO_JSVAL(nobj); + obj = JS_THIS_OBJECT(cx, vp); if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; begin = 0; @@ -1580,10 +1642,10 @@ array_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) for (slot = begin; slot < end; slot++) { if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || - !GetArrayElement(cx, obj, slot, &hole, vp)) { + !GetArrayElement(cx, obj, slot, &hole, localroot)) { return JS_FALSE; } - if (!hole && !SetArrayElement(cx, nobj, slot - begin, *vp)) + if (!hole && !SetArrayElement(cx, nobj, slot - begin, *localroot)) return JS_FALSE; } return js_SetLengthProperty(cx, nobj, end - begin); @@ -1592,13 +1654,14 @@ array_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #if JS_HAS_ARRAY_EXTRAS static JSBool -array_indexOfHelper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval, JSBool isLast) +array_indexOfHelper(JSContext *cx, JSBool isLast, uintN argc, jsval *vp) { + JSObject *obj; jsuint length, i, stop; jsint direction; JSBool hole; + obj = JSVAL_TO_OBJECT(vp[1]); if (!js_GetLengthProperty(cx, obj, &length)) return JS_FALSE; if (length == 0) @@ -1609,7 +1672,7 @@ array_indexOfHelper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } else { jsdouble start; - if (!js_ValueToNumber(cx, argv[1], &start)) + if (!js_ValueToNumber(cx, vp[3], &start)) return JS_FALSE; start = js_DoubleToInteger(start); if (start < 0) { @@ -1640,33 +1703,31 @@ array_indexOfHelper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, for (;;) { if (!JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) || - !GetArrayElement(cx, obj, (jsuint)i, &hole, rval)) { + !GetArrayElement(cx, obj, (jsuint)i, &hole, vp)) { return JS_FALSE; } - if (!hole && js_StrictlyEqual(*rval, argv[0])) - return js_NewNumberValue(cx, i, rval); + if (!hole && js_StrictlyEqual(*vp, vp[2])) + return js_NewNumberValue(cx, i, vp); if (i == stop) goto not_found; i += direction; } not_found: - *rval = INT_TO_JSVAL(-1); + *vp = INT_TO_JSVAL(-1); return JS_TRUE; } static JSBool -array_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_indexOf(JSContext *cx, uintN argc, jsval *vp) { - return array_indexOfHelper(cx, obj, argc, argv, rval, JS_FALSE); + return array_indexOfHelper(cx, JS_FALSE, argc, vp); } static JSBool -array_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) { - return array_indexOfHelper(cx, obj, argc, argv, rval, JS_TRUE); + return array_indexOfHelper(cx, JS_TRUE, argc, vp); } /* Order is important; extras that take a predicate funarg must follow MAP. */ @@ -1683,21 +1744,25 @@ typedef enum ArrayExtraMode { #define REDUCE_MODE(mode) ((mode) == REDUCE || (mode) == REDUCE_RIGHT) static JSBool -array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, - ArrayExtraMode mode) +array_extra(JSContext *cx, ArrayExtraMode mode, uintN argc, jsval *vp) { - jsval *vp, *sp, *origsp, *oldsp; + enum { ELEM, TEMP, RVAL, NROOTS }; + jsval *argv, roots[NROOTS], *sp, *origsp, *oldsp; + JSObject *obj; + JSBool ok, cond, hole; jsuint length, newlen; JSObject *callable, *thisp, *newarr; jsint start, end, step, i; + JSTempValueRooter tvr; void *mark; JSStackFrame *fp; - JSBool ok, cond, hole; /* Hoist the explicit local root address computation. */ - vp = argv + argc; + argv = vp + 2; - if (!js_GetLengthProperty(cx, obj, &length)) + obj = JSVAL_TO_OBJECT(vp[1]); + ok = js_GetLengthProperty(cx, obj, &length); + if (!ok) return JS_FALSE; /* @@ -1715,9 +1780,11 @@ array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, #ifdef __GNUC__ /* quell GCC overwarning */ newlen = 0; newarr = NULL; - ok = JS_TRUE; #endif start = 0, end = length, step = 1; + memset(roots, 0, sizeof roots); + JS_PUSH_TEMP_ROOT(cx, NROOTS, roots, &tvr); + switch (mode) { case REDUCE_RIGHT: start = length - 1, end = -1, step = -1; @@ -1726,21 +1793,24 @@ array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, if (length == 0 && argc == 1) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE); - return JS_FALSE; + ok = JS_FALSE; + goto early_out; } if (argc >= 2) { - *rval = argv[1]; + roots[RVAL] = argv[1]; } else { do { - if (!GetArrayElement(cx, obj, start, &hole, rval)) - return JS_FALSE; + ok = GetArrayElement(cx, obj, start, &hole, &roots[RVAL]); + if (!ok) + goto early_out; start += step; } while (hole && start != end); if (hole && start == end) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_EMPTY_ARRAY_REDUCE); - return JS_FALSE; + ok = JS_FALSE; + goto early_out; } } break; @@ -1748,26 +1818,29 @@ array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, case FILTER: newlen = (mode == MAP) ? length : 0; newarr = js_NewArrayObject(cx, newlen, NULL); - if (!newarr) - return JS_FALSE; - *rval = OBJECT_TO_JSVAL(newarr); + if (!newarr) { + ok = JS_FALSE; + goto early_out; + } + roots[RVAL] = OBJECT_TO_JSVAL(newarr); break; case SOME: - *rval = JSVAL_FALSE; + roots[RVAL] = JSVAL_FALSE; break; case EVERY: - *rval = JSVAL_TRUE; + roots[RVAL] = JSVAL_TRUE; break; case FOREACH: break; } if (length == 0) - return JS_TRUE; + goto early_out; if (argc > 1 && !REDUCE_MODE(mode)) { - if (!js_ValueToObject(cx, argv[1], &thisp)) - return JS_FALSE; + ok = js_ValueToObject(cx, argv[1], &thisp); + if (!ok) + goto early_out; argv[1] = OBJECT_TO_JSVAL(thisp); } else { thisp = NULL; @@ -1779,8 +1852,10 @@ array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, */ argc = 3 + REDUCE_MODE(mode); origsp = js_AllocStack(cx, 2 + argc + 1, &mark); - if (!origsp) - return JS_FALSE; + if (!origsp) { + ok = JS_FALSE; + goto early_out; + } /* Lift current frame to include our args. */ fp = cx->fp; @@ -1788,7 +1863,7 @@ array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, for (i = start; i != end; i += step) { ok = (JS_CHECK_OPERATION_LIMIT(cx, JSOW_JUMP) && - GetArrayElement(cx, obj, i, &hole, vp)); + GetArrayElement(cx, obj, i, &hole, &roots[ELEM])); if (!ok) break; if (hole) @@ -1796,33 +1871,34 @@ array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, /* * Push callable and 'this', then args. We must do this for every - * iteration around the loop since js_Invoke uses origsp[0] for rval - * storage and some native functions use origsp[1] for local rooting. + * iteration around the loop since js_Invoke uses origsp[0] for return + * value storage, while some native functions use origsp[1] for local + * rooting. */ sp = origsp; *sp++ = OBJECT_TO_JSVAL(callable); *sp++ = OBJECT_TO_JSVAL(thisp); if (REDUCE_MODE(mode)) - *sp++ = *rval; - *sp++ = *vp; + *sp++ = roots[RVAL]; + *sp++ = roots[ELEM]; *sp++ = INT_TO_JSVAL(i); *sp++ = OBJECT_TO_JSVAL(obj); /* Do the call. */ fp->sp = sp; ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL); - vp[1] = fp->sp[-1]; + roots[TEMP] = fp->sp[-1]; fp->sp = oldsp; if (!ok) break; if (mode > MAP) { - if (vp[1] == JSVAL_NULL) { + if (roots[TEMP] == JSVAL_NULL) { cond = JS_FALSE; - } else if (JSVAL_IS_BOOLEAN(vp[1])) { - cond = JSVAL_TO_BOOLEAN(vp[1]); + } else if (JSVAL_IS_BOOLEAN(roots[TEMP])) { + cond = JSVAL_TO_BOOLEAN(roots[TEMP]); } else { - ok = js_ValueToBoolean(cx, vp[1], &cond); + ok = js_ValueToBoolean(cx, roots[TEMP], &cond); if (!ok) goto out; } @@ -1833,127 +1909,129 @@ array_extra(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, break; case REDUCE: case REDUCE_RIGHT: - *rval = vp[1]; + roots[RVAL] = roots[TEMP]; break; case MAP: - ok = SetArrayElement(cx, newarr, i, vp[1]); + ok = SetArrayElement(cx, newarr, i, roots[TEMP]); if (!ok) goto out; break; case FILTER: if (!cond) break; - /* Filter passed *vp, push as result. */ - ok = SetArrayElement(cx, newarr, newlen++, *vp); + /* The filter passed roots[ELEM], so push it onto our result. */ + ok = SetArrayElement(cx, newarr, newlen++, roots[ELEM]); if (!ok) goto out; break; case SOME: if (cond) { - *rval = JSVAL_TRUE; + roots[RVAL] = JSVAL_TRUE; goto out; } break; case EVERY: if (!cond) { - *rval = JSVAL_FALSE; + roots[RVAL] = JSVAL_FALSE; goto out; } break; } } - out: + out: js_FreeStack(cx, mark); if (ok && mode == FILTER) ok = js_SetLengthProperty(cx, newarr, newlen); + early_out: + *vp = roots[RVAL]; + JS_POP_TEMP_ROOT(cx, &tvr); return ok; } static JSBool -array_forEach(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_forEach(JSContext *cx, uintN argc, jsval *vp) { - return array_extra(cx, obj, argc, argv, rval, FOREACH); + return array_extra(cx, FOREACH, argc, vp); } static JSBool -array_map(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_map(JSContext *cx, uintN argc, jsval *vp) { - return array_extra(cx, obj, argc, argv, rval, MAP); + return array_extra(cx, MAP, argc, vp); } static JSBool -array_reduce(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_reduce(JSContext *cx, uintN argc, jsval *vp) { - return array_extra(cx, obj, argc, argv, rval, REDUCE); + return array_extra(cx, REDUCE, argc, vp); } static JSBool -array_reduceRight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_reduceRight(JSContext *cx, uintN argc, jsval *vp) { - return array_extra(cx, obj, argc, argv, rval, REDUCE_RIGHT); + return array_extra(cx, REDUCE_RIGHT, argc, vp); } static JSBool -array_filter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_filter(JSContext *cx, uintN argc, jsval *vp) { - return array_extra(cx, obj, argc, argv, rval, FILTER); + return array_extra(cx, FILTER, argc, vp); } static JSBool -array_some(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_some(JSContext *cx, uintN argc, jsval *vp) { - return array_extra(cx, obj, argc, argv, rval, SOME); + return array_extra(cx, SOME, argc, vp); } static JSBool -array_every(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +array_every(JSContext *cx, uintN argc, jsval *vp) { - return array_extra(cx, obj, argc, argv, rval, EVERY); + return array_extra(cx, EVERY, argc, vp); } #endif +static JSPropertySpec array_props[] = { + {js_length_str, -1, JSPROP_SHARED | JSPROP_PERMANENT, + array_length_getter, array_length_setter}, + {0,0,0,0,0} +}; + static JSFunctionSpec array_methods[] = { #if JS_HAS_TOSOURCE - {js_toSource_str, array_toSource, 0,0,0}, + JS_FN(js_toSource_str, array_toSource, 0,0,0,0), #endif - {js_toString_str, array_toString, 0,0,0}, - {js_toLocaleString_str, array_toLocaleString, 0,0,0}, + JS_FN(js_toString_str, array_toString, 0,0,0,0), + JS_FN(js_toLocaleString_str,array_toLocaleString,0,0,0,0), /* Perl-ish methods. */ - {"join", array_join, 1,JSFUN_GENERIC_NATIVE,0}, - {"reverse", array_reverse, 0,JSFUN_GENERIC_NATIVE,2}, - {"sort", array_sort, 1,JSFUN_GENERIC_NATIVE,1}, - {"push", array_push, 1,JSFUN_GENERIC_NATIVE,0}, - {"pop", array_pop, 0,JSFUN_GENERIC_NATIVE,0}, - {"shift", array_shift, 0,JSFUN_GENERIC_NATIVE,1}, - {"unshift", array_unshift, 1,JSFUN_GENERIC_NATIVE,1}, - {"splice", array_splice, 2,JSFUN_GENERIC_NATIVE,1}, + JS_FN("join", array_join, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("reverse", array_reverse, 0,0,JSFUN_GENERIC_NATIVE,2), + JS_FN("sort", array_sort, 0,1,JSFUN_GENERIC_NATIVE,1), + JS_FN("push", array_push, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("pop", array_pop, 0,0,JSFUN_GENERIC_NATIVE,0), + JS_FN("shift", array_shift, 0,0,JSFUN_GENERIC_NATIVE,1), + JS_FN("unshift", array_unshift, 0,1,JSFUN_GENERIC_NATIVE,1), + JS_FN("splice", array_splice, 0,2,JSFUN_GENERIC_NATIVE,1), /* Python-esque sequence methods. */ - {"concat", array_concat, 1,JSFUN_GENERIC_NATIVE,1}, - {"slice", array_slice, 2,JSFUN_GENERIC_NATIVE,1}, + JS_FN("concat", array_concat, 0,1,JSFUN_GENERIC_NATIVE,1), + JS_FN("slice", array_slice, 0,2,JSFUN_GENERIC_NATIVE,1), #if JS_HAS_ARRAY_EXTRAS - {"indexOf", array_indexOf, 1,JSFUN_GENERIC_NATIVE,0}, - {"lastIndexOf", array_lastIndexOf, 1,JSFUN_GENERIC_NATIVE,0}, - {"forEach", array_forEach, 1,JSFUN_GENERIC_NATIVE,2}, - {"map", array_map, 1,JSFUN_GENERIC_NATIVE,2}, - {"reduce", array_reduce, 1,JSFUN_GENERIC_NATIVE,2}, - {"reduceRight", array_reduceRight, 1,JSFUN_GENERIC_NATIVE,2}, - {"filter", array_filter, 1,JSFUN_GENERIC_NATIVE,2}, - {"some", array_some, 1,JSFUN_GENERIC_NATIVE,2}, - {"every", array_every, 1,JSFUN_GENERIC_NATIVE,2}, + JS_FN("indexOf", array_indexOf, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("lastIndexOf", array_lastIndexOf, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("forEach", array_forEach, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("map", array_map, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("reduce", array_reduce, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("reduceRight", array_reduceRight, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("filter", array_filter, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("some", array_some, 1,1,JSFUN_GENERIC_NATIVE,0), + JS_FN("every", array_every, 1,1,JSFUN_GENERIC_NATIVE,0), #endif - {0,0,0,0,0} + JS_FS_END }; static JSBool @@ -1993,7 +2071,7 @@ js_InitArrayClass(JSContext *cx, JSObject *obj) JSObject *proto; proto = JS_InitClass(cx, obj, NULL, &js_ArrayClass, Array, 1, - NULL, array_methods, NULL, NULL); + array_props, array_methods, NULL, NULL); /* Initialize the Array prototype object so it gets a length property. */ if (!proto || !InitArrayObject(cx, proto, 0, NULL)) diff --git a/mozilla/js/src/jsarray.h b/mozilla/js/src/jsarray.h index 1108b5e73f0..195dc69e048 100644 --- a/mozilla/js/src/jsarray.h +++ b/mozilla/js/src/jsarray.h @@ -61,6 +61,8 @@ js_InitArrayClass(JSContext *cx, JSObject *obj); extern JSObject * js_NewArrayObject(JSContext *cx, jsuint length, jsval *vector); +#define JSSLOT_ARRAY_LENGTH JSSLOT_PRIVATE + extern JSBool js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp); diff --git a/mozilla/js/src/jsatom.h b/mozilla/js/src/jsatom.h index 306c6683337..75901ae85c4 100644 --- a/mozilla/js/src/jsatom.h +++ b/mozilla/js/src/jsatom.h @@ -300,7 +300,6 @@ extern const char js_next_str[]; extern const char js_noSuchMethod_str[]; extern const char js_object_str[]; extern const char js_parent_str[]; -extern const char js_private_str[]; extern const char js_proto_str[]; extern const char js_ptagc_str[]; extern const char js_qualifier_str[]; diff --git a/mozilla/js/src/jsbool.c b/mozilla/js/src/jsbool.c index 3a7114753cd..778426006c8 100644 --- a/mozilla/js/src/jsbool.c +++ b/mozilla/js/src/jsbool.c @@ -66,78 +66,57 @@ JSClass js_BooleanClass = { #include "jsprf.h" static JSBool -bool_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +bool_toSource(JSContext *cx, uintN argc, jsval *vp) { jsval v; char buf[32]; JSString *str; - if (JSVAL_IS_BOOLEAN((jsval)obj)) { - v = (jsval)obj; - } else { - if (!JS_InstanceOf(cx, obj, &js_BooleanClass, argv)) - return JS_FALSE; - v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - if (!JSVAL_IS_BOOLEAN(v)) - return js_obj_toSource(cx, obj, argc, argv, rval); - } + if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_BooleanClass.name, js_boolean_strs[JSVAL_TO_BOOLEAN(v) ? 1 : 0]); str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } #endif static JSBool -bool_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +bool_toString(JSContext *cx, uintN argc, jsval *vp) { jsval v; JSAtom *atom; JSString *str; - if (JSVAL_IS_BOOLEAN((jsval)obj)) { - v = (jsval)obj; - } else { - if (!JS_InstanceOf(cx, obj, &js_BooleanClass, argv)) - return JS_FALSE; - v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - if (!JSVAL_IS_BOOLEAN(v)) - return js_obj_toString(cx, obj, argc, argv, rval); - } + if (!js_GetPrimitiveThis(cx, vp, &js_BooleanClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_BOOLEAN(v)); atom = cx->runtime->atomState.booleanAtoms[JSVAL_TO_BOOLEAN(v) ? 1 : 0]; str = ATOM_TO_STRING(atom); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -bool_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +bool_valueOf(JSContext *cx, uintN argc, jsval *vp) { - if (JSVAL_IS_BOOLEAN((jsval)obj)) { - *rval = (jsval)obj; - return JS_TRUE; - } - if (!JS_InstanceOf(cx, obj, &js_BooleanClass, argv)) - return JS_FALSE; - *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - return JS_TRUE; + return js_GetPrimitiveThis(cx, vp, &js_BooleanClass, vp); } static JSFunctionSpec boolean_methods[] = { #if JS_HAS_TOSOURCE - {js_toSource_str, bool_toSource, 0,JSFUN_THISP_BOOLEAN,0}, + JS_FN(js_toSource_str, bool_toSource, 0, 0, JSFUN_THISP_BOOLEAN,0), #endif - {js_toString_str, bool_toString, 0,JSFUN_THISP_BOOLEAN,0}, - {js_valueOf_str, bool_valueOf, 0,JSFUN_THISP_BOOLEAN,0}, - {0,0,0,0,0} + JS_FN(js_toString_str, bool_toString, 0, 0, JSFUN_THISP_BOOLEAN,0), + JS_FN(js_valueOf_str, bool_valueOf, 0, 0, JSFUN_THISP_BOOLEAN,0), + JS_FS_END }; static JSBool diff --git a/mozilla/js/src/jscntxt.c b/mozilla/js/src/jscntxt.c index c25d21c8c3c..2f379311094 100644 --- a/mozilla/js/src/jscntxt.c +++ b/mozilla/js/src/jscntxt.c @@ -422,6 +422,14 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode) */ js_FinishDeflatedStringCache(rt); + /* + * Free unit string storage only after the last GC has completed, so + * that js_FinalizeStringRT can detect unit strings and avoid calling + * free on their chars storage. + */ + free(rt->unitStrings); + rt->unitStrings = NULL; + /* Take the runtime down, now that it has no contexts or atoms. */ JS_LOCK_GC(rt); rt->state = JSRTS_DOWN; diff --git a/mozilla/js/src/jscntxt.h b/mozilla/js/src/jscntxt.h index ace31bce536..a97d3fe4a00 100644 --- a/mozilla/js/src/jscntxt.h +++ b/mozilla/js/src/jscntxt.h @@ -248,8 +248,12 @@ struct JSRuntime { uint32 deflatedStringCacheBytes; #endif - /* Empty string held for use by this runtime's contexts. */ + /* + * Empty and unit-length strings held for use by this runtime's contexts. + * The unitStrings array and its elements are created on demand. + */ JSString *emptyString; + JSString **unitStrings; /* List of active contexts sharing this runtime; protected by gcLock. */ JSCList contextList; @@ -638,6 +642,9 @@ struct JSContext { * property values associated with this context's global object. */ uint8 xmlSettingFlags; + uint8 padding; +#else + uint16 padding; #endif /* Runtime version control identifier. */ diff --git a/mozilla/js/src/jsdate.c b/mozilla/js/src/jsdate.c index 4aed48cc7c6..31c0e8643cf 100644 --- a/mozilla/js/src/jsdate.c +++ b/mozilla/js/src/jsdate.c @@ -563,23 +563,24 @@ date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour, /* * See ECMA 15.9.4.[3-10]; */ -/* XXX this function must be above date_parseString to avoid a - horrid bug in the Win16 1.52 compiler */ #define MAXARGS 7 + static JSBool -date_UTC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +date_UTC(JSContext *cx, uintN argc, jsval *vp) { - jsdouble array[MAXARGS]; + jsval *argv; uintN loop; + jsdouble array[MAXARGS]; jsdouble d; + argv = vp + 2; for (loop = 0; loop < MAXARGS; loop++) { if (loop < argc) { if (!js_ValueToNumber(cx, argv[loop], &d)) return JS_FALSE; /* return NaN if any arg is NaN */ if (!JSDOUBLE_IS_FINITE(d)) { - return js_NewNumberValue(cx, d, rval); + return js_NewNumberValue(cx, d, vp); } array[loop] = floor(d); } else { @@ -600,7 +601,7 @@ date_UTC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) array[3], array[4], array[5], array[6]); d = TIMECLIP(d); - return js_NewNumberValue(cx, d, rval); + return js_NewNumberValue(cx, d, vp); } static JSBool @@ -619,7 +620,7 @@ date_parseString(JSString *str, jsdouble *result) int sec = -1; int c = -1; int n = -1; - jsdouble tzoffset = -1; /* was an int, overflowed on win16!!! */ + int tzoffset = -1; int prevc = 0; JSBool seenplusminus = JS_FALSE; int temp; @@ -872,25 +873,25 @@ syntax: } static JSBool -date_parse(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +date_parse(JSContext *cx, uintN argc, jsval *vp) { JSString *str; jsdouble result; - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; if (!date_parseString(str, &result)) { - *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); return JS_TRUE; } result = TIMECLIP(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_now(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +date_now(JSContext *cx, uintN argc, jsval *vp) { int64 us, ms, us2ms; jsdouble msec_time; @@ -900,7 +901,7 @@ date_now(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JSLL_DIV(ms, us, us2ms); JSLL_L2D(msec_time, ms); - return js_NewDoubleValue(cx, msec_time, rval); + return js_NewDoubleValue(cx, msec_time, vp); } /* @@ -908,15 +909,16 @@ date_now(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Date type. */ static JSBool -GetUTCTime(JSContext *cx, JSObject *obj, jsval *argv, jsdouble *rv) +GetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) { jsval v; - if (!JS_InstanceOf(cx, obj, &js_DateClass, argv)) + + if (vp && !JS_InstanceOf(cx, obj, &js_DateClass, vp + 2)) return JS_FALSE; if (!JS_GetReservedSlot(cx, obj, UTC_TIME_SLOT, &v)) return JS_FALSE; - *rv = *JSVAL_TO_DOUBLE(v); + *dp = *JSVAL_TO_DOUBLE(v); return JS_TRUE; } @@ -927,9 +929,9 @@ GetUTCTime(JSContext *cx, JSObject *obj, jsval *argv, jsdouble *rv) * It also invalidates cached local time. */ static JSBool -SetUTCTimePtr(JSContext *cx, JSObject *obj, jsval *argv, jsdouble *v) +SetUTCTimePtr(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) { - if (!JS_InstanceOf(cx, obj, &js_DateClass, argv)) + if (vp && !JS_InstanceOf(cx, obj, &js_DateClass, vp + 2)) return JS_FALSE; /* Invalidate local time cache. */ @@ -938,19 +940,19 @@ SetUTCTimePtr(JSContext *cx, JSObject *obj, jsval *argv, jsdouble *v) return JS_FALSE; } - return JS_SetReservedSlot(cx, obj, UTC_TIME_SLOT, DOUBLE_TO_JSVAL(v)); + return JS_SetReservedSlot(cx, obj, UTC_TIME_SLOT, DOUBLE_TO_JSVAL(dp)); } /* * Set UTC time to a given time. */ static JSBool -SetUTCTime(JSContext *cx, JSObject *obj, jsval *argv, jsdouble t) +SetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble t) { - jsdouble *v = js_NewDouble(cx, t, 0); - if (!v) + jsdouble *dp = js_NewDouble(cx, t, 0); + if (!dp) return JS_FALSE; - return SetUTCTimePtr(cx, obj, argv, v); + return SetUTCTimePtr(cx, obj, vp, dp); } /* @@ -958,7 +960,7 @@ SetUTCTime(JSContext *cx, JSObject *obj, jsval *argv, jsdouble t) * (e.g., NaN), the local time slot is set to the UTC time without conversion. */ static JSBool -GetLocalTime(JSContext *cx, JSObject *obj, jsval *argv, jsdouble *rv) +GetLocalTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp) { jsval v; jsdouble result; @@ -970,7 +972,7 @@ GetLocalTime(JSContext *cx, JSObject *obj, jsval *argv, jsdouble *rv) result = *JSVAL_TO_DOUBLE(v); if (JSDOUBLE_IS_NaN(result)) { - if (!GetUTCTime(cx, obj, argv, &result)) + if (!GetUTCTime(cx, obj, vp, &result)) return JS_FALSE; /* if result is NaN, it couldn't be finite. */ @@ -987,7 +989,7 @@ GetLocalTime(JSContext *cx, JSObject *obj, jsval *argv, jsdouble *rv) } } - *rv = result; + *dp = result; return JS_TRUE; } @@ -995,23 +997,20 @@ GetLocalTime(JSContext *cx, JSObject *obj, jsval *argv, jsdouble *rv) * See ECMA 15.9.5.4 thru 15.9.5.23 */ static JSBool -date_getTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) -{ - jsdouble v; - if (!GetUTCTime(cx, obj, argv, &v)) - return JS_FALSE; - - return js_NewNumberValue(cx, v, rval); -} - -static JSBool -GetYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval, JSBool fullyear) +date_getTime(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetLocalTime(cx, obj, argv, &result)) + return GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result) && + js_NewNumberValue(cx, result, vp); +} + +static JSBool +GetYear(JSContext *cx, JSBool fullyear, jsval *vp) +{ + jsdouble result; + + if (!GetLocalTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) { @@ -1022,249 +1021,249 @@ GetYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, result -= 1900; } - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getYear(JSContext *cx, uintN argc, jsval *vp) { - return GetYear(cx, obj, argc, argv, rval, JS_FALSE); + return GetYear(cx, JS_FALSE, vp); } static JSBool -date_getFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getFullYear(JSContext *cx, uintN argc, jsval *vp) { - return GetYear(cx, obj, argc, argv, rval, JS_TRUE); + return GetYear(cx, JS_TRUE, vp); } static JSBool -date_getUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getUTCFullYear(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = YearFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getMonth(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetLocalTime(cx, obj, argv, &result)) + if (!GetLocalTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = MonthFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getUTCMonth(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getUTCMonth(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = MonthFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getDate(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetLocalTime(cx, obj, argv, &result)) + + if (!GetLocalTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = DateFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getUTCDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getUTCDate(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = DateFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +date_getDay(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetLocalTime(cx, obj, argv, &result)) + + if (!GetLocalTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = WeekDay(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getUTCDay(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getUTCDay(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = WeekDay(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getHours(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetLocalTime(cx, obj, argv, &result)) + + if (!GetLocalTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = HourFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getUTCHours(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getUTCHours(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = HourFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getMinutes(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetLocalTime(cx, obj, argv, &result)) + + if (!GetLocalTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = MinFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getUTCMinutes(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = MinFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } /* Date.getSeconds is mapped to getUTCSeconds */ static JSBool -date_getUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getUTCSeconds(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = SecFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } /* Date.getMilliseconds is mapped to getUTCMilliseconds */ static JSBool -date_getUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &result)) return JS_FALSE; if (JSDOUBLE_IS_FINITE(result)) result = msFromTime(result); - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_getTimezoneOffset(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_getTimezoneOffset(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; jsdouble utctime, localtime, result; - if (!GetUTCTime(cx, obj, argv, &utctime)) + + obj = JSVAL_TO_OBJECT(vp[1]); + if (!GetUTCTime(cx, obj, vp, &utctime)) + return JS_FALSE; + if (!GetLocalTime(cx, obj, NULL, &localtime)) return JS_FALSE; - if (!GetLocalTime(cx, obj, argv, &localtime)) - return JS_FALSE; /* - * Return the time zone offset in minutes for the current locale - * that is appropriate for this time. This value would be a - * constant except for daylight savings time. + * Return the time zone offset in minutes for the current locale that is + * appropriate for this time. This value would be a constant except for + * daylight savings time. */ result = (utctime - localtime) / msPerMinute; - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_setTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_setTime(JSContext *cx, uintN argc, jsval *vp) { jsdouble result; - if (!js_ValueToNumber(cx, argv[0], &result)) + if (!js_ValueToNumber(cx, vp[2], &result)) return JS_FALSE; result = TIMECLIP(result); - if (!SetUTCTime(cx, obj, argv, result)) + if (!SetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, result)) return JS_FALSE; - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - uintN maxargs, JSBool local, jsval *rval) +date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) { + JSObject *obj; + jsval *argv; uintN i; jsdouble args[4], *argp, *stop; jsdouble hour, min, sec, msec; @@ -1273,14 +1272,16 @@ date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsdouble msec_time; jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!GetUTCTime(cx, obj, vp, &result)) return JS_FALSE; /* just return NaN if the date is already NaN */ if (!JSDOUBLE_IS_FINITE(result)) - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); - /* Satisfy the ECMA rule that if a function is called with + /* + * 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 @@ -1292,14 +1293,17 @@ date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, argc = 1; /* should be safe, because length of all setters is 1 */ else if (argc > maxargs) argc = maxargs; /* clamp argc */ + JS_ASSERT(1 <= argc && argc <= 4); + argv = vp + 2; for (i = 0; i < argc; i++) { if (!js_ValueToNumber(cx, argv[i], &args[i])) return JS_FALSE; if (!JSDOUBLE_IS_FINITE(args[i])) { - if (!SetUTCTimePtr(cx, obj, argv, cx->runtime->jsNaN)) + if (!SetUTCTimePtr(cx, obj, NULL, cx->runtime->jsNaN)) return JS_FALSE; - return js_NewNumberValue(cx, *cx->runtime->jsNaN, rval); + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; } args[i] = js_DoubleToInteger(args[i]); } @@ -1342,79 +1346,73 @@ date_makeTime(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* fprintf(stderr, "%f\n", result); */ result = TIMECLIP(result); - if (!SetUTCTime(cx, obj, argv, result)) + if (!SetUTCTime(cx, obj, NULL, result)) return JS_FALSE; - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_setMilliseconds(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setMilliseconds(JSContext *cx, uintN argc, jsval *vp) { - return date_makeTime(cx, obj, argc, argv, 1, JS_TRUE, rval); + return date_makeTime(cx, 1, JS_TRUE, argc, vp); } static JSBool -date_setUTCMilliseconds(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp) { - return date_makeTime(cx, obj, argc, argv, 1, JS_FALSE, rval); + return date_makeTime(cx, 1, JS_FALSE, argc, vp); } static JSBool -date_setSeconds(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setSeconds(JSContext *cx, uintN argc, jsval *vp) { - return date_makeTime(cx, obj, argc, argv, 2, JS_TRUE, rval); + return date_makeTime(cx, 2, JS_TRUE, argc, vp); } static JSBool -date_setUTCSeconds(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setUTCSeconds(JSContext *cx, uintN argc, jsval *vp) { - return date_makeTime(cx, obj, argc, argv, 2, JS_FALSE, rval); + return date_makeTime(cx, 2, JS_FALSE, argc, vp); } static JSBool -date_setMinutes(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setMinutes(JSContext *cx, uintN argc, jsval *vp) { - return date_makeTime(cx, obj, argc, argv, 3, JS_TRUE, rval); + return date_makeTime(cx, 3, JS_TRUE, argc, vp); } static JSBool -date_setUTCMinutes(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setUTCMinutes(JSContext *cx, uintN argc, jsval *vp) { - return date_makeTime(cx, obj, argc, argv, 3, JS_FALSE, rval); + return date_makeTime(cx, 3, JS_FALSE, argc, vp); } static JSBool -date_setHours(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setHours(JSContext *cx, uintN argc, jsval *vp) { - return date_makeTime(cx, obj, argc, argv, 4, JS_TRUE, rval); + return date_makeTime(cx, 4, JS_TRUE, argc, vp); } static JSBool -date_setUTCHours(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setUTCHours(JSContext *cx, uintN argc, jsval *vp) { - return date_makeTime(cx, obj, argc, argv, 4, JS_FALSE, rval); + return date_makeTime(cx, 4, JS_FALSE, argc, vp); } static JSBool -date_makeDate(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, uintN maxargs, JSBool local, jsval *rval) +date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp) { + JSObject *obj; + jsval *argv; uintN i; jsdouble lorutime; /* local or UTC version of *date */ jsdouble args[3], *argp, *stop; jsdouble year, month, day; jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!GetUTCTime(cx, obj, vp, &result)) return JS_FALSE; /* see complaint about ECMA in date_MakeTime */ @@ -1422,14 +1420,17 @@ date_makeDate(JSContext *cx, JSObject *obj, uintN argc, argc = 1; /* should be safe, because length of all setters is 1 */ else if (argc > maxargs) argc = maxargs; /* clamp argc */ + JS_ASSERT(1 <= argc && argc <= 3); + argv = vp + 2; for (i = 0; i < argc; i++) { if (!js_ValueToNumber(cx, argv[i], &args[i])) return JS_FALSE; if (!JSDOUBLE_IS_FINITE(args[i])) { - if (!SetUTCTimePtr(cx, obj, argv, cx->runtime->jsNaN)) + if (!SetUTCTimePtr(cx, obj, NULL, cx->runtime->jsNaN)) return JS_FALSE; - return js_NewNumberValue(cx, *cx->runtime->jsNaN, rval); + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + return JS_TRUE; } args[i] = js_DoubleToInteger(args[i]); } @@ -1438,14 +1439,10 @@ date_makeDate(JSContext *cx, JSObject *obj, uintN argc, * If we are, use 0 as the time. */ if (!(JSDOUBLE_IS_FINITE(result))) { if (maxargs < 3) - return js_NewNumberValue(cx, result, rval); - else - lorutime = +0.; + return js_NewNumberValue(cx, result, vp); + lorutime = +0.; } else { - if (local) - lorutime = LocalTime(result); - else - lorutime = result; + lorutime = local ? LocalTime(result) : result; } argp = args; @@ -1472,72 +1469,67 @@ date_makeDate(JSContext *cx, JSObject *obj, uintN argc, result = UTC(result); result = TIMECLIP(result); - if (!SetUTCTime(cx, obj, argv, result)) + if (!SetUTCTime(cx, obj, NULL, result)) return JS_FALSE; - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } static JSBool -date_setDate(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setDate(JSContext *cx, uintN argc, jsval *vp) { - return date_makeDate(cx, obj, argc, argv, 1, JS_TRUE, rval); + return date_makeDate(cx, 1, JS_TRUE, argc, vp); } static JSBool -date_setUTCDate(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setUTCDate(JSContext *cx, uintN argc, jsval *vp) { - return date_makeDate(cx, obj, argc, argv, 1, JS_FALSE, rval); + return date_makeDate(cx, 1, JS_FALSE, argc, vp); } static JSBool -date_setMonth(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setMonth(JSContext *cx, uintN argc, jsval *vp) { - return date_makeDate(cx, obj, argc, argv, 2, JS_TRUE, rval); + return date_makeDate(cx, 2, JS_TRUE, argc, vp); } static JSBool -date_setUTCMonth(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setUTCMonth(JSContext *cx, uintN argc, jsval *vp) { - return date_makeDate(cx, obj, argc, argv, 2, JS_FALSE, rval); + return date_makeDate(cx, 2, JS_FALSE, argc, vp); } static JSBool -date_setFullYear(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setFullYear(JSContext *cx, uintN argc, jsval *vp) { - return date_makeDate(cx, obj, argc, argv, 3, JS_TRUE, rval); + return date_makeDate(cx, 3, JS_TRUE, argc, vp); } static JSBool -date_setUTCFullYear(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setUTCFullYear(JSContext *cx, uintN argc, jsval *vp) { - return date_makeDate(cx, obj, argc, argv, 3, JS_FALSE, rval); + return date_makeDate(cx, 3, JS_FALSE, argc, vp); } static JSBool -date_setYear(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_setYear(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; jsdouble t; jsdouble year; jsdouble day; jsdouble result; - if (!GetUTCTime(cx, obj, argv, &result)) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!GetUTCTime(cx, obj, vp, &result)) return JS_FALSE; - if (!js_ValueToNumber(cx, argv[0], &year)) + if (!js_ValueToNumber(cx, vp[2], &year)) return JS_FALSE; if (!JSDOUBLE_IS_FINITE(year)) { - if (!SetUTCTimePtr(cx, obj, argv, cx->runtime->jsNaN)) + if (!SetUTCTimePtr(cx, obj, NULL, cx->runtime->jsNaN)) return JS_FALSE; - return js_NewNumberValue(cx, *cx->runtime->jsNaN, rval); + return js_NewNumberValue(cx, *cx->runtime->jsNaN, vp); } year = js_DoubleToInteger(year); @@ -1556,10 +1548,10 @@ date_setYear(JSContext *cx, JSObject *obj, uintN argc, result = UTC(result); result = TIMECLIP(result); - if (!SetUTCTime(cx, obj, argv, result)) + if (!SetUTCTime(cx, obj, NULL, result)) return JS_FALSE; - return js_NewNumberValue(cx, result, rval); + return js_NewNumberValue(cx, result, vp); } /* constants for toString, toUTCString */ @@ -1574,14 +1566,13 @@ static const char* months[] = }; static JSBool -date_toGMTString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_toGMTString(JSContext *cx, uintN argc, jsval *vp) { char buf[100]; JSString *str; jsdouble utctime; - if (!GetUTCTime(cx, obj, argv, &utctime)) + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &utctime)) return JS_FALSE; if (!JSDOUBLE_IS_FINITE(utctime)) { @@ -1602,7 +1593,7 @@ date_toGMTString(JSContext *cx, JSObject *obj, uintN argc, str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } @@ -1770,15 +1761,16 @@ date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval) } static JSBool -date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval, const char *format) +date_toLocaleHelper(JSContext *cx, const char *format, jsval *vp) { + JSObject *obj; char buf[100]; JSString *str; PRMJTime split; jsdouble utctime; - if (!GetUTCTime(cx, obj, argv, &utctime)) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!GetUTCTime(cx, obj, vp, &utctime)) return JS_FALSE; if (!JSDOUBLE_IS_FINITE(utctime)) { @@ -1793,7 +1785,7 @@ date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc, /* If it failed, default to toString. */ if (result_len == 0) - return date_format(cx, utctime, FORMATSPEC_FULL, rval); + return date_format(cx, utctime, FORMATSPEC_FULL, vp); /* Hacked check against undesired 2-digit year 00/00/00 form. */ if (strcmp(format, "%x") == 0 && result_len >= 6 && @@ -1811,95 +1803,91 @@ date_toLocaleHelper(JSContext *cx, JSObject *obj, uintN argc, } if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) - return cx->localeCallbacks->localeToUnicode(cx, buf, rval); + return cx->localeCallbacks->localeToUnicode(cx, buf, vp); str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -date_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_toLocaleString(JSContext *cx, uintN argc, jsval *vp) { /* 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, argc, argv, rval, + return date_toLocaleHelper(cx, #if defined(_WIN32) && !defined(__MWERKS__) "%#c" #else "%c" #endif - ); + , vp); } static JSBool -date_toLocaleDateString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_toLocaleDateString(JSContext *cx, uintN argc, jsval *vp) { /* 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, argc, argv, rval, + return date_toLocaleHelper(cx, #if defined(_WIN32) && !defined(__MWERKS__) "%#x" #else "%x" #endif - ); + , vp); } static JSBool -date_toLocaleTimeString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_toLocaleTimeString(JSContext *cx, uintN argc, jsval *vp) { - return date_toLocaleHelper(cx, obj, argc, argv, rval, "%X"); + return date_toLocaleHelper(cx, "%X", vp); } static JSBool -date_toLocaleFormat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_toLocaleFormat(JSContext *cx, uintN argc, jsval *vp) { JSString *fmt; const char *fmtbytes; if (argc == 0) - return date_toLocaleString(cx, obj, argc, argv, rval); + return date_toLocaleString(cx, argc, vp); - fmt = js_ValueToString(cx, argv[0]); + fmt = js_ValueToString(cx, vp[2]); if (!fmt) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(fmt); + vp[2] = STRING_TO_JSVAL(fmt); fmtbytes = js_GetStringBytes(cx, fmt); if (!fmtbytes) return JS_FALSE; - return date_toLocaleHelper(cx, obj, argc, argv, rval, fmtbytes); + return date_toLocaleHelper(cx, fmtbytes, vp); } static JSBool -date_toTimeString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_toTimeString(JSContext *cx, uintN argc, jsval *vp) { jsdouble utctime; - if (!GetUTCTime(cx, obj, argv, &utctime)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &utctime)) return JS_FALSE; - return date_format(cx, utctime, FORMATSPEC_TIME, rval); + return date_format(cx, utctime, FORMATSPEC_TIME, vp); } static JSBool -date_toDateString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +date_toDateString(JSContext *cx, uintN argc, jsval *vp) { jsdouble utctime; - if (!GetUTCTime(cx, obj, argv, &utctime)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &utctime)) return JS_FALSE; - return date_format(cx, utctime, FORMATSPEC_DATE, rval); + return date_format(cx, utctime, FORMATSPEC_DATE, vp); } #if JS_HAS_TOSOURCE @@ -1907,14 +1895,13 @@ date_toDateString(JSContext *cx, JSObject *obj, uintN argc, #include "jsdtoa.h" static JSBool -date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_toSource(JSContext *cx, uintN argc, jsval *vp) { jsdouble utctime; char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes; JSString *str; - if (!GetUTCTime(cx, obj, argv, &utctime)) + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &utctime)) return JS_FALSE; numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, utctime); @@ -1934,25 +1921,26 @@ date_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, free(bytes); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } #endif static JSBool -date_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_toString(JSContext *cx, uintN argc, jsval *vp) { jsdouble utctime; - if (!GetUTCTime(cx, obj, argv, &utctime)) + + if (!GetUTCTime(cx, JSVAL_TO_OBJECT(vp[1]), vp, &utctime)) return JS_FALSE; - return date_format(cx, utctime, FORMATSPEC_FULL, rval); + return date_format(cx, utctime, FORMATSPEC_FULL, vp); } static JSBool -date_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +date_valueOf(JSContext *cx, uintN argc, jsval *vp) { + JSString *str, *str2; + /* 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 * GetUTCTime, which does the check. @@ -1960,20 +1948,16 @@ date_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* If called directly with no arguments, convert to a time number. */ if (argc == 0) - return date_getTime(cx, obj, argc, argv, rval); + return date_getTime(cx, argc, vp); /* Convert to number only if the hint was given, otherwise favor string. */ - if (argc == 1) { - JSString *str, *str2; - - str = js_ValueToString(cx, argv[0]); - if (!str) - return JS_FALSE; - str2 = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); - if (js_EqualStrings(str, str2)) - return date_getTime(cx, obj, argc, argv, rval); - } - return date_toString(cx, obj, argc, argv, rval); + str = js_ValueToString(cx, vp[2]); + if (!str) + return JS_FALSE; + str2 = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]); + if (js_EqualStrings(str, str2)) + return date_getTime(cx, argc, vp); + return date_toString(cx, argc, vp); } @@ -1982,61 +1966,61 @@ date_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, */ static JSFunctionSpec date_static_methods[] = { - {"UTC", date_UTC, MAXARGS,0,0 }, - {"parse", date_parse, 1,0,0 }, - {"now", date_now, 0,0,0 }, - {0,0,0,0,0} + JS_FN("UTC", date_UTC, 2,MAXARGS,0,0), + JS_FN("parse", date_parse, 1,1,0,0), + JS_FN("now", date_now, 0,0,0,0), + JS_FS_END }; static JSFunctionSpec date_methods[] = { - {"getTime", date_getTime, 0,0,0 }, - {"getTimezoneOffset", date_getTimezoneOffset, 0,0,0 }, - {"getYear", date_getYear, 0,0,0 }, - {"getFullYear", date_getFullYear, 0,0,0 }, - {"getUTCFullYear", date_getUTCFullYear, 0,0,0 }, - {"getMonth", date_getMonth, 0,0,0 }, - {"getUTCMonth", date_getUTCMonth, 0,0,0 }, - {"getDate", date_getDate, 0,0,0 }, - {"getUTCDate", date_getUTCDate, 0,0,0 }, - {"getDay", date_getDay, 0,0,0 }, - {"getUTCDay", date_getUTCDay, 0,0,0 }, - {"getHours", date_getHours, 0,0,0 }, - {"getUTCHours", date_getUTCHours, 0,0,0 }, - {"getMinutes", date_getMinutes, 0,0,0 }, - {"getUTCMinutes", date_getUTCMinutes, 0,0,0 }, - {"getSeconds", date_getUTCSeconds, 0,0,0 }, - {"getUTCSeconds", date_getUTCSeconds, 0,0,0 }, - {"getMilliseconds", date_getUTCMilliseconds,0,0,0 }, - {"getUTCMilliseconds", date_getUTCMilliseconds,0,0,0 }, - {"setTime", date_setTime, 1,0,0 }, - {"setYear", date_setYear, 1,0,0 }, - {"setFullYear", date_setFullYear, 3,0,0 }, - {"setUTCFullYear", date_setUTCFullYear, 3,0,0 }, - {"setMonth", date_setMonth, 2,0,0 }, - {"setUTCMonth", date_setUTCMonth, 2,0,0 }, - {"setDate", date_setDate, 1,0,0 }, - {"setUTCDate", date_setUTCDate, 1,0,0 }, - {"setHours", date_setHours, 4,0,0 }, - {"setUTCHours", date_setUTCHours, 4,0,0 }, - {"setMinutes", date_setMinutes, 3,0,0 }, - {"setUTCMinutes", date_setUTCMinutes, 3,0,0 }, - {"setSeconds", date_setSeconds, 2,0,0 }, - {"setUTCSeconds", date_setUTCSeconds, 2,0,0 }, - {"setMilliseconds", date_setMilliseconds, 1,0,0 }, - {"setUTCMilliseconds", date_setUTCMilliseconds,1,0,0 }, - {"toUTCString", date_toGMTString, 0,0,0 }, - {js_toLocaleString_str, date_toLocaleString, 0,0,0 }, - {"toLocaleDateString", date_toLocaleDateString,0,0,0 }, - {"toLocaleTimeString", date_toLocaleTimeString,0,0,0 }, - {"toLocaleFormat", date_toLocaleFormat, 1,0,0 }, - {"toDateString", date_toDateString, 0,0,0 }, - {"toTimeString", date_toTimeString, 0,0,0 }, + JS_FN("getTime", date_getTime, 0,0,0,0), + JS_FN("getTimezoneOffset", date_getTimezoneOffset, 0,0,0,0), + JS_FN("getYear", date_getYear, 0,0,0,0), + JS_FN("getFullYear", date_getFullYear, 0,0,0,0), + JS_FN("getUTCFullYear", date_getUTCFullYear, 0,0,0,0), + JS_FN("getMonth", date_getMonth, 0,0,0,0), + JS_FN("getUTCMonth", date_getUTCMonth, 0,0,0,0), + JS_FN("getDate", date_getDate, 0,0,0,0), + JS_FN("getUTCDate", date_getUTCDate, 0,0,0,0), + JS_FN("getDay", date_getDay, 0,0,0,0), + JS_FN("getUTCDay", date_getUTCDay, 0,0,0,0), + JS_FN("getHours", date_getHours, 0,0,0,0), + JS_FN("getUTCHours", date_getUTCHours, 0,0,0,0), + JS_FN("getMinutes", date_getMinutes, 0,0,0,0), + JS_FN("getUTCMinutes", date_getUTCMinutes, 0,0,0,0), + JS_FN("getSeconds", date_getUTCSeconds, 0,0,0,0), + JS_FN("getUTCSeconds", date_getUTCSeconds, 0,0,0,0), + JS_FN("getMilliseconds", date_getUTCMilliseconds, 0,0,0,0), + JS_FN("getUTCMilliseconds", date_getUTCMilliseconds, 0,0,0,0), + JS_FN("setTime", date_setTime, 1,1,0,0), + JS_FN("setYear", date_setYear, 1,1,0,0), + JS_FN("setFullYear", date_setFullYear, 1,3,0,0), + JS_FN("setUTCFullYear", date_setUTCFullYear, 1,3,0,0), + JS_FN("setMonth", date_setMonth, 1,2,0,0), + JS_FN("setUTCMonth", date_setUTCMonth, 1,2,0,0), + JS_FN("setDate", date_setDate, 1,1,0,0), + JS_FN("setUTCDate", date_setUTCDate, 1,1,0,0), + JS_FN("setHours", date_setHours, 1,4,0,0), + JS_FN("setUTCHours", date_setUTCHours, 1,4,0,0), + JS_FN("setMinutes", date_setMinutes, 1,3,0,0), + JS_FN("setUTCMinutes", date_setUTCMinutes, 1,3,0,0), + JS_FN("setSeconds", date_setSeconds, 1,2,0,0), + JS_FN("setUTCSeconds", date_setUTCSeconds, 1,2,0,0), + JS_FN("setMilliseconds", date_setMilliseconds, 1,1,0,0), + JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,1,0,0), + JS_FN("toUTCString", date_toGMTString, 0,0,0,0), + JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0,0,0), + JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0,0,0), + JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0,0,0), + JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0,0,0), + JS_FN("toDateString", date_toDateString, 0,0,0,0), + JS_FN("toTimeString", date_toTimeString, 0,0,0,0), #if JS_HAS_TOSOURCE - {js_toSource_str, date_toSource, 0,0,0 }, + JS_FN(js_toSource_str, date_toSource, 0,0,0,0), #endif - {js_toString_str, date_toString, 0,0,0 }, - {js_valueOf_str, date_valueOf, 0,0,0 }, - {0,0,0,0,0} + JS_FN(js_toString_str, date_toString, 0,0,0,0), + JS_FN(js_valueOf_str, date_valueOf, 0,0,0,0), + JS_FS_END }; static jsdouble * @@ -2297,6 +2281,7 @@ JS_FRIEND_API(void) js_DateSetYear(JSContext *cx, JSObject *obj, int year) { jsdouble local; + if (!GetLocalTime(cx, obj, NULL, &local)) return; @@ -2320,6 +2305,7 @@ JS_FRIEND_API(void) js_DateSetMonth(JSContext *cx, JSObject *obj, int month) { jsdouble local; + if (!GetLocalTime(cx, obj, NULL, &local)) return; @@ -2341,6 +2327,7 @@ JS_FRIEND_API(void) js_DateSetDate(JSContext *cx, JSObject *obj, int date) { jsdouble local; + if (!GetLocalTime(cx, obj, NULL, &local)) return; @@ -2361,6 +2348,7 @@ JS_FRIEND_API(void) js_DateSetHours(JSContext *cx, JSObject *obj, int hours) { jsdouble local; + if (!GetLocalTime(cx, obj, NULL, &local)) return; @@ -2380,6 +2368,7 @@ JS_FRIEND_API(void) js_DateSetMinutes(JSContext *cx, JSObject *obj, int minutes) { jsdouble local; + if (!GetLocalTime(cx, obj, NULL, &local)) return; @@ -2399,6 +2388,7 @@ JS_FRIEND_API(void) js_DateSetSeconds(JSContext *cx, JSObject *obj, int seconds) { jsdouble local; + if (!GetLocalTime(cx, obj, NULL, &local)) return; diff --git a/mozilla/js/src/jsdbgapi.c b/mozilla/js/src/jsdbgapi.c index 82f58590bd6..e2f80292aee 100644 --- a/mozilla/js/src/jsdbgapi.c +++ b/mozilla/js/src/jsdbgapi.c @@ -525,7 +525,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) closure = (JSObject *) wp->closure; clasp = OBJ_GET_CLASS(cx, closure); if (clasp == &js_FunctionClass) { - fun = (JSFunction *) JS_GetPrivate(cx, closure); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, closure); script = FUN_SCRIPT(fun); } else if (clasp == &js_ScriptClass) { fun = NULL; @@ -537,7 +537,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp) nslots = 2; if (fun) { - nslots += fun->nargs; + nslots += FUN_MINARGS(fun); if (FUN_NATIVE(fun)) nslots += fun->u.n.extra; } @@ -597,7 +597,7 @@ js_watch_set_wrapper(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, funobj = JSVAL_TO_OBJECT(argv[-2]); JS_ASSERT(OBJ_GET_CLASS(cx, funobj) == &js_FunctionClass); - wrapper = (JSFunction *) JS_GetPrivate(cx, funobj); + wrapper = (JSFunction *) OBJ_GET_PRIVATE(cx, funobj); userid = ATOM_KEY(wrapper->atom); *rval = argv[0]; return js_watch_set(cx, obj, userid, rval); @@ -879,6 +879,12 @@ JS_GetFunctionNative(JSContext *cx, JSFunction *fun) return FUN_NATIVE(fun); } +JS_PUBLIC_API(JSFastNative) +JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun) +{ + return FUN_FAST_NATIVE(fun); +} + JS_PUBLIC_API(JSPrincipals *) JS_GetScriptPrincipals(JSContext *cx, JSScript *script) { @@ -1051,7 +1057,13 @@ JS_GetFrameFunction(JSContext *cx, JSStackFrame *fp) JS_PUBLIC_API(JSObject *) JS_GetFrameFunctionObject(JSContext *cx, JSStackFrame *fp) { - return fp->argv && fp->fun ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL; + if (fp->argv && fp->fun) { + JSObject *obj = JSVAL_TO_OBJECT(fp->argv[-2]); + JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass); + JS_ASSERT(OBJ_GET_PRIVATE(cx, obj) == fp->fun); + return obj; + } + return NULL; } JS_PUBLIC_API(JSBool) diff --git a/mozilla/js/src/jsdbgapi.h b/mozilla/js/src/jsdbgapi.h index 1110b0292ab..5696529b8d7 100644 --- a/mozilla/js/src/jsdbgapi.h +++ b/mozilla/js/src/jsdbgapi.h @@ -137,6 +137,9 @@ JS_GetFunctionScript(JSContext *cx, JSFunction *fun); extern JS_PUBLIC_API(JSNative) JS_GetFunctionNative(JSContext *cx, JSFunction *fun); +extern JS_PUBLIC_API(JSFastNative) +JS_GetFunctionFastNative(JSContext *cx, JSFunction *fun); + extern JS_PUBLIC_API(JSPrincipals *) JS_GetScriptPrincipals(JSContext *cx, JSScript *script); diff --git a/mozilla/js/src/jsemit.c b/mozilla/js/src/jsemit.c index 0f35436f1df..f553fd0ea41 100644 --- a/mozilla/js/src/jsemit.c +++ b/mozilla/js/src/jsemit.c @@ -1761,7 +1761,6 @@ EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg) /* * Slight sugar for EmitIndexOp, again accessing cx and cg from the macro * caller's lexical environment, and embedding a false return on error. - * XXXbe hey, who checks for fun->nvars and fun->nargs overflow?! */ #define EMIT_INDEX_OP(op, index) \ JS_BEGIN_MACRO \ @@ -2113,7 +2112,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn, * name in that scope object. See comments at case JSOP_NAMEDFUNOBJ: * in jsinterp.c. */ - fun = (JSFunction *) JS_GetPrivate(cx, pn->pn_funpob->object); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, pn->pn_funpob->object); if (fun->atom) *answer = JS_TRUE; break; @@ -2305,7 +2304,7 @@ EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn, if (op == JSOP_ARGUMENTS) { if (js_Emit1(cx, cg, op) < 0) return JS_FALSE; - if (callContext && js_Emit1(cx, cg, JSOP_NULL) < 0) + if (callContext && js_Emit1(cx, cg, JSOP_GLOBALTHIS) < 0) return JS_FALSE; } else { if (pn->pn_slot >= 0) { @@ -4029,7 +4028,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION); cg2->parent = cg; - fun = (JSFunction *) JS_GetPrivate(cx, pn->pn_funpob->object); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, pn->pn_funpob->object); if (!js_EmitFunctionBody(cx, cg2, pn->pn_body, fun)) return JS_FALSE; @@ -5928,11 +5927,14 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) /* FALL THROUGH */ default: /* - * Push null after the expression as this object for the function - * call. js_ComputeThis replaces null by a proper object. + * Push the appropriate global object after the expression as the + * |this| parameter for the function call. ECMA-262 specifies that + * this happens after actual argument evaluation, but the result + * can't be affected by argument evaluation so we do it early and + * avoid null testing in js_ComputeThis. */ if (!js_EmitTree(cx, cg, pn2) || - !js_Emit1(cx, cg, JSOP_NULL) < 0) { + !js_Emit1(cx, cg, JSOP_GLOBALTHIS) < 0) { return JS_FALSE; } } @@ -5947,8 +5949,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) */ oldflags = cg->treeContext.flags; cg->treeContext.flags &= ~TCF_IN_FOR_INIT; - for (pn2 = pn2->pn_next; pn2; pn2 = pn2->pn_next) { - if (!js_EmitTree(cx, cg, pn2)) + for (pn3 = pn2->pn_next; pn3; pn3 = pn3->pn_next) { + if (!js_EmitTree(cx, cg, pn3)) return JS_FALSE; } cg->treeContext.flags |= oldflags & TCF_IN_FOR_INIT; diff --git a/mozilla/js/src/jsexn.c b/mozilla/js/src/jsexn.c index 6fd2acb3c1d..b53c3509122 100644 --- a/mozilla/js/src/jsexn.c +++ b/mozilla/js/src/jsexn.c @@ -811,20 +811,22 @@ Exception(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * number information along with this message. */ static JSBool -exn_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +exn_toString(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; jsval v; JSString *name, *message, *result; jschar *chars, *cp; size_t name_length, message_length, length; + obj = JSVAL_TO_OBJECT(vp[1]); if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), &v)) { return JS_FALSE; } name = JSVAL_IS_STRING(v) ? JSVAL_TO_STRING(v) : cx->runtime->emptyString; - *rval = STRING_TO_JSVAL(name); + *vp = STRING_TO_JSVAL(name); if (!JS_GetProperty(cx, obj, js_message_str, &v)) return JS_FALSE; @@ -857,7 +859,7 @@ exn_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) result = name; } - *rval = STRING_TO_JSVAL(result); + *vp = STRING_TO_JSVAL(result); return JS_TRUE; } @@ -866,45 +868,47 @@ exn_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Return a string that may eval to something similar to the original object. */ static JSBool -exn_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +exn_toSource(JSContext *cx, uintN argc, jsval *vp) { - jsval *vp; + jsval *localroots; + JSObject *obj; JSString *name, *message, *filename, *lineno_as_str, *result; uint32 lineno; size_t lineno_length, name_length, message_length, filename_length, length; jschar *chars, *cp; - vp = argv + argc; /* beginning of explicit local roots */ + localroots = JS_ARGV(cx, vp) + argc; + obj = JS_THIS_OBJECT(cx, vp); if (!OBJ_GET_PROPERTY(cx, obj, ATOM_TO_JSID(cx->runtime->atomState.nameAtom), - rval)) { + vp)) { return JS_FALSE; } - name = js_ValueToString(cx, *rval); + name = js_ValueToString(cx, *vp); if (!name) return JS_FALSE; - *rval = STRING_TO_JSVAL(name); + *vp = STRING_TO_JSVAL(name); - if (!JS_GetProperty(cx, obj, js_message_str, &vp[0]) || - !(message = js_ValueToSource(cx, vp[0]))) { + if (!JS_GetProperty(cx, obj, js_message_str, &localroots[0]) || + !(message = js_ValueToSource(cx, localroots[0]))) { return JS_FALSE; } - vp[0] = STRING_TO_JSVAL(message); + localroots[0] = STRING_TO_JSVAL(message); - if (!JS_GetProperty(cx, obj, js_fileName_str, &vp[1]) || - !(filename = js_ValueToSource(cx, vp[1]))) { + if (!JS_GetProperty(cx, obj, js_fileName_str, &localroots[1]) || + !(filename = js_ValueToSource(cx, localroots[1]))) { return JS_FALSE; } - vp[1] = STRING_TO_JSVAL(filename); + localroots[1] = STRING_TO_JSVAL(filename); - if (!JS_GetProperty(cx, obj, js_lineNumber_str, &vp[2]) || - !js_ValueToECMAUint32 (cx, vp[2], &lineno)) { + if (!JS_GetProperty(cx, obj, js_lineNumber_str, &localroots[2]) || + !js_ValueToECMAUint32 (cx, localroots[2], &lineno)) { return JS_FALSE; } if (lineno != 0) { - lineno_as_str = js_ValueToString(cx, vp[2]); + lineno_as_str = js_ValueToString(cx, localroots[2]); if (!lineno_as_str) return JS_FALSE; lineno_length = JSSTRING_LENGTH(lineno_as_str); @@ -977,17 +981,17 @@ exn_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JS_free(cx, chars); return JS_FALSE; } - *rval = STRING_TO_JSVAL(result); + *vp = STRING_TO_JSVAL(result); return JS_TRUE; } #endif static JSFunctionSpec exception_methods[] = { #if JS_HAS_TOSOURCE - {js_toSource_str, exn_toSource, 0,0,3}, + JS_FN(js_toSource_str, exn_toSource, 0,0,0,3), #endif - {js_toString_str, exn_toString, 0,0,0}, - {0,0,0,0,0} + JS_FN(js_toString_str, exn_toString, 0,0,0,0), + JS_FS_END }; JSObject * @@ -1239,7 +1243,7 @@ js_ReportUncaughtException(JSContext *cx) { jsval exn; JSObject *exnObject; - jsval vp[5]; + jsval roots[5]; JSTempValueRooter tvr; JSErrorReport *reportp, report; JSString *str; @@ -1252,8 +1256,8 @@ js_ReportUncaughtException(JSContext *cx) if (!JS_GetPendingException(cx, &exn)) return JS_FALSE; - memset(vp, 0, sizeof vp); - JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(vp), vp, &tvr); + memset(roots, 0, sizeof roots); + JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); /* * Because js_ValueToString below could error and an exception object @@ -1265,7 +1269,7 @@ js_ReportUncaughtException(JSContext *cx) exnObject = NULL; } else { exnObject = JSVAL_TO_OBJECT(exn); - vp[0] = exn; + roots[0] = exn; } JS_ClearPendingException(cx); @@ -1276,7 +1280,7 @@ js_ReportUncaughtException(JSContext *cx) if (!str) { bytes = "unknown (can't convert to string)"; } else { - vp[1] = STRING_TO_JSVAL(str); + roots[1] = STRING_TO_JSVAL(str); bytes = js_GetStringBytes(cx, str); if (!bytes) { ok = JS_FALSE; @@ -1291,21 +1295,21 @@ js_ReportUncaughtException(JSContext *cx) const char *filename; uint32 lineno; - ok = JS_GetProperty(cx, exnObject, js_message_str, &vp[2]); + ok = JS_GetProperty(cx, exnObject, js_message_str, &roots[2]); if (!ok) goto out; - if (JSVAL_IS_STRING(vp[2])) { - bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(vp[2])); + if (JSVAL_IS_STRING(roots[2])) { + bytes = js_GetStringBytes(cx, JSVAL_TO_STRING(roots[2])); if (!bytes) { ok = JS_FALSE; goto out; } } - ok = JS_GetProperty(cx, exnObject, js_fileName_str, &vp[3]); + ok = JS_GetProperty(cx, exnObject, js_fileName_str, &roots[3]); if (!ok) goto out; - str = js_ValueToString(cx, vp[3]); + str = js_ValueToString(cx, roots[3]); if (!str) { ok = JS_FALSE; goto out; @@ -1316,10 +1320,10 @@ js_ReportUncaughtException(JSContext *cx) goto out; } - ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &vp[4]); + ok = JS_GetProperty(cx, exnObject, js_lineNumber_str, &roots[4]); if (!ok) goto out; - ok = js_ValueToECMAUint32 (cx, vp[4], &lineno); + ok = js_ValueToECMAUint32 (cx, roots[4], &lineno); if (!ok) goto out; diff --git a/mozilla/js/src/jsfun.c b/mozilla/js/src/jsfun.c index 96eb773c43a..7ad467ead55 100644 --- a/mozilla/js/src/jsfun.c +++ b/mozilla/js/src/jsfun.c @@ -207,7 +207,7 @@ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp) /* * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share * storage between the formal parameter and arguments[k] for all - * k >= fp->argc && k < fp->fun->nargs. For example, in + * fp->argc <= k && k < fp->fun->nargs. For example, in * * function f(x) { x = 42; return arguments[0]; } * f(); @@ -848,7 +848,7 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object; if (!funobj) return JS_TRUE; - JS_ASSERT((JSFunction *) JS_GetPrivate(cx, funobj) == fp->fun); + JS_ASSERT((JSFunction *) OBJ_GET_PRIVATE(cx, funobj) == fp->fun); str = JSVAL_TO_STRING(id); atom = js_AtomizeString(cx, str, 0); @@ -872,7 +872,7 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, /* Ensure we found an arg or var property for the same function. */ if ((sprop->flags & SPROP_IS_HIDDEN) && (obj2 == funobj || - (JSFunction *) JS_GetPrivate(cx, obj2) == fp->fun)) { + (JSFunction *) OBJ_GET_PRIVATE(cx, obj2) == fp->fun)) { if (getter == js_GetArgument) { vp = fp->argv; nslots = JS_MAX(fp->argc, fp->fun->nargs); @@ -1316,7 +1316,7 @@ fun_xdrObject(JSXDRState *xdr, JSObject **objp) * (return true, no error report) in case one does due to API pilot * or internal error. */ - fun = (JSFunction *) JS_GetPrivate(cx, *objp); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, *objp); if (!fun) return JS_TRUE; if (!FUN_INTERPRETED(fun)) { @@ -1510,7 +1510,7 @@ fun_trace(JSTracer *trc, JSObject *obj) { JSFunction *fun; - fun = (JSFunction *) JS_GetPrivate(trc->context, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); if (fun) { JS_CALL_TRACER(trc, fun, JSTRACE_FUNCTION, "private"); if (fun->object != obj) @@ -1553,85 +1553,83 @@ JS_FRIEND_DATA(JSClass) js_FunctionClass = { JS_CLASS_TRACE(fun_trace), fun_reserveSlots }; -JSBool -js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent, - uintN argc, jsval *argv, jsval *rval) +static JSBool +fun_toStringHelper(JSContext *cx, uint32 indent, uintN argc, jsval *vp) { jsval fval; + JSObject *obj; JSFunction *fun; JSString *str; - if (!argv) { - JS_ASSERT(JS_ObjectIsFunction(cx, obj)); - } else { - fval = argv[-1]; - if (!VALUE_IS_FUNCTION(cx, fval)) { - /* - * If we don't have a function to start off with, try converting - * the object to a function. If that doesn't work, complain. - */ - if (JSVAL_IS_OBJECT(fval)) { - obj = JSVAL_TO_OBJECT(fval); - if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION, - &fval)) { - return JS_FALSE; - } - argv[-1] = fval; - } - if (!VALUE_IS_FUNCTION(cx, fval)) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_INCOMPATIBLE_PROTO, - js_Function_str, js_toString_str, - JS_GetTypeName(cx, - JS_TypeOfValue(cx, fval))); + fval = vp[1]; + if (!VALUE_IS_FUNCTION(cx, fval)) { + /* + * If we don't have a function to start off with, try converting the + * object to a function. If that doesn't work, complain. + */ + if (!JSVAL_IS_PRIMITIVE(fval)) { + obj = JSVAL_TO_OBJECT(fval); + if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION, + &fval)) { return JS_FALSE; } + vp[1] = fval; + } + if (!VALUE_IS_FUNCTION(cx, fval)) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_INCOMPATIBLE_PROTO, + js_Function_str, js_toString_str, + JS_GetTypeName(cx, JS_TypeOfValue(cx, fval))); + return JS_FALSE; } - - obj = JSVAL_TO_OBJECT(fval); } - fun = (JSFunction *) JS_GetPrivate(cx, obj); + obj = JSVAL_TO_OBJECT(fval); + if (argc != 0 && !js_ValueToECMAUint32(cx, vp[2], &indent)) + return JS_FALSE; + + JS_ASSERT(JS_ObjectIsFunction(cx, obj)); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); if (!fun) return JS_TRUE; - if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) - return JS_FALSE; str = JS_DecompileFunction(cx, fun, (uintN)indent); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +fun_toString(JSContext *cx, uintN argc, jsval *vp) { - return js_fun_toString(cx, obj, 0, argc, argv, rval); + return fun_toStringHelper(cx, 0, argc, vp); } #if JS_HAS_TOSOURCE static JSBool -fun_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +fun_toSource(JSContext *cx, uintN argc, jsval *vp) { - return js_fun_toString(cx, obj, JS_DONT_PRETTY_PRINT, argc, argv, rval); + return fun_toStringHelper(cx, JS_DONT_PRETTY_PRINT, argc, vp); } #endif static const char call_str[] = "call"; static JSBool -fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +fun_call(JSContext *cx, uintN argc, jsval *vp) { - jsval fval, *sp, *oldsp; + JSObject *obj; + jsval fval, *argv, *sp, *oldsp; JSString *str; void *mark; uintN i; JSStackFrame *fp; JSBool ok; - if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1])) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1])) return JS_FALSE; - fval = argv[-1]; + fval = vp[1]; if (!VALUE_IS_FUNCTION(cx, fval)) { str = JS_ValueToString(cx, fval); @@ -1648,6 +1646,7 @@ fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_FALSE; } + argv = vp + 2; if (argc == 0) { /* Call fun with its global object as the 'this' param if no args. */ obj = NULL; @@ -1676,21 +1675,24 @@ fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) fp = cx->fp; oldsp = fp->sp; fp->sp = sp; - ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER); + ok = js_Invoke(cx, argc, + (fp->flags & JSFRAME_IN_FAST_CALL) + ? JSINVOKE_INTERNAL + : JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER); /* Store rval and pop stack back to our frame's sp. */ - *rval = fp->sp[-1]; + *vp = fp->sp[-1]; fp->sp = oldsp; js_FreeStack(cx, mark); return ok; } static JSBool -fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +fun_apply(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj, *aobj; jsval fval, *sp, *oldsp; JSString *str; - JSObject *aobj; jsuint length; JSBool arraylike, ok; void *mark; @@ -1699,12 +1701,13 @@ fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (argc == 0) { /* Will get globalObject as 'this' and no other arguments. */ - return fun_call(cx, obj, argc, argv, rval); + return fun_call(cx, argc, vp); } - if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1])) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1])) return JS_FALSE; - fval = argv[-1]; + fval = vp[1]; if (!VALUE_IS_FUNCTION(cx, fval)) { str = JS_ValueToString(cx, fval); @@ -1727,13 +1730,13 @@ fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (argc >= 2) { /* If the 2nd arg is null or void, call the function with 0 args. */ - if (JSVAL_IS_NULL(argv[1]) || JSVAL_IS_VOID(argv[1])) { + if (JSVAL_IS_NULL(vp[3]) || JSVAL_IS_VOID(vp[3])) { argc = 0; } else { /* The second arg must be an array (or arguments object). */ arraylike = JS_FALSE; - if (!JSVAL_IS_PRIMITIVE(argv[1])) { - aobj = JSVAL_TO_OBJECT(argv[1]); + if (!JSVAL_IS_PRIMITIVE(vp[3])) { + aobj = JSVAL_TO_OBJECT(vp[3]); if (!js_IsArrayLike(cx, aobj, &arraylike, &length)) return JS_FALSE; } @@ -1746,9 +1749,9 @@ fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } /* Convert the first arg to 'this' and skip over it. */ - if (!JSVAL_IS_PRIMITIVE(argv[0])) - obj = JSVAL_TO_OBJECT(argv[0]); - else if (!js_ValueToObject(cx, argv[0], &obj)) + if (!JSVAL_IS_PRIMITIVE(vp[2])) + obj = JSVAL_TO_OBJECT(vp[2]); + else if (!js_ValueToObject(cx, vp[2], &obj)) return JS_FALSE; /* Allocate stack space for fval, obj, and the args. */ @@ -1771,10 +1774,13 @@ fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) fp = cx->fp; oldsp = fp->sp; fp->sp = sp; - ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER); + ok = js_Invoke(cx, argc, + (fp->flags & JSFRAME_IN_FAST_CALL) + ? JSINVOKE_INTERNAL + : JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER); /* Store rval and pop stack back to our frame's sp. */ - *rval = fp->sp[-1]; + *vp = fp->sp[-1]; fp->sp = oldsp; out: js_FreeStack(cx, mark); @@ -1783,8 +1789,7 @@ out: #ifdef NARCISSUS static JSBool -fun_applyConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp) { JSObject *aobj; uintN length, i; @@ -1793,8 +1798,8 @@ fun_applyConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JSStackFrame *fp; JSBool ok; - if (JSVAL_IS_PRIMITIVE(argv[0]) || - (aobj = JSVAL_TO_OBJECT(argv[0]), + if (JSVAL_IS_PRIMITIVE(vp[2]) || + (aobj = JSVAL_TO_OBJECT(vp[2]), OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass && OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, @@ -1813,7 +1818,7 @@ fun_applyConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, fp = cx->fp; oldsp = fp->sp; - *sp++ = OBJECT_TO_JSVAL(obj); + *sp++ = vp[1]; *sp++ = JSVAL_NULL; /* This is filled automagically. */ for (i = 0; i < length; i++) { ok = JS_GetElement(cx, aobj, (jsint)i, sp); @@ -1826,7 +1831,7 @@ fun_applyConstructor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, fp->sp = sp; ok = js_InvokeConstructor(cx, newsp, length); - *rval = fp->sp[-1]; + *vp = fp->sp[-1]; fp->sp = oldsp; out: js_FreeStack(cx, mark); @@ -1836,15 +1841,15 @@ out: static JSFunctionSpec function_methods[] = { #if JS_HAS_TOSOURCE - {js_toSource_str, fun_toSource, 0,0,0}, + JS_FN(js_toSource_str, fun_toSource, 0,0,0,0), #endif - {js_toString_str, fun_toString, 1,0,0}, - {"apply", fun_apply, 2,0,0}, - {call_str, fun_call, 1,0,0}, + JS_FN(js_toString_str, fun_toString, 0,0,0,0), + JS_FN("apply", fun_apply, 0,2,0,0), + JS_FN(call_str, fun_call, 0,1,0,0), #ifdef NARCISSUS - {"__applyConstructor__", fun_applyConstructor, 1,0,0}, + JS_FN("__applyConstructor__", fun_applyConstructor, 0,1,0,0), #endif - {0,0,0,0,0} + JS_FS_END }; static JSBool @@ -2209,7 +2214,7 @@ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs, fun->flags = flags & JSFUN_FLAGS_MASK; fun->u.n.native = native; fun->u.n.extra = 0; - fun->u.n.spare = 0; + fun->u.n.minargs = 0; fun->atom = atom; fun->clasp = NULL; diff --git a/mozilla/js/src/jsfun.h b/mozilla/js/src/jsfun.h index c4c8063a1c3..6013d4a2b40 100644 --- a/mozilla/js/src/jsfun.h +++ b/mozilla/js/src/jsfun.h @@ -49,12 +49,14 @@ JS_BEGIN_EXTERN_C struct JSFunction { JSObject *object; /* back-pointer to GC'ed object header */ - uint16 nargs; /* minimum number of actual arguments */ + uint16 nargs; /* maximum number of specified arguments, + reflected as f.length/f.arity */ uint16 flags; /* bound method and other flags, see jsapi.h */ union { struct { uint16 extra; /* number of arg slots for local GC roots */ - uint16 spare; /* reserved for future use */ + uint16 minargs; /* minimum number of specified arguments, used + only when calling fast native */ JSNative native; /* native method pointer or null */ } n; struct { @@ -70,9 +72,18 @@ struct JSFunction { #define JSFUN_EXPR_CLOSURE 0x4000 /* expression closure: function(x)x*x */ #define JSFUN_INTERPRETED 0x8000 /* use u.i if set, u.n if unset */ +#define JSFUN_SCRIPT_OR_FAST_NATIVE (JSFUN_INTERPRETED | JSFUN_FAST_NATIVE) + #define FUN_INTERPRETED(fun) ((fun)->flags & JSFUN_INTERPRETED) -#define FUN_NATIVE(fun) (FUN_INTERPRETED(fun) ? NULL : (fun)->u.n.native) +#define FUN_SLOW_NATIVE(fun) (!((fun)->flags & JSFUN_SCRIPT_OR_FAST_NATIVE)) #define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL) +#define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL) +#define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ + ? (JSFastNative) (fun)->u.n.native \ + : NULL) +#define FUN_MINARGS(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \ + ? (fun)->u.n.minargs \ + : (fun)->nargs) extern JSClass js_ArgumentsClass; extern JSClass js_CallClass; @@ -87,10 +98,6 @@ extern JS_FRIEND_DATA(JSClass) js_FunctionClass; (!JSVAL_IS_PRIMITIVE(v) && \ OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_FunctionClass) -extern JSBool -js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent, - uintN argc, jsval *argv, jsval *rval); - extern JSObject * js_InitFunctionClass(JSContext *cx, JSObject *obj); diff --git a/mozilla/js/src/jsgc.c b/mozilla/js/src/jsgc.c index 7ba39153bc9..a0cd88d7bd5 100644 --- a/mozilla/js/src/jsgc.c +++ b/mozilla/js/src/jsgc.c @@ -1943,7 +1943,8 @@ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num, void js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) { - uintN depth, nslots; + uintN depth, nslots, minargs; + if (fp->callobj) JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call"); if (fp->argsobj) @@ -2000,8 +2001,9 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp) if (fp->argv) { nslots = fp->argc; if (fp->fun) { - if (fp->fun->nargs > nslots) - nslots = fp->fun->nargs; + minargs = FUN_MINARGS(fp->fun); + if (minargs > nslots) + nslots = minargs; if (!FUN_INTERPRETED(fp->fun)) nslots += fp->fun->u.n.extra; } diff --git a/mozilla/js/src/jsinterp.c b/mozilla/js/src/jsinterp.c index fd49fdbf056..72f8636b69a 100644 --- a/mozilla/js/src/jsinterp.c +++ b/mozilla/js/src/jsinterp.c @@ -506,67 +506,101 @@ PutBlockObjects(JSContext *cx, JSStackFrame *fp) } JSBool -js_ComputeThis(JSContext *cx, jsval *argv) +js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp) +{ + jsval v; + JSObject *obj; + + v = vp[1]; + if (JSVAL_IS_OBJECT(v)) { + obj = JSVAL_TO_OBJECT(v); + if (!JS_InstanceOf(cx, obj, clasp, vp + 2)) + return JS_FALSE; + v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + } + *thisvp = v; + return JS_TRUE; +} + +/* + * ECMA requires "the global object", but in embeddings such as the browser, + * which have multiple top-level objects (windows, frames, etc. in the DOM), + * we prefer fun's parent. An example that causes this code to run: + * + * // in window w1 + * function f() { return this } + * function g() { return f } + * + * // in window w2 + * var h = w1.g() + * alert(h() == w1) + * + * The alert should display "true". + */ +static JSBool +ComputeGlobalThis(JSContext *cx, jsval *argv) { JSObject *thisp; - if (!JSVAL_IS_OBJECT(argv[-1])) - return js_PrimitiveToObject(cx, &argv[-1]); - - thisp = JSVAL_TO_OBJECT(argv[-1]); - if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) { - if (!thisp->map->ops->thisObject) - return JS_TRUE; - - /* Some objects (e.g., With) delegate 'this' to another object. */ - thisp = OBJ_THIS_OBJECT(cx, thisp); - if (!thisp) - return JS_FALSE; + if (JSVAL_IS_PRIMITIVE(argv[-2]) || + !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]))) { + thisp = cx->globalObject; } else { - /* - * ECMA requires "the global object", but in the presence of multiple - * top-level objects (windows, frames, or certain layers in the client - * object model), we prefer fun's parent. An example that causes this - * code to run: - * - * // in window w1 - * function f() { return this } - * function g() { return f } - * - * // in window w2 - * var h = w1.g() - * alert(h() == w1) - * - * The alert should display "true". - */ - if (JSVAL_IS_PRIMITIVE(argv[-2]) || - !OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]))) { - thisp = cx->globalObject; - } else { - jsid id; - jsval v; - uintN attrs; - JSObject *parent; + jsid id; + jsval v; + uintN attrs; + JSObject *parent; - /* Walk up the parent chain. */ - thisp = JSVAL_TO_OBJECT(argv[-2]); - id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom); - for (;;) { - if (!OBJ_CHECK_ACCESS(cx, thisp, id, JSACC_PARENT, &v, &attrs)) - return JS_FALSE; - parent = JSVAL_IS_VOID(v) - ? OBJ_GET_PARENT(cx, thisp) - : JSVAL_TO_OBJECT(v); - if (!parent) - break; - thisp = parent; - } + /* Walk up the parent chain. */ + thisp = JSVAL_TO_OBJECT(argv[-2]); + id = ATOM_TO_JSID(cx->runtime->atomState.parentAtom); + for (;;) { + if (!OBJ_CHECK_ACCESS(cx, thisp, id, JSACC_PARENT, &v, &attrs)) + return JS_FALSE; + parent = JSVAL_IS_VOID(v) + ? OBJ_GET_PARENT(cx, thisp) + : JSVAL_TO_OBJECT(v); + if (!parent) + break; + thisp = parent; } } argv[-1] = OBJECT_TO_JSVAL(thisp); return JS_TRUE; } +static JSBool +ComputeThis(JSContext *cx, jsval *argv) +{ + JSObject *thisp; + + JS_ASSERT(!JSVAL_IS_NULL(argv[-1])); + if (!JSVAL_IS_OBJECT(argv[-1])) + return js_PrimitiveToObject(cx, &argv[-1]); + + thisp = JSVAL_TO_OBJECT(argv[-1]); + if (OBJ_GET_CLASS(cx, thisp) == &js_CallClass) + return ComputeGlobalThis(cx, argv); + + if (!thisp->map->ops->thisObject) + return JS_TRUE; + + /* Some objects (e.g., With) delegate 'this' to another object. */ + thisp = thisp->map->ops->thisObject(cx, thisp); + if (!thisp) + return JS_FALSE; + argv[-1] = OBJECT_TO_JSVAL(thisp); + return JS_TRUE; +} + +JSBool +js_ComputeThis(JSContext *cx, jsval *argv) +{ + if (JSVAL_IS_NULL(argv[-1])) + return ComputeGlobalThis(cx, argv); + return ComputeThis(cx, argv); +} + #if JS_HAS_NO_SUCH_METHOD static JSBool @@ -581,24 +615,9 @@ NoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags, JSBool ok; jsbytecode *pc; - /* - * We must call js_ComputeThis here to censor Call objects. A performance - * hit, since we'll call it again in the normal sequence of invoke events, - * but at least it's idempotent. - * - * Normally, we call ComputeThis after all frame members have been set, - * and in particular, after any revision of the callee value at *vp due - * to clasp->convert (see below). This matters because ComputeThis may - * access *vp via fp->argv[-2], to follow the parent chain to a global - * object to use as the 'this' parameter. - * - * Obviously, here in the JSVAL_IS_PRIMITIVE(v) case, there can't be any - * such defaulting of 'this' to callee (v, *vp) ancestor. - */ + /* NB: js_ComputeThis or equivalent must have been called already. */ JS_ASSERT(JSVAL_IS_PRIMITIVE(vp[0])); - if (!js_ComputeThis(cx, vp + 2)) - return JS_FALSE; - + JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); RESTORE_SP(fp); /* From here on, control must flow through label out: to return. */ @@ -883,7 +902,7 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv) key.lineno = 0; name = ""; if (VALUE_IS_FUNCTION(cx, callee)) { - fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(callee)); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, JSVAL_TO_OBJECT(callee)); if (fun->atom) name = js_AtomToPrintableString(cx, fun->atom); if (FUN_INTERPRETED(fun)) { @@ -973,7 +992,7 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv) break; case JSTYPE_FUNCTION: if (VALUE_IS_FUNCTION(cx, argval)) { - fun = (JSFunction *)JS_GetPrivate(cx, JSVAL_TO_OBJECT(argval)); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, JSVAL_TO_OBJECT(argval)); if (fun && fun->atom) { str = ATOM_TO_STRING(fun->atom); break; @@ -1010,6 +1029,35 @@ LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv) # define ASSERT_NOT_THROWING(cx) /* nothing */ #endif +#define START_FAST_CALL(fp) (JS_ASSERT(!((fp)->flags & JSFRAME_IN_FAST_CALL)),\ + (fp)->flags |= JSFRAME_IN_FAST_CALL) +#define END_FAST_CALL(fp) (JS_ASSERT((fp)->flags & JSFRAME_IN_FAST_CALL), \ + (fp)->flags &= ~JSFRAME_IN_FAST_CALL) + +/* + * We check if the function accepts a primitive value as |this|. For that we + * use a table that maps value's tag into the corresponding function flag. + */ +JS_STATIC_ASSERT(JSVAL_INT == 1); +JS_STATIC_ASSERT(JSVAL_DOUBLE == 2); +JS_STATIC_ASSERT(JSVAL_STRING == 4); +JS_STATIC_ASSERT(JSVAL_BOOLEAN == 6); + +static const uint16 PrimitiveTestFlags[] = { + JSFUN_THISP_NUMBER, /* INT */ + JSFUN_THISP_NUMBER, /* DOUBLE */ + JSFUN_THISP_NUMBER, /* INT */ + JSFUN_THISP_STRING, /* STRING */ + JSFUN_THISP_NUMBER, /* INT */ + JSFUN_THISP_BOOLEAN, /* BOOLEAN */ + JSFUN_THISP_NUMBER /* INT */ +}; + +#define PRIMITIVE_THIS_TEST(fun,thisv) \ + (JS_ASSERT(thisv != JSVAL_VOID), \ + JSFUN_THISP_TEST(JSFUN_THISP_FLAGS((fun)->flags), \ + PrimitiveTestFlags[JSVAL_TAG(thisv) - 1])) + /* * Find a function reference and its 'this' object implicit first parameter * under argc arguments on cx's stack, and call the function. Push missing @@ -1121,8 +1169,9 @@ js_Invoke(JSContext *cx, uintN argc, uintN flags) } else { have_fun: /* Get private data and set derived locals from it. */ - fun = (JSFunction *) JS_GetPrivate(cx, funobj); - nslots = (fun->nargs > argc) ? fun->nargs - argc : 0; + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, funobj); + nalloc = FUN_MINARGS(fun); + nslots = (nalloc > argc) ? nalloc - argc : 0; if (FUN_INTERPRETED(fun)) { native = NULL; script = fun->u.i.script; @@ -1138,31 +1187,8 @@ have_fun: /* Handle bound method special case. */ vp[1] = OBJECT_TO_JSVAL(parent); } else if (!JSVAL_IS_OBJECT(vp[1])) { - /* - * We check if the function accepts a primitive value as |this|. - * For that we use a table that maps value's tag into the - * corresponding function flag. - */ - uintN flagToTest; - - JS_STATIC_ASSERT(JSVAL_INT == 1); - JS_STATIC_ASSERT(JSVAL_DOUBLE == 2); - JS_STATIC_ASSERT(JSVAL_STRING == 4); - JS_STATIC_ASSERT(JSVAL_BOOLEAN == 6); - static const uint16 PrimitiveTestFlags[] = { - JSFUN_THISP_NUMBER, /* INT */ - JSFUN_THISP_NUMBER, /* DOUBLE */ - JSFUN_THISP_NUMBER, /* INT */ - JSFUN_THISP_STRING, /* STRING */ - JSFUN_THISP_NUMBER, /* INT */ - JSFUN_THISP_BOOLEAN, /* BOOLEAN */ - JSFUN_THISP_NUMBER /* INT */ - }; - JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT)); - JS_ASSERT(vp[1] != JSVAL_VOID); - flagToTest = PrimitiveTestFlags[JSVAL_TAG(vp[1]) - 1]; - if (JSFUN_THISP_TEST(JSFUN_THISP_FLAGS(fun->flags), flagToTest)) + if (PRIMITIVE_THIS_TEST(fun, vp[1])) goto init_frame; } } @@ -1172,6 +1198,11 @@ have_fun: JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1])); frame.rval = vp[1]; } else { + /* + * We must call js_ComputeThis in case we are not called from the + * interpreter, where a prior bytecode has computed an appropriate + * |this| already. + */ ok = js_ComputeThis(cx, vp + 2); if (!ok) goto out2; @@ -1182,7 +1213,7 @@ have_fun: * Initialize the rest of frame, except for sp (set by SAVE_SP later). * * To set thisp we use an explicit cast and not JSVAL_TO_OBJECT, as vp[1] - * can be a primitive value here for native functions specified with + * can be a primitive value here for those native functions specified with * JSFUN_THISP_(NUMBER|STRING|BOOLEAN) flags. */ frame.thisp = (JSObject *)vp[1]; @@ -1309,7 +1340,43 @@ have_fun: /* But ensure that we have a scope chain. */ if (!frame.scopeChain) frame.scopeChain = parent; - ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval); + + if (fun && (fun->flags & JSFUN_FAST_NATIVE)) { + /* + * Note the lack of START/END_FAST_CALL bracketing here. Unlike + * the other JSFastNative call (see the JSOP_CALL special case in + * js_Interpret), we have a full stack frame for this call. + */ + ok = ((JSFastNative) native)(cx, argc, frame.argv - 2); + frame.rval = frame.argv[-2]; + } else { +#ifdef DEBUG_brendan + static FILE *fp; + if (!fp) { + fp = fopen("/tmp/slow-natives.dump", "w"); + if (fp) + setlinebuf(fp); + } + if (fp) { + fprintf(fp, "%p %s.%s\n", + native, + JSVAL_IS_OBJECT(vp[1]) + ? ((OBJ_GET_CLASS(cx, frame.thisp) == &js_FunctionClass) + ? JS_GetFunctionName(JS_GetPrivate(cx, frame.thisp)) + : OBJ_GET_CLASS(cx, frame.thisp)->name) + : JSVAL_IS_BOOLEAN(vp[1]) + ? js_BooleanClass.name + : JSVAL_IS_STRING(vp[1]) + ? js_StringClass.name + : js_NumberClass.name, + fun && fun->atom + ? JS_GetFunctionName(fun) + : "???"); + } +#endif + ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval); + } + JS_RUNTIME_METER(cx->runtime, nativeCalls); #ifdef DEBUG_NOT_THROWING if (ok && !alreadyThrowing) @@ -1875,7 +1942,7 @@ js_InvokeConstructor(JSContext *cx, jsval *vp, uintN argc) parent = OBJ_GET_PARENT(cx, obj2); if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) { - funclasp = ((JSFunction *)JS_GetPrivate(cx, obj2))->clasp; + funclasp = ((JSFunction *) OBJ_GET_PRIVATE(cx, obj2))->clasp; if (funclasp) clasp = funclasp; } @@ -3815,8 +3882,8 @@ interrupt: BEGIN_CASE(JSOP_CALLELEM) /* - * XXX callelem should call getMethod on XML objects as CALLPROP - * does. See bug 362910. + * FIXME: JSOP_CALLELEM should call getMethod on XML objects as + * CALLPROP does. See bug 362910. */ ELEMENT_OP(-1, ok = OBJ_GET_PROPERTY(cx, obj, id, &rval)); STORE_OPND(-2, rval); @@ -3848,185 +3915,221 @@ interrupt: vp = sp - (argc + 2); lval = *vp; SAVE_SP_AND_PC(fp); - if (VALUE_IS_FUNCTION(cx, lval) && - (obj = JSVAL_TO_OBJECT(lval), - fun = (JSFunction *) JS_GetPrivate(cx, obj), - FUN_INTERPRETED(fun))) - /* inline_call: */ - { - uintN nframeslots, nvars, nslots, missing; - JSArena *a; - jsuword avail, nbytes; - JSBool overflow; - void *newmark; - jsval *rvp; - JSInlineFrame *newifp; - JSInterpreterHook hook; + if (VALUE_IS_FUNCTION(cx, lval)) { + obj = JSVAL_TO_OBJECT(lval); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); - /* Restrict recursion of lightweight functions. */ - if (inlineCallCount == MAX_INLINE_CALL_COUNT) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_OVER_RECURSED); + if (fun->flags & JSFUN_FAST_NATIVE) { + uintN nargs = JS_MAX(argc, fun->u.n.minargs); + + nargs += fun->u.n.extra; + if (argc < nargs) { + /* + * If we can't fit missing args and local roots in + * this frame's operand stack, take the slow path. + */ + nargs -= argc; + if (sp + nargs > fp->spbase + depth) + goto do_invoke; + do { + PUSH(JSVAL_VOID); + } while (--nargs != 0); + SAVE_SP(fp); + } + + JS_ASSERT(!JSVAL_IS_PRIMITIVE(vp[1]) || + PRIMITIVE_THIS_TEST(fun, vp[1])); + + START_FAST_CALL(fp); + ok = ((JSFastNative) fun->u.n.native)(cx, argc, vp); + END_FAST_CALL(fp); + if (!ok) + goto out; + sp = vp + 1; + vp[-depth] = (jsval)pc; + goto end_call; + } + + if (fun->flags & JSFUN_INTERPRETED) { + uintN nframeslots, nvars, nslots, missing; + JSArena *a; + jsuword avail, nbytes; + JSBool overflow; + void *newmark; + jsval *rvp; + JSInlineFrame *newifp; + JSInterpreterHook hook; + + /* Restrict recursion of lightweight functions. */ + if (inlineCallCount == MAX_INLINE_CALL_COUNT) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_OVER_RECURSED); + ok = JS_FALSE; + goto out; + } + + /* Compute the total number of stack slots needed by fun. */ + nframeslots = JS_HOWMANY(sizeof(JSInlineFrame), + sizeof(jsval)); + nvars = fun->u.i.nvars; + script = fun->u.i.script; + depth = (jsint) script->depth; + atoms = script->atomMap.vector; + nslots = nframeslots + nvars + 2 * depth; + + /* Allocate missing expected args adjacent to actuals. */ + missing = (fun->nargs > argc) ? fun->nargs - argc : 0; + a = cx->stackPool.current; + avail = a->avail; + newmark = (void *) avail; + if (missing) { + newsp = sp + missing; + overflow = (jsuword) newsp > a->limit; + if (overflow) + nslots += 2 + argc + missing; + else if ((jsuword) newsp > avail) + avail = a->avail = (jsuword) newsp; + } +#ifdef __GNUC__ + else overflow = JS_FALSE; /* suppress bogus gcc warnings */ +#endif + + /* Allocate the inline frame with its vars and operands. */ + newsp = (jsval *) avail; + nbytes = nslots * sizeof(jsval); + avail += nbytes; + if (avail <= a->limit) { + a->avail = avail; + } else { + JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool, + nbytes); + if (!newsp) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_STACK_OVERFLOW, + (fp && fp->fun) + ? JS_GetFunctionName(fp->fun) + : "script"); + goto bad_inline_call; + } + } + + /* + * Move args if missing overflow arena a, then push any + * missing args. + */ + rvp = vp; + if (missing) { + if (overflow) { + memcpy(newsp, vp, (2 + argc) * sizeof(jsval)); + vp = newsp; + sp = vp + 2 + argc; + newsp = sp + missing; + } + do { + PUSH(JSVAL_VOID); + } while (--missing != 0); + } + + /* Claim space for the stack frame and initialize it. */ + newifp = (JSInlineFrame *) newsp; + newsp += nframeslots; + newifp->frame.callobj = NULL; + newifp->frame.argsobj = NULL; + newifp->frame.varobj = NULL; + newifp->frame.script = script; + newifp->frame.fun = fun; + newifp->frame.argc = argc; + newifp->frame.argv = vp + 2; + newifp->frame.rval = JSVAL_VOID; + newifp->frame.nvars = nvars; + newifp->frame.vars = newsp; + newifp->frame.down = fp; + newifp->frame.annotation = NULL; + newifp->frame.scopeChain = parent = OBJ_GET_PARENT(cx, obj); + newifp->frame.sharpDepth = 0; + newifp->frame.sharpArray = NULL; + newifp->frame.flags = 0; + newifp->frame.dormantNext = NULL; + newifp->frame.xmlNamespace = NULL; + newifp->frame.blockChain = NULL; + newifp->rvp = rvp; + newifp->mark = newmark; + + /* Compute the 'this' parameter now that argv is set. */ + JS_ASSERT(!JSFUN_BOUND_METHOD_TEST(fun->flags)); + JS_ASSERT(!PRIMITIVE_THIS_TEST(fun, vp[1])); + newifp->frame.thisp = (JSObject *)vp[1]; +#ifdef DUMP_CALL_TABLE + LogCall(cx, *vp, argc, vp + 2); +#endif + + /* Push void to initialize local variables. */ + sp = newsp; + while (nvars--) + PUSH(JSVAL_VOID); + sp += depth; + newifp->frame.spbase = sp; + SAVE_SP(&newifp->frame); + + /* Call the debugger hook if present. */ + hook = cx->debugHooks->callHook; + if (hook) { + newifp->frame.pc = NULL; + newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0, + cx->debugHooks->callHookData); + LOAD_INTERRUPT_HANDLER(cx); + } else { + newifp->hookData = NULL; + } + + /* Scope with a call object parented by callee's parent. */ + if (JSFUN_HEAVYWEIGHT_TEST(fun->flags) && + !js_GetCallObject(cx, &newifp->frame, parent)) { + goto bad_inline_call; + } + + /* Switch version if currentVersion wasn't overridden. */ + newifp->callerVersion = (JSVersion) cx->version; + if (JS_LIKELY(cx->version == currentVersion)) { + currentVersion = (JSVersion) script->version; + if (currentVersion != cx->version) + js_SetVersion(cx, currentVersion); + } + + /* Push the frame and set interpreter registers. */ + cx->fp = fp = &newifp->frame; + pc = script->code; +#if !JS_THREADED_INTERP + endpc = pc + script->length; +#endif + inlineCallCount++; + JS_RUNTIME_METER(rt, inlineCalls); + + /* Load first op and dispatch it (safe since JSOP_STOP). */ + op = (JSOp) *pc; + DO_OP(); + + bad_inline_call: + RESTORE_SP(fp); + JS_ASSERT(fp->pc == pc); + script = fp->script; + depth = (jsint) script->depth; + atoms = script->atomMap.vector; + js_FreeRawStack(cx, newmark); ok = JS_FALSE; goto out; } - - /* Compute the total number of stack slots needed for fun. */ - nframeslots = JS_HOWMANY(sizeof(JSInlineFrame), sizeof(jsval)); - nvars = fun->u.i.nvars; - script = fun->u.i.script; - depth = (jsint) script->depth; - atoms = script->atomMap.vector; - nslots = nframeslots + nvars + 2 * depth; - - /* Allocate missing expected args adjacent to actual args. */ - missing = (fun->nargs > argc) ? fun->nargs - argc : 0; - a = cx->stackPool.current; - avail = a->avail; - newmark = (void *) avail; - if (missing) { - newsp = sp + missing; - overflow = (jsuword) newsp > a->limit; - if (overflow) - nslots += 2 + argc + missing; - else if ((jsuword) newsp > avail) - avail = a->avail = (jsuword) newsp; - } -#ifdef __GNUC__ - else overflow = JS_FALSE; /* suppress bogus gcc warnings */ -#endif - - /* Allocate the inline frame with its vars and operand slots. */ - newsp = (jsval *) avail; - nbytes = nslots * sizeof(jsval); - avail += nbytes; - if (avail <= a->limit) { - a->avail = avail; - } else { - JS_ARENA_ALLOCATE_CAST(newsp, jsval *, &cx->stackPool, - nbytes); - if (!newsp) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_STACK_OVERFLOW, - (fp && fp->fun) - ? JS_GetFunctionName(fp->fun) - : "script"); - goto bad_inline_call; - } - } - - /* Move args if missing overflow arena a, push missing args. */ - rvp = vp; - if (missing) { - if (overflow) { - memcpy(newsp, vp, (2 + argc) * sizeof(jsval)); - vp = newsp; - sp = vp + 2 + argc; - newsp = sp + missing; - } - do { - PUSH(JSVAL_VOID); - } while (--missing != 0); - } - - /* Claim space for the stack frame and initialize it. */ - newifp = (JSInlineFrame *) newsp; - newsp += nframeslots; - newifp->frame.callobj = NULL; - newifp->frame.argsobj = NULL; - newifp->frame.varobj = NULL; - newifp->frame.script = script; - newifp->frame.fun = fun; - newifp->frame.argc = argc; - newifp->frame.argv = vp + 2; - newifp->frame.rval = JSVAL_VOID; - newifp->frame.nvars = nvars; - newifp->frame.vars = newsp; - newifp->frame.down = fp; - newifp->frame.annotation = NULL; - newifp->frame.scopeChain = parent = OBJ_GET_PARENT(cx, obj); - newifp->frame.sharpDepth = 0; - newifp->frame.sharpArray = NULL; - newifp->frame.flags = 0; - newifp->frame.dormantNext = NULL; - newifp->frame.xmlNamespace = NULL; - newifp->frame.blockChain = NULL; - newifp->rvp = rvp; - newifp->mark = newmark; - - /* Compute the 'this' parameter now that argv is set. */ - if (JSFUN_BOUND_METHOD_TEST(fun->flags)) - vp[1] = OBJECT_TO_JSVAL(parent); - if (!js_ComputeThis(cx, vp + 2)) - goto bad_inline_call; - newifp->frame.thisp = JSVAL_TO_OBJECT(vp[1]); -#ifdef DUMP_CALL_TABLE - LogCall(cx, *vp, argc, vp + 2); -#endif - - /* Push void to initialize local variables. */ - sp = newsp; - while (nvars--) - PUSH(JSVAL_VOID); - sp += depth; - newifp->frame.spbase = sp; - SAVE_SP(&newifp->frame); - - /* Call the debugger hook if present. */ - hook = cx->debugHooks->callHook; - if (hook) { - newifp->frame.pc = NULL; - newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0, - cx->debugHooks->callHookData); - LOAD_INTERRUPT_HANDLER(cx); - } else { - newifp->hookData = NULL; - } - - /* Scope with a call object parented by the callee's parent. */ - if (JSFUN_HEAVYWEIGHT_TEST(fun->flags) && - !js_GetCallObject(cx, &newifp->frame, parent)) { - goto bad_inline_call; - } - - /* Switch to new version if currentVersion wasn't overridden. */ - newifp->callerVersion = (JSVersion) cx->version; - if (JS_LIKELY(cx->version == currentVersion)) { - currentVersion = (JSVersion) script->version; - if (currentVersion != cx->version) - js_SetVersion(cx, currentVersion); - } - - /* Push the frame and set interpreter registers. */ - cx->fp = fp = &newifp->frame; - pc = script->code; -#if !JS_THREADED_INTERP - endpc = pc + script->length; -#endif - inlineCallCount++; - JS_RUNTIME_METER(rt, inlineCalls); - - /* Load first opcode and dispatch it (safe since JSOP_STOP). */ - op = (JSOp) *pc; - DO_OP(); - - bad_inline_call: - RESTORE_SP(fp); - JS_ASSERT(fp->pc == pc); - script = fp->script; - depth = (jsint) script->depth; - atoms = script->atomMap.vector; - js_FreeRawStack(cx, newmark); - ok = JS_FALSE; - goto out; } + do_invoke: ok = js_Invoke(cx, argc, 0); RESTORE_SP(fp); LOAD_INTERRUPT_HANDLER(cx); if (!ok) goto out; JS_RUNTIME_METER(rt, nonInlineCalls); + + end_call: #if JS_HAS_LVALUE_RETURN if (cx->rval2set) { /* @@ -4110,8 +4213,13 @@ interrupt: OBJ_DROP_PROPERTY(cx, obj2, prop); } PUSH_OPND(rval); - if (op == JSOP_CALLNAME) + if (op == JSOP_CALLNAME) { PUSH_OPND(OBJECT_TO_JSVAL(obj)); + SAVE_SP(fp); + ok = ComputeThis(cx, sp); + if (!ok) + goto out; + } END_CASE(JSOP_NAME) BEGIN_CASE(JSOP_UINT16) @@ -4576,6 +4684,19 @@ interrupt: PUSH_OPND(rval); END_CASE(JSOP_ARGCNT) +#define PUSH_GLOBAL_THIS(cx,sp) \ + JS_BEGIN_MACRO \ + PUSH_OPND(JSVAL_NULL); \ + SAVE_SP_AND_PC(fp); \ + ok = ComputeGlobalThis(cx, sp); \ + if (!ok) \ + goto out; \ + JS_END_MACRO + + BEGIN_CASE(JSOP_GLOBALTHIS) + PUSH_GLOBAL_THIS(cx, sp); + END_CASE(JSOP_GLOBALTHIS) + BEGIN_CASE(JSOP_GETARG) BEGIN_CASE(JSOP_CALLARG) slot = GET_ARGNO(pc); @@ -4583,7 +4704,7 @@ interrupt: METER_SLOT_OP(op, slot); PUSH_OPND(fp->argv[slot]); if (op == JSOP_CALLARG) - PUSH_OPND(JSVAL_NULL); + PUSH_GLOBAL_THIS(cx, sp); END_CASE(JSOP_GETARG) BEGIN_CASE(JSOP_SETARG) @@ -4602,7 +4723,7 @@ interrupt: METER_SLOT_OP(op, slot); PUSH_OPND(fp->vars[slot]); if (op == JSOP_CALLVAR) - PUSH_OPND(JSVAL_NULL); + PUSH_GLOBAL_THIS(cx, sp); END_CASE(JSOP_GETVAR) BEGIN_CASE(JSOP_SETVAR) @@ -4722,7 +4843,7 @@ interrupt: BEGIN_CASE(JSOP_DEFFUN) LOAD_FUNCTION(0); - fun = (JSFunction *) JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); id = ATOM_TO_JSID(fun->atom); /* @@ -4963,7 +5084,7 @@ interrupt: * name is [fun->atom, the identifier parsed by the compiler], * value is Result(3), and attributes are { DontDelete, ReadOnly }. */ - fun = (JSFunction *) JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); attrs = JSFUN_GSFLAG2ATTR(fun->flags); if (attrs) { attrs |= JSPROP_SHARED; @@ -5037,7 +5158,7 @@ interrupt: * unless fun is a getter or setter (in which case, obj is cast to * a JSPropertyOp and passed accordingly). */ - fun = (JSFunction *) JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); attrs = JSFUN_GSFLAG2ATTR(fun->flags); if (attrs) { attrs |= JSPROP_SHARED; @@ -5515,8 +5636,13 @@ interrupt: if (!ok) goto out; STORE_OPND(-1, rval); - if (op == JSOP_CALLXMLNAME) + if (op == JSOP_CALLXMLNAME) { PUSH_OPND(OBJECT_TO_JSVAL(obj)); + SAVE_SP(fp); + ok = ComputeThis(cx, sp); + if (!ok) + goto out; + } END_CASE(JSOP_XMLNAME) BEGIN_CASE(JSOP_DESCENDANTS) @@ -5661,10 +5787,10 @@ interrupt: /* Get an immediate atom naming the property. */ LOAD_ATOM(0); id = ATOM_TO_JSID(atom); - lval = FETCH_OPND(-1); + PUSH(JSVAL_NULL); SAVE_SP_AND_PC(fp); + lval = FETCH_OPND(-2); if (!JSVAL_IS_PRIMITIVE(lval)) { - STORE_OPND(-1, lval); obj = JSVAL_TO_OBJECT(lval); /* Special-case XML object method lookup, per ECMA-357. */ @@ -5678,6 +5804,13 @@ interrupt: } else { ok = OBJ_GET_PROPERTY(cx, obj, id, &rval); } + if (!ok) + goto out; + STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); + STORE_OPND(-2, rval); + ok = ComputeThis(cx, sp); + if (!ok) + goto out; } else { if (JSVAL_IS_STRING(lval)) { i = JSProto_String; @@ -5692,18 +5825,27 @@ interrupt: ok = JS_FALSE; goto out; } + ok = js_GetClassPrototype(cx, NULL, INT_TO_JSID(i), &obj); if (!ok) goto out; JS_ASSERT(obj); - STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); ok = OBJ_GET_PROPERTY(cx, obj, id, &rval); - obj = (JSObject *) lval; /* keep tagged as non-object */ + if (!ok) + goto out; + STORE_OPND(-1, lval); + STORE_OPND(-2, rval); + + /* Wrap primitive lval in object clothing if necessary. */ + if (!VALUE_IS_FUNCTION(cx, rval) || + (obj = JSVAL_TO_OBJECT(rval), + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj), + !PRIMITIVE_THIS_TEST(fun, lval))) { + ok = js_PrimitiveToObject(cx, &sp[-1]); + if (!ok) + goto out; + } } - if (!ok) - goto out; - STORE_OPND(-1, rval); - PUSH_OPND(OBJECT_TO_JSVAL(obj)); END_CASE(JSOP_CALLPROP) BEGIN_CASE(JSOP_GETFUNNS) @@ -5810,7 +5952,7 @@ interrupt: JS_ASSERT(slot < (uintN)depth); PUSH_OPND(fp->spbase[slot]); if (op == JSOP_CALLLOCAL) - PUSH_OPND(JSVAL_NULL); + PUSH_GLOBAL_THIS(cx, sp); END_CASE(JSOP_GETLOCAL) BEGIN_CASE(JSOP_SETLOCAL) @@ -5906,8 +6048,21 @@ interrupt: JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_ArrayClass); rval = FETCH_OPND(-1); - /* We know that the array is created with only a 'length' slot. */ - i = obj->map->freeslot - (JSSLOT_FREE(&js_ArrayClass) + 1); + /* + * We know that the array is created with only a 'length' private + * data slot at JSSLOT_ARRAY_LENGTH, and that previous iterations + * of the comprehension have added the only properties directly in + * the array object. + */ + lval = obj->fslots[JSSLOT_ARRAY_LENGTH]; + JS_ASSERT(JSVAL_IS_INT(lval)); + i = JSVAL_TO_INT(lval); + if (i == ARRAY_INIT_LIMIT) { + JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL, + JSMSG_ARRAY_INIT_TOO_BIG); + ok = JS_FALSE; + goto out; + } id = INT_TO_JSID(i); SAVE_SP_AND_PC(fp); @@ -5932,7 +6087,6 @@ interrupt: #if JS_THREADED_INTERP L_JSOP_BACKPATCH: L_JSOP_BACKPATCH_POP: - L_JSOP_UNUSED117: #else default: #endif diff --git a/mozilla/js/src/jsinterp.h b/mozilla/js/src/jsinterp.h index 43a50178126..4881d46ab83 100644 --- a/mozilla/js/src/jsinterp.h +++ b/mozilla/js/src/jsinterp.h @@ -110,6 +110,8 @@ typedef struct JSInlineFrame { #define JSFRAME_ITERATOR 0x800 /* trying to get an iterator for for-in */ #define JSFRAME_POP_BLOCKS 0x1000 /* scope chain contains blocks to pop */ #define JSFRAME_GENERATOR 0x2000 /* frame belongs to generator-iterator */ +#define JSFRAME_IN_FAST_CALL 0x4000 /* calling frame is calling a fast native */ +#define JSFRAME_DID_SET_RVAL 0x8000 /* fast native used JS_SET_RVAL(cx, vp) */ #define JSFRAME_OVERRIDE_SHIFT 24 /* override bit-set params; see jsfun.c */ #define JSFRAME_OVERRIDE_BITS 8 @@ -151,6 +153,18 @@ extern void js_DumpCallTable(JSContext *cx); extern JSObject * js_GetScopeChain(JSContext *cx, JSStackFrame *fp); +/* + * Given a context and a vector of [callee, this, args...] for a function that + * was specified with a JSFUN_THISP_PRIMITIVE flag, get the primitive value of + * |this| into *thisvp. In doing so, if |this| is an object, insist it is an + * instance of clasp and extract its private slot value to return via *thisvp. + * + * NB: this function loads and uses *vp before storing *thisvp, so the two may + * alias the same jsval. + */ +extern JSBool +js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp); + /* * For a call with arguments argv including argv[-1] (nominal |this|) and * argv[-2] (callee) replace null |this| with callee's parent, replace diff --git a/mozilla/js/src/jsiter.c b/mozilla/js/src/jsiter.c index 9d09ad48487..9296d19d4af 100644 --- a/mozilla/js/src/jsiter.c +++ b/mozilla/js/src/jsiter.c @@ -282,17 +282,19 @@ js_ThrowStopIteration(JSContext *cx, JSObject *obj) } static JSBool -iterator_next(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +iterator_next(JSContext *cx, uintN argc, jsval *vp) { - if (!JS_InstanceOf(cx, obj, &js_IteratorClass, argv)) + JSObject *obj; + + obj = JSVAL_TO_OBJECT(vp[1]); + if (!JS_InstanceOf(cx, obj, &js_IteratorClass, vp + 2)) return JS_FALSE; - if (!IteratorNextImpl(cx, obj, rval)) + if (!IteratorNextImpl(cx, obj, vp)) return JS_FALSE; - if (*rval == JSVAL_HOLE) { - *rval = JSVAL_NULL; + if (*vp == JSVAL_HOLE) { + *vp = JSVAL_NULL; js_ThrowStopIteration(cx, obj); return JS_FALSE; } @@ -300,17 +302,18 @@ iterator_next(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -iterator_self(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +iterator_self(JSContext *cx, uintN argc, jsval *vp) { - *rval = OBJECT_TO_JSVAL(obj); + *vp = vp[1]; return JS_TRUE; } +#define JSPROP_ROPERM (JSPROP_READONLY | JSPROP_PERMANENT) + static JSFunctionSpec iterator_methods[] = { - {js_iterator_str, iterator_self, 0,JSPROP_READONLY|JSPROP_PERMANENT,0}, - {js_next_str, iterator_next, 0,JSPROP_READONLY|JSPROP_PERMANENT,0}, - {0,0,0,0,0} + JS_FN(js_iterator_str, iterator_self, 0,0,JSPROP_ROPERM,0), + JS_FN(js_next_str, iterator_next, 0,0,JSPROP_ROPERM,0), + JS_FS_END }; uintN @@ -900,8 +903,10 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, if (ok) { /* Returned, explicitly or by falling off the end. */ - if (op == JSGENOP_CLOSE) + if (op == JSGENOP_CLOSE) { + *rval = JSVAL_VOID; return JS_TRUE; + } return js_ThrowStopIteration(cx, obj); } @@ -916,6 +921,7 @@ static JSBool CloseGenerator(JSContext *cx, JSObject *obj) { JSGenerator *gen; + jsval junk; JS_ASSERT(STOBJ_GET_CLASS(obj) == &js_GeneratorClass); gen = (JSGenerator *) JS_GetPrivate(cx, obj); @@ -927,21 +933,22 @@ CloseGenerator(JSContext *cx, JSObject *obj) if (gen->state == JSGEN_CLOSED) return JS_TRUE; - /* We pass null as rval since SendToGenerator never uses it with CLOSE. */ - return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JSVAL_VOID, NULL); + /* SendToGenerator always sets *rval to JSVAL_VOID for JSGENOP_CLOSE. */ + return SendToGenerator(cx, JSGENOP_CLOSE, obj, gen, JSVAL_VOID, &junk); } /* * Common subroutine of generator_(next|send|throw|close) methods. */ static JSBool -generator_op(JSContext *cx, JSGeneratorOp op, - JSObject *obj, uintN argc, jsval *argv, jsval *rval) +generator_op(JSContext *cx, JSGeneratorOp op, jsval *vp) { + JSObject *obj; JSGenerator *gen; jsval arg; - if (!JS_InstanceOf(cx, obj, &js_GeneratorClass, argv)) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!JS_InstanceOf(cx, obj, &js_GeneratorClass, vp + 2)) return JS_FALSE; gen = (JSGenerator *) JS_GetPrivate(cx, obj); @@ -957,9 +964,9 @@ generator_op(JSContext *cx, JSGeneratorOp op, break; case JSGENOP_SEND: - if (!JSVAL_IS_VOID(argv[0])) { + if (!JSVAL_IS_VOID(vp[2])) { js_ReportValueError(cx, JSMSG_BAD_GENERATOR_SEND, - JSDVG_SEARCH_STACK, argv[0], NULL); + JSDVG_SEARCH_STACK, vp[2], NULL); return JS_FALSE; } break; @@ -976,7 +983,7 @@ generator_op(JSContext *cx, JSGeneratorOp op, case JSGENOP_SEND: return js_ThrowStopIteration(cx, obj); case JSGENOP_THROW: - JS_SetPendingException(cx, argv[0]); + JS_SetPendingException(cx, vp[2]); return JS_FALSE; default: JS_ASSERT(op == JSGENOP_CLOSE); @@ -985,48 +992,44 @@ generator_op(JSContext *cx, JSGeneratorOp op, } arg = (op == JSGENOP_SEND || op == JSGENOP_THROW) - ? argv[0] + ? vp[2] : JSVAL_VOID; - if (!SendToGenerator(cx, op, obj, gen, arg, rval)) + if (!SendToGenerator(cx, op, obj, gen, arg, vp)) return JS_FALSE; return JS_TRUE; } static JSBool -generator_send(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +generator_send(JSContext *cx, uintN argc, jsval *vp) { - return generator_op(cx, JSGENOP_SEND, obj, argc, argv, rval); + return generator_op(cx, JSGENOP_SEND, vp); } static JSBool -generator_next(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +generator_next(JSContext *cx, uintN argc, jsval *vp) { - return generator_op(cx, JSGENOP_NEXT, obj, argc, argv, rval); + return generator_op(cx, JSGENOP_NEXT, vp); } static JSBool -generator_throw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +generator_throw(JSContext *cx, uintN argc, jsval *vp) { - return generator_op(cx, JSGENOP_THROW, obj, argc, argv, rval); + return generator_op(cx, JSGENOP_THROW, vp); } static JSBool -generator_close(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +generator_close(JSContext *cx, uintN argc, jsval *vp) { - return generator_op(cx, JSGENOP_CLOSE, obj, argc, argv, rval); + return generator_op(cx, JSGENOP_CLOSE, vp); } static JSFunctionSpec generator_methods[] = { - {js_iterator_str, iterator_self, 0,JSPROP_READONLY|JSPROP_PERMANENT,0}, - {js_next_str, generator_next, 0,JSPROP_READONLY|JSPROP_PERMANENT,0}, - {js_send_str, generator_send, 1,JSPROP_READONLY|JSPROP_PERMANENT,0}, - {js_throw_str, generator_throw, 1,JSPROP_READONLY|JSPROP_PERMANENT,0}, - {js_close_str, generator_close, 0,JSPROP_READONLY|JSPROP_PERMANENT,0}, - {0,0,0,0,0} + JS_FN(js_iterator_str, iterator_self, 0,0,JSPROP_ROPERM,0), + JS_FN(js_next_str, generator_next, 0,0,JSPROP_ROPERM,0), + JS_FN(js_send_str, generator_send, 1,1,JSPROP_ROPERM,0), + JS_FN(js_throw_str, generator_throw, 1,1,JSPROP_ROPERM,0), + JS_FN(js_close_str, generator_close, 0,0,JSPROP_ROPERM,0), + JS_FS_END }; #endif /* JS_HAS_GENERATORS */ diff --git a/mozilla/js/src/jsnum.c b/mozilla/js/src/jsnum.c index 27e132e39c5..676e55a185c 100644 --- a/mozilla/js/src/jsnum.c +++ b/mozilla/js/src/jsnum.c @@ -66,35 +66,35 @@ #include "jsstr.h" static JSBool -num_isNaN(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_isNaN(JSContext *cx, uintN argc, jsval *vp) { jsdouble x; - if (!js_ValueToNumber(cx, argv[0], &x)) + if (!js_ValueToNumber(cx, vp[2], &x)) return JS_FALSE; - *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x)); + *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_NaN(x)); return JS_TRUE; } static JSBool -num_isFinite(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_isFinite(JSContext *cx, uintN argc, jsval *vp) { jsdouble x; - if (!js_ValueToNumber(cx, argv[0], &x)) + if (!js_ValueToNumber(cx, vp[2], &x)) return JS_FALSE; - *rval = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x)); + *vp = BOOLEAN_TO_JSVAL(JSDOUBLE_IS_FINITE(x)); return JS_TRUE; } static JSBool -num_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_parseFloat(JSContext *cx, uintN argc, jsval *vp) { JSString *str; jsdouble d; const jschar *bp, *ep; - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; /* XXXbe js_strtod shouldn't require NUL termination */ @@ -104,15 +104,15 @@ num_parseFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rva if (!js_strtod(cx, bp, &ep, &d)) return JS_FALSE; if (ep == bp) { - *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); return JS_TRUE; } - return js_NewNumberValue(cx, d, rval); + return js_NewNumberValue(cx, d, vp); } /* See ECMA 15.1.2.2. */ static JSBool -num_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_parseInt(JSContext *cx, uintN argc, jsval *vp) { jsint radix; JSString *str; @@ -120,17 +120,17 @@ num_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) const jschar *bp, *ep; if (argc > 1) { - if (!js_ValueToECMAInt32(cx, argv[1], &radix)) + if (!js_ValueToECMAInt32(cx, vp[3], &radix)) return JS_FALSE; } else { radix = 0; } if (radix != 0 && (radix < 2 || radix > 36)) { - *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); return JS_TRUE; } - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; /* XXXbe js_strtointeger shouldn't require NUL termination */ @@ -140,10 +140,10 @@ num_parseInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (!js_strtointeger(cx, bp, &ep, radix, &d)) return JS_FALSE; if (ep == bp) { - *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); return JS_TRUE; } - return js_NewNumberValue(cx, d, rval); + return js_NewNumberValue(cx, d, vp); } const char js_Infinity_str[] = "Infinity"; @@ -154,11 +154,11 @@ const char js_parseFloat_str[] = "parseFloat"; const char js_parseInt_str[] = "parseInt"; static JSFunctionSpec number_functions[] = { - {js_isNaN_str, num_isNaN, 1,0,0}, - {js_isFinite_str, num_isFinite, 1,0,0}, - {js_parseFloat_str, num_parseFloat, 1,0,0}, - {js_parseInt_str, num_parseInt, 2,0,0}, - {0,0,0,0,0} + JS_FN(js_isNaN_str, num_isNaN, 1,1,0,0), + JS_FN(js_isFinite_str, num_isFinite, 1,1,0,0), + JS_FN(js_parseFloat_str, num_parseFloat, 1,1,0,0), + JS_FN(js_parseInt_str, num_parseInt, 1,2,0,0), + JS_FS_END }; JSClass js_NumberClass = { @@ -193,7 +193,7 @@ Number(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #if JS_HAS_TOSOURCE static JSBool -num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_toSource(JSContext *cx, uintN argc, jsval *vp) { jsval v; jsdouble d; @@ -201,14 +201,9 @@ num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) char buf[64]; JSString *str; - if (JSVAL_IS_NUMBER((jsval)obj)) { - v = (jsval)obj; - } else { - if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv)) - return JS_FALSE; - v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - JS_ASSERT(JSVAL_IS_NUMBER(v)); - } + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_NUMBER(v)); d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); numStr = JS_dtostr(numBuf, sizeof numBuf, DTOSTR_STANDARD, 0, d); if (!numStr) { @@ -219,7 +214,7 @@ num_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) str = JS_NewStringCopyZ(cx, buf); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } #endif @@ -253,25 +248,20 @@ IntToString(jsint i, char *buf, size_t bufSize) } static JSBool -num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_toString(JSContext *cx, uintN argc, jsval *vp) { jsval v; jsdouble d; jsint base; JSString *str; - if (JSVAL_IS_NUMBER((jsval)obj)) { - v = (jsval)obj; - } else { - if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv)) - return JS_FALSE; - v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - JS_ASSERT(JSVAL_IS_NUMBER(v)); - } + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_NUMBER(v)); d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); base = 10; if (argc != 0) { - if (!js_ValueToECMAInt32(cx, argv[0], &base)) + if (!js_ValueToECMAInt32(cx, vp[2], &base)) return JS_FALSE; if (base < 2 || base > 36) { char numBuf[12]; @@ -294,13 +284,12 @@ num_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +num_toLocaleString(JSContext *cx, uintN argc, jsval *vp) { char thousandsLength, decimalLength; const char *numGrouping, *tmpGroup; @@ -314,10 +303,10 @@ num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, * Create the string, move back to bytes to make string twiddling * a bit easier and so we can insert platform charset seperators. */ - if (!num_toString(cx, obj, 0, argv, rval)) + if (!num_toString(cx, argc, vp)) return JS_FALSE; - JS_ASSERT(JSVAL_IS_STRING(*rval)); - numStr = JSVAL_TO_STRING(*rval); + JS_ASSERT(JSVAL_IS_STRING(*vp)); + numStr = JSVAL_TO_STRING(*vp); num = js_GetStringBytes(cx, numStr); if (!num) return JS_FALSE; @@ -383,7 +372,7 @@ num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, } if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode) - return cx->localeCallbacks->localeToUnicode(cx, buf, rval); + return cx->localeCallbacks->localeToUnicode(cx, buf, vp); str = JS_NewString(cx, buf, size); if (!str) { @@ -391,21 +380,25 @@ num_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); - + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -num_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_valueOf(JSContext *cx, uintN argc, jsval *vp) { - if (JSVAL_IS_NUMBER((jsval)obj)) { - *rval = (jsval)obj; + jsval v; + JSObject *obj; + + v = vp[1]; + if (JSVAL_IS_NUMBER(v)) { + *vp = v; return JS_TRUE; } - if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv)) + obj = JSVAL_TO_OBJECT(v); + if (!JS_InstanceOf(cx, obj, &js_NumberClass, vp + 2)) return JS_FALSE; - *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); + *vp = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); return JS_TRUE; } @@ -413,29 +406,28 @@ num_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #define MAX_PRECISION 100 static JSBool -num_to(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, JSDToStrMode zeroArgMode, - JSDToStrMode oneArgMode, jsint precisionMin, jsint precisionMax, jsint precisionOffset) +num_to(JSContext *cx, JSDToStrMode zeroArgMode, JSDToStrMode oneArgMode, + jsint precisionMin, jsint precisionMax, jsint precisionOffset, + uintN argc, jsval *vp) { jsval v; jsdouble d, precision; JSString *str; - char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)], *numStr; /* Use MAX_PRECISION+1 because precisionOffset can be 1 */ - if (JSVAL_IS_NUMBER((jsval)obj)) { - v = (jsval)obj; - } else { - if (!JS_InstanceOf(cx, obj, &js_NumberClass, argv)) - return JS_FALSE; - v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - JS_ASSERT(JSVAL_IS_NUMBER(v)); - } + /* Use MAX_PRECISION+1 because precisionOffset can be 1. */ + char buf[DTOSTR_VARIABLE_BUFFER_SIZE(MAX_PRECISION+1)]; + char *numStr; + + if (!js_GetPrimitiveThis(cx, vp, &js_NumberClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_NUMBER(v)); d = JSVAL_IS_INT(v) ? (jsdouble)JSVAL_TO_INT(v) : *JSVAL_TO_DOUBLE(v); - if (JSVAL_IS_VOID(argv[0])) { + if (argc == 0) { precision = 0.0; oneArgMode = zeroArgMode; } else { - if (!js_ValueToNumber(cx, argv[0], &precision)) + if (!js_ValueToNumber(cx, vp[2], &precision)) return JS_FALSE; precision = js_DoubleToInteger(precision); if (precision < precisionMin || precision > precisionMax) { @@ -456,42 +448,46 @@ num_to(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval, JSDTo str = JS_NewStringCopyZ(cx, numStr); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(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, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_toFixed(JSContext *cx, uintN argc, jsval *vp) { - /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */ - return num_to(cx, obj, argc, argv, rval, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0); + return num_to(cx, DTOSTR_FIXED, DTOSTR_FIXED, -20, MAX_PRECISION, 0, + argc, vp); } static JSBool -num_toExponential(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_toExponential(JSContext *cx, uintN argc, jsval *vp) { - /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */ - return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, MAX_PRECISION, 1); + return num_to(cx, DTOSTR_STANDARD_EXPONENTIAL, DTOSTR_EXPONENTIAL, 0, + MAX_PRECISION, 1, argc, vp); } static JSBool -num_toPrecision(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +num_toPrecision(JSContext *cx, uintN argc, jsval *vp) { - /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */ - return num_to(cx, obj, argc, argv, rval, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0); + return num_to(cx, DTOSTR_STANDARD, DTOSTR_PRECISION, 1, MAX_PRECISION, 0, + argc, vp); } static JSFunctionSpec number_methods[] = { #if JS_HAS_TOSOURCE - {js_toSource_str, num_toSource, 0,JSFUN_THISP_NUMBER,0}, + JS_FN(js_toSource_str, num_toSource, 0,0,JSFUN_THISP_NUMBER,0), #endif - {js_toString_str, num_toString, 0,JSFUN_THISP_NUMBER,0}, - {js_toLocaleString_str, num_toLocaleString, 0,JSFUN_THISP_NUMBER,0}, - {js_valueOf_str, num_valueOf, 0,JSFUN_THISP_NUMBER,0}, - {"toFixed", num_toFixed, 1,JSFUN_THISP_NUMBER,0}, - {"toExponential", num_toExponential, 1,JSFUN_THISP_NUMBER,0}, - {"toPrecision", num_toPrecision, 1,JSFUN_THISP_NUMBER,0}, - {0,0,0,0,0} + JS_FN(js_toString_str, num_toString, 0,0,JSFUN_THISP_NUMBER,0), + JS_FN(js_toLocaleString_str, num_toLocaleString, 0,0,JSFUN_THISP_NUMBER,0), + JS_FN(js_valueOf_str, num_valueOf, 0,0,JSFUN_THISP_NUMBER,0), + JS_FN("toFixed", num_toFixed, 1,1,JSFUN_THISP_NUMBER,0), + JS_FN("toExponential", num_toExponential, 1,1,JSFUN_THISP_NUMBER,0), + JS_FN("toPrecision", num_toPrecision, 1,1,JSFUN_THISP_NUMBER,0), + JS_FS_END }; /* NB: Keep this in synch with number_constants[]. */ diff --git a/mozilla/js/src/jsobj.c b/mozilla/js/src/jsobj.c index 71767cda593..6d3168e0a36 100644 --- a/mozilla/js/src/jsobj.c +++ b/mozilla/js/src/jsobj.c @@ -703,11 +703,11 @@ js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map) #define OBJ_TOSTRING_EXTRA 4 /* for 4 local GC roots */ #if JS_HAS_TOSOURCE -JSBool -js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +static JSBool +obj_toSource(JSContext *cx, uintN argc, jsval *vp) { JSBool ok, outermost; + JSObject *obj; JSHashEntry *he; JSIdArray *ida; jschar *chars, *ochars, *vsharp; @@ -735,6 +735,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* If outermost, we need parentheses to be an expression, not a block. */ outermost = (cx->sharpObjectMap.depth == 0); + obj = JSVAL_TO_OBJECT(vp[1]); he = js_EnterSharpObject(cx, obj, &ida, &chars); if (!he) return JS_FALSE; @@ -833,15 +834,15 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* * We have four local roots for cooked and raw value GC safety. Hoist the - * "argv + 2" out of the loop using the val local, which refers to the raw + * "vp + 4" out of the loop using the val local, which refers to the raw * (unconverted, "uncooked") values. */ - val = argv + 2; + val = vp + 4; for (i = 0, length = ida->length; i < length; i++) { JSBool idIsLexicalIdentifier, needOldStyleGetterSetter; - /* Get strings for id and value and GC-root them via argv. */ + /* Get strings for id and value and GC-root them via vp. */ id = ida->vector[i]; #if JS_HAS_GETTER_SETTER @@ -861,7 +862,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, OBJ_DROP_PROPERTY(cx, obj2, prop); goto error; } - *rval = STRING_TO_JSVAL(idstr); /* local root */ + *vp = STRING_TO_JSVAL(idstr); /* local root */ idIsLexicalIdentifier = js_IsIdentifier(idstr); needOldStyleGetterSetter = !idIsLexicalIdentifier || @@ -936,7 +937,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, ok = JS_FALSE; goto error; } - *rval = STRING_TO_JSVAL(idstr); /* local root */ + *vp = STRING_TO_JSVAL(idstr); /* local root */ } idstrchars = JSSTRING_CHARS(idstr); idstrlength = JSSTRING_LENGTH(idstr); @@ -948,7 +949,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, ok = JS_FALSE; goto error; } - argv[j] = STRING_TO_JSVAL(valstr); /* local root */ + vp[2 + j] = STRING_TO_JSVAL(valstr); /* local root */ vchars = JSSTRING_CHARS(valstr); vlength = JSSTRING_LENGTH(valstr); @@ -1137,7 +1138,7 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, free(chars); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; overflow: @@ -1148,16 +1149,15 @@ js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } #endif /* JS_HAS_TOSOURCE */ -JSBool -js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +static JSBool +obj_toString(JSContext *cx, uintN argc, jsval *vp) { jschar *chars; size_t nchars; const char *clazz, *prefix; JSString *str; - clazz = OBJ_GET_CLASS(cx, obj)->name; + clazz = OBJ_GET_CLASS(cx, JS_THIS_OBJECT(cx, vp))->name; nchars = 9 + strlen(clazz); /* 9 for "[object ]" */ chars = (jschar *) JS_malloc(cx, (nchars + 1) * sizeof(jschar)); if (!chars) @@ -1177,28 +1177,27 @@ js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JS_free(cx, chars); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -js_obj_toLocaleString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +obj_toLocaleString(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - str = js_ValueToString(cx, argv[-1]); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -obj_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +obj_valueOf(JSContext *cx, uintN argc, jsval *vp) { - *rval = OBJECT_TO_JSVAL(obj); + *vp = vp[1]; return JS_TRUE; } @@ -1455,33 +1454,37 @@ obj_watch_handler(JSContext *cx, JSObject *obj, jsval id, jsval old, jsval *nvp, } static JSBool -obj_watch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +obj_watch(JSContext *cx, uintN argc, jsval *vp) { JSObject *callable; jsval userid, value; jsid propid; + JSObject *obj; uintN attrs; - callable = js_ValueToCallableObject(cx, &argv[1], 0); + callable = js_ValueToCallableObject(cx, &vp[3], 0); if (!callable) return JS_FALSE; /* Compute the unique int/atom symbol id needed by js_LookupProperty. */ - userid = argv[0]; + userid = vp[2]; if (!JS_ValueToId(cx, userid, &propid)) return JS_FALSE; + obj = JSVAL_TO_OBJECT(vp[1]); if (!OBJ_CHECK_ACCESS(cx, obj, propid, JSACC_WATCH, &value, &attrs)) return JS_FALSE; if (attrs & JSPROP_READONLY) return JS_TRUE; + *vp = JSVAL_VOID; return JS_SetWatchPoint(cx, obj, userid, obj_watch_handler, callable); } static JSBool -obj_unwatch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +obj_unwatch(JSContext *cx, uintN argc, jsval *vp) { - return JS_ClearWatchPoint(cx, obj, argv[0], NULL, NULL); + *vp = JSVAL_VOID; + return JS_ClearWatchPoint(cx, JSVAL_TO_OBJECT(vp[1]), vp[2], NULL, NULL); } #endif /* JS_HAS_OBJ_WATCHPOINT */ @@ -1493,30 +1496,31 @@ obj_unwatch(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) /* Proposed ECMA 15.2.4.5. */ static JSBool -obj_hasOwnProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +obj_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) { - return js_HasOwnPropertyHelper(cx, obj, obj->map->ops->lookupProperty, - argc, argv, rval); + JSObject *obj; + + obj = JSVAL_TO_OBJECT(vp[1]); + return js_HasOwnPropertyHelper(cx, obj->map->ops->lookupProperty, vp); } JSBool -js_HasOwnPropertyHelper(JSContext *cx, JSObject *obj, JSLookupPropOp lookup, - uintN argc, jsval *argv, jsval *rval) +js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, jsval *vp) { jsid id; - JSObject *obj2; + JSObject *obj, *obj2; JSProperty *prop; JSScopeProperty *sprop; - if (!JS_ValueToId(cx, argv[0], &id)) + if (!JS_ValueToId(cx, vp[2], &id)) return JS_FALSE; + obj = JSVAL_TO_OBJECT(vp[1]); if (!lookup(cx, obj, id, &obj2, &prop)) return JS_FALSE; if (!prop) { - *rval = JSVAL_FALSE; + *vp = JSVAL_FALSE; } else if (obj2 == obj) { - *rval = JSVAL_TRUE; + *vp = JSVAL_TRUE; } else { JSClass *clasp; JSExtendedClass *xclasp; @@ -1527,7 +1531,7 @@ js_HasOwnPropertyHelper(JSContext *cx, JSObject *obj, JSLookupPropOp lookup, : NULL; if (xclasp && xclasp->outerObject && xclasp->outerObject(cx, obj2) == obj) { - *rval = JSVAL_TRUE; + *vp = JSVAL_TRUE; } else if (OBJ_IS_NATIVE(obj2) && OBJ_GET_CLASS(cx, obj2) == clasp) { /* * The combination of JSPROP_SHARED and JSPROP_PERMANENT in a @@ -1545,9 +1549,9 @@ js_HasOwnPropertyHelper(JSContext *cx, JSObject *obj, JSLookupPropOp lookup, * owned, or indirectly delegated. */ sprop = (JSScopeProperty *)prop; - *rval = BOOLEAN_TO_JSVAL(SPROP_IS_SHARED_PERMANENT(sprop)); + *vp = BOOLEAN_TO_JSVAL(SPROP_IS_SHARED_PERMANENT(sprop)); } else { - *rval = JSVAL_FALSE; + *vp = JSVAL_FALSE; } } if (prop) @@ -1557,36 +1561,35 @@ js_HasOwnPropertyHelper(JSContext *cx, JSObject *obj, JSLookupPropOp lookup, /* Proposed ECMA 15.2.4.6. */ static JSBool -obj_isPrototypeOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +obj_isPrototypeOf(JSContext *cx, uintN argc, jsval *vp) { JSBool b; - if (!js_IsDelegate(cx, obj, *argv, &b)) + if (!js_IsDelegate(cx, JSVAL_TO_OBJECT(vp[1]), vp[2], &b)) return JS_FALSE; - *rval = BOOLEAN_TO_JSVAL(b); + *vp = BOOLEAN_TO_JSVAL(b); return JS_TRUE; } /* Proposed ECMA 15.2.4.7. */ static JSBool -obj_propertyIsEnumerable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +obj_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp) { jsid id; + JSObject *obj, *pobj; uintN attrs; - JSObject *obj2; JSProperty *prop; JSBool ok; - if (!JS_ValueToId(cx, argv[0], &id)) + if (!JS_ValueToId(cx, vp[2], &id)) return JS_FALSE; - if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) + obj = JS_THIS_OBJECT(cx, vp); + if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) return JS_FALSE; if (!prop) { - *rval = JSVAL_FALSE; + *vp = JSVAL_FALSE; return JS_TRUE; } @@ -1601,31 +1604,31 @@ obj_propertyIsEnumerable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, * technique used to satisfy ECMA requirements; users should not be able * to distinguish a shared permanent proto-property from a local one. */ - if (obj2 != obj && - !(OBJ_IS_NATIVE(obj2) && + if (pobj != obj && + !(OBJ_IS_NATIVE(pobj) && SPROP_IS_SHARED_PERMANENT((JSScopeProperty *)prop))) { - OBJ_DROP_PROPERTY(cx, obj2, prop); - *rval = JSVAL_FALSE; + OBJ_DROP_PROPERTY(cx, pobj, prop); + *vp = JSVAL_FALSE; return JS_TRUE; } - ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &attrs); - OBJ_DROP_PROPERTY(cx, obj2, prop); + ok = OBJ_GET_ATTRIBUTES(cx, pobj, id, prop, &attrs); + OBJ_DROP_PROPERTY(cx, pobj, prop); if (ok) - *rval = BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0); + *vp = BOOLEAN_TO_JSVAL((attrs & JSPROP_ENUMERATE) != 0); return ok; } #if JS_HAS_GETTER_SETTER static JSBool -obj_defineGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +obj_defineGetter(JSContext *cx, uintN argc, jsval *vp) { jsval fval, junk; jsid id; + JSObject *obj; uintN attrs; - fval = argv[1]; + fval = vp[3]; if (JS_TypeOfValue(cx, fval) != JSTYPE_FUNCTION) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GETTER_OR_SETTER, @@ -1633,8 +1636,9 @@ obj_defineGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; } - if (!JS_ValueToId(cx, argv[0], &id)) + if (!JS_ValueToId(cx, vp[2], &id)) return JS_FALSE; + obj = JSVAL_TO_OBJECT(vp[1]); if (!js_CheckRedeclaration(cx, obj, id, JSPROP_GETTER, NULL, NULL)) return JS_FALSE; /* @@ -1643,6 +1647,7 @@ obj_defineGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, */ if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &junk, &attrs)) return JS_FALSE; + *vp = JSVAL_VOID; return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, (JSPropertyOp) JSVAL_TO_OBJECT(fval), NULL, JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED, @@ -1650,14 +1655,14 @@ obj_defineGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -obj_defineSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +obj_defineSetter(JSContext *cx, uintN argc, jsval *vp) { jsval fval, junk; jsid id; + JSObject *obj; uintN attrs; - fval = argv[1]; + fval = vp[3]; if (JS_TypeOfValue(cx, fval) != JSTYPE_FUNCTION) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GETTER_OR_SETTER, @@ -1665,8 +1670,9 @@ obj_defineSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; } - if (!JS_ValueToId(cx, argv[0], &id)) + if (!JS_ValueToId(cx, vp[2], &id)) return JS_FALSE; + obj = JSVAL_TO_OBJECT(vp[1]); if (!js_CheckRedeclaration(cx, obj, id, JSPROP_SETTER, NULL, NULL)) return JS_FALSE; /* @@ -1675,6 +1681,7 @@ obj_defineSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, */ if (!OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &junk, &attrs)) return JS_FALSE; + *vp = JSVAL_VOID; return OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, (JSPropertyOp) JSVAL_TO_OBJECT(fval), JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED, @@ -1682,23 +1689,23 @@ obj_defineSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -obj_lookupGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +obj_lookupGetter(JSContext *cx, uintN argc, jsval *vp) { jsid id; JSObject *pobj; JSProperty *prop; JSScopeProperty *sprop; - if (!JS_ValueToId(cx, argv[0], &id)) + if (!JS_ValueToId(cx, vp[2], &id)) return JS_FALSE; - if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) + if (!OBJ_LOOKUP_PROPERTY(cx, JSVAL_TO_OBJECT(vp[1]), id, &pobj, &prop)) return JS_FALSE; + *vp = JSVAL_VOID; if (prop) { if (OBJ_IS_NATIVE(pobj)) { sprop = (JSScopeProperty *) prop; if (sprop->attrs & JSPROP_GETTER) - *rval = OBJECT_TO_JSVAL(sprop->getter); + *vp = OBJECT_TO_JSVAL(sprop->getter); } OBJ_DROP_PROPERTY(cx, pobj, prop); } @@ -1706,23 +1713,23 @@ obj_lookupGetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -obj_lookupSetter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +obj_lookupSetter(JSContext *cx, uintN argc, jsval *vp) { jsid id; JSObject *pobj; JSProperty *prop; JSScopeProperty *sprop; - if (!JS_ValueToId(cx, argv[0], &id)) + if (!JS_ValueToId(cx, vp[2], &id)) return JS_FALSE; - if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &pobj, &prop)) + if (!OBJ_LOOKUP_PROPERTY(cx, JSVAL_TO_OBJECT(vp[1]), id, &pobj, &prop)) return JS_FALSE; + *vp = JSVAL_VOID; if (prop) { if (OBJ_IS_NATIVE(pobj)) { sprop = (JSScopeProperty *) prop; if (sprop->attrs & JSPROP_SETTER) - *rval = OBJECT_TO_JSVAL(sprop->setter); + *vp = OBJECT_TO_JSVAL(sprop->setter); } OBJ_DROP_PROPERTY(cx, pobj, prop); } @@ -1746,25 +1753,25 @@ const char js_lookupSetter_str[] = "__lookupSetter__"; static JSFunctionSpec object_methods[] = { #if JS_HAS_TOSOURCE - {js_toSource_str, js_obj_toSource, 0, 0, OBJ_TOSTRING_EXTRA}, + JS_FN(js_toSource_str, obj_toSource, 0,0,0,OBJ_TOSTRING_EXTRA), #endif - {js_toString_str, js_obj_toString, 0, 0, OBJ_TOSTRING_EXTRA}, - {js_toLocaleString_str, js_obj_toLocaleString, 0, 0, OBJ_TOSTRING_EXTRA}, - {js_valueOf_str, obj_valueOf, 0,0,0}, + JS_FN(js_toString_str, obj_toString, 0,0,0,0), + JS_FN(js_toLocaleString_str, obj_toLocaleString, 0,0,0,0), + JS_FN(js_valueOf_str, obj_valueOf, 0,0,0,0), #if JS_HAS_OBJ_WATCHPOINT - {js_watch_str, obj_watch, 2,0,0}, - {js_unwatch_str, obj_unwatch, 1,0,0}, + JS_FN(js_watch_str, obj_watch, 2,2,0,0), + JS_FN(js_unwatch_str, obj_unwatch, 1,1,0,0), #endif - {js_hasOwnProperty_str, obj_hasOwnProperty, 1,0,0}, - {js_isPrototypeOf_str, obj_isPrototypeOf, 1,0,0}, - {js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,0,0}, + JS_FN(js_hasOwnProperty_str, obj_hasOwnProperty, 1,1,0,0), + JS_FN(js_isPrototypeOf_str, obj_isPrototypeOf, 1,1,0,0), + JS_FN(js_propertyIsEnumerable_str, obj_propertyIsEnumerable, 1,1,0,0), #if JS_HAS_GETTER_SETTER - {js_defineGetter_str, obj_defineGetter, 2,0,0}, - {js_defineSetter_str, obj_defineSetter, 2,0,0}, - {js_lookupGetter_str, obj_lookupGetter, 1,0,0}, - {js_lookupSetter_str, obj_lookupSetter, 1,0,0}, + JS_FN(js_defineGetter_str, obj_defineGetter, 2,2,0,0), + JS_FN(js_defineSetter_str, obj_defineSetter, 2,2,0,0), + JS_FN(js_lookupGetter_str, obj_lookupGetter, 1,1,0,0), + JS_FN(js_lookupSetter_str, obj_lookupSetter, 1,1,0,0), #endif - {0,0,0,0,0} + JS_FS_END }; static JSBool diff --git a/mozilla/js/src/jsobj.h b/mozilla/js/src/jsobj.h index 0bf3f7fa488..19d44a01b06 100644 --- a/mozilla/js/src/jsobj.h +++ b/mozilla/js/src/jsobj.h @@ -154,19 +154,23 @@ struct JSObject { : (JS_ASSERT((slot) < (uint32)(obj)->dslots[-1]), \ (obj)->dslots[(slot) - JS_INITIAL_NSLOTS] = (value))) -#define STOBJ_GET_PROTO(obj) \ +#define STOBJ_GET_PROTO(obj) \ JSVAL_TO_OBJECT((obj)->fslots[JSSLOT_PROTO]) #define STOBJ_SET_PROTO(obj,proto) \ ((obj)->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto)) -#define STOBJ_GET_PARENT(obj) \ +#define STOBJ_GET_PARENT(obj) \ JSVAL_TO_OBJECT((obj)->fslots[JSSLOT_PARENT]) #define STOBJ_SET_PARENT(obj,parent) \ ((obj)->fslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent)) -#define STOBJ_GET_CLASS(obj) \ +#define STOBJ_GET_CLASS(obj) \ ((JSClass *)JSVAL_TO_PRIVATE((obj)->fslots[JSSLOT_CLASS])) +#define STOBJ_GET_PRIVATE(obj) \ + (JS_ASSERT(JSVAL_IS_INT(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE))), \ + JSVAL_TO_PRIVATE(STOBJ_GET_SLOT(obj, JSSLOT_PRIVATE))) + #define OBJ_CHECK_SLOT(obj,slot) \ JS_ASSERT(slot < (obj)->map->freeslot) @@ -195,6 +199,9 @@ struct JSObject { #define LOCKED_OBJ_GET_CLASS(obj) \ (OBJ_CHECK_SLOT(obj, JSSLOT_CLASS), STOBJ_GET_CLASS(obj)) +#define LOCKED_OBJ_GET_PRIVATE(obj) \ + (OBJ_CHECK_SLOT(obj, JSSLOT_PRIVATE), STOBJ_GET_PRIVATE(obj)) + #ifdef JS_THREADSAFE /* Thread-safe functions and wrapper macros for accessing slots in obj. */ @@ -260,10 +267,11 @@ struct JSObject { /* * Class is invariant and comes from the fixed JSCLASS_SLOT. Thus no locking - * is necessary to read it. + * is necessary to read it. Same for the private slot. */ #define GC_AWARE_GET_CLASS(cx, obj) STOBJ_GET_CLASS(obj) #define OBJ_GET_CLASS(cx,obj) STOBJ_GET_CLASS(obj) +#define OBJ_GET_PRIVATE(cx,obj) STOBJ_GET_PRIVATE(obj) /* Test whether a map or object is native. */ #define MAP_IS_NATIVE(map) \ @@ -360,16 +368,7 @@ extern void js_TraceSharpMap(JSTracer *trc, JSSharpObjectMap *map); extern JSBool -js_obj_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); - -extern JSBool -js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); - -extern JSBool -js_HasOwnPropertyHelper(JSContext *cx, JSObject *obj, JSLookupPropOp lookup, - uintN argc, jsval *argv, jsval *rval); +js_HasOwnPropertyHelper(JSContext *cx, JSLookupPropOp lookup, jsval *vp); extern JSObject* js_InitBlockClass(JSContext *cx, JSObject* obj); diff --git a/mozilla/js/src/jsopcode.c b/mozilla/js/src/jsopcode.c index cf076ff2f2c..b8c29df573a 100644 --- a/mozilla/js/src/jsopcode.c +++ b/mozilla/js/src/jsopcode.c @@ -2078,7 +2078,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) JS_GET_SCRIPT_OBJECT(jp->script, js_GetSrcNoteOffset(sn, 0), obj); do_function: - fun = (JSFunction *) JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); jp2 = JS_NEW_PRINTER(cx, "nested_function", jp->indent, jp->pretty); if (!jp2) @@ -2114,6 +2114,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) if ((cs->prec != 0 && cs->prec <= js_CodeSpec[NEXT_OP(pc)].prec) || pc[JSOP_GROUP_LENGTH] == JSOP_NULL || + pc[JSOP_GROUP_LENGTH] == JSOP_GLOBALTHIS || pc[JSOP_GROUP_LENGTH] == JSOP_DUP || pc[JSOP_GROUP_LENGTH] == JSOP_IFEQ || pc[JSOP_GROUP_LENGTH] == JSOP_IFNE) { @@ -2736,7 +2737,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) case JSOP_RETURN: obj = jp->object; LOCAL_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass); - fun = (JSFunction *) JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); if (fun->flags & JSFUN_EXPR_CLOSURE) { rval = POP_STR(); js_printf(jp, (*rval == '{') ? "(%s)%s" : ss_format, @@ -3822,7 +3823,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) SprintStack ss2; LOAD_FUNCTION(0); - fun = (JSFunction *) JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); LOCAL_ASSERT(FUN_INTERPRETED(fun)); inner = fun->u.i.script; @@ -3855,11 +3856,11 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) jp->script = outer; /* - * Advance over this op and its null |this| push, and + * Advance over this op and its global |this| push, and * arrange to advance over the call to this lambda. */ pc += len; - LOCAL_ASSERT(*pc == JSOP_NULL); + LOCAL_ASSERT(*pc == JSOP_GLOBALTHIS); pc += JSOP_NULL_LENGTH; LOCAL_ASSERT(*pc == JSOP_CALL); LOCAL_ASSERT(GET_ARGC(pc) == 0); @@ -3938,14 +3939,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) * parenthesization without confusing getter/setter code * that checks for JSOP_ANONFUNOBJ and JSOP_NAMEDFUNOBJ. */ - fun = (JSFunction *) JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); if (!(fun->flags & JSFUN_EXPR_CLOSURE)) indent |= JS_IN_GROUP_CONTEXT; - if (!js_fun_toString(cx, obj, indent, 0, NULL, &val)) + str = JS_DecompileFunction(cx, fun, indent); + if (!str) return NULL; } - sprint_string_value: - str = JSVAL_TO_STRING(val); + sprint_string: todo = SprintString(&ss->sprinter, str); break; @@ -3957,9 +3958,10 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop) case JSOP_REGEXP: GET_REGEXP_FROM_BYTECODE(jp->script, pc, 0, obj); do_regexp: - if (!js_regexp_toString(cx, obj, 0, NULL, &val)) + if (!js_regexp_toString(cx, obj, &val)) return NULL; - goto sprint_string_value; + str = JSVAL_TO_STRING(val); + goto sprint_string; case JSOP_TABLESWITCH: case JSOP_TABLESWITCHX: diff --git a/mozilla/js/src/jsopcode.tbl b/mozilla/js/src/jsopcode.tbl index 8bd4f3321eb..04128aed217 100644 --- a/mozilla/js/src/jsopcode.tbl +++ b/mozilla/js/src/jsopcode.tbl @@ -262,7 +262,9 @@ OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 0, 0, 0, JOF_BYTE) /* More exception handling ops. */ OPDEF(JSOP_EXCEPTION, 116,"exception", NULL, 1, 0, 1, 0, JOF_BYTE) -OPDEF(JSOP_UNUSED117, 117,"", NULL, 0, 0, 0, 0, 0) + +/* Push the global object as |this| for a non-reference-type callable. */ +OPDEF(JSOP_GLOBALTHIS,117,"globalthis", js_null_str, 1, 0, 1, 0, JOF_BYTE) /* * ECMA-compliant switch statement ops. @@ -310,10 +312,13 @@ OPDEF(JSOP_NAMEDFUNOBJ, 129, "namedfunobj", NULL, 3, 0, 1, 19, JOF_OBJECT */ OPDEF(JSOP_SETLOCALPOP, 130, "setlocalpop", NULL, 3, 1, 0, 3, JOF_LOCAL|JOF_NAME|JOF_SET) -/* ECMA-mandated parenthesization opcode, which nulls the reference base register, obj; see jsinterp.c. */ +/* Parenthesization opcode to help the decompiler. */ OPDEF(JSOP_GROUP, 131, "group", NULL, 1, 0, 0, 19, JOF_BYTE) -/* Host object extension: given 'o.item(i) = j', the left-hand side compiles JSOP_SETCALL, rather than JSOP_CALL. */ +/* + * Host object extension: given 'o.item(i) = j', the left-hand side compiles + * JSOP_SETCALL, rather than JSOP_CALL. + */ OPDEF(JSOP_SETCALL, 132, "setcall", NULL, 3, -1, 2, 18, JOF_UINT16|JOF_SET|JOF_ASSIGNING) /* diff --git a/mozilla/js/src/jsparse.c b/mozilla/js/src/jsparse.c index 44d6899aa22..a0fd1cef64c 100644 --- a/mozilla/js/src/jsparse.c +++ b/mozilla/js/src/jsparse.c @@ -1236,7 +1236,7 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, * can properly optimize accesses. */ JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass); - JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj)); + JS_ASSERT(fp->fun == (JSFunction *) OBJ_GET_PRIVATE(cx, varobj)); if (!js_LookupHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom), &pobj, &prop)) { return NULL; diff --git a/mozilla/js/src/jspubtd.h b/mozilla/js/src/jspubtd.h index 17907c553b2..f72b5b30edc 100644 --- a/mozilla/js/src/jspubtd.h +++ b/mozilla/js/src/jspubtd.h @@ -132,6 +132,8 @@ typedef struct JSContext JSContext; typedef struct JSErrorReport JSErrorReport; typedef struct JSFunction JSFunction; typedef struct JSFunctionSpec JSFunctionSpec; +typedef struct JSFastNativeSpec JSFastNativeSpec; +typedef struct JSFastNativeBlock JSFastNativeBlock; typedef struct JSTracer JSTracer; typedef struct JSIdArray JSIdArray; typedef struct JSProperty JSProperty; @@ -589,6 +591,10 @@ typedef JSBool (* JS_DLL_CALLBACK JSNative)(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval); +/* See jsapi.h, the JS_CALLEE, JS_THIS, etc. macros. */ +typedef JSBool +(* JS_DLL_CALLBACK JSFastNative)(JSContext *cx, uintN argc, jsval *vp); + /* Callbacks and their arguments. */ typedef enum JSContextOp { diff --git a/mozilla/js/src/jsregexp.c b/mozilla/js/src/jsregexp.c index 8880db9bd61..1db0288e609 100644 --- a/mozilla/js/src/jsregexp.c +++ b/mozilla/js/src/jsregexp.c @@ -3812,13 +3812,14 @@ regexp_finalize(JSContext *cx, JSObject *obj) /* Forward static prototype. */ static JSBool -regexp_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + JSBool test, jsval *rval); static JSBool regexp_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - return regexp_exec(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval); + return regexp_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, + JS_FALSE, rval); } #if JS_HAS_XDR @@ -3894,8 +3895,7 @@ JSClass js_RegExpClass = { static const jschar empty_regexp_ucstr[] = {'(', '?', ':', ')', 0}; JSBool -js_regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp) { JSRegExp *re; const jschar *source; @@ -3904,13 +3904,13 @@ js_regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, uintN flags; JSString *str; - if (!JS_InstanceOf(cx, obj, &js_RegExpClass, argv)) + if (!JS_InstanceOf(cx, obj, &js_RegExpClass, vp + 2)) return JS_FALSE; JS_LOCK_OBJ(cx, obj); re = (JSRegExp *) JS_GetPrivate(cx, obj); if (!re) { JS_UNLOCK_OBJ(cx, obj); - *rval = STRING_TO_JSVAL(cx->runtime->emptyString); + *vp = STRING_TO_JSVAL(cx->runtime->emptyString); return JS_TRUE; } @@ -3951,13 +3951,19 @@ js_regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JS_free(cx, chars); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -regexp_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +regexp_toString(JSContext *cx, uintN argc, jsval *vp) +{ + return js_regexp_toString(cx, JS_THIS_OBJECT(cx, vp), vp); +} + +static JSBool +regexp_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) { JSString *opt, *str; JSRegExp *oldre, *re; @@ -4075,6 +4081,12 @@ created: return ok2; } +static JSBool +regexp_compile(JSContext *cx, uintN argc, jsval *vp) +{ + return regexp_compile_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp); +} + static JSBool regexp_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JSBool test, jsval *rval) @@ -4152,30 +4164,31 @@ out: } static JSBool -regexp_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +regexp_exec(JSContext *cx, uintN argc, jsval *vp) { - return regexp_exec_sub(cx, obj, argc, argv, JS_FALSE, rval); + return regexp_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, JS_FALSE, + vp); } static JSBool -regexp_test(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +regexp_test(JSContext *cx, uintN argc, jsval *vp) { - if (!regexp_exec_sub(cx, obj, argc, argv, JS_TRUE, rval)) + if (!regexp_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, JS_TRUE, vp)) return JS_FALSE; - if (*rval != JSVAL_TRUE) - *rval = JSVAL_FALSE; + if (*vp != JSVAL_TRUE) + *vp = JSVAL_FALSE; return JS_TRUE; } static JSFunctionSpec regexp_methods[] = { #if JS_HAS_TOSOURCE - {js_toSource_str, js_regexp_toString, 0,0,0}, + JS_FN(js_toSource_str, regexp_toString, 0,0,0,0), #endif - {js_toString_str, js_regexp_toString, 0,0,0}, - {"compile", regexp_compile, 1,0,0}, - {"exec", regexp_exec, 0,0,0}, - {"test", regexp_test, 0,0,0}, - {0,0,0,0,0} + JS_FN(js_toString_str, regexp_toString, 0,0,0,0), + JS_FN("compile", regexp_compile, 0,2,0,0), + JS_FN("exec", regexp_exec, 0,1,0,0), + JS_FN("test", regexp_test, 0,1,0,0), + JS_FS_END }; static JSBool @@ -4184,7 +4197,7 @@ RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) { /* * If first arg is regexp and no flags are given, just return the arg. - * (regexp_compile detects the regexp + flags case and throws a + * (regexp_compile_sub detects the regexp + flags case and throws a * TypeError.) See 10.15.3.1. */ if ((argc < 2 || JSVAL_IS_VOID(argv[1])) && @@ -4200,12 +4213,12 @@ RegExp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_FALSE; /* - * regexp_compile does not use rval to root its temporaries - * so we can use it to root obj. + * regexp_compile_sub does not use rval to root its temporaries so we + * can use it to root obj. */ *rval = OBJECT_TO_JSVAL(obj); } - return regexp_compile(cx, obj, argc, argv, rval); + return regexp_compile_sub(cx, obj, argc, argv, rval); } JSObject * @@ -4230,7 +4243,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj) } /* Give RegExp.prototype private data so it matches the empty string. */ - if (!regexp_compile(cx, proto, 0, NULL, &rval)) + if (!regexp_compile_sub(cx, proto, 0, NULL, &rval)) goto bad; return proto; diff --git a/mozilla/js/src/jsregexp.h b/mozilla/js/src/jsregexp.h index fc16217fc5c..e1a540939cd 100644 --- a/mozilla/js/src/jsregexp.h +++ b/mozilla/js/src/jsregexp.h @@ -155,8 +155,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj); * Export js_regexp_toString to the decompiler. */ extern JSBool -js_regexp_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +js_regexp_toString(JSContext *cx, JSObject *obj, jsval *vp); /* * Create, serialize/deserialize, or clone a RegExp object. diff --git a/mozilla/js/src/jsscript.c b/mozilla/js/src/jsscript.c index 216fa755099..23ffa7e4fe3 100644 --- a/mozilla/js/src/jsscript.c +++ b/mozilla/js/src/jsscript.c @@ -64,8 +64,8 @@ #if JS_HAS_SCRIPT_OBJECT -static const char js_script_exec[] = "Script.prototype.exec"; -static const char js_script_compile[] = "Script.prototype.compile"; +static const char js_script_exec_str[] = "Script.prototype.exec"; +static const char js_script_compile_str[] = "Script.prototype.compile"; /* * This routine requires that obj has been locked previously. @@ -94,9 +94,9 @@ AdjustScriptExecDepth(JSContext *cx, JSObject *obj, jsint delta) #if JS_HAS_TOSOURCE static JSBool -script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +script_toSource(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; uint32 indent; JSScript *script; size_t i, j, k, n; @@ -104,11 +104,12 @@ script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jschar *s, *t; JSString *str; - if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2)) return JS_FALSE; indent = 0; - if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) + if (argc != 0 && !js_ValueToECMAUint32(cx, vp[2], &indent)) return JS_FALSE; script = (JSScript *) JS_GetPrivate(cx, obj); @@ -151,28 +152,29 @@ script_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JS_free(cx, t); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } #endif /* JS_HAS_TOSOURCE */ static JSBool -script_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +script_toString(JSContext *cx, uintN argc, jsval *vp) { uint32 indent; + JSObject *obj; JSScript *script; JSString *str; indent = 0; - if (argc && !js_ValueToECMAUint32(cx, argv[0], &indent)) + if (argc != 0 && !js_ValueToECMAUint32(cx, vp[2], &indent)) return JS_FALSE; - if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) + obj = JS_THIS_OBJECT(cx, vp); + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2)) return JS_FALSE; script = (JSScript *) JS_GetPrivate(cx, obj); if (!script) { - *rval = STRING_TO_JSVAL(cx->runtime->emptyString); + *vp = STRING_TO_JSVAL(cx->runtime->emptyString); return JS_TRUE; } @@ -180,13 +182,13 @@ script_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, (uintN)indent); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) { JSString *str; JSObject *scopeobj; @@ -242,7 +244,7 @@ script_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } /* Ensure we compile this script with the right (inner) principals. */ - scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile); + scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile_str); if (!scopeobj) return JS_FALSE; @@ -295,7 +297,14 @@ out: } static JSBool -script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +script_compile(JSContext *cx, uintN argc, jsval *vp) +{ + return script_compile_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp); +} + +static JSBool +script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, + jsval *rval) { JSObject *scopeobj, *parent; JSStackFrame *fp, *caller; @@ -307,7 +316,7 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_FALSE; scopeobj = NULL; - if (argc) { + if (argc != 0) { if (!js_ValueToObject(cx, argv[0], &scopeobj)) return JS_FALSE; argv[0] = OBJECT_TO_JSVAL(scopeobj); @@ -360,7 +369,7 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } } - scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec); + scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec_str); if (!scopeobj) return JS_FALSE; @@ -388,6 +397,12 @@ out: return ok; } +static JSBool +script_exec(JSContext *cx, uintN argc, jsval *vp) +{ + return script_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp); +} + #endif /* JS_HAS_SCRIPT_OBJECT */ #if JS_HAS_XDR @@ -618,9 +633,9 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) */ static JSBool -script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +script_freeze(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; JSXDRState *xdr; JSScript *script; JSBool ok, hasMagic; @@ -628,7 +643,8 @@ script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, void *buf; JSString *str; - if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2)) return JS_FALSE; script = (JSScript *) JS_GetPrivate(cx, obj); if (!script) @@ -644,7 +660,7 @@ script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (!ok) goto out; if (!hasMagic) { - *rval = JSVAL_VOID; + *vp = JSVAL_VOID; goto out; } @@ -673,7 +689,7 @@ script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, goto out; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); out: JS_XDRDestroy(xdr); @@ -681,9 +697,9 @@ out: } static JSBool -script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +script_thaw(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; JSXDRState *xdr; JSString *str; void *buf; @@ -693,15 +709,16 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JSBool ok, hasMagic; jsint execDepth; - if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) + obj = JSVAL_TO_OBJECT(vp[1]); + if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2)) return JS_FALSE; if (argc == 0) return JS_TRUE; - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); + vp[2] = STRING_TO_JSVAL(str); /* create new XDR */ xdr = JS_XDRNewMem(cx, JSXDR_DECODE); @@ -735,7 +752,7 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (!ok) goto out; if (!hasMagic) { - *rval = JSVAL_FALSE; + *vp = JSVAL_FALSE; goto out; } @@ -768,14 +785,14 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, out: /* * We reset the buffer to be NULL so that it doesn't free the chars - * memory owned by str (argv[0]). + * memory owned by str (vp[2]). */ JS_XDRMemSetData(xdr, NULL, 0); JS_XDRDestroy(xdr); #if IS_BIG_ENDIAN JS_free(cx, buf); #endif - *rval = JSVAL_TRUE; + *vp = JSVAL_TRUE; return ok; } @@ -788,16 +805,16 @@ static const char js_thaw_str[] = "thaw"; static JSFunctionSpec script_methods[] = { #if JS_HAS_TOSOURCE - {js_toSource_str, script_toSource, 0,0,0}, + JS_FN(js_toSource_str, script_toSource, 0,0,0,0), #endif - {js_toString_str, script_toString, 0,0,0}, - {"compile", script_compile, 2,0,0}, - {"exec", script_exec, 1,0,0}, + JS_FN(js_toString_str, script_toString, 0,0,0,0), + JS_FN("compile", script_compile, 0,2,0,0), + JS_FN("exec", script_exec, 0,1,0,0), #if JS_HAS_XDR_FREEZE_THAW - {"freeze", script_freeze, 0,0,0}, - {js_thaw_str, script_thaw, 1,0,0}, + JS_FN("freeze", script_freeze, 0,0,0,0), + JS_FN(js_thaw_str, script_thaw, 0,1,0,0), #endif /* JS_HAS_XDR_FREEZE_THAW */ - {0,0,0,0,0} + JS_FS_END }; #endif /* JS_HAS_SCRIPT_OBJECT */ @@ -816,7 +833,7 @@ static JSBool script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { #if JS_HAS_SCRIPT_OBJECT - return script_exec(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval); + return script_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval); #else return JS_FALSE; #endif @@ -858,8 +875,8 @@ Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_FALSE; /* - * script_compile does not use rval to root its temporaries - * so we can use it to root obj. + * script_compile_sub does not use rval to root its temporaries so we + * can use it to root obj. */ *rval = OBJECT_TO_JSVAL(obj); } @@ -867,27 +884,29 @@ Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (!JS_SetReservedSlot(cx, obj, 0, INT_TO_JSVAL(0))) return JS_FALSE; - return script_compile(cx, obj, argc, argv, rval); + return script_compile_sub(cx, obj, argc, argv, rval); } #if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW static JSBool -script_static_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +script_static_thaw(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; + obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL); if (!obj) return JS_FALSE; - if (!script_thaw(cx, obj, argc, argv, rval)) + vp[1] = OBJECT_TO_JSVAL(obj); + if (!script_thaw(cx, vp)) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } static JSFunctionSpec script_static_methods[] = { - {js_thaw_str, script_static_thaw, 1,0,0}, - {0,0,0,0,0} + JS_FN(js_thaw_str, script_static_thaw, 1,1,0,0), + JS_FS_END }; #else /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */ @@ -1611,7 +1630,7 @@ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc) pc += js_CodeSpec[*pc].length; if (*pc == JSOP_DEFFUN) { GET_FUNCTION_FROM_BYTECODE(script, pc, 0, obj); - fun = (JSFunction *) JS_GetPrivate(cx, obj); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, obj); JS_ASSERT(FUN_INTERPRETED(fun)); return fun->u.i.script->lineno; } diff --git a/mozilla/js/src/jsstr.c b/mozilla/js/src/jsstr.c index 14729b24908..e6a7f98e910 100644 --- a/mozilla/js/src/jsstr.c +++ b/mozilla/js/src/jsstr.c @@ -244,20 +244,16 @@ js_UndependString(JSContext *cx, JSString *str) * Forward declarations for URI encode/decode and helper routines */ static JSBool -str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +str_decodeURI(JSContext *cx, uintN argc, jsval *vp); static JSBool -str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp); static JSBool -str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +str_encodeURI(JSContext *cx, uintN argc, jsval *vp); static JSBool -str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval); +str_encodeURI_Component(JSContext *cx, uintN argc, jsval *vp); static uint32 Utf8ToOneUcs4Char(const uint8 *utf8Buffer, int utf8Length); @@ -301,7 +297,7 @@ static const uint8 urlCharType[256] = #define IS_OK(C, mask) (urlCharType[((uint8) (C))] & (mask)) -/* See ECMA-262 15.1.2.4. */ +/* See ECMA-262 Edition 3 B.2.1 */ JSBool js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { @@ -402,9 +398,15 @@ js_str_escape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval } #undef IS_OK -/* See ECMA-262 15.1.2.5 */ static JSBool -str_unescape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_escape(JSContext *cx, uintN argc, jsval *vp) +{ + return js_str_escape(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp); +} + +/* See ECMA-262 Edition 3 B.2.2 */ +static JSBool +str_unescape(JSContext *cx, uintN argc, jsval *vp) { JSString *str; size_t i, ni, length; @@ -412,10 +414,10 @@ str_unescape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) jschar *newchars; jschar ch; - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); + vp[2] = STRING_TO_JSVAL(str); chars = JSSTRING_CHARS(str); length = JSSTRING_LENGTH(str); @@ -453,20 +455,20 @@ str_unescape(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JS_free(cx, newchars); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } #if JS_HAS_UNEVAL static JSBool -str_uneval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_uneval(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - str = js_ValueToSource(cx, argv[0]); + str = js_ValueToSource(cx, vp[2]); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } #endif @@ -482,17 +484,17 @@ const char js_decodeURIComponent_str[] = "decodeURIComponent"; const char js_encodeURIComponent_str[] = "encodeURIComponent"; static JSFunctionSpec string_functions[] = { - {js_escape_str, js_str_escape, 1,0,0}, - {js_unescape_str, str_unescape, 1,0,0}, + JS_FN(js_escape_str, str_escape, 1,1,0,0), + JS_FN(js_unescape_str, str_unescape, 1,1,0,0), #if JS_HAS_UNEVAL - {js_uneval_str, str_uneval, 1,0,0}, + JS_FN(js_uneval_str, str_uneval, 1,1,0,0), #endif - {js_decodeURI_str, str_decodeURI, 1,0,0}, - {js_encodeURI_str, str_encodeURI, 1,0,0}, - {js_decodeURIComponent_str, str_decodeURI_Component, 1,0,0}, - {js_encodeURIComponent_str, str_encodeURI_Component, 1,0,0}, + JS_FN(js_decodeURI_str, str_decodeURI, 1,1,0,0), + JS_FN(js_encodeURI_str, str_encodeURI, 1,1,0,0), + JS_FN(js_decodeURIComponent_str, str_decodeURI_Component, 1,1,0,0), + JS_FN(js_encodeURIComponent_str, str_encodeURI_Component, 1,1,0,0), - {0,0,0,0,0} + JS_FS_END }; jschar js_empty_ucstr[] = {0}; @@ -610,24 +612,24 @@ JSClass js_StringClass = { * toSource, toString, and valueOf. */ static JSBool -str_quote(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_quote(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); str = js_QuoteString(cx, str, '"'); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_toSource(JSContext *cx, uintN argc, jsval *vp) { jsval v; JSString *str; @@ -635,15 +637,9 @@ str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) char buf[16]; jschar *s, *t; - if (JSVAL_IS_STRING((jsval)obj)) { - v = (jsval)obj; - } else { - if (!JS_InstanceOf(cx, obj, &js_StringClass, argv)) - return JS_FALSE; - v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - if (!JSVAL_IS_STRING(v)) - return js_obj_toSource(cx, obj, argc, argv, rval); - } + if (!js_GetPrimitiveThis(cx, vp, &js_StringClass, &v)) + return JS_FALSE; + JS_ASSERT(JSVAL_IS_STRING(v)); str = js_QuoteString(cx, JSVAL_TO_STRING(v), '"'); if (!str) return JS_FALSE; @@ -666,61 +662,35 @@ str_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JS_free(cx, t); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } #endif /* JS_HAS_TOSOURCE */ static JSBool -str_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_toString(JSContext *cx, uintN argc, jsval *vp) { - jsval v; - - if (JSVAL_IS_STRING((jsval)obj)) { - *rval = (jsval)obj; - return JS_TRUE; - } - if (!JS_InstanceOf(cx, obj, &js_StringClass, argv)) - return JS_FALSE; - v = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - if (!JSVAL_IS_STRING(v)) - return js_obj_toString(cx, obj, argc, argv, rval); - *rval = v; - return JS_TRUE; -} - -static JSBool -str_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) -{ - if (JSVAL_IS_STRING((jsval)obj)) { - *rval = (jsval)obj; - return JS_TRUE; - } - if (!JS_InstanceOf(cx, obj, &js_StringClass, argv)) - return JS_FALSE; - *rval = OBJ_GET_SLOT(cx, obj, JSSLOT_PRIVATE); - return JS_TRUE; + return js_GetPrimitiveThis(cx, vp, &js_StringClass, vp); } /* * Java-like string native methods. */ static JSBool -str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_substring(JSContext *cx, uintN argc, jsval *vp) { JSString *str; jsdouble d; jsdouble length, begin, end; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); if (argc != 0) { - if (!js_ValueToNumber(cx, argv[0], &d)) + if (!js_ValueToNumber(cx, vp[2], &d)) return JS_FALSE; length = JSSTRING_LENGTH(str); begin = js_DoubleToInteger(d); @@ -732,7 +702,7 @@ str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (argc == 1) { end = length; } else { - if (!js_ValueToNumber(cx, argv[1], &d)) + if (!js_ValueToNumber(cx, vp[3], &d)) return JS_FALSE; end = js_DoubleToInteger(d); if (end < 0) @@ -752,22 +722,21 @@ str_substring(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (!str) return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_toLowerCase(JSContext *cx, uintN argc, jsval *vp) { JSString *str; size_t i, n; jschar *s, *news; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); n = JSSTRING_LENGTH(str); news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); @@ -782,13 +751,12 @@ str_toLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JS_free(cx, news); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_toLocaleLowerCase(JSContext *cx, uintN argc, jsval *vp) { JSString *str; @@ -797,27 +765,26 @@ str_toLocaleLowerCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, * ECMA has reserved that argument, presumably for defining the locale. */ if (cx->localeCallbacks && cx->localeCallbacks->localeToLowerCase) { - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); - return cx->localeCallbacks->localeToLowerCase(cx, str, rval); + vp[1] = STRING_TO_JSVAL(str); + return cx->localeCallbacks->localeToLowerCase(cx, str, vp); } - return str_toLowerCase(cx, obj, 0, argv, rval); + return str_toLowerCase(cx, 0, vp); } static JSBool -str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_toUpperCase(JSContext *cx, uintN argc, jsval *vp) { JSString *str; size_t i, n; jschar *s, *news; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); n = JSSTRING_LENGTH(str); news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); @@ -832,13 +799,12 @@ str_toUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JS_free(cx, news); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_toLocaleUpperCase(JSContext *cx, uintN argc, jsval *vp) { JSString *str; @@ -847,100 +813,128 @@ str_toLocaleUpperCase(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, * ECMA has reserved that argument, presumbaly for defining the locale. */ if (cx->localeCallbacks && cx->localeCallbacks->localeToUpperCase) { - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); - return cx->localeCallbacks->localeToUpperCase(cx, str, rval); + vp[1] = STRING_TO_JSVAL(str); + return cx->localeCallbacks->localeToUpperCase(cx, str, vp); } - return str_toUpperCase(cx, obj, 0, argv, rval); + return str_toUpperCase(cx, 0, vp); } static JSBool -str_localeCompare(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_localeCompare(JSContext *cx, uintN argc, jsval *vp) { JSString *str, *thatStr; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); if (argc == 0) { - *rval = JSVAL_ZERO; + *vp = JSVAL_ZERO; } else { - thatStr = js_ValueToString(cx, argv[0]); + thatStr = js_ValueToString(cx, vp[2]); if (!thatStr) return JS_FALSE; if (cx->localeCallbacks && cx->localeCallbacks->localeCompare) { - argv[0] = STRING_TO_JSVAL(thatStr); - return cx->localeCallbacks->localeCompare(cx, str, thatStr, rval); + vp[2] = STRING_TO_JSVAL(thatStr); + return cx->localeCallbacks->localeCompare(cx, str, thatStr, vp); } - *rval = INT_TO_JSVAL(js_CompareStrings(str, thatStr)); + *vp = INT_TO_JSVAL(js_CompareStrings(str, thatStr)); } return JS_TRUE; } static JSBool -str_charAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_charAt(JSContext *cx, uintN argc, jsval *vp) { + jsval t, v; JSString *str; + jsint i; + jschar c; jsdouble d; - size_t index; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) - return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); - - if (argc == 0) { - d = 0.0; + t = vp[1]; + v = vp[2]; + if (JSVAL_IS_STRING(t) && JSVAL_IS_INT(v)) { + str = JSVAL_TO_STRING(t); + i = JSVAL_TO_INT(v); + if ((size_t)i >= JSSTRING_LENGTH(str)) + goto out_of_range; } else { - if (!js_ValueToNumber(cx, argv[0], &d)) - return JS_FALSE; - d = js_DoubleToInteger(d); - } - - if (d < 0 || JSSTRING_LENGTH(str) <= d) { - *rval = JS_GetEmptyStringValue(cx); - } else { - index = (size_t)d; - str = js_NewDependentString(cx, str, index, 1, 0); + str = js_ValueToString(cx, t); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); + + if (argc == 0) { + d = 0.0; + } else { + if (!js_ValueToNumber(cx, v, &d)) + return JS_FALSE; + d = js_DoubleToInteger(d); + } + + if (d < 0 || JSSTRING_LENGTH(str) <= d) + goto out_of_range; + i = (jsint) d; } + + c = JSSTRING_CHARS(str)[i]; + str = (c < UNIT_STRING_LIMIT) + ? js_GetUnitString(cx, c) + : js_NewDependentString(cx, str, i, 1, 0); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; + +out_of_range: + *vp = JS_GetEmptyStringValue(cx); return JS_TRUE; } static JSBool -str_charCodeAt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_charCodeAt(JSContext *cx, uintN argc, jsval *vp) { + jsval t, v; JSString *str; + jsint i; jsdouble d; - size_t index; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) - return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); - - if (argc == 0) { - d = 0.0; + t = vp[1]; + v = vp[2]; + if (JSVAL_IS_STRING(t) && JSVAL_IS_INT(v)) { + str = JSVAL_TO_STRING(t); + i = JSVAL_TO_INT(v); + if ((size_t)i >= JSSTRING_LENGTH(str)) + goto out_of_range; } else { - if (!js_ValueToNumber(cx, argv[0], &d)) + str = js_ValueToString(cx, t); + if (!str) return JS_FALSE; - d = js_DoubleToInteger(d); + vp[1] = STRING_TO_JSVAL(str); + + if (argc == 0) { + d = 0.0; + } else { + if (!js_ValueToNumber(cx, v, &d)) + return JS_FALSE; + d = js_DoubleToInteger(d); + } + + if (d < 0 || JSSTRING_LENGTH(str) <= d) + goto out_of_range; + i = (jsint) d; } - if (d < 0 || JSSTRING_LENGTH(str) <= d) { - *rval = JS_GetNaNValue(cx); - } else { - index = (size_t)d; - *rval = INT_TO_JSVAL((jsint) JSSTRING_CHARS(str)[index]); - } + *vp = INT_TO_JSVAL(JSSTRING_CHARS(str)[i]); + return JS_TRUE; + +out_of_range: + *vp = JS_GetNaNValue(cx); return JS_TRUE; } @@ -977,29 +971,38 @@ js_BoyerMooreHorspool(const jschar *text, jsint textlen, } static JSBool -str_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_indexOf(JSContext *cx, uintN argc, jsval *vp) { + jsval t, v; JSString *str, *str2; - jsint i, j, index, textlen, patlen; const jschar *text, *pat; + jsint i, j, index, textlen, patlen; jsdouble d; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) - return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + t = vp[1]; + v = vp[2]; + if (JSVAL_IS_STRING(t) && JSVAL_IS_STRING(v)) { + str = JSVAL_TO_STRING(t); + str2 = JSVAL_TO_STRING(v); + } else { + str = js_ValueToString(cx, t); + if (!str) + return JS_FALSE; + vp[1] = STRING_TO_JSVAL(str); + + str2 = js_ValueToString(cx, v); + if (!str2) + return JS_FALSE; + vp[2] = STRING_TO_JSVAL(str2); + } + text = JSSTRING_CHARS(str); textlen = (jsint) JSSTRING_LENGTH(str); - - str2 = js_ValueToString(cx, argv[0]); - if (!str2) - return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str2); pat = JSSTRING_CHARS(str2); patlen = (jsint) JSSTRING_LENGTH(str2); if (argc > 1) { - if (!js_ValueToNumber(cx, argv[1], &d)) + if (!js_ValueToNumber(cx, vp[3], &d)) return JS_FALSE; d = js_DoubleToInteger(d); if (d < 0) @@ -1012,7 +1015,7 @@ str_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) i = 0; } if (patlen == 0) { - *rval = INT_TO_JSVAL(i); + *vp = INT_TO_JSVAL(i); return JS_TRUE; } @@ -1038,35 +1041,34 @@ str_indexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } out: - *rval = INT_TO_JSVAL(index); + *vp = INT_TO_JSVAL(index); return JS_TRUE; } static JSBool -str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_lastIndexOf(JSContext *cx, uintN argc, jsval *vp) { JSString *str, *str2; const jschar *text, *pat; jsint i, j, textlen, patlen; jsdouble d; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); text = JSSTRING_CHARS(str); textlen = (jsint) JSSTRING_LENGTH(str); - str2 = js_ValueToString(cx, argv[0]); + str2 = js_ValueToString(cx, vp[2]); if (!str2) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str2); + vp[2] = STRING_TO_JSVAL(str2); pat = JSSTRING_CHARS(str2); patlen = (jsint) JSSTRING_LENGTH(str2); if (argc > 1) { - if (!js_ValueToNumber(cx, argv[1], &d)) + if (!js_ValueToNumber(cx, vp[3], &d)) return JS_FALSE; if (JSDOUBLE_IS_NaN(d)) { i = textlen; @@ -1084,7 +1086,7 @@ str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } if (patlen == 0) { - *rval = INT_TO_JSVAL(i); + *vp = INT_TO_JSVAL(i); return JS_TRUE; } @@ -1099,7 +1101,7 @@ str_lastIndexOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, j = 0; } } - *rval = INT_TO_JSVAL(i); + *vp = INT_TO_JSVAL(i); return JS_TRUE; } @@ -1128,10 +1130,10 @@ typedef struct GlobData { #define GLOBAL_REGEXP 0x10 /* out: regexp had the 'g' flag */ static JSBool -match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, +match_or_replace(JSContext *cx, JSBool (*glob)(JSContext *cx, jsint count, GlobData *data), void (*destroy)(JSContext *cx, GlobData *data), - GlobData *data, jsval *rval) + GlobData *data, uintN argc, jsval *vp) { JSString *str, *src, *opt; JSObject *reobj; @@ -1140,22 +1142,22 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JSBool ok, test; jsint count; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); data->str = str; - if (JSVAL_IS_REGEXP(cx, argv[0])) { - reobj = JSVAL_TO_OBJECT(argv[0]); + if (JSVAL_IS_REGEXP(cx, vp[2])) { + reobj = JSVAL_TO_OBJECT(vp[2]); re = (JSRegExp *) JS_GetPrivate(cx, reobj); } else { - src = js_ValueToString(cx, argv[0]); + src = js_ValueToString(cx, vp[2]); if (!src) return JS_FALSE; if (data->optarg < argc) { - argv[0] = STRING_TO_JSVAL(src); - opt = js_ValueToString(cx, argv[data->optarg]); + vp[2] = STRING_TO_JSVAL(src); + opt = js_ValueToString(cx, vp[2 + data->optarg]); if (!opt) return JS_FALSE; } else { @@ -1175,11 +1177,11 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, data->flags |= GLOBAL_REGEXP; index = 0; if (GET_MODE(data->flags) == MODE_SEARCH) { - ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval); + ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp); if (ok) { - *rval = (*rval == JSVAL_TRUE) - ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length) - : INT_TO_JSVAL(-1); + *vp = (*vp == JSVAL_TRUE) + ? INT_TO_JSVAL(cx->regExpStatics.leftContext.length) + : INT_TO_JSVAL(-1); } } else if (data->flags & GLOBAL_REGEXP) { if (reobj) { @@ -1191,8 +1193,8 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (ok) { length = JSSTRING_LENGTH(str); for (count = 0; index <= length; count++) { - ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, rval); - if (!ok || *rval != JSVAL_TRUE) + ok = js_ExecuteRegExp(cx, re, str, &index, JS_TRUE, vp); + if (!ok || *vp != JSVAL_TRUE) break; ok = glob(cx, count, data); if (!ok) @@ -1214,7 +1216,7 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, * MODE_MATCH implies str_match is being called from a script or a * scripted function. If the caller cares only about testing null * vs. non-null return value, optimize away the array object that - * would normally be returned in *rval. + * would normally be returned in *vp. */ JSStackFrame *fp = cx->fp->down; @@ -1241,7 +1243,7 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } } } - ok = js_ExecuteRegExp(cx, re, str, &index, test, rval); + ok = js_ExecuteRegExp(cx, re, str, &index, test, vp); } DROP_REGEXP(cx, re); @@ -1288,30 +1290,29 @@ match_glob(JSContext *cx, jsint count, GlobData *data) } static JSBool -str_match(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_match(JSContext *cx, uintN argc, jsval *vp) { MatchData mdata; JSBool ok; mdata.base.flags = MODE_MATCH; mdata.base.optarg = 1; - mdata.arrayval = &argv[2]; + mdata.arrayval = &vp[4]; *mdata.arrayval = JSVAL_NULL; - ok = match_or_replace(cx, obj, argc, argv, match_glob, NULL, &mdata.base, - rval); + ok = match_or_replace(cx, match_glob, NULL, &mdata.base, argc, vp); if (ok && !JSVAL_IS_NULL(*mdata.arrayval)) - *rval = *mdata.arrayval; + *vp = *mdata.arrayval; return ok; } static JSBool -str_search(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_search(JSContext *cx, uintN argc, jsval *vp) { GlobData data; data.flags = MODE_SEARCH; data.optarg = 1; - return match_or_replace(cx, obj, argc, argv, NULL, NULL, &data, rval); + return match_or_replace(cx, NULL, NULL, &data, argc, vp); } typedef struct ReplaceData { @@ -1406,7 +1407,7 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep) * Save the regExpStatics from the current regexp, since they may be * clobbered by a RegExp usage in the lambda function. Note that all * members of JSRegExpStatics are JSSubStrings, so not GC roots, save - * input, which is rooted otherwise via argv[-1] in str_replace. + * input, which is rooted otherwise via vp[1] in str_replace. */ JSRegExpStatics save = cx->regExpStatics; JSBool freeMoreParens = JS_FALSE; @@ -1594,7 +1595,7 @@ replace_glob(JSContext *cx, jsint count, GlobData *data) } static JSBool -str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_replace(JSContext *cx, uintN argc, jsval *vp) { JSObject *lambda; JSString *repstr, *str; @@ -1603,13 +1604,13 @@ str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) jschar *chars; size_t leftlen, rightlen, length; - if (JS_TypeOfValue(cx, argv[1]) == JSTYPE_FUNCTION) { - lambda = JSVAL_TO_OBJECT(argv[1]); + if (JS_TypeOfValue(cx, vp[3]) == JSTYPE_FUNCTION) { + lambda = JSVAL_TO_OBJECT(vp[3]); repstr = NULL; } else { - if (!JS_ConvertValue(cx, argv[1], JSTYPE_STRING, &argv[1])) + if (!JS_ConvertValue(cx, vp[3], JSTYPE_STRING, &vp[3])) return JS_FALSE; - repstr = JSVAL_TO_STRING(argv[1]); + repstr = JSVAL_TO_STRING(vp[3]); lambda = NULL; } @@ -1635,15 +1636,15 @@ str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) rdata.index = 0; rdata.leftIndex = 0; - ok = match_or_replace(cx, obj, argc, argv, replace_glob, replace_destroy, - &rdata.base, rval); + ok = match_or_replace(cx, replace_glob, replace_destroy, &rdata.base, + argc, vp); if (!ok) return JS_FALSE; if (!rdata.chars) { - if ((rdata.base.flags & GLOBAL_REGEXP) || *rval != JSVAL_TRUE) { + if ((rdata.base.flags & GLOBAL_REGEXP) || *vp != JSVAL_TRUE) { /* Didn't match even once. */ - *rval = STRING_TO_JSVAL(rdata.base.str); + *vp = STRING_TO_JSVAL(rdata.base.str); goto out; } leftlen = cx->regExpStatics.leftContext.length; @@ -1681,7 +1682,7 @@ str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) ok = JS_FALSE; goto out; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); out: /* If KEEP_REGEXP is still set, it's our job to destroy regexp now. */ @@ -1803,7 +1804,7 @@ find_split(JSContext *cx, JSString *str, JSRegExp *re, jsint *ip, } static JSBool -str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_split(JSContext *cx, uintN argc, jsval *vp) { JSString *str, *sub; JSObject *arrayobj; @@ -1815,32 +1816,32 @@ str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) jsint i, j; uint32 len, limit; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); arrayobj = js_ConstructObject(cx, &js_ArrayClass, NULL, NULL, 0, NULL); if (!arrayobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(arrayobj); + *vp = OBJECT_TO_JSVAL(arrayobj); if (argc == 0) { v = STRING_TO_JSVAL(str); ok = JS_SetElement(cx, arrayobj, 0, &v); } else { - if (JSVAL_IS_REGEXP(cx, argv[0])) { - re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[0])); + if (JSVAL_IS_REGEXP(cx, vp[2])) { + re = (JSRegExp *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(vp[2])); sep = &tmp; /* Set a magic value so we can detect a successful re match. */ sep->chars = NULL; sep->length = 0; } else { - JSString *str2 = js_ValueToString(cx, argv[0]); + JSString *str2 = js_ValueToString(cx, vp[2]); if (!str2) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str2); + vp[2] = STRING_TO_JSVAL(str2); /* * Point sep at a local copy of str2's header because find_split @@ -1853,10 +1854,10 @@ str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } /* Use the second argument as the split limit, if given. */ - limited = (argc > 1) && !JSVAL_IS_VOID(argv[1]); + limited = (argc > 1) && !JSVAL_IS_VOID(vp[3]); limit = 0; /* Avoid warning. */ if (limited) { - if (!js_ValueToNumber(cx, argv[1], &d)) + if (!js_ValueToNumber(cx, vp[3], &d)) return JS_FALSE; /* Clamp limit between 0 and 1 + string length. */ @@ -1911,19 +1912,19 @@ str_split(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #if JS_HAS_PERL_SUBSTR static JSBool -str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_substr(JSContext *cx, uintN argc, jsval *vp) { JSString *str; jsdouble d; jsdouble length, begin, end; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); if (argc != 0) { - if (!js_ValueToNumber(cx, argv[0], &d)) + if (!js_ValueToNumber(cx, vp[2], &d)) return JS_FALSE; length = JSSTRING_LENGTH(str); begin = js_DoubleToInteger(d); @@ -1938,7 +1939,7 @@ str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (argc == 1) { end = length; } else { - if (!js_ValueToNumber(cx, argv[1], &d)) + if (!js_ValueToNumber(cx, vp[3], &d)) return JS_FALSE; end = js_DoubleToInteger(d); if (end < 0) @@ -1948,12 +1949,14 @@ str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) end = length; } - str = js_NewDependentString(cx, str, (size_t)begin, - (size_t)(end - begin), 0); + str = js_NewDependentString(cx, str, + (size_t)begin, + (size_t)(end - begin), + 0); if (!str) return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } #endif /* JS_HAS_PERL_SUBSTR */ @@ -1962,17 +1965,18 @@ str_substr(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Python-esque sequence operations. */ static JSBool -str_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_concat(JSContext *cx, uintN argc, jsval *vp) { JSString *str, *str2; + jsval *argv; uintN i; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, vp[1]); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); - for (i = 0; i < argc; i++) { + for (i = 0, argv = vp + 2; i < argc; i++) { str2 = js_ValueToString(cx, argv[i]); if (!str2) return JS_FALSE; @@ -1983,27 +1987,54 @@ str_concat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_slice(JSContext *cx, uintN argc, jsval *vp) { + jsval t, v; JSString *str; - jsdouble d; - jsdouble length, begin, end; + jschar c; - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + t = vp[1]; + v = vp[2]; + if (argc == 1 && JSVAL_IS_STRING(t) && JSVAL_IS_INT(v)) { + size_t begin, end, length; + + str = JSVAL_TO_STRING(t); + begin = JSVAL_TO_INT(v); + end = JSSTRING_LENGTH(str); + if (begin <= end) { + length = end - begin; + if (length == 0) { + str = cx->runtime->emptyString; + } else { + str = (length == 1 && + (c = JSSTRING_CHARS(str)[begin]) < UNIT_STRING_LIMIT) + ? js_GetUnitString(cx, c) + : js_NewDependentString(cx, str, begin, length, 0); + if (!str) + return JS_FALSE; + } + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; + } + } + + str = js_ValueToString(cx, t); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); if (argc != 0) { - if (!js_ValueToNumber(cx, argv[0], &d)) + double begin, end, length; + + if (!js_ValueToNumber(cx, v, &begin)) return JS_FALSE; + begin = js_DoubleToInteger(begin); length = JSSTRING_LENGTH(str); - begin = js_DoubleToInteger(d); if (begin < 0) { begin += length; if (begin < 0) @@ -2015,9 +2046,9 @@ str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (argc == 1) { end = length; } else { - if (!js_ValueToNumber(cx, argv[1], &d)) + if (!js_ValueToNumber(cx, vp[3], &end)) return JS_FALSE; - end = js_DoubleToInteger(d); + end = js_DoubleToInteger(end); if (end < 0) { end += length; if (end < 0) @@ -2029,12 +2060,14 @@ str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) end = begin; } - str = js_NewDependentString(cx, str, (size_t)begin, - (size_t)(end - begin), 0); + str = js_NewDependentString(cx, str, + (size_t)begin, + (size_t)(end - begin), + 0); if (!str) return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } @@ -2043,22 +2076,24 @@ str_slice(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * HTML composition aids. */ static JSBool -tagify(JSContext *cx, JSObject *obj, jsval *argv, - const char *begin, JSString *param, const char *end, - jsval *rval) +tagify(JSContext *cx, const char *begin, JSString *param, const char *end, + jsval *vp) { + jsval v; JSString *str; jschar *tagbuf; size_t beglen, endlen, parlen, taglen; size_t i, j; - if (JSVAL_IS_STRING((jsval)obj)) { - str = JSVAL_TO_STRING((jsval)obj); + v = vp[1]; + if (!JSVAL_IS_OBJECT(v)) { + JS_ASSERT(JSVAL_IS_STRING(v)); + str = JSVAL_TO_STRING(v); } else { - str = js_ValueToString(cx, OBJECT_TO_JSVAL(obj)); + str = js_ValueToString(cx, v); if (!str) return JS_FALSE; - argv[-1] = STRING_TO_JSVAL(str); + vp[1] = STRING_TO_JSVAL(str); } if (!end) @@ -2110,173 +2145,156 @@ tagify(JSContext *cx, JSObject *obj, jsval *argv, free((char *)tagbuf); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSBool -tagify_value(JSContext *cx, JSObject *obj, jsval *argv, - const char *begin, const char *end, - jsval *rval) +tagify_value(JSContext *cx, const char *begin, const char *end, jsval *vp) { JSString *param; - param = js_ValueToString(cx, argv[0]); + param = js_ValueToString(cx, vp[2]); if (!param) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(param); - return tagify(cx, obj, argv, begin, param, end, rval); + vp[2] = STRING_TO_JSVAL(param); + return tagify(cx, begin, param, end, vp); } static JSBool -str_bold(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_bold(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "b", NULL, NULL, rval); + return tagify(cx, "b", NULL, NULL, vp); } static JSBool -str_italics(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_italics(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "i", NULL, NULL, rval); + return tagify(cx, "i", NULL, NULL, vp); } static JSBool -str_fixed(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_fixed(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "tt", NULL, NULL, rval); + return tagify(cx, "tt", NULL, NULL, vp); } static JSBool -str_fontsize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_fontsize(JSContext *cx, uintN argc, jsval *vp) { - return tagify_value(cx, obj, argv, "font size", "font", rval); + return tagify_value(cx, "font size", "font", vp); } static JSBool -str_fontcolor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_fontcolor(JSContext *cx, uintN argc, jsval *vp) { - return tagify_value(cx, obj, argv, "font color", "font", rval); + return tagify_value(cx, "font color", "font", vp); } static JSBool -str_link(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_link(JSContext *cx, uintN argc, jsval *vp) { - return tagify_value(cx, obj, argv, "a href", "a", rval); + return tagify_value(cx, "a href", "a", vp); } static JSBool -str_anchor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_anchor(JSContext *cx, uintN argc, jsval *vp) { - return tagify_value(cx, obj, argv, "a name", "a", rval); + return tagify_value(cx, "a name", "a", vp); } static JSBool -str_strike(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_strike(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "strike", NULL, NULL, rval); + return tagify(cx, "strike", NULL, NULL, vp); } static JSBool -str_small(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_small(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "small", NULL, NULL, rval); + return tagify(cx, "small", NULL, NULL, vp); } static JSBool -str_big(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_big(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "big", NULL, NULL, rval); + return tagify(cx, "big", NULL, NULL, vp); } static JSBool -str_blink(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_blink(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "blink", NULL, NULL, rval); + return tagify(cx, "blink", NULL, NULL, vp); } static JSBool -str_sup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_sup(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "sup", NULL, NULL, rval); + return tagify(cx, "sup", NULL, NULL, vp); } static JSBool -str_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +str_sub(JSContext *cx, uintN argc, jsval *vp) { - return tagify(cx, obj, argv, "sub", NULL, NULL, rval); + return tagify(cx, "sub", NULL, NULL, vp); } #endif /* JS_HAS_STR_HTML_HELPERS */ +#define GENERIC JSFUN_GENERIC_NATIVE +#define PRIMITIVE JSFUN_THISP_PRIMITIVE +#define GENERIC_PRIMITIVE (GENERIC | PRIMITIVE) + static JSFunctionSpec string_methods[] = { #if JS_HAS_TOSOURCE - {"quote", str_quote, 0,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {js_toSource_str, str_toSource, 0,JSFUN_THISP_STRING,0}, + JS_FN("quote", str_quote, 0,0,GENERIC_PRIMITIVE,0), + JS_FN(js_toSource_str, str_toSource, 0,0,JSFUN_THISP_STRING,0), #endif /* Java-like methods. */ - {js_toString_str, str_toString, 0,JSFUN_THISP_STRING,0}, - {js_valueOf_str, str_valueOf, 0,JSFUN_THISP_STRING,0}, - {"substring", str_substring, 2,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"toLowerCase", str_toLowerCase, 0,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"toUpperCase", str_toUpperCase, 0,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"charAt", str_charAt, 1,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"charCodeAt", str_charCodeAt, 1,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"indexOf", str_indexOf, 1,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"lastIndexOf", str_lastIndexOf, 1,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"toLocaleLowerCase", str_toLocaleLowerCase, 0,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"toLocaleUpperCase", str_toLocaleUpperCase, 0,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"localeCompare", str_localeCompare, 1,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, + JS_FN(js_toString_str, str_toString, 0,0,JSFUN_THISP_STRING,0), + JS_FN(js_valueOf_str, str_toString, 0,0,JSFUN_THISP_STRING,0), + JS_FN("substring", str_substring, 0,2,GENERIC_PRIMITIVE,0), + JS_FN("toLowerCase", str_toLowerCase, 0,0,GENERIC_PRIMITIVE,0), + JS_FN("toUpperCase", str_toUpperCase, 0,0,GENERIC_PRIMITIVE,0), + JS_FN("charAt", str_charAt, 1,1,GENERIC_PRIMITIVE,0), + JS_FN("charCodeAt", str_charCodeAt, 1,1,GENERIC_PRIMITIVE,0), + JS_FN("indexOf", str_indexOf, 1,1,GENERIC_PRIMITIVE,0), + JS_FN("lastIndexOf", str_lastIndexOf, 1,1,GENERIC_PRIMITIVE,0), + JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,0,GENERIC_PRIMITIVE,0), + JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,0,GENERIC_PRIMITIVE,0), + JS_FN("localeCompare", str_localeCompare, 1,1,GENERIC_PRIMITIVE,0), /* Perl-ish methods (search is actually Python-esque). */ - {"match", str_match, 1,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,2}, - {"search", str_search, 1,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"replace", str_replace, 2,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"split", str_split, 2,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, + JS_FN("match", str_match, 1,1,GENERIC_PRIMITIVE,2), + JS_FN("search", str_search, 1,1,GENERIC_PRIMITIVE,0), + JS_FN("replace", str_replace, 2,2,GENERIC_PRIMITIVE,0), + JS_FN("split", str_split, 0,2,GENERIC_PRIMITIVE,0), #if JS_HAS_PERL_SUBSTR - {"substr", str_substr, 2,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, + JS_FN("substr", str_substr, 0,2,GENERIC_PRIMITIVE,0), #endif /* Python-esque sequence methods. */ - {"concat", str_concat, 0,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, - {"slice", str_slice, 0,JSFUN_GENERIC_NATIVE| - JSFUN_THISP_PRIMITIVE,0}, + JS_FN("concat", str_concat, 0,1,GENERIC_PRIMITIVE,0), + JS_FN("slice", str_slice, 1,2,GENERIC_PRIMITIVE,0), /* HTML string methods. */ #if JS_HAS_STR_HTML_HELPERS - {"bold", str_bold, 0,JSFUN_THISP_PRIMITIVE,0}, - {"italics", str_italics, 0,JSFUN_THISP_PRIMITIVE,0}, - {"fixed", str_fixed, 0,JSFUN_THISP_PRIMITIVE,0}, - {"fontsize", str_fontsize, 1,JSFUN_THISP_PRIMITIVE,0}, - {"fontcolor", str_fontcolor, 1,JSFUN_THISP_PRIMITIVE,0}, - {"link", str_link, 1,JSFUN_THISP_PRIMITIVE,0}, - {"anchor", str_anchor, 1,JSFUN_THISP_PRIMITIVE,0}, - {"strike", str_strike, 0,JSFUN_THISP_PRIMITIVE,0}, - {"small", str_small, 0,JSFUN_THISP_PRIMITIVE,0}, - {"big", str_big, 0,JSFUN_THISP_PRIMITIVE,0}, - {"blink", str_blink, 0,JSFUN_THISP_PRIMITIVE,0}, - {"sup", str_sup, 0,JSFUN_THISP_PRIMITIVE,0}, - {"sub", str_sub, 0,JSFUN_THISP_PRIMITIVE,0}, + JS_FN("bold", str_bold, 0,0,PRIMITIVE,0), + JS_FN("italics", str_italics, 0,0,PRIMITIVE,0), + JS_FN("fixed", str_fixed, 0,0,PRIMITIVE,0), + JS_FN("fontsize", str_fontsize, 1,1,PRIMITIVE,0), + JS_FN("fontcolor", str_fontcolor, 1,1,PRIMITIVE,0), + JS_FN("link", str_link, 1,1,PRIMITIVE,0), + JS_FN("anchor", str_anchor, 1,1,PRIMITIVE,0), + JS_FN("strike", str_strike, 0,0,PRIMITIVE,0), + JS_FN("small", str_small, 0,0,PRIMITIVE,0), + JS_FN("big", str_big, 0,0,PRIMITIVE,0), + JS_FN("blink", str_blink, 0,0,PRIMITIVE,0), + JS_FN("sup", str_sup, 0,0,PRIMITIVE,0), + JS_FN("sub", str_sub, 0,0,PRIMITIVE,0), #endif - {0,0,0,0,0} + JS_FS_END }; static JSBool @@ -2301,14 +2319,15 @@ String(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -str_fromCharCode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_fromCharCode(JSContext *cx, uintN argc, jsval *vp) { + jsval *argv; jschar *chars; uintN i; uint16 code; JSString *str; + argv = vp + 2; JS_ASSERT(argc < ARRAY_INIT_LIMIT); chars = (jschar *) JS_malloc(cx, (argc + 1) * sizeof(jschar)); if (!chars) @@ -2326,13 +2345,13 @@ str_fromCharCode(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JS_free(cx, chars); return JS_FALSE; } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSFunctionSpec string_static_methods[] = { - {"fromCharCode", str_fromCharCode, 1,0,0}, - {0,0,0,0,0} + JS_FN("fromCharCode", str_fromCharCode, 0,1,0,0), + JS_FS_END }; JSBool @@ -2379,6 +2398,66 @@ js_InitRuntimeStringState(JSContext *cx) } +#define UNIT_STRING_SPACE(sp) ((jschar *) ((sp) + UNIT_STRING_LIMIT)) +#define UNIT_STRING_SPACE_RT(rt) UNIT_STRING_SPACE((rt)->unitStrings) + +#define IN_UNIT_STRING_SPACE(sp,cp) \ + ((cp) - UNIT_STRING_SPACE(sp) < 2 * UNIT_STRING_LIMIT) +#define IN_UNIT_STRING_SPACE_RT(rt,cp) \ + IN_UNIT_STRING_SPACE((rt)->unitStrings, cp) + +JSString * +js_GetUnitString(JSContext *cx, jschar c) +{ +#if 1 + JSRuntime *rt; + JSString **sp, *str; + jschar *cp, i; + + JS_ASSERT(c < UNIT_STRING_LIMIT); + rt = cx->runtime; + if (!rt->unitStrings) { + sp = (JSString **) calloc(UNIT_STRING_LIMIT * sizeof(JSString *) + + UNIT_STRING_LIMIT * 2 * sizeof(jschar), + 1); + if (!sp) { + JS_ReportOutOfMemory(cx); + return NULL; + } + cp = UNIT_STRING_SPACE(sp); + for (i = 0; i < UNIT_STRING_LIMIT; i++) { + *cp = i; + cp += 2; + } + JS_LOCK_GC(rt); + if (!rt->unitStrings) { + rt->unitStrings = sp; + JS_UNLOCK_GC(rt); + } else { + JS_UNLOCK_GC(rt); + free(sp); + } + } + if (!rt->unitStrings[c]) { + cp = UNIT_STRING_SPACE_RT(rt); + str = js_NewString(cx, cp + 2 * c, 1, GCF_LOCK); + if (!str) + return NULL; + JS_LOCK_GC(rt); + if (!rt->unitStrings[c]) { + rt->unitStrings[c] = str; + JS_UNLOCK_GC(rt); + } else { + JS_UNLOCK_GC(rt); + js_UnlockGCThingRT(rt, str); + } + } + return rt->unitStrings[c]; +#else + return js_NewStringCopyN(cx, &c, 1, 0); +#endif +} + void js_FinishRuntimeStringState(JSContext *cx) { @@ -2386,6 +2465,15 @@ js_FinishRuntimeStringState(JSContext *cx) js_UnlockGCThingRT(rt, rt->emptyString); rt->emptyString = NULL; + + if (rt->unitStrings) { + jschar c; + + for (c = 0; c < UNIT_STRING_LIMIT; c++) { + if (rt->unitStrings[c]) + js_UnlockGCThingRT(rt, rt->unitStrings[c]); + } + } } void @@ -2542,7 +2630,7 @@ js_NewStringCopyN(JSContext *cx, const jschar *s, size_t n, uintN gcflag) jschar *news; JSString *str; - news = (jschar *)JS_malloc(cx, (n + 1) * sizeof(jschar)); + news = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar)); if (!news) return NULL; js_strncpy(news, s, n); @@ -2621,7 +2709,7 @@ js_FinalizeStringRT(JSRuntime *rt, JSString *str) } else { /* A stillborn string has null chars, so is not valid. */ valid = (str->chars != NULL); - if (valid) + if (valid && !IN_UNIT_STRING_SPACE_RT(rt, str->chars)) free(str->chars); } if (valid) { @@ -4752,56 +4840,52 @@ bad: } static JSBool -str_decodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_decodeURI(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); - return Decode(cx, str, js_uriReservedPlusPound_ucstr, rval); + vp[2] = STRING_TO_JSVAL(str); + return Decode(cx, str, js_uriReservedPlusPound_ucstr, vp); } static JSBool -str_decodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_decodeURI_Component(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); - return Decode(cx, str, js_empty_ucstr, rval); + vp[2] = STRING_TO_JSVAL(str); + return Decode(cx, str, js_empty_ucstr, vp); } static JSBool -str_encodeURI(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_encodeURI(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); + vp[2] = STRING_TO_JSVAL(str); return Encode(cx, str, js_uriReservedPlusPound_ucstr, js_uriUnescaped_ucstr, - rval); + vp); } static JSBool -str_encodeURI_Component(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +str_encodeURI_Component(JSContext *cx, uintN argc, jsval *vp) { JSString *str; - str = js_ValueToString(cx, argv[0]); + str = js_ValueToString(cx, vp[2]); if (!str) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(str); - return Encode(cx, str, js_uriUnescaped_ucstr, NULL, rval); + vp[2] = STRING_TO_JSVAL(str); + return Encode(cx, str, js_uriUnescaped_ucstr, NULL, vp); } /* diff --git a/mozilla/js/src/jsstr.h b/mozilla/js/src/jsstr.h index 7b22135ee6e..72883b5c246 100644 --- a/mozilla/js/src/jsstr.h +++ b/mozilla/js/src/jsstr.h @@ -297,6 +297,22 @@ typedef enum JSCharType { extern JSBool js_InitRuntimeStringState(JSContext *cx); +/* + * Maximum character code for which we will create a pinned unit string on + * demand -- see JSRuntime.unitStrings in jscntxt.h. + */ +#define UNIT_STRING_LIMIT 256 + +/* + * Get the independent string containing only character code c (backstopped + * with a NUL as usual for independent strings). + * + * This function must be called only for c < UNIT_STRING_LIMIT. It asserts to + * insist on this requirement in DEBUG builds. + */ +extern JSString * +js_GetUnitString(JSContext *cx, jschar c); + extern void js_FinishRuntimeStringState(JSContext *cx); diff --git a/mozilla/js/src/jsxml.c b/mozilla/js/src/jsxml.c index cb6a2694792..f448eec6ebb 100644 --- a/mozilla/js/src/jsxml.c +++ b/mozilla/js/src/jsxml.c @@ -256,23 +256,25 @@ static JSPropertySpec namespace_props[] = { }; static JSBool -namespace_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +namespace_toString(JSContext *cx, uintN argc, jsval *vp) { JSXMLNamespace *ns; ns = (JSXMLNamespace *) - JS_GetInstancePrivate(cx, obj, &js_NamespaceClass.base, argv); + JS_GetInstancePrivate(cx, + JS_THIS_OBJECT(cx, vp), + &js_NamespaceClass.base, + vp + 2); if (!ns) return JS_FALSE; - *rval = STRING_TO_JSVAL(ns->uri); + *vp = STRING_TO_JSVAL(ns->uri); return JS_TRUE; } static JSFunctionSpec namespace_methods[] = { - {js_toString_str, namespace_toString, 0,0,0}, - {0,0,0,0,0} + JS_FN(js_toString_str, namespace_toString, 0,0,0,0), + JS_FS_END }; JSXMLNamespace * @@ -488,21 +490,22 @@ static JSPropertySpec qname_props[] = { }; static JSBool -qname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +qname_toString(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj; JSClass *clasp; JSXMLQName *qn; JSString *str, *qualstr; size_t length; jschar *chars; + obj = JS_THIS_OBJECT(cx, vp); clasp = OBJ_GET_CLASS(cx, obj); if (clasp == &js_AttributeNameClass || clasp == &js_AnyNameClass) { qn = (JSXMLQName *) JS_GetPrivate(cx, obj); } else { qn = (JSXMLQName *) - JS_GetInstancePrivate(cx, obj, &js_QNameClass.base, argv); + JS_GetInstancePrivate(cx, obj, &js_QNameClass.base, vp + 2); if (!qn) return JS_FALSE; } @@ -538,13 +541,13 @@ qname_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } } - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } static JSFunctionSpec qname_methods[] = { - {js_toString_str, qname_toString, 0,0,0}, - {0,0,0,0,0} + JS_FN(js_toString_str, qname_toString, 0,0,0,0), + JS_FS_END }; JSXMLQName * @@ -5585,14 +5588,15 @@ CallConstructorFunction(JSContext *cx, JSObject *obj, JSClass *clasp, } static JSXML * -StartNonListXMLMethod(JSContext *cx, JSObject **objp, jsval *argv) +StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp) { JSXML *xml; JSFunction *fun; - JS_ASSERT(VALUE_IS_FUNCTION(cx, argv[-2])); + JS_ASSERT(VALUE_IS_FUNCTION(cx, *vp)); - xml = (JSXML *) JS_GetInstancePrivate(cx, *objp, &js_XMLClass, argv); + *objp = JS_THIS_OBJECT(cx, vp); + xml = (JSXML *) JS_GetInstancePrivate(cx, *objp, &js_XMLClass, vp + 2); if (!xml || xml->xml_class != JSXML_CLASS_LIST) return xml; @@ -5602,12 +5606,12 @@ StartNonListXMLMethod(JSContext *cx, JSObject **objp, jsval *argv) *objp = js_GetXMLObject(cx, xml); if (!*objp) return NULL; - argv[-1] = OBJECT_TO_JSVAL(*objp); + vp[1] = OBJECT_TO_JSVAL(*objp); return xml; } } - fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(argv[-2])); + fun = (JSFunction *) OBJ_GET_PRIVATE(cx, JSVAL_TO_OBJECT(*vp)); if (fun) { char numBuf[12]; JS_snprintf(numBuf, sizeof numBuf, "%u", xml->xml_kids.length); @@ -5618,26 +5622,23 @@ StartNonListXMLMethod(JSContext *cx, JSObject **objp, jsval *argv) return NULL; } +/* Beware: these two are not bracketed by JS_BEGIN/END_MACRO. */ #define XML_METHOD_PROLOG \ - JS_BEGIN_MACRO \ - xml = (JSXML *) JS_GetInstancePrivate(cx, obj, &js_XMLClass, argv); \ - if (!xml) \ - return JS_FALSE; \ - JS_END_MACRO + JSObject *obj = JS_THIS_OBJECT(cx, vp); \ + JSXML *xml = (JSXML *)JS_GetInstancePrivate(cx, obj, &js_XMLClass, vp+2); \ + if (!xml) \ + return JS_FALSE #define NON_LIST_XML_METHOD_PROLOG \ - JS_BEGIN_MACRO \ - xml = StartNonListXMLMethod(cx, &obj, argv); \ - if (!xml) \ - return JS_FALSE; \ - JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST); \ - JS_END_MACRO + JSObject *obj; \ + JSXML *xml = StartNonListXMLMethod(cx, vp, &obj); \ + if (!xml) \ + return JS_FALSE; \ + JS_ASSERT(xml->xml_class != JSXML_CLASS_LIST) static JSBool -xml_addNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_addNamespace(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; JSObject *nsobj; JSXMLNamespace *ns; @@ -5648,26 +5649,26 @@ xml_addNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (!xml) return JS_FALSE; - nsobj = CallConstructorFunction(cx, obj, &js_NamespaceClass.base, 1, argv); + nsobj = CallConstructorFunction(cx, obj, &js_NamespaceClass.base, 1, + vp + 2); if (!nsobj) return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nsobj); + vp[2] = OBJECT_TO_JSVAL(nsobj); ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj); if (!AddInScopeNamespace(cx, xml, ns)) return JS_FALSE; ns->declared = JS_TRUE; - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } static JSBool -xml_appendChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_appendChild(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *vxml; jsval name, v; JSObject *vobj; + JSXML *vxml; NON_LIST_XML_METHOD_PROLOG; xml = CHECK_COPY_ON_WRITE(cx, xml, obj); @@ -5688,31 +5689,30 @@ xml_appendChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (!IndexToIdVal(cx, vxml->xml_kids.length, &name)) return JS_FALSE; - if (!PutProperty(cx, JSVAL_TO_OBJECT(v), name, &argv[0])) + if (!PutProperty(cx, JSVAL_TO_OBJECT(v), name, &vp[2])) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } /* XML and XMLList */ static JSBool -xml_attribute(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_attribute(JSContext *cx, uintN argc, jsval *vp) { JSXMLQName *qn; - qn = ToAttributeName(cx, argv[0]); + qn = ToAttributeName(cx, vp[2]); if (!qn) return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(qn->object); /* local root */ - return GetProperty(cx, obj, argv[0], rval); + vp[2] = OBJECT_TO_JSVAL(qn->object); /* local root */ + + return GetProperty(cx, JS_THIS_OBJECT(cx, vp), vp[2], vp); } /* XML and XMLList */ static JSBool -xml_attributes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_attributes(JSContext *cx, uintN argc, jsval *vp) { jsval name; JSXMLQName *qn; @@ -5725,7 +5725,7 @@ xml_attributes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; name = OBJECT_TO_JSVAL(qn->object); JS_PUSH_SINGLE_TEMP_ROOT(cx, name, &tvr); - ok = GetProperty(cx, obj, name, rval); + ok = GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); JS_POP_TEMP_ROOT(cx, &tvr); return ok; } @@ -5779,18 +5779,18 @@ xml_child_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval name, /* XML and XMLList */ static JSBool -xml_child(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_child(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *list, *kid, *vxml; - JSXMLArrayCursor cursor; jsval name, v; + JSXML *list, *kid, *vxml; + JSXMLArrayCursor cursor; JSObject *kidobj; XML_METHOD_PROLOG; - name = argv[0]; + name = vp[2]; if (xml->xml_class == JSXML_CLASS_LIST) { /* ECMA-357 13.5.4.4 */ - list = xml_list_helper(cx, xml, rval); + list = xml_list_helper(cx, xml, vp); if (!list) return JS_FALSE; @@ -5818,24 +5818,23 @@ xml_child(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } /* ECMA-357 Edition 2 13.3.4.6 (note 13.3, not 13.4 as in Edition 1). */ - if (!xml_child_helper(cx, obj, xml, name, rval)) + if (!xml_child_helper(cx, obj, xml, name, vp)) return JS_FALSE; - if (JSVAL_IS_VOID(*rval) && !xml_list_helper(cx, xml, rval)) + if (JSVAL_IS_VOID(*vp) && !xml_list_helper(cx, xml, vp)) return JS_FALSE; return JS_TRUE; } static JSBool -xml_childIndex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_childIndex(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *parent; + JSXML *parent; uint32 i, n; NON_LIST_XML_METHOD_PROLOG; parent = xml->parent; if (!parent || xml->xml_class == JSXML_CLASS_ATTRIBUTE) { - *rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); + *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN); return JS_TRUE; } for (i = 0, n = JSXML_LENGTH(parent); i < n; i++) { @@ -5843,33 +5842,30 @@ xml_childIndex(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, break; } JS_ASSERT(i < n); - return js_NewNumberValue(cx, i, rval); + return js_NewNumberValue(cx, i, vp); } /* XML and XMLList */ static JSBool -xml_children(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_children(JSContext *cx, uintN argc, jsval *vp) { jsval name; name = ATOM_KEY(cx->runtime->atomState.starAtom); - return GetProperty(cx, obj, name, rval); + return GetProperty(cx, JS_THIS_OBJECT(cx, vp), name, vp); } /* XML and XMLList */ static JSBool -xml_comments(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_comments_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval *vp) { - JSXML *xml, *list, *kid, *vxml; + JSXML *list, *kid, *vxml; JSBool ok; uint32 i, n; JSObject *kidobj; jsval v; - XML_METHOD_PROLOG; - list = xml_list_helper(cx, xml, rval); + list = xml_list_helper(cx, xml, vp); if (!list) return JS_FALSE; @@ -5885,7 +5881,7 @@ xml_comments(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, break; kidobj = js_GetXMLObject(cx, kid); if (kidobj) { - ok = xml_comments(cx, kidobj, argc, argv, &v); + ok = xml_comments_helper(cx, kidobj, kid, &v); } else { ok = JS_FALSE; v = JSVAL_NULL; @@ -5916,19 +5912,25 @@ xml_comments(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return ok; } +static JSBool +xml_comments(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + return xml_comments_helper(cx, obj, xml, vp); +} + /* XML and XMLList */ static JSBool -xml_contains(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_contains(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *kid; jsval value; JSBool eq; JSXMLArrayCursor cursor; + JSXML *kid; JSObject *kidobj; XML_METHOD_PROLOG; - value = argv[0]; + value = vp[2]; if (xml->xml_class == JSXML_CLASS_LIST) { eq = JS_FALSE; XMLArrayCursorInit(&cursor, &xml->xml_kids); @@ -5946,67 +5948,55 @@ xml_contains(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (!xml_equality(cx, obj, value, &eq)) return JS_FALSE; } - *rval = BOOLEAN_TO_JSVAL(eq); + *vp = BOOLEAN_TO_JSVAL(eq); return JS_TRUE; } /* XML and XMLList */ static JSBool -xml_copy(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_copy(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *copy; + JSXML *copy; XML_METHOD_PROLOG; copy = DeepCopy(cx, xml, NULL, 0); if (!copy) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(copy->object); + *vp = OBJECT_TO_JSVAL(copy->object); return JS_TRUE; } /* XML and XMLList */ static JSBool -xml_descendants(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_descendants(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *list; jsval name; + JSXML *list; XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0]; + name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; list = Descendants(cx, xml, name); if (!list) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(list->object); + *vp = OBJECT_TO_JSVAL(list->object); return JS_TRUE; } /* XML and XMLList */ static JSBool -xml_elements(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_elements_helper(JSContext *cx, JSObject *obj, JSXML *xml, + JSXMLQName *nameqn, jsval *vp) { - JSXML *xml, *list, *kid, *vxml; - jsval name, v; - JSXMLQName *nameqn; - jsid funid; + JSXML *list, *kid, *vxml; + jsval v; JSBool ok; JSXMLArrayCursor cursor; JSObject *kidobj; uint32 i, n; - XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0]; - nameqn = ToXMLName(cx, name, &funid); - if (!nameqn) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nameqn->object); - - list = xml_list_helper(cx, xml, rval); + list = xml_list_helper(cx, xml, vp); if (!list) return JS_FALSE; - if (funid) - return JS_TRUE; list->xml_targetprop = nameqn; ok = JS_TRUE; @@ -6021,7 +6011,7 @@ xml_elements(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, break; kidobj = js_GetXMLObject(cx, kid); if (kidobj) { - ok = xml_elements(cx, kidobj, argc, argv, &v); + ok = xml_elements_helper(cx, kidobj, kid, nameqn, &v); } else { ok = JS_FALSE; v = JSVAL_NULL; @@ -6053,34 +6043,54 @@ xml_elements(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return ok; } -/* XML and XMLList */ static JSBool -xml_hasOwnProperty(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_elements(JSContext *cx, uintN argc, jsval *vp) { jsval name; - JSBool found; + JSXMLQName *nameqn; + jsid funid; - if (!JS_InstanceOf(cx, obj, &js_XMLClass, argv)) - return JS_FALSE; + XML_METHOD_PROLOG; - name = argv[0]; - if (!HasProperty(cx, obj, name, &found)) + name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; + nameqn = ToXMLName(cx, name, &funid); + if (!nameqn) return JS_FALSE; - if (found) { - *rval = JSVAL_TRUE; - return JS_TRUE; - } - return js_HasOwnPropertyHelper(cx, obj, js_LookupProperty, argc, argv, - rval); + vp[2] = OBJECT_TO_JSVAL(nameqn->object); + + if (funid) + return xml_list_helper(cx, xml, vp) != NULL; + + return xml_elements_helper(cx, obj, xml, nameqn, vp); } /* XML and XMLList */ static JSBool -xml_hasComplexContent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *kid; + JSObject *obj; + jsval name; + JSBool found; + + obj = JSVAL_TO_OBJECT(vp[1]); + if (!JS_InstanceOf(cx, obj, &js_XMLClass, vp + 2)) + return JS_FALSE; + + name = vp[2]; + if (!HasProperty(cx, obj, name, &found)) + return JS_FALSE; + if (found) { + *vp = JSVAL_TRUE; + return JS_TRUE; + } + return js_HasOwnPropertyHelper(cx, js_LookupProperty, vp); +} + +/* XML and XMLList */ +static JSBool +xml_hasComplexContent(JSContext *cx, uintN argc, jsval *vp) +{ + JSXML *kid; JSObject *kidobj; uint32 i, n; @@ -6091,11 +6101,11 @@ again: case JSXML_CLASS_COMMENT: case JSXML_CLASS_PROCESSING_INSTRUCTION: case JSXML_CLASS_TEXT: - *rval = JSVAL_FALSE; + *vp = JSVAL_FALSE; break; case JSXML_CLASS_LIST: if (xml->xml_kids.length == 0) { - *rval = JSVAL_TRUE; + *vp = JSVAL_TRUE; } else if (xml->xml_kids.length == 1) { kid = XMLARRAY_MEMBER(&xml->xml_kids, 0, JSXML); if (kid) { @@ -6109,11 +6119,11 @@ again: } /* FALL THROUGH */ default: - *rval = JSVAL_FALSE; + *vp = JSVAL_FALSE; for (i = 0, n = xml->xml_kids.length; i < n; i++) { kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); if (kid && kid->xml_class == JSXML_CLASS_ELEMENT) { - *rval = JSVAL_TRUE; + *vp = JSVAL_TRUE; break; } } @@ -6124,13 +6134,10 @@ again: /* XML and XMLList */ static JSBool -xml_hasSimpleContent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_hasSimpleContent(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; - XML_METHOD_PROLOG; - *rval = BOOLEAN_TO_JSVAL(HasSimpleContent(xml)); + *vp = BOOLEAN_TO_JSVAL(HasSimpleContent(xml)); return JS_TRUE; } @@ -6236,10 +6243,8 @@ FindInScopeNamespaces(JSContext *cx, JSXML *xml, JSXMLArray *nsarray) } static JSBool -xml_inScopeNamespaces(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_inScopeNamespaces(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; JSTempRootedNSArray namespaces; JSBool ok; @@ -6247,24 +6252,23 @@ xml_inScopeNamespaces(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, InitTempNSArray(cx, &namespaces); ok = FindInScopeNamespaces(cx, xml, &namespaces.array) && - TempNSArrayToJSArray(cx, &namespaces, rval); + TempNSArrayToJSArray(cx, &namespaces, vp); FinishTempNSArray(cx, &namespaces); return ok; } static JSBool -xml_insertChildAfter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_insertChildAfter(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *kid; jsval arg; + JSXML *kid; uint32 i; NON_LIST_XML_METHOD_PROLOG; if (!JSXML_HAS_KIDS(xml)) return JS_TRUE; - arg = argv[0]; + arg = vp[2]; if (JSVAL_IS_NULL(arg)) { kid = NULL; i = 0; @@ -6281,25 +6285,24 @@ xml_insertChildAfter(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, xml = CHECK_COPY_ON_WRITE(cx, xml, obj); if (!xml) return JS_FALSE; - if (!Insert(cx, xml, i, argv[1])) + if (!Insert(cx, xml, i, vp[3])) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } static JSBool -xml_insertChildBefore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_insertChildBefore(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *kid; jsval arg; + JSXML *kid; uint32 i; NON_LIST_XML_METHOD_PROLOG; if (!JSXML_HAS_KIDS(xml)) return JS_TRUE; - arg = argv[0]; + arg = vp[2]; if (JSVAL_IS_NULL(arg)) { kid = NULL; i = xml->xml_kids.length; @@ -6315,62 +6318,54 @@ xml_insertChildBefore(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, xml = CHECK_COPY_ON_WRITE(cx, xml, obj); if (!xml) return JS_FALSE; - if (!Insert(cx, xml, i, argv[1])) + if (!Insert(cx, xml, i, vp[3])) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } /* XML and XMLList */ static JSBool -xml_length(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_length(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; - XML_METHOD_PROLOG; if (xml->xml_class != JSXML_CLASS_LIST) { - *rval = JSVAL_ONE; + *vp = JSVAL_ONE; } else { - if (!js_NewNumberValue(cx, xml->xml_kids.length, rval)) + if (!js_NewNumberValue(cx, xml->xml_kids.length, vp)) return JS_FALSE; } return JS_TRUE; } static JSBool -xml_localName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_localName(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; - NON_LIST_XML_METHOD_PROLOG; - *rval = xml->name ? STRING_TO_JSVAL(xml->name->localName) : JSVAL_NULL; + *vp = xml->name ? STRING_TO_JSVAL(xml->name->localName) : JSVAL_NULL; return JS_TRUE; } static JSBool -xml_name(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_name(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; JSObject *nameobj; NON_LIST_XML_METHOD_PROLOG; if (!xml->name) { - *rval = JSVAL_NULL; + *vp = JSVAL_NULL; } else { nameobj = js_GetXMLQNameObject(cx, xml->name); if (!nameobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(nameobj); + *vp = OBJECT_TO_JSVAL(nameobj); } return JS_TRUE; } static JSBool -xml_namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_namespace(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; JSString *prefix; JSTempRootedNSArray inScopeNSes; JSBool ok; @@ -6380,17 +6375,17 @@ xml_namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, NON_LIST_XML_METHOD_PROLOG; if (argc == 0 && !JSXML_HAS_NAME(xml)) { - *rval = JSVAL_NULL; + *vp = JSVAL_NULL; return JS_TRUE; } if (argc == 0) { prefix = NULL; } else { - prefix = js_ValueToString(cx, argv[0]); + prefix = js_ValueToString(cx, vp[2]); if (!prefix) return JS_FALSE; - argv[0] = STRING_TO_JSVAL(prefix); /* local root */ + vp[2] = STRING_TO_JSVAL(prefix); /* local root */ } /* After this point the control must flow through label out. */ @@ -6416,14 +6411,14 @@ xml_namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } if (!ns) { - *rval = JSVAL_VOID; + *vp = JSVAL_VOID; } else { nsobj = js_GetXMLNamespaceObject(cx, ns); if (!nsobj) { ok = JS_FALSE; goto out; } - *rval = OBJECT_TO_JSVAL(nsobj); + *vp = OBJECT_TO_JSVAL(nsobj); } out: @@ -6432,12 +6427,11 @@ xml_namespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -xml_namespaceDeclarations(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_namespaceDeclarations(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *yml; JSBool ok; JSTempRootedNSArray ancestors, declared; + JSXML *yml; uint32 i, n; JSXMLNamespace *ns; @@ -6477,7 +6471,7 @@ xml_namespaceDeclarations(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } } - ok = TempNSArrayToJSArray(cx, &declared, rval); + ok = TempNSArrayToJSArray(cx, &declared, vp); out: /* Finishing must be in reverse order of initialization to follow LIFO. */ @@ -6500,17 +6494,15 @@ const char *js_xml_class_str[] = { }; static JSBool -xml_nodeKind(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_nodeKind(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; JSString *str; NON_LIST_XML_METHOD_PROLOG; str = JS_InternString(cx, js_xml_class_str[xml->xml_class]); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } @@ -6525,17 +6517,13 @@ NormalizingDelete(JSContext *cx, JSXML *xml, uint32 index) /* XML and XMLList */ static JSBool -xml_normalize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_normalize_helper(JSContext *cx, JSObject *obj, JSXML *xml) { - JSXML *xml, *kid, *kid2; + JSXML *kid, *kid2; uint32 i, n; JSObject *kidobj; JSString *str; - jsval junk; - XML_METHOD_PROLOG; - *rval = OBJECT_TO_JSVAL(obj); if (!JSXML_HAS_KIDS(xml)) return JS_TRUE; @@ -6549,7 +6537,7 @@ xml_normalize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, continue; if (kid->xml_class == JSXML_CLASS_ELEMENT) { kidobj = js_GetXMLObject(cx, kid); - if (!kidobj || !xml_normalize(cx, kidobj, argc, argv, &junk)) + if (!kidobj || !xml_normalize_helper(cx, kidobj, kid)) return JS_FALSE; } else if (kid->xml_class == JSXML_CLASS_TEXT) { while (i + 1 < n && @@ -6573,18 +6561,26 @@ xml_normalize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_TRUE; } +static JSBool +xml_normalize(JSContext *cx, uintN argc, jsval *vp) +{ + XML_METHOD_PROLOG; + *vp = OBJECT_TO_JSVAL(obj); + return xml_normalize_helper(cx, obj, xml); +} + /* XML and XMLList */ static JSBool -xml_parent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_parent(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *parent, *kid; + JSXML *parent, *kid; uint32 i, n; JSObject *parentobj; XML_METHOD_PROLOG; parent = xml->parent; if (xml->xml_class == JSXML_CLASS_LIST) { - *rval = JSVAL_VOID; + *vp = JSVAL_VOID; n = xml->xml_kids.length; if (n == 0) return JS_TRUE; @@ -6601,43 +6597,32 @@ xml_parent(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } if (!parent) { - *rval = JSVAL_NULL; + *vp = JSVAL_NULL; return JS_TRUE; } parentobj = js_GetXMLObject(cx, parent); if (!parentobj) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(parentobj); + *vp = OBJECT_TO_JSVAL(parentobj); return JS_TRUE; } /* XML and XMLList */ static JSBool -xml_processingInstructions(JSContext *cx, JSObject *obj, uintN argc, - jsval *argv, jsval *rval) +xml_processingInstructions_helper(JSContext *cx, JSObject *obj, JSXML *xml, + JSXMLQName *nameqn, jsval *vp) { - JSXML *xml, *list, *kid, *vxml; - jsval name, v; - JSXMLQName *nameqn; - jsid funid; + JSXML *list, *kid, *vxml; JSBool ok; JSXMLArrayCursor cursor; JSObject *kidobj; + jsval v; uint32 i, n; - XML_METHOD_PROLOG; - name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : argv[0]; - nameqn = ToXMLName(cx, name, &funid); - if (!nameqn) - return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nameqn->object); - - list = xml_list_helper(cx, xml, rval); + list = xml_list_helper(cx, xml, vp); if (!list) return JS_FALSE; - if (funid) - return JS_TRUE; list->xml_targetprop = nameqn; ok = JS_TRUE; @@ -6652,7 +6637,8 @@ xml_processingInstructions(JSContext *cx, JSObject *obj, uintN argc, break; kidobj = js_GetXMLObject(cx, kid); if (kidobj) { - ok = xml_processingInstructions(cx, kidobj, argc, argv, &v); + ok = xml_processingInstructions_helper(cx, kidobj, kid, + nameqn, &v); } else { ok = JS_FALSE; v = JSVAL_NULL; @@ -6687,38 +6673,54 @@ xml_processingInstructions(JSContext *cx, JSObject *obj, uintN argc, } static JSBool -xml_prependChild(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_processingInstructions(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; + jsval name; + JSXMLQName *nameqn; + jsid funid; + XML_METHOD_PROLOG; + + name = (argc == 0) ? ATOM_KEY(cx->runtime->atomState.starAtom) : vp[2]; + nameqn = ToXMLName(cx, name, &funid); + if (!nameqn) + return JS_FALSE; + vp[2] = OBJECT_TO_JSVAL(nameqn->object); + + if (funid) + return xml_list_helper(cx, xml, vp) != NULL; + + return xml_processingInstructions_helper(cx, obj, xml, nameqn, vp); +} + +static JSBool +xml_prependChild(JSContext *cx, uintN argc, jsval *vp) +{ NON_LIST_XML_METHOD_PROLOG; xml = CHECK_COPY_ON_WRITE(cx, xml, obj); if (!xml) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(obj); - return Insert(cx, xml, 0, argv[0]); + *vp = OBJECT_TO_JSVAL(obj); + return Insert(cx, xml, 0, vp[2]); } /* XML and XMLList */ static JSBool -xml_propertyIsEnumerable(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_propertyIsEnumerable(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; jsval name; uint32 index; XML_METHOD_PROLOG; - name = argv[0]; - *rval = JSVAL_FALSE; + name = vp[2]; + *vp = JSVAL_FALSE; if (js_IdIsIndex(name, &index)) { if (xml->xml_class == JSXML_CLASS_LIST) { /* 13.5.4.18. */ - *rval = BOOLEAN_TO_JSVAL(index < xml->xml_kids.length); + *vp = BOOLEAN_TO_JSVAL(index < xml->xml_kids.length); } else { /* 13.4.4.30. */ - *rval = BOOLEAN_TO_JSVAL(index == 0); + *vp = BOOLEAN_TO_JSVAL(index == 0); } } return JS_TRUE; @@ -6774,25 +6776,23 @@ xml_removeNamespace_helper(JSContext *cx, JSXML *xml, JSXMLNamespace *ns) } static JSBool -xml_removeNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_removeNamespace(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; JSObject *nsobj; JSXMLNamespace *ns; NON_LIST_XML_METHOD_PROLOG; - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); if (xml->xml_class != JSXML_CLASS_ELEMENT) return JS_TRUE; xml = CHECK_COPY_ON_WRITE(cx, xml, obj); if (!xml) return JS_FALSE; - nsobj = CallConstructorFunction(cx, obj, &js_NamespaceClass.base, 1, argv); + nsobj = CallConstructorFunction(cx, obj, &js_NamespaceClass.base, 1, vp + 2); if (!nsobj) return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nsobj); + vp[2] = OBJECT_TO_JSVAL(nsobj); ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj); /* NOTE: remove ns from each ancestor if not used by that ancestor. */ @@ -6800,39 +6800,39 @@ xml_removeNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -xml_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_replace(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *vxml, *kid; jsval name, value; + JSXML *vxml, *kid; uint32 index, matchIndex; JSObject *nameobj; JSXMLQName *nameqn; NON_LIST_XML_METHOD_PROLOG; - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); if (xml->xml_class != JSXML_CLASS_ELEMENT) return JS_TRUE; - value = argv[1]; + value = vp[3]; vxml = VALUE_IS_XML(cx, value) ? (JSXML *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(value)) : NULL; if (!vxml) { - if (!JS_ConvertValue(cx, value, JSTYPE_STRING, &argv[1])) + if (!JS_ConvertValue(cx, value, JSTYPE_STRING, &vp[3])) return JS_FALSE; - value = argv[1]; + value = vp[3]; } else { vxml = DeepCopy(cx, vxml, NULL, 0); if (!vxml) return JS_FALSE; - value = argv[1] = OBJECT_TO_JSVAL(vxml->object); + value = vp[3] = OBJECT_TO_JSVAL(vxml->object); } xml = CHECK_COPY_ON_WRITE(cx, xml, obj); if (!xml) return JS_FALSE; - name = argv[0]; + name = vp[2]; if (js_IdIsIndex(name, &index)) return Replace(cx, xml, index, value); @@ -6840,7 +6840,7 @@ xml_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) nameobj = CallConstructorFunction(cx, obj, &js_QNameClass.base, 1, &name); if (!nameobj) return JS_FALSE; - argv[0] = OBJECT_TO_JSVAL(nameobj); + vp[2] = OBJECT_TO_JSVAL(nameobj); nameqn = (JSXMLQName *) JS_GetPrivate(cx, nameobj); index = xml->xml_kids.length; @@ -6859,26 +6859,25 @@ xml_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -xml_setChildren(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_setChildren(JSContext *cx, uintN argc, jsval *vp) { - if (!StartNonListXMLMethod(cx, &obj, argv)) + JSObject *obj; + + if (!StartNonListXMLMethod(cx, vp, &obj)) return JS_FALSE; if (!PutProperty(cx, obj, ATOM_KEY(cx->runtime->atomState.starAtom), - &argv[0])) { + &vp[2])) { return JS_FALSE; } - *rval = OBJECT_TO_JSVAL(obj); + *vp = OBJECT_TO_JSVAL(obj); return JS_TRUE; } static JSBool -xml_setLocalName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_setLocalName(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; jsval name; JSXMLQName *nameqn; JSString *namestr; @@ -6887,15 +6886,15 @@ xml_setLocalName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (!JSXML_HAS_NAME(xml)) return JS_TRUE; - name = argv[0]; + name = vp[2]; if (!JSVAL_IS_PRIMITIVE(name) && OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(name)) == &js_QNameClass.base) { nameqn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(name)); namestr = nameqn->localName; } else { - if (!JS_ConvertValue(cx, name, JSTYPE_STRING, &argv[0])) + if (!JS_ConvertValue(cx, name, JSTYPE_STRING, &vp[2])) return JS_FALSE; - name = argv[0]; + name = vp[2]; namestr = JSVAL_TO_STRING(name); } @@ -6907,12 +6906,12 @@ xml_setLocalName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -xml_setName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_setName(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *nsowner; jsval name; JSXMLQName *nameqn; JSObject *nameobj; + JSXML *nsowner; JSXMLArray *nsarray; uint32 i, n; JSXMLNamespace *ns; @@ -6921,12 +6920,12 @@ xml_setName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) if (!JSXML_HAS_NAME(xml)) return JS_TRUE; - name = argv[0]; + name = vp[2]; if (!JSVAL_IS_PRIMITIVE(name) && OBJ_GET_CLASS(cx, JSVAL_TO_OBJECT(name)) == &js_QNameClass.base && !(nameqn = (JSXMLQName *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(name))) ->uri) { - name = argv[0] = STRING_TO_JSVAL(nameqn->localName); + name = vp[2] = STRING_TO_JSVAL(nameqn->localName); } nameobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 1, &name); @@ -7011,13 +7010,12 @@ xml_setName(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } static JSBool -xml_setNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml, *nsowner; JSObject *nsobj, *qnobj; JSXMLNamespace *ns; jsval qnargv[2]; + JSXML *nsowner; NON_LIST_XML_METHOD_PROLOG; if (!JSXML_HAS_NAME(xml)) @@ -7027,13 +7025,14 @@ xml_setNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, if (!xml || !js_GetXMLQNameObject(cx, xml->name)) return JS_FALSE; - nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, 1, argv); + nsobj = js_ConstructObject(cx, &js_NamespaceClass.base, NULL, obj, 1, + vp + 2); if (!nsobj) return JS_FALSE; ns = (JSXMLNamespace *) JS_GetPrivate(cx, nsobj); ns->declared = JS_TRUE; - qnargv[0] = argv[0] = OBJECT_TO_JSVAL(nsobj); + qnargv[0] = vp[2] = OBJECT_TO_JSVAL(nsobj); qnargv[1] = OBJECT_TO_JSVAL(xml->name->object); qnobj = js_ConstructObject(cx, &js_QNameClass.base, NULL, NULL, 2, qnargv); if (!qnobj) @@ -7057,16 +7056,15 @@ xml_setNamespace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, /* XML and XMLList */ static JSBool -xml_text(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_text_helper(JSContext *cx, JSObject *obj, JSXML *xml, jsval *vp) { - JSXML *xml, *list, *kid, *vxml; + JSXML *list, *kid, *vxml; uint32 i, n; JSBool ok; JSObject *kidobj; jsval v; - XML_METHOD_PROLOG; - list = xml_list_helper(cx, xml, rval); + list = xml_list_helper(cx, xml, vp); if (!list) return JS_FALSE; @@ -7080,7 +7078,7 @@ xml_text(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) break; kidobj = js_GetXMLObject(cx, kid); if (kidobj) { - ok = xml_text(cx, kidobj, argc, argv, &v); + ok = xml_text_helper(cx, kidobj, kid, &v); } else { ok = JS_FALSE; v = JSVAL_NULL; @@ -7105,18 +7103,11 @@ xml_text(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_TRUE; } -/* XML and XMLList */ static JSBool -xml_toXMLString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_text(JSContext *cx, uintN argc, jsval *vp) { - JSString *str; - - str = ToXMLString(cx, OBJECT_TO_JSVAL(obj)); - if (!str) - return JS_FALSE; - *rval = STRING_TO_JSVAL(str); - return JS_TRUE; + XML_METHOD_PROLOG; + return xml_text_helper(cx, obj, xml, vp); } /* XML and XMLList */ @@ -7158,70 +7149,81 @@ xml_toString_helper(JSContext *cx, JSXML *xml) } static JSBool -xml_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_toString(JSContext *cx, uintN argc, jsval *vp) { - JSXML *xml; JSString *str; XML_METHOD_PROLOG; str = xml_toString_helper(cx, xml); if (!str) return JS_FALSE; - *rval = STRING_TO_JSVAL(str); + *vp = STRING_TO_JSVAL(str); return JS_TRUE; } /* XML and XMLList */ static JSBool -xml_valueOf(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_toXMLString(JSContext *cx, uintN argc, jsval *vp) { - *rval = OBJECT_TO_JSVAL(obj); + JSString *str; + + str = ToXMLString(cx, vp[1]); + if (!str) + return JS_FALSE; + *vp = STRING_TO_JSVAL(str); + return JS_TRUE; +} + +/* XML and XMLList */ +static JSBool +xml_valueOf(JSContext *cx, uintN argc, jsval *vp) +{ + *vp = vp[1]; return JS_TRUE; } static JSFunctionSpec xml_methods[] = { - {"addNamespace", xml_addNamespace, 1,0,0}, - {"appendChild", xml_appendChild, 1,0,0}, - {js_attribute_str, xml_attribute, 1,0,0}, - {"attributes", xml_attributes, 0,0,0}, - {"child", xml_child, 1,0,0}, - {"childIndex", xml_childIndex, 0,0,0}, - {"children", xml_children, 0,0,0}, - {"comments", xml_comments, 0,0,0}, - {"contains", xml_contains, 1,0,0}, - {"copy", xml_copy, 0,0,0}, - {"descendants", xml_descendants, 1,0,0}, - {"elements", xml_elements, 1,0,0}, - {"hasOwnProperty", xml_hasOwnProperty, 1,0,0}, - {"hasComplexContent", xml_hasComplexContent, 1,0,0}, - {"hasSimpleContent", xml_hasSimpleContent, 1,0,0}, - {"inScopeNamespaces", xml_inScopeNamespaces, 0,0,0}, - {"insertChildAfter", xml_insertChildAfter, 2,0,0}, - {"insertChildBefore", xml_insertChildBefore, 2,0,0}, - {js_length_str, xml_length, 0,0,0}, - {js_localName_str, xml_localName, 0,0,0}, - {js_name_str, xml_name, 0,0,0}, - {js_namespace_str, xml_namespace, 1,0,0}, - {"namespaceDeclarations", xml_namespaceDeclarations, 0,0,0}, - {"nodeKind", xml_nodeKind, 0,0,0}, - {"normalize", xml_normalize, 0,0,0}, - {js_xml_parent_str, xml_parent, 0,0,0}, - {"processingInstructions",xml_processingInstructions,1,0,0}, - {"prependChild", xml_prependChild, 1,0,0}, - {"propertyIsEnumerable", xml_propertyIsEnumerable, 1,0,0}, - {"removeNamespace", xml_removeNamespace, 1,0,0}, - {"replace", xml_replace, 2,0,0}, - {"setChildren", xml_setChildren, 1,0,0}, - {"setLocalName", xml_setLocalName, 1,0,0}, - {"setName", xml_setName, 1,0,0}, - {"setNamespace", xml_setNamespace, 1,0,0}, - {js_text_str, xml_text, 0,0,0}, - {js_toString_str, xml_toString, 0,0,0}, - {js_toXMLString_str, xml_toXMLString, 0,0,0}, - {js_toSource_str, xml_toXMLString, 0,0,0}, - {js_valueOf_str, xml_valueOf, 0,0,0}, - {0,0,0,0,0} + JS_FN("addNamespace", xml_addNamespace, 1,1,0,0), + JS_FN("appendChild", xml_appendChild, 1,1,0,0), + JS_FN(js_attribute_str, xml_attribute, 1,1,0,0), + JS_FN("attributes", xml_attributes, 0,0,0,0), + JS_FN("child", xml_child, 1,1,0,0), + JS_FN("childIndex", xml_childIndex, 0,0,0,0), + JS_FN("children", xml_children, 0,0,0,0), + JS_FN("comments", xml_comments, 0,0,0,0), + JS_FN("contains", xml_contains, 1,1,0,0), + JS_FN("copy", xml_copy, 0,0,0,0), + JS_FN("descendants", xml_descendants, 0,1,0,0), + JS_FN("elements", xml_elements, 0,1,0,0), + JS_FN("hasOwnProperty", xml_hasOwnProperty, 1,1,0,0), + JS_FN("hasComplexContent", xml_hasComplexContent, 1,1,0,0), + JS_FN("hasSimpleContent", xml_hasSimpleContent, 1,1,0,0), + JS_FN("inScopeNamespaces", xml_inScopeNamespaces, 0,0,0,0), + JS_FN("insertChildAfter", xml_insertChildAfter, 2,2,0,0), + JS_FN("insertChildBefore", xml_insertChildBefore, 2,2,0,0), + JS_FN(js_length_str, xml_length, 0,0,0,0), + JS_FN(js_localName_str, xml_localName, 0,0,0,0), + JS_FN(js_name_str, xml_name, 0,0,0,0), + JS_FN(js_namespace_str, xml_namespace, 0,1,0,0), + JS_FN("namespaceDeclarations", xml_namespaceDeclarations, 0,0,0,0), + JS_FN("nodeKind", xml_nodeKind, 0,0,0,0), + JS_FN("normalize", xml_normalize, 0,0,0,0), + JS_FN(js_xml_parent_str, xml_parent, 0,0,0,0), + JS_FN("processingInstructions",xml_processingInstructions,0,1,0,0), + JS_FN("prependChild", xml_prependChild, 1,1,0,0), + JS_FN("propertyIsEnumerable", xml_propertyIsEnumerable, 1,1,0,0), + JS_FN("removeNamespace", xml_removeNamespace, 1,1,0,0), + JS_FN("replace", xml_replace, 2,2,0,0), + JS_FN("setChildren", xml_setChildren, 1,1,0,0), + JS_FN("setLocalName", xml_setLocalName, 1,1,0,0), + JS_FN("setName", xml_setName, 1,1,0,0), + JS_FN("setNamespace", xml_setNamespace, 1,1,0,0), + JS_FN(js_text_str, xml_text, 0,0,0,0), + JS_FN(js_toString_str, xml_toString, 0,0,0,0), + JS_FN(js_toXMLString_str, xml_toXMLString, 0,0,0,0), + JS_FN(js_toSource_str, xml_toXMLString, 0,0,0,0), + JS_FN(js_valueOf_str, xml_valueOf, 0,0,0,0), + JS_FS_END }; static JSBool @@ -7263,26 +7265,26 @@ SetDefaultXMLSettings(JSContext *cx, JSObject *obj) } static JSBool -xml_settings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +xml_settings(JSContext *cx, uintN argc, jsval *vp) { JSObject *settings; settings = JS_NewObject(cx, NULL, NULL, NULL); if (!settings) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(settings); - return CopyXMLSettings(cx, obj, settings); + *vp = OBJECT_TO_JSVAL(settings); + return CopyXMLSettings(cx, JS_THIS_OBJECT(cx, vp), settings); } static JSBool -xml_setSettings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_setSettings(JSContext *cx, uintN argc, jsval *vp) { + JSObject *obj, *settings; jsval v; JSBool ok; - JSObject *settings; - v = argv[0]; + obj = JS_THIS_OBJECT(cx, vp); + v = vp[2]; if (JSVAL_IS_NULL(v) || JSVAL_IS_VOID(v)) { cx->xmlSettingFlags = 0; ok = SetDefaultXMLSettings(cx, obj); @@ -7299,23 +7301,22 @@ xml_setSettings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, } static JSBool -xml_defaultSettings(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, - jsval *rval) +xml_defaultSettings(JSContext *cx, uintN argc, jsval *vp) { JSObject *settings; settings = JS_NewObject(cx, NULL, NULL, NULL); if (!settings) return JS_FALSE; - *rval = OBJECT_TO_JSVAL(settings); + *vp = OBJECT_TO_JSVAL(settings); return SetDefaultXMLSettings(cx, settings); } static JSFunctionSpec xml_static_methods[] = { - {"settings", xml_settings, 0,0,0}, - {"setSettings", xml_setSettings, 1,0,0}, - {"defaultSettings", xml_defaultSettings, 0,0,0}, - {0,0,0,0,0} + JS_FN("settings", xml_settings, 0,0,0,0), + JS_FN("setSettings", xml_setSettings, 1,1,0,0), + JS_FN("defaultSettings", xml_defaultSettings, 0,0,0,0), + JS_FS_END }; static JSBool @@ -7632,12 +7633,12 @@ js_InitAnyNameClass(JSContext *cx, JSObject *obj) JSObject * js_InitXMLClass(JSContext *cx, JSObject *obj) { - JSObject *proto, *pobj, *ctor; + JSObject *proto, *pobj; JSFunction *fun; JSXML *xml; JSProperty *prop; JSScopeProperty *sprop; - jsval cval, argv[1], junk; + jsval cval, vp[3]; /* Define the isXMLName function. */ if (!JS_DefineFunction(cx, obj, js_isXMLName_str, xml_isXMLName, 1, 0)) @@ -7676,9 +7677,10 @@ js_InitXMLClass(JSContext *cx, JSObject *obj) JS_ASSERT(VALUE_IS_FUNCTION(cx, cval)); /* Set default settings. */ - ctor = JSVAL_TO_OBJECT(cval); - argv[0] = JSVAL_VOID; - if (!xml_setSettings(cx, ctor, 1, argv, &junk)) + vp[0] = JSVAL_NULL; + vp[1] = cval; + vp[2] = JSVAL_VOID; + if (!xml_setSettings(cx, 1, vp)) return NULL; /* Define the XMLList function and give it the same prototype as XML. */