static void CloseLiveIterators(JSContext *cx, const InlineFrameIterator &frame) { JSScript *script = frame.script(); jsbytecode *pc = frame.pc(); if (!script->hasTrynotes()) return; JSTryNote *tn = script->trynotes()->vector; JSTryNote *tnEnd = tn + script->trynotes()->length; uint32 pcOffset = uint32(pc - script->main()); for (; tn != tnEnd; ++tn) { if (pcOffset < tn->start) continue; if (pcOffset >= tn->start + tn->length) continue; if (tn->kind != JSTRY_ITER) continue; JS_ASSERT(JSOp(*(script->main() + tn->start + tn->length)) == JSOP_ENDITER); JS_ASSERT(tn->stackDepth > 0); uint32 localSlot = tn->stackDepth; CloseLiveIterator(cx, frame, localSlot); } }
static jsbytecode * FindExceptionHandler(JSContext *cx) { StackFrame *fp = cx->fp(); JSScript *script = fp->script(); if (!script->hasTrynotes()) return NULL; error: if (cx->isExceptionPending()) { for (TryNoteIter tni(cx->regs()); !tni.done(); ++tni) { JSTryNote *tn = *tni; UnwindScope(cx, tn->stackDepth); /* * Set pc to the first bytecode after the the try note to point * to the beginning of catch or finally or to [enditer] closing * the for-in loop. */ jsbytecode *pc = script->main() + tn->start + tn->length; cx->regs().pc = pc; cx->regs().sp = fp->base() + tn->stackDepth; switch (tn->kind) { case JSTRY_CATCH: JS_ASSERT(JSOp(*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. */ JS_ASSERT(JSOp(*pc) == JSOP_ENDITER); bool ok = UnwindIteratorForException(cx, &cx->regs().sp[-1].toObject()); cx->regs().sp -= 1; if (!ok) goto error; } } } } else { UnwindForUncatchableException(cx, cx->regs()); } return NULL; }
static jsbytecode * FindExceptionHandler(JSContext *cx) { StackFrame *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; UnwindScope(cx, tn->stackDepth); jsbytecode *pc = script->main() + tn->start + tn->length; cx->regs().pc = pc; cx->regs().sp = fp->base() + tn->stackDepth; switch (tn->kind) { case JSTRY_CATCH: JS_ASSERT(JSOp(*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(JSOp(*pc) == JSOP_ENDITER); cx->clearPendingException(); bool ok = !!js_CloseIterator(cx, &cx->regs().sp[-1].toObject()); cx->regs().sp -= 1; if (!ok) goto top; cx->setPendingException(v); } } } } return NULL; }