📄 jsinterp.c
字号:
/* * Load the debugger's interrupt hook here and after calling out to native * functions (but not to getters, setters, or other native hooks), so we do * not have to reload it each time through the interpreter loop -- we hope * the compiler can keep it in a register. * XXX if it spills, we still lose */#define LOAD_INTERRUPT_HANDLER(rt) (interruptHandler = (rt)->interruptHandler) LOAD_INTERRUPT_HANDLER(rt); pc = script->code; endpc = pc + script->length; depth = (jsint) script->depth; len = -1; /* Check for too much js_Interpret nesting, or too deep a C stack. */ if (++cx->interpLevel == MAX_INTERP_LEVEL || !JS_CHECK_STACK_SIZE(cx, stackDummy)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED); ok = JS_FALSE; goto out; } /* * Allocate operand and pc stack slots for the script's worst-case depth. */ newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark); if (!newsp) { ok = JS_FALSE; goto out; } sp = newsp + depth; fp->spbase = sp; fp->spend = sp + depth; SAVE_SP(fp); while (pc < endpc) { fp->pc = pc; op = (JSOp) *pc; do_op: cs = &js_CodeSpec[op]; len = cs->length;#ifdef DEBUG tracefp = (FILE *) cx->tracefp; if (tracefp) { intN nuses, n; fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, script, pc)); js_Disassemble1(cx, script, pc, PTRDIFF(pc, script->code, jsbytecode), JS_FALSE, tracefp); nuses = cs->nuses; if (nuses) { SAVE_SP(fp); for (n = -nuses; n < 0; n++) { str = js_DecompileValueGenerator(cx, n, sp[n], NULL); if (str != NULL) { fprintf(tracefp, "%s %s", (n == -nuses) ? " inputs:" : ",", JS_GetStringBytes(str)); } } fprintf(tracefp, " @ %td\n", sp - fp->spbase); } }#endif if (interruptHandler) { SAVE_SP(fp); switch (interruptHandler(cx, script, pc, &rval, rt->interruptHandlerData)) { case JSTRAP_ERROR: ok = JS_FALSE; goto out; case JSTRAP_CONTINUE: break; case JSTRAP_RETURN: fp->rval = rval; goto out;#if JS_HAS_EXCEPTIONS case JSTRAP_THROW: cx->throwing = JS_TRUE; cx->exception = rval; ok = JS_FALSE; goto out;#endif /* JS_HAS_EXCEPTIONS */ default:; } LOAD_INTERRUPT_HANDLER(rt); } switch (op) { case JSOP_NOP: break; case JSOP_GROUP: obj = NULL; break; case JSOP_PUSH: PUSH_OPND(JSVAL_VOID); break; case JSOP_POP: sp--; break; case JSOP_POP2: sp -= 2; break; case JSOP_FLASHSWAP: id = pc[1] << 8 | pc[2]; ltmp = sp[-1]; sp[-1] = sp[-id]; sp[-id] = ltmp; break; case JSOP_SWAP: /* * N.B. JSOP_SWAP doesn't swap the corresponding generating pcs * for the operands it swaps. */ ltmp = sp[-1]; sp[-1] = sp[-2]; sp[-2] = ltmp; break; case JSOP_POPV: *result = POP_OPND(); break; case JSOP_ENTERWITH: rval = FETCH_OPND(-1); VALUE_TO_OBJECT(cx, rval, obj); withobj = js_NewObject(cx, &js_WithClass, obj, fp->scopeChain); if (!withobj) goto out; fp->scopeChain = withobj; STORE_OPND(-1, OBJECT_TO_JSVAL(withobj)); break; case JSOP_LEAVEWITH: rval = POP_OPND(); JS_ASSERT(JSVAL_IS_OBJECT(rval)); withobj = JSVAL_TO_OBJECT(rval); JS_ASSERT(OBJ_GET_CLASS(cx, withobj) == &js_WithClass); rval = OBJ_GET_SLOT(cx, withobj, JSSLOT_PARENT); JS_ASSERT(JSVAL_IS_OBJECT(rval)); fp->scopeChain = JSVAL_TO_OBJECT(rval); break; case JSOP_SETRVAL: fp->rval = POP_OPND(); break; case JSOP_RETURN: CHECK_BRANCH(-1); fp->rval = POP_OPND(); /* FALL THROUGH */ case JSOP_RETRVAL: /* fp->rval already set */ if (inlineCallCount) inline_return: { JSInlineFrame *ifp = (JSInlineFrame *) fp; void *hookData = ifp->hookData; if (hookData) { JSInterpreterHook hook = cx->runtime->callHook; if (hook) { hook(cx, fp, JS_FALSE, &ok, hookData); LOAD_INTERRUPT_HANDLER(rt); } }#if JS_HAS_ARGS_OBJECT if (fp->argsobj) ok &= js_PutArgsObject(cx, fp);#endif /* Restore context version only if callee hasn't set version. */ if (cx->version == currentVersion) { currentVersion = ifp->callerVersion; if (currentVersion != cx->version) JS_SetVersion(cx, currentVersion); } /* Store the return value in the caller's operand frame. */ vp = fp->argv - 2; *vp = fp->rval; /* Restore cx->fp and release the inline frame's space. */ cx->fp = fp = fp->down; JS_ARENA_RELEASE(&cx->stackPool, ifp->mark); /* Restore sp to point just above the return value. */ fp->sp = vp + 1; RESTORE_SP(fp); /* Restore the calling script's interpreter registers. */ script = fp->script; depth = (jsint) script->depth; pc = fp->pc; endpc = script->code + script->length; /* Store the generating pc for the return value. */ vp[-depth] = (jsval)pc; /* Set remaining variables for 'goto advance_pc'. */ op = (JSOp) *pc; cs = &js_CodeSpec[op]; len = cs->length; /* Resume execution in the calling frame. */ inlineCallCount--; if (ok) goto advance_pc; } goto out;#if JS_HAS_SWITCH_STATEMENT case JSOP_DEFAULT: (void) POP(); /* FALL THROUGH */#endif case JSOP_GOTO: len = GET_JUMP_OFFSET(pc); CHECK_BRANCH(len); break; case JSOP_IFEQ: POP_BOOLEAN(cx, rval, cond); if (cond == JS_FALSE) { len = GET_JUMP_OFFSET(pc); CHECK_BRANCH(len); } break; case JSOP_IFNE: POP_BOOLEAN(cx, rval, cond); if (cond != JS_FALSE) { len = GET_JUMP_OFFSET(pc); CHECK_BRANCH(len); } break; case JSOP_OR: POP_BOOLEAN(cx, rval, cond); if (cond == JS_TRUE) { len = GET_JUMP_OFFSET(pc); PUSH_OPND(rval); } break; case JSOP_AND: POP_BOOLEAN(cx, rval, cond); if (cond == JS_FALSE) { len = GET_JUMP_OFFSET(pc); PUSH_OPND(rval); } break;#if JS_HAS_SWITCH_STATEMENT case JSOP_DEFAULTX: (void) POP(); /* FALL THROUGH */#endif case JSOP_GOTOX: len = GET_JUMPX_OFFSET(pc); CHECK_BRANCH(len); break; case JSOP_IFEQX: POP_BOOLEAN(cx, rval, cond); if (cond == JS_FALSE) { len = GET_JUMPX_OFFSET(pc); CHECK_BRANCH(len); } break; case JSOP_IFNEX: POP_BOOLEAN(cx, rval, cond); if (cond != JS_FALSE) { len = GET_JUMPX_OFFSET(pc); CHECK_BRANCH(len); } break; case JSOP_ORX: POP_BOOLEAN(cx, rval, cond); if (cond == JS_TRUE) { len = GET_JUMPX_OFFSET(pc); PUSH_OPND(rval); } break; case JSOP_ANDX: POP_BOOLEAN(cx, rval, cond); if (cond == JS_FALSE) { len = GET_JUMPX_OFFSET(pc); PUSH_OPND(rval); } break; case JSOP_TOOBJECT: SAVE_SP(fp); ok = js_ValueToObject(cx, FETCH_OPND(-1), &obj); if (!ok) goto out; STORE_OPND(-1, OBJECT_TO_JSVAL(obj)); break;#define FETCH_ELEMENT_ID(n, id) \ JS_BEGIN_MACRO \ /* If the index is not a jsint, atomize it. */ \ id = (jsid) FETCH_OPND(n); \ if (JSVAL_IS_INT(id)) { \ atom = NULL; \ } else { \ SAVE_SP(fp); \ atom = js_ValueToStringAtom(cx, (jsval)id); \ if (!atom) { \ ok = JS_FALSE; \ goto out; \ } \ id = (jsid)atom; \ } \ JS_END_MACRO#define POP_ELEMENT_ID(id) \ JS_BEGIN_MACRO \ FETCH_ELEMENT_ID(-1, id); \ sp--; \ JS_END_MACRO#if JS_HAS_IN_OPERATOR case JSOP_IN: SAVE_SP(fp); rval = FETCH_OPND(-1); if (JSVAL_IS_PRIMITIVE(rval)) { str = js_DecompileValueGenerator(cx, -1, rval, NULL); if (str) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_IN_NOT_OBJECT, JS_GetStringBytes(str)); } ok = JS_FALSE; goto out; } obj = JSVAL_TO_OBJECT(rval); FETCH_ELEMENT_ID(-2, id); ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop); if (!ok) goto out; sp--; STORE_OPND(-1, BOOLEAN_TO_JSVAL(prop != NULL)); if (prop) OBJ_DROP_PROPERTY(cx, obj2, prop); break;#endif /* JS_HAS_IN_OPERATOR */ case JSOP_FORPROP: /* * Handle JSOP_FORPROP first,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -