void * JS_FASTCALL stubs::CompileFunction(VMFrame &f, uint32 nactual) { /* * We have a partially constructed frame. That's not really good enough to * compile though because we could throw, so get a full, adjusted frame. */ JSContext *cx = f.cx; JSStackFrame *fp = f.fp(); /* * Since we can only use members set by initCallFrameCallerHalf, * we must carefully extract the callee from the nactual. */ JSObject &callee = fp->formalArgsEnd()[-(int(nactual) + 2)].toObject(); JSFunction *fun = callee.getFunctionPrivate(); JSScript *script = fun->script(); /* * FixupArity/RemovePartialFrame expect to be called after the early * prologue. */ fp->initCallFrameEarlyPrologue(fun, nactual); if (nactual != fp->numFormalArgs()) { fp = (JSStackFrame *)FixupArity(f, nactual); if (!fp) return NULL; } /* Finish frame initialization. */ fp->initCallFrameLatePrologue(); /* These would have been initialized by the prologue. */ f.regs.fp = fp; f.regs.sp = fp->base(); f.regs.pc = script->code; if (fun->isHeavyweight() && !js::CreateFunCallObject(cx, fp)) THROWV(NULL); CompileStatus status = CanMethodJIT(cx, script, fp, CompileRequest_JIT); if (status == Compile_Okay) return script->getJIT(fp->isConstructing())->invokeEntry; /* Function did not compile... interpret it. */ JSBool ok = Interpret(cx, fp); InlineReturn(f); if (!ok) THROWV(NULL); return NULL; }
static jsbytecode * FindExceptionHandler(JSContext *cx) { JSStackFrame *fp = cx->fp(); JSScript *script = fp->script(); top: if (cx->isExceptionPending() && JSScript::isValidOffset(script->trynotesOffset)) { // The PC is updated before every stub call, so we can use it here. unsigned offset = cx->regs->pc - script->main; JSTryNoteArray *tnarray = script->trynotes(); for (unsigned i = 0; i < tnarray->length; ++i) { JSTryNote *tn = &tnarray->vector[i]; // The following if condition actually tests two separate conditions: // (1) offset - tn->start >= tn->length // means the PC is not in the range of this try note, so we // should continue searching, after considering: // (2) offset - tn->start == tn->length // means the PC is at the first op of the exception handler // for this try note. This happens when an exception is thrown // during recording: the interpreter sets the PC to the handler // and then exits. In this case, we are in fact at the right // exception handler. // // Hypothetically, the op we are at might have thrown an // exception, in which case this would not be the right handler. // But the first ops of exception handlers generated by our // bytecode compiler cannot throw, so this is not possible. if (offset - tn->start > tn->length) continue; if (tn->stackDepth > cx->regs->sp - fp->base()) continue; jsbytecode *pc = script->main + tn->start + tn->length; JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE); JS_ASSERT(cx->regs->sp == fp->base() + tn->stackDepth); switch (tn->kind) { case JSTRY_CATCH: JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENTERBLOCK); #if JS_HAS_GENERATORS /* Catch cannot intercept the closing of a generator. */ if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) break; #endif /* * Don't clear cx->throwing to save cx->exception from GC * until it is pushed to the stack via [exception] in the * catch block. */ return pc; case JSTRY_FINALLY: /* * Push (true, exception) pair for finally to indicate that * [retsub] should rethrow the exception. */ cx->regs->sp[0].setBoolean(true); cx->regs->sp[1] = cx->getPendingException(); cx->regs->sp += 2; cx->clearPendingException(); return pc; case JSTRY_ITER: { /* * This is similar to JSOP_ENDITER in the interpreter loop, * except the code now uses the stack slot normally used by * JSOP_NEXTITER, namely regs.sp[-1] before the regs.sp -= 2 * adjustment and regs.sp[1] after, to save and restore the * pending exception. */ Value v = cx->getPendingException(); JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == JSOP_ENDITER); cx->clearPendingException(); ok = !!js_CloseIterator(cx, &cx->regs->sp[-1].toObject()); cx->regs->sp -= 1; if (!ok) goto top; cx->setPendingException(v); } } } } return NULL; }