jsinterp.c
来自「java script test programing source code」· C语言 代码 · 共 1,863 行 · 第 1/5 页
C
1,863 行
/* Try to avoid another header if we can piggyback on the last segment. */ a = cx->stackPool.current; sh = cx->stackHeaders; if (sh && JS_STACK_SEGMENT(sh) + sh->nslots == sp) { /* Extend the last stack segment, give back the 2 header slots. */ sh->nslots += nslots; a->avail -= 2 * sizeof(jsval); } else { /* * Need a new stack segment, so we must initialize unused slots in the * current frame. See js_GC, just before marking the "operand" jsvals, * where we scan from fp->spbase to fp->sp or through fp->script->depth * (whichever covers fewer slots). */ fp = cx->fp; if (fp && fp->script && fp->spbase) {#ifdef DEBUG jsuword depthdiff = fp->script->depth * sizeof(jsval); JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <= depthdiff); JS_ASSERT(JS_UPTRDIFF(*markp, fp->spbase) >= depthdiff);#endif end = fp->spbase + fp->script->depth; for (vp = fp->sp; vp < end; vp++) *vp = JSVAL_VOID; } /* Allocate and push a stack segment header from the 2 extra slots. */ sh = (JSStackHeader *)sp; sh->nslots = nslots; sh->down = cx->stackHeaders; cx->stackHeaders = sh; sp += 2; } /* * Store JSVAL_NULL using memset, to let compilers optimize as they see * fit, in case a caller allocates and pushes GC-things one by one, which * could nest a last-ditch GC that will scan this segment. */ memset(sp, 0, nslots * sizeof(jsval)); return sp;}JS_FRIEND_API(void)js_FreeStack(JSContext *cx, void *mark){ JSStackHeader *sh; jsuword slotdiff; /* Check for zero nslots allocation special case. */ if (!mark) return; /* We can assert because js_FreeStack always balances js_AllocStack. */ sh = cx->stackHeaders; JS_ASSERT(sh); /* If mark is in the current segment, reduce sh->nslots, else pop sh. */ slotdiff = JS_UPTRDIFF(mark, JS_STACK_SEGMENT(sh)) / sizeof(jsval); if (slotdiff < (jsuword)sh->nslots) sh->nslots = slotdiff; else cx->stackHeaders = sh->down; /* Release the stackPool space allocated since mark was set. */ JS_ARENA_RELEASE(&cx->stackPool, mark);}JSBooljs_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ return JS_TRUE;}JSBooljs_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ return JS_TRUE;}JSBooljs_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ return JS_TRUE;}JSBooljs_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp){ return JS_TRUE;}JSObject *js_GetScopeChain(JSContext *cx, JSStackFrame *fp){ JSObject *obj, *cursor, *clonedChild, *parent; JSTempValueRooter tvr; obj = fp->blockChain; if (!obj) { /* * Don't force a call object for a lightweight function call, but do * insist that there is a call object for a heavyweight function call. */ JS_ASSERT(!fp->fun || !(fp->fun->flags & JSFUN_HEAVYWEIGHT) || fp->callobj); JS_ASSERT(fp->scopeChain); return fp->scopeChain; } /* * We have one or more lexical scopes to reflect into fp->scopeChain, so * make sure there's a call object at the current head of the scope chain, * if this frame is a call frame. */ if (fp->fun && !fp->callobj) { JS_ASSERT(OBJ_GET_CLASS(cx, fp->scopeChain) != &js_BlockClass || JS_GetPrivate(cx, fp->scopeChain) != fp); if (!js_GetCallObject(cx, fp, fp->scopeChain)) return NULL; } /* * Clone the block chain. To avoid recursive cloning we set the parent of * the cloned child after we clone the parent. In the following loop when * clonedChild is null it indicates the first iteration when no special GC * rooting is necessary. On the second and the following iterations we * have to protect cloned so far chain against the GC during cloning of * the cursor object. */ cursor = obj; clonedChild = NULL; for (;;) { parent = OBJ_GET_PARENT(cx, cursor); /* * We pass fp->scopeChain and not null even if we override the parent * slot later as null triggers useless calculations of slot's value in * js_NewObject that js_CloneBlockObject calls. */ cursor = js_CloneBlockObject(cx, cursor, fp->scopeChain, fp); if (!cursor) { if (clonedChild) JS_POP_TEMP_ROOT(cx, &tvr); return NULL; } if (!clonedChild) { /* * The first iteration. Check if other follow and root obj if so * to protect the whole cloned chain against GC. */ obj = cursor; if (!parent) break; JS_PUSH_TEMP_ROOT_OBJECT(cx, obj, &tvr); } else { /* * Avoid OBJ_SET_PARENT overhead as clonedChild cannot escape to * other threads. */ clonedChild->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(cursor); if (!parent) { JS_ASSERT(tvr.u.value == OBJECT_TO_JSVAL(obj)); JS_POP_TEMP_ROOT(cx, &tvr); break; } } clonedChild = cursor; cursor = parent; } fp->flags |= JSFRAME_POP_BLOCKS; fp->scopeChain = obj; fp->blockChain = NULL; return obj;}/* * Walk the scope chain looking for block scopes whose locals need to be * copied from stack slots into object slots before fp goes away. */static JSBoolPutBlockObjects(JSContext *cx, JSStackFrame *fp){ JSBool ok; JSObject *obj; ok = JS_TRUE; for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) { if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) { if (JS_GetPrivate(cx, obj) != fp) break; ok &= js_PutBlockObject(cx, obj); } } return ok;}JSObject *js_ComputeThis(JSContext *cx, JSObject *thisp, jsval *argv){ if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) { /* Some objects (e.g., With) delegate 'this' to another object. */ thisp = OBJ_THIS_OBJECT(cx, thisp); if (!thisp) return NULL; } 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; /* 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 NULL; if (JSVAL_IS_VOID(v)) v = OBJ_GET_SLOT(cx, thisp, JSSLOT_PARENT); if (JSVAL_IS_NULL(v)) break; thisp = JSVAL_TO_OBJECT(v); } } } argv[-1] = OBJECT_TO_JSVAL(thisp); return thisp;}#if JS_HAS_NO_SUCH_METHODstatic JSBoolNoSuchMethod(JSContext *cx, JSStackFrame *fp, jsval *vp, uint32 flags, uintN argc){ JSObject *thisp, *argsobj; jsval *sp, roots[3]; JSTempValueRooter tvr; jsid id; JSBool ok; jsbytecode *pc; jsatomid atomIndex; /* * 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. */ JS_ASSERT(JSVAL_IS_PRIMITIVE(vp[0])); RESTORE_SP(fp); if (JSVAL_IS_OBJECT(vp[1])) { thisp = JSVAL_TO_OBJECT(vp[1]); } else { PRIMITIVE_TO_OBJECT(cx, vp[1], thisp); if (!thisp) return JS_FALSE; vp[1] = OBJECT_TO_JSVAL(thisp); } thisp = js_ComputeThis(cx, thisp, vp + 2); if (!thisp) return JS_FALSE; vp[1] = OBJECT_TO_JSVAL(thisp); /* From here on, control must flow through label out: to return. */ memset(roots, 0, sizeof roots); JS_PUSH_TEMP_ROOT(cx, JS_ARRAY_LENGTH(roots), roots, &tvr); id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);#if JS_HAS_XML_SUPPORT if (OBJECT_IS_XML(cx, thisp)) { JSXMLObjectOps *ops; ops = (JSXMLObjectOps *) thisp->map->ops; thisp = ops->getMethod(cx, thisp, id, &roots[2]); if (!thisp) { ok = JS_FALSE; goto out; } vp[1] = OBJECT_TO_JSVAL(thisp); } else#endif { ok = OBJ_GET_PROPERTY(cx, thisp, id, &roots[2]); if (!ok) goto out; } if (JSVAL_IS_PRIMITIVE(roots[2])) goto not_function; pc = (jsbytecode *) vp[-(intN)fp->script->depth]; switch ((JSOp) *pc) { case JSOP_NAME: case JSOP_GETPROP:#if JS_HAS_XML_SUPPORT case JSOP_GETMETHOD:#endif atomIndex = GET_ATOM_INDEX(pc); roots[0] = ATOM_KEY(js_GetAtom(cx, &fp->script->atomMap, atomIndex)); argsobj = js_NewArrayObject(cx, argc, vp + 2); if (!argsobj) { ok = JS_FALSE; goto out; } roots[1] = OBJECT_TO_JSVAL(argsobj); ok = js_InternalInvoke(cx, thisp, roots[2], flags | JSINVOKE_INTERNAL, 2, roots, &vp[0]); break; default: goto not_function; } out: JS_POP_TEMP_ROOT(cx, &tvr); return ok; not_function: js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_FUNFLAGS); ok = JS_FALSE; goto out;}#endif /* JS_HAS_NO_SUCH_METHOD */#ifdef DUMP_CALL_TABLE#include "jsclist.h"#include "jshash.h"#include "jsdtoa.h"typedef struct CallKey { jsval callee; /* callee value */ const char *filename; /* function filename or null */ uintN lineno; /* function lineno or 0 */} CallKey;/* Compensate for typeof null == "object" brain damage. */#define JSTYPE_NULL JSTYPE_LIMIT#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))#define TYPENAME(t) (((t) == JSTYPE_NULL) ? js_null_str : js_type_str[t])#define NTYPEHIST (JSTYPE_LIMIT + 1)typedef struct CallValue { uint32 total; /* total call count */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?