LCOV - app.info - js/src/methodjit/InvokeHelpers.cpp

LCOV - code coverage report
| Current view: | directory - js/src/methodjit - InvokeHelpers.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 461 | 393 | 85.2 %
| Date: | 2012-04-07 | Functions: | 27 | 25 | 92.6 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
          18                 :  * May 28, 2008.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  *   Brendan Eich <brendan@mozilla.org>
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *   David Anderson <danderson@mozilla.com>
          25                 :  *   David Mandelin <dmandelin@mozilla.com>
          26                 :  *
          27                 :  * Alternatively, the contents of this file may be used under the terms of
          28                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          29                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          30                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          31                 :  * of those above. If you wish to allow use of your version of this file only
          32                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          33                 :  * use your version of this file under the terms of the MPL, indicate your
          34                 :  * decision by deleting the provisions above and replace them with the notice
          35                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          36                 :  * the provisions above, a recipient may use your version of this file under
          37                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          38                 :  *
          39                 :  * ***** END LICENSE BLOCK ***** */
          40                 :
          41                 : #include "jscntxt.h"
          42                 : #include "jsscope.h"
          43                 : #include "jsobj.h"
          44                 : #include "jslibmath.h"
          45                 : #include "jsiter.h"
          46                 : #include "jsnum.h"
          47                 : #include "jsxml.h"
          48                 : #include "jsbool.h"
          49                 : #include "assembler/assembler/MacroAssemblerCodeRef.h"
          50                 : #include "assembler/assembler/CodeLocation.h"
          51                 : #include "jstypes.h"
          52                 : #include "methodjit/StubCalls.h"
          53                 : #include "methodjit/MonoIC.h"
          54                 : #include "jsanalyze.h"
          55                 : #include "methodjit/BaseCompiler.h"
          56                 : #include "methodjit/ICRepatcher.h"
          57                 : #include "vm/Debugger.h"
          58                 :
          59                 : #include "jsinterpinlines.h"
          60                 : #include "jsscopeinlines.h"
          61                 : #include "jsscriptinlines.h"
          62                 : #include "jsobjinlines.h"
          63                 : #include "jscntxtinlines.h"
          64                 : #include "jsatominlines.h"
          65                 : #include "StubCalls-inl.h"
          66                 :
          67                 : #include "jsautooplen.h"
          68                 :
          69                 : using namespace js;
          70                 : using namespace js::mjit;
          71                 : using namespace JSC;
          72                 :
          73                 : using ic::Repatcher;
          74                 :
          75                 : static jsbytecode *
          76         1273550 : FindExceptionHandler(JSContext *cx)
          77                 : {
          78         1273550 :     StackFrame *fp = cx->fp();
          79         1273550 :     JSScript *script = fp->script();
          80                 :
          81         1273550 :     if (!JSScript::isValidOffset(script->trynotesOffset))
          82         1270499 :         return NULL;
          83                 :
          84                 :   error:
          85            3054 :     if (cx->isExceptionPending()) {
          86            3081 :         for (TryNoteIter tni(cx->regs()); !tni.done(); ++tni) {
          87            2942 :             JSTryNote *tn = *tni;
          88                 :
          89            2942 :             UnwindScope(cx, tn->stackDepth);
          90                 :
          91                 :             /*
          92                 :              * Set pc to the first bytecode after the the try note to point
          93                 :              * to the beginning of catch or finally or to [enditer] closing
          94                 :              * the for-in loop.
          95                 :              */
          96            2942 :             jsbytecode *pc = script->main() + tn->start + tn->length;
          97            2942 :             cx->regs().pc = pc;
          98            2942 :             cx->regs().sp = fp->base() + tn->stackDepth;
          99                 :
         100            2942 :             switch (tn->kind) {
         101                 :                 case JSTRY_CATCH:
         102            2905 :                   JS_ASSERT(JSOp(*pc) == JSOP_ENTERBLOCK);
         103                 :
         104                 : #if JS_HAS_GENERATORS
         105                 :                   /* Catch cannot intercept the closing of a generator. */
         106            2905 :                   if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING)))
         107               0 :                       break;
         108                 : #endif
         109                 :
         110                 :                   /*
         111                 :                    * Don't clear cx->throwing to save cx->exception from GC
         112                 :                    * until it is pushed to the stack via [exception] in the
         113                 :                    * catch block.
         114                 :                    */
         115            2905 :                   return pc;
         116                 :
         117                 :                 case JSTRY_FINALLY:
         118                 :                   /*
         119                 :                    * Push (true, exception) pair for finally to indicate that
         120                 :                    * [retsub] should rethrow the exception.
         121                 :                    */
         122               0 :                   cx->regs().sp[0].setBoolean(true);
         123               0 :                   cx->regs().sp[1] = cx->getPendingException();
         124               0 :                   cx->regs().sp += 2;
         125               0 :                   cx->clearPendingException();
         126               0 :                   return pc;
         127                 :
         128                 :                 case JSTRY_ITER:
         129                 :                 {
         130                 :                   /*
         131                 :                    * This is similar to JSOP_ENDITER in the interpreter loop,
         132                 :                    * except the code now uses the stack slot normally used by
         133                 :                    * JSOP_NEXTITER, namely regs.sp[-1] before the regs.sp -= 2
         134                 :                    * adjustment and regs.sp[1] after, to save and restore the
         135                 :                    * pending exception.
         136                 :                    */
         137              37 :                   JS_ASSERT(JSOp(*pc) == JSOP_ENDITER);
         138              37 :                   bool ok = UnwindIteratorForException(cx, &cx->regs().sp[-1].toObject());
         139              37 :                   cx->regs().sp -= 1;
         140              37 :                   if (!ok)
         141               3 :                       goto error;
         142                 :                 }
         143                 :             }
         144                 :         }
         145                 :     } else {
         146               7 :         UnwindForUncatchableException(cx, cx->regs());
         147                 :     }
         148                 :
         149             146 :     return NULL;
         150                 : }
         151                 :
         152                 : /*
         153                 :  * Clean up a frame and return.
         154                 :  */
         155                 : static void
         156         1255589 : InlineReturn(VMFrame &f)
         157                 : {
         158         1255589 :     JS_ASSERT(f.fp() != f.entryfp);
         159         1255589 :     JS_ASSERT(!IsActiveWithOrBlock(f.cx, f.fp()->scopeChain(), 0));
         160         1255589 :     JS_ASSERT(!f.fp()->hasBlockChain());
         161         1255589 :     f.cx->stack.popInlineFrame(f.regs);
         162                 :
         163         2511178 :     DebugOnly<JSOp> op = JSOp(*f.regs.pc);
         164         1467644 :     JS_ASSERT(op == JSOP_CALL ||
         165                 :               op == JSOP_NEW ||
         166                 :               op == JSOP_EVAL ||
         167                 :               op == JSOP_FUNCALL ||
         168         1467644 :               op == JSOP_FUNAPPLY);
         169         1255589 :     f.regs.pc += JSOP_CALL_LENGTH;
         170         1255589 : }
         171                 :
         172                 : void JS_FASTCALL
         173          408168 : stubs::SlowCall(VMFrame &f, uint32_t argc)
         174                 : {
         175          408168 :     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
         176          408168 :     if (!InvokeKernel(f.cx, args))
         177              86 :         THROW();
         178                 :
         179          408082 :     types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         180                 : }
         181                 :
         182                 : void JS_FASTCALL
         183              28 : stubs::SlowNew(VMFrame &f, uint32_t argc)
         184                 : {
         185              28 :     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
         186              28 :     if (!InvokeConstructorKernel(f.cx, args))
         187              16 :         THROW();
         188                 :
         189              12 :     types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         190                 : }
         191                 :
         192                 : static inline bool
         193              40 : CheckStackQuota(VMFrame &f)
         194                 : {
         195              40 :     JS_ASSERT(f.regs.sp == f.fp()->base());
         196                 :
         197              40 :     f.stackLimit = f.cx->stack.space().getStackLimit(f.cx, DONT_REPORT_ERROR);
         198              40 :     if (f.stackLimit)
         199              24 :         return true;
         200                 :
         201                 :     /* Remove the current partially-constructed frame before throwing. */
         202              16 :     f.cx->stack.popFrameAfterOverflow();
         203              16 :     js_ReportOverRecursed(f.cx);
         204                 :
         205              16 :     return false;
         206                 : }
         207                 :
         208                 : /*
         209                 :  * HitStackQuota is called after the early prologue pushing the new frame would
         210                 :  * overflow f.stackLimit.
         211                 :  */
         212                 : void JS_FASTCALL
         213              20 : stubs::HitStackQuota(VMFrame &f)
         214                 : {
         215              20 :     if (!CheckStackQuota(f))
         216              16 :         THROW();
         217                 : }
         218                 :
         219                 : /*
         220                 :  * This function must only be called after the early prologue, since it depends
         221                 :  * on fp->exec.fun.
         222                 :  */
         223                 : void * JS_FASTCALL
         224          935060 : stubs::FixupArity(VMFrame &f, uint32_t nactual)
         225                 : {
         226          935060 :     JSContext *cx = f.cx;
         227          935060 :     StackFrame *oldfp = f.fp();
         228                 :
         229          935060 :     JS_ASSERT(nactual != oldfp->numFormalArgs());
         230                 :
         231                 :     /*
         232                 :      * Grossssss! *move* the stack frame. If this ends up being perf-critical,
         233                 :      * we can figure out how to spot-optimize it. Be careful to touch only the
         234                 :      * members that have been initialized by the caller and early prologue.
         235                 :      */
         236          935060 :     InitialFrameFlags initial = oldfp->initialFlags();
         237          935060 :     JSFunction *fun           = oldfp->fun();
         238          935060 :     JSScript *script          = fun->script();
         239          935060 :     void *ncode               = oldfp->nativeReturnAddress();
         240                 :
         241                 :     /* Pop the inline frame. */
         242          935060 :     f.regs.popPartialFrame((Value *)oldfp);
         243                 :
         244                 :     /* Reserve enough space for a callee frame. */
         245          935060 :     CallArgs args = CallArgsFromSp(nactual, f.regs.sp);
         246                 :     StackFrame *fp = cx->stack.getFixupFrame(cx, DONT_REPORT_ERROR, args, fun,
         247          935060 :                                              script, ncode, initial, &f.stackLimit);
         248                 :
         249          935060 :     if (!fp) {
         250              12 :         f.regs.updateForNcode(f.jit(), ncode);
         251              12 :         js_ReportOverRecursed(cx);
         252              12 :         THROWV(NULL);
         253                 :     }
         254                 :
         255                 :     /* The caller takes care of assigning fp to regs. */
         256          935048 :     return fp;
         257                 : }
         258                 :
         259                 : struct ResetStubRejoin {
         260                 :     VMFrame &f;
         261            3392 :     ResetStubRejoin(VMFrame &f) : f(f) {}
         262            3392 :     ~ResetStubRejoin() { f.stubRejoin = 0; }
         263                 : };
         264                 :
         265                 : void * JS_FASTCALL
         266            3392 : stubs::CompileFunction(VMFrame &f, uint32_t argc)
         267                 : {
         268                 :     /*
         269                 :      * Note: the stubRejoin kind for the frame was written before the call, and
         270                 :      * needs to be cleared out on all return paths (doing this directly in the
         271                 :      * IC stub will not handle cases where we recompiled or threw).
         272                 :      */
         273            3392 :     JS_ASSERT_IF(f.cx->typeInferenceEnabled(), f.stubRejoin);
         274            6784 :     ResetStubRejoin reset(f);
         275                 :
         276            3392 :     InitialFrameFlags initial = f.fp()->initialFlags();
         277            3392 :     f.regs.popPartialFrame((Value *)f.fp());
         278                 :
         279            3392 :     if (InitialFrameFlagsAreConstructing(initial))
         280               1 :         return UncachedNew(f, argc);
         281            3391 :     else if (InitialFrameFlagsAreLowered(initial))
         282             273 :         return UncachedLoweredCall(f, argc);
         283                 :     else
         284            3118 :         return UncachedCall(f, argc);
         285                 : }
         286                 :
         287                 : static inline bool
         288        11195172 : UncachedInlineCall(VMFrame &f, InitialFrameFlags initial,
         289                 :                    void **pret, bool *unjittable, uint32_t argc)
         290                 : {
         291        11195172 :     JSContext *cx = f.cx;
         292        11195172 :     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
         293        11195172 :     JSFunction *newfun = args.callee().toFunction();
         294        11195172 :     JSScript *newscript = newfun->script();
         295                 :
         296        11195172 :     bool construct = InitialFrameFlagsAreConstructing(initial);
         297                 :
         298         1300013 :     bool newType = construct && cx->typeInferenceEnabled() &&
         299        12495185 :         types::UseNewType(cx, f.script(), f.pc());
         300                 :
         301        11195172 :     types::TypeMonitorCall(cx, args, construct);
         302                 :
         303                 :     /* Try to compile if not already compiled. */
         304        11195172 :     CompileStatus status = CanMethodJIT(cx, newscript, newscript->code, construct, CompileRequest_Interpreter);
         305        11195172 :     if (status == Compile_Error) {
         306                 :         /* A runtime exception was thrown, get out. */
         307               0 :         return false;
         308                 :     }
         309        11195172 :     if (status == Compile_Abort)
         310            2816 :         *unjittable = true;
         311                 :
         312                 :     /*
         313                 :      * Make sure we are not calling from an inline frame if we need to make a
         314                 :      * call object for the callee, as doing so could trigger GC and cause
         315                 :      * jitcode discarding / frame expansion.
         316                 :      */
         317        11195172 :     if (f.regs.inlined() && newfun->isHeavyweight()) {
         318               0 :         ExpandInlineFrames(cx->compartment);
         319               0 :         JS_ASSERT(!f.regs.inlined());
         320                 :     }
         321                 :
         322                 :     /*
         323                 :      * Preserve f.regs.fp while pushing the new frame, for the invariant that
         324                 :      * f.regs reflects the state when we entered the stub call. This handoff is
         325                 :      * tricky: we need to make sure that f.regs is not updated to the new
         326                 :      * frame, and we also need to ensure that cx->regs still points to f.regs
         327                 :      * when space is reserved, in case doing so throws an exception.
         328                 :      */
         329        11195172 :     FrameRegs regs = f.regs;
         330                 :
         331                 :     /* Get pointer to new frame/slots, prepare arguments. */
         332        11195172 :     if (!cx->stack.pushInlineFrame(cx, regs, args, *newfun, newscript, initial, &f.stackLimit))
         333              21 :         return false;
         334                 :
         335                 :     /* Finish the handoff to the new frame regs. */
         336        22390302 :     PreserveRegsGuard regsGuard(cx, regs);
         337                 :
         338                 :     /* Scope with a call object parented by callee's parent. */
         339        11195151 :     if (!regs.fp()->functionPrologue(cx))
         340               0 :         return false;
         341                 :
         342                 :     /*
         343                 :      * If newscript was successfully compiled, run it. Skip for calls which
         344                 :      * will be constructing a new type object for 'this'.
         345                 :      */
         346        11195151 :     if (!newType) {
         347        11195141 :         if (JITScript *jit = newscript->getJIT(regs.fp()->isConstructing())) {
         348        11181028 :             if (jit->invokeEntry) {
         349        11175538 :                 *pret = jit->invokeEntry;
         350                 :
         351                 :                 /* Restore the old fp around and let the JIT code repush the new fp. */
         352        11175538 :                 regs.popFrame((Value *) regs.fp());
         353        11175538 :                 return true;
         354                 :             }
         355                 :         }
         356                 :     }
         357                 :
         358                 :     /*
         359                 :      * Otherwise, run newscript in the interpreter. Expand any inlined frame we
         360                 :      * are calling from, as the new frame is not associated with the VMFrame
         361                 :      * and will not have its prevpc info updated if frame expansion is
         362                 :      * triggered while interpreting.
         363                 :      */
         364           19613 :     if (f.regs.inlined()) {
         365               0 :         ExpandInlineFrames(cx->compartment);
         366               0 :         JS_ASSERT(!f.regs.inlined());
         367               0 :         regs.fp()->resetInlinePrev(f.fp(), f.regs.pc);
         368                 :     }
         369                 :
         370           19613 :     JS_CHECK_RECURSION(cx, return false);
         371                 :
         372           19610 :     bool ok = Interpret(cx, cx->fp());
         373           19610 :     f.cx->stack.popInlineFrame(regs);
         374                 :
         375           19610 :     if (ok)
         376           19132 :         types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         377                 :
         378           19610 :     *pret = NULL;
         379           19610 :     return ok;
         380                 : }
         381                 :
         382                 : void * JS_FASTCALL
         383         1373343 : stubs::UncachedNew(VMFrame &f, uint32_t argc)
         384                 : {
         385                 :     UncachedCallResult ucr;
         386         1373343 :     UncachedNewHelper(f, argc, &ucr);
         387         1373343 :     return ucr.codeAddr;
         388                 : }
         389                 :
         390                 : void
         391         1377158 : stubs::UncachedNewHelper(VMFrame &f, uint32_t argc, UncachedCallResult *ucr)
         392                 : {
         393         1377158 :     ucr->init();
         394         1377158 :     JSContext *cx = f.cx;
         395         1377158 :     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
         396                 :
         397                 :     /* Try to do a fast inline call before the general Invoke path. */
         398         1377158 :     if (IsFunctionObject(args.calleev(), &ucr->fun) && ucr->fun->isInterpretedConstructor()) {
         399         1300013 :         if (!UncachedInlineCall(f, INITIAL_CONSTRUCT, &ucr->codeAddr, &ucr->unjittable, argc))
         400               7 :             THROW();
         401                 :     } else {
         402           77145 :         if (!InvokeConstructorKernel(cx, args))
         403             131 :             THROW();
         404           77014 :         types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         405                 :     }
         406                 : }
         407                 :
         408                 : void * JS_FASTCALL
         409        16100857 : stubs::UncachedCall(VMFrame &f, uint32_t argc)
         410                 : {
         411                 :     UncachedCallResult ucr;
         412        16100857 :     UncachedCallHelper(f, argc, false, &ucr);
         413        16100857 :     return ucr.codeAddr;
         414                 : }
         415                 :
         416                 : void * JS_FASTCALL
         417             273 : stubs::UncachedLoweredCall(VMFrame &f, uint32_t argc)
         418                 : {
         419                 :     UncachedCallResult ucr;
         420             273 :     UncachedCallHelper(f, argc, true, &ucr);
         421             273 :     return ucr.codeAddr;
         422                 : }
         423                 :
         424                 : void JS_FASTCALL
         425           61436 : stubs::Eval(VMFrame &f, uint32_t argc)
         426                 : {
         427           61436 :     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
         428                 :
         429           61436 :     if (!IsBuiltinEvalForScope(&f.fp()->scopeChain(), args.calleev())) {
         430               6 :         if (!InvokeKernel(f.cx, args))
         431               0 :             THROW();
         432                 :
         433               6 :         types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         434               6 :         return;
         435                 :     }
         436                 :
         437           61430 :     JS_ASSERT(f.fp() == f.cx->fp());
         438           61430 :     if (!DirectEval(f.cx, args))
         439              96 :         THROW();
         440                 :
         441           61334 :     types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         442                 : }
         443                 :
         444                 : void
         445        16129843 : stubs::UncachedCallHelper(VMFrame &f, uint32_t argc, bool lowered, UncachedCallResult *ucr)
         446                 : {
         447        16129843 :     ucr->init();
         448                 :
         449        16129843 :     JSContext *cx = f.cx;
         450        16129843 :     CallArgs args = CallArgsFromSp(argc, f.regs.sp);
         451                 :
         452        16129843 :     if (IsFunctionObject(args.calleev(), &ucr->fun)) {
         453        16126808 :         if (ucr->fun->isInterpreted()) {
         454         9895159 :             InitialFrameFlags initial = lowered ? INITIAL_LOWERED : INITIAL_NONE;
         455         9895159 :             if (!UncachedInlineCall(f, initial, &ucr->codeAddr, &ucr->unjittable, argc))
         456             495 :                 THROW();
         457         9894664 :             return;
         458                 :         }
         459                 :
         460         6231649 :         if (ucr->fun->isNative()) {
         461         6231649 :             if (!CallJSNative(cx, ucr->fun->native(), args))
         462            4723 :                 THROW();
         463         6226926 :             types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         464         6226926 :             return;
         465                 :         }
         466                 :     }
         467                 :
         468            3035 :     if (!InvokeKernel(f.cx, args))
         469              84 :         THROW();
         470                 :
         471            2951 :     types::TypeScript::Monitor(f.cx, f.script(), f.pc(), args.rval());
         472            2951 :     return;
         473                 : }
         474                 :
         475                 : static void
         476           18853 : RemoveOrphanedNative(JSContext *cx, StackFrame *fp)
         477                 : {
         478                 :     /*
         479                 :      * Remove fp from the list of frames holding a reference on the orphaned
         480                 :      * native pools. If all the references have been removed, release all the
         481                 :      * pools. We don't release pools piecemeal as a pool can be referenced by
         482                 :      * multiple frames.
         483                 :      */
         484           18853 :     JaegerCompartment *jc = cx->compartment->jaegerCompartment();
         485           18853 :     if (jc->orphanedNativeFrames.empty())
         486           17969 :         return;
         487           87909 :     for (unsigned i = 0; i < jc->orphanedNativeFrames.length(); i++) {
         488           87909 :         if (fp == jc->orphanedNativeFrames[i]) {
         489             884 :             jc->orphanedNativeFrames[i] = jc->orphanedNativeFrames.back();
         490             884 :             jc->orphanedNativeFrames.popBack();
         491             884 :             break;
         492                 :         }
         493                 :     }
         494             884 :     if (jc->orphanedNativeFrames.empty()) {
         495             588 :         for (unsigned i = 0; i < jc->orphanedNativePools.length(); i++)
         496             294 :             jc->orphanedNativePools[i]->release();
         497             294 :         jc->orphanedNativePools.clear();
         498                 :     }
         499                 : }
         500                 :
         501                 : extern "C" void *
         502           17973 : js_InternalThrow(VMFrame &f)
         503                 : {
         504           17973 :     JSContext *cx = f.cx;
         505                 :
         506           17973 :     ExpandInlineFrames(cx->compartment);
         507                 :
         508                 :     // The current frame may have an associated orphaned native, if the native
         509                 :     // or SplatApplyArgs threw an exception.
         510           17973 :     RemoveOrphanedNative(cx, f.fp());
         511                 :
         512           17973 :     JS_ASSERT(!f.fp()->finishedInInterpreter());
         513                 :
         514                 :     // Make sure sp is up to date.
         515           17973 :     JS_ASSERT(&cx->regs() == &f.regs);
         516                 :
         517           17973 :     jsbytecode *pc = NULL;
         518         1255589 :     for (;;) {
         519         1273562 :         if (cx->isExceptionPending()) {
         520                 :             // Call the throw hook if necessary
         521         1271744 :             JSThrowHook handler = cx->runtime->debugHooks.throwHook;
         522         1271744 :             if (handler || !cx->compartment->getDebuggees().empty()) {
         523                 :                 Value rval;
         524             398 :                 JSTrapStatus st = Debugger::onExceptionUnwind(cx, &rval);
         525             398 :                 if (st == JSTRAP_CONTINUE && handler) {
         526              18 :                     st = handler(cx, cx->fp()->script(), cx->regs().pc, &rval,
         527              36 :                                  cx->runtime->debugHooks.throwHookData);
         528                 :                 }
         529                 :
         530             398 :                 switch (st) {
         531                 :                 case JSTRAP_ERROR:
         532              16 :                     cx->clearPendingException();
         533              16 :                     break;
         534                 :
         535                 :                 case JSTRAP_CONTINUE:
         536             366 :                     break;
         537                 :
         538                 :                 case JSTRAP_RETURN:
         539              12 :                     cx->clearPendingException();
         540              12 :                     cx->fp()->setReturnValue(rval);
         541              12 :                     return cx->jaegerCompartment()->forceReturnFromExternC();
         542                 :
         543                 :                 case JSTRAP_THROW:
         544               4 :                     cx->setPendingException(rval);
         545               4 :                     break;
         546                 :
         547                 :                 default:
         548               0 :                     JS_NOT_REACHED("bad onExceptionUnwind status");
         549                 :                 }
         550                 :             }
         551                 :         }
         552                 :
         553         1273550 :         pc = FindExceptionHandler(cx);
         554         1273550 :         if (pc)
         555            2905 :             break;
         556                 :
         557                 :         // The JIT guarantees that ScriptDebugEpilogue() and ScriptEpilogue()
         558                 :         // have always been run upon exiting to its caller. This is important
         559                 :         // for consistency, where execution modes make similar guarantees about
         560                 :         // prologues and epilogues. Interpret(), and Invoke() all rely on this
         561                 :         // property.
         562         1270645 :         JS_ASSERT(!f.fp()->finishedInInterpreter());
         563         1270645 :         UnwindScope(cx, 0);
         564         1270645 :         f.regs.sp = f.fp()->base();
         565                 :
         566         1270645 :         if (cx->compartment->debugMode()) {
         567                 :             // This can turn a throw or error into a healthy return. Note that
         568                 :             // we will run ScriptDebugEpilogue again (from AnyFrameEpilogue);
         569                 :             // ScriptDebugEpilogue is prepared for this eventuality.
         570          576909 :             if (js::ScriptDebugEpilogue(cx, f.fp(), false))
         571              34 :                 return cx->jaegerCompartment()->forceReturnFromExternC();
         572                 :         }
         573                 :
         574                 :
         575         1270611 :         ScriptEpilogue(f.cx, f.fp(), false);
         576                 :
         577                 :         // Don't remove the last frame, this is the responsibility of
         578                 :         // JaegerShot()'s caller. We only guarantee that ScriptEpilogue()
         579                 :         // has been run.
         580         1270611 :         if (f.entryfp == f.fp())
         581           15022 :             break;
         582                 :
         583         1255589 :         JS_ASSERT(&cx->regs() == &f.regs);
         584         1255589 :         InlineReturn(f);
         585                 :     }
         586                 :
         587           17927 :     JS_ASSERT(&cx->regs() == &f.regs);
         588                 :
         589           17927 :     if (!pc)
         590           15022 :         return NULL;
         591                 :
         592            2905 :     StackFrame *fp = cx->fp();
         593            2905 :     JSScript *script = fp->script();
         594                 :
         595                 :     /*
         596                 :      * Fall back to EnterMethodJIT and finish the frame in the interpreter.
         597                 :      * With type inference enabled, we may wipe out all JIT code on the
         598                 :      * stack without patching ncode values to jump to the interpreter, and
         599                 :      * thus can only enter JIT code via EnterMethodJIT (which overwrites
         600                 :      * its entry frame's ncode). See ClearAllFrames.
         601                 :      */
         602            2905 :     cx->compartment->jaegerCompartment()->setLastUnfinished(Jaeger_Unfinished);
         603                 :
         604            2905 :     if (!script->ensureRanAnalysis(cx, NULL)) {
         605               0 :         js_ReportOutOfMemory(cx);
         606               0 :         return NULL;
         607                 :     }
         608                 :
         609            5810 :     analyze::AutoEnterAnalysis enter(cx);
         610                 :
         611                 :     /*
         612                 :      * Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go
         613                 :      * back into the interpreter with a pending exception. This will cause
         614                 :      * it to immediately rethrow.
         615                 :      */
         616            2905 :     if (cx->isExceptionPending()) {
         617            2905 :         JS_ASSERT(JSOp(*pc) == JSOP_ENTERBLOCK);
         618            2905 :         StaticBlockObject &blockObj = script->getObject(GET_UINT32_INDEX(pc))->asStaticBlock();
         619            2905 :         Value *vp = cx->regs().sp + blockObj.slotCount();
         620            2905 :         SetValueRangeToUndefined(cx->regs().sp, vp);
         621            2905 :         cx->regs().sp = vp;
         622            2905 :         JS_ASSERT(JSOp(pc[JSOP_ENTERBLOCK_LENGTH]) == JSOP_EXCEPTION);
         623            2905 :         cx->regs().sp[0] = cx->getPendingException();
         624            2905 :         cx->clearPendingException();
         625            2905 :         cx->regs().sp++;
         626            2905 :         cx->regs().pc = pc + JSOP_ENTERBLOCK_LENGTH + JSOP_EXCEPTION_LENGTH;
         627            2905 :         cx->regs().fp()->setBlockChain(&blockObj);
         628                 :     }
         629                 :
         630            2905 :     *f.oldregs = f.regs;
         631                 :
         632            2905 :     return NULL;
         633                 : }
         634                 :
         635                 : void JS_FASTCALL
         636         1646803 : stubs::CreateThis(VMFrame &f, JSObject *proto)
         637                 : {
         638         1646803 :     JSContext *cx = f.cx;
         639         1646803 :     StackFrame *fp = f.fp();
         640         1646803 :     JSObject *callee = &fp->callee();
         641         1646803 :     JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
         642         1646803 :     if (!obj)
         643               0 :         THROW();
         644         1646803 :     fp->formalArgs()[-1].setObject(*obj);
         645                 : }
         646                 :
         647                 : void JS_FASTCALL
         648        11798837 : stubs::ScriptDebugPrologue(VMFrame &f)
         649                 : {
         650        11798837 :     Probes::enterJSFun(f.cx, f.fp()->maybeFun(), f.fp()->script());
         651        11798837 :     JSTrapStatus status = js::ScriptDebugPrologue(f.cx, f.fp());
         652        11798837 :     switch (status) {
         653                 :       case JSTRAP_CONTINUE:
         654        11797156 :         break;
         655                 :       case JSTRAP_RETURN:
         656              20 :         *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromFastCall();
         657              20 :         return;
         658                 :       case JSTRAP_ERROR:
         659                 :       case JSTRAP_THROW:
         660            1661 :         THROW();
         661                 :       default:
         662               0 :         JS_NOT_REACHED("bad ScriptDebugPrologue status");
         663                 :     }
         664                 : }
         665                 :
         666                 : void JS_FASTCALL
         667        10898779 : stubs::ScriptDebugEpilogue(VMFrame &f)
         668                 : {
         669        10898779 :     Probes::exitJSFun(f.cx, f.fp()->maybeFun(), f.fp()->script());
         670        10898779 :     if (!js::ScriptDebugEpilogue(f.cx, f.fp(), JS_TRUE))
         671              32 :         THROW();
         672                 : }
         673                 :
         674                 : void JS_FASTCALL
         675               0 : stubs::ScriptProbeOnlyPrologue(VMFrame &f)
         676                 : {
         677               0 :     Probes::enterJSFun(f.cx, f.fp()->fun(), f.fp()->script());
         678               0 : }
         679                 :
         680                 : void JS_FASTCALL
         681               0 : stubs::ScriptProbeOnlyEpilogue(VMFrame &f)
         682                 : {
         683               0 :     Probes::exitJSFun(f.cx, f.fp()->fun(), f.fp()->script());
         684               0 : }
         685                 :
         686                 : void JS_FASTCALL
         687            5575 : stubs::CrossChunkShim(VMFrame &f, void *edge_)
         688                 : {
         689           11150 :     DebugOnly<CrossChunkEdge*> edge = (CrossChunkEdge *) edge_;
         690                 :
         691            5575 :     mjit::ExpandInlineFrames(f.cx->compartment);
         692                 :
         693            5575 :     JSScript *script = f.script();
         694            5575 :     JS_ASSERT(edge->target < script->length);
         695            5575 :     JS_ASSERT(script->code + edge->target == f.pc());
         696                 :
         697            5575 :     CompileStatus status = CanMethodJIT(f.cx, script, f.pc(), f.fp()->isConstructing(),
         698            5575 :                                         CompileRequest_Interpreter);
         699            5575 :     if (status == Compile_Error)
         700               0 :         THROW();
         701                 :
         702            5575 :     void **addr = f.returnAddressLocation();
         703            5575 :     *addr = JS_FUNC_TO_DATA_PTR(void *, JaegerInterpoline);
         704                 :
         705            5575 :     f.fp()->setRejoin(StubRejoin(REJOIN_RESUME));
         706                 : }
         707                 :
         708                 : JS_STATIC_ASSERT(JSOP_NOP == 0);
         709                 :
         710                 : /* :XXX: common out with identical copy in Compiler.cpp */
         711                 : #if defined(JS_METHODJIT_SPEW)
         712                 : static const char *OpcodeNames[] = {
         713                 : # define OPDEF(op,val,name,token,length,nuses,ndefs,prec,format) #name,
         714                 : # include "jsopcode.tbl"
         715                 : # undef OPDEF
         716                 : };
         717                 : #endif
         718                 :
         719                 : static void
         720              17 : FinishVarIncOp(VMFrame &f, RejoinState rejoin, Value ov, Value nv, Value *vp)
         721                 : {
         722                 :     /* Finish an increment operation on a LOCAL or ARG. These do not involve property accesses. */
         723              17 :     JS_ASSERT(rejoin == REJOIN_POS || rejoin == REJOIN_BINARY);
         724                 :
         725              17 :     JSContext *cx = f.cx;
         726                 :
         727              17 :     JSOp op = JSOp(*f.pc());
         728               0 :     JS_ASSERT(op == JSOP_LOCALINC || op == JSOP_INCLOCAL ||
         729                 :               op == JSOP_LOCALDEC || op == JSOP_DECLOCAL ||
         730                 :               op == JSOP_ARGINC || op == JSOP_INCARG ||
         731              17 :               op == JSOP_ARGDEC || op == JSOP_DECARG);
         732              17 :     const JSCodeSpec *cs = &js_CodeSpec[op];
         733                 :
         734              17 :     unsigned i = GET_SLOTNO(f.pc());
         735              17 :     Value *var = (JOF_TYPE(cs->format) == JOF_LOCAL) ? f.fp()->slots() + i : &f.fp()->formalArg(i);
         736                 :
         737              17 :     if (rejoin == REJOIN_POS) {
         738               5 :         double d = ov.toNumber();
         739               5 :         double N = (cs->format & JOF_INC) ? 1 : -1;
         740               5 :         if (!nv.setNumber(d + N))
         741               5 :             types::TypeScript::MonitorOverflow(cx, f.script(), f.pc());
         742                 :     }
         743                 :
         744              17 :     *var = nv;
         745              17 :     *vp = (cs->format & JOF_POST) ? ov : nv;
         746              17 : }
         747                 :
         748                 : extern "C" void *
         749           44126 : js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VMFrame &f)
         750                 : {
         751           44126 :     JSRejoinState jsrejoin = f.fp()->rejoin();
         752                 :     RejoinState rejoin;
         753           44126 :     if (jsrejoin & 0x1) {
         754                 :         /* Rejoin after a scripted call finished. Restore f.regs.pc and f.regs.inlined (NULL) */
         755             270 :         uint32_t pcOffset = jsrejoin >> 1;
         756             270 :         f.regs.pc = f.fp()->script()->code + pcOffset;
         757             270 :         f.regs.clearInlined();
         758             270 :         rejoin = REJOIN_SCRIPTED;
         759                 :     } else {
         760           43856 :         rejoin = (RejoinState) (jsrejoin >> 1);
         761                 :     }
         762                 :
         763           44126 :     JSContext *cx = f.cx;
         764           44126 :     StackFrame *fp = f.regs.fp();
         765           44126 :     JSScript *script = fp->script();
         766                 :
         767           44126 :     jsbytecode *pc = f.regs.pc;
         768                 :
         769           44126 :     JSOp op = JSOp(*pc);
         770           44126 :     const JSCodeSpec *cs = &js_CodeSpec[op];
         771                 :
         772           44126 :     if (!script->ensureRanAnalysis(cx, NULL)) {
         773               0 :         js_ReportOutOfMemory(cx);
         774               0 :         return js_InternalThrow(f);
         775                 :     }
         776                 :
         777           88252 :     analyze::AutoEnterAnalysis enter(cx);
         778           44126 :     analyze::ScriptAnalysis *analysis = script->analysis();
         779                 :
         780                 :     /*
         781                 :      * f.regs.sp is not normally maintained by stubs (except for call prologues
         782                 :      * where it indicates the new frame), so is not expected to be coherent
         783                 :      * here. Update it to its value at the start of the opcode.
         784                 :      */
         785           44126 :     Value *oldsp = f.regs.sp;
         786           44126 :     f.regs.sp = fp->base() + analysis->getCode(pc).stackDepth;
         787                 :
         788           44126 :     jsbytecode *nextpc = pc + GetBytecodeLength(pc);
         789           44126 :     Value *nextsp = NULL;
         790           44126 :     if (nextpc != script->code + script->length && analysis->maybeCode(nextpc))
         791           44063 :         nextsp = fp->base() + analysis->getCode(nextpc).stackDepth;
         792                 :
         793           44126 :     JS_ASSERT(&cx->regs() == &f.regs);
         794                 :
         795                 : #ifdef JS_METHODJIT_SPEW
         796                 :     JaegerSpew(JSpew_Recompile, "interpreter rejoin (file \"%s\") (line \"%d\") (op %s) (opline \"%d\")\n",
         797           44126 :                script->filename, script->lineno, OpcodeNames[op], PCToLineNumber(script, pc));
         798                 : #endif
         799                 :
         800           44126 :     uint32_t nextDepth = UINT32_MAX;
         801           44126 :     bool skipTrap = false;
         802                 :
         803           44126 :     if ((cs->format & (JOF_INC | JOF_DEC)) &&
         804                 :         (rejoin == REJOIN_POS || rejoin == REJOIN_BINARY)) {
         805                 :         /*
         806                 :          * We may reenter the interpreter while finishing the INC/DEC operation
         807                 :          * on a local or arg (property INC/DEC operations will rejoin into the
         808                 :          * decomposed version of the op.
         809                 :          */
         810              17 :         JS_ASSERT(cs->format & (JOF_LOCAL | JOF_QARG));
         811                 :
         812              17 :         nextDepth = analysis->getCode(nextpc).stackDepth;
         813              17 :         enter.leave();
         814                 :
         815              17 :         if (rejoin != REJOIN_BINARY || !analysis->incrementInitialValueObserved(pc)) {
         816                 :             /* Stack layout is 'V', 'N' or 'N+1' (only if the N is not needed) */
         817              14 :             FinishVarIncOp(f, rejoin, nextsp[-1], nextsp[-1], &nextsp[-1]);
         818                 :         } else {
         819                 :             /* Stack layout is 'N N+1' */
         820               3 :             FinishVarIncOp(f, rejoin, nextsp[-1], nextsp[0], &nextsp[-1]);
         821                 :         }
         822                 :
         823              17 :         rejoin = REJOIN_FALLTHROUGH;
         824                 :     }
         825                 :
         826           44126 :     switch (rejoin) {
         827                 :       case REJOIN_SCRIPTED: {
         828                 :         jsval_layout rval;
         829                 : #ifdef JS_NUNBOX32
         830             270 :         rval.asBits = ((uint64_t)returnType << 32) | (uint32_t)returnData;
         831                 : #elif JS_PUNBOX64
         832                 :         rval.asBits = (uint64_t)returnType | (uint64_t)returnData;
         833                 : #else
         834                 : #error "Unknown boxing format"
         835                 : #endif
         836                 :
         837             270 :         nextsp[-1] = IMPL_TO_JSVAL(rval);
         838                 :
         839                 :         /*
         840                 :          * When making a scripted call at monitored sites, it is the caller's
         841                 :          * responsibility to update the pushed type set.
         842                 :          */
         843             270 :         types::TypeScript::Monitor(cx, script, pc, nextsp[-1]);
         844             270 :         f.regs.pc = nextpc;
         845             270 :         break;
         846                 :       }
         847                 :
         848                 :       case REJOIN_NONE:
         849               0 :         JS_NOT_REACHED("Unpossible rejoin!");
         850                 :         break;
         851                 :
         852                 :       case REJOIN_RESUME:
         853            6088 :         break;
         854                 :
         855                 :       case REJOIN_TRAP:
         856                 :         /*
         857                 :          * Make sure when resuming in the interpreter we do not execute the
         858                 :          * trap again. Watch out for the case where the trap removed itself.
         859                 :          */
         860              24 :         if (script->hasBreakpointsAt(pc))
         861               8 :             skipTrap = true;
         862              24 :         break;
         863                 :
         864                 :       case REJOIN_FALLTHROUGH:
         865            5455 :         f.regs.pc = nextpc;
         866            5455 :         break;
         867                 :
         868                 :       case REJOIN_NATIVE:
         869                 :       case REJOIN_NATIVE_LOWERED:
         870                 :       case REJOIN_NATIVE_GETTER: {
         871                 :         /*
         872                 :          * We don't rejoin until after the native stub finishes execution, in
         873                 :          * which case the return value will be in memory. For lowered natives,
         874                 :          * the return value will be in the 'this' value's slot.
         875                 :          */
         876             880 :         if (rejoin != REJOIN_NATIVE)
         877               0 :             nextsp[-1] = nextsp[0];
         878                 :
         879                 :         /* Release this reference on the orphaned native stub. */
         880             880 :         RemoveOrphanedNative(cx, fp);
         881                 :
         882             880 :         f.regs.pc = nextpc;
         883             880 :         break;
         884                 :       }
         885                 :
         886                 :       case REJOIN_PUSH_BOOLEAN:
         887               3 :         nextsp[-1].setBoolean(returnReg != NULL);
         888               3 :         f.regs.pc = nextpc;
         889               3 :         break;
         890                 :
         891                 :       case REJOIN_PUSH_OBJECT:
         892               0 :         nextsp[-1].setObject(* (JSObject *) returnReg);
         893               0 :         f.regs.pc = nextpc;
         894               0 :         break;
         895                 :
         896                 :       case REJOIN_DEFLOCALFUN:
         897               0 :         fp->slots()[GET_SLOTNO(pc)].setObject(* (JSObject *) returnReg);
         898               0 :         f.regs.pc = nextpc;
         899               0 :         break;
         900                 :
         901                 :       case REJOIN_THIS_PROTOTYPE: {
         902               0 :         JSObject *callee = &fp->callee();
         903               0 :         JSObject *proto = f.regs.sp[0].isObject() ? &f.regs.sp[0].toObject() : NULL;
         904               0 :         JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
         905               0 :         if (!obj)
         906               0 :             return js_InternalThrow(f);
         907               0 :         fp->formalArgs()[-1].setObject(*obj);
         908                 :
         909               0 :         if (Probes::callTrackingActive(cx))
         910               0 :             Probes::enterJSFun(f.cx, f.fp()->maybeFun(), f.fp()->script());
         911                 :
         912               0 :         if (script->debugMode) {
         913               0 :             JSTrapStatus status = js::ScriptDebugPrologue(f.cx, f.fp());
         914               0 :             switch (status) {
         915                 :               case JSTRAP_CONTINUE:
         916                 :                 break;
         917                 :               case JSTRAP_RETURN:
         918               0 :                 *f.returnAddressLocation() = f.cx->jaegerCompartment()->forceReturnFromExternC();
         919               0 :                 return NULL;
         920                 :               case JSTRAP_THROW:
         921                 :               case JSTRAP_ERROR:
         922               0 :                 return js_InternalThrow(f);
         923                 :               default:
         924               0 :                 JS_NOT_REACHED("bad ScriptDebugPrologue status");
         925                 :             }
         926                 :         }
         927                 :
         928               0 :         break;
         929                 :       }
         930                 :
         931                 :       case REJOIN_CHECK_ARGUMENTS:
         932                 :         /*
         933                 :          * Do all the work needed in arity check JIT prologues after the
         934                 :          * arguments check occurs (FixupArity has been called if needed, but
         935                 :          * the stack check and late prologue have not been performed.
         936                 :          */
         937              20 :         if (!CheckStackQuota(f))
         938               0 :             return js_InternalThrow(f);
         939                 :
         940              20 :         SetValueRangeToUndefined(fp->slots(), script->nfixed);
         941                 :
         942              20 :         if (!fp->functionPrologue(cx))
         943               0 :             return js_InternalThrow(f);
         944                 :         /* FALLTHROUGH */
         945                 :
         946                 :       case REJOIN_FUNCTION_PROLOGUE:
         947              20 :         fp->scopeChain();
         948                 :
         949                 :         /* Construct the 'this' object for the frame if necessary. */
         950              20 :         if (!ScriptPrologueOrGeneratorResume(cx, fp, types::UseNewTypeAtEntry(cx, fp)))
         951               0 :             return js_InternalThrow(f);
         952                 :
         953                 :         /*
         954                 :          * Having called ScriptPrologueOrGeneratorResume, we would normally call
         955                 :          * ScriptDebugPrologue here. But in debug mode, we only use JITted
         956                 :          * functions' invokeEntry entry point, whereas CheckArgumentTypes
         957                 :          * (REJOIN_CHECK_ARGUMENTS) and FunctionFramePrologue
         958                 :          * (REJOIN_FUNCTION_PROLOGUE) are only reachable via the other entry
         959                 :          * points. So we should never need either of these rejoin tails in debug
         960                 :          * mode.
         961                 :          *
         962                 :          * If we fix bug 699196 ("Debug mode code could use inline caches
         963                 :          * now"), then these cases will become reachable again.
         964                 :          */
         965              20 :         JS_ASSERT(!cx->compartment->debugMode());
         966                 :
         967              20 :         break;
         968                 :
         969                 :       case REJOIN_CALL_PROLOGUE:
         970                 :       case REJOIN_CALL_PROLOGUE_LOWERED_CALL:
         971                 :       case REJOIN_CALL_PROLOGUE_LOWERED_APPLY:
         972            8735 :         if (returnReg) {
         973             869 :             uint32_t argc = 0;
         974             869 :             if (rejoin == REJOIN_CALL_PROLOGUE)
         975             869 :                 argc = GET_ARGC(pc);
         976               0 :             else if (rejoin == REJOIN_CALL_PROLOGUE_LOWERED_CALL)
         977               0 :                 argc = GET_ARGC(pc) - 1;
         978                 :             else
         979               0 :                 argc = f.u.call.dynamicArgc;
         980                 :
         981                 :             /*
         982                 :              * The caller frame's code was discarded, but we still need to
         983                 :              * execute the callee and have a JIT code pointer to do so.
         984                 :              * Set the argc and frame registers as the call path does, but set
         985                 :              * the callee frame's return address to jump back into the
         986                 :              * Interpoline, and change the caller frame's rejoin to reflect the
         987                 :              * state after the call.
         988                 :              */
         989             869 :             f.regs.restorePartialFrame(oldsp); /* f.regs.sp stored the new frame */
         990             869 :             f.scratch = (void *) uintptr_t(argc); /* The interpoline will load f.scratch into argc */
         991             869 :             f.fp()->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void *, JaegerInterpolineScripted));
         992             869 :             fp->setRejoin(REJOIN_SCRIPTED | ((pc - script->code) << 1));
         993             869 :             return returnReg;
         994                 :         } else {
         995                 :             /*
         996                 :              * The call has already finished, and the return value is on the
         997                 :              * stack. For lowered call/apply, the return value has been stored
         998                 :              * in the wrong slot, so adjust it here.
         999                 :              */
        1000            7866 :             f.regs.pc = nextpc;
        1001            7866 :             if (rejoin != REJOIN_CALL_PROLOGUE) {
        1002                 :                 /* Same offset return value as for lowered native calls. */
        1003              30 :                 nextsp[-1] = nextsp[0];
        1004                 :             }
        1005                 :         }
        1006            7866 :         break;
        1007                 :
        1008                 :       case REJOIN_CALL_SPLAT: {
        1009                 :         /* Leave analysis early and do the Invoke which SplatApplyArgs prepared. */
        1010               1 :         nextDepth = analysis->getCode(nextpc).stackDepth;
        1011               1 :         enter.leave();
        1012               1 :         f.regs.sp = nextsp + 2 + f.u.call.dynamicArgc;
        1013               1 :         if (!InvokeKernel(cx, CallArgsFromSp(f.u.call.dynamicArgc, f.regs.sp)))
        1014               0 :             return js_InternalThrow(f);
        1015               1 :         nextsp[-1] = nextsp[0];
        1016               1 :         f.regs.pc = nextpc;
        1017               1 :         break;
        1018                 :       }
        1019                 :
        1020                 :       case REJOIN_GETTER:
        1021                 :         /*
        1022                 :          * Match the PC to figure out whether this property fetch is part of a
        1023                 :          * fused opcode which needs to be finished.
        1024                 :          */
        1025           21603 :         switch (op) {
        1026                 :           case JSOP_INSTANCEOF: {
        1027                 :             /*
        1028                 :              * If we recompiled from a getprop used within JSOP_INSTANCEOF,
        1029                 :              * the stack looks like 'LHS RHS protov'. Inline the remaining
        1030                 :              * portion of fun_hasInstance.
        1031                 :              */
        1032               0 :             if (f.regs.sp[0].isPrimitive()) {
        1033               0 :                 js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, f.regs.sp[-1], NULL);
        1034               0 :                 return js_InternalThrow(f);
        1035                 :             }
        1036               0 :             nextsp[-1].setBoolean(js_IsDelegate(cx, &f.regs.sp[0].toObject(), f.regs.sp[-2]));
        1037               0 :             f.regs.pc = nextpc;
        1038               0 :             break;
        1039                 :           }
        1040                 :
        1041                 :           default:
        1042           21603 :             f.regs.pc = nextpc;
        1043           21603 :             break;
        1044                 :         }
        1045           21603 :         break;
        1046                 :
        1047                 :       case REJOIN_POS:
        1048                 :         /* Convert-to-number which might be part of an INC* op. */
        1049              14 :         JS_ASSERT(op == JSOP_POS);
        1050              14 :         f.regs.pc = nextpc;
        1051              14 :         break;
        1052                 :
        1053                 :       case REJOIN_BINARY:
        1054                 :         /* Binary arithmetic op which might be part of an INC* op. */
        1055             158 :         JS_ASSERT(op == JSOP_ADD || op == JSOP_SUB || op == JSOP_MUL || op == JSOP_DIV);
        1056             158 :         f.regs.pc = nextpc;
        1057             158 :         break;
        1058                 :
        1059                 :       case REJOIN_BRANCH: {
        1060                 :         /*
        1061                 :          * This must be an opcode fused with IFNE/IFEQ. Unfused IFNE/IFEQ are
        1062                 :          * implemented in terms of ValueToBoolean, which is infallible and
        1063                 :          * cannot trigger recompilation.
        1064                 :          */
        1065             875 :         bool takeBranch = false;
        1066             875 :         switch (JSOp(*nextpc)) {
        1067                 :           case JSOP_IFNE:
        1068             871 :             takeBranch = returnReg != NULL;
        1069             871 :             break;
        1070                 :           case JSOP_IFEQ:
        1071               4 :             takeBranch = returnReg == NULL;
        1072               4 :             break;
        1073                 :           default:
        1074               0 :             JS_NOT_REACHED("Bad branch op");
        1075                 :         }
        1076             875 :         if (takeBranch)
        1077             868 :             f.regs.pc = nextpc + GET_JUMP_OFFSET(nextpc);
        1078                 :         else
        1079               7 :             f.regs.pc = nextpc + GetBytecodeLength(nextpc);
        1080             875 :         break;
        1081                 :       }
        1082                 :
        1083                 :       default:
        1084               0 :         JS_NOT_REACHED("Missing rejoin");
        1085                 :     }
        1086                 :
        1087           43257 :     if (nextDepth == UINT32_MAX)
        1088           43239 :         nextDepth = analysis->getCode(f.regs.pc).stackDepth;
        1089           43257 :     f.regs.sp = fp->base() + nextDepth;
        1090                 :
        1091                 :     /*
        1092                 :      * Monitor the result of the previous op when finishing a JOF_TYPESET op.
        1093                 :      * The result may not have been marked if we bailed out while inside a stub
        1094                 :      * for the op.
        1095                 :      */
        1096           43257 :     if (f.regs.pc == nextpc && (js_CodeSpec[op].format & JOF_TYPESET))
        1097           35633 :         types::TypeScript::Monitor(cx, script, pc, f.regs.sp[-1]);
        1098                 :
        1099                 :     /* Mark the entry frame as unfinished, and update the regs to resume at. */
        1100           43257 :     JaegerStatus status = skipTrap ? Jaeger_UnfinishedAtTrap : Jaeger_Unfinished;
        1101           43257 :     cx->compartment->jaegerCompartment()->setLastUnfinished(status);
        1102           43257 :     *f.oldregs = f.regs;
        1103                 :
        1104           43257 :     return NULL;
        1105                 : }

Generated by: LCOV version 1.7