📄 jsfun.c
字号:
}
if (!js_XDRScript(xdr, &fun->script, NULL))
return JS_FALSE;
if (xdr->mode == JSXDR_DECODE) {
*objp = fun->object;
if (atomstr) {
fun->atom = js_AtomizeString(cx, atomstr, 0);
if (!fun->atom)
return JS_FALSE;
if (!OBJ_DEFINE_PROPERTY(cx, cx->globalObject,
(jsid)fun->atom, OBJECT_TO_JSVAL(*objp),
NULL, NULL, JSPROP_ENUMERATE,
NULL)) {
return JS_FALSE;
}
}
js_CallNewScriptHook(cx, fun->script, fun);
}
return JS_TRUE;
}
#else /* !JS_HAS_XDR */
#define fun_xdrObject NULL
#endif /* !JS_HAS_XDR */
#if JS_HAS_INSTANCEOF
/*
* [[HasInstance]] internal method for Function objects: fetch the .prototype
* property of its 'this' parameter, and walks the prototype chain of v (only
* if v is an object) returning true if .prototype is found.
*/
static JSBool
fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
{
jsval pval, cval;
JSString *str;
JSObject *proto, *obj2;
JSFunction *cfun, *ofun;
if (!OBJ_GET_PROPERTY(cx, obj,
(jsid)cx->runtime->atomState.classPrototypeAtom,
&pval)) {
return JS_FALSE;
}
if (JSVAL_IS_PRIMITIVE(pval)) {
/*
* Throw a runtime error if instanceof is called on a function that
* has a non-object as its .prototype value.
*/
str = js_DecompileValueGenerator(cx, -1, OBJECT_TO_JSVAL(obj), NULL);
if (str) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_PROTOTYPE, JS_GetStringBytes(str));
}
return JS_FALSE;
}
proto = JSVAL_TO_OBJECT(pval);
if (!js_IsDelegate(cx, proto, v, bp))
return JS_FALSE;
if (!*bp && !JSVAL_IS_PRIMITIVE(v)) {
/*
* Extension for "brutal sharing" of standard class constructors: if
* a script is compiled using a single, shared set of constructors, in
* particular Function and RegExp, but executed many times using other
* sets of standard constructors, then (/re/ instanceof RegExp), e.g.,
* will be false.
*
* We extend instanceof in this case to look for a matching native or
* script underlying the function object found in the 'constructor'
* property of the object in question (which is JSVAL_TO_OBJECT(v)),
* or found in the 'constructor' property of one of its prototypes.
*
* See also jsexn.c, where the *Error constructors are defined, each
* with its own native function, to satisfy (e instanceof Error) even
* when exceptions cross standard-class sharing boundaries. Note that
* Error.prototype may not lie on e's __proto__ chain in that case.
*/
obj2 = JSVAL_TO_OBJECT(v);
do {
if (!OBJ_GET_PROPERTY(cx, obj2,
(jsid)cx->runtime->atomState.constructorAtom,
&cval)) {
return JS_FALSE;
}
if (JSVAL_IS_FUNCTION(cx, cval)) {
cfun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(cval));
ofun = (JSFunction *) JS_GetPrivate(cx, obj);
if (cfun->native == ofun->native &&
cfun->script == ofun->script) {
*bp = JS_TRUE;
break;
}
}
} while ((obj2 = OBJ_GET_PROTO(cx, obj2)) != NULL);
}
return JS_TRUE;
}
#else /* !JS_HAS_INSTANCEOF */
#define fun_hasInstance NULL
#endif /* !JS_HAS_INSTANCEOF */
static uint32
fun_mark(JSContext *cx, JSObject *obj, void *arg)
{
JSFunction *fun;
fun = (JSFunction *) JS_GetPrivate(cx, obj);
if (fun) {
if (fun->atom)
GC_MARK_ATOM(cx, fun->atom, arg);
if (fun->script)
js_MarkScript(cx, fun->script, arg);
}
return 0;
}
/*
* Reserve two slots in all function objects for XPConnect. Note that this
* does not bloat every instance, only those on which reserved slots are set,
* and those on which ad-hoc properties are defined.
*/
JSClass js_FunctionClass = {
js_Function_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2),
JS_PropertyStub, JS_PropertyStub,
fun_getProperty, JS_PropertyStub,
JS_EnumerateStub, (JSResolveOp)fun_resolve,
fun_convert, fun_finalize,
NULL, NULL,
NULL, NULL,
fun_xdrObject, fun_hasInstance,
fun_mark, 0
};
JSBool
js_fun_toString(JSContext *cx, JSObject *obj, uint32 indent,
uintN argc, jsval *argv, jsval *rval)
{
jsval fval;
JSFunction *fun;
JSString *str;
if (!argv) {
JS_ASSERT(JS_ObjectIsFunction(cx, obj));
} else {
fval = argv[-1];
if (!JSVAL_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;
}
}
if (!JSVAL_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);
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);
return JS_TRUE;
}
static JSBool
fun_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
return js_fun_toString(cx, obj, 0, argc, argv, rval);
}
#if JS_HAS_TOSOURCE
static JSBool
fun_toSource(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
return js_fun_toString(cx, obj, JS_DONT_PRETTY_PRINT, argc, argv, rval);
}
#endif
static const char js_call_str[] = "call";
#if JS_HAS_CALL_FUNCTION
static JSBool
fun_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
jsval fval, *sp, *oldsp;
void *mark;
uintN i;
JSStackFrame *fp;
JSBool ok;
if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1]))
return JS_FALSE;
fval = argv[-1];
if (!JSVAL_IS_FUNCTION(cx, fval)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, js_call_str,
JS_GetStringBytes(JS_ValueToString(cx, fval)));
return JS_FALSE;
}
if (argc == 0) {
/* Call fun with its parent as the 'this' parameter if no args. */
obj = OBJ_GET_PARENT(cx, obj);
} else {
/* Otherwise convert the first arg to 'this' and skip over it. */
if (!js_ValueToObject(cx, argv[0], &obj))
return JS_FALSE;
argc--;
argv++;
}
/* Allocate stack space for fval, obj, and the args. */
sp = js_AllocStack(cx, 2 + argc, &mark);
if (!sp)
return JS_FALSE;
/* Push fval, obj, and the args. */
*sp++ = fval;
*sp++ = OBJECT_TO_JSVAL(obj);
for (i = 0; i < argc; i++)
*sp++ = argv[i];
/* Lift current frame to include the args and do the call. */
fp = cx->fp;
oldsp = fp->sp;
fp->sp = sp;
ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
/* Store rval and pop stack back to our frame's sp. */
*rval = fp->sp[-1];
fp->sp = oldsp;
js_FreeStack(cx, mark);
return ok;
}
#endif /* JS_HAS_CALL_FUNCTION */
#if JS_HAS_APPLY_FUNCTION
static JSBool
fun_apply(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
jsval fval, *sp, *oldsp;
JSObject *aobj;
jsuint length;
void *mark;
uintN i;
JSBool ok;
JSStackFrame *fp;
if (argc == 0) {
/* Will get globalObject as 'this' and no other agurments. */
return fun_call(cx, obj, argc, argv, rval);
}
if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &argv[-1]))
return JS_FALSE;
fval = argv[-1];
if (!JSVAL_IS_FUNCTION(cx, fval)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_INCOMPATIBLE_PROTO,
js_Function_str, "apply",
JS_GetStringBytes(JS_ValueToString(cx, fval)));
return JS_FALSE;
}
/* Quell GCC overwarnings. */
aobj = NULL;
length = 0;
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])) {
argc = 0;
} else {
/* The second arg must be an array (or arguments object). */
if (JSVAL_IS_PRIMITIVE(argv[1]) ||
(aobj = JSVAL_TO_OBJECT(argv[1]),
OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass &&
OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass))
{
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_APPLY_ARGS);
return JS_FALSE;
}
if (!js_GetLengthProperty(cx, aobj, &length))
return JS_FALSE;
}
}
/* Convert the first arg to 'this' and skip over it. */
if (!js_ValueToObject(cx, argv[0], &obj))
return JS_FALSE;
/* Allocate stack space for fval, obj, and the args. */
argc = (uintN)JS_MIN(length, ARGC_LIMIT - 1);
sp = js_AllocStack(cx, 2 + argc, &mark);
if (!sp)
return JS_FALSE;
/* Push fval, obj, and aobj's elements as args. */
*sp++ = fval;
*sp++ = OBJECT_TO_JSVAL(obj);
for (i = 0; i < argc; i++) {
ok = JS_GetElement(cx, aobj, (jsint)i, sp);
if (!ok)
goto out;
sp++;
}
/* Lift current frame to include the args and do the call. */
fp = cx->fp;
oldsp = fp->sp;
fp->sp = sp;
ok = js_Invoke(cx, argc, JSINVOKE_INTERNAL | JSINVOKE_SKIP_CALLER);
/* Store rval and pop stack back to our frame's sp. */
*rval = fp->sp[-1];
fp->sp = oldsp;
out:
js_FreeStack(cx, mark);
return ok;
}
#endif /* JS_HAS_APPLY_FUNCTION */
static JSFunctionSpec function_methods[] = {
#if JS_HAS_TOSOURCE
{js_toSource_str, fun_toSource, 0,0,0},
#endif
{js_toString_str, fun_toString, 1,0,0},
#if JS_HAS_APPLY_FUNCTION
{"apply", fun_apply, 2,0,0},
#endif
#if JS_HAS_CALL_FUNCTION
{js_call_str, fun_call, 1,0,0},
#endif
{0,0,0,0,0}
};
JSBool
js_IsIdentifier(JSString *str)
{
size_t n;
jschar *s, c;
n = JSSTRING_LENGTH(str);
if (n == 0)
return JS_FALSE;
s = JSSTRING_CHARS(str);
c = *s;
if (!JS_ISIDENT_START(c))
return JS_FALSE;
for (n--; n != 0; n--) {
c = *++s;
if (!JS_ISIDENT(c))
return JS_FALSE;
}
return JS_TRUE;
}
static JSBool
Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
JSStackFrame *fp, *caller;
JSFunction *fun;
JSObject *parent;
uintN i, n, lineno, dupflag;
JSAtom *atom;
const char *filename;
JSObject *obj2;
JSScopeProperty *sprop;
JSString *str, *arg;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -