📄 jsinterp.c
字号:
hook = cx->runtime->executeHook; hookData = NULL; oldfp = cx->fp; frame.callobj = frame.argsobj = NULL; frame.script = script; if (down) { /* Propagate arg/var state for eval and the debugger API. */ frame.varobj = down->varobj; frame.fun = down->fun; frame.thisp = down->thisp; frame.argc = down->argc; frame.argv = down->argv; frame.nvars = down->nvars; frame.vars = down->vars; frame.annotation = down->annotation; frame.sharpArray = down->sharpArray; } else { obj = chain; if (cx->options & JSOPTION_VAROBJFIX) { while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL) obj = tmp; } frame.varobj = obj; frame.fun = NULL; frame.thisp = chain; frame.argc = frame.nvars = 0; frame.argv = frame.vars = NULL; frame.annotation = NULL; frame.sharpArray = NULL; } frame.rval = JSVAL_VOID; frame.down = down; frame.scopeChain = chain; frame.pc = NULL; frame.sp = oldfp ? oldfp->sp : NULL; frame.spbase = NULL; frame.spend = NULL; frame.sharpDepth = 0; frame.flags = special; frame.dormantNext = NULL; frame.objAtomMap = NULL; frame.constant_pool = NULL; /* * Here we wrap the call to js_Interpret with code to (conditionally) * save and restore the old stack frame chain into a chain of 'dormant' * frame chains. Since we are replacing cx->fp, we were running into * the problem that if GC was called under this frame, some of the GC * things associated with the old frame chain (available here only in * the C variable 'oldfp') were not rooted and were being collected. * * So, now we preserve the links to these 'dormant' frame chains in cx * before calling js_Interpret and cleanup afterwards. The GC walks * these dormant chains and marks objects in the same way that it marks * objects in the primary cx->fp chain. */ if (oldfp && oldfp != down) { JS_ASSERT(!oldfp->dormantNext); oldfp->dormantNext = cx->dormantFrameChain; cx->dormantFrameChain = oldfp; } cx->fp = &frame; if (hook) hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->executeHookData); /* * Use frame.rval, not result, so the last result stays rooted across any * GC activations nested within this js_Interpret. */ ok = js_Interpret(cx, &frame.rval); *result = frame.rval; if (hookData) { hook = cx->runtime->executeHook; if (hook) hook(cx, &frame, JS_FALSE, &ok, hookData); } cx->fp = oldfp; if (oldfp && oldfp != down) { JS_ASSERT(cx->dormantFrameChain == oldfp); cx->dormantFrameChain = oldfp->dormantNext; oldfp->dormantNext = NULL; } return ok;}#if JS_HAS_EXPORT_IMPORT/* * If id is JSVAL_VOID, import all exported properties from obj. */static JSBoolImportProperty(JSContext *cx, JSObject *obj, jsid id){ JSBool ok; JSIdArray *ida; JSProperty *prop; JSObject *obj2, *target, *funobj, *closure; JSString *str; uintN attrs; jsuint i; jsval value; if (JSVAL_IS_VOID(id)) { ida = JS_Enumerate(cx, obj); if (!ida) return JS_FALSE; ok = JS_TRUE; if (ida->length == 0) goto out; } else { ida = NULL; if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) return JS_FALSE; if (!prop) { str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, ID_TO_VALUE(id), NULL); if (str) js_ReportIsNotDefined(cx, JS_GetStringBytes(str)); return JS_FALSE; } ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs); OBJ_DROP_PROPERTY(cx, obj2, prop); if (!ok) return JS_FALSE; if (!(attrs & JSPROP_EXPORTED)) { str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK, ID_TO_VALUE(id), NULL); if (str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_EXPORTED, JS_GetStringBytes(str)); } return JS_FALSE; } } target = cx->fp->varobj; i = 0; do { if (ida) { id = ida->vector[i]; ok = OBJ_GET_ATTRIBUTES(cx, obj, id, NULL, &attrs); if (!ok) goto out; if (!(attrs & JSPROP_EXPORTED)) continue; } ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_IMPORT, &value, &attrs); if (!ok) goto out; if (JSVAL_IS_FUNCTION(cx, value)) { funobj = JSVAL_TO_OBJECT(value); closure = js_CloneFunctionObject(cx, funobj, obj); if (!closure) { ok = JS_FALSE; goto out; } value = OBJECT_TO_JSVAL(closure); } /* * Handle the case of importing a property that refers to a local * variable or formal parameter of a function activation. These * properties are accessed by opcodes using stack slot numbers * generated by the compiler rather than runtime name-lookup. These * local references, therefore, bypass the normal scope chain lookup. * So, instead of defining a new property in the activation object, * modify the existing value in the stack slot. */ if (OBJ_GET_CLASS(cx, target) == &js_CallClass) { ok = OBJ_LOOKUP_PROPERTY(cx, target, id, &obj2, &prop); if (!ok) goto out; } else { prop = NULL; } if (prop && target == obj2) { ok = OBJ_SET_PROPERTY(cx, target, id, &value); } else { ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL, attrs & ~JSPROP_EXPORTED, NULL); } if (prop) OBJ_DROP_PROPERTY(cx, obj2, prop); if (!ok) goto out; } while (ida && ++i < ida->length);out: if (ida) JS_DestroyIdArray(cx, ida); return ok;}#endif /* JS_HAS_EXPORT_IMPORT */JSBooljs_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs, JSBool *foundp){ JSObject *obj2; JSProperty *prop; JSBool ok; uintN oldAttrs, report; JSBool isFunction; jsval value; const char *type, *name; if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop)) return JS_FALSE; *foundp = (prop != NULL); if (!prop) return JS_TRUE; ok = OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs); OBJ_DROP_PROPERTY(cx, obj2, prop); if (!ok) return JS_FALSE; /* If either property is readonly, we have an error. */ report = ((oldAttrs | attrs) & JSPROP_READONLY) ? JSREPORT_ERROR : JSREPORT_WARNING | JSREPORT_STRICT; if (report != JSREPORT_ERROR) { /* * Allow redeclaration of variables and functions, but insist that the * new value is not a getter if the old value was, ditto for setters -- * unless prop is impermanent (in which case anyone could delete it and * redefine it, willy-nilly). */ if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER))) return JS_TRUE; if ((~(oldAttrs ^ attrs) & (JSPROP_GETTER | JSPROP_SETTER)) == 0) return JS_TRUE; if (!(oldAttrs & JSPROP_PERMANENT)) return JS_TRUE; report = JSREPORT_ERROR; } isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0; if (!isFunction) { if (!OBJ_GET_PROPERTY(cx, obj, id, &value)) return JS_FALSE; isFunction = JSVAL_IS_FUNCTION(cx, value); } type = (oldAttrs & attrs & JSPROP_GETTER) ? js_getter_str : (oldAttrs & attrs & JSPROP_SETTER) ? js_setter_str : (oldAttrs & JSPROP_READONLY) ? js_const_str : isFunction ? js_function_str : js_var_str; name = js_AtomToPrintableString(cx, (JSAtom *)id); if (!name) return JS_FALSE; return JS_ReportErrorFlagsAndNumber(cx, report, js_GetErrorMessage, NULL, JSMSG_REDECLARED_VAR, type, name);}#ifndef MAX_INTERP_LEVEL#if defined(XP_OS2)#define MAX_INTERP_LEVEL 250#elif defined _MSC_VER && _MSC_VER <= 800#define MAX_INTERP_LEVEL 30#else#define MAX_INTERP_LEVEL 1000#endif#endif#define MAX_INLINE_CALL_COUNT 1000JSBooljs_Interpret(JSContext *cx, jsval *result){ JSRuntime *rt; JSStackFrame *fp; JSScript *script; uintN inlineCallCount; JSObject *obj, *obj2, *proto, *parent; JSVersion currentVersion, originalVersion; JSBranchCallback onbranch; JSBool ok, cond; JSTrapHandler interruptHandler; jsint depth, len; jsval *sp = NULL, *newsp; void *mark; jsbytecode *pc, *pc2, *endpc; JSOp op, op2; const JSCodeSpec *cs = NULL; JSAtom *atom; uintN argc, slot, attrs; jsval *vp, lval, rval, ltmp, rtmp; jsid id = 0; JSObject *withobj, *origobj, *propobj; jsval iter_state; JSProperty *prop; JSScopeProperty *sprop; JSString *str, *str2; jsint i, j; jsdouble d, d2; const JSClass *clasp, *funclasp; JSFunction *fun; JSType type;#ifdef DEBUG FILE *tracefp = NULL;#endif#if JS_HAS_EXPORT_IMPORT JSIdArray *ida;#endif#if JS_HAS_SWITCH_STATEMENT jsint low, high, off, npairs; JSBool match;#endif#if JS_HAS_GETTER_SETTER JSPropertyOp getter, setter;#endif int stackDummy; *result = JSVAL_VOID; rt = cx->runtime; /* Set registerized frame pointer and derived script pointer. */ fp = cx->fp; script = fp->script; /* Count of JS function calls that nest in this C js_Interpret frame. */ inlineCallCount = 0; /* * Optimized Get and SetVersion for proper script language versioning. * * If any native method or JSClass/JSObjectOps hook calls JS_SetVersion * and changes cx->version, the effect will "stick" and we will stop * maintaining currentVersion. This is relied upon by testsuites, for * the most part -- web browsers select version before compiling and not * at run-time. */ currentVersion = script->version; originalVersion = cx->version; if (currentVersion != originalVersion) JS_SetVersion(cx, currentVersion); /* * Prepare to call a user-supplied branch handler, and abort the script * if it returns false. We reload onbranch after calling out to native * functions (but not to getters, setters, or other native hooks). */#define LOAD_BRANCH_CALLBACK(cx) (onbranch = (cx)->branchCallback) LOAD_BRANCH_CALLBACK(cx); ok = JS_TRUE;#define CHECK_BRANCH(len) \ JS_BEGIN_MACRO \ if (len <= 0 && onbranch) { \ SAVE_SP(fp); \ if (!(ok = (*onbranch)(cx, script))) \ goto out; \ } \ JS_END_MACRO
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -