Fast (frame-less) native call optimizations (385393, r=igor).

This commit is contained in:
brendan@mozilla.org 2007-08-01 21:33:52 -07:00
parent 03a713b38b
commit 767c4ea288
34 changed files with 2718 additions and 2195 deletions

View File

@ -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. */

View File

@ -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;

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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[];

View File

@ -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

View File

@ -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;

View File

@ -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. */

File diff suppressed because it is too large Load Diff

View File

@ -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,8 +537,8 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
nslots = 2;
if (fun) {
nslots += fun->nargs;
if (FUN_NATIVE(fun))
nslots += FUN_MINARGS(fun);
if (!FUN_INTERPRETED(fun))
nslots += fun->u.n.extra;
}
@ -564,6 +564,7 @@ js_watch_set(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
frame.pc = script->code + script->length
- JSOP_STOP_LENGTH;
}
frame.callee = closure;
frame.fun = fun;
frame.argv = argv + 2;
frame.down = cx->fp;
@ -597,7 +598,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 +880,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)
{
@ -914,9 +921,10 @@ JS_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
{
if (!fp)
fp = cx->fp;
while ((fp = fp->down) != NULL) {
while (fp) {
if (fp->script)
return fp;
fp = fp->down;
}
return NULL;
}
@ -928,10 +936,8 @@ JS_StackFramePrincipals(JSContext *cx, JSStackFrame *fp)
JSRuntime *rt = cx->runtime;
if (rt->findObjectPrincipals) {
JSObject *callee = JSVAL_TO_OBJECT(fp->argv[-2]);
if (fp->fun->object != callee)
return rt->findObjectPrincipals(cx, callee);
if (fp->fun->object != fp->callee)
return rt->findObjectPrincipals(cx, fp->callee);
/* FALL THROUGH */
}
}
@ -944,13 +950,11 @@ JS_PUBLIC_API(JSPrincipals *)
JS_EvalFramePrincipals(JSContext *cx, JSStackFrame *fp, JSStackFrame *caller)
{
JSRuntime *rt;
JSObject *callee;
JSPrincipals *principals, *callerPrincipals;
rt = cx->runtime;
if (rt->findObjectPrincipals) {
callee = JSVAL_TO_OBJECT(fp->argv[-2]);
principals = rt->findObjectPrincipals(cx, callee);
principals = rt->findObjectPrincipals(cx, fp->callee);
} else {
principals = NULL;
}
@ -1051,7 +1055,19 @@ 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;
/*
* Test both fp->fun and fp->argv to defend against any control flow from
* the compiler reaching this API entry point, where fp is a frame pushed
* by the compiler that has non-null fun but null argv.
*/
if (fp->fun && fp->argv) {
JSObject *obj = fp->callee;
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)
@ -1063,7 +1079,7 @@ JS_IsConstructorFrame(JSContext *cx, JSStackFrame *fp)
JS_PUBLIC_API(JSObject *)
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp)
{
return fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : NULL;
return fp->callee;
}
JS_PUBLIC_API(JSBool)
@ -1550,9 +1566,8 @@ JS_GetTopScriptFilenameFlags(JSContext *cx, JSStackFrame *fp)
if (!fp)
fp = cx->fp;
while (fp) {
if (fp->script) {
if (fp->script)
return JS_GetScriptFilenameFlags(fp->script);
}
fp = fp->down;
}
return 0;

View File

@ -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);
@ -229,7 +232,7 @@ extern JS_PUBLIC_API(void)
JS_SetFrameReturnValue(JSContext *cx, JSStackFrame *fp, jsval rval);
/**
* Return fp's callee function object (fp->argv[-2]) if it has one.
* Return fp's callee function object (fp->callee) if it has one.
*/
extern JS_PUBLIC_API(JSObject *)
JS_GetFrameCalleeObject(JSContext *cx, JSStackFrame *fp);

View File

@ -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) {
@ -3212,6 +3211,7 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body,
JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj &&
fp->scopeChain != funobj));
memset(&frame, 0, sizeof frame);
frame.callee = funobj;
frame.fun = fun;
frame.varobj = frame.scopeChain = funobj;
frame.down = fp;
@ -4029,7 +4029,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 +5928,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 +5950,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;

View File

@ -274,12 +274,10 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message,
stackDepth = 0;
valueCount = 0;
for (fp = cx->fp; fp; fp = fp->down) {
if (fp->fun && fp->argv) {
if (fp->fun) {
if (checkAccess) {
v = fp->argv[-2];
if (!JSVAL_IS_PRIMITIVE(v) &&
!checkAccess(cx, JSVAL_TO_OBJECT(v), callerid,
JSACC_READ, &v /* ignored */)) {
if (!checkAccess(cx, fp->callee, callerid, JSACC_READ,
&v /* ignored */)) {
break;
}
}
@ -811,20 +809,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 +857,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 +866,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 +979,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 +1241,7 @@ js_ReportUncaughtException(JSContext *cx)
{
jsval exn;
JSObject *exnObject;
jsval vp[5];
jsval roots[5];
JSTempValueRooter tvr;
JSErrorReport *reportp, report;
JSString *str;
@ -1252,8 +1254,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 +1267,7 @@ js_ReportUncaughtException(JSContext *cx)
exnObject = NULL;
} else {
exnObject = JSVAL_TO_OBJECT(exn);
vp[0] = exn;
roots[0] = exn;
}
JS_ClearPendingException(cx);
@ -1276,7 +1278,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 +1293,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 +1318,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;

View File

@ -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();
@ -376,7 +376,7 @@ args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
switch (slot) {
case ARGS_CALLEE:
if (!TEST_OVERRIDE_BIT(fp, slot))
*vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
*vp = OBJECT_TO_JSVAL(fp->callee);
break;
case ARGS_LENGTH:
@ -464,8 +464,7 @@ args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
atom = cx->runtime->atomState.calleeAtom;
if (str == ATOM_TO_STRING(atom)) {
tinyid = ARGS_CALLEE;
value = fp->argv ? fp->argv[-2]
: OBJECT_TO_JSVAL(fp->fun->object);
value = OBJECT_TO_JSVAL(fp->callee);
} else {
atom = NULL;
@ -594,7 +593,7 @@ js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
/* The default call parent is its function's parent (static link). */
if (!parent) {
funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
funobj = fp->callee;
if (funobj)
parent = OBJ_GET_PARENT(cx, funobj);
}
@ -763,13 +762,13 @@ call_enumerate(JSContext *cx, JSObject *obj)
return JS_TRUE;
/*
* Do not enumerate a cloned function object at fp->argv[-2], it may have
* Do not enumerate a cloned function object at fp->callee, it may have
* gained its own (mutable) scope (e.g., a brutally-shared XUL script sets
* the clone's prototype property). We must enumerate the function object
* that was decorated with parameter and local variable properties by the
* compiler when the compiler created fp->fun, namely fp->fun->object.
*
* Contrast with call_resolve, where we prefer fp->argv[-2], because we'll
* Contrast with call_resolve, where we prefer fp->callee, because we'll
* use js_LookupProperty to find any overridden properties in that object,
* if it was a mutated clone; and if not, we will search its prototype,
* fp->fun->object, to find compiler-created params and locals.
@ -845,10 +844,10 @@ call_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
if (!JSVAL_IS_STRING(id))
return JS_TRUE;
funobj = fp->argv ? JSVAL_TO_OBJECT(fp->argv[-2]) : fp->fun->object;
funobj = fp->callee;
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 +871,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);
@ -933,7 +932,7 @@ call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (fp) {
JS_ASSERT(fp->fun);
*vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
*vp = OBJECT_TO_JSVAL(fp->callee);
}
}
return JS_TRUE;
@ -1066,8 +1065,8 @@ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
case FUN_CALLER:
while (fp && (fp->flags & JSFRAME_SKIP_CALLER) && fp->down)
fp = fp->down;
if (fp && fp->down && fp->down->fun && fp->down->argv)
*vp = fp->down->argv[-2];
if (fp && fp->down && fp->down->fun)
*vp = OBJECT_TO_JSVAL(fp->down->callee);
else
*vp = JSVAL_NULL;
if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) {
@ -1316,7 +1315,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 +1509,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 +1552,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 +1645,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 +1674,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 +1700,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 +1729,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 +1748,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 +1773,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 +1788,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 +1797,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 +1817,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 +1830,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 +1840,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
@ -2205,7 +2209,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;
@ -2366,7 +2370,9 @@ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
}
js_ReportValueError3(cx, error,
(fp && fp->spbase <= vp && vp < fp->sp)
(fp &&
!(fp->flags & JSFRAME_IN_FAST_CALL) &&
fp->spbase <= vp && vp < fp->sp)
? vp - fp->sp
: (flags & JSV2F_SEARCH_STACK)
? JSDVG_SEARCH_STACK

View File

@ -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);

View File

@ -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)
@ -1971,41 +1972,19 @@ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
(fp->fun && JSFUN_THISP_FLAGS(fp->fun->flags)));
JS_CALL_VALUE_TRACER(trc, (jsval)fp->thisp, "this");
/*
* Mark fp->argv, even though in the common case it will be marked via our
* caller's frame, or via a JSStackHeader if fp was pushed by an external
* invocation.
*
* The hard case is when there is not enough contiguous space in the stack
* arena for actual, missing formal, and local root (JSFunctionSpec.extra)
* slots. In this case, fp->argv points to new space in a new arena, and
* marking the caller's operand stack, or an external caller's allocated
* stack tracked by a JSStackHeader, will not mark all the values stored
* and addressable via fp->argv.
*
* But note that fp->argv[-2] will be marked via the caller, even when the
* arg-vector moves. And fp->argv[-1] will be marked as well, and we mark
* it redundantly just above this comment.
*
* So in summary, solely for the hard case of moving argv due to missing
* formals and extra roots, we must mark actuals, missing formals, and any
* local roots arrayed at fp->argv here.
*
* It would be good to avoid redundant marking of the same reference, in
* the case where fp->argv does point into caller-allocated space tracked
* by fp->down->spbase or cx->stackHeaders. This would allow callbacks
* such as the forthcoming rt->gcThingCallback (bug 333078) to compute JS
* reference counts. So this comment deserves a FIXME bug to cite.
*/
if (fp->callee)
JS_CALL_OBJECT_TRACER(trc, fp->callee, "callee");
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;
}
TRACE_JSVALS(trc, nslots, fp->argv, "arg");
TRACE_JSVALS(trc, nslots + 2, fp->argv - 2, "arg");
}
JS_CALL_VALUE_TRACER(trc, fp->rval, "rval");
if (fp->vars)

View File

@ -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,13 +1213,14 @@ 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];
frame.varobj = NULL;
frame.callobj = frame.argsobj = NULL;
frame.script = script;
frame.callee = funobj;
frame.fun = fun;
frame.argc = argc;
frame.argv = sp - argc;
@ -1309,7 +1341,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)
@ -1497,6 +1565,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
frame.callobj = down->callobj;
frame.argsobj = down->argsobj;
frame.varobj = down->varobj;
frame.callee = down->callee;
frame.fun = down->fun;
frame.thisp = down->thisp;
frame.argc = down->argc;
@ -1513,6 +1582,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
obj = tmp;
}
frame.varobj = obj;
frame.callee = NULL;
frame.fun = NULL;
frame.thisp = chain;
frame.argc = 0;
@ -1875,7 +1945,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 +3885,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 +3918,222 @@ 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_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.callee = obj;
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;
if (fun->flags & JSFUN_FAST_NATIVE) {
uintN nargs = JS_MAX(argc, fun->u.n.minargs);
/* 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;
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;
}
/* 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 +4217,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)
@ -4207,7 +4319,7 @@ interrupt:
* contains script->regexps->nregexps reserved slot for the
* cloned regexps, see fun_reserveSlots, jsfun.c.
*/
funobj = JSVAL_TO_OBJECT(fp->argv[-2]);
funobj = fp->callee;
slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass);
if (!JS_GetReservedSlot(cx, funobj, slot, &rval))
return JS_FALSE;
@ -4576,6 +4688,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 +4708,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 +4727,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 +4847,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 +5088,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 +5162,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 +5640,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 +5791,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 +5808,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;
@ -5687,23 +5824,32 @@ interrupt:
i = JSProto_Boolean;
} else {
JS_ASSERT(JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval));
js_ReportValueError(cx, JSMSG_NO_PROPERTIES,
JSDVG_SEARCH_STACK, lval, NULL);
js_ReportValueError(cx, JSMSG_NO_PROPERTIES, -2, lval,
NULL);
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 +5956,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 +6052,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 +6091,6 @@ interrupt:
#if JS_THREADED_INTERP
L_JSOP_BACKPATCH:
L_JSOP_BACKPATCH_POP:
L_JSOP_UNUSED117:
#else
default:
#endif

View File

@ -61,6 +61,7 @@ struct JSStackFrame {
JSObject *callobj; /* lazily created Call object */
JSObject *argsobj; /* lazily created arguments object */
JSObject *varobj; /* variables object, where vars go */
JSObject *callee; /* function or script object */
JSScript *script; /* script being interpreted */
JSFunction *fun; /* function being called or null */
JSObject *thisp; /* "this" pointer if in method */
@ -110,6 +111,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 +154,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

View File

@ -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
@ -676,17 +679,8 @@ generator_trace(JSTracer *trc, JSObject *obj)
JSGenerator *gen;
gen = (JSGenerator *) JS_GetPrivate(trc->context, obj);
if (gen) {
/*
* We must trace argv[-2], as js_TraceStackFrame will not. Note
* that js_TraceStackFrame will trace thisp (argv[-1]) and actual
* arguments, plus any missing formals and local GC roots.
*/
JS_ASSERT(!JSVAL_IS_PRIMITIVE(gen->frame.argv[-2]));
JS_CALL_OBJECT_TRACER(trc, JSVAL_TO_OBJECT(gen->frame.argv[-2]),
"generator");
if (gen)
js_TraceStackFrame(trc, &gen->frame);
}
}
JSClass js_GeneratorClass = {
@ -753,6 +747,7 @@ js_NewGenerator(JSContext *cx, JSStackFrame *fp)
/* Copy call-invariant script and function references. */
gen->frame.script = fp->script;
gen->frame.callee = fp->callee;
gen->frame.fun = fp->fun;
/* Use newsp to carve space out of gen->stack. */
@ -900,8 +895,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 +913,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 +925,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 +956,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 +975,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 +984,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 */

View File

@ -101,57 +101,57 @@ JSClass js_MathClass = {
};
static JSBool
math_abs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_abs(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_fabs(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_acos(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_acos(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_acos(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_asin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_asin(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_asin(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_atan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_atan(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_atan(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_atan2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_atan2(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, y, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
if (!js_ValueToNumber(cx, argv[1], &y))
if (!js_ValueToNumber(cx, vp[3], &y))
return JS_FALSE;
#if !JS_USE_FDLIBM_MATH && defined(_MSC_VER)
/*
@ -165,95 +165,97 @@ math_atan2(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
z = fd_copysign(M_PI / 4, x);
if (y < 0)
z *= 3;
return js_NewDoubleValue(cx, z, rval);
return js_NewDoubleValue(cx, z, vp);
}
#endif
z = fd_atan2(x, y);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_ceil(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_ceil(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_ceil(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_cos(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_cos(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_cos(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_exp(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_exp(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
#ifdef _WIN32
if (!JSDOUBLE_IS_NaN(x)) {
if (x == *cx->runtime->jsPositiveInfinity) {
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
return JS_TRUE;
}
if (x == *cx->runtime->jsNegativeInfinity) {
*rval = JSVAL_ZERO;
*vp = JSVAL_ZERO;
return JS_TRUE;
}
}
#endif
z = fd_exp(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_floor(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_floor(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_floor(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_log(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_log(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_max(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_max(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z = *cx->runtime->jsNegativeInfinity;
jsval *argv;
uintN i;
if (argc == 0) {
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
return JS_TRUE;
}
argv = vp + 2;
for (i = 0; i < argc; i++) {
if (!js_ValueToNumber(cx, argv[i], &x))
return JS_FALSE;
if (JSDOUBLE_IS_NaN(x)) {
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
return JS_TRUE;
}
if (x == 0 && x == z && fd_copysign(1.0, z) == -1)
@ -261,24 +263,26 @@ math_max(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
else
z = (x > z) ? x : z;
}
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_min(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_min(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z = *cx->runtime->jsPositiveInfinity;
jsval *argv;
uintN i;
if (argc == 0) {
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
return JS_TRUE;
}
argv = vp + 2;
for (i = 0; i < argc; i++) {
if (!js_ValueToNumber(cx, argv[i], &x))
return JS_FALSE;
if (JSDOUBLE_IS_NaN(x)) {
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
return JS_TRUE;
}
if (x == 0 && x == z && fd_copysign(1.0,x) == -1)
@ -286,17 +290,17 @@ math_min(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
else
z = (x < z) ? x : z;
}
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_pow(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_pow(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, y, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
if (!js_ValueToNumber(cx, argv[1], &y))
if (!js_ValueToNumber(cx, vp[3], &y))
return JS_FALSE;
#if !JS_USE_FDLIBM_MATH
/*
@ -304,17 +308,17 @@ math_pow(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
* we need to wrap the libm call to make it ECMA compliant.
*/
if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
*rval = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
*vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
return JS_TRUE;
}
/* pow(x, +-0) is always 1, even for x = NaN. */
if (y == 0) {
*rval = JSVAL_ONE;
*vp = JSVAL_ONE;
return JS_TRUE;
}
#endif
z = fd_pow(x, y);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
/*
@ -391,7 +395,7 @@ random_nextDouble(JSRuntime *rt)
}
static JSBool
math_random(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_random(JSContext *cx, uintN argc, jsval *vp)
{
JSRuntime *rt;
jsdouble z;
@ -401,7 +405,7 @@ math_random(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
random_init(rt);
z = random_nextDouble(rt);
JS_UNLOCK_RUNTIME(rt);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
#if defined _WIN32 && !defined WINCE && _MSC_VER < 1400
@ -420,82 +424,81 @@ js_copysign(double x, double y)
#endif
static JSBool
math_round(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_round(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_copysign(fd_floor(x + 0.5), x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_sin(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_sin(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_sin(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_sqrt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_sqrt(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_sqrt(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
static JSBool
math_tan(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
math_tan(JSContext *cx, uintN argc, jsval *vp)
{
jsdouble x, z;
if (!js_ValueToNumber(cx, argv[0], &x))
if (!js_ValueToNumber(cx, vp[2], &x))
return JS_FALSE;
z = fd_tan(x);
return js_NewNumberValue(cx, z, rval);
return js_NewNumberValue(cx, z, vp);
}
#if JS_HAS_TOSOURCE
static JSBool
math_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
jsval *rval)
math_toSource(JSContext *cx, uintN argc, jsval *vp)
{
*rval = ATOM_KEY(CLASS_ATOM(cx, Math));
*vp = ATOM_KEY(CLASS_ATOM(cx, Math));
return JS_TRUE;
}
#endif
static JSFunctionSpec math_static_methods[] = {
#if JS_HAS_TOSOURCE
{js_toSource_str, math_toSource, 0, 0, 0},
JS_FN(js_toSource_str, math_toSource, 0, 0, 0, 0),
#endif
{"abs", math_abs, 1, 0, 0},
{"acos", math_acos, 1, 0, 0},
{"asin", math_asin, 1, 0, 0},
{"atan", math_atan, 1, 0, 0},
{"atan2", math_atan2, 2, 0, 0},
{"ceil", math_ceil, 1, 0, 0},
{"cos", math_cos, 1, 0, 0},
{"exp", math_exp, 1, 0, 0},
{"floor", math_floor, 1, 0, 0},
{"log", math_log, 1, 0, 0},
{"max", math_max, 2, 0, 0},
{"min", math_min, 2, 0, 0},
{"pow", math_pow, 2, 0, 0},
{"random", math_random, 0, 0, 0},
{"round", math_round, 1, 0, 0},
{"sin", math_sin, 1, 0, 0},
{"sqrt", math_sqrt, 1, 0, 0},
{"tan", math_tan, 1, 0, 0},
{0,0,0,0,0}
JS_FN("abs", math_abs, 1, 1, 0, 0),
JS_FN("acos", math_acos, 1, 1, 0, 0),
JS_FN("asin", math_asin, 1, 1, 0, 0),
JS_FN("atan", math_atan, 1, 1, 0, 0),
JS_FN("atan2", math_atan2, 2, 2, 0, 0),
JS_FN("ceil", math_ceil, 1, 1, 0, 0),
JS_FN("cos", math_cos, 1, 1, 0, 0),
JS_FN("exp", math_exp, 1, 1, 0, 0),
JS_FN("floor", math_floor, 1, 1, 0, 0),
JS_FN("log", math_log, 1, 1, 0, 0),
JS_FN("max", math_max, 0, 2, 0, 0),
JS_FN("min", math_min, 0, 2, 0, 0),
JS_FN("pow", math_pow, 2, 2, 0, 0),
JS_FN("random", math_random, 0, 0, 0, 0),
JS_FN("round", math_round, 1, 1, 0, 0),
JS_FN("sin", math_sin, 1, 1, 0, 0),
JS_FN("sqrt", math_sqrt, 1, 1, 0, 0),
JS_FN("tan", math_tan, 1, 1, 0, 0),
JS_FS_END
};
JSObject *

View File

@ -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[]. */

View File

@ -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
@ -4248,8 +4255,8 @@ ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
* So we switch the cx->fp to the frame below us. We stick the
* current frame in the dormantFrameChain to protect it from gc.
*/
JSStackFrame *fp = cx->fp;
if (fp->down) {
JS_ASSERT(!fp->dormantNext);
fp->dormantNext = cx->dormantFrameChain;

View File

@ -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);

View File

@ -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:

View File

@ -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)
/*

View File

@ -485,6 +485,7 @@ MaybeSetupFrame(JSContext *cx, JSObject *chain, JSStackFrame *oldfp,
if (oldfp && (newfp->flags & JSFRAME_SPECIAL)) {
newfp->varobj = oldfp->varobj;
newfp->vars = oldfp->vars;
newfp->callee = oldfp->callee;
newfp->fun = oldfp->fun;
}
}
@ -779,6 +780,7 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,
if (!fp || fp->fun != fun || fp->varobj != funobj ||
fp->scopeChain != funobj) {
memset(&frame, 0, sizeof frame);
frame.callee = funobj;
frame.fun = fun;
frame.varobj = frame.scopeChain = funobj;
frame.down = fp;
@ -894,6 +896,7 @@ js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun)
JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj &&
fp->scopeChain != funobj));
memset(&frame, 0, sizeof frame);
frame.callee = funobj;
frame.fun = fun;
frame.varobj = frame.scopeChain = funobj;
frame.down = fp;
@ -1236,7 +1239,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;

View File

@ -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 {

View File

@ -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;

View File

@ -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.

View File

@ -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);
@ -332,7 +341,7 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags));
/* Scope chain links from Call object to callee's parent. */
parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(caller->argv[-2]));
parent = OBJ_GET_PARENT(cx, caller->callee);
if (!js_GetCallObject(cx, caller, parent))
return JS_FALSE;
}
@ -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;
@ -382,12 +391,18 @@ script_exec(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
goto out;
ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
out:
AdjustScriptExecDepth(cx, obj, -1);
AdjustScriptExecDepth(cx, obj, -1);
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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);

File diff suppressed because it is too large Load Diff