Remove JSOP_BEGIN and fix tracer integration issues (bug 603044, r=luke+dmandelin).
authorDavid Anderson <danderson@mozilla.com>
Fri, 15 Oct 2010 11:36:56 -0700
changeset 56201 e000b5963fde57b3f5ec1a379f09bbd0198bd6dc
parent 56200 80dc55aaf0a2c54b7c7f7da2c5c532752059f827
child 56202 ae031ec5ad637a8f259ef5256531a200a14015cd
push idunknown
push userunknown
push dateunknown
reviewersluke
bugs603044
milestone2.0b8pre
Remove JSOP_BEGIN and fix tracer integration issues (bug 603044, r=luke+dmandelin).
js/jsd/idl/jsdIDebuggerService.idl
js/jsd/jsd.h
js/jsd/jsd_scpt.c
js/jsd/jsd_xpc.cpp
js/jsd/jsd_xpc.h
js/jsd/jsdebug.c
js/jsd/jsdebug.h
js/jsd/test/Makefile.in
js/jsd/test/test_bug602003.html
js/src/jscntxt.cpp
js/src/jscntxt.h
js/src/jsdbgapi.cpp
js/src/jsdbgapi.h
js/src/jsemit.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsopcode.tbl
js/src/jspropertycache.cpp
js/src/jsscript.cpp
js/src/jsscriptinlines.h
js/src/jstracer.cpp
js/src/jsxdrapi.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PolyIC.h
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/trace-test/tests/jaeger/bug563000/trap-force-return-1.js
js/src/trace-test/tests/jaeger/bug563000/trap-parent-from-trap.js
js/src/trace-test/tests/jaeger/bug563000/trap-self-from-trap.js
js/src/trace-test/tests/jaeger/deepBailAfterRunTracer.js
--- a/js/jsd/idl/jsdIDebuggerService.idl
+++ b/js/jsd/idl/jsdIDebuggerService.idl
@@ -850,17 +850,17 @@ interface jsdIStackFrame : jsdIEphemeral
                   in unsigned long line, out jsdIValue result);
     
 };
 
 /**
  * Script object.  In JavaScript engine terms, there's a single script for each
  * function, and one for the top level script.
  */
-[scriptable, uuid(53dadd96-69f6-4846-8958-cc8eaa3f9f09)]
+[scriptable, uuid(7e6fb9ed-4382-421d-9a14-c80a486e983b)]
 interface jsdIScript : jsdIEphemeral
 {
     /** Internal use only. */
     [noscript] readonly attribute JSDContext JSDContext;
     /** Internal use only. */
     [noscript] readonly attribute JSDScript  JSDScript;
     
     /**
@@ -997,27 +997,16 @@ interface jsdIScript : jsdIEphemeral
     unsigned long lineToPc (in unsigned long line, in unsigned long pcmap);
     /**
      * Determine is a particular line is executable, like checking that
      * lineToPc == pcToLine, except in one call.
      * The |pcmap| argument specifies which pc to source line map to use.
      */
     boolean isLineExecutable (in unsigned long line, in unsigned long pcmap);
     /**
-     * Get the first valid PC in the script. This will be either
-     * (a) the first bytecode in the script, or (b) the next bytecode
-     * in the script, iff the first bytecode is a JSOP_BEGIN.
-     */
-    unsigned long getFirstValidPC ();
-    /**
-     * Return the last valid PC in the script (i.e., the PC just after 
-     * the last bytecode).
-     */
-    unsigned long getEndValidPC ();
-    /**
      * Set a breakpoint at a PC in this script.
      */
     void setBreakpoint (in unsigned long pc);
     /**
      * Clear a breakpoint at a PC in this script.
      */
     void clearBreakpoint (in unsigned long pc);
     /**
--- a/js/jsd/jsd.h
+++ b/js/jsd/jsd.h
@@ -473,22 +473,16 @@ extern JSBool
 jsd_SetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc hook, void* callerdata);
 
 extern JSBool
 jsd_GetScriptHook(JSDContext* jsdc, JSD_ScriptHookProc* hook, void** callerdata);
 
 extern jsuword
 jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line);
 
-extern jsuword
-jsd_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript);
-
-extern jsuword
-jsd_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript);
-
 extern uintN
 jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc);
 
 extern void
 jsd_NewScriptHookProc(
                 JSContext   *cx,
                 const char  *filename,      /* URL this script loads from */
                 uintN       lineno,         /* line where this script starts */
--- a/js/jsd/jsd_scpt.c
+++ b/js/jsd/jsd_scpt.c
@@ -495,32 +495,30 @@ jsd_GetScriptLineExtent(JSDContext* jsdc
     if( NOT_SET_YET == (int)jsdscript->lineExtent )
         jsdscript->lineExtent = JS_GetScriptLineExtent(jsdc->dumbContext, jsdscript->script);
     return jsdscript->lineExtent;
 }
 
 jsuword
 jsd_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
 {
+#ifdef LIVEWIRE
+    if( jsdscript && jsdscript->lwscript )
+    {
+        uintN newline;
+        jsdlw_RawToProcessedLineNumber(jsdc, jsdscript, line, &newline);
+        if( line != newline )
+            line = newline;
+    }
+#endif
+
     return (jsuword) JS_LineNumberToPC(jsdc->dumbContext, 
                                        jsdscript->script, line );
 }
 
-jsuword
-jsd_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript)
-{
-    return (jsuword) JS_FirstValidPC(jsdc->dumbContext, jsdscript->script );
-}
-
-jsuword
-jsd_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript)
-{
-    return (jsuword) JS_EndPC(jsdc->dumbContext, jsdscript->script );
-}
-
 uintN
 jsd_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
 {
     uintN first = jsdscript->lineBase;
     uintN last = first + jsd_GetScriptLineExtent(jsdc, jsdscript) - 1;
     uintN line = pc
         ? JS_PCToLineNumber(jsdc->dumbContext, 
                             jsdscript->script,
--- a/js/jsd/jsd_xpc.cpp
+++ b/js/jsd/jsd_xpc.cpp
@@ -953,34 +953,30 @@ jsdScript::jsdScript (JSDContext *aCx, J
                                                              mTag(0),
                                                              mCx(aCx),
                                                              mScript(aScript),
                                                              mFileName(0), 
                                                              mFunctionName(0),
                                                              mBaseLineNumber(0),
                                                              mLineExtent(0),
                                                              mPPLineMap(0),
-                                                             mFirstValidPC(0),
-                                                             mFirstPC(0),
-                                                             mEndPC(0)
+                                                             mFirstPC(0)
 {
     DEBUG_CREATE ("jsdScript", gScriptCount);
 
     if (mScript) {
         /* copy the script's information now, so we have it later, when it
          * gets destroyed. */
         JSD_LockScriptSubsystem(mCx);
         mFileName = new nsCString(JSD_GetScriptFilename(mCx, mScript));
         mFunctionName =
             new nsCString(JSD_GetScriptFunctionName(mCx, mScript));
         mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
         mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
         mFirstPC = JSD_GetClosestPC(mCx, mScript, 0);
-        mFirstValidPC = JSD_GetFirstValidPC(mCx, mScript);
-        mEndPC = JSD_GetEndPC(mCx, mScript);
         JSD_UnlockScriptSubsystem(mCx);
         
         mValid = PR_TRUE;
     }
 }
 
 jsdScript::~jsdScript () 
 {
@@ -1475,32 +1471,16 @@ jsdScript::IsLineExecutable(PRUint32 aLi
     } else {
         return NS_ERROR_INVALID_ARG;
     }
     
     return NS_OK;
 }
 
 NS_IMETHODIMP
-jsdScript::GetFirstValidPC(PRUint32 *_rval)
-{
-    ASSERT_VALID_EPHEMERAL;
-    *_rval = PRUint32(mFirstValidPC - mFirstPC);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
-jsdScript::GetEndValidPC(PRUint32 *_rval)
-{
-    ASSERT_VALID_EPHEMERAL;
-    *_rval = PRUint32(mEndPC - mFirstPC);
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 jsdScript::SetBreakpoint(PRUint32 aPC)
 {
     ASSERT_VALID_EPHEMERAL;
     jsuword pc = mFirstPC + aPC;
     JSD_SetExecutionHook (mCx, mScript, pc, jsds_ExecutionHookProc, NULL);
     return NS_OK;
 }
 
--- a/js/jsd/jsd_xpc.h
+++ b/js/jsd/jsd_xpc.h
@@ -177,19 +177,17 @@ class jsdScript : public jsdIScript
     PRUint32    mTag;
     JSDContext *mCx;
     JSDScript  *mScript;
     nsCString  *mFileName;
     nsCString  *mFunctionName;
     PRUint32    mBaseLineNumber, mLineExtent;
     PCMapEntry *mPPLineMap;
     PRUint32    mPCMapSize;
-    jsuword     mFirstPC;        /* address of first PC in script */
-    jsuword     mFirstValidPC;   /* address of first valid bkpt PC */
-    jsuword     mEndPC;          /* address of end of script code */
+    jsuword     mFirstPC;
 };
 
 PRUint32 jsdScript::LastTag = 0;
 
 class jsdContext : public jsdIContext
 {
   public:
     NS_DECL_ISUPPORTS
--- a/js/jsd/jsdebug.c
+++ b/js/jsd/jsdebug.c
@@ -343,32 +343,16 @@ JSD_GetScriptHook(JSDContext* jsdc, JSD_
 JSD_PUBLIC_API(jsuword)
 JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     JSD_ASSERT_VALID_SCRIPT(jsdscript);
     return jsd_GetClosestPC(jsdc, jsdscript, line);
 }
 
-JSD_PUBLIC_API(jsuword)
-JSD_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript)
-{
-    JSD_ASSERT_VALID_CONTEXT(jsdc);
-    JSD_ASSERT_VALID_SCRIPT(jsdscript);
-    return jsd_GetFirstValidPC(jsdc, jsdscript);
-}
-
-JSD_PUBLIC_API(jsuword)
-JSD_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript)
-{
-    JSD_ASSERT_VALID_CONTEXT(jsdc);
-    JSD_ASSERT_VALID_SCRIPT(jsdscript);
-    return jsd_GetEndPC(jsdc, jsdscript);
-}
-
 JSD_PUBLIC_API(uintN)
 JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc)
 {
     JSD_ASSERT_VALID_CONTEXT(jsdc);
     JSD_ASSERT_VALID_SCRIPT(jsdscript);
     return jsd_GetClosestLine(jsdc, jsdscript, pc);
 }
 
--- a/js/jsd/jsdebug.h
+++ b/js/jsd/jsdebug.h
@@ -482,29 +482,16 @@ JSD_GetScriptHook(JSDContext* jsdc, JSD_
 * If no code is on the given line, then the returned pc represents the first
 * code within the script (if any) after the given line.
 * This function can be used to set breakpoints -- see JSD_SetExecutionHook
 */
 extern JSD_PUBLIC_API(jsuword)
 JSD_GetClosestPC(JSDContext* jsdc, JSDScript* jsdscript, uintN line);
 
 /*
-* Get the first 'Program Counter' value where a breakpoint can be set.
-*/
-extern JSD_PUBLIC_API(jsuword)
-JSD_GetFirstValidPC(JSDContext* jsdc, JSDScript* jsdscript);
-
-/*
-* Get the 'Program Counter' value just after the last byte of the script.
-* 0 is returned for invalid scripts.
-*/
-extern JSD_PUBLIC_API(jsuword)
-JSD_GetEndPC(JSDContext* jsdc, JSDScript* jsdscript);
-
-/*
 * Get the source line number for a given 'Program Counter' location.
 * Returns 0 if no source line information is appropriate (or available) for
 * the given pc.
 */
 extern JSD_PUBLIC_API(uintN)
 JSD_GetClosestLine(JSDContext* jsdc, JSDScript* jsdscript, jsuword pc);
 
 /* these are only used in cases where scripts are created outside of JS*/
--- a/js/jsd/test/Makefile.in
+++ b/js/jsd/test/Makefile.in
@@ -43,13 +43,12 @@ relativesrcdir  = js/jsd/test
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE = jsdebug
 
 include $(topsrcdir)/config/rules.mk
 
 _TEST_FILES = 	test_bug507448.html \
-                test_bug602003.html \
 		$(NULL)
 
 libs:: $(_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
deleted file mode 100644
--- a/js/jsd/test/test_bug602003.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=507448
--->
-<head>
-  <title>Test for Bug 602003</title>
-  <script type="application/javascript" src="/MochiKit/packed.js"></script>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=507448">Mozilla Bug 507448</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-  
-</div>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 602003 **/
-
-// This is somewhat unfortunate: jsd only deals with scripts that have a
-// nonzero line number, so we can't just createElement a script here.
-// So break the test up into three <script>s, of which the middle one has our test functions.
-
-netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-var jsdIDebuggerService = Components.interfaces.jsdIDebuggerService;
-var jsd = Components.classes['@mozilla.org/js/jsd/debugger-service;1']
-                    .getService(jsdIDebuggerService);
-var jsdOn = jsd.isOn;
-if (!jsdOn) {
-  jsd.on();
-  ok(jsd.isOn, "JSD should be running.");
-}
-</script>
-<script>
-  function g(a,b) { return a + b }
-</script>
-<script>
-  netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-  var script = jsd.wrapValue(g).script;
-
-  // Test the script start/end PC APIs.
-  var start = script.getFirstValidPC();
-  var end = script.getEndValidPC();
-
-  // Start PC should be 1 for a function because it starts with JSOP_BEGIN.
-  is(start, 1, "Start PC should be 1");
-
-  // End PC should be something greater than 1, and not huge. Changes
-  // in the bytecode will change this, so we'll just be approximate.
-  ok(1 < end && end < 100, "End PC doesn't seem sane.");
-
-  if (!jsdOn) {
-    jsd.off();
-    ok(!jsd.isOn, "JSD shouldn't be running anymore.");
-  }
-</script>
-</pre>
-</body>
-</html>
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -470,19 +470,17 @@ AllFramesIter::AllFramesIter(JSContext *
 {
 }
 
 AllFramesIter&
 AllFramesIter::operator++()
 {
     JS_ASSERT(!done());
     if (curfp == curcs->getInitialFrame()) {
-        do {
-            curcs = curcs->getPreviousInMemory();
-        } while (curcs && !curcs->inContext());
+        curcs = curcs->getPreviousInMemory();
         curfp = curcs ? curcs->getCurrentFrame() : NULL;
     } else {
         curfp = curfp->prev();
     }
     return *this;
 }
 
 bool
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -2003,17 +2003,17 @@ struct JSContext
 
     bool hasfp() {
         JS_ASSERT_IF(regs, regs->fp);
         return !!regs;
     }
 
   public:
     friend class js::StackSpace;
-    friend bool js::Interpret(JSContext *, JSStackFrame *, uintN, uintN);
+    friend bool js::Interpret(JSContext *, JSStackFrame *, uintN, JSInterpMode);
 
     void resetCompartment();
 
     /* 'regs' must only be changed by calling this function. */
     void setCurrentRegs(JSFrameRegs *regs) {
         JS_ASSERT_IF(regs, regs->fp);
         this->regs = regs;
         if (!regs)
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -230,22 +230,16 @@ JS_SetTrap(JSContext *cx, JSScript *scri
         return JS_FALSE;
 
     if (script == JSScript::emptyScript()) {
         JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
                                      NULL, JSMSG_READ_ONLY, "empty script");
         return JS_FALSE;
     }
 
-    if (JSOp(*pc) == JSOP_BEGIN) {
-        JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR, js_GetErrorMessage,
-                                     NULL, JSMSG_READ_ONLY, "trap invalid on BEGIN opcode");
-        return JS_FALSE;
-    }
-
     JS_ASSERT((JSOp) *pc != JSOP_TRAP);
     junk = NULL;
     rt = cx->runtime;
     DBG_LOCK(rt);
     trap = FindTrap(rt, script, pc);
     if (trap) {
         JS_ASSERT(trap->script == script && trap->pc == pc);
         JS_ASSERT(*pc == JSOP_TRAP);
@@ -1017,23 +1011,16 @@ JS_PCToLineNumber(JSContext *cx, JSScrip
 
 JS_PUBLIC_API(jsbytecode *)
 JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno)
 {
     return js_LineNumberToPC(script, lineno);
 }
 
 JS_PUBLIC_API(jsbytecode *)
-JS_FirstValidPC(JSContext *cx, JSScript *script)
-{
-    jsbytecode *pc = script->code;
-    return *pc == JSOP_BEGIN ? pc + JSOP_BEGIN_LENGTH : pc;
-}
-
-JS_PUBLIC_API(jsbytecode *)
 JS_EndPC(JSContext *cx, JSScript *script)
 {
     return script->code + script->length;
 }
 
 JS_PUBLIC_API(uintN)
 JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun)
 {
--- a/js/src/jsdbgapi.h
+++ b/js/src/jsdbgapi.h
@@ -155,19 +155,16 @@ js_WrapWatchedSetter(JSContext *cx, jsid
 
 extern JS_PUBLIC_API(uintN)
 JS_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc);
 
 extern JS_PUBLIC_API(jsbytecode *)
 JS_LineNumberToPC(JSContext *cx, JSScript *script, uintN lineno);
 
 extern JS_PUBLIC_API(jsbytecode *)
-JS_FirstValidPC(JSContext *cx, JSScript *script);
-
-extern JS_PUBLIC_API(jsbytecode *)
 JS_EndPC(JSContext *cx, JSScript *script);
 
 extern JS_PUBLIC_API(uintN)
 JS_GetFunctionArgumentCount(JSContext *cx, JSFunction *fun);
 
 extern JS_PUBLIC_API(JSBool)
 JS_FunctionHasLocalNames(JSContext *cx, JSFunction *fun);
 
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -3708,25 +3708,20 @@ out:
 bad:
     ok = JS_FALSE;
     goto out;
 }
 
 JSBool
 js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body)
 {
-    CG_SWITCH_TO_PROLOG(cg);
-    JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));
-    if (js_Emit1(cx, cg, JSOP_BEGIN) < 0)
-        return false;
-    CG_SWITCH_TO_MAIN(cg);
-
     if (cg->flags & TCF_FUN_IS_GENERATOR) {
-        /* JSOP_GENERATOR must be the first real instruction. */
+        /* JSOP_GENERATOR must be the first instruction. */
         CG_SWITCH_TO_PROLOG(cg);
+        JS_ASSERT(CG_NEXT(cg) == CG_BASE(cg));
         if (js_Emit1(cx, cg, JSOP_GENERATOR) < 0)
             return false;
         CG_SWITCH_TO_MAIN(cg);
     }
 
     if (cg->needsEagerArguments()) {
         CG_SWITCH_TO_PROLOG(cg);
         if (js_Emit1(cx, cg, JSOP_ARGUMENTS) < 0 || js_Emit1(cx, cg, JSOP_POP) < 0)
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -77,17 +77,16 @@
 #include "jsvector.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/Logging.h"
 
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
 #include "jsinterpinlines.h"
 #include "jsobjinlines.h"
-#include "jsprobes.h"
 #include "jspropertycacheinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsstrinlines.h"
 #include "jsopcodeinlines.h"
 
 #if JS_HAS_XML_SUPPORT
 #include "jsxml.h"
@@ -729,37 +728,22 @@ Invoke(JSContext *cx, const CallArgs &ar
             JSObject *thisp = thisv.toObject().thisObject(cx);
             if (!thisp)
                  return false;
             JS_ASSERT(IsSaneThisObject(*thisp));
             thisv.setObject(*thisp);
         }
     }
 
-    JSInterpreterHook hook = cx->debugHooks->callHook;
-    void *hookData = NULL;
-    if (JS_UNLIKELY(hook != NULL))
-        hookData = hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData);
-
     /* Run function until JSOP_STOP, JSOP_RETURN or error. */
     JSBool ok;
     {
         AutoPreserveEnumerators preserve(cx);
-        Probes::enterJSFun(cx, fun);
         ok = RunScript(cx, script, fp);
-        Probes::exitJSFun(cx, fun);
-    }
-
-    if (JS_UNLIKELY(hookData != NULL)) {
-        hook = cx->debugHooks->callHook;
-        if (hook)
-            hook(cx, fp, JS_FALSE, &ok, hookData);
-    }
-
-    PutActivationObjects(cx, fp);
+    }
 
     args.rval() = fp->returnValue();
     JS_ASSERT_IF(ok && (flags & JSINVOKE_CONSTRUCT), !args.rval().isPrimitive());
 
     return ok;
 }
 
 bool
@@ -2156,21 +2140,38 @@ IteratorNext(JSContext *cx, JSObject *it
             *rval = *ni->currentValue();
             ni->incValueCursor();
             return true;
         }
     }
     return js_IteratorNext(cx, iterobj, rval);
 }
 
+static inline bool
+ScriptPrologue(JSContext *cx, JSStackFrame *fp)
+{
+    if (fp->isConstructing()) {
+        JSObject *obj = js_CreateThisForFunction(cx, &fp->callee());
+        if (!obj)
+            return false;
+        fp->functionThis().setObject(*obj);
+    }
+    JSInterpreterHook hook = cx->debugHooks->callHook;
+    if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame())
+        fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
+
+    Probes::enterJSFun(cx, fp->maybeFun());
+
+    return true;
+}
 
 namespace js {
 
 JS_REQUIRES_STACK JS_NEVER_INLINE bool
-Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, uintN interpFlags)
+Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInterpMode interpMode)
 {
 #ifdef MOZ_TRACEVIS
     TraceVisStateObj tvso(cx, S_INTERP);
 #endif
     JSAutoResolveFlags rf(cx, JSRESOLVE_INFER);
 
 # ifdef DEBUG
     /*
@@ -2391,17 +2392,17 @@ Interpret(JSContext *cx, JSStackFrame *e
 #if defined(JS_TRACER) && defined(JS_METHODJIT)
 # define LEAVE_ON_SAFE_POINT()                                                \
     do {                                                                      \
         JS_ASSERT_IF(leaveOnSafePoint, !TRACE_RECORDER(cx));                  \
         if (leaveOnSafePoint && !regs.fp->hasImacropc() &&                    \
             script->maybeNativeCodeForPC(regs.fp->isConstructing(), regs.pc)) { \
             JS_ASSERT(!TRACE_RECORDER(cx));                                   \
             interpReturnOK = true;                                            \
-            goto stop_recording;                                              \
+            goto leave_on_safe_point;                                         \
         }                                                                     \
     } while (0)
 #else
 # define LEAVE_ON_SAFE_POINT() /* nop */
 #endif
 
 #define BRANCH(n)                                                             \
     JS_BEGIN_MACRO                                                            \
@@ -2427,35 +2428,47 @@ Interpret(JSContext *cx, JSStackFrame *e
     JS_BEGIN_MACRO                                                            \
         if (cx->debugHooks->interruptHook)                                    \
             ENABLE_INTERRUPTS();                                              \
     JS_END_MACRO
 
     /* Check for too deep of a native thread stack. */
     JS_CHECK_RECURSION(cx, return JS_FALSE);
 
-    MUST_FLOW_THROUGH("exit");
-    ++cx->interpLevel;
+    JSFrameRegs regs = *cx->regs;
 
     /* Repoint cx->regs to a local variable for faster access. */
-    JSFrameRegs *const prevContextRegs = cx->regs;
-    JSFrameRegs regs = *cx->regs;
-    cx->setCurrentRegs(&regs);
+    struct InterpExitGuard {
+        JSContext *cx;
+        const JSFrameRegs &regs;
+        JSFrameRegs *prevContextRegs;
+        InterpExitGuard(JSContext *cx, JSFrameRegs &regs)
+          : cx(cx), regs(regs), prevContextRegs(cx->regs) {
+            cx->setCurrentRegs(&regs);
+            ++cx->interpLevel;
+        }
+        ~InterpExitGuard() {
+            --cx->interpLevel;
+            JS_ASSERT(cx->regs == &regs);
+            *prevContextRegs = regs;
+            cx->setCurrentRegs(prevContextRegs);
+        }
+    } interpGuard(cx, regs);
 
     /* Copy in hot values that change infrequently. */
     JSRuntime *const rt = cx->runtime;
     JSScript *script = regs.fp->script();
     Value *argv = regs.fp->maybeFormalArgs();
     CHECK_INTERRUPT_HANDLER();
 
     JS_ASSERT(!script->isEmpty());
     JS_ASSERT(script->length > 1);
 
 #if defined(JS_TRACER) && defined(JS_METHODJIT)
-    bool leaveOnSafePoint = !!(interpFlags & JSINTERP_SAFEPOINT);
+    bool leaveOnSafePoint = (interpMode == JSINTERP_SAFEPOINT);
 # define CLEAR_LEAVE_ON_TRACE_POINT() ((void) (leaveOnSafePoint = false))
 #else
 # define CLEAR_LEAVE_ON_TRACE_POINT() ((void) 0)
 #endif
 
     if (!entryFrame)
         entryFrame = regs.fp;
 
@@ -2465,17 +2478,17 @@ Interpret(JSContext *cx, JSStackFrame *e
      * the atom map to turn frequently executed LOAD_ATOM into simple array
      * access. For less frequent object and regexp loads we have to recover
      * the segment from atoms pointer first.
      */
     JSAtom **atoms = script->atomMap.vector;
 
 #if JS_HAS_GENERATORS
     if (JS_UNLIKELY(regs.fp->isGeneratorFrame())) {
-        JS_ASSERT(prevContextRegs == &cx->generatorFor(regs.fp)->regs);
+        JS_ASSERT(interpGuard.prevContextRegs == &cx->generatorFor(regs.fp)->regs);
         JS_ASSERT((size_t) (regs.pc - script->code) <= script->length);
         JS_ASSERT((size_t) (regs.sp - regs.fp->base()) <= StackDepth(script));
 
         /*
          * To support generator_throw and to catch ignored exceptions,
          * fail if cx->throwing is set.
          */
         if (cx->throwing)
@@ -2484,27 +2497,36 @@ Interpret(JSContext *cx, JSStackFrame *e
 #endif
 
 #ifdef JS_TRACER
     /*
      * The method JIT may have already initiated a recording, in which case
      * there should already be a valid recorder. Otherwise...
      * we cannot reenter the interpreter while recording.
      */
-    if (interpFlags & JSINTERP_RECORD) {
+    if (interpMode == JSINTERP_RECORD) {
         JS_ASSERT(TRACE_RECORDER(cx));
         ENABLE_INTERRUPTS();
     } else if (TRACE_RECORDER(cx)) {
         AbortRecording(cx, "attempt to reenter interpreter while recording");
     }
 
     if (regs.fp->hasImacropc())
         atoms = COMMON_ATOMS_START(&rt->atomState);
 #endif
 
+    /* Don't call the script prologue if executing between Method and Trace JIT. */
+    if (interpMode == JSINTERP_NORMAL) {
+        JS_ASSERT_IF(!regs.fp->isGeneratorFrame(), regs.pc == script->code);
+        if (!ScriptPrologue(cx, regs.fp))
+            goto error;
+    }
+
+    CHECK_INTERRUPT_HANDLER();
+
     /* State communicated between non-local jumps: */
     JSBool interpReturnOK;
     JSAtom *atomNotDefined;
 
     /*
      * It is important that "op" be initialized before calling DO_OP because
      * it is possible for "op" to be specially assigned during the normal
      * processing of an opcode while looping. We rely on DO_NEXT_OP to manage
@@ -2580,17 +2602,18 @@ Interpret(JSContext *cx, JSStackFrame *e
             moreInterrupts = true;
         }
 
 #ifdef JS_TRACER
         if (TraceRecorder* tr = TRACE_RECORDER(cx)) {
             AbortableRecordingStatus status = tr->monitorRecording(op);
             JS_ASSERT_IF(cx->throwing, status == ARECORD_ERROR);
 
-            if (interpFlags & (JSINTERP_RECORD | JSINTERP_SAFEPOINT)) {
+            if (interpMode != JSINTERP_NORMAL) {
+                JS_ASSERT(interpMode == JSINTERP_RECORD || JSINTERP_SAFEPOINT);
                 switch (status) {
                   case ARECORD_IMACRO_ABORTED:
                   case ARECORD_ABORTED:
                   case ARECORD_COMPLETED:
                   case ARECORD_STOP:
 #ifdef JS_METHODJIT
                     leaveOnSafePoint = true;
                     LEAVE_ON_SAFE_POINT();
@@ -2755,37 +2778,21 @@ BEGIN_CASE(JSOP_STOP)
     }
 #endif
 
     interpReturnOK = true;
     if (entryFrame != regs.fp)
   inline_return:
     {
         JS_ASSERT(!js_IsActiveWithOrBlock(cx, &regs.fp->scopeChain(), 0));
-        if (JS_UNLIKELY(regs.fp->hasHookData())) {
-            if (JSInterpreterHook hook = cx->debugHooks->callHook) {
-                hook(cx, regs.fp, JS_FALSE, &interpReturnOK, regs.fp->hookData());
-                CHECK_INTERRUPT_HANDLER();
-            }
-        }
-
-        PutActivationObjects(cx, regs.fp);
-
-        Probes::exitJSFun(cx, regs.fp->maybeFun());
-
-        /*
-         * If inline-constructing, replace primitive rval with the new object
-         * passed in via |this|, and instrument this constructor invocation.
-         */
-        if (regs.fp->isConstructing()) {
-            if (regs.fp->returnValue().isPrimitive())
-                regs.fp->setReturnValue(ObjectValue(regs.fp->constructorThis()));
-            JS_RUNTIME_METER(cx->runtime, constructs);
-        }
-
+        interpReturnOK = ScriptEpilogue(cx, regs.fp, interpReturnOK);
+        CHECK_INTERRUPT_HANDLER();
+
+        /* The JIT inlines ScriptEpilogue. */
+  jit_return:
         Value *newsp = regs.fp->actualArgs() - 1;
         newsp[-1] = regs.fp->returnValue();
         cx->stack().popInlineFrame(cx, regs.fp->prev(), newsp);
 
         /* Sync interpreter registers. */
         script = regs.fp->script();
         argv = regs.fp->maybeFormalArgs();
         atoms = FrameAtomBase(cx, regs.fp);
@@ -2798,28 +2805,16 @@ BEGIN_CASE(JSOP_STOP)
                       == JSOP_CALL_LENGTH);
             TRACE_0(LeaveFrame);
             len = JSOP_CALL_LENGTH;
             DO_NEXT_OP(len);
         }
         goto error;
     } else {
         JS_ASSERT(regs.sp == regs.fp->base());
-        if (regs.fp->isConstructing() && regs.fp->returnValue().isPrimitive())
-            regs.fp->setReturnValue(ObjectValue(regs.fp->constructorThis()));
-
-#if defined(JS_TRACER) && defined(JS_METHODJIT)
-        /* Hack: re-push rval so either JIT will read it properly. */
-        regs.fp->setBailedAtReturn();
-        if (TRACE_RECORDER(cx)) {
-            AbortRecording(cx, "recording out of Interpret");
-            interpReturnOK = true;
-            goto stop_recording;
-        }
-#endif
     }
     interpReturnOK = true;
     goto exit;
 }
 
 BEGIN_CASE(JSOP_DEFAULT)
     regs.sp--;
     /* FALL THROUGH */
@@ -4564,51 +4559,16 @@ BEGIN_CASE(JSOP_ENUMELEM)
     FETCH_ELEMENT_ID(obj, -1, id);
     Value rval = regs.sp[-3];
     if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
         goto error;
     regs.sp -= 3;
 }
 END_CASE(JSOP_ENUMELEM)
 
-BEGIN_CASE(JSOP_BEGIN)
-{
-    if (regs.fp->isConstructing()) {
-        JSObject *obj2 = js_CreateThisForFunction(cx, &regs.fp->callee());
-        if (!obj2)
-            goto error;
-        regs.fp->functionThis().setObject(*obj2);
-    }
-
-    /* Call the debugger hook if present. */
-    if (JSInterpreterHook hook = cx->debugHooks->callHook) {
-        regs.fp->setHookData(hook(cx, regs.fp, JS_TRUE, 0,
-                                  cx->debugHooks->callHookData));
-        CHECK_INTERRUPT_HANDLER();
-    }
-
-    JS_RUNTIME_METER(rt, inlineCalls);
-
-    Probes::enterJSFun(cx, regs.fp->fun());
-
-#ifdef JS_METHODJIT
-    /* Try to ensure methods are method JIT'd.  */
-    mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp);
-    if (status == mjit::Compile_Error)
-        goto error;
-    if (!TRACE_RECORDER(cx) && status == mjit::Compile_Okay) {
-        if (!mjit::JaegerShot(cx))
-            goto error;
-        interpReturnOK = true;
-        goto inline_return;
-    }
-#endif
-}
-END_CASE(JSOP_BEGIN)
-
 {
     JSFunction *newfun;
     JSObject *callee;
     uint32 flags;
     uintN argc;
     Value *vp;
 
 BEGIN_CASE(JSOP_NEW)
@@ -4698,22 +4658,41 @@ BEGIN_CASE(JSOP_APPLY)
             argv = regs.fp->formalArgsEnd() - newfun->nargs;
             atoms = script->atomMap.vector;
 
             /* Now that the new frame is rooted, maybe create a call object. */
             if (newfun->isHeavyweight() && !js_GetCallObject(cx, regs.fp))
                 goto error;
 
             inlineCallCount++;
+            JS_RUNTIME_METER(rt, inlineCalls);
 
             TRACE_0(EnterFrame);
 
+            CHECK_INTERRUPT_HANDLER();
+
+#ifdef JS_METHODJIT
+            /* Try to ensure methods are method JIT'd.  */
+            mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, regs.fp);
+            if (status == mjit::Compile_Error)
+                goto error;
+            if (!TRACE_RECORDER(cx) && status == mjit::Compile_Okay) {
+                interpReturnOK = mjit::JaegerShot(cx);
+                CHECK_INTERRUPT_HANDLER();
+                goto jit_return;
+            }
+#endif
+
+            if (!ScriptPrologue(cx, regs.fp))
+                goto error;
+
+            CHECK_INTERRUPT_HANDLER();
+
             /* Load first op and dispatch it (safe since JSOP_STOP). */
             op = (JSOp) *regs.pc;
-            JS_ASSERT(op == JSOP_BEGIN);
             DO_OP();
         }
 
         Probes::enterJSFun(cx, newfun);
         JSBool ok = CallJSNative(cx, newfun->u.n.native, argc, vp);
         Probes::exitJSFun(cx, newfun);
         regs.sp = vp + 1;
         if (!ok)
@@ -6928,58 +6907,57 @@ END_CASE(JSOP_ARRAYPUSH)
 #ifdef DEBUG
     cx->tracePrevPc = NULL;
 #endif
 
     if (entryFrame != regs.fp)
         goto inline_return;
 
   exit:
+    interpReturnOK = ScriptEpilogue(cx, regs.fp, interpReturnOK);
+    regs.fp->setFinishedInInterpreter();
+
     /*
      * At this point we are inevitably leaving an interpreted function or a
      * top-level script, and returning to one of:
      * (a) an "out of line" call made through js_Invoke;
      * (b) a js_Execute activation;
      * (c) a generator (SendToGenerator, jsiter.c).
      *
      * We must not be in an inline frame. The check above ensures that for the
      * error case and for a normal return, the code jumps directly to parent's
      * frame pc.
      */
     JS_ASSERT(entryFrame == regs.fp);
-    JS_ASSERT(cx->regs == &regs);
-    *prevContextRegs = regs;
-    cx->setCurrentRegs(prevContextRegs);
 
 #ifdef JS_TRACER
-    JS_ASSERT_IF(interpReturnOK && (interpFlags & JSINTERP_RECORD), !TRACE_RECORDER(cx));
+    JS_ASSERT_IF(interpReturnOK && interpMode == JSINTERP_RECORD, !TRACE_RECORDER(cx));
     if (TRACE_RECORDER(cx))
         AbortRecording(cx, "recording out of Interpret");
 #endif
 
     JS_ASSERT_IF(!regs.fp->isGeneratorFrame(), !js_IsActiveWithOrBlock(cx, &regs.fp->scopeChain(), 0));
 
-    --cx->interpLevel;
-
     return interpReturnOK;
 
   atom_not_defined:
     {
         const char *printable;
 
         printable = js_AtomToPrintableString(cx, atomNotDefined);
         if (printable)
             js_ReportIsNotDefined(cx, printable);
         goto error;
     }
 
+    /*
+     * This path is used when it's guaranteed the method can be finished
+     * inside the JIT.
+     */
 #if defined(JS_TRACER) && defined(JS_METHODJIT)
-  stop_recording:
+  leave_on_safe_point:
 #endif
-    JS_ASSERT(cx->regs == &regs);
-    *prevContextRegs = regs;
-    cx->setCurrentRegs(prevContextRegs);
     return interpReturnOK;
 }
 
 } /* namespace js */
 
 #endif /* !defined jsinvoke_cpp___ */
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -54,20 +54,21 @@ struct JSFrameRegs
 {
     STATIC_SKIP_INFERENCE
     js::Value       *sp;                  /* stack pointer */
     jsbytecode      *pc;                  /* program counter */
     JSStackFrame    *fp;                  /* active frame */
 };
 
 /* Flags to toggle js::Interpret() execution. */
-enum JSInterpFlags
+enum JSInterpMode
 {
-    JSINTERP_RECORD            =     0x1, /* interpreter has been started to record/run traces */
-    JSINTERP_SAFEPOINT         =     0x2  /* interpreter should leave on a method JIT safe point */
+    JSINTERP_NORMAL            =     0, /* Interpreter is running normally. */
+    JSINTERP_RECORD            =     1, /* interpreter has been started to record/run traces */
+    JSINTERP_SAFEPOINT         =     2  /* interpreter should leave on a method JIT safe point */
 };
 
 /* Flags used in JSStackFrame::flags_ */
 enum JSFrameFlags
 {
     /* Primary frame type */
     JSFRAME_GLOBAL             =     0x1, /* frame pushed for a global script */
     JSFRAME_FUNCTION           =     0x2, /* frame pushed for a scripted call */
@@ -78,17 +79,17 @@ enum JSFrameFlags
     JSFRAME_DEBUGGER           =    0x10, /* frame pushed by JS_EvaluateInStackFrame */
     JSFRAME_GENERATOR          =    0x20, /* frame is associated with a generator */
     JSFRAME_FLOATING_GENERATOR =    0x40, /* frame is is in generator obj, not on stack */
     JSFRAME_CONSTRUCTING       =    0x80, /* frame is for a constructor invocation */
 
     /* Temporary frame states */
     JSFRAME_ASSIGNING          =   0x100, /* not-JOF_ASSIGNING op is assigning */
     JSFRAME_YIELDING           =   0x200, /* js::Interpret dispatched JSOP_YIELD */
-    JSFRAME_BAILED_AT_RETURN   =   0x400, /* bailed at JSOP_RETURN */
+    JSFRAME_FINISHED_IN_INTERPRETER = 0x400, /* set if frame finished in Interpret() */
 
     /* Concerning function arguments */
     JSFRAME_OVERRIDE_ARGS      =  0x1000, /* overridden arguments local variable */
     JSFRAME_OVERFLOW_ARGS      =  0x2000, /* numActualArgs > numFormalArgs */
     JSFRAME_UNDERFLOW_ARGS     =  0x4000, /* numActualArgs < numFormalArgs */
 
     /* Lazy frame initialization */
     JSFRAME_HAS_IMACRO_PC      =   0x8000, /* frame has imacpc value available */
@@ -168,16 +169,20 @@ struct JSStackFrame
         return !!(flags_ & (JSFRAME_FUNCTION | JSFRAME_GLOBAL));
     }
 
     bool isEvalFrame() const {
         JS_ASSERT_IF(flags_ & JSFRAME_EVAL, isScriptFrame());
         return flags_ & JSFRAME_EVAL;
     }
 
+    bool isExecuteFrame() const {
+        return !!(flags_ & (JSFRAME_GLOBAL | JSFRAME_EVAL));
+    }
+
     /*
      * Frame initialization
      *
      * After acquiring a pointer to an uninitialized stack frame on the VM
      * stack from js::StackSpace, these members are used to initialize the
      * stack frame before officially pushing the frame into the context.
      * Collecting frame initialization into a set of inline helpers allows
      * simpler reasoning and makes call-optimization easier.
@@ -675,22 +680,22 @@ struct JSStackFrame
     void setYielding() {
         flags_ |= JSFRAME_YIELDING;
     }
 
     void clearYielding() {
         flags_ &= ~JSFRAME_YIELDING;
     }
 
-    bool isBailedAtReturn() const {
-        return flags_ & JSFRAME_BAILED_AT_RETURN;
+    void setFinishedInInterpreter() {
+        flags_ |= JSFRAME_FINISHED_IN_INTERPRETER;
     }
 
-    void setBailedAtReturn() {
-        flags_ |= JSFRAME_BAILED_AT_RETURN;
+    bool finishedInInterpreter() const {
+        return !!(flags_ & JSFRAME_FINISHED_IN_INTERPRETER);
     }
 
     /*
      * Variables object accessors
      *
      * A stack frame's 'varobj' refers to the 'variables object' (ES3 term)
      * associated with the Execution Context's VariableEnvironment (ES5 10.3).
      *
@@ -977,17 +982,17 @@ extern JS_FORCES_STACK bool
 Execute(JSContext *cx, JSObject *chain, JSScript *script,
         JSStackFrame *prev, uintN flags, Value *result);
 
 /*
  * Execute the caller-initialized frame for a user-defined script or function
  * pointed to by cx->fp until completion or error.
  */
 extern JS_REQUIRES_STACK JS_NEVER_INLINE bool
-Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0, uintN interpFlags = 0);
+Interpret(JSContext *cx, JSStackFrame *stopFp, uintN inlineCallCount = 0, JSInterpMode mode = JSINTERP_NORMAL);
 
 extern JS_REQUIRES_STACK bool
 RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp);
 
 #define JSPROP_INITIALIZER 0x100   /* NB: Not a valid property attribute. */
 
 extern bool
 CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
--- a/js/src/jsinterpinlines.h
+++ b/js/src/jsinterpinlines.h
@@ -1,9 +1,10 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=99:
  *
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -106,17 +107,17 @@ JSStackFrame::resetInvokeCallFrame()
                            JSFRAME_UNDERFLOW_ARGS |
                            JSFRAME_HAS_CALL_OBJ |
                            JSFRAME_HAS_ARGS_OBJ |
                            JSFRAME_OVERRIDE_ARGS |
                            JSFRAME_HAS_PREVPC |
                            JSFRAME_HAS_RVAL |
                            JSFRAME_HAS_SCOPECHAIN |
                            JSFRAME_HAS_ANNOTATION |
-                           JSFRAME_BAILED_AT_RETURN)));
+                           JSFRAME_FINISHED_IN_INTERPRETER)));
     flags_ &= JSFRAME_FUNCTION |
               JSFRAME_OVERFLOW_ARGS |
               JSFRAME_HAS_PREVPC |
               JSFRAME_UNDERFLOW_ARGS;
 
     JS_ASSERT_IF(!hasCallObj(), scopeChain_ == calleeValue().toObject().getParent());
     JS_ASSERT_IF(hasCallObj(), scopeChain_ == callObj().getParent());
     if (hasCallObj())
@@ -257,16 +258,21 @@ JSStackFrame::stealFrameAndSlots(js::Val
      * Repoint Call, Arguments, Block and With objects to the new live frame.
      * Call and Arguments are done directly because we have pointers to them.
      * Block and With objects are done indirectly through 'liveFrame'. See
      * js_LiveFrameToFloating comment in jsiter.h.
      */
     if (hasCallObj()) {
         callObj().setPrivate(this);
         otherfp->flags_ &= ~JSFRAME_HAS_CALL_OBJ;
+        if (js_IsNamedLambda(fun())) {
+            JSObject *env = callObj().getParent();
+            JS_ASSERT(env->getClass() == &js_DeclEnvClass);
+            env->setPrivate(this);
+        }
     }
     if (hasArgsObj()) {
         argsObj().setPrivate(this);
         otherfp->flags_ &= ~JSFRAME_HAS_ARGS_OBJ;
     }
 }
 
 inline js::Value &
@@ -668,11 +674,40 @@ ValuePropertyBearer(JSContext *cx, const
     }
 
     JSObject *pobj;
     if (!js_GetClassPrototype(cx, NULL, protoKey, &pobj))
         return NULL;
     return pobj;
 }
 
+static inline bool
+ScriptEpilogue(JSContext *cx, JSStackFrame *fp, JSBool ok)
+{
+    Probes::exitJSFun(cx, fp->maybeFun());
+    JSInterpreterHook hook = cx->debugHooks->callHook;
+    if (hook && fp->hasHookData() && !fp->isExecuteFrame())
+        hook(cx, fp, JS_FALSE, &ok, fp->hookData());
+
+    /*
+     * An eval frame's parent owns its activation objects. A yielding frame's
+     * activation objects are transferred to the floating frame, stored in the
+     * generator.
+     */
+    if (fp->isFunctionFrame() && !fp->isEvalFrame() && !fp->isYielding())
+        PutActivationObjects(cx, fp);
+
+    /*
+     * If inline-constructing, replace primitive rval with the new object
+     * passed in via |this|, and instrument this constructor invocation.
+     */
+    if (fp->isConstructing()) {
+        if (fp->returnValue().isPrimitive())
+            fp->setReturnValue(ObjectValue(fp->constructorThis()));
+        JS_RUNTIME_METER(cx->runtime, constructs);
+    }
+
+    return ok;
+}
+
 }
 
 #endif /* jsinterpinlines_h__ */
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1267,17 +1267,17 @@ SendToGenerator(JSContext *cx, JSGenerat
                             JS_GetFunctionId(gen->floatingFrame()->fun()));
         return JS_FALSE;
     }
 
     /* Check for OOM errors here, where we can fail easily. */
     if (!cx->ensureGeneratorStackSpace())
         return JS_FALSE;
 
-    JS_ASSERT(gen->state ==  JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
+    JS_ASSERT(gen->state == JSGEN_NEWBORN || gen->state == JSGEN_OPEN);
     switch (op) {
       case JSGENOP_NEXT:
       case JSGENOP_SEND:
         if (gen->state == JSGEN_OPEN) {
             /*
              * Store the argument to send as the result of the yield
              * expression.
              */
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -618,11 +618,9 @@ OPDEF(JSOP_FORGLOBAL,     246,"forglobal
  * They are emitted directly after instructions, such as DEFFUN, that need fast access to
  * the blockChain. The special NULLBLOCKCHAIN is needed because the JOF_OBJECT
  * does not permit NULL object references, since it stores an index into a table of
  * objects.
  */
 OPDEF(JSOP_BLOCKCHAIN,    247,"blockchain",    NULL,  3,  0,  0,  0, JOF_OBJECT)
 OPDEF(JSOP_NULLBLOCKCHAIN,248,"nullblockchain",NULL,  1,  0,  0,  0, JOF_BYTE)
 
-OPDEF(JSOP_BEGIN,         249,"begin",         NULL,  1,  0,  0,  0,  JOF_BYTE|JOF_TMPSLOT)
-
-/* When adding bytecodes, don't forget to update JSXDR_BYTECODE_VERSION. */
+/* When changing bytecodes, don't forget to update JSXDR_BYTECODE_VERSION. */
--- a/js/src/jspropertycache.cpp
+++ b/js/src/jspropertycache.cpp
@@ -303,17 +303,17 @@ PropertyCache::fill(JSContext *cx, JSObj
 static inline JSAtom *
 GetAtomFromBytecode(JSContext *cx, jsbytecode *pc, JSOp op, const JSCodeSpec &cs)
 {
     if (op == JSOP_LENGTH)
         return cx->runtime->atomState.lengthAtom;
 
     // The method JIT's implementation of instanceof contains an internal lookup
     // of the prototype property.
-    if (op == JSOP_INSTANCEOF || op == JSOP_BEGIN)
+    if (op == JSOP_INSTANCEOF)
         return cx->runtime->atomState.classPrototypeAtom;
 
     ptrdiff_t pcoff = (JOF_TYPE(cs.format) == JOF_SLOTATOM) ? SLOTNO_LEN : 0;
     JSAtom *atom;
     GET_ATOM_FROM_BYTECODE(cx->fp()->script(), pc, pcoff, atom);
     return atom;
 }
 
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1092,17 +1092,18 @@ JSScript::NewScriptFromCG(JSContext *cx,
     /* The counts of indexed things must be checked during code generation. */
     JS_ASSERT(cg->atomList.count <= INDEX_LIMIT);
     JS_ASSERT(cg->objectList.length <= INDEX_LIMIT);
     JS_ASSERT(cg->regexpList.length <= INDEX_LIMIT);
 
     mainLength = CG_OFFSET(cg);
     prologLength = CG_PROLOG_OFFSET(cg);
 
-    if (prologLength + mainLength <= 3) {
+    if (prologLength + mainLength <= 3 &&
+        !(cg->flags & TCF_IN_FUNCTION)) {
         /*
          * Check very short scripts to see whether they are "empty" and return
          * the const empty-script singleton if so.
          */
         jsbytecode *pc = prologLength ? CG_PROLOG_BASE(cg) : CG_BASE(cg);
 
         if ((cg->flags & TCF_NO_SCRIPT_RVAL) && JSOp(*pc) == JSOP_FALSE)
             ++pc;
--- a/js/src/jsscriptinlines.h
+++ b/js/src/jsscriptinlines.h
@@ -65,23 +65,28 @@ JSScript::getRegExp(size_t index)
     JSObject *obj = arr->vector[index];
     JS_ASSERT(obj->getClass() == &js_RegExpClass);
     return obj;
 }
 
 inline bool
 JSScript::isEmpty() const
 {
+    return (this == emptyScript());
+
+    // See bug 603044 comment #21.
+#if 0
     if (this == emptyScript())
         return true;
 
     if (length <= 3) {
         jsbytecode *pc = code;
 
         if (noScriptRval && JSOp(*pc) == JSOP_FALSE)
             ++pc;
         if (JSOp(*pc) == JSOP_STOP)
             return true;
     }
     return false;
+#endif
 }
 
 #endif /* jsscriptinlines_h___ */
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -10492,16 +10492,23 @@ TraceRecorder::record_EnterFrame()
     }
 
     /* Try inlining one level in case this recursion doesn't go too deep. */
     if (fp->script() == fp->prev()->script() &&
         fp->prev()->prev() && fp->prev()->prev()->script() == fp->script()) {
         RETURN_STOP_A("recursion started inlining");
     }
 
+    if (fp->isConstructing()) {
+        LIns* args[] = { callee_ins, INS_CONSTPTR(&js_ObjectClass), cx_ins };
+        LIns* tv_ins = lir->insCall(&js_CreateThisFromTrace_ci, args);
+        guard(false, lir->insEqP_0(tv_ins), OOM_EXIT);
+        set(&fp->thisValue(), tv_ins);
+    }
+
     return ARECORD_CONTINUE;
 }
 
 JS_REQUIRES_STACK AbortableRecordingStatus
 TraceRecorder::record_LeaveFrame()
 {
     debug_only_stmt(JSStackFrame *fp = cx->fp();)
 
@@ -11194,30 +11201,16 @@ TraceRecorder::emitNativePropertyOp(cons
     // If the native op succeeds but we deep-bail here, the result value is
     // lost!  Therefore this can only be used for setters of shared properties.
     // In that case we ignore the result value anyway.
     LIns* status_ins = loadFromState(LIR_ldi, builtinStatus);
     propagateFailureToBuiltinStatus(ok_ins, status_ins);
     guard(true, lir->insEqI_0(status_ins), STATUS_EXIT);
 }
 
-JS_REQUIRES_STACK AbortableRecordingStatus
-TraceRecorder::record_JSOP_BEGIN()
-{
-    JSStackFrame* fp = cx->fp();
-    if (fp->isConstructing()) {
-        LIns* callee_ins = get(&cx->fp()->calleeValue());
-        LIns* args[] = { callee_ins, INS_CONSTPTR(&js_ObjectClass), cx_ins };
-        LIns* tv_ins = lir->insCall(&js_CreateThisFromTrace_ci, args);
-        guard(false, lir->insEqP_0(tv_ins), OOM_EXIT);
-        set(&fp->thisValue(), tv_ins);
-    }
-    return ARECORD_CONTINUE;
-}
-
 JS_REQUIRES_STACK RecordingStatus
 TraceRecorder::emitNativeCall(JSSpecializedNative* sn, uintN argc, LIns* args[], bool rooted)
 {
     if (JSTN_ERRTYPE(sn) == FAIL_STATUS) {
         // This needs to capture the pre-call state of the stack. So do not set
         // pendingSpecializedNative before taking this snapshot.
         JS_ASSERT(!pendingSpecializedNative);
 
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -200,17 +200,17 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number should be XDR'ed once near the front of any file or
  * larger storage unit containing XDR'ed bytecode and other data, and checked
  * before deserialization of bytecode.  If the saved version does not match
  * the current version, abort deserialization and invalidate the file.
  */
-#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 73)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 74)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 JS_END_EXTERN_C
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -213,16 +213,20 @@ mjit::Compiler::~Compiler()
     cx->free(jumpMap);
 }
 
 CompileStatus JS_NEVER_INLINE
 mjit::TryCompile(JSContext *cx, JSStackFrame *fp)
 {
     JS_ASSERT(cx->fp() == fp);
 
+    // Ensure that constructors have at least one slot.
+    if (fp->isConstructing() && !fp->script()->nslots)
+        fp->script()->nslots++;
+
     Compiler cc(cx, fp);
 
     return cc.compile();
 }
 
 CompileStatus
 mjit::Compiler::generatePrologue()
 {
@@ -311,16 +315,22 @@ mjit::Compiler::generatePrologue()
                                               FrameFlagsAddress(), Imm32(JSFRAME_HAS_SCOPECHAIN));
             masm.loadPayload(Address(JSFrameReg, JSStackFrame::offsetOfCallee(fun)), t0);
             masm.loadPtr(Address(t0, offsetof(JSObject, parent)), t0);
             masm.storePtr(t0, Address(JSFrameReg, JSStackFrame::offsetOfScopeChain()));
             hasScope.linkTo(masm.label(), &masm);
         }
     }
 
+    if (isConstructing)
+        constructThis();
+
+    if (debugMode)
+        stubCall(stubs::EnterScript);
+
     return Compile_Okay;
 }
 
 CompileStatus
 mjit::Compiler::generateEpilogue()
 {
     return Compile_Okay;
 }
@@ -1389,27 +1399,27 @@ mjit::Compiler::generateMethod()
             PC += JSOP_LOCALINC_LENGTH;
             if (popped)
                 PC += JSOP_POP_LENGTH;
             break;
           }
           END_CASE(JSOP_LOCALDEC)
 
           BEGIN_CASE(JSOP_BINDNAME)
-            jsop_bindname(fullAtomIndex(PC));
+            jsop_bindname(fullAtomIndex(PC), true);
           END_CASE(JSOP_BINDNAME)
 
           BEGIN_CASE(JSOP_SETPROP)
-            if (!jsop_setprop(script->getAtom(fullAtomIndex(PC))))
+            if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)), true))
                 return Compile_Error;
           END_CASE(JSOP_SETPROP)
 
           BEGIN_CASE(JSOP_SETNAME)
           BEGIN_CASE(JSOP_SETMETHOD)
-            if (!jsop_setprop(script->getAtom(fullAtomIndex(PC))))
+            if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)), true))
                 return Compile_Error;
           END_CASE(JSOP_SETNAME)
 
           BEGIN_CASE(JSOP_THROW)
             prepareStubCall(Uses(1));
             stubCall(stubs::Throw);
             frame.pop();
           END_CASE(JSOP_THROW)
@@ -1752,23 +1762,16 @@ mjit::Compiler::generateMethod()
           BEGIN_CASE(JSOP_DECGLOBAL)
           BEGIN_CASE(JSOP_GLOBALINC)
           BEGIN_CASE(JSOP_GLOBALDEC)
             /* Advances PC automatically. */
             jsop_globalinc(op, GET_SLOTNO(PC));
             break;
           END_CASE(JSOP_GLOBALINC)
 
-          BEGIN_CASE(JSOP_BEGIN)
-            if (isConstructing) {
-                if (!constructThis())
-                    return Compile_Error;
-            }
-          END_CASE(JSOP_BEGIN)
-
           default:
            /* Sorry, this opcode isn't implemented yet. */
 #ifdef JS_METHODJIT_SPEW
             JaegerSpew(JSpew_Abort, "opcode %s not handled yet (%s line %d)\n", OpcodeNames[op],
                        script->filename, js_PCToLineNumber(cx, script, PC));
 #endif
             return Compile_Abort;
         }
@@ -1982,16 +1985,21 @@ mjit::Compiler::emitReturnValue(Assemble
 void
 mjit::Compiler::emitReturn(FrameEntry *fe)
 {
     JS_ASSERT_IF(!fun, JSOp(*PC) == JSOP_STOP);
 
     /* Only the top of the stack can be returned. */
     JS_ASSERT_IF(fe, fe == frame.peek(-1));
 
+    if (debugMode) {
+        prepareStubCall(Uses(0));
+        stubCall(stubs::LeaveScript);
+    }
+
     /*
      * If there's a function object, deal with the fact that it can escape.
      * Note that after we've placed the call object, all tracked state can
      * be thrown away. This will happen anyway because the next live opcode
      * (if any) must have an incoming edge.
      *
      * However, it's an optimization to throw it away early - the tracker
      * won't be spilled on further exits or join points.
@@ -2414,30 +2422,38 @@ mjit::Compiler::emitStubCmpOp(BoolStub s
                                     : Assembler::NonZero;
         Jump j = masm.branchTest32(cond, Registers::ReturnReg,
                                    Registers::ReturnReg);
         jumpAndTrace(j, target);
     }
 }
 
 void
-mjit::Compiler::jsop_setprop_slow(JSAtom *atom)
+mjit::Compiler::jsop_setprop_slow(JSAtom *atom, bool usePropCache)
 {
     prepareStubCall(Uses(2));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
-    stubCall(STRICT_VARIANT(stubs::SetName));
+    if (usePropCache)
+        stubCall(STRICT_VARIANT(stubs::SetName));
+    else
+        stubCall(STRICT_VARIANT(stubs::SetPropNoCache));
     JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
     frame.shimmy(1);
 }
 
 void
-mjit::Compiler::jsop_getprop_slow()
+mjit::Compiler::jsop_getprop_slow(JSAtom *atom, bool usePropCache)
 {
     prepareStubCall(Uses(1));
-    stubCall(stubs::GetProp);
+    if (usePropCache) {
+        stubCall(stubs::GetProp);
+    } else {
+        masm.move(ImmPtr(atom), Registers::ArgReg1);
+        stubCall(stubs::GetPropNoCache);
+    }
     frame.pop();
     frame.pushSynced();
 }
 
 bool
 mjit::Compiler::jsop_callprop_slow(JSAtom *atom)
 {
     prepareStubCall(Uses(1));
@@ -2493,41 +2509,41 @@ mjit::Compiler::passMICAddress(MICGenInf
 #if defined JS_POLYIC
 void
 mjit::Compiler::passPICAddress(PICGenInfo &pic)
 {
     pic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
 }
 
 bool
-mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck)
+mjit::Compiler::jsop_getprop(JSAtom *atom, bool doTypeCheck, bool usePropCache)
 {
     FrameEntry *top = frame.peek(-1);
 
     /* If the incoming type will never PIC, take slow path. */
     if (top->isTypeKnown() && top->getKnownType() != JSVAL_TYPE_OBJECT) {
         JS_ASSERT_IF(atom == cx->runtime->atomState.lengthAtom,
                      top->getKnownType() != JSVAL_TYPE_STRING);
-        jsop_getprop_slow();
+        jsop_getprop_slow(atom, usePropCache);
         return true;
     }
 
     /*
      * These two must be loaded first. The objReg because the string path
      * wants to read it, and the shapeReg because it could cause a spill that
      * the string path wouldn't sink back.
      */
     RegisterID objReg = Registers::ReturnReg;
     RegisterID shapeReg = Registers::ReturnReg;
     if (atom == cx->runtime->atomState.lengthAtom) {
         objReg = frame.copyDataIntoReg(top);
         shapeReg = frame.allocReg();
     }
 
-    PICGenInfo pic(ic::PICInfo::GET);
+    PICGenInfo pic(ic::PICInfo::GET, usePropCache);
 
     /* Guard that the type is an object. */
     Jump typeCheck;
     if (doTypeCheck && !top->isTypeKnown()) {
         RegisterID reg = frame.tempRegForType(top);
         pic.typeReg = reg;
 
         /* Start the hot path where it's easy to patch it. */
@@ -2626,17 +2642,17 @@ mjit::Compiler::jsop_getprop(JSAtom *ato
     return true;
 }
 
 #ifdef JS_POLYIC
 bool
 mjit::Compiler::jsop_getelem_pic(FrameEntry *obj, FrameEntry *id, RegisterID objReg,
                                  RegisterID idReg, RegisterID shapeReg)
 {
-    PICGenInfo pic(ic::PICInfo::GETELEM);
+    PICGenInfo pic(ic::PICInfo::GETELEM, true);
 
     pic.objRemat = frame.dataRematInfo(obj);
     pic.idRemat = frame.dataRematInfo(id);
     pic.shapeReg = shapeReg;
     pic.hasTypeCheck = false;
 
     pic.fastPathStart = masm.label();
 
@@ -2741,17 +2757,17 @@ mjit::Compiler::jsop_callprop_generic(JS
     /*
      * These two must be loaded first. The objReg because the string path
      * wants to read it, and the shapeReg because it could cause a spill that
      * the string path wouldn't sink back.
      */
     RegisterID objReg = frame.copyDataIntoReg(top);
     RegisterID shapeReg = frame.allocReg();
 
-    PICGenInfo pic(ic::PICInfo::CALL);
+    PICGenInfo pic(ic::PICInfo::CALL, true);
 
     /* Guard that the type is an object. */
     pic.typeReg = frame.copyTypeIntoReg(top);
 
     /* Start the hot path where it's easy to patch it. */
     pic.fastPathStart = masm.label();
 
     /*
@@ -2911,17 +2927,17 @@ mjit::Compiler::jsop_callprop_str(JSAtom
     return true;
 }
 
 bool
 mjit::Compiler::jsop_callprop_obj(JSAtom *atom)
 {
     FrameEntry *top = frame.peek(-1);
 
-    PICGenInfo pic(ic::PICInfo::CALL);
+    PICGenInfo pic(ic::PICInfo::CALL, true);
 
     JS_ASSERT(top->isTypeKnown());
     JS_ASSERT(top->getKnownType() == JSVAL_TYPE_OBJECT);
 
     pic.fastPathStart = masm.label();
     pic.hasTypeCheck = false;
     pic.typeReg = Registers::ReturnReg;
 
@@ -3029,58 +3045,50 @@ mjit::Compiler::jsop_callprop(JSAtom *at
     }
 
     if (top->isTypeKnown())
         return jsop_callprop_obj(atom);
     return jsop_callprop_generic(atom);
 }
 
 bool
-mjit::Compiler::jsop_setprop(JSAtom *atom)
+mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
 {
     FrameEntry *lhs = frame.peek(-2);
     FrameEntry *rhs = frame.peek(-1);
 
     /* If the incoming type will never PIC, take slow path. */
     if (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_OBJECT) {
-        jsop_setprop_slow(atom);
+        jsop_setprop_slow(atom, usePropCache);
         return true;
     }
 
     JSOp op = JSOp(*PC);
 
-    PICGenInfo pic(op == JSOP_SETMETHOD ? ic::PICInfo::SETMETHOD : ic::PICInfo::SET);
+    PICGenInfo pic(op == JSOP_SETMETHOD ? ic::PICInfo::SETMETHOD : ic::PICInfo::SET, usePropCache);
     pic.atom = atom;
 
     /* Guard that the type is an object. */
     Jump typeCheck;
     if (!lhs->isTypeKnown()) {
         RegisterID reg = frame.tempRegForType(lhs);
         pic.typeReg = reg;
 
         /* Start the hot path where it's easy to patch it. */
         pic.fastPathStart = masm.label();
         Jump j = masm.testObject(Assembler::NotEqual, reg);
 
         pic.typeCheck = stubcc.linkExit(j, Uses(2));
         stubcc.leave();
 
-        /*
-         * This gets called from PROPINC/PROPDEC which aren't compatible with
-         * the normal SETNAME property cache logic.
-         */
-        JSOp op = JSOp(*PC);
         stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
-        if (op == JSOP_SETNAME || op == JSOP_SETPROP || op == JSOP_SETGNAME || op ==
-            JSOP_SETMETHOD) {
+        if (usePropCache)
             stubcc.call(STRICT_VARIANT(stubs::SetName));
-        } else {
+        else
             stubcc.call(STRICT_VARIANT(stubs::SetPropNoCache));
-        }
-
         typeCheck = stubcc.masm.jump();
         pic.hasTypeCheck = true;
     } else {
         pic.fastPathStart = masm.label();
         pic.hasTypeCheck = false;
         pic.typeReg = Registers::ReturnReg;
     }
 
@@ -3175,17 +3183,17 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
 
     pics.append(pic);
     return true;
 }
 
 void
 mjit::Compiler::jsop_name(JSAtom *atom)
 {
-    PICGenInfo pic(ic::PICInfo::NAME);
+    PICGenInfo pic(ic::PICInfo::NAME, true);
 
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
     pic.typeReg = Registers::ReturnReg;
     pic.atom = atom;
     pic.hasTypeCheck = false;
     pic.fastPathStart = masm.label();
 
@@ -3207,17 +3215,17 @@ mjit::Compiler::jsop_name(JSAtom *atom)
     stubcc.rejoin(Changes(1));
 
     pics.append(pic);
 }
 
 bool
 mjit::Compiler::jsop_xname(JSAtom *atom)
 {
-    PICGenInfo pic(ic::PICInfo::XNAME);
+    PICGenInfo pic(ic::PICInfo::XNAME, true);
 
     FrameEntry *fe = frame.peek(-1);
     if (fe->isNotType(JSVAL_TYPE_OBJECT)) {
         return jsop_getprop(atom);
     }
 
     if (!fe->isTypeKnown()) {
         Jump notObject = frame.testObject(Assembler::NotEqual, fe);
@@ -3249,19 +3257,19 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
 
     stubcc.rejoin(Changes(1));
 
     pics.append(pic);
     return true;
 }
 
 void
-mjit::Compiler::jsop_bindname(uint32 index)
+mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
 {
-    PICGenInfo pic(ic::PICInfo::BIND);
+    PICGenInfo pic(ic::PICInfo::BIND, usePropCache);
 
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
     pic.typeReg = Registers::ReturnReg;
     pic.atom = script->getAtom(index);
     pic.hasTypeCheck = false;
     pic.fastPathStart = masm.label();
 
@@ -3312,49 +3320,54 @@ mjit::Compiler::jsop_name(JSAtom *atom)
 
 bool
 mjit::Compiler::jsop_xname(JSAtom *atom)
 {
     return jsop_getprop(atom);
 }
 
 bool
-mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck)
+mjit::Compiler::jsop_getprop(JSAtom *atom, bool typecheck, bool usePropCache)
 {
-    jsop_getprop_slow();
+    jsop_getprop_slow(atom, usePropCache);
     return true;
 }
 
 bool
 mjit::Compiler::jsop_callprop(JSAtom *atom)
 {
     return jsop_callprop_slow(atom);
 }
 
 bool
-mjit::Compiler::jsop_setprop(JSAtom *atom)
+mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
 {
-    jsop_setprop_slow(atom);
+    jsop_setprop_slow(atom, usePropCache);
     return true;
 }
 
 void
-mjit::Compiler::jsop_bindname(uint32 index)
+mjit::Compiler::jsop_bindname(uint32 index, bool usePropCache)
 {
     RegisterID reg = frame.allocReg();
     Address scopeChain(JSFrameReg, JSStackFrame::offsetOfScopeChain());
     masm.loadPtr(scopeChain, reg);
 
     Address address(reg, offsetof(JSObject, parent));
 
     Jump j = masm.branchPtr(Assembler::NotEqual, masm.payloadOf(address), ImmPtr(0));
 
     stubcc.linkExit(j, Uses(0));
     stubcc.leave();
-    stubcc.call(stubs::BindName);
+    if (usePropCache) {
+        stubcc.call(stubs::BindName);
+    } else {
+        masm.move(ImmPtr(script->getAtom(index)), Registers::ArgReg1);
+        stubcc.call(stubs::BindNameNoCache);
+    }
 
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
 
     stubcc.rejoin(Changes(1));
 }
 #endif
 
 void
@@ -3487,29 +3500,29 @@ mjit::Compiler::jsop_nameinc(JSOp op, Vo
 
         frame.push(Int32Value(amt));
         // V 1
 
         /* Use sub since it calls ValueToNumber instead of string concat. */
         jsop_binary(JSOP_SUB, stubs::Sub);
         // N+1
 
-        jsop_bindname(index);
+        jsop_bindname(index, false);
         // V+1 OBJ
 
         frame.dup2();
         // V+1 OBJ V+1 OBJ
 
         frame.shift(-3);
         // OBJ OBJ V+1
 
         frame.shift(-1);
         // OBJ V+1
 
-        if (!jsop_setprop(atom))
+        if (!jsop_setprop(atom, false))
             return false;
         // V+1
 
         if (pop)
             frame.pop();
     } else {
         /* The pre-value is observed, making this more tricky. */
 
@@ -3523,29 +3536,29 @@ mjit::Compiler::jsop_nameinc(JSOp op, Vo
         // N N
 
         frame.push(Int32Value(-amt));
         // N N 1
 
         jsop_binary(JSOP_ADD, stubs::Add);
         // N N+1
 
-        jsop_bindname(index);
+        jsop_bindname(index, false);
         // N N+1 OBJ
 
         frame.dup2();
         // N N+1 OBJ N+1 OBJ
 
         frame.shift(-3);
         // N OBJ OBJ N+1
 
         frame.shift(-1);
         // N OBJ N+1
 
-        if (!jsop_setprop(atom))
+        if (!jsop_setprop(atom, false))
             return false;
         // N N+1
 
         frame.pop();
         // N
     }
 
     if (pop)
@@ -3584,17 +3597,17 @@ mjit::Compiler::jsop_propinc(JSOp op, Vo
 
             frame.push(Int32Value(amt));
             // OBJ V 1
 
             /* Use sub since it calls ValueToNumber instead of string concat. */
             jsop_binary(JSOP_SUB, stubs::Sub);
             // OBJ V+1
 
-            if (!jsop_setprop(atom))
+            if (!jsop_setprop(atom, false))
                 return false;
             // V+1
 
             if (pop)
                 frame.pop();
         } else {
             /* The pre-value is observed, making this more tricky. */
 
@@ -3618,17 +3631,17 @@ mjit::Compiler::jsop_propinc(JSOp op, Vo
             // OBJ N N+1
 
             frame.dupAt(-3);
             // OBJ N N+1 OBJ
 
             frame.dupAt(-2);
             // OBJ N N+1 OBJ N+1
 
-            if (!jsop_setprop(atom))
+            if (!jsop_setprop(atom, false))
                 return false;
             // OBJ N N+1 N+1
 
             frame.popn(2);
             // OBJ N
 
             frame.shimmy(1);
             // N
@@ -4419,17 +4432,17 @@ mjit::Compiler::constructThis()
 
     // Load the callee.
     Address callee(JSFrameReg, JSStackFrame::offsetOfCallee(fun));
     RegisterID calleeReg = frame.allocReg();
     masm.loadPayload(callee, calleeReg);
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, calleeReg);
 
     // Get callee.prototype.
-    if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom))
+    if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, false))
         return false;
 
     // Reach into the proto Value and grab a register for its data.
     FrameEntry *protoFe = frame.peek(-1);
     RegisterID protoReg = frame.ownRegForData(protoFe);
 
     // Now, get the type. If it's not an object, set protoReg to NULL.
     Jump isNotObject = frame.testObject(Assembler::NotEqual, protoFe);
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -146,44 +146,47 @@ class Compiler : public BaseCompiler
         Label joinPoint;
         DataLabelPtr fastNcodePatch;
         DataLabelPtr slowNcodePatch;
         bool hasSlowNcode;
     };
 
 #if defined JS_POLYIC
     struct PICGenInfo {
-        PICGenInfo(ic::PICInfo::Kind kind) : kind(kind)
+        PICGenInfo(ic::PICInfo::Kind kind, bool usePropCache)
+          : kind(kind), usePropCache(usePropCache)
         { }
         ic::PICInfo::Kind kind;
         Label fastPathStart;
         Label storeBack;
         Label typeCheck;
         Label slowPathStart;
         DataLabelPtr addrLabel;
         RegisterID shapeReg;
         RegisterID objReg;
         RegisterID idReg;
         RegisterID typeReg;
+        bool usePropCache;
         Label shapeGuard;
         JSAtom *atom;
         StateRemat objRemat;
         StateRemat idRemat;
         Call callReturn;
         bool hasTypeCheck;
         ValueRemat vr;
 # if defined JS_CPU_X64
         ic::PICLabels labels;
 # endif
 
         void copySimpleMembersTo(ic::PICInfo &pi) const {
             pi.kind = kind;
             pi.shapeReg = shapeReg;
             pi.objReg = objReg;
             pi.atom = atom;
+            pi.usePropCache = usePropCache;
             if (kind == ic::PICInfo::SET) {
                 pi.u.vr = vr;
             } else if (kind != ic::PICInfo::NAME) {
                 pi.u.get.idReg = idReg;
                 pi.u.get.typeReg = typeReg;
                 pi.u.get.hasTypeCheck = hasTypeCheck;
                 pi.u.get.objRemat = objRemat.offset;
             }
@@ -310,20 +313,20 @@ class Compiler : public BaseCompiler
     void jsop_getgname(uint32 index);
     void jsop_getgname_slow(uint32 index);
     void jsop_setgname(uint32 index);
     void jsop_setgname_slow(uint32 index);
     void jsop_bindgname();
     void jsop_setelem_slow();
     void jsop_getelem_slow();
     void jsop_unbrand();
-    bool jsop_getprop(JSAtom *atom, bool typeCheck = true);
+    bool jsop_getprop(JSAtom *atom, bool typeCheck = true, bool usePropCache = true);
     bool jsop_length();
-    bool jsop_setprop(JSAtom *atom);
-    void jsop_setprop_slow(JSAtom *atom);
+    bool jsop_setprop(JSAtom *atom, bool usePropCache = true);
+    void jsop_setprop_slow(JSAtom *atom, bool usePropCache = true);
     bool jsop_callprop_slow(JSAtom *atom);
     bool jsop_callprop(JSAtom *atom);
     bool jsop_callprop_obj(JSAtom *atom);
     bool jsop_callprop_str(JSAtom *atom);
     bool jsop_callprop_generic(JSAtom *atom);
     bool jsop_instanceof();
     void jsop_name(JSAtom *atom);
     bool jsop_xname(JSAtom *atom);
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -68,19 +68,16 @@
 #include "StubCalls-inl.h"
 
 #include "jsautooplen.h"
 
 using namespace js;
 using namespace js::mjit;
 using namespace JSC;
 
-static bool
-InlineReturn(VMFrame &f, JSBool ok, JSBool popFrame = JS_TRUE);
-
 static jsbytecode *
 FindExceptionHandler(JSContext *cx)
 {
     JSStackFrame *fp = cx->fp();
     JSScript *script = fp->script();
 
 top:
     if (cx->throwing && script->trynotesOffset) {
@@ -172,56 +169,29 @@ top:
 /*
  * Clean up a frame and return.  popFrame indicates whether to additionally pop
  * the frame and store the return value on the caller's stack.  The frame will
  * normally be popped by the caller on return from a call into JIT code,
  * so must be popped here when that caller code will not execute.  This can be
  * either because of a call into an un-JITable script, or because the call is
  * throwing an exception.
  */
-static bool
-InlineReturn(VMFrame &f, JSBool ok, JSBool popFrame)
+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));
 
-    // Marker for debug support.
-    if (JS_UNLIKELY(fp->hasHookData())) {
-        JSInterpreterHook hook;
-        JSBool status;
-
-        hook = cx->debugHooks->callHook;
-        if (hook) {
-            /*
-             * Do not pass &ok directly as exposing the address inhibits
-             * optimizations and uninitialised warnings.
-             */
-            status = ok;
-            hook(cx, fp, JS_FALSE, &status, fp->hookData());
-            ok = (status == JS_TRUE);
-            // CHECK_INTERRUPT_HANDLER();
-        }
-    }
-
-    PutActivationObjects(cx, fp);
-
-    if (fp->isConstructing() && fp->returnValue().isPrimitive())
-        fp->setReturnValue(fp->thisValue());
-
-    if (popFrame) {
-        Value *newsp = fp->actualArgs() - 1;
-        newsp[-1] = fp->returnValue();
-        cx->stack().popInlineFrame(cx, fp->prev(), newsp);
-    }
-
-    return ok;
+    Value *newsp = fp->actualArgs() - 1;
+    newsp[-1] = fp->returnValue();
+    cx->stack().popInlineFrame(cx, fp->prev(), newsp);
 }
 
 void JS_FASTCALL
 stubs::SlowCall(VMFrame &f, uint32 argc)
 {
     Value *vp = f.regs.sp - (argc + 2);
 
     if (!Invoke(f.cx, InvokeArgsAlreadyOnTheStack(vp, argc), 0))
@@ -367,29 +337,28 @@ stubs::CompileFunction(VMFrame &f, uint3
         THROWV(NULL);
 
     CompileStatus status = CanMethodJIT(cx, script, fp);
     if (status == Compile_Okay)
         return script->getJIT(callingNew)->invokeEntry;
 
     /* Function did not compile... interpret it. */
     JSBool ok = Interpret(cx, fp);
-    InlineReturn(f, ok);
+    InlineReturn(f);
 
     if (!ok)
         THROWV(NULL);
 
     return NULL;
 }
 
 static inline bool
 UncachedInlineCall(VMFrame &f, uint32 flags, void **pret, uint32 argc)
 {
     JSContext *cx = f.cx;
-    JSStackFrame *fp = f.fp();
     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,
@@ -407,40 +376,34 @@ UncachedInlineCall(VMFrame &f, uint32 fl
     /* 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_GetCallObject(cx, newfp))
         return false;
 
-    /* Marker for debug support. */
-    if (JSInterpreterHook hook = cx->debugHooks->callHook) {
-        newfp->setHookData(hook(cx, fp, JS_TRUE, 0,
-                                cx->debugHooks->callHookData));
-    }
-
     /* Try to compile if not already compiled. */
     if (newscript->getJITStatus(newfp->isConstructing()) == JITScript_None) {
         if (mjit::TryCompile(cx, newfp) == Compile_Error) {
             /* A runtime exception was thrown, get out. */
-            InlineReturn(f, JS_FALSE);
+            InlineReturn(f);
             return false;
         }
     }
 
     /* 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, JS_TRUE);
+    InlineReturn(f);
 
     *pret = NULL;
     return ok;
 }
 
 void * JS_FASTCALL
 stubs::UncachedNew(VMFrame &f, uint32 argc)
 {
@@ -569,21 +532,28 @@ js_InternalThrow(VMFrame &f)
             break;
 
         // If on the 'topmost' frame (where topmost means the first frame
         // called into through js_Interpret). In this case, we still unwind,
         // but we shouldn't return from a JS function, because we're not in a
         // JS function.
         bool lastFrame = (f.entryFp == f.fp());
         js_UnwindScope(cx, 0, cx->throwing);
+
+        // For consistency with Interpret(), always run the script epilogue.
+        // This simplifies interactions with RunTracer(), since it can assume
+        // no matter how a function exited (error or not), that the epilogue
+        // does not need to be run.
+        ScriptEpilogue(f.cx, f.fp(), false);
+
         if (lastFrame)
             break;
 
         JS_ASSERT(f.regs.sp == cx->regs->sp);
-        InlineReturn(f, JS_FALSE);
+        InlineReturn(f);
     }
 
     JS_ASSERT(f.regs.sp == cx->regs->sp);
 
     if (!pc)
         return NULL;
 
     JSStackFrame *fp = cx->fp();
@@ -606,46 +576,74 @@ stubs::CreateThis(VMFrame &f, JSObject *
     JSStackFrame *fp = f.fp();
     JSObject *callee = &fp->callee();
     JSObject *obj = js_CreateThisForFunctionWithProto(cx, callee, proto);
     if (!obj)
         THROW();
     fp->formalArgs()[-1].setObject(*obj);
 }
 
-static inline void
-AdvanceReturnPC(JSContext *cx)
+void JS_FASTCALL
+stubs::EnterScript(VMFrame &f)
 {
-    /* Simulate an inline_return by advancing the pc. */
-    JS_ASSERT(*cx->regs->pc == JSOP_CALL ||
-              *cx->regs->pc == JSOP_NEW ||
-              *cx->regs->pc == JSOP_EVAL ||
-              *cx->regs->pc == JSOP_APPLY);
-    cx->regs->pc += JSOP_CALL_LENGTH;
+    JSStackFrame *fp = f.fp();
+    JSContext *cx = f.cx;
+    JSInterpreterHook hook = cx->debugHooks->callHook;
+    if (JS_UNLIKELY(hook != NULL) && !fp->isExecuteFrame()) {
+        fp->setHookData(hook(cx, fp, JS_TRUE, 0, cx->debugHooks->callHookData));
+    }
+
+    Probes::enterJSFun(cx, fp->maybeFun());
+}
+
+void JS_FASTCALL
+stubs::LeaveScript(VMFrame &f)
+{
+    JSStackFrame *fp = f.fp();
+    JSContext *cx = f.cx;
+    Probes::exitJSFun(cx, fp->maybeFun());
+    JSInterpreterHook hook = cx->debugHooks->callHook;
+
+    if (hook && fp->hasHookData() && !fp->isExecuteFrame()) {
+        JSBool ok = JS_TRUE;
+        hook(cx, fp, JS_FALSE, &ok, fp->hookData());
+        if (!ok)
+            THROW();
+    }
 }
 
 #ifdef JS_TRACER
 
+/*
+ * Called when an error is in progress and the topmost frame could not handle
+ * it. This will unwind to a given frame, or find and align to an exception
+ * handler in the process.
+ */
 static inline bool
-HandleErrorInExcessFrames(VMFrame &f, JSStackFrame *stopFp)
+HandleErrorInExcessFrame(VMFrame &f, JSStackFrame *stopFp, bool searchedTopmostFrame = true)
 {
     JSContext *cx = f.cx;
 
     /*
      * Callers of this called either Interpret() or JaegerShot(), which would
      * have searched for exception handlers already. If we see stopFp, just
      * return false. Otherwise, pop the frame, since it's guaranteed useless.
+     *
+     * Note that this also guarantees ScriptEpilogue() has been called.
      */
     JSStackFrame *fp = cx->fp();
-    if (fp == stopFp)
-        return false;
+    if (searchedTopmostFrame) {
+        if (fp == stopFp)
+            return false;
 
-    bool returnOK = InlineReturn(f, false);
+        InlineReturn(f);
+    }
 
     /* Remove the bottom frame. */
+    bool returnOK = false;
     for (;;) {
         fp = cx->fp();
 
         /* Clear imacros. */
         if (fp->hasImacropc()) {
             cx->regs->pc = fp->imacropc();
             fp->clearImacropc();
         }
@@ -662,100 +660,203 @@ HandleErrorInExcessFrames(VMFrame &f, JS
         }
 
         /* Don't unwind if this was the entry frame. */
         if (fp == stopFp)
             break;
 
         /* Unwind and return. */
         returnOK &= bool(js_UnwindScope(cx, 0, returnOK || cx->throwing));
-        returnOK = InlineReturn(f, returnOK);
+        returnOK = ScriptEpilogue(cx, fp, returnOK);
+        InlineReturn(f);
     }
 
     JS_ASSERT(&f.regs == cx->regs);
     JS_ASSERT_IF(!returnOK, cx->fp() == stopFp);
 
     return returnOK;
 }
 
+/* Returns whether the current PC has method JIT'd code. */
 static inline void *
 AtSafePoint(JSContext *cx)
 {
     JSStackFrame *fp = cx->fp();
     if (fp->hasImacropc())
         return false;
 
     JSScript *script = fp->script();
     return script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc);
 }
 
+/*
+ * Interprets until either a safe point is reached that has method JIT'd
+ * code, or the current frame tries to return.
+ */
 static inline JSBool
 PartialInterpret(VMFrame &f)
 {
     JSContext *cx = f.cx;
     JSStackFrame *fp = cx->fp();
 
 #ifdef DEBUG
     JSScript *script = fp->script();
+    JS_ASSERT(!fp->finishedInInterpreter());
     JS_ASSERT(fp->hasImacropc() ||
               !script->maybeNativeCodeForPC(fp->isConstructing(), cx->regs->pc));
 #endif
 
     JSBool ok = JS_TRUE;
     ok = Interpret(cx, fp, 0, JSINTERP_SAFEPOINT);
 
     return ok;
 }
 
 JS_STATIC_ASSERT(JSOP_NOP == 0);
 
+/* Returns whether the current PC would return, popping the frame. */
 static inline JSOp
 FrameIsFinished(JSContext *cx)
 {
     JSOp op = JSOp(*cx->regs->pc);
     return (op == JSOP_RETURN ||
             op == JSOP_RETRVAL ||
             op == JSOP_STOP)
         ? op
         : JSOP_NOP;
 }
 
+
+/* Simulate an inline_return by advancing the pc. */
+static inline void
+AdvanceReturnPC(JSContext *cx)
+{
+    JS_ASSERT(*cx->regs->pc == JSOP_CALL ||
+              *cx->regs->pc == JSOP_NEW ||
+              *cx->regs->pc == JSOP_EVAL ||
+              *cx->regs->pc == JSOP_APPLY);
+    cx->regs->pc += JSOP_CALL_LENGTH;
+}
+
+
+/*
+ * Given a frame that is about to return, make sure its return value and
+ * activation objects are fixed up. Then, pop the frame and advance the
+ * current PC. Note that while we could enter the JIT at this point, the
+ * logic would still be necessary for the interpreter, so it's easier
+ * (and faster) to finish frames in C++ even if at a safe point here.
+ */
+static bool
+HandleFinishedFrame(VMFrame &f, JSStackFrame *entryFrame)
+{
+    JSContext *cx = f.cx;
+
+    JS_ASSERT(FrameIsFinished(cx));
+
+    /*
+     * This is the most difficult and complicated piece of the tracer
+     * integration, and historically has been very buggy. The problem is that
+     * although this frame has to be popped (see RemoveExcessFrames), it may
+     * be at a JSOP_RETURN opcode, and it might not have ever been executed.
+     * That is, fp->rval may not be set to the top of the stack, and if it
+     * has, the stack has already been decremented. Note that fp->rval is not
+     * the only problem: the epilogue may never have been executed.
+     *
+     * Here are the edge cases and whether the frame has been exited cleanly:
+     *  1. No: A trace exited directly before a RETURN op, and the
+     *         interpreter never ran.
+     *  2. Yes: The interpreter exited cleanly.
+     *  3. No: The interpreter exited on a safe point. LEAVE_ON_SAFE_POINT
+     *         is not used in between JSOP_RETURN and advancing the PC,
+     *         therefore, it cannot have been run if at a safe point.
+     *  4. No: Somewhere in the RunTracer call tree, we removed a frame,
+     *         and we returned to a JSOP_RETURN opcode. Note carefully
+     *         that in this situation, FrameIsFinished() returns true!
+     *  5. Yes: The function exited in the method JIT. However, in this
+     *         case, we'll never enter HandleFinishedFrame(): we always
+     *         immediately pop JIT'd frames.
+     *
+     * Since the only scenario where this fixup is NOT needed is a normal exit
+     * from the interpreter, we can cleanly check for this scenario by checking
+     * a bit it sets in the frame.
+     */
+    bool returnOK = true;
+    if (!cx->fp()->finishedInInterpreter()) {
+        if (JSOp(*cx->regs->pc) == JSOP_RETURN)
+            cx->fp()->setReturnValue(f.regs.sp[-1]);
+
+        returnOK = ScriptEpilogue(cx, cx->fp(), true);
+    }
+
+    JS_ASSERT_IF(cx->fp()->isFunctionFrame() &&
+                 !cx->fp()->isEvalFrame(),
+                 !cx->fp()->hasCallObj());
+
+    if (cx->fp() != entryFrame) {
+        InlineReturn(f);
+        AdvanceReturnPC(cx);
+    }
+
+    return returnOK;
+}
+
+/*
+ * Given a frame newer than the entry frame, try to finish it. If it's at a
+ * return position, pop the frame. If it's at a safe point, execute it in
+ * Jaeger code. Otherwise, try to interpret until a safe point.
+ *
+ * While this function is guaranteed to make progress, it may not actually
+ * finish or pop the current frame. It can either:
+ *   1) Finalize a finished frame, or
+ *   2) Finish and finalize the frame in the Method JIT, or
+ *   3) Interpret, which can:
+ *     a) Propagate an error, or
+ *     b) Finish the frame, but not finalize it, or
+ *     c) Abruptly leave at any point in the frame, or in a newer frame
+ *        pushed by a call, that has method JIT'd code.
+ */
+static bool
+EvaluateExcessFrame(VMFrame &f, JSStackFrame *entryFrame)
+{
+    JSContext *cx = f.cx;
+    JSStackFrame *fp = cx->fp();
+
+    /*
+     * A "finished" frame is when the interpreter rested on a STOP,
+     * RETURN, RETRVAL, etc. We check for finished frames BEFORE looking
+     * for a safe point. If the frame was finished, we could have already
+     * called ScriptEpilogue(), and entering the JIT could call it twice.
+     */
+    if (!fp->hasImacropc() && FrameIsFinished(cx))
+        return HandleFinishedFrame(f, entryFrame);
+
+    if (void *ncode = AtSafePoint(cx)) {
+        if (!JaegerShotAtSafePoint(cx, ncode))
+            return false;
+        InlineReturn(f);
+        AdvanceReturnPC(cx);
+        return true;
+    }
+
+    return PartialInterpret(f);
+}
+
+/*
+ * Evaluate frames newer than the entry frame until all are gone. This will
+ * always leave f.regs.fp == entryFrame.
+ */
 static bool
 FinishExcessFrames(VMFrame &f, JSStackFrame *entryFrame)
 {
     JSContext *cx = f.cx;
+
     while (cx->fp() != entryFrame || entryFrame->hasImacropc()) {
-        if (void *ncode = AtSafePoint(cx)) {
-            if (!JaegerShotAtSafePoint(cx, ncode)) {
-                if (!HandleErrorInExcessFrames(f, entryFrame))
-                    return false;
-
-                /* Could be anywhere - restart outer loop. */
-                continue;
-            }
-            InlineReturn(f, JS_TRUE);
-            AdvanceReturnPC(cx);
-        } else {
-            if (!PartialInterpret(f)) {
-                if (!HandleErrorInExcessFrames(f, entryFrame))
-                    return false;
-            } else if (cx->fp() != entryFrame) {
-                /*
-                 * Partial interpret could have dropped us anywhere. Deduce the
-                 * edge case: at a RETURN, needing to pop a frame.
-                 */
-                JS_ASSERT(!cx->fp()->hasImacropc());
-                if (FrameIsFinished(cx)) {
-                    JSOp op = JSOp(*cx->regs->pc);
-                    if (op == JSOP_RETURN && !cx->fp()->isBailedAtReturn())
-                        cx->fp()->setReturnValue(f.regs.sp[-1]);
-                    InlineReturn(f, JS_TRUE);
-                    AdvanceReturnPC(cx);
-                }
-            }
+        if (!EvaluateExcessFrame(f, entryFrame)) {
+            if (!HandleErrorInExcessFrame(f, entryFrame))
+                return false;
         }
     }
 
     return true;
 }
 
 #if JS_MONOIC
 static void
@@ -817,28 +918,28 @@ RunTracer(VMFrame &f)
     tpa = MonitorTracePoint(f.cx, inlineCallCount, blacklist);
     JS_ASSERT(!TRACE_RECORDER(cx));
 
 #if JS_MONOIC
     if (blacklist)
         DisableTraceHint(f, mic);
 #endif
 
-    if ((tpa == TPA_RanStuff || tpa == TPA_Recorded) && cx->throwing)
-        tpa = TPA_Error;
+    // Even though ExecuteTree() bypasses the interpreter, it should propagate
+    // error failures correctly.
+    JS_ASSERT_IF(cx->throwing, tpa == TPA_Error);
 
-	/* Sync up the VMFrame's view of cx->fp(). */
 	f.fp() = cx->fp();
-
+    JS_ASSERT(f.fp() == cx->fp());
     switch (tpa) {
       case TPA_Nothing:
         return NULL;
 
       case TPA_Error:
-        if (!HandleErrorInExcessFrames(f, entryFrame))
+        if (!HandleErrorInExcessFrame(f, entryFrame, f.fp()->finishedInInterpreter()))
             THROWV(NULL);
         JS_ASSERT(!cx->fp()->hasImacropc());
         break;
 
       case TPA_RanStuff:
       case TPA_Recorded:
         break;
     }
@@ -866,42 +967,36 @@ RunTracer(VMFrame &f)
      */
 
   restart:
     /* Step 1. Finish frames created after the entry frame. */
     if (!FinishExcessFrames(f, entryFrame))
         THROWV(NULL);
 
     /* IMacros are guaranteed to have been removed by now. */
+    JS_ASSERT(f.fp() == entryFrame);
     JS_ASSERT(!entryFrame->hasImacropc());
 
-    /* Step 2. If entryFrame is at a safe point, just leave. */
-    if (void *ncode = AtSafePoint(cx))
-        return ncode;
-
-    /* Step 3. If entryFrame is at a RETURN, then leave slightly differently. */
-    if (JSOp op = FrameIsFinished(cx)) {
-        /* We're not guaranteed that the RETURN was run. */
-        if (op == JSOP_RETURN && !entryFrame->isBailedAtReturn())
-            entryFrame->setReturnValue(f.regs.sp[-1]);
-
-        /* Cleanup activation objects on the frame unless it's owned by an Invoke. */
-        if (f.fp() != f.entryFp) {
-            if (!InlineReturn(f, JS_TRUE, JS_FALSE))
-                THROWV(NULL);
-        }
+    /* Step 2. If entryFrame is done, use a special path to return to EnterMethodJIT(). */
+    if (FrameIsFinished(cx)) {
+        if (!HandleFinishedFrame(f, entryFrame))
+            THROWV(NULL);
 
         void *retPtr = JS_FUNC_TO_DATA_PTR(void *, InjectJaegerReturn);
         *f.returnAddressLocation() = retPtr;
         return NULL;
     }
 
+    /* Step 3. If entryFrame is at a safe point, just leave. */
+    if (void *ncode = AtSafePoint(cx))
+        return ncode;
+
     /* Step 4. Do a partial interp, then restart the whole process. */
     if (!PartialInterpret(f)) {
-        if (!HandleErrorInExcessFrames(f, entryFrame))
+        if (!HandleErrorInExcessFrame(f, entryFrame))
             THROWV(NULL);
     }
 
     goto restart;
 }
 
 #endif /* JS_TRACER */
 
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -685,20 +685,20 @@ class SetPropCompiler : public PICStubCo
         } 
 
         return generateStub(obj->shape(), shape, false, !obj->hasSlotsArray());
     }
 };
 
 class GetPropCompiler : public PICStubCompiler
 {
-    JSObject *obj;
-    JSAtom *atom;
-    void   *stub;
-    int lastStubSecondShapeGuard;
+    JSObject    *obj;
+    JSAtom      *atom;
+    VoidStubPIC stub;
+    int         lastStubSecondShapeGuard;
 
     static int32 inlineShapeOffset(ic::PICInfo &pic) {
 #if defined JS_NUNBOX32
         return GETPROP_INLINE_SHAPE_OFFSET;
 #elif defined JS_PUNBOX64
         return pic.labels.getprop.inlineShapeOffset;
 #endif
     }
@@ -728,26 +728,21 @@ class GetPropCompiler : public PICStubCo
     }
 
     inline int32 dslotsLoad() {
         return dslotsLoad(pic);
     }
 
   public:
     GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
-                    VoidStub stub)
-      : PICStubCompiler("getprop", f, script, pic), obj(obj), atom(atom),
-        stub(JS_FUNC_TO_DATA_PTR(void *, stub)),
-        lastStubSecondShapeGuard(pic.secondShapeGuard)
-    { }
-
-    GetPropCompiler(VMFrame &f, JSScript *script, JSObject *obj, ic::PICInfo &pic, JSAtom *atom,
                     VoidStubPIC stub)
-      : PICStubCompiler("callprop", f, script, pic), obj(obj), atom(atom),
-        stub(JS_FUNC_TO_DATA_PTR(void *, stub)),
+      : PICStubCompiler(pic.kind == ic::PICInfo::CALL ? "callprop" : "getprop", f, script, pic),
+        obj(obj),
+        atom(atom),
+        stub(stub),
         lastStubSecondShapeGuard(pic.secondShapeGuard)
     { }
 
     static void reset(ic::PICInfo &pic)
     {
         RepatchBuffer repatcher(pic.fastPathStart.executableAddress(), INLINE_PATH_LENGTH);
         repatcher.repatchLEAToLoadPtr(pic.storeBack.instructionAtOffset(dslotsLoad(pic)));
         repatcher.repatch(pic.fastPathStart.dataLabel32AtOffset(
@@ -2007,36 +2002,54 @@ class BindNameCompiler : public PICStubC
 
         if (!generateStub(obj))
             return NULL;
 
         return obj;
     }
 };
 
+static void JS_FASTCALL
+DisabledLengthIC(VMFrame &f, ic::PICInfo *pic)
+{
+    stubs::Length(f);
+}
+
+static void JS_FASTCALL
+DisabledGetPropIC(VMFrame &f, ic::PICInfo *pic)
+{
+    stubs::GetProp(f);
+}
+
+static void JS_FASTCALL
+DisabledGetPropICNoCache(VMFrame &f, ic::PICInfo *pic)
+{
+    stubs::GetPropNoCache(f, pic->atom);
+}
+
 void JS_FASTCALL
 ic::GetProp(VMFrame &f, ic::PICInfo *pic)
 {
     JSScript *script = f.fp()->script();
 
     JSAtom *atom = pic->atom;
     if (atom == f.cx->runtime->atomState.lengthAtom) {
         if (f.regs.sp[-1].isString()) {
-            GetPropCompiler cc(f, script, NULL, *pic, NULL, stubs::Length);
+            GetPropCompiler cc(f, script, NULL, *pic, NULL, DisabledLengthIC);
             if (!cc.generateStringLengthStub()) {
                 cc.disable("error");
                 THROW();
             }
             JSString *str = f.regs.sp[-1].toString();
             f.regs.sp[-1].setInt32(str->length());
             return;
         } else if (!f.regs.sp[-1].isPrimitive()) {
             JSObject *obj = &f.regs.sp[-1].toObject();
             if (obj->isArray() || (obj->isArguments() && !obj->isArgsLengthOverridden())) {
-                GetPropCompiler cc(f, script, obj, *pic, NULL, stubs::Length);
+                GetPropCompiler cc(f, script, obj, *pic, NULL, DisabledLengthIC);
                 if (obj->isArray()) {
                     if (!cc.generateArrayLengthStub()) {
                         cc.disable("error");
                         THROW();
                     }
                     f.regs.sp[-1].setNumber(obj->getArrayLength());
                 } else if (obj->isArguments()) {
                     if (!cc.generateArgsLengthStub()) {
@@ -2051,17 +2064,20 @@ ic::GetProp(VMFrame &f, ic::PICInfo *pic
         atom = f.cx->runtime->atomState.lengthAtom;
     }
 
     JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-1]);
     if (!obj)
         THROW();
 
     if (pic->shouldGenerate()) {
-        GetPropCompiler cc(f, script, obj, *pic, atom, stubs::GetProp);
+        VoidStubPIC stub = pic->usePropCache
+                           ? DisabledGetPropIC
+                           : DisabledGetPropICNoCache;
+        GetPropCompiler cc(f, script, obj, *pic, atom, stub);
         if (!cc.update()) {
             cc.disable("error");
             THROW();
         }
     }
 
     Value v;
     if (!obj->getProperty(f.cx, ATOM_TO_JSID(atom), &v))
@@ -2095,26 +2111,26 @@ ic::GetElem(VMFrame &f, ic::PICInfo *pic
     Value v;
     if (!obj->getProperty(f.cx, ATOM_TO_JSID(atom), &v))
         THROW();
     f.regs.sp[-2] = v;
 }
 
 template <JSBool strict>
 static void JS_FASTCALL
-SetPropDumb(VMFrame &f, ic::PICInfo *pic)
+DisabledSetPropIC(VMFrame &f, ic::PICInfo *pic)
 {
-    stubs::SetPropNoCache<strict>(f, pic->atom);
+    stubs::SetName<strict>(f, pic->atom);
 }
 
 template <JSBool strict>
 static void JS_FASTCALL
-SetPropSlow(VMFrame &f, ic::PICInfo *pic)
+DisabledSetPropICNoCache(VMFrame &f, ic::PICInfo *pic)
 {
-    stubs::SetName<strict>(f, pic->atom);
+    stubs::SetPropNoCache<strict>(f, pic->atom);
 }
 
 void JS_FASTCALL
 ic::SetProp(VMFrame &f, ic::PICInfo *pic)
 {
     JSObject *obj = ValueToObject(f.cx, &f.regs.sp[-2]);
     if (!obj)
         THROW();
@@ -2126,45 +2142,32 @@ ic::SetProp(VMFrame &f, ic::PICInfo *pic
     // Important: We update the PIC before looking up the property so that the
     // PIC is updated only if the property already exists. The PIC doesn't try
     // to optimize adding new properties; that is for the slow case.
     //
     // Also note, we can't use SetName for PROPINC PICs because the property
     // cache can't handle a GET and SET from the same scripted PC.
     //
 
-    VoidStubPIC stub;
-    switch (JSOp(*f.regs.pc)) {
-      case JSOP_PROPINC:
-      case JSOP_PROPDEC:
-      case JSOP_INCPROP:
-      case JSOP_DECPROP:
-      case JSOP_NAMEINC:
-      case JSOP_NAMEDEC:
-      case JSOP_INCNAME:
-      case JSOP_DECNAME:
-        stub = STRICT_VARIANT(SetPropDumb);
-        break;
-      default:
-        stub = STRICT_VARIANT(SetPropSlow);
-        break;
-    }
+    VoidStubPIC stub = pic->usePropCache
+                       ? STRICT_VARIANT(DisabledSetPropIC)
+                       : STRICT_VARIANT(DisabledSetPropICNoCache);
 
     SetPropCompiler cc(f, script, obj, *pic, pic->atom, stub);
     if (!cc.update()) {
         cc.disable("error");
         THROW();
     }
     
     Value rval = f.regs.sp[-1];
     stub(f, pic);
 }
 
 static void JS_FASTCALL
-CallPropSlow(VMFrame &f, ic::PICInfo *pic)
+DisabledCallPropIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::CallProp(f, pic->atom);
 }
 
 void JS_FASTCALL
 ic::CallProp(VMFrame &f, ic::PICInfo *pic)
 {
     JSContext *cx = f.cx;
@@ -2249,17 +2252,17 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pi
                                       &rval)) {
                 THROW();
             }
             regs.sp[-1] = lval;
             regs.sp[-2] = rval;
         }
     }
 
-    GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, CallPropSlow);
+    GetPropCompiler cc(f, script, &objv.toObject(), *pic, pic->atom, DisabledCallPropIC);
     if (usePIC) {
         if (lval.isObject()) {
             if (!cc.update()) {
                 cc.disable("error");
                 THROW();
             }
         } else if (lval.isString()) {
             if (!cc.generateStringCallStub()) {
@@ -2278,36 +2281,36 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pi
         regs.sp[-2].setString(ATOM_TO_STRING(pic->atom));
         if (!js_OnUnknownMethod(cx, regs.sp - 2))
             THROW();
     }
 #endif
 }
 
 static void JS_FASTCALL
-SlowName(VMFrame &f, ic::PICInfo *pic)
+DisabledNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::Name(f);
 }
 
 static void JS_FASTCALL
-SlowXName(VMFrame &f, ic::PICInfo *pic)
+DisabledXNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::GetProp(f);
 }
 
 void JS_FASTCALL
 ic::XName(VMFrame &f, ic::PICInfo *pic)
 {
     JSScript *script = f.fp()->script();
 
     /* GETXPROP is guaranteed to have an object. */
     JSObject *obj = &f.regs.sp[-1].toObject();
 
-    ScopeNameCompiler cc(f, script, obj, *pic, pic->atom, SlowXName);
+    ScopeNameCompiler cc(f, script, obj, *pic, pic->atom, DisabledXNameIC);
 
     if (!cc.updateForXName()) {
         cc.disable("error");
         THROW();
     }
 
     Value rval;
     if (!cc.retrieve(&rval))
@@ -2315,41 +2318,50 @@ ic::XName(VMFrame &f, ic::PICInfo *pic)
     f.regs.sp[-1] = rval;
 }
 
 void JS_FASTCALL
 ic::Name(VMFrame &f, ic::PICInfo *pic)
 {
     JSScript *script = f.fp()->script();
 
-    ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, SlowName);
+    ScopeNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, DisabledNameIC);
 
     if (!cc.updateForName()) {
         cc.disable("error");
         THROW();
     }
 
     Value rval;
     if (!cc.retrieve(&rval))
         THROW();
     f.regs.sp[0] = rval;
 }
 
 static void JS_FASTCALL
-SlowBindName(VMFrame &f, ic::PICInfo *pic)
+DisabledBindNameIC(VMFrame &f, ic::PICInfo *pic)
 {
     stubs::BindName(f);
 }
 
+static void JS_FASTCALL
+DisabledBindNameICNoCache(VMFrame &f, ic::PICInfo *pic)
+{
+    stubs::BindNameNoCache(f, pic->atom);
+}
+
 void JS_FASTCALL
 ic::BindName(VMFrame &f, ic::PICInfo *pic)
 {
     JSScript *script = f.fp()->script();
 
-    BindNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, SlowBindName);
+    VoidStubPIC stub = pic->usePropCache
+                       ? DisabledBindNameIC
+                       : DisabledBindNameICNoCache;
+    BindNameCompiler cc(f, script, &f.fp()->scopeChain(), *pic, pic->atom, stub);
 
     JSObject *obj = cc.update();
     if (!obj) {
         cc.disable("error");
         THROW();
     }
 
     f.regs.sp[0].setObject(*obj);
--- a/js/src/methodjit/PolyIC.h
+++ b/js/src/methodjit/PolyIC.h
@@ -231,16 +231,19 @@ struct PICInfo {
     int secondShapeGuard : 11;
 
     Kind kind : 3;
 
     // True if register R holds the base object shape along exits from the
     // last stub.
     bool shapeRegHasBaseShape : 1;
 
+    // True if can use the property cache.
+    bool usePropCache : 1;
+
     // State flags.
     bool hit : 1;                   // this PIC has been executed
     bool inlinePathPatched : 1;     // inline path has been patched
 
     RegisterID shapeReg : 5;        // also the out type reg
     RegisterID objReg   : 5;        // also the out data reg
 
     // Number of stubs generated.
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -94,16 +94,25 @@ stubs::BindName(VMFrame &f)
         obj = js_FindIdentifierBase(cx, &f.fp()->scopeChain(), id);
         if (!obj)
             THROW();
     }
     f.regs.sp++;
     f.regs.sp[-1].setObject(*obj);
 }
 
+void JS_FASTCALL
+stubs::BindNameNoCache(VMFrame &f, JSAtom *atom)
+{
+    JSObject *obj = js_FindIdentifierBase(f.cx, &f.fp()->scopeChain(), ATOM_TO_JSID(atom));
+    if (!obj)
+        THROW();
+    f.regs.sp[0].setObject(*obj);
+}
+
 JSObject * JS_FASTCALL
 stubs::BindGlobalName(VMFrame &f)
 {
     return f.fp()->scopeChain().getGlobal();
 }
 
 template<JSBool strict>
 void JS_FASTCALL
@@ -2064,16 +2073,30 @@ InlineGetProp(VMFrame &f)
 void JS_FASTCALL
 stubs::GetProp(VMFrame &f)
 {
     if (!InlineGetProp(f))
         THROW();
 }
 
 void JS_FASTCALL
+stubs::GetPropNoCache(VMFrame &f, JSAtom *atom)
+{
+    JSContext *cx = f.cx;
+
+    Value *vp = &f.regs.sp[-1];
+    JSObject *obj = ValueToObject(cx, vp);
+    if (!obj)
+        THROW();
+
+    if (!obj->getProperty(cx, ATOM_TO_JSID(atom), vp))
+        THROW();
+}
+
+void JS_FASTCALL
 stubs::CallProp(VMFrame &f, JSAtom *origAtom)
 {
     JSContext *cx = f.cx;
     JSFrameRegs &regs = f.regs;
 
     Value lval;
     lval = regs.sp[-1];
 
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -60,16 +60,18 @@ void JS_FASTCALL InitMethod(VMFrame &f, 
 
 void JS_FASTCALL HitStackQuota(VMFrame &f);
 void * JS_FASTCALL FixupArity(VMFrame &f, uint32 argc);
 void * JS_FASTCALL CompileFunction(VMFrame &f, uint32 argc);
 void JS_FASTCALL SlowNew(VMFrame &f, uint32 argc);
 void JS_FASTCALL SlowCall(VMFrame &f, uint32 argc);
 void * JS_FASTCALL UncachedNew(VMFrame &f, uint32 argc);
 void * JS_FASTCALL UncachedCall(VMFrame &f, uint32 argc);
+void JS_FASTCALL EnterScript(VMFrame &f);
+void JS_FASTCALL LeaveScript(VMFrame &f);
 
 /*
  * Result struct for UncachedXHelper.
  *
  * These functions can have one of two results:
  *
  *   (1) The function was executed in the interpreter. Then all fields
  *       are NULL.
@@ -107,23 +109,25 @@ void * JS_FASTCALL InvokeTracer(VMFrame 
 #else
 void * JS_FASTCALL InvokeTracer(VMFrame &f);
 #endif
 
 void * JS_FASTCALL LookupSwitch(VMFrame &f, jsbytecode *pc);
 void * JS_FASTCALL TableSwitch(VMFrame &f, jsbytecode *origPc);
 
 void JS_FASTCALL BindName(VMFrame &f);
+void JS_FASTCALL BindNameNoCache(VMFrame &f, JSAtom *atom);
 JSObject * JS_FASTCALL BindGlobalName(VMFrame &f);
 template<JSBool strict> void JS_FASTCALL SetName(VMFrame &f, JSAtom *atom);
 template<JSBool strict> void JS_FASTCALL SetPropNoCache(VMFrame &f, JSAtom *atom);
 template<JSBool strict> void JS_FASTCALL SetGlobalName(VMFrame &f, JSAtom *atom);
 template<JSBool strict> void JS_FASTCALL SetGlobalNameDumb(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL Name(VMFrame &f);
 void JS_FASTCALL GetProp(VMFrame &f);
+void JS_FASTCALL GetPropNoCache(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL GetElem(VMFrame &f);
 void JS_FASTCALL CallElem(VMFrame &f);
 template<JSBool strict> void JS_FASTCALL SetElem(VMFrame &f);
 void JS_FASTCALL Length(VMFrame &f);
 void JS_FASTCALL CallName(VMFrame &f);
 void JS_FASTCALL GetUpvar(VMFrame &f, uint32 index);
 void JS_FASTCALL GetGlobalName(VMFrame &f);
 
--- a/js/src/trace-test/tests/jaeger/bug563000/trap-force-return-1.js
+++ b/js/src/trace-test/tests/jaeger/bug563000/trap-force-return-1.js
@@ -1,7 +1,7 @@
 setDebug(true);
 function main() {
   return "failure";
 }
 /* JSOP_RETURN in main. */
-trap(main, 4, "'success'");
+trap(main, 3, "'success'");
 assertEq(main(), "success");
--- a/js/src/trace-test/tests/jaeger/bug563000/trap-parent-from-trap.js
+++ b/js/src/trace-test/tests/jaeger/bug563000/trap-parent-from-trap.js
@@ -5,17 +5,17 @@ function child() {
   x = "failure1";
   /* JSOP_STOP in parent. */
   trap(parent, 10, "success()");
 }
 
 function parent() {
   x = "failure2";
 }
-/* First op in parent: because of JSOP_BEGIN, it is op 1. */
-trap(parent, 1, "child()");
+/* First op in parent. */
+trap(parent, 0, "child()");
 
 function success() {
   x = "success";
 }
 
 parent();
 assertEq(x, "success");
--- a/js/src/trace-test/tests/jaeger/bug563000/trap-self-from-trap.js
+++ b/js/src/trace-test/tests/jaeger/bug563000/trap-self-from-trap.js
@@ -1,23 +1,23 @@
 setDebug(true);
 x = "notset";
 
 function doNothing() { }
 
 function myparent(nested) {
   if (nested) {
     /* JSOP_CALL to doNothing in myparent with nested = true. */
-    trap(myparent, 25, "success()");
+    trap(myparent, 24, "success()");
     doNothing();
   } else {
     doNothing();
   }
 }
 /* JSOP_CALL to doNothing in myparent with nested = false. */
-trap(myparent, 36, "myparent(true)");
+trap(myparent, 35, "myparent(true)");
 
 function success() {
   x = "success";
 }
 
 myparent(false);
 assertEq(x, "success");
new file mode 100644
--- /dev/null
+++ b/js/src/trace-test/tests/jaeger/deepBailAfterRunTracer.js
@@ -0,0 +1,25 @@
+var o = { };
+for (var i = 0; i <= 50; i++)
+    o[i] = i;
+
+Object.defineProperty(o, "51", { get: assertEq });
+
+var threw = 0;
+function g(o, i) {
+    try {
+        assertEq(o[i], i);
+    } catch (e) {
+        threw++;
+    }
+}
+
+function f() {
+    for (var i = 0; i <= 51; i++)
+      g(o, i);
+}
+
+f();
+f();
+f();
+assertEq(threw, 3);
+