📄 jsinterp.c
字号:
sp = vp + 4; if (argc < 2) { a = cx->stackPool.current; if ((jsuword)sp > a->limit) { /* * Arguments must be contiguous, and must include argv[-1] * and argv[-2], so allocate more stack, advance sp, and * set newsp[1] to thisp (vp[1]). The other argv elements * will be set below, using negative indexing from sp. */ newsp = js_AllocRawStack(cx, 4, NULL); if (!newsp) { ok = JS_FALSE; goto out2; } newsp[1] = OBJECT_TO_JSVAL(thisp); sp = newsp + 4; } else if ((jsuword)sp > a->avail) { /* * Inline, optimized version of JS_ARENA_ALLOCATE to claim * the small number of words not already allocated as part * of the caller's operand stack. */ JS_ArenaCountAllocation(pool, (jsuword)sp - a->avail); a->avail = (jsuword)sp; } } sp[-4] = v; JS_ASSERT(sp[-3] == OBJECT_TO_JSVAL(thisp)); sp[-2] = ATOM_KEY(atom); sp[-1] = OBJECT_TO_JSVAL(argsobj); fp->sp = sp; argc = 2; break; default: goto bad; }#else goto bad;#endif } funobj = JSVAL_TO_OBJECT(v); parent = OBJ_GET_PARENT(cx, funobj); clasp = OBJ_GET_CLASS(cx, funobj); if (clasp != &js_FunctionClass) { /* Function is inlined, all other classes use object ops. */ ops = funobj->map->ops; /* * XXX * Try converting to function, for closure and API compatibility. * We attempt the conversion under all circumstances for 1.2, but * only if there is a call op defined otherwise. */ if (cx->version == JSVERSION_1_2 || ((ops == &js_ObjectOps) ? clasp->call : ops->call)) { ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v); if (!ok) goto out2; if (JSVAL_IS_FUNCTION(cx, v)) { /* Make vp refer to funobj to keep it available as argv[-2]. */ *vp = v; funobj = JSVAL_TO_OBJECT(v); parent = OBJ_GET_PARENT(cx, funobj); goto have_fun; } } fun = NULL; script = NULL; swf = NULL; minargs = nvars = 0; /* Try a call or construct native object op. */ native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call; if (!native) goto bad; } else {have_fun: /* Get private data and set derived locals from it. */ fun = (JSFunction *) JS_GetPrivate(cx, funobj); native = fun->native; script = fun->script; swf = fun->swf; minargs = fun->nargs + fun->extra; nvars = fun->nvars; /* Handle bound method special case. */ if (fun->flags & JSFUN_BOUND_METHOD) thisp = parent; } /* Initialize the rest of frame, except for sp (set by SAVE_SP later). */ frame.varobj = NULL; frame.callobj = frame.argsobj = NULL; frame.script = script; frame.swf = swf; frame.fun = fun; frame.argc = argc; frame.argv = sp - argc; frame.nvars = nvars; frame.vars = sp; frame.down = fp; frame.annotation = NULL; frame.scopeChain = NULL; /* set below for real, after cx->fp is set */ frame.pc = NULL; frame.spbase = NULL; frame.spend = NULL; frame.sharpDepth = 0; frame.sharpArray = NULL; frame.dormantNext = NULL; frame.objAtomMap = NULL; frame.constant_pool = NULL; /* Compute the 'this' parameter and store it in frame as frame.thisp. */ ok = ComputeThis(cx, thisp, &frame); if (!ok) goto out2; /* From here on, control must flow through label out: to return. */ cx->fp = &frame; /* Init these now in case we goto out before first hook call. */ hook = cx->runtime->callHook; hookData = NULL; /* Check for missing arguments expected by the function. */ nslots = (intN)((argc < minargs) ? minargs - argc : 0); if (nslots) { /* All arguments must be contiguous, so we may have to copy actuals. */ nalloc = nslots; limit = (jsval *) cx->stackPool.current->limit; if (sp + nslots > limit) { /* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */ nalloc += 2 + argc; } else { /* Take advantage of surplus slots in the caller's frame depth. */ surplus = (jsval *)mark - sp; JS_ASSERT(surplus >= 0); nalloc -= surplus; } /* Check whether we have enough space in the caller's frame. */ if (nalloc > 0) { /* Need space for actuals plus missing formals minus surplus. */ newsp = js_AllocRawStack(cx, (uintN)nalloc, NULL); if (!newsp) { ok = JS_FALSE; goto out; } /* If we couldn't allocate contiguous args, copy actuals now. */ if (newsp != mark) { JS_ASSERT(sp + nslots > limit); JS_ASSERT(2 + argc + nslots == (uintN)nalloc); *newsp++ = vp[0]; *newsp++ = vp[1]; if (argc) memcpy(newsp, frame.argv, argc * sizeof(jsval)); frame.argv = newsp; sp = frame.vars = newsp + argc; } } /* Advance frame.vars to make room for the missing args. */ frame.vars += nslots; /* Push void to initialize missing args. */ while (--nslots >= 0) PUSH(JSVAL_VOID); } /* Now allocate stack space for local variables. */ nslots = (intN)frame.nvars; if (nslots) { surplus = (intN)((jsval *)cx->stackPool.current->avail - frame.vars); if (surplus < nslots) { newsp = js_AllocRawStack(cx, (uintN)nslots, NULL); if (!newsp) { ok = JS_FALSE; goto out; } if (newsp != sp) { /* NB: Discontinuity between argv and vars. */ sp = frame.vars = newsp; } } /* Push void to initialize local variables. */ while (--nslots >= 0) PUSH(JSVAL_VOID); } /* Store the current sp in frame before calling fun. */ SAVE_SP(&frame); /* call the hook if present */ if (hook && (native || script)) hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->callHookData); /* Call the function, either a native method or an interpreted script. */ if (native) {#if JS_HAS_LVALUE_RETURN /* Set by JS_SetCallReturnValue2, used to return reference types. */ cx->rval2set = JS_FALSE;#endif /* If native, use caller varobj and scopeChain for eval. */ frame.varobj = fp->varobj; frame.scopeChain = fp->scopeChain; ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval); JS_RUNTIME_METER(cx->runtime, nativeCalls); } else if (script) { /* Use parent scope so js_GetCallObject can find the right "Call". */ frame.scopeChain = parent; if (fun->flags & JSFUN_HEAVYWEIGHT) {#if JS_HAS_CALL_OBJECT /* Scope with a call object parented by the callee's parent. */ if (!js_GetCallObject(cx, &frame, parent)) { ok = JS_FALSE; goto out; }#else /* Bad old code used the function as a proxy for all calls to it. */ frame.scopeChain = funobj;#endif } ok = js_Interpret(cx, &v); } else if (swf) { if (!js_GetCallObject(cx, &frame, parent)) { ok = JS_FALSE; goto out; } ok = swfdec_script_interpret(swf, cx, &v); } else { /* fun might be onerror trying to report a syntax error in itself. */ frame.scopeChain = NULL; ok = JS_TRUE; }out: if (hookData) { hook = cx->runtime->callHook; if (hook) hook(cx, &frame, JS_FALSE, &ok, hookData); }#if JS_HAS_CALL_OBJECT /* If frame has a call object, sync values and clear back-pointer. */ if (frame.callobj) ok &= js_PutCallObject(cx, &frame);#endif#if JS_HAS_ARGS_OBJECT /* If frame has an arguments object, sync values and clear back-pointer. */ if (frame.argsobj) ok &= js_PutArgsObject(cx, &frame);#endif /* Restore cx->fp now that we're done releasing frame objects. */ cx->fp = fp;out2: /* Pop everything we may have allocated off the stack. */ JS_ARENA_RELEASE(&cx->stackPool, mark); /* Store the return value and restore sp just above it. */ *vp = frame.rval; fp->sp = vp + 1; /* * Store the location of the JSOP_CALL or JSOP_EVAL that generated the * return value, but only if this is an external (compiled from script * source) call that has stack budget for the generating pc. */ if (fp->script && !(flags & JSINVOKE_INTERNAL)) vp[-(intN)fp->script->depth] = (jsval)fp->pc; return ok;bad: js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_CONSTRUCT); ok = JS_FALSE; goto out2;}JSBooljs_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags, uintN argc, jsval *argv, jsval *rval){ JSStackFrame *fp, *oldfp, frame; jsval *oldsp, *sp; void *mark; uintN i; JSBool ok; fp = oldfp = cx->fp; if (!fp) { memset(&frame, 0, sizeof frame); cx->fp = fp = &frame; } oldsp = fp->sp; sp = js_AllocStack(cx, 2 + argc, &mark); if (!sp) { ok = JS_FALSE; goto out; } PUSH(fval); PUSH(OBJECT_TO_JSVAL(obj)); for (i = 0; i < argc; i++) PUSH(argv[i]); fp->sp = sp; ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL); if (ok) { RESTORE_SP(fp); *rval = POP_OPND(); } js_FreeStack(cx, mark);out: fp->sp = oldsp; if (oldfp != fp) cx->fp = oldfp; return ok;}JSBooljs_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval, JSAccessMode mode, uintN argc, jsval *argv, jsval *rval){ /* * Check general (not object-ops/class-specific) access from the running * script to obj.id only if id has a scripted getter or setter that we're * about to invoke. If we don't check this case, nothing else will -- no * other native code has the chance to check. * * Contrast this non-native (scripted) case with native getter and setter * accesses, where the native itself must do an access check, if security * policies requires it. We make a checkAccess or checkObjectAccess call * back to the embedding program only in those cases where we're not going * to call an embedding-defined native function, getter, setter, or class * hook anyway. Where we do call such a native, there's no need for the * engine to impose a separate access check callback on all embeddings -- * many embeddings have no security policy at all. */ JS_ASSERT(mode == JSACC_READ || mode == JSACC_WRITE); if (cx->runtime->checkObjectAccess && JSVAL_IS_FUNCTION(cx, fval) && ((JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval)))->script && !cx->runtime->checkObjectAccess(cx, obj, ID_TO_VALUE(id), mode, &fval)) { return JS_FALSE; } return js_InternalCall(cx, obj, fval, argc, argv, rval);}JSBooljs_Execute(JSContext *cx, JSObject *chain, JSScript *script, JSStackFrame *down, uintN special, jsval *result){ JSStackFrame *oldfp, frame; JSObject *obj, *tmp; JSBool ok; JSInterpreterHook hook; void *hookData;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -