static inline bool UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, bool *unjittable, uint32 argc) { JSContext *cx = f.cx; Value *vp = f.regs.sp - (argc + 2); JSObject &callee = vp->toObject(); JSFunction *newfun = callee.getFunctionPrivate(); JSScript *newscript = newfun->script(); /* Get pointer to new frame/slots, prepare arguments. */ StackSpace &stack = cx->stack(); JSStackFrame *newfp = stack.getInlineFrameWithinLimit(cx, f.regs.sp, argc, newfun, newscript, &flags, f.entryfp, &f.stackLimit); if (JS_UNLIKELY(!newfp)) return false; /* Initialize frame, locals. */ newfp->initCallFrame(cx, callee, newfun, argc, flags); SetValueRangeToUndefined(newfp->slots(), newscript->nfixed); /* Officially push the frame. */ stack.pushInlineFrame(cx, newscript, newfp, &f.regs); JS_ASSERT(newfp == f.regs.fp); /* Scope with a call object parented by callee's parent. */ if (newfun->isHeavyweight() && !js::CreateFunCallObject(cx, newfp)) return false; /* Try to compile if not already compiled. */ if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) { CompileStatus status = CanMethodJIT(cx, newscript, newfp, CompileRequest_Interpreter); if (status == Compile_Error) { /* A runtime exception was thrown, get out. */ InlineReturn(f); return false; } if (status == Compile_Abort) *unjittable = true; } /* If newscript was successfully compiled, run it. */ if (JITScript *jit = newscript->getJIT(newfp->isConstructing())) { *pret = jit->invokeEntry; return true; } /* Otherwise, run newscript in the interpreter. */ bool ok = !!Interpret(cx, cx->fp()); InlineReturn(f); *pret = NULL; return ok; }
/* * Clean up a frame and return. */ static void InlineReturn(VMFrame &f) { JSContext *cx = f.cx; JSStackFrame *fp = f.regs.fp; JS_ASSERT(f.fp() != f.entryfp); JS_ASSERT(!js_IsActiveWithOrBlock(cx, &fp->scopeChain(), 0)); Value *newsp = fp->actualArgs() - 1; newsp[-1] = fp->returnValue(); cx->stack().popInlineFrame(cx, fp->prev(), newsp); }
/* * This function must only be called after the early prologue, since it depends * on fp->exec.fun. */ void * JS_FASTCALL stubs::FixupArity(VMFrame &f, uint32 nactual) { JSContext *cx = f.cx; JSStackFrame *oldfp = f.fp(); JS_ASSERT(nactual != oldfp->numFormalArgs()); /* * Grossssss! *move* the stack frame. If this ends up being perf-critical, * we can figure out how to spot-optimize it. Be careful to touch only the * members that have been initialized by initCallFrameCallerHalf and the * early prologue. */ uint32 flags = oldfp->isConstructingFlag(); JSFunction *fun = oldfp->fun(); void *ncode = oldfp->nativeReturnAddress(); /* Pop the inline frame. */ f.fp() = oldfp->prev(); f.regs.sp = (Value*) oldfp; /* Reserve enough space for a callee frame. */ JSStackFrame *newfp = cx->stack().getInlineFrameWithinLimit(cx, (Value*) oldfp, nactual, fun, fun->script(), &flags, f.entryfp, &f.stackLimit); if (!newfp) { /* * The PC is not coherent with the current frame, so fix it up for * exception handling. */ f.regs.pc = f.jit()->nativeToPC(ncode); THROWV(NULL); } /* Reset the part of the stack frame set by the caller. */ newfp->initCallFrameCallerHalf(cx, flags, ncode); /* Reset the part of the stack frame set by the prologue up to now. */ newfp->initCallFrameEarlyPrologue(fun, nactual); /* The caller takes care of assigning fp to regs. */ return newfp; }