📄 jsfun.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sw=4 et tw=78: * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * JS function support. */#include "jsstddef.h"#include <string.h>#include "jstypes.h"#include "jsbit.h"#include "jsutil.h" /* Added by JSIFY */#include "jsapi.h"#include "jsarray.h"#include "jsatom.h"#include "jscntxt.h"#include "jsconfig.h"#include "jsdbgapi.h"#include "jsfun.h"#include "jsgc.h"#include "jsinterp.h"#include "jslock.h"#include "jsnum.h"#include "jsobj.h"#include "jsopcode.h"#include "jsparse.h"#include "jsscan.h"#include "jsscope.h"#include "jsscript.h"#include "jsstr.h"#include "jsexn.h"#if JS_HAS_GENERATORS# include "jsiter.h"#endif/* Generic function/call/arguments tinyids -- also reflected bit numbers. */enum { CALL_ARGUMENTS = -1, /* predefined arguments local variable */ CALL_CALLEE = -2, /* reference to active function's object */ ARGS_LENGTH = -3, /* number of actual args, arity if inactive */ ARGS_CALLEE = -4, /* reference from arguments to active funobj */ FUN_ARITY = -5, /* number of formal parameters; desired argc */ FUN_NAME = -6, /* function name, "" if anonymous */ FUN_CALLER = -7 /* Function.prototype.caller, backward compat */};#if JSFRAME_OVERRIDE_BITS < 8# error "not enough override bits in JSStackFrame.flags!"#endif#define TEST_OVERRIDE_BIT(fp, tinyid) \ ((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))#define SET_OVERRIDE_BIT(fp, tinyid) \ ((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))JSBooljs_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp){ JSObject *argsobj; if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { JS_ASSERT(fp->callobj); return OBJ_GET_PROPERTY(cx, fp->callobj, ATOM_TO_JSID(cx->runtime->atomState .argumentsAtom), vp); } argsobj = js_GetArgsObject(cx, fp); if (!argsobj) return JS_FALSE; *vp = OBJECT_TO_JSVAL(argsobj); return JS_TRUE;}static JSBoolMarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot){ JSObject *argsobj; jsval bmapval, bmapint; size_t nbits, nbytes; jsbitmap *bitmap; argsobj = fp->argsobj; (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); nbits = fp->argc; JS_ASSERT(slot < nbits); if (JSVAL_IS_VOID(bmapval)) { if (nbits <= JSVAL_INT_BITS) { bmapint = 0; bitmap = (jsbitmap *) &bmapint; } else { nbytes = JS_HOWMANY(nbits, JS_BITS_PER_WORD) * sizeof(jsbitmap); bitmap = (jsbitmap *) JS_malloc(cx, nbytes); if (!bitmap) return JS_FALSE; memset(bitmap, 0, nbytes); bmapval = PRIVATE_TO_JSVAL(bitmap); JS_SetReservedSlot(cx, argsobj, 0, bmapval); } } else { if (nbits <= JSVAL_INT_BITS) { bmapint = JSVAL_TO_INT(bmapval); bitmap = (jsbitmap *) &bmapint; } else { bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval); } } JS_SET_BIT(bitmap, slot); if (bitmap == (jsbitmap *) &bmapint) { bmapval = INT_TO_JSVAL(bmapint); JS_SetReservedSlot(cx, argsobj, 0, bmapval); } return JS_TRUE;}/* NB: Infallible predicate, false does not mean error/exception. */static JSBoolArgWasDeleted(JSContext *cx, JSStackFrame *fp, uintN slot){ JSObject *argsobj; jsval bmapval, bmapint; jsbitmap *bitmap; argsobj = fp->argsobj; (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); if (JSVAL_IS_VOID(bmapval)) return JS_FALSE; if (fp->argc <= JSVAL_INT_BITS) { bmapint = JSVAL_TO_INT(bmapval); bitmap = (jsbitmap *) &bmapint; } else { bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval); } return JS_TEST_BIT(bitmap, slot) != 0;}JSBooljs_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, JSObject **objp, jsval *vp){ jsval val; JSObject *obj; uintN slot; if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) { JS_ASSERT(fp->callobj); if (!OBJ_GET_PROPERTY(cx, fp->callobj, ATOM_TO_JSID(cx->runtime->atomState .argumentsAtom), &val)) { return JS_FALSE; } if (JSVAL_IS_PRIMITIVE(val)) { obj = js_ValueToNonNullObject(cx, val); if (!obj) return JS_FALSE; } else { obj = JSVAL_TO_OBJECT(val); } *objp = obj; return OBJ_GET_PROPERTY(cx, obj, id, vp); } *objp = NULL; *vp = JSVAL_VOID; if (JSID_IS_INT(id)) { slot = (uintN) JSID_TO_INT(id); if (slot < fp->argc) { if (fp->argsobj && ArgWasDeleted(cx, fp, slot)) return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); *vp = fp->argv[slot]; } else { /* * 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 * * function f(x) { x = 42; return arguments[0]; } * f(); * * the call to f should return undefined, not 42. If fp->argsobj * is null at this point, as it would be in the example, return * undefined in *vp. */ if (fp->argsobj) return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); } } else { if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) { if (fp->argsobj && TEST_OVERRIDE_BIT(fp, ARGS_LENGTH)) return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); *vp = INT_TO_JSVAL((jsint) fp->argc); } } return JS_TRUE;}JSObject *js_GetArgsObject(JSContext *cx, JSStackFrame *fp){ JSObject *argsobj, *global, *parent; /* * We must be in a function activation; the function must be lightweight * or else fp must have a variable object. */ JS_ASSERT(fp->fun && (!(fp->fun->flags & JSFUN_HEAVYWEIGHT) || fp->varobj)); /* Skip eval and debugger frames. */ while (fp->flags & JSFRAME_SPECIAL) fp = fp->down; /* Create an arguments object for fp only if it lacks one. */ argsobj = fp->argsobj; if (argsobj) return argsobj; /* Link the new object to fp so it can get actual argument values. */ argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL); if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) { cx->weakRoots.newborn[GCX_OBJECT] = NULL; return NULL; } /* * Give arguments an intrinsic scope chain link to fp's global object. * Since the arguments object lacks a prototype because js_ArgumentsClass * is not initialized, js_NewObject won't assign a default parent to it. * * Therefore if arguments is used as the head of an eval scope chain (via * a direct or indirect call to eval(program, arguments)), any reference * to a standard class object in the program will fail to resolve due to * js_GetClassPrototype not being able to find a global object containing * the standard prototype by starting from arguments and following parent. */ global = fp->scopeChain; while ((parent = OBJ_GET_PARENT(cx, global)) != NULL) global = parent; argsobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(global); fp->argsobj = argsobj; return argsobj;}static JSBoolargs_enumerate(JSContext *cx, JSObject *obj);JSBooljs_PutArgsObject(JSContext *cx, JSStackFrame *fp){ JSObject *argsobj; jsval bmapval, rval; JSBool ok; JSRuntime *rt; /* * Reuse args_enumerate here to reflect fp's actual arguments as indexed * elements of argsobj. Do this first, before clearing and freeing the * deleted argument slot bitmap, because args_enumerate depends on that. */ argsobj = fp->argsobj; ok = args_enumerate(cx, argsobj); /* * Now clear the deleted argument number bitmap slot and free the bitmap, * if one was actually created due to 'delete arguments[0]' or similar. */ (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval); if (!JSVAL_IS_VOID(bmapval)) { JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID); if (fp->argc > JSVAL_INT_BITS) JS_free(cx, JSVAL_TO_PRIVATE(bmapval)); } /* * Now get the prototype properties so we snapshot fp->fun and fp->argc * before fp goes away. */ rt = cx->runtime; ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom), &rval); ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom), &rval); ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom), &rval); ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom), &rval); /* * Clear the private pointer to fp, which is about to go away (js_Invoke). * Do this last because the args_enumerate and js_GetProperty calls above * need to follow the private slot to find fp. */ ok &= JS_SetPrivate(cx, argsobj, NULL); fp->argsobj = NULL; return ok;}static JSBoolargs_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ jsint slot; JSStackFrame *fp; if (!JSVAL_IS_INT(id)) return JS_TRUE; fp = (JSStackFrame *) JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); if (!fp) return JS_TRUE; JS_ASSERT(fp->argsobj); slot = JSVAL_TO_INT(id); switch (slot) { case ARGS_CALLEE: case ARGS_LENGTH: SET_OVERRIDE_BIT(fp, slot); break; default: if ((uintN)slot < fp->argc && !MarkArgDeleted(cx, fp, slot)) return JS_FALSE; break; } return JS_TRUE;}static JSBoolargs_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ jsint slot; JSStackFrame *fp; if (!JSVAL_IS_INT(id)) return JS_TRUE; fp = (JSStackFrame *) JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); if (!fp) return JS_TRUE; JS_ASSERT(fp->argsobj); slot = JSVAL_TO_INT(id); switch (slot) { case ARGS_CALLEE: if (!TEST_OVERRIDE_BIT(fp, slot)) *vp = fp->argv ? fp->argv[-2] : OBJECT_TO_JSVAL(fp->fun->object); break; case ARGS_LENGTH: if (!TEST_OVERRIDE_BIT(fp, slot)) *vp = INT_TO_JSVAL((jsint)fp->argc); break; default: if ((uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) *vp = fp->argv[slot]; break; } return JS_TRUE;}static JSBoolargs_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ JSStackFrame *fp; jsint slot; if (!JSVAL_IS_INT(id)) return JS_TRUE; fp = (JSStackFrame *) JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); if (!fp) return JS_TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -