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 id16433
push userrsayre@mozilla.com
push dateWed, 20 Oct 2010 14:14:01 +0000
treeherdermozilla-central@571ddddc7e13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs603044
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);
+