📄 jsfun.c
字号:
value = vp[slot];
spflags = SPROP_HAS_SHORTID;
shortid = (intN) slot;
} else {
value = JSVAL_VOID;
spflags = 0;
shortid = 0;
}
if (!js_DefineNativeProperty(cx, obj, propid, value,
getter, setter, attrs,
spflags, shortid, NULL)) {
return JS_FALSE;
}
*objp = obj;
}
}
return JS_TRUE;
}
static JSBool
call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
JSStackFrame *fp;
if (type == JSTYPE_FUNCTION) {
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
if (fp) {
JS_ASSERT(fp->fun);
*vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object);
}
}
return JS_TRUE;
}
JSClass js_CallClass = {
js_Call_str,
JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE,
JS_PropertyStub, JS_PropertyStub,
call_getProperty, call_setProperty,
call_enumerate, (JSResolveOp)call_resolve,
call_convert, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS
};
#endif /* JS_HAS_CALL_OBJECT */
/* SHARED because fun_getProperty always computes a new value. */
#define FUNCTION_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
static JSPropertySpec function_props[] = {
{js_arguments_str, CALL_ARGUMENTS, FUNCTION_PROP_ATTRS,0,0},
{js_arity_str, FUN_ARITY, FUNCTION_PROP_ATTRS,0,0},
{js_length_str, ARGS_LENGTH, FUNCTION_PROP_ATTRS,0,0},
{js_name_str, FUN_NAME, FUNCTION_PROP_ATTRS,0,0},
{js_caller_str, FUN_CALLER, FUNCTION_PROP_ATTRS,0,0},
{0,0,0,0,0}
};
static JSBool
fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
{
jsint slot;
JSFunction *fun;
JSStackFrame *fp;
#if defined _MSC_VER &&_MSC_VER <= 800
/* MSVC1.5 coredumps */
jsval bogus = *vp;
#endif
if (!JSVAL_IS_INT(id))
return JS_TRUE;
slot = JSVAL_TO_INT(id);
/* No valid function object should lack private data, but check anyway. */
fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
if (!fun)
return JS_TRUE;
/* Find fun's top-most activation record. */
for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
fp = fp->down) {
continue;
}
switch (slot) {
case CALL_ARGUMENTS:
#if JS_HAS_ARGS_OBJECT
/* Warn if strict about f.arguments or equivalent unqualified uses. */
if (!JS_ReportErrorFlagsAndNumber(cx,
JSREPORT_WARNING | JSREPORT_STRICT,
js_GetErrorMessage, NULL,
JSMSG_DEPRECATED_USAGE,
js_arguments_str)) {
return JS_FALSE;
}
if (fp) {
if (!js_GetArgsValue(cx, fp, vp))
return JS_FALSE;
} else {
*vp = JSVAL_NULL;
}
break;
#else /* !JS_HAS_ARGS_OBJECT */
*vp = OBJECT_TO_JSVAL(fp ? obj : NULL);
break;
#endif /* !JS_HAS_ARGS_OBJECT */
case ARGS_LENGTH:
if (!JSVERSION_IS_ECMA(cx->version))
*vp = INT_TO_JSVAL((jsint)(fp && fp->fun ? fp->argc : fun->nargs));
else
case FUN_ARITY:
*vp = INT_TO_JSVAL((jsint)fun->nargs);
break;
case FUN_NAME:
*vp = fun->atom
? ATOM_KEY(fun->atom)
: STRING_TO_JSVAL(cx->runtime->emptyString);
break;
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];
else
*vp = JSVAL_NULL;
if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) {
id = ATOM_KEY(cx->runtime->atomState.callerAtom);
if (!cx->runtime->checkObjectAccess(cx, obj, id, JSACC_READ, vp))
return JS_FALSE;
}
break;
default:
/* XXX fun[0] and fun.arguments[0] are equivalent. */
if (fp && fp->fun && (uintN)slot < fp->fun->nargs)
#if defined _MSC_VER &&_MSC_VER <= 800
/* MSVC1.5 coredumps */
if (bogus == *vp)
#endif
*vp = fp->argv[slot];
break;
}
return JS_TRUE;
}
static JSBool
fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
JSObject **objp)
{
JSFunction *fun;
JSString *str;
JSAtom *prototypeAtom;
if (!JSVAL_IS_STRING(id))
return JS_TRUE;
/* No valid function object should lack private data, but check anyway. */
fun = (JSFunction *)JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL);
if (!fun || !fun->object)
return JS_TRUE;
/* No need to reflect fun.prototype in 'fun.prototype = ...'. */
if (flags & JSRESOLVE_ASSIGNING)
return JS_TRUE;
/*
* Ok, check whether id is 'prototype' and bootstrap the function object's
* prototype property.
*/
str = JSVAL_TO_STRING(id);
prototypeAtom = cx->runtime->atomState.classPrototypeAtom;
if (str == ATOM_TO_STRING(prototypeAtom)) {
JSObject *proto, *parentProto;
jsval pval;
proto = parentProto = NULL;
if (fun->object != obj && fun->object) {
/*
* Clone of a function: make its prototype property value have the
* same class as the clone-parent's prototype.
*/
if (!OBJ_GET_PROPERTY(cx, fun->object, (jsid)prototypeAtom, &pval))
return JS_FALSE;
if (JSVAL_IS_OBJECT(pval))
parentProto = JSVAL_TO_OBJECT(pval);
}
/*
* Beware of the wacky case of a user function named Object -- trying
* to find a prototype for that will recur back here ad perniciem.
*/
if (!parentProto && fun->atom == cx->runtime->atomState.ObjectAtom)
return JS_TRUE;
/*
* If resolving "prototype" in a clone, clone the parent's prototype.
* Pass the constructor's (obj's) parent as the prototype parent, to
* avoid defaulting to parentProto.constructor.__parent__.
*/
proto = js_NewObject(cx, &js_ObjectClass, parentProto,
OBJ_GET_PARENT(cx, obj));
if (!proto)
return JS_FALSE;
/*
* ECMA says that constructor.prototype is DontEnum | DontDelete for
* user-defined functions, but DontEnum | ReadOnly | DontDelete for
* native "system" constructors such as Object or Function. So lazily
* set the former here in fun_resolve, but eagerly define the latter
* in JS_InitClass, with the right attributes.
*/
if (!js_SetClassPrototype(cx, obj, proto, JSPROP_PERMANENT)) {
cx->newborn[GCX_OBJECT] = NULL;
return JS_FALSE;
}
*objp = obj;
}
return JS_TRUE;
}
static JSBool
fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
{
switch (type) {
case JSTYPE_FUNCTION:
*vp = OBJECT_TO_JSVAL(obj);
return JS_TRUE;
default:
return js_TryValueOf(cx, obj, type, vp);
}
}
static void
fun_finalize(JSContext *cx, JSObject *obj)
{
JSFunction *fun;
/* No valid function object should lack private data, but check anyway. */
fun = (JSFunction *) JS_GetPrivate(cx, obj);
if (!fun)
return;
if (fun->object == obj)
fun->object = NULL;
JS_ATOMIC_DECREMENT(&fun->nrefs);
if (fun->nrefs)
return;
if (fun->script)
js_DestroyScript(cx, fun->script);
JS_free(cx, fun);
}
#if JS_HAS_XDR
#include "jsxdrapi.h"
enum {
JSXDR_FUNARG = 1,
JSXDR_FUNVAR = 2,
JSXDR_FUNCONST = 3
};
/* XXX store parent and proto, if defined */
static JSBool
fun_xdrObject(JSXDRState *xdr, JSObject **objp)
{
JSContext *cx;
JSFunction *fun;
JSString *atomstr;
char *propname;
JSScopeProperty *sprop;
uint32 userid; /* NB: holds a signed int-tagged jsval */
JSAtom *atom;
uintN i, n, dupflag;
uint32 type;
#ifdef DEBUG
uintN nvars = 0, nargs = 0;
#endif
cx = xdr->cx;
if (xdr->mode == JSXDR_ENCODE) {
/*
* No valid function object should lack private data, but fail soft
* (return true, no error report) in case one does due to API pilot
* or internal error.
*/
fun = (JSFunction *) JS_GetPrivate(cx, *objp);
if (!fun)
return JS_TRUE;
atomstr = fun->atom ? ATOM_TO_STRING(fun->atom) : NULL;
} else {
fun = js_NewFunction(cx, NULL, NULL, 0, 0, NULL, NULL);
if (!fun)
return JS_FALSE;
atomstr = NULL;
}
if (!JS_XDRStringOrNull(xdr, &atomstr) ||
!JS_XDRUint16(xdr, &fun->nargs) ||
!JS_XDRUint16(xdr, &fun->extra) ||
!JS_XDRUint16(xdr, &fun->nvars) ||
!JS_XDRUint8(xdr, &fun->flags)) {
return JS_FALSE;
}
/* do arguments and local vars */
if (fun->object) {
n = fun->nargs + fun->nvars;
if (xdr->mode == JSXDR_ENCODE) {
JSScope *scope;
JSScopeProperty **spvec, *auto_spvec[8];
void *mark;
if (n <= sizeof auto_spvec / sizeof auto_spvec[0]) {
spvec = auto_spvec;
mark = NULL;
} else {
mark = JS_ARENA_MARK(&cx->tempPool);
JS_ARENA_ALLOCATE_CAST(spvec, JSScopeProperty **, &cx->tempPool,
n * sizeof(JSScopeProperty *));
if (!spvec) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
}
}
scope = OBJ_SCOPE(fun->object);
for (sprop = SCOPE_LAST_PROP(scope); sprop;
sprop = sprop->parent) {
if (sprop->getter == js_GetArgument) {
JS_ASSERT(nargs++ <= fun->nargs);
spvec[sprop->shortid] = sprop;
} else if (sprop->getter == js_GetLocalVariable) {
JS_ASSERT(nvars++ <= fun->nvars);
spvec[fun->nargs + sprop->shortid] = sprop;
}
}
for (i = 0; i < n; i++) {
sprop = spvec[i];
JS_ASSERT(sprop->flags & SPROP_HAS_SHORTID);
type = (i < fun->nargs)
? JSXDR_FUNARG
: (sprop->attrs & JSPROP_READONLY)
? JSXDR_FUNCONST
: JSXDR_FUNVAR;
userid = INT_TO_JSVAL(sprop->shortid);
/* XXX lossy conversion, need new XDR version for ECMAv3 */
propname = JS_GetStringBytes(ATOM_TO_STRING((JSAtom *)sprop->id));
if (!propname ||
!JS_XDRUint32(xdr, &type) ||
!JS_XDRUint32(xdr, &userid) ||
!JS_XDRCString(xdr, &propname)) {
if (mark)
JS_ARENA_RELEASE(&cx->tempPool, mark);
return JS_FALSE;
}
}
if (mark)
JS_ARENA_RELEASE(&cx->tempPool, mark);
} else {
JSPropertyOp getter, setter;
for (i = n; i != 0; i--) {
uintN attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
if (!JS_XDRUint32(xdr, &type) ||
!JS_XDRUint32(xdr, &userid) ||
!JS_XDRCString(xdr, &propname)) {
return JS_FALSE;
}
JS_ASSERT(type == JSXDR_FUNARG || type == JSXDR_FUNVAR ||
type == JSXDR_FUNCONST);
if (type == JSXDR_FUNARG) {
getter = js_GetArgument;
setter = js_SetArgument;
JS_ASSERT(nargs++ <= fun->nargs);
} else if (type == JSXDR_FUNVAR || type == JSXDR_FUNCONST) {
getter = js_GetLocalVariable;
setter = js_SetLocalVariable;
if (type == JSXDR_FUNCONST)
attrs |= JSPROP_READONLY;
JS_ASSERT(nvars++ <= fun->nvars);
} else {
getter = NULL;
setter = NULL;
}
atom = js_Atomize(cx, propname, strlen(propname), 0);
JS_free(cx, propname);
if (!atom)
return JS_FALSE;
/* Flag duplicate argument if atom is bound in fun->object. */
dupflag = SCOPE_GET_PROPERTY(OBJ_SCOPE(fun->object), (jsid)atom)
? SPROP_IS_DUPLICATE
: 0;
if (!js_AddNativeProperty(cx, fun->object, (jsid)atom,
getter, setter, SPROP_INVALID_SLOT,
attrs | JSPROP_SHARED,
SPROP_HAS_SHORTID | dupflag,
JSVAL_TO_INT(userid))) {
return JS_FALSE;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -