📄 jsfun.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** 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"/* 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)))#if JS_HAS_ARGS_OBJECTJSBooljs_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, (jsid) cx->runtime->atomState.argumentsAtom, vp); } argsobj = js_GetArgsObject(cx, fp); if (!argsobj) return JS_FALSE; *vp = OBJECT_TO_JSVAL(argsobj); return JS_TRUE;}#define MAXARGS(fp) ((fp)->fun ? JS_MAX((fp)->argc, (fp)->fun->nargs) \ : (fp)->argc)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 = MAXARGS(fp); 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 (MAXARGS(fp) <= 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, (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 (JSVAL_IS_INT(id)) { slot = (uintN) JSVAL_TO_INT(id); if (slot < MAXARGS(fp)) { if (fp->argsobj && ArgWasDeleted(cx, fp, slot)) return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp); *vp = fp->argv[slot]; } } else { if (id == (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; /* 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->newborn[GCX_OBJECT] = NULL; return NULL; } 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 (MAXARGS(fp) > 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, (jsid)rt->atomState.calleeAtom, &rval); ok &= js_SetProperty(cx, argsobj, (jsid)rt->atomState.calleeAtom, &rval); ok &= js_GetProperty(cx, argsobj, (jsid)rt->atomState.lengthAtom, &rval); ok &= js_SetProperty(cx, argsobj, (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 < MAXARGS(fp) && !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 < MAXARGS(fp) && !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; 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 < MAXARGS(fp) && !ArgWasDeleted(cx, fp, slot)) fp->argv[slot] = *vp; break; } return JS_TRUE;}static JSBoolargs_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags, JSObject **objp){ JSStackFrame *fp; uintN slot; JSString *str; JSAtom *atom; intN tinyid; jsval value; *objp = NULL; fp = (JSStackFrame *) JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL); if (!fp) return JS_TRUE; JS_ASSERT(fp->argsobj); if (JSVAL_IS_INT(id)) { slot = JSVAL_TO_INT(id); if (slot < MAXARGS(fp) && !ArgWasDeleted(cx, fp, slot)) { /* XXX ECMA specs DontEnum, contrary to other array-like objects */ if (!js_DefineProperty(cx, obj, (jsid) id, fp->argv[slot], args_getProperty, args_setProperty, JSVERSION_IS_ECMA(cx->version) ? 0 : JSPROP_ENUMERATE, NULL)) { return JS_FALSE; } *objp = obj; } } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -