jsinterp.c
来自「java script test programing source code」· C语言 代码 · 共 1,863 行 · 第 1/5 页
C
1,863 行
* parameters. */ if (JSVAL_IS_PRIMITIVE(v)) {#if JS_HAS_NO_SUCH_METHOD if (fp->script && !(flags & JSINVOKE_INTERNAL)) { ok = NoSuchMethod(cx, fp, vp, flags, argc); if (ok) frame.rval = *vp; goto out2; }#endif goto bad; } /* Load thisv after potentially calling NoSuchMethod, which may set it. */ thisv = vp[1]; 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 this makes no sense -- why convert to function if clasp->call? * XXX better to call that hook without converting * XXX the only thing that needs fixing is liveconnect * * 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 ((ops == &js_ObjectOps) ? clasp->call : ops->call) { ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v); if (!ok) goto out2; if (VALUE_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; nslots = nvars = 0; /* Try a call or construct native object op. */ native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call; if (!native) goto bad; if (JSVAL_IS_OBJECT(thisv)) { thisp = JSVAL_TO_OBJECT(thisv); } else { PRIMITIVE_TO_OBJECT(cx, thisv, thisp); if (!thisp) goto out2; vp[1] = thisv = OBJECT_TO_JSVAL(thisp); } } else {have_fun: /* Get private data and set derived locals from it. */ fun = (JSFunction *) JS_GetPrivate(cx, funobj); nslots = (fun->nargs > argc) ? fun->nargs - argc : 0; if (FUN_INTERPRETED(fun)) { native = NULL; script = fun->u.i.script; nvars = fun->u.i.nvars; } else { native = fun->u.n.native; script = NULL; nvars = 0; nslots += fun->u.n.extra; } if (JSFUN_BOUND_METHOD_TEST(fun->flags)) { /* Handle bound method special case. */ thisp = parent; } else if (JSVAL_IS_OBJECT(thisv)) { thisp = JSVAL_TO_OBJECT(thisv); } else { uintN thispflags = JSFUN_THISP_FLAGS(fun->flags); JS_ASSERT(!(flags & JSINVOKE_CONSTRUCT)); if (JSVAL_IS_STRING(thisv)) { if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_STRING)) { thisp = (JSObject *) thisv; goto init_frame; } thisp = js_StringToObject(cx, JSVAL_TO_STRING(thisv)); } else if (JSVAL_IS_INT(thisv)) { if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_NUMBER)) { thisp = (JSObject *) thisv; goto init_frame; } thisp = js_NumberToObject(cx, (jsdouble)JSVAL_TO_INT(thisv)); } else if (JSVAL_IS_DOUBLE(thisv)) { if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_NUMBER)) { thisp = (JSObject *) thisv; goto init_frame; } thisp = js_NumberToObject(cx, *JSVAL_TO_DOUBLE(thisv)); } else { JS_ASSERT(JSVAL_IS_BOOLEAN(thisv)); if (JSFUN_THISP_TEST(thispflags, JSFUN_THISP_BOOLEAN)) { thisp = (JSObject *) thisv; goto init_frame; } thisp = js_BooleanToObject(cx, JSVAL_TO_BOOLEAN(thisv)); } if (!thisp) { ok = JS_FALSE; goto out2; } goto init_frame; } } if (flags & JSINVOKE_CONSTRUCT) { /* Default return value for a constructor is the new object. */ frame.rval = OBJECT_TO_JSVAL(thisp); } else { thisp = js_ComputeThis(cx, thisp, vp + 2); if (!thisp) { ok = JS_FALSE; goto out2; } } init_frame: /* Initialize the rest of frame, except for sp (set by SAVE_SP later). */ frame.thisp = thisp; frame.varobj = NULL; frame.callobj = frame.argsobj = NULL; frame.script = script; 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.sharpDepth = 0; frame.sharpArray = NULL; frame.flags = flags; frame.dormantNext = NULL; frame.xmlNamespace = NULL; frame.blockChain = NULL; /* 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 argument slots required by the function. */ if (nslots) { /* All arguments must be contiguous, so we may have to copy actuals. */ nalloc = nslots; limit = (jsval *) cx->stackPool.current->limit; JS_ASSERT((jsval *) cx->stackPool.current->base <= sp && sp <= 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. */ JS_ASSERT((jsval *)mark >= sp); surplus = (jsval *)mark - sp; nalloc -= surplus; } /* Check whether we have enough space in the caller's frame. */ if ((intN)nalloc > 0) { /* Need space for actuals plus missing formals minus surplus. */ newsp = js_AllocRawStack(cx, 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 == 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. */ do { PUSH(JSVAL_VOID); } while (--nslots != 0); } JS_ASSERT(nslots == 0); /* Now allocate stack space for local variables. */ if (nvars) { JS_ASSERT((jsval *)cx->stackPool.current->avail >= frame.vars); surplus = (jsval *)cx->stackPool.current->avail - frame.vars; if (surplus < nvars) { newsp = js_AllocRawStack(cx, nvars, 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. */ do { PUSH(JSVAL_VOID); } while (--nvars != 0); } JS_ASSERT(nvars == 0); /* 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) {#ifdef DEBUG_NOT_THROWING JSBool alreadyThrowing = cx->throwing;#endif#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);#ifdef DEBUG_NOT_THROWING if (ok && !alreadyThrowing) ASSERT_NOT_THROWING(cx);#endif } else if (script) {#ifdef DUMP_CALL_TABLE LogCall(cx, *vp, argc, frame.argv);#endif /* Use parent scope so js_GetCallObject can find the right "Call". */ frame.scopeChain = parent; if (JSFUN_HEAVYWEIGHT_TEST(fun->flags)) { /* Scope with a call object parented by the callee's parent. */ if (!js_GetCallObject(cx, &frame, parent)) { ok = JS_FALSE; goto out; } } ok = js_Interpret(cx, script->code, &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 frame has a call object, sync values and clear back-pointer. */ if (frame.callobj) ok &= js_PutCallObject(cx, &frame); /* If frame has an arguments object, sync values and clear back-pointer. */ if (frame.argsobj) ok &= js_PutArgsObject(cx, &frame); /* 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_FUNFLAGS); 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]); SAVE_SP(fp); ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL); if (ok) { RESTORE_SP(fp); /* * Store *rval in the a scoped local root if a scope is open, else in * the lastInternalResult pigeon-hole GC root, solely so users of * js_InternalInvoke and its direct and indirect (js_ValueToString for * example) callers do not need to manage roots for local, temporary * references to such results. */ *rval = POP_OPND(); if (JSVAL_IS_GCTHING(*rval)) { if (cx->localRootStack) { if (js_PushLocalRoot(cx, cx->localRootStack, *rval) < 0) ok = JS_FALSE; } else { cx->weakRoots.lastInternalResult = *rval; } } } js_FreeStack(cx, mark);out:
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?