backout bug 778948 eace14fccc47 for horrible sunspider regression r=me
authorBenjamin Peterson <benjamin@python.org>
Fri, 26 Oct 2012 17:59:35 -0700
changeset 111725 265427a0694d7ce60f068ca323c88327744b8c58
parent 111724 647d6f4cd15d961dbf3d4aa4183704e7d470e6fd
child 111726 2d4af8375b3a8102672cb2f5a84ea0ae9bcdaddb
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersme
bugs778948
milestone19.0a1
backout bug 778948 eace14fccc47 for horrible sunspider regression r=me
js/src/Makefile.in
js/src/builtin/Eval.cpp
js/src/frontend/Parser.cpp
js/src/ion/Bailouts.cpp
js/src/ion/CodeGenerator.cpp
js/src/ion/Ion.h
js/src/ion/IonCaches.cpp
js/src/ion/VMFunctions.cpp
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jscntxtinlines.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsexn.cpp
js/src/jsfun.cpp
js/src/jsgc.cpp
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsinterpinlines.h
js/src/jsiter.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/json.cpp
js/src/jsprobes.cpp
js/src/jsscript.cpp
js/src/jsstr.cpp
js/src/jstypedarray.cpp
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MonoIC.cpp
js/src/methodjit/PolyIC.cpp
js/src/methodjit/Retcon.cpp
js/src/methodjit/StubCalls.cpp
js/src/shell/js.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Debugger.cpp
js/src/vm/Interpreter-inl.h
js/src/vm/Interpreter.cpp
js/src/vm/Interpreter.h
js/src/vm/ObjectImpl-inl.h
js/src/vm/ObjectImpl.cpp
js/src/vm/Stack.cpp
--- a/js/src/Makefile.in
+++ b/js/src/Makefile.in
@@ -79,16 +79,17 @@ CPPSRCS		= \
 		jsdhash.cpp \
 		jsdtoa.cpp \
 		jsexn.cpp \
 		jsfriendapi.cpp \
 		jsfun.cpp \
 		jsgc.cpp \
 		jscrashreport.cpp \
 		jsinfer.cpp \
+		jsinterp.cpp \
 		jsiter.cpp \
 		jslog2.cpp \
 		jsmath.cpp \
 		jsmemorymetrics.cpp \
 		jsnativestack.cpp \
 		jsnum.cpp \
 		jsobj.cpp \
 		json.cpp \
@@ -117,17 +118,16 @@ CPPSRCS		= \
 		Debugger.cpp \
 		GlobalObject.cpp \
 		ObjectImpl.cpp \
 		Stack.cpp \
 		String.cpp \
 		BytecodeCompiler.cpp \
 		BytecodeEmitter.cpp \
 		FoldConstants.cpp \
-		Interpreter.cpp \
 		NameFunctions.cpp \
 		ParallelArray.cpp \
 		ParseMaps.cpp \
 		ParseNode.cpp \
 		Parser.cpp \
 		SPSProfiler.cpp \
 		TokenStream.cpp \
 		TestingFunctions.cpp \
@@ -862,17 +862,17 @@ ifdef HAVE_DTRACE
 $(CURDIR)/javascript-trace.h: $(srcdir)/devtools/javascript-trace.d
 	dtrace -h -s $(srcdir)/devtools/javascript-trace.d -o javascript-trace.h.in
 	sed -e 's/if _DTRACE_VERSION/ifdef INCLUDE_MOZILLA_DTRACE/' \
 	    -e '/const/!s/char \*/const char */g' \
 	    javascript-trace.h.in > javascript-trace.h
 
 # We can't automatically generate dependencies on auto-generated headers;
 # we have to list them explicitly.
-$(addsuffix .$(OBJ_SUFFIX),jsprobes jsobj): $(CURDIR)/javascript-trace.h
+$(addsuffix .$(OBJ_SUFFIX),jsprobes jsinterp jsobj): $(CURDIR)/javascript-trace.h
 endif
 
 ifdef HAVE_LINUX_PERF_EVENT_H
 pm_linux.$(OBJ_SUFFIX): CXXFLAGS += $(LINUX_HEADERS_INCLUDES)
 endif
 
 # Prepare self-hosted JS code for embedding
 export:: selfhosting
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -8,17 +8,17 @@
 #include "jscntxt.h"
 #include "jsonparser.h"
 
 #include "builtin/Eval.h"
 #include "frontend/BytecodeCompiler.h"
 #include "mozilla/HashFunctions.h"
 #include "vm/GlobalObject.h"
 
-#include "vm/Interpreter-inl.h"
+#include "jsinterpinlines.h"
 
 using namespace js;
 
 // We should be able to assert this for *any* fp->scopeChain().
 static void
 AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj)
 {
 #ifdef DEBUG
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -26,16 +26,17 @@
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
--- a/js/src/ion/Bailouts.cpp
+++ b/js/src/ion/Bailouts.cpp
@@ -2,16 +2,17 @@
  * vim: set ts=4 sw=4 et tw=99:
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jscntxt.h"
 #include "jscompartment.h"
+#include "jsinterp.h"
 #include "Bailouts.h"
 #include "SnapshotReader.h"
 #include "Ion.h"
 #include "IonCompartment.h"
 #include "IonSpewer.h"
 #include "jsinfer.h"
 #include "jsanalyze.h"
 #include "jsinferinlines.h"
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -7,18 +7,18 @@
 
 #include "CodeGenerator.h"
 #include "IonLinker.h"
 #include "IonSpewer.h"
 #include "MIRGenerator.h"
 #include "shared/CodeGenerator-shared-inl.h"
 #include "jsnum.h"
 #include "jsmath.h"
-
-#include "vm/Interpreter-inl.h"
+#include "jsinterpinlines.h"
+
 #include "vm/StringObject-inl.h"
 
 using namespace js;
 using namespace js::ion;
 
 namespace js {
 namespace ion {
 
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -7,17 +7,17 @@
 
 #if !defined(jsion_ion_h__) && defined(JS_ION)
 #define jsion_ion_h__
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "IonCode.h"
 #include "jsinfer.h"
-#include "vm/Interpreter.h"
+#include "jsinterp.h"
 
 namespace js {
 namespace ion {
 
 class TempAllocator;
 
 struct IonOptions
 {
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -9,19 +9,19 @@
 
 #include "CodeGenerator.h"
 #include "Ion.h"
 #include "IonCaches.h"
 #include "IonLinker.h"
 #include "IonSpewer.h"
 #include "VMFunctions.h"
 
-#include "vm/Interpreter-inl.h"
+#include "jsinterpinlines.h"
+
 #include "vm/Stack.h"
-
 #include "IonFrames-inl.h"
 
 using namespace js;
 using namespace js::ion;
 
 void
 CodeLocationJump::repoint(IonCode *code, MacroAssembler *masm)
 {
--- a/js/src/ion/VMFunctions.cpp
+++ b/js/src/ion/VMFunctions.cpp
@@ -2,22 +2,24 @@
  * vim: set ts=4 sw=4 et tw=99:
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Ion.h"
 #include "IonCompartment.h"
+#include "jsinterp.h"
 #include "ion/IonFrames.h"
 #include "ion/IonFrames-inl.h" // for GetTopIonJSScript
 
-#include "vm/Interpreter-inl.h"
 #include "vm/StringObject-inl.h"
 
+#include "jsinterpinlines.h"
+
 using namespace js;
 using namespace js::ion;
 
 namespace js {
 namespace ion {
 
 static inline bool
 ShouldMonitorReturnType(JSFunction *fun)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -28,16 +28,17 @@
 #include "jsclone.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdate.h"
 #include "jsdtoa.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsmath.h"
 #include "jsnativestack.h"
 #include "jsnum.h"
 #include "json.h"
 #include "jsobj.h"
 #include "jsopcode.h"
@@ -58,25 +59,24 @@
 #include "builtin/RegExp.h"
 #include "builtin/ParallelArray.h"
 #include "ds/LifoAlloc.h"
 #include "frontend/BytecodeCompiler.h"
 #include "gc/Marking.h"
 #include "gc/Memory.h"
 #include "js/MemoryMetrics.h"
 #include "vm/Debugger.h"
-#include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
 #include "vm/StringBuffer.h"
 #include "vm/Xdr.h"
 #include "yarr/BumpPointerAllocator.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
-#include "vm/Interpreter-inl.h"
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/ObjectImpl-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/RegExpStatics-inl.h"
 #include "vm/Stack-inl.h"
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -77,16 +77,17 @@
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsscope.h"
 #include "jswrapper.h"
 #include "methodjit/MethodJIT.h"
 #include "methodjit/StubCalls.h"
@@ -97,22 +98,22 @@
 #include "vm/NumericConversions.h"
 #include "vm/StringBuffer.h"
 
 #include "ds/Sort.h"
 
 #include "jsarrayinlines.h"
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsstrinlines.h"
 
 #include "vm/ArgumentsObject-inl.h"
-#include "vm/Interpreter-inl.h"
 #include "vm/ObjectImpl-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace mozilla;
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
 
--- a/js/src/jscntxtinlines.h
+++ b/js/src/jscntxtinlines.h
@@ -6,23 +6,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef jscntxtinlines_h___
 #define jscntxtinlines_h___
 
 #include "jscntxt.h"
 #include "jscompartment.h"
 #include "jsfriendapi.h"
+#include "jsinterp.h"
 #include "jsprobes.h"
 #include "jsxml.h"
 #include "jsgc.h"
 
 #include "frontend/ParseMaps.h"
 #include "vm/RegExpObject.h"
-#include "vm/Interpreter.h"
 
 #include "jsgcinlines.h"
 
 namespace js {
 
 inline void
 NewObjectCache::staticAsserts()
 {
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -30,16 +30,17 @@
 #include "jstypes.h"
 #include "jsprf.h"
 #include "prmjtime.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsversion.h"
 #include "jscntxt.h"
 #include "jsdate.h"
+#include "jsinterp.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsstr.h"
 #include "jslibmath.h"
 
 #include "vm/GlobalObject.h"
 #include "vm/NumericConversions.h"
 #include "vm/StringBuffer.h"
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -14,16 +14,17 @@
 #include "jsutil.h"
 #include "jsclist.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jslock.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jsstr.h"
 #include "jswatchpoint.h"
 #include "jswrapper.h"
@@ -32,20 +33,20 @@
 #include "frontend/BytecodeEmitter.h"
 #include "frontend/Parser.h"
 #include "vm/Debugger.h"
 #include "ion/Ion.h"
 
 #include "jsatominlines.h"
 #include "jsinferinlines.h"
 #include "jsobjinlines.h"
+#include "jsinterpinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
-#include "vm/Interpreter-inl.h"
 #include "vm/Stack-inl.h"
 
 #include "jsautooplen.h"
 #include "mozilla/Util.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace mozilla;
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -17,16 +17,17 @@
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 #include "jswrapper.h"
 
 #include "gc/Marking.h"
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -18,16 +18,17 @@
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jspropertytree.h"
 #include "jsproxy.h"
 #include "jsscope.h"
@@ -45,21 +46,21 @@
 
 #ifdef JS_METHODJIT
 #include "methodjit/MethodJIT.h"
 #endif
 
 #include "jsatominlines.h"
 #include "jsfuninlines.h"
 #include "jsinferinlines.h"
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/ArgumentsObject-inl.h"
-#include "vm/Interpreter-inl.h"
 #include "vm/ScopeObject-inl.h"
 #include "vm/Stack-inl.h"
 
 #ifdef JS_ION
 #include "ion/Ion.h"
 #include "ion/IonFrameIterator.h"
 #include "ion/IonFrameIterator-inl.h"
 #endif
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -52,16 +52,17 @@
 #include "jscrashreport.h"
 #include "jscrashformat.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsprobes.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
@@ -79,16 +80,17 @@
 #include "vm/Debugger.h"
 #include "vm/String.h"
 #include "ion/IonCode.h"
 #ifdef JS_ION
 # include "ion/IonMacroAssembler.h"
 #endif
 #include "ion/IonFrameIterator.h"
 
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 
 #include "vm/ScopeObject-inl.h"
 #include "vm/String-inl.h"
 
 #ifdef MOZ_VALGRIND
 # define JS_VALGRIND
 #endif
new file mode 100644
--- /dev/null
+++ b/js/src/jsinterp.cpp
@@ -0,0 +1,4025 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sw=4 et tw=99:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * JavaScript bytecode interpreter.
+ */
+
+#include "mozilla/FloatingPoint.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "jstypes.h"
+#include "jsutil.h"
+#include "jsprf.h"
+#include "jsapi.h"
+#include "jsarray.h"
+#include "jsatom.h"
+#include "jsbool.h"
+#include "jscntxt.h"
+#include "jsdate.h"
+#include "jsversion.h"
+#include "jsdbgapi.h"
+#include "jsfun.h"
+#include "jsgc.h"
+#include "jsinterp.h"
+#include "jsiter.h"
+#include "jslibmath.h"
+#include "jslock.h"
+#include "jsnum.h"
+#include "jsobj.h"
+#include "jsopcode.h"
+#include "jspropertycache.h"
+#include "jsscope.h"
+#include "jsscript.h"
+#include "jsstr.h"
+
+#include "builtin/Eval.h"
+#include "gc/Marking.h"
+#include "vm/Debugger.h"
+
+#ifdef JS_METHODJIT
+#include "methodjit/MethodJIT.h"
+#include "methodjit/Logging.h"
+#endif
+#include "ion/Ion.h"
+
+#include "jsatominlines.h"
+#include "jsinferinlines.h"
+#include "jsinterpinlines.h"
+#include "jsobjinlines.h"
+#include "jsopcodeinlines.h"
+#include "jsprobes.h"
+#include "jspropertycacheinlines.h"
+#include "jsscopeinlines.h"
+#include "jsscriptinlines.h"
+#include "jstypedarrayinlines.h"
+
+#include "builtin/Iterator-inl.h"
+#include "vm/Stack-inl.h"
+#include "vm/String-inl.h"
+
+#if JS_HAS_XML_SUPPORT
+#include "jsxml.h"
+#endif
+
+#include "jsautooplen.h"
+
+#if defined(JS_METHODJIT) && defined(JS_MONOIC)
+#include "methodjit/MonoIC.h"
+#endif
+
+#if JS_TRACE_LOGGING
+#include "TraceLogging.h"
+#endif
+
+using namespace js;
+using namespace js::gc;
+using namespace js::types;
+
+/* Some objects (e.g., With) delegate 'this' to another object. */
+static inline JSObject *
+CallThisObjectHook(JSContext *cx, HandleObject obj, Value *argv)
+{
+    JSObject *thisp = JSObject::thisObject(cx, obj);
+    if (!thisp)
+        return NULL;
+    argv[-1].setObject(*thisp);
+    return thisp;
+}
+
+/*
+ * ECMA requires "the global object", but in embeddings such as the browser,
+ * which have multiple top-level objects (windows, frames, etc. in the DOM),
+ * we prefer fun's parent.  An example that causes this code to run:
+ *
+ *   // in window w1
+ *   function f() { return this }
+ *   function g() { return f }
+ *
+ *   // in window w2
+ *   var h = w1.g()
+ *   alert(h() == w1)
+ *
+ * The alert should display "true".
+ */
+bool
+js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
+{
+    /*
+     * Check for SynthesizeFrame poisoning and fast constructors which
+     * didn't check their callee properly.
+     */
+    Value thisv = call.thisv();
+    JS_ASSERT(!thisv.isMagic());
+
+#ifdef DEBUG
+    JSFunction *fun = call.callee().isFunction() ? call.callee().toFunction() : NULL;
+    JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode());
+#endif
+
+    if (thisv.isNullOrUndefined()) {
+        Rooted<GlobalObject*> global(cx, &call.callee().global());
+        JSObject *thisp = JSObject::thisObject(cx, global);
+        if (!thisp)
+            return false;
+        call.setThis(ObjectValue(*thisp));
+        return true;
+    }
+
+    if (!thisv.isObject()) {
+        if (!js_PrimitiveToObject(cx, &thisv))
+            return false;
+        call.setThis(thisv);
+    }
+
+    return true;
+}
+
+#if JS_HAS_NO_SUCH_METHOD
+
+const uint32_t JSSLOT_FOUND_FUNCTION  = 0;
+const uint32_t JSSLOT_SAVED_ID        = 1;
+
+Class js_NoSuchMethodClass = {
+    "NoSuchMethod",
+    JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
+    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
+    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
+};
+
+/*
+ * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
+ * the base object, we search for the __noSuchMethod__ method in the base.
+ * If it exists, we store the method and the property's id into an object of
+ * NoSuchMethod class and store this object into the callee's stack slot.
+ * Later, Invoke will recognise such an object and transfer control to
+ * NoSuchMethod that invokes the method like:
+ *
+ *   this.__noSuchMethod__(id, args)
+ *
+ * where id is the name of the method that this invocation attempted to
+ * call by name, and args is an Array containing this invocation's actual
+ * parameters.
+ */
+bool
+js::OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval_, MutableHandleValue vp)
+{
+    RootedValue idval(cx, idval_);
+
+    RootedId id(cx, NameToId(cx->names().noSuchMethod));
+    RootedValue value(cx);
+    if (!GetMethod(cx, obj, id, 0, &value))
+        return false;
+    TypeScript::MonitorUnknown(cx);
+
+    if (value.get().isPrimitive()) {
+        vp.set(value);
+    } else {
+#if JS_HAS_XML_SUPPORT
+        /* Extract the function name from function::name qname. */
+        if (idval.get().isObject()) {
+            JSObject *obj = &idval.get().toObject();
+            if (js_GetLocalNameFromFunctionQName(obj, id.address(), cx))
+                idval = IdToValue(id);
+        }
+#endif
+
+        JSObject *obj = NewObjectWithClassProto(cx, &js_NoSuchMethodClass, NULL, NULL);
+        if (!obj)
+            return false;
+
+        obj->setSlot(JSSLOT_FOUND_FUNCTION, value);
+        obj->setSlot(JSSLOT_SAVED_ID, idval);
+        vp.setObject(*obj);
+    }
+    return true;
+}
+
+static JSBool
+NoSuchMethod(JSContext *cx, unsigned argc, Value *vp)
+{
+    InvokeArgsGuard args;
+    if (!cx->stack.pushInvokeArgs(cx, 2, &args))
+        return JS_FALSE;
+
+    JS_ASSERT(vp[0].isObject());
+    JS_ASSERT(vp[1].isObject());
+    JSObject *obj = &vp[0].toObject();
+    JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
+
+    args.setCallee(obj->getSlot(JSSLOT_FOUND_FUNCTION));
+    args.setThis(vp[1]);
+    args[0] = obj->getSlot(JSSLOT_SAVED_ID);
+    JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2);
+    if (!argsobj)
+        return JS_FALSE;
+    args[1].setObject(*argsobj);
+    JSBool ok = Invoke(cx, args);
+    vp[0] = args.rval();
+    return ok;
+}
+
+#endif /* JS_HAS_NO_SUCH_METHOD */
+
+bool
+js::ReportIsNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct)
+{
+    unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
+
+    RootedValue val(cx, v);
+    js_ReportValueError3(cx, error, JSDVG_SEARCH_STACK, val, NullPtr(), NULL, NULL);
+    return false;
+}
+
+bool
+js::ReportIsNotFunction(JSContext *cx, const Value *vp, MaybeConstruct construct)
+{
+    ptrdiff_t spIndex = cx->stack.spIndexOf(vp);
+    unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
+
+    RootedValue val(cx, *vp);
+    js_ReportValueError3(cx, error, spIndex, val, NullPtr(), NULL, NULL);
+    return false;
+}
+
+JSObject *
+js::ValueToCallable(JSContext *cx, const Value *vp, MaybeConstruct construct)
+{
+    if (vp->isObject()) {
+        JSObject *callable = &vp->toObject();
+        if (callable->isCallable())
+            return callable;
+    }
+
+    ReportIsNotFunction(cx, vp, construct);
+    return NULL;
+}
+
+bool
+js::RunScript(JSContext *cx, HandleScript script, StackFrame *fp)
+{
+    JS_ASSERT(script);
+    JS_ASSERT(fp == cx->fp());
+    JS_ASSERT(fp->script() == script);
+    JS_ASSERT_IF(!fp->isGeneratorFrame(), cx->regs().pc == script->code);
+    JS_ASSERT_IF(fp->isEvalFrame(), script->isActiveEval);
+#ifdef JS_METHODJIT_SPEW
+    JMCheckLogging();
+#endif
+
+    JS_CHECK_RECURSION(cx, return false);
+
+#ifdef DEBUG
+    struct CheckStackBalance {
+        JSContext *cx;
+        StackFrame *fp;
+        RootedObject enumerators;
+        CheckStackBalance(JSContext *cx)
+          : cx(cx), fp(cx->fp()), enumerators(cx, cx->enumerators)
+        {}
+        ~CheckStackBalance() {
+            JS_ASSERT(fp == cx->fp());
+            JS_ASSERT_IF(!fp->isGeneratorFrame(), enumerators == cx->enumerators);
+        }
+    } check(cx);
+#endif
+
+    SPSEntryMarker marker(cx->runtime);
+
+#ifdef JS_ION
+    if (ion::IsEnabled(cx)) {
+        ion::MethodStatus status = ion::CanEnter(cx, script, fp, false);
+        if (status == ion::Method_Error)
+            return false;
+        if (status == ion::Method_Compiled) {
+            ion::IonExecStatus status = ion::Cannon(cx, fp);
+
+            // Note that if we bailed out, new inline frames may have been
+            // pushed, so we interpret with the current fp.
+            if (status == ion::IonExec_Bailout)
+                return Interpret(cx, fp, JSINTERP_REJOIN);
+
+            return status != ion::IonExec_Error;
+        }
+    }
+#endif
+
+#ifdef JS_METHODJIT
+    mjit::CompileStatus status;
+    status = mjit::CanMethodJIT(cx, script, script->code, fp->isConstructing(),
+                                mjit::CompileRequest_Interpreter, fp);
+    if (status == mjit::Compile_Error)
+        return false;
+
+    if (status == mjit::Compile_Okay)
+        return mjit::JaegerStatusToSuccess(mjit::JaegerShot(cx, false));
+#endif
+
+    return Interpret(cx, fp) != Interpret_Error;
+}
+
+/*
+ * Find a function reference and its 'this' value implicit first parameter
+ * under argc arguments on cx's stack, and call the function.  Push missing
+ * required arguments, allocate declared local variables, and pop everything
+ * when done.  Then push the return value.
+ */
+bool
+js::InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct)
+{
+    JS_ASSERT(args.length() <= StackSpace::ARGS_LENGTH_MAX);
+    JS_ASSERT(!cx->compartment->activeAnalysis);
+
+    /* We should never enter a new script while cx->iterValue is live. */
+    JS_ASSERT(cx->iterValue.isMagic(JS_NO_ITER_VALUE));
+
+    /* MaybeConstruct is a subset of InitialFrameFlags */
+    InitialFrameFlags initial = (InitialFrameFlags) construct;
+
+    if (args.calleev().isPrimitive())
+        return ReportIsNotFunction(cx, args.calleev().address(), construct);
+
+    JSObject &callee = args.callee();
+    Class *clasp = callee.getClass();
+
+    /* Invoke non-functions. */
+    if (JS_UNLIKELY(clasp != &FunctionClass)) {
+#if JS_HAS_NO_SUCH_METHOD
+        if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
+            return NoSuchMethod(cx, args.length(), args.base());
+#endif
+        JS_ASSERT_IF(construct, !clasp->construct);
+        if (!clasp->call)
+            return ReportIsNotFunction(cx, args.calleev().address(), construct);
+        return CallJSNative(cx, clasp->call, args);
+    }
+
+    /* Invoke native functions. */
+    RootedFunction fun(cx, callee.toFunction());
+    JS_ASSERT_IF(construct, !fun->isNativeConstructor());
+    if (fun->isNative())
+        return CallJSNative(cx, fun->native(), args);
+
+    if (!TypeMonitorCall(cx, args, construct))
+        return false;
+
+    /* Get pointer to new frame/slots, prepare arguments. */
+    InvokeFrameGuard ifg;
+    if (!cx->stack.pushInvokeFrame(cx, args, initial, &ifg))
+        return false;
+
+    /* Run function until JSOP_STOP, JSOP_RETURN or error. */
+    RootedScript script(cx, fun->script());
+    JSBool ok = RunScript(cx, script, ifg.fp());
+
+    /* Propagate the return value out. */
+    args.rval().set(ifg.fp()->returnValue());
+    JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive());
+    return ok;
+}
+
+bool
+js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, Value *argv,
+           Value *rval)
+{
+    InvokeArgsGuard args;
+    if (!cx->stack.pushInvokeArgs(cx, argc, &args))
+        return false;
+
+    args.setCallee(fval);
+    args.setThis(thisv);
+    PodCopy(args.array(), argv, argc);
+
+    if (args.thisv().isObject()) {
+        /*
+         * We must call the thisObject hook in case we are not called from the
+         * interpreter, where a prior bytecode has computed an appropriate
+         * |this| already.
+         */
+        RootedObject thisObj(cx, &args.thisv().toObject());
+        JSObject *thisp = JSObject::thisObject(cx, thisObj);
+        if (!thisp)
+             return false;
+        args.setThis(ObjectValue(*thisp));
+    }
+
+    if (!Invoke(cx, args))
+        return false;
+
+    *rval = args.rval();
+    return true;
+}
+
+bool
+js::InvokeConstructorKernel(JSContext *cx, CallArgs args)
+{
+    JS_ASSERT(!FunctionClass.construct);
+
+    args.setThis(MagicValue(JS_IS_CONSTRUCTING));
+
+    if (!args.calleev().isObject())
+        return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
+
+    JSObject &callee = args.callee();
+    if (callee.isFunction()) {
+        JSFunction *fun = callee.toFunction();
+
+        if (fun->isNativeConstructor()) {
+            Probes::calloutBegin(cx, fun);
+            bool ok = CallJSNativeConstructor(cx, fun->native(), args);
+            Probes::calloutEnd(cx, fun);
+            return ok;
+        }
+
+        if (!fun->isInterpretedConstructor())
+            return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
+
+        if (!InvokeKernel(cx, args, CONSTRUCT))
+            return false;
+
+        JS_ASSERT(args.rval().isObject());
+        return true;
+    }
+
+    Class *clasp = callee.getClass();
+    if (!clasp->construct)
+        return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
+
+    return CallJSNativeConstructor(cx, clasp->construct, args);
+}
+
+bool
+js::InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv, Value *rval)
+{
+    InvokeArgsGuard args;
+    if (!cx->stack.pushInvokeArgs(cx, argc, &args))
+        return false;
+
+    args.setCallee(fval);
+    args.setThis(MagicValue(JS_THIS_POISON));
+    PodCopy(args.array(), argv, argc);
+
+    if (!InvokeConstructor(cx, args))
+        return false;
+
+    *rval = args.rval();
+    return true;
+}
+
+bool
+js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, unsigned argc, Value *argv,
+                         Value *rval)
+{
+    /*
+     * Invoke could result in another try to get or set the same id again, see
+     * bug 355497.
+     */
+    JS_CHECK_RECURSION(cx, return false);
+
+    return Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
+}
+
+bool
+js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Value &thisv,
+                  ExecuteType type, StackFrame *evalInFrame, Value *result)
+{
+    JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
+    JS_ASSERT_IF(type == EXECUTE_GLOBAL, !scopeChain.isScope());
+
+    if (script->isEmpty()) {
+        if (result)
+            result->setUndefined();
+        return true;
+    }
+
+    ExecuteFrameGuard efg;
+    if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
+        return false;
+
+    if (!script->ensureRanAnalysis(cx))
+        return false;
+    TypeScript::SetThis(cx, script, efg.fp()->thisValue());
+
+    Probes::startExecution(script);
+    bool ok = RunScript(cx, script, efg.fp());
+    Probes::stopExecution(script);
+
+    /* Propgate the return value out. */
+    if (result)
+        *result = efg.fp()->returnValue();
+    return ok;
+}
+
+bool
+js::Execute(JSContext *cx, HandleScript script, JSObject &scopeChainArg, Value *rval)
+{
+    /* The scope chain could be anything, so innerize just in case. */
+    RootedObject scopeChain(cx, &scopeChainArg);
+    scopeChain = GetInnerObject(cx, scopeChain);
+    if (!scopeChain)
+        return false;
+
+    /* If we were handed a non-native object, complain bitterly. */
+    if (!scopeChain->isNative()) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NON_NATIVE_SCOPE);
+        return false;
+    }
+    JS_ASSERT(!scopeChain->getOps()->defineProperty);
+
+    /* The VAROBJFIX option makes varObj == globalObj in global code. */
+    if (!cx->hasRunOption(JSOPTION_VAROBJFIX)) {
+        if (!scopeChain->setVarObj(cx))
+            return false;
+    }
+
+    /* Use the scope chain as 'this', modulo outerization. */
+    JSObject *thisObj = JSObject::thisObject(cx, scopeChain);
+    if (!thisObj)
+        return false;
+    Value thisv = ObjectValue(*thisObj);
+
+    return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
+                         NULL /* evalInFrame */, rval);
+}
+
+bool
+js::HasInstance(JSContext *cx, HandleObject obj, HandleValue v, JSBool *bp)
+{
+    Class *clasp = obj->getClass();
+    RootedValue local(cx, v);
+    if (clasp->hasInstance)
+        return clasp->hasInstance(cx, obj, &local, bp);
+
+    RootedValue val(cx, ObjectValue(*obj));
+    js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
+                        JSDVG_SEARCH_STACK, val, NullPtr());
+    return JS_FALSE;
+}
+
+bool
+js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result)
+{
+#if JS_HAS_XML_SUPPORT
+    if (JS_UNLIKELY(lval.isObject() && lval.toObject().isXML()) ||
+                    (rval.isObject() && rval.toObject().isXML())) {
+        JSBool res;
+        if (!js_TestXMLEquality(cx, lval, rval, &res))
+            return false;
+        *result = !!res;
+        return true;
+    }
+#endif
+
+    if (SameType(lval, rval)) {
+        if (lval.isString()) {
+            JSString *l = lval.toString();
+            JSString *r = rval.toString();
+            return EqualStrings(cx, l, r, result);
+        }
+
+        if (lval.isDouble()) {
+            double l = lval.toDouble(), r = rval.toDouble();
+            *result = (l == r);
+            return true;
+        }
+
+        if (lval.isObject()) {
+            JSObject *l = &lval.toObject();
+            JSObject *r = &rval.toObject();
+
+            if (JSEqualityOp eq = l->getClass()->ext.equality) {
+                JSBool res;
+                RootedObject lobj(cx, l);
+                RootedValue r(cx, rval);
+                if (!eq(cx, lobj, r, &res))
+                    return false;
+                *result = !!res;
+                return true;
+            }
+
+            *result = l == r;
+            return true;
+        }
+
+        *result = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
+        return true;
+    }
+
+    if (lval.isNullOrUndefined()) {
+        *result = rval.isNullOrUndefined();
+        return true;
+    }
+
+    if (rval.isNullOrUndefined()) {
+        *result = false;
+        return true;
+    }
+
+    RootedValue lvalue(cx, lval);
+    RootedValue rvalue(cx, rval);
+
+    if (!ToPrimitive(cx, lvalue.address()))
+        return false;
+    if (!ToPrimitive(cx, rvalue.address()))
+        return false;
+
+    if (lvalue.get().isString() && rvalue.get().isString()) {
+        JSString *l = lvalue.get().toString();
+        JSString *r = rvalue.get().toString();
+        return EqualStrings(cx, l, r, result);
+    }
+
+    double l, r;
+    if (!ToNumber(cx, lvalue, &l) || !ToNumber(cx, rvalue, &r))
+        return false;
+    *result = (l == r);
+    return true;
+}
+
+bool
+js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, bool *equal)
+{
+    Value lval = lref, rval = rref;
+    if (SameType(lval, rval)) {
+        if (lval.isString())
+            return EqualStrings(cx, lval.toString(), rval.toString(), equal);
+        if (lval.isDouble()) {
+            *equal = (lval.toDouble() == rval.toDouble());
+            return true;
+        }
+        if (lval.isObject()) {
+            *equal = lval.toObject() == rval.toObject();
+            return true;
+        }
+        if (lval.isUndefined()) {
+            *equal = true;
+            return true;
+        }
+        *equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
+        return true;
+    }
+
+    if (lval.isDouble() && rval.isInt32()) {
+        double ld = lval.toDouble();
+        double rd = rval.toInt32();
+        *equal = (ld == rd);
+        return true;
+    }
+    if (lval.isInt32() && rval.isDouble()) {
+        double ld = lval.toInt32();
+        double rd = rval.toDouble();
+        *equal = (ld == rd);
+        return true;
+    }
+
+    *equal = false;
+    return true;
+}
+
+static inline bool
+IsNegativeZero(const Value &v)
+{
+    return v.isDouble() && MOZ_DOUBLE_IS_NEGATIVE_ZERO(v.toDouble());
+}
+
+static inline bool
+IsNaN(const Value &v)
+{
+    return v.isDouble() && MOZ_DOUBLE_IS_NaN(v.toDouble());
+}
+
+bool
+js::SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same)
+{
+    if (IsNegativeZero(v1)) {
+        *same = IsNegativeZero(v2);
+        return true;
+    }
+    if (IsNegativeZero(v2)) {
+        *same = false;
+        return true;
+    }
+    if (IsNaN(v1) && IsNaN(v2)) {
+        *same = true;
+        return true;
+    }
+    return StrictlyEqual(cx, v1, v2, same);
+}
+
+JSType
+js::TypeOfValue(JSContext *cx, const Value &vref)
+{
+    Value v = vref;
+    if (v.isNumber())
+        return JSTYPE_NUMBER;
+    if (v.isString())
+        return JSTYPE_STRING;
+    if (v.isNull())
+        return JSTYPE_OBJECT;
+    if (v.isUndefined())
+        return JSTYPE_VOID;
+    if (v.isObject()) {
+        RootedObject obj(cx, &v.toObject());
+        return JSObject::typeOf(cx, obj);
+    }
+    JS_ASSERT(v.isBoolean());
+    return JSTYPE_BOOLEAN;
+}
+
+/*
+ * Enter the new with scope using an object at sp[-1] and associate the depth
+ * of the with block with sp + stackIndex.
+ */
+static bool
+EnterWith(JSContext *cx, int stackIndex)
+{
+    StackFrame *fp = cx->fp();
+    Value *sp = cx->regs().sp;
+    JS_ASSERT(stackIndex < 0);
+    JS_ASSERT(int(cx->regs().stackDepth()) + stackIndex >= 0);
+
+    RootedObject obj(cx);
+    if (sp[-1].isObject()) {
+        obj = &sp[-1].toObject();
+    } else {
+        obj = js_ValueToNonNullObject(cx, sp[-1]);
+        if (!obj)
+            return false;
+        sp[-1].setObject(*obj);
+    }
+
+    WithObject *withobj = WithObject::create(cx, obj, fp->scopeChain(),
+                                             cx->regs().stackDepth() + stackIndex);
+    if (!withobj)
+        return false;
+
+    fp->pushOnScopeChain(*withobj);
+    return true;
+}
+
+/* Unwind block and scope chains to match the given depth. */
+void
+js::UnwindScope(JSContext *cx, uint32_t stackDepth)
+{
+    StackFrame *fp = cx->fp();
+    JS_ASSERT(stackDepth <= cx->regs().stackDepth());
+
+    for (ScopeIter si(fp, cx); !si.done(); ++si) {
+        switch (si.type()) {
+          case ScopeIter::Block:
+            if (si.staticBlock().stackDepth() < stackDepth)
+                return;
+            fp->popBlock(cx);
+            break;
+          case ScopeIter::With:
+            if (si.scope().asWith().stackDepth() < stackDepth)
+                return;
+            fp->popWith(cx);
+            break;
+          case ScopeIter::Call:
+          case ScopeIter::StrictEvalScope:
+            break;
+        }
+    }
+}
+
+void
+js::UnwindForUncatchableException(JSContext *cx, const FrameRegs &regs)
+{
+    /* c.f. the regular (catchable) TryNoteIter loop in Interpret. */
+    for (TryNoteIter tni(regs); !tni.done(); ++tni) {
+        JSTryNote *tn = *tni;
+        if (tn->kind == JSTRY_ITER) {
+            Value *sp = regs.spForStackDepth(tn->stackDepth);
+            UnwindIteratorForUncatchableException(cx, &sp[-1].toObject());
+        }
+    }
+}
+
+TryNoteIter::TryNoteIter(const FrameRegs &regs)
+  : regs(regs),
+    script(regs.fp()->script().unsafeGet()),
+    pcOffset(regs.pc - script->main())
+{
+    if (script->hasTrynotes()) {
+        tn = script->trynotes()->vector;
+        tnEnd = tn + script->trynotes()->length;
+    } else {
+        tn = tnEnd = NULL;
+    }
+    settle();
+}
+
+void
+TryNoteIter::operator++()
+{
+    ++tn;
+    settle();
+}
+
+bool
+TryNoteIter::done() const
+{
+    return tn == tnEnd;
+}
+
+void
+TryNoteIter::settle()
+{
+    for (; tn != tnEnd; ++tn) {
+        /* If pc is out of range, try the next one. */
+        if (pcOffset - tn->start >= tn->length)
+            continue;
+
+        /*
+         * We have a note that covers the exception pc but we must check
+         * whether the interpreter has already executed the corresponding
+         * handler. This is possible when the executed bytecode implements
+         * break or return from inside a for-in loop.
+         *
+         * In this case the emitter generates additional [enditer] and [gosub]
+         * opcodes to close all outstanding iterators and execute the finally
+         * blocks. If such an [enditer] throws an exception, its pc can still
+         * be inside several nested for-in loops and try-finally statements
+         * even if we have already closed the corresponding iterators and
+         * invoked the finally blocks.
+         *
+         * To address this, we make [enditer] always decrease the stack even
+         * when its implementation throws an exception. Thus already executed
+         * [enditer] and [gosub] opcodes will have try notes with the stack
+         * depth exceeding the current one and this condition is what we use to
+         * filter them out.
+         */
+        if (tn->stackDepth <= regs.stackDepth())
+            break;
+    }
+}
+
+/*
+ * Increment/decrement the value 'v'. The resulting value is stored in *slot.
+ * The result of the expression (taking into account prefix/postfix) is stored
+ * in *expr.
+ */
+static bool
+DoIncDec(JSContext *cx, HandleScript script, jsbytecode *pc, const Value &v, Value *slot, Value *expr)
+{
+    const JSCodeSpec &cs = js_CodeSpec[*pc];
+
+    if (v.isInt32()) {
+        int32_t i = v.toInt32();
+        if (i > JSVAL_INT_MIN && i < JSVAL_INT_MAX) {
+            int32_t sum = i + (cs.format & JOF_INC ? 1 : -1);
+            *slot = Int32Value(sum);
+            *expr = (cs.format & JOF_POST) ? Int32Value(i) : *slot;
+            return true;
+        }
+    }
+
+    double d;
+    if (!ToNumber(cx, v, &d))
+        return false;
+
+    double sum = d + (cs.format & JOF_INC ? 1 : -1);
+    *slot = NumberValue(sum);
+    *expr = (cs.format & JOF_POST) ? NumberValue(d) : *slot;
+
+    TypeScript::MonitorOverflow(cx, script, pc);
+    return true;
+}
+
+#define PUSH_COPY(v)             do { *regs.sp++ = v; assertSameCompartment(cx, regs.sp[-1]); } while (0)
+#define PUSH_COPY_SKIP_CHECK(v)  *regs.sp++ = v
+#define PUSH_NULL()              regs.sp++->setNull()
+#define PUSH_UNDEFINED()         regs.sp++->setUndefined()
+#define PUSH_BOOLEAN(b)          regs.sp++->setBoolean(b)
+#define PUSH_DOUBLE(d)           regs.sp++->setDouble(d)
+#define PUSH_INT32(i)            regs.sp++->setInt32(i)
+#define PUSH_STRING(s)           do { regs.sp++->setString(s); assertSameCompartment(cx, regs.sp[-1]); } while (0)
+#define PUSH_OBJECT(obj)         do { regs.sp++->setObject(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
+#define PUSH_OBJECT_OR_NULL(obj) do { regs.sp++->setObjectOrNull(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
+#define PUSH_HOLE()              regs.sp++->setMagic(JS_ARRAY_HOLE)
+#define POP_COPY_TO(v)           v = *--regs.sp
+#define POP_RETURN_VALUE()       regs.fp()->setReturnValue(*--regs.sp)
+
+#define FETCH_OBJECT(cx, n, obj)                                              \
+    JS_BEGIN_MACRO                                                            \
+        HandleValue val = HandleValue::fromMarkedLocation(&regs.sp[n]);       \
+        obj = ToObject(cx, (val));                                            \
+        if (!obj)                                                             \
+            goto error;                                                       \
+    JS_END_MACRO
+
+template<typename T>
+class GenericInterruptEnabler : public InterpreterFrames::InterruptEnablerBase {
+  public:
+    GenericInterruptEnabler(T *variable, T value) : variable(variable), value(value) { }
+    void enable() const { *variable = value; }
+
+  private:
+    T *variable;
+    T value;
+};
+
+inline InterpreterFrames::InterpreterFrames(JSContext *cx, FrameRegs *regs,
+                                            const InterruptEnablerBase &enabler)
+  : context(cx), regs(regs), enabler(enabler)
+{
+    older = cx->runtime->interpreterFrames;
+    cx->runtime->interpreterFrames = this;
+}
+
+inline InterpreterFrames::~InterpreterFrames()
+{
+    context->runtime->interpreterFrames = older;
+}
+
+#if defined(DEBUG) && !defined(JS_THREADSAFE) && !defined(JSGC_ROOT_ANALYSIS)
+void
+js::AssertValidPropertyCacheHit(JSContext *cx, JSObject *start_,
+                                JSObject *found, PropertyCacheEntry *entry)
+{
+    jsbytecode *pc;
+    JSScript *script = cx->stack.currentScript(&pc);
+
+    uint64_t sample = cx->runtime->gcNumber;
+    PropertyCacheEntry savedEntry = *entry;
+
+    RootedPropertyName name(cx, GetNameFromBytecode(cx, script, pc, JSOp(*pc)));
+    RootedObject start(cx, start_);
+    RootedObject pobj(cx);
+    RootedShape prop(cx);
+    bool ok = baseops::LookupProperty(cx, start, name, &pobj, &prop);
+    JS_ASSERT(ok);
+
+    if (cx->runtime->gcNumber != sample)
+        cx->propertyCache().restore(&savedEntry);
+    JS_ASSERT(prop);
+    JS_ASSERT(pobj == found);
+    JS_ASSERT(entry->prop == prop);
+}
+#endif /* DEBUG && !JS_THREADSAFE */
+
+/*
+ * Ensure that the intrepreter switch can close call-bytecode cases in the
+ * same way as non-call bytecodes.
+ */
+JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
+JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
+JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH);
+JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
+
+/*
+ * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
+ * remain distinct for the decompiler.
+ */
+JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
+
+/* See TRY_BRANCH_AFTER_COND. */
+JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
+JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1);
+
+/* For the fastest case inder JSOP_INCNAME, etc. */
+JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_DECNAME_LENGTH);
+JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEINC_LENGTH);
+JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH);
+
+/*
+ * Inline fast paths for iteration. js_IteratorMore and js_IteratorNext handle
+ * all cases, but we inline the most frequently taken paths here.
+ */
+static inline bool
+IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValue rval)
+{
+    if (iterobj->isPropertyIterator()) {
+        NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
+        if (ni->isKeyIter()) {
+            *cond = (ni->props_cursor < ni->props_end);
+            return true;
+        }
+    }
+    Rooted<JSObject*> iobj(cx, iterobj);
+    if (!js_IteratorMore(cx, iobj, rval))
+        return false;
+    *cond = rval.isTrue();
+    return true;
+}
+
+static inline bool
+IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
+{
+    if (iterobj->isPropertyIterator()) {
+        NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
+        if (ni->isKeyIter()) {
+            JS_ASSERT(ni->props_cursor < ni->props_end);
+            rval.setString(*ni->current());
+            ni->incCursor();
+            return true;
+        }
+    }
+    return js_IteratorNext(cx, iterobj, rval);
+}
+
+/*
+ * For bytecodes which push values and then fall through, make sure the
+ * types of the pushed values are consistent with type inference information.
+ */
+static inline void
+TypeCheckNextBytecode(JSContext *cx, HandleScript script, unsigned n, const FrameRegs &regs)
+{
+#ifdef DEBUG
+    if (cx->typeInferenceEnabled() && n == GetBytecodeLength(regs.pc))
+        TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
+#endif
+}
+
+JS_NEVER_INLINE InterpretStatus
+js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
+{
+    JSAutoResolveFlags rf(cx, RESOLVE_INFER);
+
+    if (interpMode == JSINTERP_NORMAL)
+        gc::MaybeVerifyBarriers(cx, true);
+
+    JS_ASSERT(!cx->compartment->activeAnalysis);
+
+#define CHECK_PCCOUNT_INTERRUPTS() JS_ASSERT_IF(script->hasScriptCounts, switchMask == -1)
+
+    register int switchMask = 0;
+    int switchOp;
+    typedef GenericInterruptEnabler<int> InterruptEnabler;
+    InterruptEnabler interrupts(&switchMask, -1);
+
+# define DO_OP()            goto do_op
+# define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
+                                JS_ASSERT((n) == len);                        \
+                                goto advance_pc;                              \
+                            JS_END_MACRO
+
+# define BEGIN_CASE(OP)     case OP:
+# define END_CASE(OP)       END_CASE_LEN(OP##_LENGTH)
+# define END_CASE_LEN(n)    END_CASE_LENX(n)
+# define END_CASE_LENX(n)   END_CASE_LEN##n
+
+/*
+ * To share the code for all len == 1 cases we use the specialized label with
+ * code that falls through to advance_pc: .
+ */
+# define END_CASE_LEN1      goto advance_pc_by_one;
+# define END_CASE_LEN2      len = 2; goto advance_pc;
+# define END_CASE_LEN3      len = 3; goto advance_pc;
+# define END_CASE_LEN4      len = 4; goto advance_pc;
+# define END_CASE_LEN5      len = 5; goto advance_pc;
+# define END_CASE_LEN6      len = 6; goto advance_pc;
+# define END_CASE_LEN7      len = 7; goto advance_pc;
+# define END_CASE_LEN8      len = 8; goto advance_pc;
+# define END_CASE_LEN9      len = 9; goto advance_pc;
+# define END_CASE_LEN10     len = 10; goto advance_pc;
+# define END_CASE_LEN11     len = 11; goto advance_pc;
+# define END_CASE_LEN12     len = 12; goto advance_pc;
+# define END_VARLEN_CASE    goto advance_pc;
+# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
+# define END_EMPTY_CASES    goto advance_pc_by_one;
+
+#define LOAD_DOUBLE(PCOFF, dbl)                                               \
+    (dbl = script->getConst(GET_UINT32_INDEX(regs.pc + (PCOFF))).toDouble())
+
+#ifdef JS_METHODJIT
+
+#define CHECK_PARTIAL_METHODJIT(status)                                       \
+    JS_BEGIN_MACRO                                                            \
+        switch (status) {                                                     \
+          case mjit::Jaeger_UnfinishedAtTrap:                                 \
+            interpMode = JSINTERP_SKIP_TRAP;                                  \
+            /* FALLTHROUGH */                                                 \
+          case mjit::Jaeger_Unfinished:                                       \
+            op = (JSOp) *regs.pc;                                             \
+            SET_SCRIPT(regs.fp()->script());                                  \
+            if (cx->isExceptionPending())                                     \
+                goto error;                                                   \
+            DO_OP();                                                          \
+          default:;                                                           \
+        }                                                                     \
+    JS_END_MACRO
+#endif
+
+    /*
+     * Prepare to call a user-supplied branch handler, and abort the script
+     * if it returns false.
+     */
+#define CHECK_BRANCH()                                                        \
+    JS_BEGIN_MACRO                                                            \
+        if (cx->runtime->interrupt && !js_HandleExecutionInterrupt(cx))       \
+            goto error;                                                       \
+    JS_END_MACRO
+
+#define BRANCH(n)                                                             \
+    JS_BEGIN_MACRO                                                            \
+        regs.pc += (n);                                                       \
+        op = (JSOp) *regs.pc;                                                 \
+        if ((n) <= 0)                                                         \
+            goto check_backedge;                                              \
+        DO_OP();                                                              \
+    JS_END_MACRO
+
+#define SET_SCRIPT(s)                                                         \
+    JS_BEGIN_MACRO                                                            \
+        EnterAssertNoGCScope();                                               \
+        script = (s);                                                         \
+        if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \
+            interrupts.enable();                                              \
+        JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP,                        \
+                     script->hasAnyBreakpointsOrStepMode());                  \
+        LeaveAssertNoGCScope();                                               \
+    JS_END_MACRO
+
+    /* Repoint cx->regs to a local variable for faster access. */
+    FrameRegs regs = cx->regs();
+    PreserveRegsGuard interpGuard(cx, regs);
+
+    /*
+     * Help Debugger find frames running scripts that it has put in
+     * single-step mode.
+     */
+    InterpreterFrames interpreterFrame(cx, &regs, interrupts);
+
+    /* Copy in hot values that change infrequently. */
+    JSRuntime *const rt = cx->runtime;
+    RootedScript script(cx);
+    SET_SCRIPT(regs.fp()->script());
+
+    /* Reset the loop count on the script we're entering. */
+    script->resetLoopCount();
+
+#if JS_TRACE_LOGGING
+    AutoTraceLog logger(TraceLogging::defaultLogger(),
+                        TraceLogging::INTERPRETER_START,
+                        TraceLogging::INTERPRETER_STOP,
+                        script);
+#endif
+
+    /*
+     * Pool of rooters for use in this interpreter frame. References to these
+     * are used for local variables within interpreter cases. This avoids
+     * creating new rooters each time an interpreter case is entered, and also
+     * correctness pitfalls due to incorrect compilation of destructor calls
+     * around computed gotos.
+     */
+    RootedValue rootValue0(cx), rootValue1(cx);
+    RootedString rootString0(cx), rootString1(cx);
+    RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
+    RootedFunction rootFunction0(cx);
+    RootedTypeObject rootType0(cx);
+    RootedPropertyName rootName0(cx);
+    RootedId rootId0(cx);
+    RootedShape rootShape0(cx);
+    DebugOnly<uint32_t> blockDepth;
+
+    if (!entryFrame)
+        entryFrame = regs.fp();
+
+#if JS_HAS_GENERATORS
+    if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) {
+        JS_ASSERT(size_t(regs.pc - script->code) <= script->length);
+        JS_ASSERT(regs.stackDepth() <= script->nslots);
+
+        /*
+         * To support generator_throw and to catch ignored exceptions,
+         * fail if cx->isExceptionPending() is true.
+         */
+        if (cx->isExceptionPending()) {
+            Probes::enterScript(cx, script, script->function(), regs.fp());
+            goto error;
+        }
+    }
+#endif
+
+    /* State communicated between non-local jumps: */
+    bool interpReturnOK;
+
+    /* Don't call the script prologue if executing between Method and Trace JIT. */
+    if (interpMode == JSINTERP_NORMAL) {
+        StackFrame *fp = regs.fp();
+        if (!fp->isGeneratorFrame()) {
+            if (!fp->prologue(cx, UseNewTypeAtEntry(cx, fp)))
+                goto error;
+        } else {
+            Probes::enterScript(cx, script, script->function(), fp);
+        }
+        if (cx->compartment->debugMode()) {
+            JSTrapStatus status = ScriptDebugPrologue(cx, fp);
+            switch (status) {
+              case JSTRAP_CONTINUE:
+                break;
+              case JSTRAP_RETURN:
+                interpReturnOK = true;
+                goto forced_return;
+              case JSTRAP_THROW:
+              case JSTRAP_ERROR:
+                goto error;
+              default:
+                JS_NOT_REACHED("bad ScriptDebugPrologue status");
+            }
+        }
+    }
+
+    /* The REJOIN mode acts like the normal mode, except the prologue is skipped. */
+    if (interpMode == JSINTERP_REJOIN)
+        interpMode = JSINTERP_NORMAL;
+
+    /*
+     * 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
+     * "op" correctly in all other cases.
+     */
+    JSOp op;
+    int32_t len;
+    len = 0;
+
+    if (rt->profilingScripts || cx->runtime->debugHooks.interruptHook)
+        interrupts.enable();
+
+    DO_NEXT_OP(len);
+
+    for (;;) {
+      advance_pc_by_one:
+        JS_ASSERT(js_CodeSpec[op].length == 1);
+        len = 1;
+      advance_pc:
+        TypeCheckNextBytecode(cx, script, len, regs);
+        js::gc::MaybeVerifyBarriers(cx);
+        regs.pc += len;
+        op = (JSOp) *regs.pc;
+
+      do_op:
+        CHECK_PCCOUNT_INTERRUPTS();
+        switchOp = int(op) | switchMask;
+      do_switch:
+        switch (switchOp) {
+
+  case -1:
+    JS_ASSERT(switchMask == -1);
+    {
+        bool moreInterrupts = false;
+
+        if (cx->runtime->profilingScripts) {
+            if (!script->hasScriptCounts)
+                script->initScriptCounts(cx);
+            moreInterrupts = true;
+        }
+
+        if (script->hasScriptCounts) {
+            PCCounts counts = script->getPCCounts(regs.pc);
+            counts.get(PCCounts::BASE_INTERP)++;
+            moreInterrupts = true;
+        }
+
+        JSInterruptHook hook = cx->runtime->debugHooks.interruptHook;
+        if (hook || script->stepModeEnabled()) {
+            Value rval;
+            JSTrapStatus status = JSTRAP_CONTINUE;
+            if (hook)
+                status = hook(cx, script, regs.pc, &rval, cx->runtime->debugHooks.interruptHookData);
+            if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
+                status = Debugger::onSingleStep(cx, &rval);
+            switch (status) {
+              case JSTRAP_ERROR:
+                goto error;
+              case JSTRAP_CONTINUE:
+                break;
+              case JSTRAP_RETURN:
+                regs.fp()->setReturnValue(rval);
+                interpReturnOK = true;
+                goto forced_return;
+              case JSTRAP_THROW:
+                cx->setPendingException(rval);
+                goto error;
+              default:;
+            }
+            moreInterrupts = true;
+        }
+
+        if (script->hasAnyBreakpointsOrStepMode())
+            moreInterrupts = true;
+
+        if (script->hasBreakpointsAt(regs.pc) && interpMode != JSINTERP_SKIP_TRAP) {
+            Value rval;
+            JSTrapStatus status = Debugger::onTrap(cx, &rval);
+            switch (status) {
+              case JSTRAP_ERROR:
+                goto error;
+              case JSTRAP_RETURN:
+                regs.fp()->setReturnValue(rval);
+                interpReturnOK = true;
+                goto forced_return;
+              case JSTRAP_THROW:
+                cx->setPendingException(rval);
+                goto error;
+              default:
+                break;
+            }
+            JS_ASSERT(status == JSTRAP_CONTINUE);
+            JS_ASSERT(rval.isInt32() && rval.toInt32() == op);
+        }
+
+        interpMode = JSINTERP_NORMAL;
+
+        switchMask = moreInterrupts ? -1 : 0;
+        switchOp = int(op);
+        goto do_switch;
+    }
+
+/* No-ops for ease of decompilation. */
+ADD_EMPTY_CASE(JSOP_NOP)
+ADD_EMPTY_CASE(JSOP_UNUSED1)
+ADD_EMPTY_CASE(JSOP_UNUSED2)
+ADD_EMPTY_CASE(JSOP_UNUSED3)
+ADD_EMPTY_CASE(JSOP_UNUSED10)
+ADD_EMPTY_CASE(JSOP_UNUSED11)
+ADD_EMPTY_CASE(JSOP_UNUSED12)
+ADD_EMPTY_CASE(JSOP_UNUSED13)
+ADD_EMPTY_CASE(JSOP_UNUSED15)
+ADD_EMPTY_CASE(JSOP_UNUSED17)
+ADD_EMPTY_CASE(JSOP_UNUSED18)
+ADD_EMPTY_CASE(JSOP_UNUSED19)
+ADD_EMPTY_CASE(JSOP_UNUSED20)
+ADD_EMPTY_CASE(JSOP_UNUSED21)
+ADD_EMPTY_CASE(JSOP_UNUSED22)
+ADD_EMPTY_CASE(JSOP_UNUSED23)
+ADD_EMPTY_CASE(JSOP_UNUSED24)
+ADD_EMPTY_CASE(JSOP_UNUSED25)
+ADD_EMPTY_CASE(JSOP_UNUSED29)
+ADD_EMPTY_CASE(JSOP_UNUSED30)
+ADD_EMPTY_CASE(JSOP_UNUSED31)
+ADD_EMPTY_CASE(JSOP_CONDSWITCH)
+ADD_EMPTY_CASE(JSOP_TRY)
+#if JS_HAS_XML_SUPPORT
+ADD_EMPTY_CASE(JSOP_STARTXML)
+ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
+#endif
+END_EMPTY_CASES
+
+BEGIN_CASE(JSOP_LOOPHEAD)
+
+    script->incrLoopCount();
+
+END_CASE(JSOP_LOOPHEAD)
+
+BEGIN_CASE(JSOP_LABEL)
+END_CASE(JSOP_LABEL)
+
+check_backedge:
+{
+    CHECK_BRANCH();
+    if (op != JSOP_LOOPHEAD)
+        DO_OP();
+
+#ifdef JS_METHODJIT
+    // Attempt on-stack replacement with JaegerMonkey code, which is keyed to
+    // the interpreter state at the JSOP_LOOPHEAD at the start of the loop.
+    // Unlike IonMonkey, this requires two different code fragments to perform
+    // hoisting.
+    mjit::CompileStatus status =
+        mjit::CanMethodJIT(cx, script, regs.pc, regs.fp()->isConstructing(),
+                           mjit::CompileRequest_Interpreter, regs.fp());
+    if (status == mjit::Compile_Error)
+        goto error;
+    if (status == mjit::Compile_Okay) {
+        void *ncode =
+            script->nativeCodeForPC(regs.fp()->isConstructing(), regs.pc);
+        JS_ASSERT(ncode);
+        mjit::JaegerStatus status = mjit::JaegerShotAtSafePoint(cx, ncode, true);
+        if (status == mjit::Jaeger_ThrowBeforeEnter)
+            goto error;
+        CHECK_PARTIAL_METHODJIT(status);
+        interpReturnOK = (status == mjit::Jaeger_Returned);
+        if (entryFrame != regs.fp())
+            goto jit_return;
+        regs.fp()->setFinishedInInterpreter();
+        goto leave_on_safe_point;
+    }
+#endif /* JS_METHODJIT */
+
+    DO_OP();
+}
+
+BEGIN_CASE(JSOP_LOOPENTRY)
+
+#ifdef JS_ION
+    // Attempt on-stack replacement with Ion code. IonMonkey OSR takes place at
+    // the point of the initial loop entry, to consolidate hoisted code between
+    // entry points.
+    if (ion::IsEnabled(cx)) {
+        ion::MethodStatus status =
+            ion::CanEnterAtBranch(cx, script, regs.fp(), regs.pc);
+        if (status == ion::Method_Error)
+            goto error;
+        if (status == ion::Method_Compiled) {
+            ion::IonExecStatus maybeOsr = ion::SideCannon(cx, regs.fp(), regs.pc);
+            if (maybeOsr == ion::IonExec_Bailout) {
+                // We hit a deoptimization path in the first Ion frame, so now
+                // we've just replaced the entire Ion activation.
+                SET_SCRIPT(regs.fp()->script());
+                op = JSOp(*regs.pc);
+                DO_OP();
+            }
+
+            interpReturnOK = (maybeOsr == ion::IonExec_Ok);
+
+            if (entryFrame != regs.fp())
+                goto jit_return;
+
+            regs.fp()->setFinishedInInterpreter();
+            goto leave_on_safe_point;
+        }
+    }
+#endif /* JS_ION */
+
+END_CASE(JSOP_LOOPENTRY)
+
+BEGIN_CASE(JSOP_NOTEARG)
+END_CASE(JSOP_NOTEARG)
+
+/* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
+BEGIN_CASE(JSOP_LINENO)
+END_CASE(JSOP_LINENO)
+
+BEGIN_CASE(JSOP_UNDEFINED)
+    PUSH_UNDEFINED();
+END_CASE(JSOP_UNDEFINED)
+
+BEGIN_CASE(JSOP_POP)
+    regs.sp--;
+END_CASE(JSOP_POP)
+
+BEGIN_CASE(JSOP_POPN)
+    JS_ASSERT(GET_UINT16(regs.pc) <= regs.stackDepth());
+    regs.sp -= GET_UINT16(regs.pc);
+#ifdef DEBUG
+    if (StaticBlockObject *block = regs.fp()->maybeBlockChain())
+        JS_ASSERT(regs.stackDepth() >= block->stackDepth() + block->slotCount());
+#endif
+END_CASE(JSOP_POPN)
+
+BEGIN_CASE(JSOP_SETRVAL)
+BEGIN_CASE(JSOP_POPV)
+    POP_RETURN_VALUE();
+END_CASE(JSOP_POPV)
+
+BEGIN_CASE(JSOP_ENTERWITH)
+    if (!EnterWith(cx, -1))
+        goto error;
+
+    /*
+     * We must ensure that different "with" blocks have different stack depth
+     * associated with them. This allows the try handler search to properly
+     * recover the scope chain. Thus we must keep the stack at least at the
+     * current level.
+     *
+     * We set sp[-1] to the current "with" object to help asserting the
+     * enter/leave balance in [leavewith].
+     */
+    regs.sp[-1].setObject(*regs.fp()->scopeChain());
+END_CASE(JSOP_ENTERWITH)
+
+BEGIN_CASE(JSOP_LEAVEWITH)
+    JS_ASSERT(regs.sp[-1].toObject() == *regs.fp()->scopeChain());
+    regs.fp()->popWith(cx);
+    regs.sp--;
+END_CASE(JSOP_LEAVEWITH)
+
+BEGIN_CASE(JSOP_RETURN)
+    POP_RETURN_VALUE();
+    /* FALL THROUGH */
+
+BEGIN_CASE(JSOP_RETRVAL)    /* fp return value already set */
+BEGIN_CASE(JSOP_STOP)
+{
+    /*
+     * When the inlined frame exits with an exception or an error, ok will be
+     * false after the inline_return label.
+     */
+    CHECK_BRANCH();
+
+    interpReturnOK = true;
+    if (entryFrame != regs.fp())
+  inline_return:
+    {
+        if (cx->compartment->debugMode())
+            interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
+
+        if (!regs.fp()->isYielding())
+            regs.fp()->epilogue(cx);
+        else
+            Probes::exitScript(cx, script, script->function(), regs.fp());
+
+        /* The JIT inlines the epilogue. */
+#ifdef JS_METHODJIT
+  jit_return:
+#endif
+
+        /* The results of lowered call/apply frames need to be shifted. */
+        bool shiftResult = regs.fp()->loweredCallOrApply();
+
+        cx->stack.popInlineFrame(regs);
+        SET_SCRIPT(regs.fp()->script());
+
+        JS_ASSERT(*regs.pc == JSOP_NEW || *regs.pc == JSOP_CALL ||
+                  *regs.pc == JSOP_FUNCALL || *regs.pc == JSOP_FUNAPPLY);
+
+        /* Resume execution in the calling frame. */
+        if (JS_LIKELY(interpReturnOK)) {
+            TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
+
+            if (shiftResult) {
+                regs.sp[-2] = regs.sp[-1];
+                regs.sp--;
+            }
+
+            len = JSOP_CALL_LENGTH;
+            DO_NEXT_OP(len);
+        }
+
+        /* Increment pc so that |sp - fp->slots == ReconstructStackDepth(pc)|. */
+        regs.pc += JSOP_CALL_LENGTH;
+        goto error;
+    } else {
+        JS_ASSERT(regs.stackDepth() == 0);
+    }
+    interpReturnOK = true;
+    goto exit;
+}
+
+BEGIN_CASE(JSOP_DEFAULT)
+    regs.sp--;
+    /* FALL THROUGH */
+BEGIN_CASE(JSOP_GOTO)
+{
+    len = GET_JUMP_OFFSET(regs.pc);
+    BRANCH(len);
+}
+END_CASE(JSOP_GOTO)
+
+BEGIN_CASE(JSOP_IFEQ)
+{
+    bool cond = ToBoolean(regs.sp[-1]);
+    regs.sp--;
+    if (cond == false) {
+        len = GET_JUMP_OFFSET(regs.pc);
+        BRANCH(len);
+    }
+}
+END_CASE(JSOP_IFEQ)
+
+BEGIN_CASE(JSOP_IFNE)
+{
+    bool cond = ToBoolean(regs.sp[-1]);
+    regs.sp--;
+    if (cond != false) {
+        len = GET_JUMP_OFFSET(regs.pc);
+        BRANCH(len);
+    }
+}
+END_CASE(JSOP_IFNE)
+
+BEGIN_CASE(JSOP_OR)
+{
+    bool cond = ToBoolean(regs.sp[-1]);
+    if (cond == true) {
+        len = GET_JUMP_OFFSET(regs.pc);
+        DO_NEXT_OP(len);
+    }
+}
+END_CASE(JSOP_OR)
+
+BEGIN_CASE(JSOP_AND)
+{
+    bool cond = ToBoolean(regs.sp[-1]);
+    if (cond == false) {
+        len = GET_JUMP_OFFSET(regs.pc);
+        DO_NEXT_OP(len);
+    }
+}
+END_CASE(JSOP_AND)
+
+/*
+ * If the index value at sp[n] is not an int that fits in a jsval, it could
+ * be an object (an XML QName, AttributeName, or AnyName), but only if we are
+ * compiling with JS_HAS_XML_SUPPORT.  Otherwise convert the index value to a
+ * string atom id.
+ */
+#define FETCH_ELEMENT_ID(obj, n, id)                                          \
+    JS_BEGIN_MACRO                                                            \
+        const Value &idval_ = regs.sp[n];                                     \
+        if (!ValueToId(cx, obj, idval_, id.address()))                        \
+            goto error;                                                       \
+    JS_END_MACRO
+
+#define TRY_BRANCH_AFTER_COND(cond,spdec)                                     \
+    JS_BEGIN_MACRO                                                            \
+        JS_ASSERT(js_CodeSpec[op].length == 1);                               \
+        unsigned diff_ = (unsigned) GET_UINT8(regs.pc) - (unsigned) JSOP_IFEQ;         \
+        if (diff_ <= 1) {                                                     \
+            regs.sp -= spdec;                                                 \
+            if (cond == (diff_ != 0)) {                                       \
+                ++regs.pc;                                                    \
+                len = GET_JUMP_OFFSET(regs.pc);                               \
+                BRANCH(len);                                                  \
+            }                                                                 \
+            len = 1 + JSOP_IFEQ_LENGTH;                                       \
+            DO_NEXT_OP(len);                                                  \
+        }                                                                     \
+    JS_END_MACRO
+
+BEGIN_CASE(JSOP_IN)
+{
+    HandleValue rref = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+    if (!rref.isObject()) {
+        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NullPtr());
+        goto error;
+    }
+    RootedObject &obj = rootObject0;
+    obj = &rref.toObject();
+    RootedId &id = rootId0;
+    FETCH_ELEMENT_ID(obj, -2, id);
+    RootedObject &obj2 = rootObject1;
+    RootedShape &prop = rootShape0;
+    if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
+        goto error;
+    bool cond = prop != NULL;
+    TRY_BRANCH_AFTER_COND(cond, 2);
+    regs.sp--;
+    regs.sp[-1].setBoolean(cond);
+}
+END_CASE(JSOP_IN)
+
+BEGIN_CASE(JSOP_ITER)
+{
+    JS_ASSERT(regs.stackDepth() >= 1);
+    uint8_t flags = GET_UINT8(regs.pc);
+    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
+    if (!ValueToIterator(cx, flags, res))
+        goto error;
+    JS_ASSERT(!res.isPrimitive());
+}
+END_CASE(JSOP_ITER)
+
+BEGIN_CASE(JSOP_MOREITER)
+{
+    JS_ASSERT(regs.stackDepth() >= 1);
+    JS_ASSERT(regs.sp[-1].isObject());
+    PUSH_NULL();
+    bool cond;
+    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
+    if (!IteratorMore(cx, &regs.sp[-2].toObject(), &cond, res))
+        goto error;
+    regs.sp[-1].setBoolean(cond);
+}
+END_CASE(JSOP_MOREITER)
+
+BEGIN_CASE(JSOP_ITERNEXT)
+{
+    JS_ASSERT(regs.sp[-1].isObject());
+    PUSH_NULL();
+    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
+    RootedObject &obj = rootObject0;
+    obj = &regs.sp[-2].toObject();
+    if (!IteratorNext(cx, obj, res))
+        goto error;
+}
+END_CASE(JSOP_ITERNEXT)
+
+BEGIN_CASE(JSOP_ENDITER)
+{
+    JS_ASSERT(regs.stackDepth() >= 1);
+    RootedObject &obj = rootObject0;
+    obj = &regs.sp[-1].toObject();
+    bool ok = CloseIterator(cx, obj);
+    regs.sp--;
+    if (!ok)
+        goto error;
+}
+END_CASE(JSOP_ENDITER)
+
+BEGIN_CASE(JSOP_DUP)
+{
+    JS_ASSERT(regs.stackDepth() >= 1);
+    const Value &rref = regs.sp[-1];
+    PUSH_COPY(rref);
+}
+END_CASE(JSOP_DUP)
+
+BEGIN_CASE(JSOP_DUP2)
+{
+    JS_ASSERT(regs.stackDepth() >= 2);
+    const Value &lref = regs.sp[-2];
+    const Value &rref = regs.sp[-1];
+    PUSH_COPY(lref);
+    PUSH_COPY(rref);
+}
+END_CASE(JSOP_DUP2)
+
+BEGIN_CASE(JSOP_SWAP)
+{
+    JS_ASSERT(regs.stackDepth() >= 2);
+    Value &lref = regs.sp[-2];
+    Value &rref = regs.sp[-1];
+    lref.swap(rref);
+}
+END_CASE(JSOP_SWAP)
+
+BEGIN_CASE(JSOP_PICK)
+{
+    unsigned i = GET_UINT8(regs.pc);
+    JS_ASSERT(regs.stackDepth() >= i + 1);
+    Value lval = regs.sp[-int(i + 1)];
+    memmove(regs.sp - (i + 1), regs.sp - i, sizeof(Value) * i);
+    regs.sp[-1] = lval;
+}
+END_CASE(JSOP_PICK)
+
+BEGIN_CASE(JSOP_SETCONST)
+{
+    RootedPropertyName &name = rootName0;
+    name = script->getName(regs.pc);
+
+    RootedValue &rval = rootValue0;
+    rval = regs.sp[-1];
+
+    RootedObject &obj = rootObject0;
+    obj = &regs.fp()->varObj();
+    if (!JSObject::defineProperty(cx, obj, name, rval,
+                                  JS_PropertyStub, JS_StrictPropertyStub,
+                                  JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
+        goto error;
+    }
+}
+END_CASE(JSOP_SETCONST);
+
+#if JS_HAS_DESTRUCTURING
+BEGIN_CASE(JSOP_ENUMCONSTELEM)
+{
+    RootedValue &rval = rootValue0;
+    rval = regs.sp[-3];
+
+    RootedObject &obj = rootObject0;
+    FETCH_OBJECT(cx, -2, obj);
+    RootedId &id = rootId0;
+    FETCH_ELEMENT_ID(obj, -1, id);
+    if (!JSObject::defineGeneric(cx, obj, id, rval,
+                                 JS_PropertyStub, JS_StrictPropertyStub,
+                                 JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
+        goto error;
+    }
+    regs.sp -= 3;
+}
+END_CASE(JSOP_ENUMCONSTELEM)
+#endif
+
+BEGIN_CASE(JSOP_BINDGNAME)
+    PUSH_OBJECT(regs.fp()->global());
+END_CASE(JSOP_BINDGNAME)
+
+BEGIN_CASE(JSOP_BINDNAME)
+{
+    RootedObject &scopeChain = rootObject0;
+    scopeChain = regs.fp()->scopeChain();
+
+    RootedPropertyName &name = rootName0;
+    name = script->getName(regs.pc);
+
+    /* Assigning to an undeclared name adds a property to the global object. */
+    RootedObject &scope = rootObject1;
+    if (!LookupNameWithGlobalDefault(cx, name, scopeChain, &scope))
+        goto error;
+
+    PUSH_OBJECT(*scope);
+}
+END_CASE(JSOP_BINDNAME)
+
+#define BITWISE_OP(OP)                                                        \
+    JS_BEGIN_MACRO                                                            \
+        int32_t i, j;                                                         \
+        if (!ToInt32(cx, regs.sp[-2], &i))                                    \
+            goto error;                                                       \
+        if (!ToInt32(cx, regs.sp[-1], &j))                                    \
+            goto error;                                                       \
+        i = i OP j;                                                           \
+        regs.sp--;                                                            \
+        regs.sp[-1].setInt32(i);                                              \
+    JS_END_MACRO
+
+BEGIN_CASE(JSOP_BITOR)
+    BITWISE_OP(|);
+END_CASE(JSOP_BITOR)
+
+BEGIN_CASE(JSOP_BITXOR)
+    BITWISE_OP(^);
+END_CASE(JSOP_BITXOR)
+
+BEGIN_CASE(JSOP_BITAND)
+    BITWISE_OP(&);
+END_CASE(JSOP_BITAND)
+
+#undef BITWISE_OP
+
+#define EQUALITY_OP(OP)                                                       \
+    JS_BEGIN_MACRO                                                            \
+        Value rval = regs.sp[-1];                                             \
+        Value lval = regs.sp[-2];                                             \
+        bool cond;                                                            \
+        if (!LooselyEqual(cx, lval, rval, &cond))                             \
+            goto error;                                                       \
+        cond = cond OP JS_TRUE;                                               \
+        TRY_BRANCH_AFTER_COND(cond, 2);                                       \
+        regs.sp--;                                                            \
+        regs.sp[-1].setBoolean(cond);                                         \
+    JS_END_MACRO
+
+BEGIN_CASE(JSOP_EQ)
+    EQUALITY_OP(==);
+END_CASE(JSOP_EQ)
+
+BEGIN_CASE(JSOP_NE)
+    EQUALITY_OP(!=);
+END_CASE(JSOP_NE)
+
+#undef EQUALITY_OP
+
+#define STRICT_EQUALITY_OP(OP, COND)                                          \
+    JS_BEGIN_MACRO                                                            \
+        const Value &rref = regs.sp[-1];                                      \
+        const Value &lref = regs.sp[-2];                                      \
+        bool equal;                                                           \
+        if (!StrictlyEqual(cx, lref, rref, &equal))                           \
+            goto error;                                                       \
+        COND = equal OP JS_TRUE;                                              \
+        regs.sp--;                                                            \
+    JS_END_MACRO
+
+BEGIN_CASE(JSOP_STRICTEQ)
+{
+    bool cond;
+    STRICT_EQUALITY_OP(==, cond);
+    regs.sp[-1].setBoolean(cond);
+}
+END_CASE(JSOP_STRICTEQ)
+
+BEGIN_CASE(JSOP_STRICTNE)
+{
+    bool cond;
+    STRICT_EQUALITY_OP(!=, cond);
+    regs.sp[-1].setBoolean(cond);
+}
+END_CASE(JSOP_STRICTNE)
+
+BEGIN_CASE(JSOP_CASE)
+{
+    bool cond;
+    STRICT_EQUALITY_OP(==, cond);
+    if (cond) {
+        regs.sp--;
+        len = GET_JUMP_OFFSET(regs.pc);
+        BRANCH(len);
+    }
+}
+END_CASE(JSOP_CASE)
+
+#undef STRICT_EQUALITY_OP
+
+BEGIN_CASE(JSOP_LT)
+{
+    bool cond;
+    const Value &lref = regs.sp[-2];
+    const Value &rref = regs.sp[-1];
+    if (!LessThanOperation(cx, lref, rref, &cond))
+        goto error;
+    TRY_BRANCH_AFTER_COND(cond, 2);
+    regs.sp[-2].setBoolean(cond);
+    regs.sp--;
+}
+END_CASE(JSOP_LT)
+
+BEGIN_CASE(JSOP_LE)
+{
+    bool cond;
+    const Value &lref = regs.sp[-2];
+    const Value &rref = regs.sp[-1];
+    if (!LessThanOrEqualOperation(cx, lref, rref, &cond))
+        goto error;
+    TRY_BRANCH_AFTER_COND(cond, 2);
+    regs.sp[-2].setBoolean(cond);
+    regs.sp--;
+}
+END_CASE(JSOP_LE)
+
+BEGIN_CASE(JSOP_GT)
+{
+    bool cond;
+    const Value &lref = regs.sp[-2];
+    const Value &rref = regs.sp[-1];
+    if (!GreaterThanOperation(cx, lref, rref, &cond))
+        goto error;
+    TRY_BRANCH_AFTER_COND(cond, 2);
+    regs.sp[-2].setBoolean(cond);
+    regs.sp--;
+}
+END_CASE(JSOP_GT)
+
+BEGIN_CASE(JSOP_GE)
+{
+    bool cond;
+    const Value &lref = regs.sp[-2];
+    const Value &rref = regs.sp[-1];
+    if (!GreaterThanOrEqualOperation(cx, lref, rref, &cond))
+        goto error;
+    TRY_BRANCH_AFTER_COND(cond, 2);
+    regs.sp[-2].setBoolean(cond);
+    regs.sp--;
+}
+END_CASE(JSOP_GE)
+
+#define SIGNED_SHIFT_OP(OP)                                                   \
+    JS_BEGIN_MACRO                                                            \
+        int32_t i, j;                                                         \
+        if (!ToInt32(cx, regs.sp[-2], &i))                                    \
+            goto error;                                                       \
+        if (!ToInt32(cx, regs.sp[-1], &j))                                    \
+            goto error;                                                       \
+        i = i OP (j & 31);                                                    \
+        regs.sp--;                                                            \
+        regs.sp[-1].setInt32(i);                                              \
+    JS_END_MACRO
+
+BEGIN_CASE(JSOP_LSH)
+    SIGNED_SHIFT_OP(<<);
+END_CASE(JSOP_LSH)
+
+BEGIN_CASE(JSOP_RSH)
+    SIGNED_SHIFT_OP(>>);
+END_CASE(JSOP_RSH)
+
+#undef SIGNED_SHIFT_OP
+
+BEGIN_CASE(JSOP_URSH)
+{
+    HandleValue lval = HandleValue::fromMarkedLocation(&regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+    if (!UrshOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
+}
+END_CASE(JSOP_URSH)
+
+BEGIN_CASE(JSOP_ADD)
+{
+    Value lval = regs.sp[-2];
+    Value rval = regs.sp[-1];
+    if (!AddOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
+}
+END_CASE(JSOP_ADD)
+
+BEGIN_CASE(JSOP_SUB)
+{
+    RootedValue &lval = rootValue0, &rval = rootValue1;
+    lval = regs.sp[-2];
+    rval = regs.sp[-1];
+    if (!SubOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
+}
+END_CASE(JSOP_SUB)
+
+BEGIN_CASE(JSOP_MUL)
+{
+    RootedValue &lval = rootValue0, &rval = rootValue1;
+    lval = regs.sp[-2];
+    rval = regs.sp[-1];
+    if (!MulOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
+}
+END_CASE(JSOP_MUL)
+
+BEGIN_CASE(JSOP_DIV)
+{
+    RootedValue &lval = rootValue0, &rval = rootValue1;
+    lval = regs.sp[-2];
+    rval = regs.sp[-1];
+    if (!DivOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
+}
+END_CASE(JSOP_DIV)
+
+BEGIN_CASE(JSOP_MOD)
+{
+    RootedValue &lval = rootValue0, &rval = rootValue1;
+    lval = regs.sp[-2];
+    rval = regs.sp[-1];
+    if (!ModOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
+        goto error;
+    regs.sp--;
+}
+END_CASE(JSOP_MOD)
+
+BEGIN_CASE(JSOP_NOT)
+{
+    bool cond = ToBoolean(regs.sp[-1]);
+    regs.sp--;
+    PUSH_BOOLEAN(!cond);
+}
+END_CASE(JSOP_NOT)
+
+BEGIN_CASE(JSOP_BITNOT)
+{
+    int32_t i;
+    HandleValue value = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+    if (!BitNot(cx, value, &i))
+        goto error;
+    regs.sp[-1].setInt32(i);
+}
+END_CASE(JSOP_BITNOT)
+
+BEGIN_CASE(JSOP_NEG)
+{
+    /*
+     * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies
+     * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the
+     * results, -0.0 or INT32_MAX + 1, are double values.
+     */
+    Value ref = regs.sp[-1];
+    int32_t i;
+    if (ref.isInt32() && (i = ref.toInt32()) != 0 && i != INT32_MIN) {
+        i = -i;
+        regs.sp[-1].setInt32(i);
+    } else {
+        double d;
+        if (!ToNumber(cx, regs.sp[-1], &d))
+            goto error;
+        d = -d;
+        if (!regs.sp[-1].setNumber(d) && !ref.isDouble())
+            TypeScript::MonitorOverflow(cx, script, regs.pc);
+    }
+}
+END_CASE(JSOP_NEG)
+
+BEGIN_CASE(JSOP_POS)
+    if (!ToNumber(cx, &regs.sp[-1]))
+        goto error;
+    if (!regs.sp[-1].isInt32())
+        TypeScript::MonitorOverflow(cx, script, regs.pc);
+END_CASE(JSOP_POS)
+
+BEGIN_CASE(JSOP_DELNAME)
+{
+    RootedPropertyName &name = rootName0;
+    name = script->getName(regs.pc);
+
+    RootedObject &scopeObj = rootObject0;
+    scopeObj = cx->stack.currentScriptedScopeChain();
+
+    RootedObject &scope = rootObject1;
+    RootedObject &pobj = rootObject2;
+    RootedShape &prop = rootShape0;
+    if (!LookupName(cx, name, scopeObj, &scope, &pobj, &prop))
+        goto error;
+
+    /* Strict mode code should never contain JSOP_DELNAME opcodes. */
+    JS_ASSERT(!script->strictModeCode);
+
+    /* ECMA says to return true if name is undefined or inherited. */
+    PUSH_BOOLEAN(true);
+    if (prop) {
+        MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
+        if (!JSObject::deleteProperty(cx, scope, name, res, false))
+            goto error;
+    }
+}
+END_CASE(JSOP_DELNAME)
+
+BEGIN_CASE(JSOP_DELPROP)
+{
+    RootedPropertyName &name = rootName0;
+    name = script->getName(regs.pc);
+
+    RootedObject &obj = rootObject0;
+    FETCH_OBJECT(cx, -1, obj);
+
+    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
+    if (!JSObject::deleteProperty(cx, obj, name, res, script->strictModeCode))
+        goto error;
+}
+END_CASE(JSOP_DELPROP)
+
+BEGIN_CASE(JSOP_DELELEM)
+{
+    /* Fetch the left part and resolve it to a non-null object. */
+    RootedObject &obj = rootObject0;
+    FETCH_OBJECT(cx, -2, obj);
+
+    RootedValue &propval = rootValue0;
+    propval = regs.sp[-1];
+
+    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
+    if (!JSObject::deleteByValue(cx, obj, propval, res, script->strictModeCode))
+        goto error;
+
+    regs.sp--;
+}
+END_CASE(JSOP_DELELEM)
+
+BEGIN_CASE(JSOP_TOID)
+{
+    /*
+     * Increment or decrement requires use to lookup the same property twice, but we need to avoid
+     * the oberservable stringification the second time.
+     * There must be an object value below the id, which will not be popped
+     * but is necessary in interning the id for XML.
+     */
+    RootedValue &objval = rootValue0, &idval = rootValue1;
+    objval = regs.sp[-2];
+    idval = regs.sp[-1];
+
+    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
+    if (!ToIdOperation(cx, script, regs.pc, objval, idval, res))
+        goto error;
+}
+END_CASE(JSOP_TOID)
+
+BEGIN_CASE(JSOP_TYPEOFEXPR)
+BEGIN_CASE(JSOP_TYPEOF)
+{
+    HandleValue ref = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+    regs.sp[-1].setString(TypeOfOperation(cx, ref));
+}
+END_CASE(JSOP_TYPEOF)
+
+BEGIN_CASE(JSOP_VOID)
+    regs.sp[-1].setUndefined();
+END_CASE(JSOP_VOID)
+
+BEGIN_CASE(JSOP_INCELEM)
+BEGIN_CASE(JSOP_DECELEM)
+BEGIN_CASE(JSOP_ELEMINC)
+BEGIN_CASE(JSOP_ELEMDEC)
+    /* No-op */
+END_CASE(JSOP_INCELEM)
+
+BEGIN_CASE(JSOP_INCPROP)
+BEGIN_CASE(JSOP_DECPROP)
+BEGIN_CASE(JSOP_PROPINC)
+BEGIN_CASE(JSOP_PROPDEC)
+BEGIN_CASE(JSOP_INCNAME)
+BEGIN_CASE(JSOP_DECNAME)
+BEGIN_CASE(JSOP_NAMEINC)
+BEGIN_CASE(JSOP_NAMEDEC)
+BEGIN_CASE(JSOP_INCGNAME)
+BEGIN_CASE(JSOP_DECGNAME)
+BEGIN_CASE(JSOP_GNAMEINC)
+BEGIN_CASE(JSOP_GNAMEDEC)
+    /* No-op */
+END_CASE(JSOP_INCPROP)
+
+BEGIN_CASE(JSOP_DECALIASEDVAR)
+BEGIN_CASE(JSOP_ALIASEDVARDEC)
+BEGIN_CASE(JSOP_INCALIASEDVAR)
+BEGIN_CASE(JSOP_ALIASEDVARINC)
+    /* No-op */
+END_CASE(JSOP_ALIASEDVARINC)
+
+BEGIN_CASE(JSOP_DECARG)
+BEGIN_CASE(JSOP_ARGDEC)
+BEGIN_CASE(JSOP_INCARG)
+BEGIN_CASE(JSOP_ARGINC)
+{
+    unsigned i = GET_ARGNO(regs.pc);
+    if (script->argsObjAliasesFormals()) {
+        const Value &arg = regs.fp()->argsObj().arg(i);
+        Value v;
+        if (!DoIncDec(cx, script, regs.pc, arg, &v, &regs.sp[0]))
+            goto error;
+        regs.fp()->argsObj().setArg(i, v);
+    } else {
+        Value &arg = regs.fp()->unaliasedFormal(i);
+        if (!DoIncDec(cx, script, regs.pc, arg, &arg, &regs.sp[0]))
+            goto error;
+    }
+    regs.sp++;
+}
+END_CASE(JSOP_ARGINC);
+
+BEGIN_CASE(JSOP_DECLOCAL)
+BEGIN_CASE(JSOP_LOCALDEC)
+BEGIN_CASE(JSOP_INCLOCAL)
+BEGIN_CASE(JSOP_LOCALINC)
+{
+    unsigned i = GET_SLOTNO(regs.pc);
+    Value &local = regs.fp()->unaliasedLocal(i);
+    if (!DoIncDec(cx, script, regs.pc, local, &local, &regs.sp[0]))
+        goto error;
+    regs.sp++;
+}
+END_CASE(JSOP_LOCALINC)
+
+BEGIN_CASE(JSOP_THIS)
+    if (!ComputeThis(cx, regs.fp()))
+        goto error;
+    PUSH_COPY(regs.fp()->thisValue());
+END_CASE(JSOP_THIS)
+
+BEGIN_CASE(JSOP_GETPROP)
+BEGIN_CASE(JSOP_GETXPROP)
+BEGIN_CASE(JSOP_LENGTH)
+BEGIN_CASE(JSOP_CALLPROP)
+{
+    RootedValue &lval = rootValue0;
+    lval = regs.sp[-1];
+
+    RootedValue rval(cx);
+    if (!GetPropertyOperation(cx, script, regs.pc, &lval, &rval))
+        goto error;
+
+    TypeScript::Monitor(cx, script, regs.pc, rval);
+
+    regs.sp[-1] = rval;
+    assertSameCompartment(cx, regs.sp[-1]);
+}
+END_CASE(JSOP_GETPROP)
+
+BEGIN_CASE(JSOP_SETGNAME)
+BEGIN_CASE(JSOP_SETNAME)
+{
+    RootedObject &scope = rootObject0;
+    scope = &regs.sp[-2].toObject();
+
+    HandleValue value = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+
+    if (!SetNameOperation(cx, script, regs.pc, scope, value))
+        goto error;
+
+    regs.sp[-2] = regs.sp[-1];
+    regs.sp--;
+}
+END_CASE(JSOP_SETNAME)
+
+BEGIN_CASE(JSOP_SETPROP)
+{
+    HandleValue lval = HandleValue::fromMarkedLocation(&regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+
+    if (!SetPropertyOperation(cx, regs.pc, lval, rval))
+        goto error;
+
+    regs.sp[-2] = regs.sp[-1];
+    regs.sp--;
+}
+END_CASE(JSOP_SETPROP)
+
+BEGIN_CASE(JSOP_GETELEM)
+BEGIN_CASE(JSOP_CALLELEM)
+{
+    MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
+    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+
+    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
+    if (!GetElementOperation(cx, op, lval, rval, res))
+        goto error;
+    TypeScript::Monitor(cx, script, regs.pc, res);
+    regs.sp--;
+}
+END_CASE(JSOP_GETELEM)
+
+BEGIN_CASE(JSOP_SETELEM)
+{
+    RootedObject &obj = rootObject0;
+    FETCH_OBJECT(cx, -3, obj);
+    RootedId &id = rootId0;
+    FETCH_ELEMENT_ID(obj, -2, id);
+    Value &value = regs.sp[-1];
+    if (!SetObjectElementOperation(cx, obj, id, value, script->strictModeCode))
+        goto error;
+    regs.sp[-3] = value;
+    regs.sp -= 2;
+}
+END_CASE(JSOP_SETELEM)
+
+BEGIN_CASE(JSOP_ENUMELEM)
+{
+    RootedObject &obj = rootObject0;
+    RootedValue &rval = rootValue0;
+
+    /* Funky: the value to set is under the [obj, id] pair. */
+    FETCH_OBJECT(cx, -2, obj);
+    RootedId &id = rootId0;
+    FETCH_ELEMENT_ID(obj, -1, id);
+    rval = regs.sp[-3];
+    if (!JSObject::setGeneric(cx, obj, obj, id, &rval, script->strictModeCode))
+        goto error;
+    regs.sp -= 3;
+}
+END_CASE(JSOP_ENUMELEM)
+
+BEGIN_CASE(JSOP_EVAL)
+{
+    CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
+    if (IsBuiltinEvalForScope(regs.fp()->scopeChain(), args.calleev())) {
+        if (!DirectEval(cx, args))
+            goto error;
+    } else {
+        if (!InvokeKernel(cx, args))
+            goto error;
+    }
+    regs.sp = args.spAfterCall();
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
+}
+END_CASE(JSOP_EVAL)
+
+BEGIN_CASE(JSOP_FUNAPPLY)
+    if (!GuardFunApplyArgumentsOptimization(cx))
+        goto error;
+    /* FALL THROUGH */
+
+BEGIN_CASE(JSOP_NEW)
+BEGIN_CASE(JSOP_CALL)
+BEGIN_CASE(JSOP_FUNCALL)
+{
+    if (regs.fp()->hasPushedSPSFrame())
+        cx->runtime->spsProfiler.updatePC(script, regs.pc);
+    JS_ASSERT(regs.stackDepth() >= 2 + GET_ARGC(regs.pc));
+    CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
+
+    bool construct = (*regs.pc == JSOP_NEW);
+
+    RootedFunction &fun = rootFunction0;
+    /* Don't bother trying to fast-path calls to scripted non-constructors. */
+    if (!IsFunctionObject(args.calleev(), fun.address()) || !fun->isInterpretedConstructor()) {
+        if (construct) {
+            if (!InvokeConstructorKernel(cx, args))
+                goto error;
+        } else {
+            if (!InvokeKernel(cx, args))
+                goto error;
+        }
+        Value *newsp = args.spAfterCall();
+        TypeScript::Monitor(cx, script, regs.pc, newsp[-1]);
+        regs.sp = newsp;
+        len = JSOP_CALL_LENGTH;
+        DO_NEXT_OP(len);
+    }
+
+    if (!TypeMonitorCall(cx, args, construct))
+        goto error;
+
+    InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
+    bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc);
+    RawScript funScript = fun->script().unsafeGet();
+    if (!cx->stack.pushInlineFrame(cx, regs, args, *fun, funScript, initial))
+        goto error;
+
+    SET_SCRIPT(regs.fp()->script());
+    script->resetLoopCount();
+
+#ifdef JS_ION
+    if (!newType && ion::IsEnabled(cx)) {
+        ion::MethodStatus status = ion::CanEnter(cx, script, regs.fp(), newType);
+        if (status == ion::Method_Error)
+            goto error;
+        if (status == ion::Method_Compiled) {
+            ion::IonExecStatus exec = ion::Cannon(cx, regs.fp());
+            CHECK_BRANCH();
+            if (exec == ion::IonExec_Bailout) {
+                SET_SCRIPT(regs.fp()->script());
+                op = JSOp(*regs.pc);
+                DO_OP();
+            }
+            interpReturnOK = (exec == ion::IonExec_Error) ? false : true;
+            goto jit_return;
+        }
+    }
+#endif
+
+#ifdef JS_METHODJIT
+    if (!newType && cx->methodJitEnabled) {
+        /* Try to ensure methods are method JIT'd.  */
+        mjit::CompileStatus status = mjit::CanMethodJIT(cx, script, script->code,
+                                                        construct,
+                                                        mjit::CompileRequest_Interpreter,
+                                                        regs.fp());
+        if (status == mjit::Compile_Error)
+            goto error;
+        if (status == mjit::Compile_Okay) {
+            mjit::JaegerStatus status = mjit::JaegerShot(cx, true);
+            CHECK_PARTIAL_METHODJIT(status);
+            interpReturnOK = mjit::JaegerStatusToSuccess(status);
+            goto jit_return;
+        }
+    }
+#endif
+
+    if (!regs.fp()->prologue(cx, newType))
+        goto error;
+    if (cx->compartment->debugMode()) {
+        switch (ScriptDebugPrologue(cx, regs.fp())) {
+          case JSTRAP_CONTINUE:
+            break;
+          case JSTRAP_RETURN:
+            interpReturnOK = true;
+            goto forced_return;
+          case JSTRAP_THROW:
+          case JSTRAP_ERROR:
+            goto error;
+          default:
+            JS_NOT_REACHED("bad ScriptDebugPrologue status");
+        }
+    }
+
+    /* Load first op and dispatch it (safe since JSOP_STOP). */
+    op = (JSOp) *regs.pc;
+    DO_OP();
+}
+
+BEGIN_CASE(JSOP_SETCALL)
+{
+    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_LEFTSIDE_OF_ASS);
+    goto error;
+}
+END_CASE(JSOP_SETCALL)
+
+BEGIN_CASE(JSOP_IMPLICITTHIS)
+{
+    RootedPropertyName &name = rootName0;
+    name = script->getName(regs.pc);
+
+    RootedObject &scopeObj = rootObject0;
+    scopeObj = cx->stack.currentScriptedScopeChain();
+
+    RootedObject &scope = rootObject1;
+    if (!LookupNameWithGlobalDefault(cx, name, scopeObj, &scope))
+        goto error;
+
+    Value v;
+    if (!ComputeImplicitThis(cx, scope, &v))
+        goto error;
+    PUSH_COPY(v);
+}
+END_CASE(JSOP_IMPLICITTHIS)
+
+BEGIN_CASE(JSOP_GETGNAME)
+BEGIN_CASE(JSOP_CALLGNAME)
+BEGIN_CASE(JSOP_NAME)
+BEGIN_CASE(JSOP_CALLNAME)
+{
+    RootedValue &rval = rootValue0;
+
+    if (!NameOperation(cx, regs.pc, &rval))
+        goto error;
+
+    PUSH_COPY(rval);
+    TypeScript::Monitor(cx, script, regs.pc, rval);
+}
+END_CASE(JSOP_NAME)
+
+BEGIN_CASE(JSOP_INTRINSICNAME)
+BEGIN_CASE(JSOP_CALLINTRINSIC)
+{
+    RootedValue &rval = rootValue0;
+
+    if (!IntrinsicNameOperation(cx, script, regs.pc, &rval))
+        goto error;
+
+    PUSH_COPY(rval);
+    TypeScript::Monitor(cx, script, regs.pc, rval);
+}
+END_CASE(JSOP_INTRINSICNAME)
+
+BEGIN_CASE(JSOP_UINT16)
+    PUSH_INT32((int32_t) GET_UINT16(regs.pc));
+END_CASE(JSOP_UINT16)
+
+BEGIN_CASE(JSOP_UINT24)
+    PUSH_INT32((int32_t) GET_UINT24(regs.pc));
+END_CASE(JSOP_UINT24)
+
+BEGIN_CASE(JSOP_INT8)
+    PUSH_INT32(GET_INT8(regs.pc));
+END_CASE(JSOP_INT8)
+
+BEGIN_CASE(JSOP_INT32)
+    PUSH_INT32(GET_INT32(regs.pc));
+END_CASE(JSOP_INT32)
+
+BEGIN_CASE(JSOP_DOUBLE)
+{
+    double dbl;
+    LOAD_DOUBLE(0, dbl);
+    PUSH_DOUBLE(dbl);
+}
+END_CASE(JSOP_DOUBLE)
+
+BEGIN_CASE(JSOP_STRING)
+    PUSH_STRING(script->getAtom(regs.pc));
+END_CASE(JSOP_STRING)
+
+BEGIN_CASE(JSOP_OBJECT)
+    PUSH_OBJECT(*script->getObject(regs.pc));
+END_CASE(JSOP_OBJECT)
+
+BEGIN_CASE(JSOP_REGEXP)
+{
+    /*
+     * Push a regexp object cloned from the regexp literal object mapped by the
+     * bytecode at pc.
+     */
+    uint32_t index = GET_UINT32_INDEX(regs.pc);
+    JSObject *proto = regs.fp()->global().getOrCreateRegExpPrototype(cx);
+    if (!proto)
+        goto error;
+    JSObject *obj = CloneRegExpObject(cx, script->getRegExp(index), proto);
+    if (!obj)
+        goto error;
+    PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_REGEXP)
+
+BEGIN_CASE(JSOP_ZERO)
+    PUSH_INT32(0);
+END_CASE(JSOP_ZERO)
+
+BEGIN_CASE(JSOP_ONE)
+    PUSH_INT32(1);
+END_CASE(JSOP_ONE)
+
+BEGIN_CASE(JSOP_NULL)
+    PUSH_NULL();
+END_CASE(JSOP_NULL)
+
+BEGIN_CASE(JSOP_FALSE)
+    PUSH_BOOLEAN(false);
+END_CASE(JSOP_FALSE)
+
+BEGIN_CASE(JSOP_TRUE)
+    PUSH_BOOLEAN(true);
+END_CASE(JSOP_TRUE)
+
+{
+BEGIN_CASE(JSOP_TABLESWITCH)
+{
+    jsbytecode *pc2 = regs.pc;
+    len = GET_JUMP_OFFSET(pc2);
+
+    /*
+     * ECMAv2+ forbids conversion of discriminant, so we will skip to the
+     * default case if the discriminant isn't already an int jsval.  (This
+     * opcode is emitted only for dense int-domain switches.)
+     */
+    const Value &rref = *--regs.sp;
+    int32_t i;
+    if (rref.isInt32()) {
+        i = rref.toInt32();
+    } else {
+        double d;
+        /* Don't use MOZ_DOUBLE_IS_INT32; treat -0 (double) as 0. */
+        if (!rref.isDouble() || (d = rref.toDouble()) != (i = int32_t(rref.toDouble())))
+            DO_NEXT_OP(len);
+    }
+
+    pc2 += JUMP_OFFSET_LEN;
+    int32_t low = GET_JUMP_OFFSET(pc2);
+    pc2 += JUMP_OFFSET_LEN;
+    int32_t high = GET_JUMP_OFFSET(pc2);
+
+    i -= low;
+    if ((uint32_t)i < (uint32_t)(high - low + 1)) {
+        pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
+        int32_t off = (int32_t) GET_JUMP_OFFSET(pc2);
+        if (off)
+            len = off;
+    }
+}
+END_VARLEN_CASE
+}
+
+{
+BEGIN_CASE(JSOP_LOOKUPSWITCH)
+{
+    int32_t off;
+    off = JUMP_OFFSET_LEN;
+
+    /*
+     * JSOP_LOOKUPSWITCH are never used if any atom index in it would exceed
+     * 64K limit.
+     */
+    jsbytecode *pc2 = regs.pc;
+
+    Value lval = regs.sp[-1];
+    regs.sp--;
+
+    int npairs;
+    if (!lval.isPrimitive())
+        goto end_lookup_switch;
+
+    pc2 += off;
+    npairs = GET_UINT16(pc2);
+    pc2 += UINT16_LEN;
+    JS_ASSERT(npairs);  /* empty switch uses JSOP_TABLESWITCH */
+
+    bool match;
+#define SEARCH_PAIRS(MATCH_CODE)                                              \
+    for (;;) {                                                                \
+        Value rval = script->getConst(GET_UINT32_INDEX(pc2));                 \
+        MATCH_CODE                                                            \
+        pc2 += UINT32_INDEX_LEN;                                              \
+        if (match)                                                            \
+            break;                                                            \
+        pc2 += off;                                                           \
+        if (--npairs == 0) {                                                  \
+            pc2 = regs.pc;                                                    \
+            break;                                                            \
+        }                                                                     \
+    }
+
+    if (lval.isString()) {
+        JSLinearString *str = lval.toString()->ensureLinear(cx);
+        if (!str)
+            goto error;
+        JSLinearString *str2;
+        SEARCH_PAIRS(
+            match = (rval.isString() &&
+                     ((str2 = &rval.toString()->asLinear()) == str ||
+                      EqualStrings(str2, str)));
+        )
+    } else if (lval.isNumber()) {
+        double ldbl = lval.toNumber();
+        SEARCH_PAIRS(
+            match = rval.isNumber() && ldbl == rval.toNumber();
+        )
+    } else {
+        SEARCH_PAIRS(
+            match = (lval == rval);
+        )
+    }
+#undef SEARCH_PAIRS
+
+  end_lookup_switch:
+    len = GET_JUMP_OFFSET(pc2);
+}
+END_VARLEN_CASE
+}
+
+BEGIN_CASE(JSOP_ARGUMENTS)
+    JS_ASSERT(!regs.fp()->fun()->hasRest());
+    if (script->needsArgsObj()) {
+        ArgumentsObject *obj = ArgumentsObject::createExpected(cx, regs.fp());
+        if (!obj)
+            goto error;
+        PUSH_COPY(ObjectValue(*obj));
+    } else {
+        PUSH_COPY(MagicValue(JS_OPTIMIZED_ARGUMENTS));
+    }
+END_CASE(JSOP_ARGUMENTS)
+
+BEGIN_CASE(JSOP_REST)
+{
+    RootedObject &rest = rootObject0;
+    rest = regs.fp()->createRestParameter(cx);
+    if (!rest)
+        goto error;
+    PUSH_COPY(ObjectValue(*rest));
+    if (!SetInitializerObjectType(cx, script, regs.pc, rest))
+        goto error;
+}
+END_CASE(JSOP_REST)
+
+BEGIN_CASE(JSOP_CALLALIASEDVAR)
+BEGIN_CASE(JSOP_GETALIASEDVAR)
+{
+    ScopeCoordinate sc = ScopeCoordinate(regs.pc);
+    PUSH_COPY(regs.fp()->aliasedVarScope(sc).aliasedVar(sc));
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
+}
+END_CASE(JSOP_GETALIASEDVAR)
+
+BEGIN_CASE(JSOP_SETALIASEDVAR)
+{
+    ScopeCoordinate sc = ScopeCoordinate(regs.pc);
+    regs.fp()->aliasedVarScope(sc).setAliasedVar(sc, regs.sp[-1]);
+}
+END_CASE(JSOP_SETALIASEDVAR)
+
+BEGIN_CASE(JSOP_GETARG)
+BEGIN_CASE(JSOP_CALLARG)
+{
+    unsigned i = GET_ARGNO(regs.pc);
+    if (script->argsObjAliasesFormals())
+        PUSH_COPY(regs.fp()->argsObj().arg(i));
+    else
+        PUSH_COPY(regs.fp()->unaliasedFormal(i));
+}
+END_CASE(JSOP_GETARG)
+
+BEGIN_CASE(JSOP_SETARG)
+{
+    unsigned i = GET_ARGNO(regs.pc);
+    if (script->argsObjAliasesFormals())
+        regs.fp()->argsObj().setArg(i, regs.sp[-1]);
+    else
+        regs.fp()->unaliasedFormal(i) = regs.sp[-1];
+}
+END_CASE(JSOP_SETARG)
+
+BEGIN_CASE(JSOP_GETLOCAL)
+BEGIN_CASE(JSOP_CALLLOCAL)
+{
+    unsigned i = GET_SLOTNO(regs.pc);
+    PUSH_COPY_SKIP_CHECK(regs.fp()->unaliasedLocal(i));
+
+    /*
+     * Skip the same-compartment assertion if the local will be immediately
+     * popped. We do not guarantee sync for dead locals when coming in from the
+     * method JIT, and a GETLOCAL followed by POP is not considered to be
+     * a use of the variable.
+     */
+    if (regs.pc[JSOP_GETLOCAL_LENGTH] != JSOP_POP)
+        assertSameCompartment(cx, regs.sp[-1]);
+}
+END_CASE(JSOP_GETLOCAL)
+
+BEGIN_CASE(JSOP_SETLOCAL)
+{
+    unsigned i = GET_SLOTNO(regs.pc);
+    regs.fp()->unaliasedLocal(i) = regs.sp[-1];
+}
+END_CASE(JSOP_SETLOCAL)
+
+BEGIN_CASE(JSOP_DEFCONST)
+BEGIN_CASE(JSOP_DEFVAR)
+{
+    /* ES5 10.5 step 8 (with subsequent errata). */
+    unsigned attrs = JSPROP_ENUMERATE;
+    if (!regs.fp()->isEvalFrame())
+        attrs |= JSPROP_PERMANENT;
+    if (op == JSOP_DEFCONST)
+        attrs |= JSPROP_READONLY;
+
+    /* Step 8b. */
+    RootedObject &obj = rootObject0;
+    obj = &regs.fp()->varObj();
+
+    RootedPropertyName &name = rootName0;
+    name = script->getName(regs.pc);
+
+    if (!DefVarOrConstOperation(cx, obj, name, attrs))
+        goto error;
+}
+END_CASE(JSOP_DEFVAR)
+
+BEGIN_CASE(JSOP_DEFFUN)
+{
+    /*
+     * A top-level function defined in Global or Eval code (see ECMA-262
+     * Ed. 3), or else a SpiderMonkey extension: a named function statement in
+     * a compound statement (not at the top statement level of global code, or
+     * at the top level of a function body).
+     */
+    RootedFunction &fun = rootFunction0;
+    fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
+
+    /*
+     * If static link is not current scope, clone fun's object to link to the
+     * current scope via parent. We do this to enable sharing of compiled
+     * functions among multiple equivalent scopes, amortizing the cost of
+     * compilation over a number of executions.  Examples include XUL scripts
+     * and event handlers shared among Firefox or other Mozilla app chrome
+     * windows, and user-defined JS functions precompiled and then shared among
+     * requests in server-side JS.
+     */
+    HandleObject scopeChain = regs.fp()->scopeChain();
+    if (fun->environment() != scopeChain) {
+        fun = CloneFunctionObjectIfNotSingleton(cx, fun, scopeChain);
+        if (!fun)
+            goto error;
+    } else {
+        JS_ASSERT(script->compileAndGo);
+        JS_ASSERT(regs.fp()->isGlobalFrame() || regs.fp()->isEvalInFunction());
+    }
+
+    /*
+     * ECMA requires functions defined when entering Eval code to be
+     * impermanent.
+     */
+    unsigned attrs = regs.fp()->isEvalFrame()
+                  ? JSPROP_ENUMERATE
+                  : JSPROP_ENUMERATE | JSPROP_PERMANENT;
+
+    /*
+     * We define the function as a property of the variable object and not the
+     * current scope chain even for the case of function expression statements
+     * and functions defined by eval inside let or with blocks.
+     */
+    RootedObject &parent = rootObject0;
+    parent = &regs.fp()->varObj();
+
+    /* ES5 10.5 (NB: with subsequent errata). */
+    RootedPropertyName &name = rootName0;
+    name = fun->atom()->asPropertyName();
+    RootedShape &shape = rootShape0;
+    RootedObject &pobj = rootObject1;
+    if (!JSObject::lookupProperty(cx, parent, name, &pobj, &shape))
+        goto error;
+
+    RootedValue &rval = rootValue0;
+    rval = ObjectValue(*fun);
+
+    do {
+        /* Steps 5d, 5f. */
+        if (!shape || pobj != parent) {
+            if (!JSObject::defineProperty(cx, parent, name, rval,
+                                          JS_PropertyStub, JS_StrictPropertyStub, attrs))
+            {
+                goto error;
+            }
+            break;
+        }
+
+        /* Step 5e. */
+        JS_ASSERT(parent->isNative());
+        if (parent->isGlobal()) {
+            if (shape->configurable()) {
+                if (!JSObject::defineProperty(cx, parent, name, rval,
+                                              JS_PropertyStub, JS_StrictPropertyStub, attrs))
+                {
+                    goto error;
+                }
+                break;
+            }
+
+            if (shape->isAccessorDescriptor() || !shape->writable() || !shape->enumerable()) {
+                JSAutoByteString bytes;
+                if (js_AtomToPrintableString(cx, name, &bytes)) {
+                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                         JSMSG_CANT_REDEFINE_PROP, bytes.ptr());
+                }
+                goto error;
+            }
+        }
+
+        /*
+         * Non-global properties, and global properties which we aren't simply
+         * redefining, must be set.  First, this preserves their attributes.
+         * Second, this will produce warnings and/or errors as necessary if the
+         * specified Call object property is not writable (const).
+         */
+
+        /* Step 5f. */
+        if (!JSObject::setProperty(cx, parent, parent, name, &rval, script->strictModeCode))
+            goto error;
+    } while (false);
+}
+END_CASE(JSOP_DEFFUN)
+
+BEGIN_CASE(JSOP_LAMBDA)
+{
+    /* Load the specified function object literal. */
+    RootedFunction &fun = rootFunction0;
+    fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
+
+    JSFunction *obj = CloneFunctionObjectIfNotSingleton(cx, fun, regs.fp()->scopeChain());
+    if (!obj)
+        goto error;
+
+    JS_ASSERT(obj->getProto());
+    PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_LAMBDA)
+
+BEGIN_CASE(JSOP_CALLEE)
+    JS_ASSERT(regs.fp()->isNonEvalFunctionFrame());
+    PUSH_COPY(regs.fp()->calleev());
+END_CASE(JSOP_CALLEE)
+
+BEGIN_CASE(JSOP_GETTER)
+BEGIN_CASE(JSOP_SETTER)
+{
+    JSOp op2 = JSOp(*++regs.pc);
+    RootedId &id = rootId0;
+    RootedValue &rval = rootValue0;
+    RootedValue &scratch = rootValue1;
+    int i;
+
+    RootedObject &obj = rootObject0;
+    switch (op2) {
+      case JSOP_SETNAME:
+      case JSOP_SETPROP:
+        id = NameToId(script->getName(regs.pc));
+        rval = regs.sp[-1];
+        i = -1;
+        goto gs_pop_lval;
+      case JSOP_SETELEM:
+        rval = regs.sp[-1];
+        id = JSID_VOID;
+        i = -2;
+      gs_pop_lval:
+        FETCH_OBJECT(cx, i - 1, obj);
+        break;
+
+      case JSOP_INITPROP:
+        JS_ASSERT(regs.stackDepth() >= 2);
+        rval = regs.sp[-1];
+        i = -1;
+        id = NameToId(script->getName(regs.pc));
+        goto gs_get_lval;
+      default:
+        JS_ASSERT(op2 == JSOP_INITELEM);
+        JS_ASSERT(regs.stackDepth() >= 3);
+        rval = regs.sp[-1];
+        id = JSID_VOID;
+        i = -2;
+      gs_get_lval:
+      {
+        const Value &lref = regs.sp[i-1];
+        JS_ASSERT(lref.isObject());
+        obj = &lref.toObject();
+        break;
+      }
+    }
+
+    /* Ensure that id has a type suitable for use with obj. */
+    if (JSID_IS_VOID(id))
+        FETCH_ELEMENT_ID(obj, i, id);
+
+    if (!js_IsCallable(rval)) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_GETTER_OR_SETTER,
+                             (op == JSOP_GETTER) ? js_getter_str : js_setter_str);
+        goto error;
+    }
+
+    /*
+     * Getters and setters are just like watchpoints from an access control
+     * point of view.
+     */
+    scratch.setUndefined();
+    unsigned attrs;
+    if (!CheckAccess(cx, obj, id, JSACC_WATCH, &scratch, &attrs))
+        goto error;
+
+    PropertyOp getter;
+    StrictPropertyOp setter;
+    if (op == JSOP_GETTER) {
+        getter = CastAsPropertyOp(&rval.toObject());
+        setter = JS_StrictPropertyStub;
+        attrs = JSPROP_GETTER;
+    } else {
+        getter = JS_PropertyStub;
+        setter = CastAsStrictPropertyOp(&rval.toObject());
+        attrs = JSPROP_SETTER;
+    }
+    attrs |= JSPROP_ENUMERATE | JSPROP_SHARED;
+
+    scratch.setUndefined();
+    if (!JSObject::defineGeneric(cx, obj, id, scratch, getter, setter, attrs))
+        goto error;
+
+    regs.sp += i;
+    if (js_CodeSpec[op2].ndefs > js_CodeSpec[op2].nuses) {
+        JS_ASSERT(js_CodeSpec[op2].ndefs == js_CodeSpec[op2].nuses + 1);
+        regs.sp[-1] = rval;
+        assertSameCompartment(cx, regs.sp[-1]);
+    }
+    len = js_CodeSpec[op2].length;
+    DO_NEXT_OP(len);
+}
+
+BEGIN_CASE(JSOP_HOLE)
+    PUSH_HOLE();
+END_CASE(JSOP_HOLE)
+
+BEGIN_CASE(JSOP_NEWINIT)
+{
+    uint8_t i = GET_UINT8(regs.pc);
+    JS_ASSERT(i == JSProto_Array || i == JSProto_Object);
+
+    RootedObject &obj = rootObject0;
+    if (i == JSProto_Array) {
+        obj = NewDenseEmptyArray(cx);
+    } else {
+        gc::AllocKind kind = GuessObjectGCKind(0);
+        obj = NewBuiltinClassInstance(cx, &ObjectClass, kind);
+    }
+    if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
+        goto error;
+
+    PUSH_OBJECT(*obj);
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
+}
+END_CASE(JSOP_NEWINIT)
+
+BEGIN_CASE(JSOP_NEWARRAY)
+{
+    unsigned count = GET_UINT24(regs.pc);
+    RootedObject &obj = rootObject0;
+    obj = NewDenseAllocatedArray(cx, count);
+    if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
+        goto error;
+
+    PUSH_OBJECT(*obj);
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
+}
+END_CASE(JSOP_NEWARRAY)
+
+BEGIN_CASE(JSOP_NEWOBJECT)
+{
+    RootedObject &baseobj = rootObject0;
+    baseobj = script->getObject(regs.pc);
+
+    RootedObject &obj = rootObject1;
+    obj = CopyInitializerObject(cx, baseobj);
+    if (!obj || !SetInitializerObjectType(cx, script, regs.pc, obj))
+        goto error;
+
+    PUSH_OBJECT(*obj);
+    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
+}
+END_CASE(JSOP_NEWOBJECT)
+
+BEGIN_CASE(JSOP_ENDINIT)
+{
+    /* FIXME remove JSOP_ENDINIT bug 588522 */
+    JS_ASSERT(regs.stackDepth() >= 1);
+    JS_ASSERT(regs.sp[-1].isObject());
+}
+END_CASE(JSOP_ENDINIT)
+
+BEGIN_CASE(JSOP_INITPROP)
+{
+    /* Load the property's initial value into rval. */
+    JS_ASSERT(regs.stackDepth() >= 2);
+    RootedValue &rval = rootValue0;
+    rval = regs.sp[-1];
+
+    /* Load the object being initialized into lval/obj. */
+    RootedObject &obj = rootObject0;
+    obj = &regs.sp[-2].toObject();
+    JS_ASSERT(obj->isObject());
+
+    PropertyName *name = script->getName(regs.pc);
+
+    RootedId &id = rootId0;
+    id = NameToId(name);
+
+    if (JS_UNLIKELY(name == cx->names().proto)
+        ? !baseops::SetPropertyHelper(cx, obj, obj, id, 0, &rval, script->strictModeCode)
+        : !DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
+                                JSPROP_ENUMERATE, 0, 0, 0)) {
+        goto error;
+    }
+
+    regs.sp--;
+}
+END_CASE(JSOP_INITPROP);
+
+BEGIN_CASE(JSOP_INITELEM_INC)
+BEGIN_CASE(JSOP_INITELEM)
+{
+    /* Pop the element's value into rval. */
+    JS_ASSERT(regs.stackDepth() >= 3);
+    HandleValue rref = HandleValue::fromMarkedLocation(&regs.sp[-1]);
+
+    RootedObject &obj = rootObject0;
+
+    /* Find the object being initialized at top of stack. */
+    const Value &lref = regs.sp[-3];
+    JS_ASSERT(lref.isObject());
+    obj = &lref.toObject();
+
+    /* Fetch id now that we have obj. */
+    RootedId &id = rootId0;
+    FETCH_ELEMENT_ID(obj, -2, id);
+
+    /*
+     * If rref is a hole, do not call JSObject::defineProperty. In this case,
+     * obj must be an array, so if the current op is the last element
+     * initialiser, set the array length to one greater than id.
+     */
+    if (rref.isMagic(JS_ARRAY_HOLE)) {
+        JS_ASSERT(obj->isArray());
+        JS_ASSERT(JSID_IS_INT(id));
+        JS_ASSERT(uint32_t(JSID_TO_INT(id)) < StackSpace::ARGS_LENGTH_MAX);
+        JSOp next = JSOp(*(regs.pc + GetBytecodeLength(regs.pc)));
+        if ((next == JSOP_ENDINIT && op == JSOP_INITELEM) ||
+            (next == JSOP_POP && op == JSOP_INITELEM_INC))
+        {
+            if (!SetLengthProperty(cx, obj, (uint32_t) (JSID_TO_INT(id) + 1)))
+                goto error;
+        }
+    } else {
+        if (!JSObject::defineGeneric(cx, obj, id, rref, NULL, NULL, JSPROP_ENUMERATE))
+            goto error;
+    }
+    if (op == JSOP_INITELEM_INC) {
+        JS_ASSERT(obj->isArray());
+        if (JSID_TO_INT(id) == INT32_MAX) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                 JSMSG_SPREAD_TOO_LARGE);
+            goto error;
+        }
+        regs.sp[-2].setInt32(JSID_TO_INT(id) + 1);
+        regs.sp--;
+    } else {
+        regs.sp -= 2;
+    }
+}
+END_CASE(JSOP_INITELEM)
+
+BEGIN_CASE(JSOP_SPREAD)
+{
+    int32_t count = regs.sp[-2].toInt32();
+    RootedObject arr(cx, &regs.sp[-3].toObject());
+    const Value iterable = regs.sp[-1];
+    ForOfIterator iter(cx, iterable);
+    RootedValue &iterVal = rootValue0;
+    while (iter.next()) {
+        if (count == INT32_MAX) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                 JSMSG_SPREAD_TOO_LARGE);
+            goto error;
+        }
+        iterVal = iter.value();
+        if (!JSObject::defineElement(cx, arr, count++, iterVal, NULL, NULL, JSPROP_ENUMERATE))
+            goto error;
+    }
+    if (!iter.close())
+        goto error;
+    regs.sp[-2].setInt32(count);
+    regs.sp--;
+}
+END_CASE(JSOP_SPREAD)
+
+{
+BEGIN_CASE(JSOP_GOSUB)
+    PUSH_BOOLEAN(false);
+    int32_t i = (regs.pc - script->code) + JSOP_GOSUB_LENGTH;
+    len = GET_JUMP_OFFSET(regs.pc);
+    PUSH_INT32(i);
+END_VARLEN_CASE
+}
+
+{
+BEGIN_CASE(JSOP_RETSUB)
+    /* Pop [exception or hole, retsub pc-index]. */
+    Value rval, lval;
+    POP_COPY_TO(rval);
+    POP_COPY_TO(lval);
+    JS_ASSERT(lval.isBoolean());
+    if (lval.toBoolean()) {
+        /*
+         * Exception was pending during finally, throw it *before* we adjust
+         * pc, because pc indexes into script->trynotes.  This turns out not to
+         * be necessary, but it seems clearer.  And it points out a FIXME:
+         * 350509, due to Igor Bukanov.
+         */
+        cx->setPendingException(rval);
+        goto error;
+    }
+    JS_ASSERT(rval.isInt32());
+
+    /* Increment the PC by this much. */
+    len = rval.toInt32() - int32_t(regs.pc - script->code);
+END_VARLEN_CASE
+}
+
+BEGIN_CASE(JSOP_EXCEPTION)
+    PUSH_COPY(cx->getPendingException());
+    cx->clearPendingException();
+    CHECK_BRANCH();
+END_CASE(JSOP_EXCEPTION)
+
+BEGIN_CASE(JSOP_FINALLY)
+    CHECK_BRANCH();
+END_CASE(JSOP_FINALLY)
+
+BEGIN_CASE(JSOP_THROWING)
+{
+    JS_ASSERT(!cx->isExceptionPending());
+    Value v;
+    POP_COPY_TO(v);
+    cx->setPendingException(v);
+}
+END_CASE(JSOP_THROWING)
+
+BEGIN_CASE(JSOP_THROW)
+{
+    CHECK_BRANCH();
+    RootedValue &v = rootValue0;
+    POP_COPY_TO(v);
+    JS_ALWAYS_FALSE(Throw(cx, v));
+    /* let the code at error try to catch the exception. */
+    goto error;
+}
+
+BEGIN_CASE(JSOP_INSTANCEOF)
+{
+    RootedValue &rref = rootValue0;
+    rref = regs.sp[-1];
+    if (rref.isPrimitive()) {
+        js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, -1, rref, NullPtr());
+        goto error;
+    }
+    RootedObject &obj = rootObject0;
+    obj = &rref.toObject();
+    JSBool cond = JS_FALSE;
+    if (!HasInstance(cx, obj, HandleValue::fromMarkedLocation(&regs.sp[-2]), &cond))
+        goto error;
+    regs.sp--;
+    regs.sp[-1].setBoolean(cond);
+}
+END_CASE(JSOP_INSTANCEOF)
+
+BEGIN_CASE(JSOP_DEBUGGER)
+{
+    JSTrapStatus st = JSTRAP_CONTINUE;
+    Value rval;
+    if (JSDebuggerHandler handler = cx->runtime->debugHooks.debuggerHandler)
+        st = handler(cx, script, regs.pc, &rval, cx->runtime->debugHooks.debuggerHandlerData);
+    if (st == JSTRAP_CONTINUE)
+        st = Debugger::onDebuggerStatement(cx, &rval);
+    switch (st) {
+      case JSTRAP_ERROR:
+        goto error;
+      case JSTRAP_CONTINUE:
+        break;
+      case JSTRAP_RETURN:
+        regs.fp()->setReturnValue(rval);
+        interpReturnOK = true;
+        goto forced_return;
+      case JSTRAP_THROW:
+        cx->setPendingException(rval);
+        goto error;
+      default:;
+    }
+}
+END_CASE(JSOP_DEBUGGER)
+
+#if JS_HAS_XML_SUPPORT
+BEGIN_CASE(JSOP_DEFXMLNS)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    if (!js_SetDefaultXMLNamespace(cx, regs.sp[-1]))
+        goto error;
+    regs.sp--;
+}
+END_CASE(JSOP_DEFXMLNS)
+
+BEGIN_CASE(JSOP_ANYNAME)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    cx->runtime->gcExactScanningEnabled = false;
+
+    jsid id;
+    if (!js_GetAnyName(cx, &id))
+        goto error;
+    PUSH_COPY(IdToValue(id));
+}
+END_CASE(JSOP_ANYNAME)
+#endif
+
+BEGIN_CASE(JSOP_QNAMEPART)
+    /*
+     * We do not JS_ASSERT(!script->strictModeCode) here because JSOP_QNAMEPART
+     * is used for __proto__ and (in contexts where we favor JSOP_*ELEM instead
+     * of JSOP_*PROP) obj.prop compiled as obj['prop'].
+     */
+    PUSH_STRING(script->getAtom(regs.pc));
+END_CASE(JSOP_QNAMEPART)
+
+#if JS_HAS_XML_SUPPORT
+BEGIN_CASE(JSOP_QNAMECONST)
+{
+    JS_ASSERT(!script->strictModeCode);
+    Value rval = StringValue(script->getAtom(regs.pc));
+    Value lval = regs.sp[-1];
+    JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval);
+    if (!obj)
+        goto error;
+    regs.sp[-1].setObject(*obj);
+}
+END_CASE(JSOP_QNAMECONST)
+
+BEGIN_CASE(JSOP_QNAME)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value rval = regs.sp[-1];
+    Value lval = regs.sp[-2];
+    JSObject *obj = js_ConstructXMLQNameObject(cx, lval, rval);
+    if (!obj)
+        goto error;
+    regs.sp--;
+    regs.sp[-1].setObject(*obj);
+}
+END_CASE(JSOP_QNAME)
+
+BEGIN_CASE(JSOP_TOATTRNAME)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value rval;
+    rval = regs.sp[-1];
+    if (!js_ToAttributeName(cx, &rval))
+        goto error;
+    regs.sp[-1] = rval;
+}
+END_CASE(JSOP_TOATTRNAME)
+
+BEGIN_CASE(JSOP_TOATTRVAL)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value rval;
+    rval = regs.sp[-1];
+    JS_ASSERT(rval.isString());
+    JSString *str = js_EscapeAttributeValue(cx, rval.toString(), JS_FALSE);
+    if (!str)
+        goto error;
+    regs.sp[-1].setString(str);
+}
+END_CASE(JSOP_TOATTRVAL)
+
+BEGIN_CASE(JSOP_ADDATTRNAME)
+BEGIN_CASE(JSOP_ADDATTRVAL)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value rval = regs.sp[-1];
+    Value lval = regs.sp[-2];
+    JSString *str = lval.toString();
+    JSString *str2 = rval.toString();
+    str = js_AddAttributePart(cx, op == JSOP_ADDATTRNAME, str, str2);
+    if (!str)
+        goto error;
+    regs.sp--;
+    regs.sp[-1].setString(str);
+}
+END_CASE(JSOP_ADDATTRNAME)
+
+BEGIN_CASE(JSOP_BINDXMLNAME)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value lval;
+    lval = regs.sp[-1];
+    RootedObject &obj = rootObject0;
+    jsid id;
+    if (!js_FindXMLProperty(cx, lval, &obj, &id))
+        goto error;
+    regs.sp[-1].setObjectOrNull(obj);
+    PUSH_COPY(IdToValue(id));
+}
+END_CASE(JSOP_BINDXMLNAME)
+
+BEGIN_CASE(JSOP_SETXMLNAME)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Rooted<JSObject*> obj(cx, &regs.sp[-3].toObject());
+    RootedValue &rval = rootValue0;
+    rval = regs.sp[-1];
+    RootedId &id = rootId0;
+    FETCH_ELEMENT_ID(obj, -2, id);
+    if (!JSObject::setGeneric(cx, obj, obj, id, &rval, script->strictModeCode))
+        goto error;
+    rval = regs.sp[-1];
+    regs.sp -= 2;
+    regs.sp[-1] = rval;
+}
+END_CASE(JSOP_SETXMLNAME)
+
+BEGIN_CASE(JSOP_CALLXMLNAME)
+BEGIN_CASE(JSOP_XMLNAME)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value lval = regs.sp[-1];
+    RootedObject &obj = rootObject0;
+    RootedId &id = rootId0;
+    if (!js_FindXMLProperty(cx, lval, &obj, id.address()))
+        goto error;
+    RootedValue &rval = rootValue0;
+    if (!JSObject::getGeneric(cx, obj, obj, id, &rval))
+        goto error;
+    regs.sp[-1] = rval;
+    if (op == JSOP_CALLXMLNAME) {
+        Value v;
+        if (!ComputeImplicitThis(cx, obj, &v))
+            goto error;
+        PUSH_COPY(v);
+    }
+}
+END_CASE(JSOP_XMLNAME)
+
+BEGIN_CASE(JSOP_DESCENDANTS)
+BEGIN_CASE(JSOP_DELDESC)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    JSObject *obj;
+    FETCH_OBJECT(cx, -2, obj);
+    jsval rval = regs.sp[-1];
+    if (!js_GetXMLDescendants(cx, obj, rval, &rval))
+        goto error;
+
+    if (op == JSOP_DELDESC) {
+        regs.sp[-1] = rval;   /* set local root */
+        if (!js_DeleteXMLListElements(cx, JSVAL_TO_OBJECT(rval)))
+            goto error;
+        rval = JSVAL_TRUE;                  /* always succeed */
+    }
+
+    regs.sp--;
+    regs.sp[-1] = rval;
+}
+END_CASE(JSOP_DESCENDANTS)
+
+BEGIN_CASE(JSOP_FILTER)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    /*
+     * We push the hole value before jumping to [enditer] so we can detect the
+     * first iteration and direct js_StepXMLListFilter to initialize filter's
+     * state.
+     */
+    PUSH_HOLE();
+    len = GET_JUMP_OFFSET(regs.pc);
+    JS_ASSERT(len > 0);
+}
+END_VARLEN_CASE
+
+BEGIN_CASE(JSOP_ENDFILTER)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    bool cond = !regs.sp[-1].isMagic();
+    if (cond) {
+        /* Exit the "with" block left from the previous iteration. */
+        regs.fp()->popWith(cx);
+    }
+    if (!js_StepXMLListFilter(cx, cond))
+        goto error;
+    if (!regs.sp[-1].isNull()) {
+        /*
+         * Decrease sp after EnterWith returns as we use sp[-1] there to root
+         * temporaries.
+         */
+        JS_ASSERT(IsXML(regs.sp[-1]));
+        if (!EnterWith(cx, -2))
+            goto error;
+        regs.sp--;
+        len = GET_JUMP_OFFSET(regs.pc);
+        JS_ASSERT(len < 0);
+        BRANCH(len);
+    }
+    regs.sp--;
+}
+END_CASE(JSOP_ENDFILTER);
+
+BEGIN_CASE(JSOP_TOXML)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    cx->runtime->gcExactScanningEnabled = false;
+
+    Value rval = regs.sp[-1];
+    JSObject *obj = js_ValueToXMLObject(cx, rval);
+    if (!obj)
+        goto error;
+    regs.sp[-1].setObject(*obj);
+}
+END_CASE(JSOP_TOXML)
+
+BEGIN_CASE(JSOP_TOXMLLIST)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value rval = regs.sp[-1];
+    JSObject *obj = js_ValueToXMLListObject(cx, rval);
+    if (!obj)
+        goto error;
+    regs.sp[-1].setObject(*obj);
+}
+END_CASE(JSOP_TOXMLLIST)
+
+BEGIN_CASE(JSOP_XMLTAGEXPR)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value rval = regs.sp[-1];
+    JSString *str = ToString(cx, rval);
+    if (!str)
+        goto error;
+    regs.sp[-1].setString(str);
+}
+END_CASE(JSOP_XMLTAGEXPR)
+
+BEGIN_CASE(JSOP_XMLELTEXPR)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value rval = regs.sp[-1];
+    JSString *str;
+    if (IsXML(rval)) {
+        str = js_ValueToXMLString(cx, rval);
+    } else {
+        str = ToString(cx, rval);
+        if (str)
+            str = js_EscapeElementValue(cx, str);
+    }
+    if (!str)
+        goto error;
+    regs.sp[-1].setString(str);
+}
+END_CASE(JSOP_XMLELTEXPR)
+
+BEGIN_CASE(JSOP_XMLCDATA)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    JSAtom *atom = script->getAtom(regs.pc);
+    JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_TEXT, NULL, atom);
+    if (!obj)
+        goto error;
+    PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_XMLCDATA)
+
+BEGIN_CASE(JSOP_XMLCOMMENT)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    JSAtom *atom = script->getAtom(regs.pc);
+    JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_COMMENT, NULL, atom);
+    if (!obj)
+        goto error;
+    PUSH_OBJECT(*obj);
+}
+END_CASE(JSOP_XMLCOMMENT)
+
+BEGIN_CASE(JSOP_XMLPI)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    JSAtom *atom = script->getAtom(regs.pc);
+    Value rval = regs.sp[-1];
+    JSString *str2 = rval.toString();
+    JSObject *obj = js_NewXMLSpecialObject(cx, JSXML_CLASS_PROCESSING_INSTRUCTION, atom, str2);
+    if (!obj)
+        goto error;
+    regs.sp[-1].setObject(*obj);
+}
+END_CASE(JSOP_XMLPI)
+
+BEGIN_CASE(JSOP_GETFUNNS)
+{
+    JS_ASSERT(!script->strictModeCode);
+
+    Value rval;
+    if (!cx->fp()->global().getFunctionNamespace(cx, &rval))
+        goto error;
+    PUSH_COPY(rval);
+}
+END_CASE(JSOP_GETFUNNS)
+#endif /* JS_HAS_XML_SUPPORT */
+
+BEGIN_CASE(JSOP_ENTERBLOCK)
+BEGIN_CASE(JSOP_ENTERLET0)
+BEGIN_CASE(JSOP_ENTERLET1)
+{
+    StaticBlockObject &blockObj = script->getObject(regs.pc)->asStaticBlock();
+
+    if (op == JSOP_ENTERBLOCK) {
+        JS_ASSERT(regs.stackDepth() == blockObj.stackDepth());
+        JS_ASSERT(regs.stackDepth() + blockObj.slotCount() <= script->nslots);
+        Value *vp = regs.sp + blockObj.slotCount();
+        SetValueRangeToUndefined(regs.sp, vp);
+        regs.sp = vp;
+    }
+
+    /* Clone block iff there are any closed-over variables. */
+    if (!regs.fp()->pushBlock(cx, blockObj))
+        goto error;
+}
+END_CASE(JSOP_ENTERBLOCK)
+
+BEGIN_CASE(JSOP_LEAVEBLOCK)
+BEGIN_CASE(JSOP_LEAVEFORLETIN)
+BEGIN_CASE(JSOP_LEAVEBLOCKEXPR)
+{
+    blockDepth = regs.fp()->blockChain().stackDepth();
+
+    regs.fp()->popBlock(cx);
+
+    if (op == JSOP_LEAVEBLOCK) {
+        /* Pop the block's slots. */
+        regs.sp -= GET_UINT16(regs.pc);
+        JS_ASSERT(regs.stackDepth() == blockDepth);
+    } else if (op == JSOP_LEAVEBLOCKEXPR) {
+        /* Pop the block's slots maintaining the topmost expr. */
+        Value *vp = &regs.sp[-1];
+        regs.sp -= GET_UINT16(regs.pc);
+        JS_ASSERT(regs.stackDepth() == blockDepth + 1);
+        regs.sp[-1] = *vp;
+    } else {
+        /* Another op will pop; nothing to do here. */
+        len = JSOP_LEAVEFORLETIN_LENGTH;
+        DO_NEXT_OP(len);
+    }
+}
+END_CASE(JSOP_LEAVEBLOCK)
+
+#if JS_HAS_GENERATORS
+BEGIN_CASE(JSOP_GENERATOR)
+{
+    JS_ASSERT(!cx->isExceptionPending());
+    regs.fp()->initGeneratorFrame();
+    regs.pc += JSOP_GENERATOR_LENGTH;
+    JSObject *obj = js_NewGenerator(cx);
+    if (!obj)
+        goto error;
+    regs.fp()->setReturnValue(ObjectValue(*obj));
+    regs.fp()->setYielding();
+    interpReturnOK = true;
+    if (entryFrame != regs.fp())
+        goto inline_return;
+    goto exit;
+}
+
+BEGIN_CASE(JSOP_YIELD)
+    JS_ASSERT(!cx->isExceptionPending());
+    JS_ASSERT(regs.fp()->isNonEvalFunctionFrame());
+    if (cx->innermostGenerator()->state == JSGEN_CLOSING) {
+        RootedValue &val = rootValue0;
+        val.setObject(regs.fp()->callee());
+        js_ReportValueError(cx, JSMSG_BAD_GENERATOR_YIELD, JSDVG_SEARCH_STACK, val, NullPtr());
+        goto error;
+    }
+    regs.fp()->setReturnValue(regs.sp[-1]);
+    regs.fp()->setYielding();
+    regs.pc += JSOP_YIELD_LENGTH;
+    interpReturnOK = true;
+    goto exit;
+
+BEGIN_CASE(JSOP_ARRAYPUSH)
+{
+    uint32_t slot = GET_UINT16(regs.pc);
+    JS_ASSERT(script->nfixed <= slot);
+    JS_ASSERT(slot < script->nslots);
+    RootedObject &obj = rootObject0;
+    obj = &regs.fp()->unaliasedLocal(slot).toObject();
+    if (!js_NewbornArrayPush(cx, obj, regs.sp[-1]))
+        goto error;
+    regs.sp--;
+}
+END_CASE(JSOP_ARRAYPUSH)
+#endif /* JS_HAS_GENERATORS */
+
+          default:
+          {
+            char numBuf[12];
+            JS_snprintf(numBuf, sizeof numBuf, "%d", op);
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                                 JSMSG_BAD_BYTECODE, numBuf);
+            goto error;
+          }
+
+        } /* switch (op) */
+    } /* for (;;) */
+
+  error:
+    JS_ASSERT(&cx->regs() == &regs);
+    JS_ASSERT(uint32_t(regs.pc - script->code) < script->length);
+
+    /* When rejoining, we must not err before finishing Interpret's prologue. */
+    JS_ASSERT(interpMode != JSINTERP_REJOIN);
+
+    if (cx->isExceptionPending()) {
+        /* Call debugger throw hook if set. */
+        if (cx->runtime->debugHooks.throwHook || !cx->compartment->getDebuggees().empty()) {
+            Value rval;
+            JSTrapStatus st = Debugger::onExceptionUnwind(cx, &rval);
+            if (st == JSTRAP_CONTINUE) {
+                if (JSThrowHook handler = cx->runtime->debugHooks.throwHook)
+                    st = handler(cx, script, regs.pc, &rval, cx->runtime->debugHooks.throwHookData);
+            }
+
+            switch (st) {
+              case JSTRAP_ERROR:
+                cx->clearPendingException();
+                goto error;
+              case JSTRAP_RETURN:
+                cx->clearPendingException();
+                regs.fp()->setReturnValue(rval);
+                interpReturnOK = true;
+                goto forced_return;
+              case JSTRAP_THROW:
+                cx->setPendingException(rval);
+              case JSTRAP_CONTINUE:
+              default:;
+            }
+        }
+
+        for (TryNoteIter tni(regs); !tni.done(); ++tni) {
+            JSTryNote *tn = *tni;
+
+            UnwindScope(cx, tn->stackDepth);
+
+            /*
+             * Set pc to the first bytecode after the the try note to point
+             * to the beginning of catch or finally or to [enditer] closing
+             * the for-in loop.
+             */
+            regs.pc = (script)->main() + tn->start + tn->length;
+            regs.sp = regs.spForStackDepth(tn->stackDepth);
+
+            switch (tn->kind) {
+              case JSTRY_CATCH:
+                  JS_ASSERT(*regs.pc == JSOP_ENTERBLOCK);
+
+#if JS_HAS_GENERATORS
+                /* Catch cannot intercept the closing of a generator. */
+                  if (JS_UNLIKELY(cx->getPendingException().isMagic(JS_GENERATOR_CLOSING)))
+                    break;
+#endif
+
+                /*
+                 * Don't clear exceptions to save cx->exception from GC
+                 * until it is pushed to the stack via [exception] in the
+                 * catch block.
+                 */
+                len = 0;
+                DO_NEXT_OP(len);
+
+              case JSTRY_FINALLY:
+                /*
+                 * Push (true, exception) pair for finally to indicate that
+                 * [retsub] should rethrow the exception.
+                 */
+                PUSH_BOOLEAN(true);
+                PUSH_COPY(cx->getPendingException());
+                cx->clearPendingException();
+                len = 0;
+                DO_NEXT_OP(len);
+
+              case JSTRY_ITER: {
+                /* This is similar to JSOP_ENDITER in the interpreter loop. */
+                JS_ASSERT(JSOp(*regs.pc) == JSOP_ENDITER);
+                RootedObject &obj = rootObject0;
+                obj = &regs.sp[-1].toObject();
+                bool ok = UnwindIteratorForException(cx, obj);
+                regs.sp -= 1;
+                if (!ok)
+                    goto error;
+              }
+           }
+        }
+
+        /*
+         * Propagate the exception or error to the caller unless the exception
+         * is an asynchronous return from a generator.
+         */
+        interpReturnOK = false;
+#if JS_HAS_GENERATORS
+        if (JS_UNLIKELY(cx->isExceptionPending() &&
+                        cx->getPendingException().isMagic(JS_GENERATOR_CLOSING))) {
+            cx->clearPendingException();
+            interpReturnOK = true;
+            regs.fp()->clearReturnValue();
+        }
+#endif
+    } else {
+        UnwindForUncatchableException(cx, regs);
+        interpReturnOK = false;
+    }
+
+  forced_return:
+    UnwindScope(cx, 0);
+    regs.setToEndOfScript();
+
+    if (entryFrame != regs.fp())
+        goto inline_return;
+
+  exit:
+    if (cx->compartment->debugMode())
+        interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
+    if (!regs.fp()->isYielding())
+        regs.fp()->epilogue(cx);
+    else
+        Probes::exitScript(cx, script, script->function(), regs.fp());
+    regs.fp()->setFinishedInInterpreter();
+
+#ifdef JS_METHODJIT
+    /*
+     * This path is used when it's guaranteed the method can be finished
+     * inside the JIT.
+     */
+  leave_on_safe_point:
+#endif
+
+    gc::MaybeVerifyBarriers(cx, true);
+    return interpReturnOK ? Interpret_Ok : Interpret_Error;
+}
+
+bool
+js::Throw(JSContext *cx, HandleValue v)
+{
+    JS_ASSERT(!cx->isExceptionPending());
+    cx->setPendingException(v);
+    return false;
+}
+
+bool
+js::GetProperty(JSContext *cx, HandleValue v, HandlePropertyName name, MutableHandleValue vp)
+{
+    if (name == cx->names().length) {
+        // Fast path for strings, arrays and arguments.
+        if (GetLengthProperty(v, vp))
+            return true;
+    }
+
+    RootedObject obj(cx, ToObjectFromStack(cx, v));
+    if (!obj)
+        return false;
+    return JSObject::getProperty(cx, obj, obj, name, vp);
+}
+
+bool
+js::GetScopeName(JSContext *cx, HandleObject scopeChain, HandlePropertyName name, MutableHandleValue vp)
+{
+    RootedShape shape(cx);
+    RootedObject obj(cx), pobj(cx);
+    if (!LookupName(cx, name, scopeChain, &obj, &pobj, &shape))
+        return false;
+
+    if (!shape) {
+        JSAutoByteString printable;
+        if (js_AtomToPrintableString(cx, name, &printable))
+            js_ReportIsNotDefined(cx, printable.ptr());
+        return false;
+    }
+
+    return JSObject::getProperty(cx, obj, obj, name, vp);
+}
+
+/*
+ * Alternate form for NAME opcodes followed immediately by a TYPEOF,
+ * which do not report an exception on (typeof foo == "undefined") tests.
+ */
+bool
+js::GetScopeNameForTypeOf(JSContext *cx, HandleObject scopeChain, HandlePropertyName name,
+                          MutableHandleValue vp)
+{
+    RootedShape shape(cx);
+    RootedObject obj(cx), pobj(cx);
+    if (!LookupName(cx, name, scopeChain, &obj, &pobj, &shape))
+        return false;
+
+    if (!shape) {
+        vp.set(UndefinedValue());
+        return true;
+    }
+
+    return JSObject::getProperty(cx, obj, obj, name, vp);
+}
+
+JSObject *
+js::Lambda(JSContext *cx, HandleFunction fun, HandleObject parent)
+{
+    RootedObject clone(cx, CloneFunctionObjectIfNotSingleton(cx, fun, parent));
+    if (!clone)
+        return NULL;
+
+    JS_ASSERT(clone->global() == clone->global());
+    return clone;
+}
+
+template <bool strict>
+bool
+js::SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value)
+{
+    RootedValue v(cx, value);
+    return JSObject::setGeneric(cx, obj, obj, id, &v, strict);
+}
+
+template bool js::SetProperty<true> (JSContext *cx, HandleObject obj, HandleId id, const Value &value);
+template bool js::SetProperty<false>(JSContext *cx, HandleObject obj, HandleId id, const Value &value);
+
+template <bool strict>
+bool
+js::DeleteProperty(JSContext *cx, HandleValue v, HandlePropertyName name, JSBool *bp)
+{
+    // default op result is false (failure)
+    *bp = true;
+
+    // convert value to JSObject pointer
+    RootedObject obj(cx, ToObjectFromStack(cx, v));
+    if (!obj)
+        return false;
+
+    // Call deleteProperty on obj
+    RootedValue result(cx, NullValue());
+    bool delprop_ok = JSObject::deleteProperty(cx, obj, name, &result, strict);
+    if (!delprop_ok)
+        return false;
+
+    // convert result into *bp and return
+    *bp = result.toBoolean();
+    return true;
+}
+
+template bool js::DeleteProperty<true> (JSContext *cx, HandleValue val, HandlePropertyName name, JSBool *bp);
+template bool js::DeleteProperty<false>(JSContext *cx, HandleValue val, HandlePropertyName name, JSBool *bp);
+
+bool
+js::GetElement(JSContext *cx, HandleValue lref, HandleValue rref, MutableHandleValue vp)
+{
+    return GetElementOperation(cx, JSOP_GETELEM, lref, rref, vp);
+}
+
+bool
+js::GetElementMonitored(JSContext *cx, HandleValue lref, HandleValue rref,
+                        MutableHandleValue vp)
+{
+    if (!GetElement(cx, lref, rref, vp))
+        return false;
+
+    TypeScript::Monitor(cx, vp);
+    return true;
+}
+
+bool
+js::CallElement(JSContext *cx, HandleValue lref, HandleValue rref, MutableHandleValue res)
+{
+    return GetElementOperation(cx, JSOP_CALLELEM, lref, rref, res);
+}
+
+bool
+js::SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
+                     JSBool strict)
+{
+    RootedId id(cx);
+    RootedValue indexval(cx, index);
+    if (!FetchElementId(cx, obj, indexval, id.address(), &indexval))
+        return false;
+    return SetObjectElementOperation(cx, obj, id, value, strict);
+}
+
+bool
+js::AddValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+              Value *res)
+{
+    return AddOperation(cx, script, pc, lhs, rhs, res);
+}
+
+bool
+js::SubValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+              Value *res)
+{
+    return SubOperation(cx, script, pc, lhs, rhs, res);
+}
+
+bool
+js::MulValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+              Value *res)
+{
+    return MulOperation(cx, script, pc, lhs, rhs, res);
+}
+
+bool
+js::DivValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+              Value *res)
+{
+    return DivOperation(cx, script, pc, lhs, rhs, res);
+}
+
+bool
+js::ModValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+              Value *res)
+{
+    return ModOperation(cx, script, pc, lhs, rhs, res);
+}
+
+bool
+js::UrshValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+              Value *res)
+{
+    return UrshOperation(cx, script, pc, lhs, rhs, res);
+}
new file mode 100644
--- /dev/null
+++ b/js/src/jsinterp.h
@@ -0,0 +1,380 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=78:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jsinterp_h___
+#define jsinterp_h___
+/*
+ * JS interpreter interface.
+ */
+#include "jsprvtd.h"
+#include "jspubtd.h"
+#include "jsopcode.h"
+
+#include "vm/Stack.h"
+
+namespace js {
+
+/* Implemented in jsdbgapi: */
+
+/*
+ * Announce to the debugger that the thread has entered a new JavaScript frame,
+ * |fp|. Call whatever hooks have been registered to observe new frames, and
+ * return a JSTrapStatus code indication how execution should proceed:
+ *
+ * - JSTRAP_CONTINUE: Continue execution normally.
+ *
+ * - JSTRAP_THROW: Throw an exception. ScriptDebugPrologue has set |cx|'s
+ *   pending exception to the value to be thrown.
+ *
+ * - JSTRAP_ERROR: Terminate execution (as is done when a script is terminated
+ *   for running too long). ScriptDebugPrologue has cleared |cx|'s pending
+ *   exception.
+ *
+ * - JSTRAP_RETURN: Return from the new frame immediately. ScriptDebugPrologue
+ *   has set |cx->fp()|'s return value appropriately.
+ */
+extern JSTrapStatus
+ScriptDebugPrologue(JSContext *cx, StackFrame *fp);
+
+/*
+ * Announce to the debugger that the thread has exited a JavaScript frame, |fp|.
+ * If |ok| is true, the frame is returning normally; if |ok| is false, the frame
+ * is throwing an exception or terminating.
+ *
+ * Call whatever hooks have been registered to observe frame exits. Change cx's
+ * current exception and |fp|'s return value to reflect the changes in behavior
+ * the hooks request, if any. Return the new error/success value.
+ *
+ * This function may be called twice for the same outgoing frame; only the
+ * first call has any effect. (Permitting double calls simplifies some
+ * cases where an onPop handler's resumption value changes a return to a
+ * throw, or vice versa: we can redirect to a complete copy of the
+ * alternative path, containing its own call to ScriptDebugEpilogue.)
+ */
+extern bool
+ScriptDebugEpilogue(JSContext *cx, StackFrame *fp, bool ok);
+
+/*
+ * For a given |call|, convert null/undefined |this| into the global object for
+ * the callee and replace other primitives with boxed versions. This assumes
+ * that call.callee() is not strict mode code. This is the special/slow case of
+ * ComputeThis.
+ */
+extern bool
+BoxNonStrictThis(JSContext *cx, const CallReceiver &call);
+
+/*
+ * Ensure that fp->thisValue() is the correct value of |this| for the scripted
+ * call represented by |fp|. ComputeThis is necessary because fp->thisValue()
+ * may be set to 'undefined' when 'this' should really be the global object (as
+ * an optimization to avoid global-this computation).
+ */
+inline bool
+ComputeThis(JSContext *cx, StackFrame *fp);
+
+enum MaybeConstruct {
+    NO_CONSTRUCT = INITIAL_NONE,
+    CONSTRUCT = INITIAL_CONSTRUCT
+};
+
+extern bool
+ReportIsNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct = NO_CONSTRUCT);
+
+extern bool
+ReportIsNotFunction(JSContext *cx, const Value *vp, MaybeConstruct construct = NO_CONSTRUCT);
+
+extern JSObject *
+ValueToCallable(JSContext *cx, const Value *vp, MaybeConstruct construct = NO_CONSTRUCT);
+
+/*
+ * InvokeKernel assumes that the given args have been pushed on the top of the
+ * VM stack. Additionally, if 'args' is contained in a CallArgsList, that they
+ * have already been marked 'active'.
+ */
+extern bool
+InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct = NO_CONSTRUCT);
+
+/*
+ * Invoke assumes that 'args' has been pushed (via ContextStack::pushInvokeArgs)
+ * and is currently at the top of the VM stack.
+ */
+inline bool
+Invoke(JSContext *cx, InvokeArgsGuard &args, MaybeConstruct construct = NO_CONSTRUCT)
+{
+    args.setActive();
+    bool ok = InvokeKernel(cx, args, construct);
+    args.setInactive();
+    return ok;
+}
+
+/*
+ * This Invoke overload places the least requirements on the caller: it may be
+ * called at any time and it takes care of copying the given callee, this, and
+ * arguments onto the stack.
+ */
+extern bool
+Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, Value *argv,
+       Value *rval);
+
+/*
+ * This helper takes care of the infinite-recursion check necessary for
+ * getter/setter calls.
+ */
+extern bool
+InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, unsigned argc, Value *argv,
+                     Value *rval);
+
+/*
+ * InvokeConstructor* implement a function call from a constructor context
+ * (e.g. 'new') handling the the creation of the new 'this' object.
+ */
+extern bool
+InvokeConstructorKernel(JSContext *cx, CallArgs args);
+
+/* See the InvokeArgsGuard overload of Invoke. */
+inline bool
+InvokeConstructor(JSContext *cx, InvokeArgsGuard &args)
+{
+    args.setActive();
+    bool ok = InvokeConstructorKernel(cx, ImplicitCast<CallArgs>(args));
+    args.setInactive();
+    return ok;
+}
+
+/* See the fval overload of Invoke. */
+extern bool
+InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv, Value *rval);
+
+/*
+ * Executes a script with the given scopeChain/this. The 'type' indicates
+ * whether this is eval code or global code. To support debugging, the
+ * evalFrame parameter can point to an arbitrary frame in the context's call
+ * stack to simulate executing an eval in that frame.
+ */
+extern bool
+ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Value &thisv,
+              ExecuteType type, StackFrame *evalInFrame, Value *result);
+
+/* Execute a script with the given scopeChain as global code. */
+extern bool
+Execute(JSContext *cx, HandleScript script, JSObject &scopeChain, Value *rval);
+
+/* Flags to toggle js::Interpret() execution. */
+enum InterpMode
+{
+    JSINTERP_NORMAL    = 0, /* interpreter is running normally */
+    JSINTERP_REJOIN    = 1, /* as normal, but the frame has already started */
+    JSINTERP_SKIP_TRAP = 2, /* as REJOIN, but skip trap at first opcode */
+    JSINTERP_BAILOUT   = 3  /* interpreter is running from an Ion bailout */
+};
+
+enum InterpretStatus
+{
+    Interpret_Error    = 0, /* interpreter had an error */
+    Interpret_Ok       = 1, /* interpreter executed successfully */
+    Interpret_OSR      = 2  /* when mode=BAILOUT and we should OSR into Ion */
+};
+
+/*
+ * Execute the caller-initialized frame for a user-defined script or function
+ * pointed to by cx->fp until completion or error.
+ */
+extern JS_NEVER_INLINE InterpretStatus
+Interpret(JSContext *cx, StackFrame *stopFp, InterpMode mode = JSINTERP_NORMAL);
+
+extern bool
+RunScript(JSContext *cx, HandleScript script, StackFrame *fp);
+
+extern bool
+StrictlyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
+
+extern bool
+LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *equal);
+
+/* === except that NaN is the same as NaN and -0 is not the same as +0. */
+extern bool
+SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same);
+
+extern JSType
+TypeOfValue(JSContext *cx, const Value &v);
+
+extern bool
+HasInstance(JSContext *cx, HandleObject obj, HandleValue v, JSBool *bp);
+
+/*
+ * A linked list of the |FrameRegs regs;| variables belonging to all
+ * js::Interpret C++ frames on this thread's stack.
+ *
+ * Note that this is *not* a list of all JS frames running under the
+ * interpreter; that would include inlined frames, whose FrameRegs are
+ * saved in various pieces in various places. Rather, this lists each
+ * js::Interpret call's live 'regs'; when control returns to that call, it
+ * will resume execution with this 'regs' instance.
+ *
+ * When Debugger puts a script in single-step mode, all js::Interpret
+ * invocations that might be presently running that script must have
+ * interrupts enabled. It's not practical to simply check
+ * script->stepModeEnabled() at each point some callee could have changed
+ * it, because there are so many places js::Interpret could possibly cause
+ * JavaScript to run: each place an object might be coerced to a primitive
+ * or a number, for example. So instead, we simply expose a list of the
+ * 'regs' those frames are using, and let Debugger tweak the affected
+ * js::Interpret frames when an onStep handler is established.
+ *
+ * Elements of this list are allocated within the js::Interpret stack
+ * frames themselves; the list is headed by this thread's js::ThreadData.
+ */
+class InterpreterFrames {
+  public:
+    class InterruptEnablerBase {
+      public:
+        virtual void enable() const = 0;
+    };
+
+    InterpreterFrames(JSContext *cx, FrameRegs *regs, const InterruptEnablerBase &enabler);
+    ~InterpreterFrames();
+
+    /* If this js::Interpret frame is running |script|, enable interrupts. */
+    inline void enableInterruptsIfRunning(JSScript *script);
+    inline void enableInterruptsUnconditionally() { enabler.enable(); }
+
+    InterpreterFrames *older;
+
+  private:
+    JSContext *context;
+    FrameRegs *regs;
+    const InterruptEnablerBase &enabler;
+};
+
+/*
+ * Unwind block and scope chains to match the given depth. The function sets
+ * fp->sp on return to stackDepth.
+ */
+extern void
+UnwindScope(JSContext *cx, uint32_t stackDepth);
+
+/*
+ * Unwind for an uncatchable exception. This means not running finalizers, etc;
+ * just preserving the basic engine stack invariants.
+ */
+extern void
+UnwindForUncatchableException(JSContext *cx, const FrameRegs &regs);
+
+extern bool
+OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval, MutableHandleValue vp);
+
+class TryNoteIter
+{
+    const FrameRegs &regs;
+    JSScript *script;
+    uint32_t pcOffset;
+    JSTryNote *tn, *tnEnd;
+    void settle();
+  public:
+    TryNoteIter(const FrameRegs &regs);
+    bool done() const;
+    void operator++();
+    JSTryNote *operator*() const { return tn; }
+};
+
+/************************************************************************/
+
+/*
+ * To really poison a set of values, using 'magic' or 'undefined' isn't good
+ * enough since often these will just be ignored by buggy code (see bug 629974)
+ * in debug builds and crash in release builds. Instead, we use a safe-for-crash
+ * pointer.
+ */
+static JS_ALWAYS_INLINE void
+Debug_SetValueRangeToCrashOnTouch(Value *beg, Value *end)
+{
+#ifdef DEBUG
+    for (Value *v = beg; v != end; ++v)
+        v->setObject(*reinterpret_cast<JSObject *>(0x42));
+#endif
+}
+
+static JS_ALWAYS_INLINE void
+Debug_SetValueRangeToCrashOnTouch(Value *vec, size_t len)
+{
+#ifdef DEBUG
+    Debug_SetValueRangeToCrashOnTouch(vec, vec + len);
+#endif
+}
+
+static JS_ALWAYS_INLINE void
+Debug_SetValueRangeToCrashOnTouch(HeapValue *vec, size_t len)
+{
+#ifdef DEBUG
+    Debug_SetValueRangeToCrashOnTouch((Value *) vec, len);
+#endif
+}
+
+bool
+Throw(JSContext *cx, HandleValue v);
+
+bool
+GetProperty(JSContext *cx, HandleValue value, HandlePropertyName name, MutableHandleValue vp);
+
+bool
+GetScopeName(JSContext *cx, HandleObject obj, HandlePropertyName name, MutableHandleValue vp);
+
+bool
+GetScopeNameForTypeOf(JSContext *cx, HandleObject obj, HandlePropertyName name,
+                      MutableHandleValue vp);
+
+JSObject *
+Lambda(JSContext *cx, HandleFunction fun, HandleObject parent);
+
+bool
+GetElement(JSContext *cx, HandleValue lref, HandleValue rref, MutableHandleValue res);
+
+bool
+GetElementMonitored(JSContext *cx, HandleValue lref, HandleValue rref, MutableHandleValue res);
+
+bool
+CallElement(JSContext *cx, HandleValue lref, HandleValue rref, MutableHandleValue res);
+
+bool
+SetObjectElement(JSContext *cx, HandleObject obj, HandleValue index, HandleValue value,
+                 JSBool strict);
+
+bool
+AddValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+          Value *res);
+
+bool
+SubValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+          Value *res);
+
+bool
+MulValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+          Value *res);
+
+bool
+DivValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+          Value *res);
+
+bool
+ModValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+          Value *res);
+
+bool
+UrshValues(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+          Value *res);
+
+template <bool strict>
+bool
+SetProperty(JSContext *cx, HandleObject obj, HandleId id, const Value &value);
+
+template <bool strict>
+bool
+DeleteProperty(JSContext *ctx, HandleValue val, HandlePropertyName name, JSBool *bv);
+
+}  /* namespace js */
+
+#endif /* jsinterp_h___ */
new file mode 100644
--- /dev/null
+++ b/js/src/jsinterpinlines.h
@@ -0,0 +1,1069 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=99:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jsinterpinlines_h__
+#define jsinterpinlines_h__
+
+#include "jsapi.h"
+#include "jsbool.h"
+#include "jscompartment.h"
+#include "jsinfer.h"
+#include "jsinterp.h"
+#include "jslibmath.h"
+#include "jsnum.h"
+#include "jsprobes.h"
+#include "jsstr.h"
+#include "methodjit/MethodJIT.h"
+
+#include "jsatominlines.h"
+#include "jsfuninlines.h"
+#include "jsinferinlines.h"
+#include "jsopcodeinlines.h"
+#include "jspropertycacheinlines.h"
+#include "jstypedarrayinlines.h"
+
+#include "ion/Ion.h"
+#include "ion/IonCompartment.h"
+
+#include "vm/Stack-inl.h"
+
+namespace js {
+
+/*
+ * Compute the implicit |this| parameter for a call expression where the callee
+ * funval was resolved from an unqualified name reference to a property on obj
+ * (an object on the scope chain).
+ *
+ * We can avoid computing |this| eagerly and push the implicit callee-coerced
+ * |this| value, undefined, if any of these conditions hold:
+ *
+ * 1. The nominal |this|, obj, is a global object.
+ *
+ * 2. The nominal |this|, obj, has one of Block, Call, or DeclEnv class (this
+ *    is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be
+ *    censored with undefined.
+ *
+ * Otherwise, we bind |this| to obj->thisObject(). Only names inside |with|
+ * statements and embedding-specific scope objects fall into this category.
+ *
+ * If the callee is a strict mode function, then code implementing JSOP_THIS
+ * in the interpreter and JITs will leave undefined as |this|. If funval is a
+ * function not in strict mode, JSOP_THIS code replaces undefined with funval's
+ * global.
+ *
+ * We set *vp to undefined early to reduce code size and bias this code for the
+ * common and future-friendly cases.
+ */
+inline bool
+ComputeImplicitThis(JSContext *cx, HandleObject obj, Value *vp)
+{
+    vp->setUndefined();
+
+    if (obj->isGlobal())
+        return true;
+
+    if (IsCacheableNonGlobalScope(obj))
+        return true;
+
+    RawObject nobj = JSObject::thisObject(cx, obj);
+    if (!nobj)
+        return false;
+
+    vp->setObject(*nobj);
+    return true;
+}
+
+inline bool
+ComputeThis(JSContext *cx, StackFrame *fp)
+{
+    JS_ASSERT(!fp->runningInIon());
+    Value &thisv = fp->thisValue();
+    if (thisv.isObject())
+        return true;
+    if (fp->isFunctionFrame()) {
+        if (fp->fun()->inStrictMode() || fp->fun()->isSelfHostedBuiltin())
+            return true;
+        /*
+         * Eval function frames have their own |this| slot, which is a copy of the function's
+         * |this| slot. If we lazily wrap a primitive |this| in an eval function frame, the
+         * eval's frame will get the wrapper, but the function's frame will not. To prevent
+         * this, we always wrap a function's |this| before pushing an eval frame, and should
+         * thus never see an unwrapped primitive in a non-strict eval function frame.
+         */
+        JS_ASSERT(!fp->isEvalFrame());
+    }
+    return BoxNonStrictThis(cx, fp->callReceiver());
+}
+
+/*
+ * Every possible consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) (as determined
+ * by ScriptAnalysis::needsArgsObj) must check for these magic values and, when
+ * one is received, act as if the value were the function's ArgumentsObject.
+ * Additionally, it is possible that, after 'arguments' was copied into a
+ * temporary, the arguments object has been created a some other failed guard
+ * that called JSScript::argumentsOptimizationFailed. In this case, it is
+ * always valid (and necessary) to replace JS_OPTIMIZED_ARGUMENTS with the real
+ * arguments object.
+ */
+static inline bool
+IsOptimizedArguments(StackFrame *fp, Value *vp)
+{
+    AutoAssertNoGC nogc;
+    if (vp->isMagic(JS_OPTIMIZED_ARGUMENTS) && fp->script()->needsArgsObj())
+        *vp = ObjectValue(fp->argsObj());
+    return vp->isMagic(JS_OPTIMIZED_ARGUMENTS);
+}
+
+/*
+ * One optimized consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) is f.apply.
+ * However, this speculation must be guarded before calling 'apply' in case it
+ * is not the builtin Function.prototype.apply.
+ */
+static inline bool
+GuardFunApplyArgumentsOptimization(JSContext *cx)
+{
+    AssertCanGC();
+    FrameRegs &regs = cx->regs();
+    if (IsOptimizedArguments(regs.fp(), &regs.sp[-1])) {
+        CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
+        if (!IsNativeFunction(args.calleev(), js_fun_apply)) {
+            RootedScript script(cx, regs.fp()->script());
+            if (!JSScript::argumentsOptimizationFailed(cx, script))
+                return false;
+            regs.sp[-1] = ObjectValue(regs.fp()->argsObj());
+        }
+    }
+    return true;
+}
+
+/*
+ * Return an object on which we should look for the properties of |value|.
+ * This helps us implement the custom [[Get]] method that ES5's GetValue
+ * algorithm uses for primitive values, without actually constructing the
+ * temporary object that the specification does.
+ *
+ * For objects, return the object itself. For string, boolean, and number
+ * primitive values, return the appropriate constructor's prototype. For
+ * undefined and null, throw an error and return NULL, attributing the
+ * problem to the value at |spindex| on the stack.
+ */
+JS_ALWAYS_INLINE JSObject *
+ValuePropertyBearer(JSContext *cx, StackFrame *fp, HandleValue v, int spindex)
+{
+    if (v.isObject())
+        return &v.toObject();
+
+    GlobalObject &global = fp->global();
+
+    if (v.isString())
+        return global.getOrCreateStringPrototype(cx);
+    if (v.isNumber())
+        return global.getOrCreateNumberPrototype(cx);
+    if (v.isBoolean())
+        return global.getOrCreateBooleanPrototype(cx);
+
+    JS_ASSERT(v.isNull() || v.isUndefined());
+    js_ReportIsNullOrUndefined(cx, spindex, v, NullPtr());
+    return NULL;
+}
+
+inline bool
+NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Shape *shape,
+          unsigned getHow, MutableHandleValue vp)
+{
+    if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
+        /* Fast path for Object instance properties. */
+        JS_ASSERT(shape->hasSlot());
+        vp.set(pobj->nativeGetSlot(shape->slot()));
+    } else {
+        if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp.address()))
+            return false;
+    }
+    return true;
+}
+
+#if defined(DEBUG) && !defined(JS_THREADSAFE) && !defined(JSGC_ROOT_ANALYSIS)
+extern void
+AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
+                            PropertyCacheEntry *entry);
+#else
+inline void
+AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
+                            PropertyCacheEntry *entry)
+{}
+#endif
+
+inline bool
+GetPropertyGenericMaybeCallXML(JSContext *cx, JSOp op, HandleObject obj, HandleId id, MutableHandleValue vp)
+{
+    /*
+     * Various XML properties behave differently when accessed in a
+     * call vs. normal context, and getGeneric will not work right.
+     */
+#if JS_HAS_XML_SUPPORT
+    if (op == JSOP_CALLPROP && obj->isXML())
+        return js_GetXMLMethod(cx, obj, id, vp);
+#endif
+
+    return JSObject::getGeneric(cx, obj, obj, id, vp);
+}
+
+inline bool
+GetLengthProperty(const Value &lval, MutableHandleValue vp)
+{
+    /* Optimize length accesses on strings, arrays, and arguments. */
+    if (lval.isString()) {
+        vp.setInt32(lval.toString()->length());
+        return true;
+    }
+    if (lval.isObject()) {
+        JSObject *obj = &lval.toObject();
+        if (obj->isArray()) {
+            uint32_t length = obj->getArrayLength();
+            vp.setNumber(length);
+            return true;
+        }
+
+        if (obj->isArguments()) {
+            ArgumentsObject *argsobj = &obj->asArguments();
+            if (!argsobj->hasOverriddenLength()) {
+                uint32_t length = argsobj->initialLength();
+                JS_ASSERT(length < INT32_MAX);
+                vp.setInt32(int32_t(length));
+                return true;
+            }
+        }
+
+        if (obj->isTypedArray()) {
+            vp.setInt32(TypedArray::length(obj));
+            return true;
+        }
+    }
+
+    return false;
+}
+
+inline bool
+GetPropertyOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue lval,
+                     MutableHandleValue vp)
+{
+    JSOp op = JSOp(*pc);
+
+    if (op == JSOP_LENGTH) {
+        if (IsOptimizedArguments(cx->fp(), lval.address())) {
+            vp.setInt32(cx->fp()->numActualArgs());
+            return true;
+        }
+
+        if (GetLengthProperty(lval, vp))
+            return true;
+    }
+
+    RootedObject obj(cx, ToObjectFromStack(cx, lval));
+    if (!obj)
+        return false;
+
+    PropertyCacheEntry *entry;
+    Rooted<JSObject*> obj2(cx);
+    PropertyName *name;
+    cx->propertyCache().test(cx, pc, obj.get(), obj2.get(), entry, name);
+    if (!name) {
+        AssertValidPropertyCacheHit(cx, obj, obj2, entry);
+        if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp))
+            return false;
+        return true;
+    }
+
+    RootedId id(cx, NameToId(name));
+
+    if (obj->getOps()->getProperty) {
+        if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
+            return false;
+    } else {
+        if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp))
+            return false;
+    }
+
+#if JS_HAS_NO_SUCH_METHOD
+    if (op == JSOP_CALLPROP &&
+        JS_UNLIKELY(vp.isPrimitive()) &&
+        lval.isObject())
+    {
+        if (!OnUnknownMethod(cx, obj, IdToValue(id), vp))
+            return false;
+    }
+#endif
+
+    return true;
+}
+
+inline bool
+SetPropertyOperation(JSContext *cx, jsbytecode *pc, HandleValue lval, HandleValue rval)
+{
+    JS_ASSERT(*pc == JSOP_SETPROP);
+
+    RootedObject obj(cx, ToObjectFromStack(cx, lval));
+    if (!obj)
+        return false;
+
+    PropertyCacheEntry *entry;
+    JSObject *obj2;
+    PropertyName *name;
+    if (cx->propertyCache().testForSet(cx, pc, obj, &entry, &obj2, &name)) {
+        /*
+         * Property cache hit, only partially confirmed by testForSet. We
+         * know that the entry applies to regs.pc and that obj's shape
+         * matches.
+         *
+         * The entry predicts a set either an existing "own" property, or
+         * on a prototype property that has a setter.
+         */
+        Shape *shape = entry->prop;
+        JS_ASSERT_IF(shape->isDataDescriptor(), shape->writable());
+        JS_ASSERT_IF(shape->hasSlot(), entry->isOwnPropertyHit());
+
+        if (entry->isOwnPropertyHit() ||
+            ((obj2 = obj->getProto()) && obj2->lastProperty() == entry->pshape)) {
+#ifdef DEBUG
+            if (entry->isOwnPropertyHit()) {
+                JS_ASSERT(obj->nativeLookupNoAllocation(shape->propid()) == shape);
+            } else {
+                JS_ASSERT(obj2->nativeLookupNoAllocation(shape->propid()) == shape);
+                JS_ASSERT(entry->isPrototypePropertyHit());
+                JS_ASSERT(entry->kshape != entry->pshape);
+                JS_ASSERT(!shape->hasSlot());
+            }
+#endif
+
+            if (shape->hasDefaultSetter() && shape->hasSlot()) {
+                /* Fast path for, e.g., plain Object instance properties. */
+                JSObject::nativeSetSlotWithType(cx, obj, shape, rval);
+            } else {
+                RootedValue rref(cx, rval);
+                bool strict = cx->stack.currentScript()->strictModeCode;
+                if (!js_NativeSet(cx, obj, obj, shape, false, strict, rref.address()))
+                    return false;
+            }
+            return true;
+        }
+
+        GET_NAME_FROM_BYTECODE(cx->stack.currentScript(), pc, 0, name);
+    }
+
+    bool strict = cx->stack.currentScript()->strictModeCode;
+    RootedValue rref(cx, rval);
+
+    RootedId id(cx, NameToId(name));
+    if (JS_LIKELY(!obj->getOps()->setProperty)) {
+        if (!baseops::SetPropertyHelper(cx, obj, obj, id, DNP_CACHE_RESULT, &rref, strict))
+            return false;
+    } else {
+        if (!JSObject::setGeneric(cx, obj, obj, id, &rref, strict))
+            return false;
+    }
+
+    return true;
+}
+
+template <bool TypeOf> inline bool
+FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName name,
+          HandleShape shape, MutableHandleValue vp)
+{
+    if (!shape) {
+        if (TypeOf) {
+            vp.setUndefined();
+            return true;
+        }
+        JSAutoByteString printable;
+        if (js_AtomToPrintableString(cx, name, &printable))
+            js_ReportIsNotDefined(cx, printable.ptr());
+        return false;
+    }
+
+    /* Take the slow path if shape was not found in a native object. */
+    if (!obj->isNative() || !obj2->isNative()) {
+        Rooted<jsid> id(cx, NameToId(name));
+        if (!JSObject::getGeneric(cx, obj, obj, id, vp))
+            return false;
+    } else {
+        Rooted<JSObject*> normalized(cx, obj);
+        if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
+            normalized = &normalized->asWith().object();
+        if (!NativeGet(cx, normalized, obj2, shape, 0, vp))
+            return false;
+    }
+    return true;
+}
+
+inline bool
+IntrinsicNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue vp)
+{
+    JSOp op = JSOp(*pc);
+    RootedPropertyName name(cx,  GetNameFromBytecode(cx, script, pc, op));
+    cx->global()->getIntrinsicValue(cx, name, vp);
+    return true;
+}
+
+inline bool
+NameOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp)
+{
+    RootedObject obj(cx, cx->stack.currentScriptedScopeChain());
+    RootedPropertyName name(cx, cx->stack.currentScript()->getName(pc));
+
+    /*
+     * Skip along the scope chain to the enclosing global object. This is
+     * used for GNAME opcodes where the bytecode emitter has determined a
+     * name access must be on the global. It also insulates us from bugs
+     * in the emitter: type inference will assume that GNAME opcodes are
+     * accessing the global object, and the inferred behavior should match
+     * the actual behavior even if the id could be found on the scope chain
+     * before the global object.
+     */
+    if (IsGlobalOp(JSOp(*pc)))
+        obj = &obj->global();
+
+    RootedShape shape(cx);
+    RootedObject scope(cx), pobj(cx);
+    if (!LookupName(cx, name, obj, &scope, &pobj, &shape))
+        return false;
+
+    /* Kludge to allow (typeof foo == "undefined") tests. */
+    JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
+    if (op2 == JSOP_TYPEOF)
+        return FetchName<true>(cx, scope, pobj, name, shape, vp);
+    return FetchName<false>(cx, scope, pobj, name, shape, vp);
+}
+
+inline bool
+SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject scope,
+                 HandleValue val)
+{
+    JS_ASSERT(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME);
+    JS_ASSERT_IF(*pc == JSOP_SETGNAME, scope == cx->global());
+
+    bool strict = script->strictModeCode;
+    RootedPropertyName name(cx, script->getName(pc));
+    RootedValue valCopy(cx, val);
+
+    /*
+     * In strict-mode, we need to trigger an error when trying to assign to an
+     * undeclared global variable. To do this, we call SetPropertyHelper
+     * directly and pass DNP_UNQUALIFIED.
+     */
+    if (scope->isGlobal()) {
+        JS_ASSERT(!scope->getOps()->setProperty);
+        RootedId id(cx, NameToId(name));
+        return baseops::SetPropertyHelper(cx, scope, scope, id, DNP_UNQUALIFIED, &valCopy, strict);
+    }
+
+    return JSObject::setProperty(cx, scope, scope, name, &valCopy, strict);
+}
+
+inline bool
+DefVarOrConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName dn, unsigned attrs)
+{
+    JS_ASSERT(varobj->isVarObj());
+    JS_ASSERT(!varobj->getOps()->defineProperty || varobj->isDebugScope());
+
+    RootedShape prop(cx);
+    RootedObject obj2(cx);
+    if (!JSObject::lookupProperty(cx, varobj, dn, &obj2, &prop))
+        return false;
+
+    /* Steps 8c, 8d. */
+    if (!prop || (obj2 != varobj && varobj->isGlobal())) {
+        RootedValue value(cx, UndefinedValue());
+        if (!JSObject::defineProperty(cx, varobj, dn, value, JS_PropertyStub,
+                                      JS_StrictPropertyStub, attrs)) {
+            return false;
+        }
+    } else {
+        /*
+         * Extension: ordinarily we'd be done here -- but for |const|.  If we
+         * see a redeclaration that's |const|, we consider it a conflict.
+         */
+        unsigned oldAttrs;
+        if (!JSObject::getPropertyAttributes(cx, varobj, dn, &oldAttrs))
+            return false;
+        if (attrs & JSPROP_READONLY) {
+            JSAutoByteString bytes;
+            if (js_AtomToPrintableString(cx, dn, &bytes)) {
+                JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
+                                                             js_GetErrorMessage,
+                                                             NULL, JSMSG_REDECLARED_VAR,
+                                                             (oldAttrs & JSPROP_READONLY)
+                                                             ? "const"
+                                                             : "var",
+                                                             bytes.ptr()));
+            }
+            return false;
+        }
+    }
+
+    return true;
+}
+
+inline void
+InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
+{
+    if (regs->fp()->script() == script)
+        enabler.enable();
+}
+
+static JS_ALWAYS_INLINE bool
+AddOperation(JSContext *cx, HandleScript script, jsbytecode *pc, const Value &lhs, const Value &rhs,
+             Value *res)
+{
+    if (lhs.isInt32() && rhs.isInt32()) {
+        int32_t l = lhs.toInt32(), r = rhs.toInt32();
+        int32_t sum = l + r;
+        if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
+            res->setDouble(double(l) + double(r));
+            types::TypeScript::MonitorOverflow(cx, script, pc);
+        } else {
+            res->setInt32(sum);
+        }
+    } else
+#if JS_HAS_XML_SUPPORT
+    if (IsXML(lhs) && IsXML(rhs)) {
+        if (!js_ConcatenateXML(cx, &lhs.toObject(), &rhs.toObject(), res))
+            return false;
+        types::TypeScript::MonitorUnknown(cx, script, pc);
+    } else
+#endif
+    {
+        RootedValue lval(cx, lhs);
+        RootedValue rval(cx, rhs);
+
+        /*
+         * If either operand is an object, any non-integer result must be
+         * reported to inference.
+         */
+        bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
+
+        if (!ToPrimitive(cx, lval.address()))
+            return false;
+        if (!ToPrimitive(cx, rval.address()))
+            return false;
+        bool lIsString, rIsString;
+        if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
+            RootedString lstr(cx), rstr(cx);
+            if (lIsString) {
+                lstr = lval.toString();
+            } else {
+                lstr = ToString(cx, lval);
+                if (!lstr)
+                    return false;
+            }
+            if (rIsString) {
+                rstr = rval.toString();
+            } else {
+                rstr = ToString(cx, rval);
+                if (!rstr)
+                    return false;
+            }
+            JSString *str = js_ConcatStrings(cx, lstr, rstr);
+            if (!str)
+                return false;
+            if (lIsObject || rIsObject)
+                types::TypeScript::MonitorString(cx, script, pc);
+            res->setString(str);
+        } else {
+            double l, r;
+            if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
+                return false;
+            l += r;
+            if (!res->setNumber(l) &&
+                (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
+                types::TypeScript::MonitorOverflow(cx, script, pc);
+            }
+        }
+    }
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+SubOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+             Value *res)
+{
+    double d1, d2;
+    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+        return false;
+    double d = d1 - d2;
+    if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
+        types::TypeScript::MonitorOverflow(cx, script, pc);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+MulOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+             Value *res)
+{
+    double d1, d2;
+    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+        return false;
+    double d = d1 * d2;
+    if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
+        types::TypeScript::MonitorOverflow(cx, script, pc);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+DivOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+             Value *res)
+{
+    double d1, d2;
+    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+        return false;
+    res->setNumber(NumberDiv(d1, d2));
+
+    if (d2 == 0 || (res->isDouble() && !(lhs.isDouble() || rhs.isDouble())))
+        types::TypeScript::MonitorOverflow(cx, script, pc);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+ModOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
+             Value *res)
+{
+    int32_t l, r;
+    if (lhs.isInt32() && rhs.isInt32() &&
+        (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) {
+        int32_t mod = l % r;
+        res->setInt32(mod);
+        return true;
+    }
+
+    double d1, d2;
+    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
+        return false;
+
+    res->setNumber(NumberMod(d1, d2));
+    types::TypeScript::MonitorOverflow(cx, script, pc);
+    return true;
+}
+
+static inline bool
+FetchElementId(JSContext *cx, JSObject *obj, const Value &idval, jsid *idp, MutableHandleValue vp)
+{
+    int32_t i_;
+    if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) {
+        *idp = INT_TO_JSID(i_);
+        return true;
+    }
+    return !!InternNonIntElementId(cx, obj, idval, idp, vp);
+}
+
+static JS_ALWAYS_INLINE bool
+ToIdOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue objval,
+              HandleValue idval, MutableHandleValue res)
+{
+    if (idval.isInt32()) {
+        res.set(idval);
+        return true;
+    }
+
+    JSObject *obj = ToObjectFromStack(cx, objval);
+    if (!obj)
+        return false;
+
+    jsid dummy;
+    if (!InternNonIntElementId(cx, obj, idval, &dummy, res))
+        return false;
+
+    if (!res.isInt32())
+        types::TypeScript::MonitorUnknown(cx, script, pc);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value &rref, MutableHandleValue res)
+{
+#if JS_HAS_XML_SUPPORT
+    if (op == JSOP_CALLELEM && JS_UNLIKELY(obj->isXML())) {
+        jsid id;
+        if (!FetchElementId(cx, obj, rref, &id, res))
+            return false;
+        return js_GetXMLMethod(cx, obj, id, res);
+    }
+#endif
+    // Don't call GetPcScript (needed for analysis) from inside Ion since it's expensive.
+    bool analyze = !cx->fp()->beginsIonActivation();
+
+    uint32_t index;
+    if (IsDefinitelyIndex(rref, &index)) {
+        if (analyze && !obj->isNative() && !obj->isArray()) {
+            RootedScript script(cx, NULL);
+            jsbytecode *pc = NULL;
+            types::TypeScript::GetPcScript(cx, &script, &pc);
+
+            if (script->hasAnalysis())
+                script->analysis()->getCode(pc).nonNativeGetElement = true;
+        }
+
+        do {
+            if (obj->isDenseArray()) {
+                if (index < obj->getDenseArrayInitializedLength()) {
+                    res.set(obj->getDenseArrayElement(index));
+                    if (!res.isMagic())
+                        break;
+                }
+            } else if (obj->isArguments()) {
+                if (obj->asArguments().maybeGetElement(index, res))
+                    break;
+            }
+            if (!JSObject::getElement(cx, obj, obj, index, res))
+                return false;
+        } while(0);
+    } else {
+        if (analyze) {
+            RootedScript script(cx, NULL);
+            jsbytecode *pc = NULL;
+            types::TypeScript::GetPcScript(cx, &script, &pc);
+
+            if (script->hasAnalysis()) {
+                script->analysis()->getCode(pc).getStringElement = true;
+
+                if (!obj->isArray() && !obj->isNative())
+                    script->analysis()->getCode(pc).nonNativeGetElement = true;
+            }
+        }
+
+        SpecialId special;
+        res.set(rref);
+        if (ValueIsSpecial(obj, res, &special, cx)) {
+            if (!JSObject::getSpecial(cx, obj, obj, special, res))
+                return false;
+        } else {
+            JSAtom *name = ToAtom(cx, res);
+            if (!name)
+                return false;
+
+            if (name->isIndex(&index)) {
+                if (!JSObject::getElement(cx, obj, obj, index, res))
+                    return false;
+            } else {
+                if (!JSObject::getProperty(cx, obj, obj, name->asPropertyName(), res))
+                    return false;
+            }
+        }
+    }
+
+    assertSameCompartment(cx, res);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+GetElementOperation(JSContext *cx, JSOp op, HandleValue lref, HandleValue rref,
+                    MutableHandleValue res)
+{
+    AssertCanGC();
+    JS_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
+
+    if (lref.isString() && rref.isInt32()) {
+        JSString *str = lref.toString();
+        int32_t i = rref.toInt32();
+        if (size_t(i) < str->length()) {
+            str = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
+            if (!str)
+                return false;
+            res.setString(str);
+            return true;
+        }
+    }
+
+    StackFrame *fp = cx->fp();
+    RootedValue lval(cx, lref);
+    if (IsOptimizedArguments(fp, lval.address())) {
+        if (rref.isInt32()) {
+            int32_t i = rref.toInt32();
+            if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
+                res.set(fp->unaliasedActual(i));
+                return true;
+            }
+        }
+
+        RootedScript script(cx, fp->script());
+        if (!JSScript::argumentsOptimizationFailed(cx, script))
+            return false;
+
+        lval = ObjectValue(fp->argsObj());
+    }
+
+    bool isObject = lval.isObject();
+    RootedObject obj(cx, ToObjectFromStack(cx, lval));
+    if (!obj)
+        return false;
+    if (!GetObjectElementOperation(cx, op, obj, rref, res))
+        return false;
+
+#if JS_HAS_NO_SUCH_METHOD
+    if (op == JSOP_CALLELEM && JS_UNLIKELY(res.isPrimitive()) && isObject) {
+        if (!OnUnknownMethod(cx, obj, rref, res))
+            return false;
+    }
+#endif
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, const Value &value, bool strict)
+{
+    types::TypeScript::MonitorAssign(cx, obj, id);
+
+    do {
+        if (obj->isDenseArray() && JSID_IS_INT(id)) {
+            uint32_t length = obj->getDenseArrayInitializedLength();
+            int32_t i = JSID_TO_INT(id);
+            if ((uint32_t)i < length) {
+                if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
+                    if (js_PrototypeHasIndexedProperties(obj))
+                        break;
+                    if ((uint32_t)i >= obj->getArrayLength())
+                        JSObject::setArrayLength(cx, obj, i + 1);
+                }
+                JSObject::setDenseArrayElementWithType(cx, obj, i, value);
+                return true;
+            } else {
+                if (!cx->fp()->beginsIonActivation()) {
+                    RootedScript script(cx);
+                    jsbytecode *pc;
+                    types::TypeScript::GetPcScript(cx, &script, &pc);
+
+                    if (script->hasAnalysis())
+                        script->analysis()->getCode(pc).arrayWriteHole = true;
+                }
+            }
+        }
+    } while (0);
+
+    RootedValue tmp(cx, value);
+    return JSObject::setGeneric(cx, obj, obj, id, &tmp, strict);
+}
+
+static JS_ALWAYS_INLINE JSString *
+TypeOfOperation(JSContext *cx, HandleValue v)
+{
+    JSType type = JS_TypeOfValue(cx, v);
+    return TypeName(type, cx);
+}
+
+#define RELATIONAL_OP(OP)                                                     \
+    JS_BEGIN_MACRO                                                            \
+        RootedValue lvalRoot(cx, lhs), rvalRoot(cx, rhs);                     \
+        Value &lval = lvalRoot.get();                                         \
+        Value &rval = rvalRoot.get();                                         \
+        /* Optimize for two int-tagged operands (typical loop control). */    \
+        if (lval.isInt32() && rval.isInt32()) {                               \
+            *res = lval.toInt32() OP rval.toInt32();                          \
+        } else {                                                              \
+            if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval))                       \
+                return false;                                                 \
+            if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval))                       \
+                return false;                                                 \
+            if (lval.isString() && rval.isString()) {                         \
+                JSString *l = lval.toString(), *r = rval.toString();          \
+                int32_t result;                                               \
+                if (!CompareStrings(cx, l, r, &result))                       \
+                    return false;                                             \
+                *res = result OP 0;                                           \
+            } else {                                                          \
+                double l, r;                                                  \
+                if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))       \
+                    return false;;                                            \
+                *res = (l OP r);                                              \
+            }                                                                 \
+        }                                                                     \
+        return true;                                                          \
+    JS_END_MACRO
+
+static JS_ALWAYS_INLINE bool
+LessThanOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
+    RELATIONAL_OP(<);
+}
+
+static JS_ALWAYS_INLINE bool
+LessThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
+    RELATIONAL_OP(<=);
+}
+
+static JS_ALWAYS_INLINE bool
+GreaterThanOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
+    RELATIONAL_OP(>);
+}
+
+static JS_ALWAYS_INLINE bool
+GreaterThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
+    RELATIONAL_OP(>=);
+}
+
+static JS_ALWAYS_INLINE bool
+BitNot(JSContext *cx, HandleValue in, int *out)
+{
+    int i;
+    if (!ToInt32(cx, in, &i))
+        return false;
+    *out = ~i;
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+BitXor(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
+{
+    int left, right;
+    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+        return false;
+    *out = left ^ right;
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+BitOr(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
+{
+    int left, right;
+    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+        return false;
+    *out = left | right;
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+BitAnd(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
+{
+    int left, right;
+    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+        return false;
+    *out = left & right;
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+BitLsh(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
+{
+    int32_t left, right;
+    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+        return false;
+    *out = left << (right & 31);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+BitRsh(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
+{
+    int32_t left, right;
+    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+        return false;
+    *out = left >> (right & 31);
+    return true;
+}
+
+static JS_ALWAYS_INLINE bool
+UrshOperation(JSContext *cx, HandleScript script, jsbytecode *pc,
+              HandleValue lhs, HandleValue rhs, Value *out)
+{
+    uint32_t left;
+    int32_t  right;
+    if (!ToUint32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
+        return false;
+    left >>= right & 31;
+    if (!out->setNumber(uint32_t(left)))
+        types::TypeScript::MonitorOverflow(cx, script, pc);
+    return true;
+}
+
+#undef RELATIONAL_OP
+
+inline JSFunction *
+ReportIfNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct = NO_CONSTRUCT)
+{
+    if (v.isObject() && v.toObject().isFunction())
+        return v.toObject().toFunction();
+
+    ReportIsNotFunction(cx, v, construct);
+    return NULL;
+}
+
+/*
+ * FastInvokeGuard is used to optimize calls to JS functions from natives written
+ * in C++, for instance Array.map. If the callee is not Ion-compiled, this will
+ * just call Invoke. If the callee has a valid IonScript, however, it will enter
+ * Ion directly.
+ */
+class FastInvokeGuard
+{
+    InvokeArgsGuard args_;
+    RootedFunction fun_;
+    RootedScript script_;
+#ifdef JS_ION
+    ion::IonContext ictx_;
+    bool useIon_;
+#endif
+
+  public:
+    FastInvokeGuard(JSContext *cx, const Value &fval)
+      : fun_(cx),
+        script_(cx)
+#ifdef JS_ION
+        , ictx_(cx, cx->compartment, NULL),
+        useIon_(ion::IsEnabled(cx))
+#endif
+    {
+        initFunction(fval);
+    }
+
+    void initFunction(const Value &fval) {
+        if (fval.isObject() && fval.toObject().isFunction()) {
+            JSFunction *fun = fval.toObject().toFunction();
+            if (fun->isInterpreted()) {
+                fun_ = fun;
+                script_ = fun->script();
+            }
+        }
+    }
+
+    InvokeArgsGuard &args() {
+        return args_;
+    }
+
+    bool invoke(JSContext *cx) {
+#ifdef JS_ION
+        if (useIon_ && fun_) {
+            JS_ASSERT(fun_->script() == script_);
+
+            ion::MethodStatus status = ion::CanEnterUsingFastInvoke(cx, script_);
+            if (status == ion::Method_Error)
+                return false;
+            if (status == ion::Method_Compiled) {
+                ion::IonExecStatus result = ion::FastInvoke(cx, fun_, args_);
+                if (result == ion::IonExec_Error)
+                    return false;
+
+                JS_ASSERT(result == ion::IonExec_Ok);
+                return true;
+            }
+
+            JS_ASSERT(status == ion::Method_Skipped);
+
+            if (script_->canIonCompile()) {
+                // This script is not yet hot. Since calling into Ion is much
+                // faster here, bump the use count a bit to account for this.
+                script_->incUseCount(5);
+            }
+        }
+#endif
+
+        return Invoke(cx, args_);
+    }
+
+  private:
+    FastInvokeGuard(const FastInvokeGuard& other) MOZ_DELETE;
+    const FastInvokeGuard& operator=(const FastInvokeGuard& other) MOZ_DELETE;
+};
+
+}  /* namespace js */
+
+#endif /* jsinterpinlines_h__ */
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -16,16 +16,17 @@
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsexn.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsproxy.h"
 #include "jsscope.h"
 #include "jsscript.h"
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -29,16 +29,17 @@
 #include "jstypes.h"
 #include "jsutil.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdtoa.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsprf.h"
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jslibmath.h"
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -20,16 +20,17 @@
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsdate.h"
 #include "jsversion.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jsiter.h"
 #include "jslock.h"
 #include "jsmath.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsonparser.h"
 #include "jsopcode.h"
 #include "jsprobes.h"
@@ -51,16 +52,17 @@
 #include "gc/Marking.h"
 #include "js/MemoryMetrics.h"
 #include "vm/StringBuffer.h"
 #include "vm/Xdr.h"
 
 #include "jsarrayinlines.h"
 #include "jsatominlines.h"
 #include "jscntxtinlines.h"
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
 #include "vm/BooleanObject-inl.h"
 #include "vm/NumberObject-inl.h"
 #include "vm/StringObject-inl.h"
 
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -9,16 +9,17 @@
 
 #include <string.h>
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsfun.h"
+#include "jsinterp.h"
 #include "jsiter.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "json.h"
 #include "jsonparser.h"
 #include "jsprf.h"
 #include "jsstr.h"
 #include "jstypes.h"
--- a/js/src/jsprobes.cpp
+++ b/js/src/jsprobes.cpp
@@ -16,16 +16,17 @@
 #endif
 
 #include "jsapi.h"
 #include "jsutil.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
+#include "jsinterp.h"
 #include "jsobj.h"
 #include "jsprobes.h"
 #include "jsscript.h"
 #include "jsstr.h"
 
 #include "methodjit/Compiler.h"
 
 #include "jsobjinlines.h"
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -16,16 +16,17 @@
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsatom.h"
 #include "jscntxt.h"
 #include "jsversion.h"
 #include "jsdbgapi.h"
 #include "jsfun.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsopcode.h"
 #include "jsscope.h"
 #include "jsscript.h"
 
 #include "gc/Marking.h"
 #include "frontend/BytecodeEmitter.h"
@@ -33,21 +34,21 @@
 #include "js/MemoryMetrics.h"
 #include "methodjit/MethodJIT.h"
 #include "ion/IonCode.h"
 #include "methodjit/Retcon.h"
 #include "vm/Debugger.h"
 #include "vm/Xdr.h"
 
 #include "jsinferinlines.h"
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
 
 #include "frontend/SharedContext-inl.h"
-#include "vm/Interpreter-inl.h"
 #include "vm/RegExpObject-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::frontend;
 
 /* static */ unsigned
 Bindings::argumentsVarIndex(JSContext *cx, InternalBindingsHandle bindings)
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -25,39 +25,39 @@
 #include "jsutil.h"
 #include "jsprf.h"
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jsopcode.h"
 #include "jsprobes.h"
 #include "jsscope.h"
 #include "jsstr.h"
 #include "jsversion.h"
 
 #include "builtin/RegExp.h"
 #include "js/HashTable.h"
 #include "vm/GlobalObject.h"
-#include "vm/Interpreter.h"
 #include "vm/NumericConversions.h"
 #include "vm/RegExpObject.h"
 #include "vm/StringBuffer.h"
 
 #include "jsinferinlines.h"
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsstrinlines.h"
 #include "jsautooplen.h"        // generated headers last
 
-#include "vm/Interpreter-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/RegExpStatics-inl.h"
 #include "vm/StringObject-inl.h"
 #include "vm/String-inl.h"
 
 using namespace js;
 using namespace js::gc;
 using namespace js::types;
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -13,16 +13,17 @@
 #include "jsapi.h"
 #include "jsarray.h"
 #include "jsatom.h"
 #include "jsbool.h"
 #include "jscntxt.h"
 #include "jscpucfg.h"
 #include "jsversion.h"
 #include "jsgc.h"
+#include "jsinterp.h"
 #include "jslock.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jstypedarray.h"
 
 #include "gc/Barrier.h"
 #include "gc/Marking.h"
 #include "gc/StoreBuffer.h"
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -20,24 +20,24 @@
 #include "assembler/assembler/CodeLocation.h"
 #include "builtin/Eval.h"
 #include "methodjit/StubCalls.h"
 #include "methodjit/MonoIC.h"
 #include "methodjit/BaseCompiler.h"
 #include "methodjit/ICRepatcher.h"
 #include "vm/Debugger.h"
 
+#include "jsinterpinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsobjinlines.h"
 #include "jscntxtinlines.h"
 #include "jsatominlines.h"
 
 #include "StubCalls-inl.h"
-#include "vm/Interpreter-inl.h"
 
 #include "jsautooplen.h"
 
 #include "ion/Ion.h"
 
 using namespace js;
 using namespace js::mjit;
 using namespace JSC;
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -19,18 +19,17 @@
 #include "jscntxtinlines.h"
 #include "jscompartment.h"
 #include "jsscope.h"
 #include "ion/Ion.h"
 #include "ion/IonCompartment.h"
 #include "methodjit/Retcon.h"
 
 #include "jsgcinlines.h"
-
-#include "vm/Interpreter-inl.h"
+#include "jsinterpinlines.h"
 
 #if JS_TRACE_LOGGING
 #include "TraceLogging.h"
 #endif
 
 using namespace js;
 using namespace js::mjit;
 
--- a/js/src/methodjit/MonoIC.cpp
+++ b/js/src/methodjit/MonoIC.cpp
@@ -19,22 +19,21 @@
 #include "methodjit/ICRepatcher.h"
 #include "methodjit/InlineFrameAssembler.h"
 #include "methodjit/MonoIC.h"
 #include "methodjit/PolyIC.h"
 #include "methodjit/StubCalls.h"
 
 #include "builtin/RegExp.h"
 
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 
-#include "vm/Interpreter-inl.h"
-
 #include "methodjit/StubCalls-inl.h"
 #ifdef JS_ION
 # include "ion/IonMacroAssembler.h"
 #endif
 
 using namespace js;
 using namespace js::mjit;
 using namespace js::mjit::ic;
--- a/js/src/methodjit/PolyIC.cpp
+++ b/js/src/methodjit/PolyIC.cpp
@@ -12,19 +12,19 @@
 #include "assembler/assembler/LinkBuffer.h"
 #include "TypedArrayIC.h"
 #include "jsscope.h"
 #include "jsnum.h"
 #include "jstypedarray.h"
 #include "jsatominlines.h"
 #include "jsobjinlines.h"
 #include "jsscopeinlines.h"
+#include "jsinterpinlines.h"
 #include "jsautooplen.h"
 
-#include "vm/Interpreter-inl.h"
 #include "vm/ScopeObject-inl.h"
 #include "vm/StringObject-inl.h"
 
 #if defined JS_POLYIC
 
 using namespace js;
 using namespace js::mjit;
 using namespace js::mjit::ic;
--- a/js/src/methodjit/Retcon.cpp
+++ b/js/src/methodjit/Retcon.cpp
@@ -12,18 +12,17 @@
 #include "Compiler.h"
 #include "StubCalls.h"
 #include "jsdbgapi.h"
 #include "jsnum.h"
 #include "assembler/assembler/LinkBuffer.h"
 #include "assembler/assembler/RepatchBuffer.h"
 
 #include "jscntxtinlines.h"
-
-#include "vm/Interpreter-inl.h"
+#include "jsinterpinlines.h"
 
 using namespace js;
 using namespace js::mjit;
 
 namespace js {
 namespace mjit {
 
 static inline void
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -21,27 +21,27 @@
 #include "gc/Marking.h"
 #include "vm/Debugger.h"
 #include "vm/NumericConversions.h"
 #include "vm/String.h"
 #include "methodjit/Compiler.h"
 #include "methodjit/StubCalls.h"
 #include "methodjit/Retcon.h"
 
+#include "jsinterpinlines.h"
 #include "jsscopeinlines.h"
 #include "jsscriptinlines.h"
 #include "jsnuminlines.h"
 #include "jsobjinlines.h"
 #include "jscntxtinlines.h"
 #include "jsatominlines.h"
 #include "StubCalls-inl.h"
 #include "jsfuninlines.h"
 #include "jstypedarray.h"
 
-#include "vm/Interpreter-inl.h"
 #include "vm/RegExpObject-inl.h"
 #include "vm/String-inl.h"
 
 #ifdef JS_ION
 #include "ion/Ion.h"
 #endif
 
 #ifdef XP_WIN
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -49,19 +49,19 @@
 #include "methodjit/MethodJIT.h"
 
 #include "prmjtime.h"
 
 #include "jsoptparse.h"
 #include "jsheaptools.h"
 
 #include "jsinferinlines.h"
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsscriptinlines.h"
-#include "vm/Interpreter-inl.h"
 #include "ion/Ion.h"
 
 #ifdef XP_UNIX
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #endif
 
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -2,27 +2,27 @@
  * vim: set ts=8 sw=4 et tw=99:
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsgc.h"
 #include "jsinfer.h"
+#include "jsinterp.h"
 
 #include "vm/GlobalObject.h"
 #include "vm/Stack.h"
 #include "vm/Xdr.h"
 
 #include "jsobjinlines.h"
 
 #include "gc/Barrier-inl.h"
 #include "vm/Stack-inl.h"
 #include "vm/ArgumentsObject-inl.h"
-#include "vm/Interpreter.h"
 
 using namespace js;
 using namespace js::gc;
 
 static void
 CopyStackFrameArguments(const StackFrame *fp, HeapValue *dst)
 {
     JS_ASSERT(!fp->runningInIon());
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -8,27 +8,27 @@
 #include "vm/Debugger.h"
 #include "jsapi.h"
 #include "jscntxt.h"
 #include "jsnum.h"
 #include "jsobj.h"
 #include "jswrapper.h"
 #include "jsarrayinlines.h"
 #include "jsgcinlines.h"
+#include "jsinterpinlines.h"
 #include "jsobjinlines.h"
 #include "jsopcodeinlines.h"
 #include "jscompartment.h"
 
 #include "frontend/BytecodeCompiler.h"
 #include "frontend/BytecodeEmitter.h"
 #include "gc/Marking.h"
 #include "methodjit/Retcon.h"
 #include "js/Vector.h"
 
-#include "vm/Interpreter-inl.h"
 #include "vm/Stack-inl.h"
 
 using namespace js;
 using js::frontend::IsIdentifier;
 
 
 /*** Forward declarations ************************************************************************/
 
deleted file mode 100644
--- a/js/src/vm/Interpreter-inl.h
+++ /dev/null
@@ -1,1069 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=4 sw=4 et tw=99:
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef jsinterpinlines_h__
-#define jsinterpinlines_h__
-
-#include "jsapi.h"
-#include "jsbool.h"
-#include "jscompartment.h"
-#include "jsinfer.h"
-#include "jslibmath.h"
-#include "jsnum.h"
-#include "jsprobes.h"
-#include "jsstr.h"
-#include "methodjit/MethodJIT.h"
-
-#include "jsatominlines.h"
-#include "jsfuninlines.h"
-#include "jsinferinlines.h"
-#include "jsopcodeinlines.h"
-#include "jspropertycacheinlines.h"
-#include "jstypedarrayinlines.h"
-
-#include "ion/Ion.h"
-#include "ion/IonCompartment.h"
-
-#include "vm/Stack-inl.h"
-#include "vm/Interpreter.h"
-
-namespace js {
-
-/*
- * Compute the implicit |this| parameter for a call expression where the callee
- * funval was resolved from an unqualified name reference to a property on obj
- * (an object on the scope chain).
- *
- * We can avoid computing |this| eagerly and push the implicit callee-coerced
- * |this| value, undefined, if any of these conditions hold:
- *
- * 1. The nominal |this|, obj, is a global object.
- *
- * 2. The nominal |this|, obj, has one of Block, Call, or DeclEnv class (this
- *    is what IsCacheableNonGlobalScope tests). Such objects-as-scopes must be
- *    censored with undefined.
- *
- * Otherwise, we bind |this| to obj->thisObject(). Only names inside |with|
- * statements and embedding-specific scope objects fall into this category.
- *
- * If the callee is a strict mode function, then code implementing JSOP_THIS
- * in the interpreter and JITs will leave undefined as |this|. If funval is a
- * function not in strict mode, JSOP_THIS code replaces undefined with funval's
- * global.
- *
- * We set *vp to undefined early to reduce code size and bias this code for the
- * common and future-friendly cases.
- */
-inline bool
-ComputeImplicitThis(JSContext *cx, HandleObject obj, Value *vp)
-{
-    vp->setUndefined();
-
-    if (obj->isGlobal())
-        return true;
-
-    if (IsCacheableNonGlobalScope(obj))
-        return true;
-
-    RawObject nobj = JSObject::thisObject(cx, obj);
-    if (!nobj)
-        return false;
-
-    vp->setObject(*nobj);
-    return true;
-}
-
-inline bool
-ComputeThis(JSContext *cx, StackFrame *fp)
-{
-    JS_ASSERT(!fp->runningInIon());
-    Value &thisv = fp->thisValue();
-    if (thisv.isObject())
-        return true;
-    if (fp->isFunctionFrame()) {
-        if (fp->fun()->inStrictMode() || fp->fun()->isSelfHostedBuiltin())
-            return true;
-        /*
-         * Eval function frames have their own |this| slot, which is a copy of the function's
-         * |this| slot. If we lazily wrap a primitive |this| in an eval function frame, the
-         * eval's frame will get the wrapper, but the function's frame will not. To prevent
-         * this, we always wrap a function's |this| before pushing an eval frame, and should
-         * thus never see an unwrapped primitive in a non-strict eval function frame.
-         */
-        JS_ASSERT(!fp->isEvalFrame());
-    }
-    return BoxNonStrictThis(cx, fp->callReceiver());
-}
-
-/*
- * Every possible consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) (as determined
- * by ScriptAnalysis::needsArgsObj) must check for these magic values and, when
- * one is received, act as if the value were the function's ArgumentsObject.
- * Additionally, it is possible that, after 'arguments' was copied into a
- * temporary, the arguments object has been created a some other failed guard
- * that called JSScript::argumentsOptimizationFailed. In this case, it is
- * always valid (and necessary) to replace JS_OPTIMIZED_ARGUMENTS with the real
- * arguments object.
- */
-static inline bool
-IsOptimizedArguments(StackFrame *fp, Value *vp)
-{
-    AutoAssertNoGC nogc;
-    if (vp->isMagic(JS_OPTIMIZED_ARGUMENTS) && fp->script()->needsArgsObj())
-        *vp = ObjectValue(fp->argsObj());
-    return vp->isMagic(JS_OPTIMIZED_ARGUMENTS);
-}
-
-/*
- * One optimized consumer of MagicValue(JS_OPTIMIZED_ARGUMENTS) is f.apply.
- * However, this speculation must be guarded before calling 'apply' in case it
- * is not the builtin Function.prototype.apply.
- */
-static inline bool
-GuardFunApplyArgumentsOptimization(JSContext *cx)
-{
-    AssertCanGC();
-    FrameRegs &regs = cx->regs();
-    if (IsOptimizedArguments(regs.fp(), &regs.sp[-1])) {
-        CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
-        if (!IsNativeFunction(args.calleev(), js_fun_apply)) {
-            RootedScript script(cx, regs.fp()->script());
-            if (!JSScript::argumentsOptimizationFailed(cx, script))
-                return false;
-            regs.sp[-1] = ObjectValue(regs.fp()->argsObj());
-        }
-    }
-    return true;
-}
-
-/*
- * Return an object on which we should look for the properties of |value|.
- * This helps us implement the custom [[Get]] method that ES5's GetValue
- * algorithm uses for primitive values, without actually constructing the
- * temporary object that the specification does.
- *
- * For objects, return the object itself. For string, boolean, and number
- * primitive values, return the appropriate constructor's prototype. For
- * undefined and null, throw an error and return NULL, attributing the
- * problem to the value at |spindex| on the stack.
- */
-JS_ALWAYS_INLINE JSObject *
-ValuePropertyBearer(JSContext *cx, StackFrame *fp, HandleValue v, int spindex)
-{
-    if (v.isObject())
-        return &v.toObject();
-
-    GlobalObject &global = fp->global();
-
-    if (v.isString())
-        return global.getOrCreateStringPrototype(cx);
-    if (v.isNumber())
-        return global.getOrCreateNumberPrototype(cx);
-    if (v.isBoolean())
-        return global.getOrCreateBooleanPrototype(cx);
-
-    JS_ASSERT(v.isNull() || v.isUndefined());
-    js_ReportIsNullOrUndefined(cx, spindex, v, NullPtr());
-    return NULL;
-}
-
-inline bool
-NativeGet(JSContext *cx, Handle<JSObject*> obj, Handle<JSObject*> pobj, Shape *shape,
-          unsigned getHow, MutableHandleValue vp)
-{
-    if (shape->isDataDescriptor() && shape->hasDefaultGetter()) {
-        /* Fast path for Object instance properties. */
-        JS_ASSERT(shape->hasSlot());
-        vp.set(pobj->nativeGetSlot(shape->slot()));
-    } else {
-        if (!js_NativeGet(cx, obj, pobj, shape, getHow, vp.address()))
-            return false;
-    }
-    return true;
-}
-
-#if defined(DEBUG) && !defined(JS_THREADSAFE) && !defined(JSGC_ROOT_ANALYSIS)
-extern void
-AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
-                            PropertyCacheEntry *entry);
-#else
-inline void
-AssertValidPropertyCacheHit(JSContext *cx, JSObject *start, JSObject *found,
-                            PropertyCacheEntry *entry)
-{}
-#endif
-
-inline bool
-GetPropertyGenericMaybeCallXML(JSContext *cx, JSOp op, HandleObject obj, HandleId id, MutableHandleValue vp)
-{
-    /*
-     * Various XML properties behave differently when accessed in a
-     * call vs. normal context, and getGeneric will not work right.
-     */
-#if JS_HAS_XML_SUPPORT
-    if (op == JSOP_CALLPROP && obj->isXML())
-        return js_GetXMLMethod(cx, obj, id, vp);
-#endif
-
-    return JSObject::getGeneric(cx, obj, obj, id, vp);
-}
-
-inline bool
-GetLengthProperty(const Value &lval, MutableHandleValue vp)
-{
-    /* Optimize length accesses on strings, arrays, and arguments. */
-    if (lval.isString()) {
-        vp.setInt32(lval.toString()->length());
-        return true;
-    }
-    if (lval.isObject()) {
-        JSObject *obj = &lval.toObject();
-        if (obj->isArray()) {
-            uint32_t length = obj->getArrayLength();
-            vp.setNumber(length);
-            return true;
-        }
-
-        if (obj->isArguments()) {
-            ArgumentsObject *argsobj = &obj->asArguments();
-            if (!argsobj->hasOverriddenLength()) {
-                uint32_t length = argsobj->initialLength();
-                JS_ASSERT(length < INT32_MAX);
-                vp.setInt32(int32_t(length));
-                return true;
-            }
-        }
-
-        if (obj->isTypedArray()) {
-            vp.setInt32(TypedArray::length(obj));
-            return true;
-        }
-    }
-
-    return false;
-}
-
-inline bool
-GetPropertyOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue lval,
-                     MutableHandleValue vp)
-{
-    JSOp op = JSOp(*pc);
-
-    if (op == JSOP_LENGTH) {
-        if (IsOptimizedArguments(cx->fp(), lval.address())) {
-            vp.setInt32(cx->fp()->numActualArgs());
-            return true;
-        }
-
-        if (GetLengthProperty(lval, vp))
-            return true;
-    }
-
-    RootedObject obj(cx, ToObjectFromStack(cx, lval));
-    if (!obj)
-        return false;
-
-    PropertyCacheEntry *entry;
-    Rooted<JSObject*> obj2(cx);
-    PropertyName *name;
-    cx->propertyCache().test(cx, pc, obj.get(), obj2.get(), entry, name);
-    if (!name) {
-        AssertValidPropertyCacheHit(cx, obj, obj2, entry);
-        if (!NativeGet(cx, obj, obj2, entry->prop, JSGET_CACHE_RESULT, vp))
-            return false;
-        return true;
-    }
-
-    RootedId id(cx, NameToId(name));
-
-    if (obj->getOps()->getProperty) {
-        if (!GetPropertyGenericMaybeCallXML(cx, op, obj, id, vp))
-            return false;
-    } else {
-        if (!GetPropertyHelper(cx, obj, id, JSGET_CACHE_RESULT, vp))
-            return false;
-    }
-
-#if JS_HAS_NO_SUCH_METHOD
-    if (op == JSOP_CALLPROP &&
-        JS_UNLIKELY(vp.isPrimitive()) &&
-        lval.isObject())
-    {
-        if (!OnUnknownMethod(cx, obj, IdToValue(id), vp))
-            return false;
-    }
-#endif
-
-    return true;
-}
-
-inline bool
-SetPropertyOperation(JSContext *cx, jsbytecode *pc, HandleValue lval, HandleValue rval)
-{
-    JS_ASSERT(*pc == JSOP_SETPROP);
-
-    RootedObject obj(cx, ToObjectFromStack(cx, lval));
-    if (!obj)
-        return false;
-
-    PropertyCacheEntry *entry;
-    JSObject *obj2;
-    PropertyName *name;
-    if (cx->propertyCache().testForSet(cx, pc, obj, &entry, &obj2, &name)) {
-        /*
-         * Property cache hit, only partially confirmed by testForSet. We
-         * know that the entry applies to regs.pc and that obj's shape
-         * matches.
-         *
-         * The entry predicts a set either an existing "own" property, or
-         * on a prototype property that has a setter.
-         */
-        Shape *shape = entry->prop;
-        JS_ASSERT_IF(shape->isDataDescriptor(), shape->writable());
-        JS_ASSERT_IF(shape->hasSlot(), entry->isOwnPropertyHit());
-
-        if (entry->isOwnPropertyHit() ||
-            ((obj2 = obj->getProto()) && obj2->lastProperty() == entry->pshape)) {
-#ifdef DEBUG
-            if (entry->isOwnPropertyHit()) {
-                JS_ASSERT(obj->nativeLookupNoAllocation(shape->propid()) == shape);
-            } else {
-                JS_ASSERT(obj2->nativeLookupNoAllocation(shape->propid()) == shape);
-                JS_ASSERT(entry->isPrototypePropertyHit());
-                JS_ASSERT(entry->kshape != entry->pshape);
-                JS_ASSERT(!shape->hasSlot());
-            }
-#endif
-
-            if (shape->hasDefaultSetter() && shape->hasSlot()) {
-                /* Fast path for, e.g., plain Object instance properties. */
-                JSObject::nativeSetSlotWithType(cx, obj, shape, rval);
-            } else {
-                RootedValue rref(cx, rval);
-                bool strict = cx->stack.currentScript()->strictModeCode;
-                if (!js_NativeSet(cx, obj, obj, shape, false, strict, rref.address()))
-                    return false;
-            }
-            return true;
-        }
-
-        GET_NAME_FROM_BYTECODE(cx->stack.currentScript(), pc, 0, name);
-    }
-
-    bool strict = cx->stack.currentScript()->strictModeCode;
-    RootedValue rref(cx, rval);
-
-    RootedId id(cx, NameToId(name));
-    if (JS_LIKELY(!obj->getOps()->setProperty)) {
-        if (!baseops::SetPropertyHelper(cx, obj, obj, id, DNP_CACHE_RESULT, &rref, strict))
-            return false;
-    } else {
-        if (!JSObject::setGeneric(cx, obj, obj, id, &rref, strict))
-            return false;
-    }
-
-    return true;
-}
-
-template <bool TypeOf> inline bool
-FetchName(JSContext *cx, HandleObject obj, HandleObject obj2, HandlePropertyName name,
-          HandleShape shape, MutableHandleValue vp)
-{
-    if (!shape) {
-        if (TypeOf) {
-            vp.setUndefined();
-            return true;
-        }
-        JSAutoByteString printable;
-        if (js_AtomToPrintableString(cx, name, &printable))
-            js_ReportIsNotDefined(cx, printable.ptr());
-        return false;
-    }
-
-    /* Take the slow path if shape was not found in a native object. */
-    if (!obj->isNative() || !obj2->isNative()) {
-        Rooted<jsid> id(cx, NameToId(name));
-        if (!JSObject::getGeneric(cx, obj, obj, id, vp))
-            return false;
-    } else {
-        Rooted<JSObject*> normalized(cx, obj);
-        if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter())
-            normalized = &normalized->asWith().object();
-        if (!NativeGet(cx, normalized, obj2, shape, 0, vp))
-            return false;
-    }
-    return true;
-}
-
-inline bool
-IntrinsicNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, MutableHandleValue vp)
-{
-    JSOp op = JSOp(*pc);
-    RootedPropertyName name(cx,  GetNameFromBytecode(cx, script, pc, op));
-    cx->global()->getIntrinsicValue(cx, name, vp);
-    return true;
-}
-
-inline bool
-NameOperation(JSContext *cx, jsbytecode *pc, MutableHandleValue vp)
-{
-    RootedObject obj(cx, cx->stack.currentScriptedScopeChain());
-    RootedPropertyName name(cx, cx->stack.currentScript()->getName(pc));
-
-    /*
-     * Skip along the scope chain to the enclosing global object. This is
-     * used for GNAME opcodes where the bytecode emitter has determined a
-     * name access must be on the global. It also insulates us from bugs
-     * in the emitter: type inference will assume that GNAME opcodes are
-     * accessing the global object, and the inferred behavior should match
-     * the actual behavior even if the id could be found on the scope chain
-     * before the global object.
-     */
-    if (IsGlobalOp(JSOp(*pc)))
-        obj = &obj->global();
-
-    RootedShape shape(cx);
-    RootedObject scope(cx), pobj(cx);
-    if (!LookupName(cx, name, obj, &scope, &pobj, &shape))
-        return false;
-
-    /* Kludge to allow (typeof foo == "undefined") tests. */
-    JSOp op2 = JSOp(pc[JSOP_NAME_LENGTH]);
-    if (op2 == JSOP_TYPEOF)
-        return FetchName<true>(cx, scope, pobj, name, shape, vp);
-    return FetchName<false>(cx, scope, pobj, name, shape, vp);
-}
-
-inline bool
-SetNameOperation(JSContext *cx, JSScript *script, jsbytecode *pc, HandleObject scope,
-                 HandleValue val)
-{
-    JS_ASSERT(*pc == JSOP_SETNAME || *pc == JSOP_SETGNAME);
-    JS_ASSERT_IF(*pc == JSOP_SETGNAME, scope == cx->global());
-
-    bool strict = script->strictModeCode;
-    RootedPropertyName name(cx, script->getName(pc));
-    RootedValue valCopy(cx, val);
-
-    /*
-     * In strict-mode, we need to trigger an error when trying to assign to an
-     * undeclared global variable. To do this, we call SetPropertyHelper
-     * directly and pass DNP_UNQUALIFIED.
-     */
-    if (scope->isGlobal()) {
-        JS_ASSERT(!scope->getOps()->setProperty);
-        RootedId id(cx, NameToId(name));
-        return baseops::SetPropertyHelper(cx, scope, scope, id, DNP_UNQUALIFIED, &valCopy, strict);
-    }
-
-    return JSObject::setProperty(cx, scope, scope, name, &valCopy, strict);
-}
-
-inline bool
-DefVarOrConstOperation(JSContext *cx, HandleObject varobj, HandlePropertyName dn, unsigned attrs)
-{
-    JS_ASSERT(varobj->isVarObj());
-    JS_ASSERT(!varobj->getOps()->defineProperty || varobj->isDebugScope());
-
-    RootedShape prop(cx);
-    RootedObject obj2(cx);
-    if (!JSObject::lookupProperty(cx, varobj, dn, &obj2, &prop))
-        return false;
-
-    /* Steps 8c, 8d. */
-    if (!prop || (obj2 != varobj && varobj->isGlobal())) {
-        RootedValue value(cx, UndefinedValue());
-        if (!JSObject::defineProperty(cx, varobj, dn, value, JS_PropertyStub,
-                                      JS_StrictPropertyStub, attrs)) {
-            return false;
-        }
-    } else {
-        /*
-         * Extension: ordinarily we'd be done here -- but for |const|.  If we
-         * see a redeclaration that's |const|, we consider it a conflict.
-         */
-        unsigned oldAttrs;
-        if (!JSObject::getPropertyAttributes(cx, varobj, dn, &oldAttrs))
-            return false;
-        if (attrs & JSPROP_READONLY) {
-            JSAutoByteString bytes;
-            if (js_AtomToPrintableString(cx, dn, &bytes)) {
-                JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
-                                                             js_GetErrorMessage,
-                                                             NULL, JSMSG_REDECLARED_VAR,
-                                                             (oldAttrs & JSPROP_READONLY)
-                                                             ? "const"
-                                                             : "var",
-                                                             bytes.ptr()));
-            }
-            return false;
-        }
-    }
-
-    return true;
-}
-
-inline void
-InterpreterFrames::enableInterruptsIfRunning(JSScript *script)
-{
-    if (regs->fp()->script() == script)
-        enabler.enable();
-}
-
-static JS_ALWAYS_INLINE bool
-AddOperation(JSContext *cx, HandleScript script, jsbytecode *pc, const Value &lhs, const Value &rhs,
-             Value *res)
-{
-    if (lhs.isInt32() && rhs.isInt32()) {
-        int32_t l = lhs.toInt32(), r = rhs.toInt32();
-        int32_t sum = l + r;
-        if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
-            res->setDouble(double(l) + double(r));
-            types::TypeScript::MonitorOverflow(cx, script, pc);
-        } else {
-            res->setInt32(sum);
-        }
-    } else
-#if JS_HAS_XML_SUPPORT
-    if (IsXML(lhs) && IsXML(rhs)) {
-        if (!js_ConcatenateXML(cx, &lhs.toObject(), &rhs.toObject(), res))
-            return false;
-        types::TypeScript::MonitorUnknown(cx, script, pc);
-    } else
-#endif
-    {
-        RootedValue lval(cx, lhs);
-        RootedValue rval(cx, rhs);
-
-        /*
-         * If either operand is an object, any non-integer result must be
-         * reported to inference.
-         */
-        bool lIsObject = lval.isObject(), rIsObject = rval.isObject();
-
-        if (!ToPrimitive(cx, lval.address()))
-            return false;
-        if (!ToPrimitive(cx, rval.address()))
-            return false;
-        bool lIsString, rIsString;
-        if ((lIsString = lval.isString()) | (rIsString = rval.isString())) {
-            RootedString lstr(cx), rstr(cx);
-            if (lIsString) {
-                lstr = lval.toString();
-            } else {
-                lstr = ToString(cx, lval);
-                if (!lstr)
-                    return false;
-            }
-            if (rIsString) {
-                rstr = rval.toString();
-            } else {
-                rstr = ToString(cx, rval);
-                if (!rstr)
-                    return false;
-            }
-            JSString *str = js_ConcatStrings(cx, lstr, rstr);
-            if (!str)
-                return false;
-            if (lIsObject || rIsObject)
-                types::TypeScript::MonitorString(cx, script, pc);
-            res->setString(str);
-        } else {
-            double l, r;
-            if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))
-                return false;
-            l += r;
-            if (!res->setNumber(l) &&
-                (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
-                types::TypeScript::MonitorOverflow(cx, script, pc);
-            }
-        }
-    }
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-SubOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
-             Value *res)
-{
-    double d1, d2;
-    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
-        return false;
-    double d = d1 - d2;
-    if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
-        types::TypeScript::MonitorOverflow(cx, script, pc);
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-MulOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
-             Value *res)
-{
-    double d1, d2;
-    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
-        return false;
-    double d = d1 * d2;
-    if (!res->setNumber(d) && !(lhs.isDouble() || rhs.isDouble()))
-        types::TypeScript::MonitorOverflow(cx, script, pc);
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-DivOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
-             Value *res)
-{
-    double d1, d2;
-    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
-        return false;
-    res->setNumber(NumberDiv(d1, d2));
-
-    if (d2 == 0 || (res->isDouble() && !(lhs.isDouble() || rhs.isDouble())))
-        types::TypeScript::MonitorOverflow(cx, script, pc);
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-ModOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue lhs, HandleValue rhs,
-             Value *res)
-{
-    int32_t l, r;
-    if (lhs.isInt32() && rhs.isInt32() &&
-        (l = lhs.toInt32()) >= 0 && (r = rhs.toInt32()) > 0) {
-        int32_t mod = l % r;
-        res->setInt32(mod);
-        return true;
-    }
-
-    double d1, d2;
-    if (!ToNumber(cx, lhs, &d1) || !ToNumber(cx, rhs, &d2))
-        return false;
-
-    res->setNumber(NumberMod(d1, d2));
-    types::TypeScript::MonitorOverflow(cx, script, pc);
-    return true;
-}
-
-static inline bool
-FetchElementId(JSContext *cx, JSObject *obj, const Value &idval, jsid *idp, MutableHandleValue vp)
-{
-    int32_t i_;
-    if (ValueFitsInInt32(idval, &i_) && INT_FITS_IN_JSID(i_)) {
-        *idp = INT_TO_JSID(i_);
-        return true;
-    }
-    return !!InternNonIntElementId(cx, obj, idval, idp, vp);
-}
-
-static JS_ALWAYS_INLINE bool
-ToIdOperation(JSContext *cx, HandleScript script, jsbytecode *pc, HandleValue objval,
-              HandleValue idval, MutableHandleValue res)
-{
-    if (idval.isInt32()) {
-        res.set(idval);
-        return true;
-    }
-
-    JSObject *obj = ToObjectFromStack(cx, objval);
-    if (!obj)
-        return false;
-
-    jsid dummy;
-    if (!InternNonIntElementId(cx, obj, idval, &dummy, res))
-        return false;
-
-    if (!res.isInt32())
-        types::TypeScript::MonitorUnknown(cx, script, pc);
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-GetObjectElementOperation(JSContext *cx, JSOp op, HandleObject obj, const Value &rref, MutableHandleValue res)
-{
-#if JS_HAS_XML_SUPPORT
-    if (op == JSOP_CALLELEM && JS_UNLIKELY(obj->isXML())) {
-        jsid id;
-        if (!FetchElementId(cx, obj, rref, &id, res))
-            return false;
-        return js_GetXMLMethod(cx, obj, id, res);
-    }
-#endif
-    // Don't call GetPcScript (needed for analysis) from inside Ion since it's expensive.
-    bool analyze = !cx->fp()->beginsIonActivation();
-
-    uint32_t index;
-    if (IsDefinitelyIndex(rref, &index)) {
-        if (analyze && !obj->isNative() && !obj->isArray()) {
-            RootedScript script(cx, NULL);
-            jsbytecode *pc = NULL;
-            types::TypeScript::GetPcScript(cx, &script, &pc);
-
-            if (script->hasAnalysis())
-                script->analysis()->getCode(pc).nonNativeGetElement = true;
-        }
-
-        do {
-            if (obj->isDenseArray()) {
-                if (index < obj->getDenseArrayInitializedLength()) {
-                    res.set(obj->getDenseArrayElement(index));
-                    if (!res.isMagic())
-                        break;
-                }
-            } else if (obj->isArguments()) {
-                if (obj->asArguments().maybeGetElement(index, res))
-                    break;
-            }
-            if (!JSObject::getElement(cx, obj, obj, index, res))
-                return false;
-        } while(0);
-    } else {
-        if (analyze) {
-            RootedScript script(cx, NULL);
-            jsbytecode *pc = NULL;
-            types::TypeScript::GetPcScript(cx, &script, &pc);
-
-            if (script->hasAnalysis()) {
-                script->analysis()->getCode(pc).getStringElement = true;
-
-                if (!obj->isArray() && !obj->isNative())
-                    script->analysis()->getCode(pc).nonNativeGetElement = true;
-            }
-        }
-
-        SpecialId special;
-        res.set(rref);
-        if (ValueIsSpecial(obj, res, &special, cx)) {
-            if (!JSObject::getSpecial(cx, obj, obj, special, res))
-                return false;
-        } else {
-            JSAtom *name = ToAtom(cx, res);
-            if (!name)
-                return false;
-
-            if (name->isIndex(&index)) {
-                if (!JSObject::getElement(cx, obj, obj, index, res))
-                    return false;
-            } else {
-                if (!JSObject::getProperty(cx, obj, obj, name->asPropertyName(), res))
-                    return false;
-            }
-        }
-    }
-
-    assertSameCompartment(cx, res);
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-GetElementOperation(JSContext *cx, JSOp op, HandleValue lref, HandleValue rref,
-                    MutableHandleValue res)
-{
-    AssertCanGC();
-    JS_ASSERT(op == JSOP_GETELEM || op == JSOP_CALLELEM);
-
-    if (lref.isString() && rref.isInt32()) {
-        JSString *str = lref.toString();
-        int32_t i = rref.toInt32();
-        if (size_t(i) < str->length()) {
-            str = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
-            if (!str)
-                return false;
-            res.setString(str);
-            return true;
-        }
-    }
-
-    StackFrame *fp = cx->fp();
-    RootedValue lval(cx, lref);
-    if (IsOptimizedArguments(fp, lval.address())) {
-        if (rref.isInt32()) {
-            int32_t i = rref.toInt32();
-            if (i >= 0 && uint32_t(i) < fp->numActualArgs()) {
-                res.set(fp->unaliasedActual(i));
-                return true;
-            }
-        }
-
-        RootedScript script(cx, fp->script());
-        if (!JSScript::argumentsOptimizationFailed(cx, script))
-            return false;
-
-        lval = ObjectValue(fp->argsObj());
-    }
-
-    bool isObject = lval.isObject();
-    RootedObject obj(cx, ToObjectFromStack(cx, lval));
-    if (!obj)
-        return false;
-    if (!GetObjectElementOperation(cx, op, obj, rref, res))
-        return false;
-
-#if JS_HAS_NO_SUCH_METHOD
-    if (op == JSOP_CALLELEM && JS_UNLIKELY(res.isPrimitive()) && isObject) {
-        if (!OnUnknownMethod(cx, obj, rref, res))
-            return false;
-    }
-#endif
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-SetObjectElementOperation(JSContext *cx, Handle<JSObject*> obj, HandleId id, const Value &value, bool strict)
-{
-    types::TypeScript::MonitorAssign(cx, obj, id);
-
-    do {
-        if (obj->isDenseArray() && JSID_IS_INT(id)) {
-            uint32_t length = obj->getDenseArrayInitializedLength();
-            int32_t i = JSID_TO_INT(id);
-            if ((uint32_t)i < length) {
-                if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
-                    if (js_PrototypeHasIndexedProperties(obj))
-                        break;
-                    if ((uint32_t)i >= obj->getArrayLength())
-                        JSObject::setArrayLength(cx, obj, i + 1);
-                }
-                JSObject::setDenseArrayElementWithType(cx, obj, i, value);
-                return true;
-            } else {
-                if (!cx->fp()->beginsIonActivation()) {
-                    RootedScript script(cx);
-                    jsbytecode *pc;
-                    types::TypeScript::GetPcScript(cx, &script, &pc);
-
-                    if (script->hasAnalysis())
-                        script->analysis()->getCode(pc).arrayWriteHole = true;
-                }
-            }
-        }
-    } while (0);
-
-    RootedValue tmp(cx, value);
-    return JSObject::setGeneric(cx, obj, obj, id, &tmp, strict);
-}
-
-static JS_ALWAYS_INLINE JSString *
-TypeOfOperation(JSContext *cx, HandleValue v)
-{
-    JSType type = JS_TypeOfValue(cx, v);
-    return TypeName(type, cx);
-}
-
-#define RELATIONAL_OP(OP)                                                     \
-    JS_BEGIN_MACRO                                                            \
-        RootedValue lvalRoot(cx, lhs), rvalRoot(cx, rhs);                     \
-        Value &lval = lvalRoot.get();                                         \
-        Value &rval = rvalRoot.get();                                         \
-        /* Optimize for two int-tagged operands (typical loop control). */    \
-        if (lval.isInt32() && rval.isInt32()) {                               \
-            *res = lval.toInt32() OP rval.toInt32();                          \
-        } else {                                                              \
-            if (!ToPrimitive(cx, JSTYPE_NUMBER, &lval))                       \
-                return false;                                                 \
-            if (!ToPrimitive(cx, JSTYPE_NUMBER, &rval))                       \
-                return false;                                                 \
-            if (lval.isString() && rval.isString()) {                         \
-                JSString *l = lval.toString(), *r = rval.toString();          \
-                int32_t result;                                               \
-                if (!CompareStrings(cx, l, r, &result))                       \
-                    return false;                                             \
-                *res = result OP 0;                                           \
-            } else {                                                          \
-                double l, r;                                                  \
-                if (!ToNumber(cx, lval, &l) || !ToNumber(cx, rval, &r))       \
-                    return false;;                                            \
-                *res = (l OP r);                                              \
-            }                                                                 \
-        }                                                                     \
-        return true;                                                          \
-    JS_END_MACRO
-
-static JS_ALWAYS_INLINE bool
-LessThanOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
-    RELATIONAL_OP(<);
-}
-
-static JS_ALWAYS_INLINE bool
-LessThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
-    RELATIONAL_OP(<=);
-}
-
-static JS_ALWAYS_INLINE bool
-GreaterThanOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
-    RELATIONAL_OP(>);
-}
-
-static JS_ALWAYS_INLINE bool
-GreaterThanOrEqualOperation(JSContext *cx, const Value &lhs, const Value &rhs, bool *res) {
-    RELATIONAL_OP(>=);
-}
-
-static JS_ALWAYS_INLINE bool
-BitNot(JSContext *cx, HandleValue in, int *out)
-{
-    int i;
-    if (!ToInt32(cx, in, &i))
-        return false;
-    *out = ~i;
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-BitXor(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
-{
-    int left, right;
-    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
-        return false;
-    *out = left ^ right;
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-BitOr(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
-{
-    int left, right;
-    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
-        return false;
-    *out = left | right;
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-BitAnd(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
-{
-    int left, right;
-    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
-        return false;
-    *out = left & right;
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-BitLsh(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
-{
-    int32_t left, right;
-    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
-        return false;
-    *out = left << (right & 31);
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-BitRsh(JSContext *cx, HandleValue lhs, HandleValue rhs, int *out)
-{
-    int32_t left, right;
-    if (!ToInt32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
-        return false;
-    *out = left >> (right & 31);
-    return true;
-}
-
-static JS_ALWAYS_INLINE bool
-UrshOperation(JSContext *cx, HandleScript script, jsbytecode *pc,
-              HandleValue lhs, HandleValue rhs, Value *out)
-{
-    uint32_t left;
-    int32_t  right;
-    if (!ToUint32(cx, lhs, &left) || !ToInt32(cx, rhs, &right))
-        return false;
-    left >>= right & 31;
-    if (!out->setNumber(uint32_t(left)))
-        types::TypeScript::MonitorOverflow(cx, script, pc);
-    return true;
-}
-
-#undef RELATIONAL_OP
-
-inline JSFunction *
-ReportIfNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct = NO_CONSTRUCT)
-{
-    if (v.isObject() && v.toObject().isFunction())
-        return v.toObject().toFunction();
-
-    ReportIsNotFunction(cx, v, construct);
-    return NULL;
-}
-
-/*
- * FastInvokeGuard is used to optimize calls to JS functions from natives written
- * in C++, for instance Array.map. If the callee is not Ion-compiled, this will
- * just call Invoke. If the callee has a valid IonScript, however, it will enter
- * Ion directly.
- */
-class FastInvokeGuard
-{
-    InvokeArgsGuard args_;
-    RootedFunction fun_;
-    RootedScript script_;
-#ifdef JS_ION
-    ion::IonContext ictx_;
-    bool useIon_;
-#endif
-
-  public:
-    FastInvokeGuard(JSContext *cx, const Value &fval)
-      : fun_(cx),
-        script_(cx)
-#ifdef JS_ION
-        , ictx_(cx, cx->compartment, NULL),
-        useIon_(ion::IsEnabled(cx))
-#endif
-    {
-        initFunction(fval);
-    }
-
-    void initFunction(const Value &fval) {
-        if (fval.isObject() && fval.toObject().isFunction()) {
-            JSFunction *fun = fval.toObject().toFunction();
-            if (fun->isInterpreted()) {
-                fun_ = fun;
-                script_ = fun->script();
-            }
-        }
-    }
-
-    InvokeArgsGuard &args() {
-        return args_;
-    }
-
-    bool invoke(JSContext *cx) {
-#ifdef JS_ION
-        if (useIon_ && fun_) {
-            JS_ASSERT(fun_->script() == script_);
-
-            ion::MethodStatus status = ion::CanEnterUsingFastInvoke(cx, script_);
-            if (status == ion::Method_Error)
-                return false;
-            if (status == ion::Method_Compiled) {
-                ion::IonExecStatus result = ion::FastInvoke(cx, fun_, args_);
-                if (result == ion::IonExec_Error)
-                    return false;
-
-                JS_ASSERT(result == ion::IonExec_Ok);
-                return true;
-            }
-
-            JS_ASSERT(status == ion::Method_Skipped);
-
-            if (script_->canIonCompile()) {
-                // This script is not yet hot. Since calling into Ion is much
-                // faster here, bump the use count a bit to account for this.
-                script_->incUseCount(5);
-            }
-        }
-#endif
-
-        return Invoke(cx, args_);
-    }
-
-  private:
-    FastInvokeGuard(const FastInvokeGuard& other) MOZ_DELETE;
-    const FastInvokeGuard& operator=(const FastInvokeGuard& other) MOZ_DELETE;
-};
-
-}  /* namespace js */
-
-#endif /* jsinterpinlines_h__ */
deleted file mode 100644
--- a/js/src/vm/Interpreter.cpp
+++ /dev/null
@@ -1,4024 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sw=4 et tw=99:
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/*
- * JavaScript bytecode interpreter.
- */
-
-#include "mozilla/FloatingPoint.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include "jstypes.h"
-#include "jsutil.h"
-#include "jsprf.h"
-#include "jsapi.h"
-#include "jsarray.h"
-#include "jsatom.h"
-#include "jsbool.h"
-#include "jscntxt.h"
-#include "jsdate.h"
-#include "jsversion.h"
-#include "jsdbgapi.h"
-#include "jsfun.h"
-#include "jsgc.h"
-#include "jsiter.h"
-#include "jslibmath.h"
-#include "jslock.h"
-#include "jsnum.h"
-#include "jsobj.h"
-#include "jsopcode.h"
-#include "jspropertycache.h"
-#include "jsscope.h"
-#include "jsscript.h"
-#include "jsstr.h"
-
-#include "builtin/Eval.h"
-#include "gc/Marking.h"
-#include "vm/Debugger.h"
-
-#ifdef JS_METHODJIT
-#include "methodjit/MethodJIT.h"
-#include "methodjit/Logging.h"
-#endif
-#include "ion/Ion.h"
-
-#include "jsatominlines.h"
-#include "jsinferinlines.h"
-#include "jsobjinlines.h"
-#include "jsopcodeinlines.h"
-#include "jsprobes.h"
-#include "jspropertycacheinlines.h"
-#include "jsscopeinlines.h"
-#include "jsscriptinlines.h"
-#include "jstypedarrayinlines.h"
-
-#include "builtin/Iterator-inl.h"
-#include "vm/Interpreter-inl.h"
-#include "vm/Stack-inl.h"
-#include "vm/String-inl.h"
-
-#if JS_HAS_XML_SUPPORT
-#include "jsxml.h"
-#endif
-
-#include "jsautooplen.h"
-
-#if defined(JS_METHODJIT) && defined(JS_MONOIC)
-#include "methodjit/MonoIC.h"
-#endif
-
-#if JS_TRACE_LOGGING
-#include "TraceLogging.h"
-#endif
-
-using namespace js;
-using namespace js::gc;
-using namespace js::types;
-
-/* Some objects (e.g., With) delegate 'this' to another object. */
-static inline JSObject *
-CallThisObjectHook(JSContext *cx, HandleObject obj, Value *argv)
-{
-    JSObject *thisp = JSObject::thisObject(cx, obj);
-    if (!thisp)
-        return NULL;
-    argv[-1].setObject(*thisp);
-    return thisp;
-}
-
-/*
- * ECMA requires "the global object", but in embeddings such as the browser,
- * which have multiple top-level objects (windows, frames, etc. in the DOM),
- * we prefer fun's parent.  An example that causes this code to run:
- *
- *   // in window w1
- *   function f() { return this }
- *   function g() { return f }
- *
- *   // in window w2
- *   var h = w1.g()
- *   alert(h() == w1)
- *
- * The alert should display "true".
- */
-bool
-js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call)
-{
-    /*
-     * Check for SynthesizeFrame poisoning and fast constructors which
-     * didn't check their callee properly.
-     */
-    Value thisv = call.thisv();
-    JS_ASSERT(!thisv.isMagic());
-
-#ifdef DEBUG
-    JSFunction *fun = call.callee().isFunction() ? call.callee().toFunction() : NULL;
-    JS_ASSERT_IF(fun && fun->isInterpreted(), !fun->inStrictMode());
-#endif
-
-    if (thisv.isNullOrUndefined()) {
-        Rooted<GlobalObject*> global(cx, &call.callee().global());
-        JSObject *thisp = JSObject::thisObject(cx, global);
-        if (!thisp)
-            return false;
-        call.setThis(ObjectValue(*thisp));
-        return true;
-    }
-
-    if (!thisv.isObject()) {
-        if (!js_PrimitiveToObject(cx, &thisv))
-            return false;
-        call.setThis(thisv);
-    }
-
-    return true;
-}
-
-#if JS_HAS_NO_SUCH_METHOD
-
-const uint32_t JSSLOT_FOUND_FUNCTION  = 0;
-const uint32_t JSSLOT_SAVED_ID        = 1;
-
-Class js_NoSuchMethodClass = {
-    "NoSuchMethod",
-    JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS,
-    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
-    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
-};
-
-/*
- * When JSOP_CALLPROP or JSOP_CALLELEM does not find the method property of
- * the base object, we search for the __noSuchMethod__ method in the base.
- * If it exists, we store the method and the property's id into an object of
- * NoSuchMethod class and store this object into the callee's stack slot.
- * Later, Invoke will recognise such an object and transfer control to
- * NoSuchMethod that invokes the method like:
- *
- *   this.__noSuchMethod__(id, args)
- *
- * where id is the name of the method that this invocation attempted to
- * call by name, and args is an Array containing this invocation's actual
- * parameters.
- */
-bool
-js::OnUnknownMethod(JSContext *cx, HandleObject obj, Value idval_, MutableHandleValue vp)
-{
-    RootedValue idval(cx, idval_);
-
-    RootedId id(cx, NameToId(cx->names().noSuchMethod));
-    RootedValue value(cx);
-    if (!GetMethod(cx, obj, id, 0, &value))
-        return false;
-    TypeScript::MonitorUnknown(cx);
-
-    if (value.get().isPrimitive()) {
-        vp.set(value);
-    } else {
-#if JS_HAS_XML_SUPPORT
-        /* Extract the function name from function::name qname. */
-        if (idval.get().isObject()) {
-            JSObject *obj = &idval.get().toObject();
-            if (js_GetLocalNameFromFunctionQName(obj, id.address(), cx))
-                idval = IdToValue(id);
-        }
-#endif
-
-        JSObject *obj = NewObjectWithClassProto(cx, &js_NoSuchMethodClass, NULL, NULL);
-        if (!obj)
-            return false;
-
-        obj->setSlot(JSSLOT_FOUND_FUNCTION, value);
-        obj->setSlot(JSSLOT_SAVED_ID, idval);
-        vp.setObject(*obj);
-    }
-    return true;
-}
-
-static JSBool
-NoSuchMethod(JSContext *cx, unsigned argc, Value *vp)
-{
-    InvokeArgsGuard args;
-    if (!cx->stack.pushInvokeArgs(cx, 2, &args))
-        return JS_FALSE;
-
-    JS_ASSERT(vp[0].isObject());
-    JS_ASSERT(vp[1].isObject());
-    JSObject *obj = &vp[0].toObject();
-    JS_ASSERT(obj->getClass() == &js_NoSuchMethodClass);
-
-    args.setCallee(obj->getSlot(JSSLOT_FOUND_FUNCTION));
-    args.setThis(vp[1]);
-    args[0] = obj->getSlot(JSSLOT_SAVED_ID);
-    JSObject *argsobj = NewDenseCopiedArray(cx, argc, vp + 2);
-    if (!argsobj)
-        return JS_FALSE;
-    args[1].setObject(*argsobj);
-    JSBool ok = Invoke(cx, args);
-    vp[0] = args.rval();
-    return ok;
-}
-
-#endif /* JS_HAS_NO_SUCH_METHOD */
-
-bool
-js::ReportIsNotFunction(JSContext *cx, const Value &v, MaybeConstruct construct)
-{
-    unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
-
-    RootedValue val(cx, v);
-    js_ReportValueError3(cx, error, JSDVG_SEARCH_STACK, val, NullPtr(), NULL, NULL);
-    return false;
-}
-
-bool
-js::ReportIsNotFunction(JSContext *cx, const Value *vp, MaybeConstruct construct)
-{
-    ptrdiff_t spIndex = cx->stack.spIndexOf(vp);
-    unsigned error = construct ? JSMSG_NOT_CONSTRUCTOR : JSMSG_NOT_FUNCTION;
-
-    RootedValue val(cx, *vp);
-    js_ReportValueError3(cx, error, spIndex, val, NullPtr(), NULL, NULL);
-    return false;
-}
-
-JSObject *
-js::ValueToCallable(JSContext *cx, const Value *vp, MaybeConstruct construct)
-{
-    if (vp->isObject()) {
-        JSObject *callable = &vp->toObject();
-        if (callable->isCallable())
-            return callable;
-    }
-
-    ReportIsNotFunction(cx, vp, construct);
-    return NULL;
-}
-
-bool
-js::RunScript(JSContext *cx, HandleScript script, StackFrame *fp)
-{
-    JS_ASSERT(script);
-    JS_ASSERT(fp == cx->fp());
-    JS_ASSERT(fp->script() == script);
-    JS_ASSERT_IF(!fp->isGeneratorFrame(), cx->regs().pc == script->code);
-    JS_ASSERT_IF(fp->isEvalFrame(), script->isActiveEval);
-#ifdef JS_METHODJIT_SPEW
-    JMCheckLogging();
-#endif
-
-    JS_CHECK_RECURSION(cx, return false);
-
-#ifdef DEBUG
-    struct CheckStackBalance {
-        JSContext *cx;
-        StackFrame *fp;
-        RootedObject enumerators;
-        CheckStackBalance(JSContext *cx)
-          : cx(cx), fp(cx->fp()), enumerators(cx, cx->enumerators)
-        {}
-        ~CheckStackBalance() {
-            JS_ASSERT(fp == cx->fp());
-            JS_ASSERT_IF(!fp->isGeneratorFrame(), enumerators == cx->enumerators);
-        }
-    } check(cx);
-#endif
-
-    SPSEntryMarker marker(cx->runtime);
-
-#ifdef JS_ION
-    if (ion::IsEnabled(cx)) {
-        ion::MethodStatus status = ion::CanEnter(cx, script, fp, false);
-        if (status == ion::Method_Error)
-            return false;
-        if (status == ion::Method_Compiled) {
-            ion::IonExecStatus status = ion::Cannon(cx, fp);
-
-            // Note that if we bailed out, new inline frames may have been
-            // pushed, so we interpret with the current fp.
-            if (status == ion::IonExec_Bailout)
-                return Interpret(cx, fp, JSINTERP_REJOIN);
-
-            return status != ion::IonExec_Error;
-        }
-    }
-#endif
-
-#ifdef JS_METHODJIT
-    mjit::CompileStatus status;
-    status = mjit::CanMethodJIT(cx, script, script->code, fp->isConstructing(),
-                                mjit::CompileRequest_Interpreter, fp);
-    if (status == mjit::Compile_Error)
-        return false;
-
-    if (status == mjit::Compile_Okay)
-        return mjit::JaegerStatusToSuccess(mjit::JaegerShot(cx, false));
-#endif
-
-    return Interpret(cx, fp) != Interpret_Error;
-}
-
-/*
- * Find a function reference and its 'this' value implicit first parameter
- * under argc arguments on cx's stack, and call the function.  Push missing
- * required arguments, allocate declared local variables, and pop everything
- * when done.  Then push the return value.
- */
-bool
-js::InvokeKernel(JSContext *cx, CallArgs args, MaybeConstruct construct)
-{
-    JS_ASSERT(args.length() <= StackSpace::ARGS_LENGTH_MAX);
-    JS_ASSERT(!cx->compartment->activeAnalysis);
-
-    /* We should never enter a new script while cx->iterValue is live. */
-    JS_ASSERT(cx->iterValue.isMagic(JS_NO_ITER_VALUE));
-
-    /* MaybeConstruct is a subset of InitialFrameFlags */
-    InitialFrameFlags initial = (InitialFrameFlags) construct;
-
-    if (args.calleev().isPrimitive())
-        return ReportIsNotFunction(cx, args.calleev().address(), construct);
-
-    JSObject &callee = args.callee();
-    Class *clasp = callee.getClass();
-
-    /* Invoke non-functions. */
-    if (JS_UNLIKELY(clasp != &FunctionClass)) {
-#if JS_HAS_NO_SUCH_METHOD
-        if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
-            return NoSuchMethod(cx, args.length(), args.base());
-#endif
-        JS_ASSERT_IF(construct, !clasp->construct);
-        if (!clasp->call)
-            return ReportIsNotFunction(cx, args.calleev().address(), construct);
-        return CallJSNative(cx, clasp->call, args);
-    }
-
-    /* Invoke native functions. */
-    RootedFunction fun(cx, callee.toFunction());
-    JS_ASSERT_IF(construct, !fun->isNativeConstructor());
-    if (fun->isNative())
-        return CallJSNative(cx, fun->native(), args);
-
-    if (!TypeMonitorCall(cx, args, construct))
-        return false;
-
-    /* Get pointer to new frame/slots, prepare arguments. */
-    InvokeFrameGuard ifg;
-    if (!cx->stack.pushInvokeFrame(cx, args, initial, &ifg))
-        return false;
-
-    /* Run function until JSOP_STOP, JSOP_RETURN or error. */
-    RootedScript script(cx, fun->script());
-    JSBool ok = RunScript(cx, script, ifg.fp());
-
-    /* Propagate the return value out. */
-    args.rval().set(ifg.fp()->returnValue());
-    JS_ASSERT_IF(ok && construct, !args.rval().isPrimitive());
-    return ok;
-}
-
-bool
-js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, unsigned argc, Value *argv,
-           Value *rval)
-{
-    InvokeArgsGuard args;
-    if (!cx->stack.pushInvokeArgs(cx, argc, &args))
-        return false;
-
-    args.setCallee(fval);
-    args.setThis(thisv);
-    PodCopy(args.array(), argv, argc);
-
-    if (args.thisv().isObject()) {
-        /*
-         * We must call the thisObject hook in case we are not called from the
-         * interpreter, where a prior bytecode has computed an appropriate
-         * |this| already.
-         */
-        RootedObject thisObj(cx, &args.thisv().toObject());
-        JSObject *thisp = JSObject::thisObject(cx, thisObj);
-        if (!thisp)
-             return false;
-        args.setThis(ObjectValue(*thisp));
-    }
-
-    if (!Invoke(cx, args))
-        return false;
-
-    *rval = args.rval();
-    return true;
-}
-
-bool
-js::InvokeConstructorKernel(JSContext *cx, CallArgs args)
-{
-    JS_ASSERT(!FunctionClass.construct);
-
-    args.setThis(MagicValue(JS_IS_CONSTRUCTING));
-
-    if (!args.calleev().isObject())
-        return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
-
-    JSObject &callee = args.callee();
-    if (callee.isFunction()) {
-        JSFunction *fun = callee.toFunction();
-
-        if (fun->isNativeConstructor()) {
-            Probes::calloutBegin(cx, fun);
-            bool ok = CallJSNativeConstructor(cx, fun->native(), args);
-            Probes::calloutEnd(cx, fun);
-            return ok;
-        }
-
-        if (!fun->isInterpretedConstructor())
-            return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
-
-        if (!InvokeKernel(cx, args, CONSTRUCT))
-            return false;
-
-        JS_ASSERT(args.rval().isObject());
-        return true;
-    }
-
-    Class *clasp = callee.getClass();
-    if (!clasp->construct)
-        return ReportIsNotFunction(cx, args.calleev().address(), CONSTRUCT);
-
-    return CallJSNativeConstructor(cx, clasp->construct, args);
-}
-
-bool
-js::InvokeConstructor(JSContext *cx, const Value &fval, unsigned argc, Value *argv, Value *rval)
-{
-    InvokeArgsGuard args;
-    if (!cx->stack.pushInvokeArgs(cx, argc, &args))
-        return false;
-
-    args.setCallee(fval);
-    args.setThis(MagicValue(JS_THIS_POISON));
-    PodCopy(args.array(), argv, argc);
-
-    if (!InvokeConstructor(cx, args))
-        return false;
-
-    *rval = args.rval();
-    return true;
-}
-
-bool
-js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, unsigned argc, Value *argv,
-                         Value *rval)
-{
-    /*
-     * Invoke could result in another try to get or set the same id again, see
-     * bug 355497.
-     */
-    JS_CHECK_RECURSION(cx, return false);
-
-    return Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval);
-}
-
-bool
-js::ExecuteKernel(JSContext *cx, HandleScript script, JSObject &scopeChain, const Value &thisv,
-                  ExecuteType type, StackFrame *evalInFrame, Value *result)
-{
-    JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG);
-    JS_ASSERT_IF(type == EXECUTE_GLOBAL, !scopeChain.isScope());
-
-    if (script->isEmpty()) {
-        if (result)
-            result->setUndefined();
-        return true;
-    }
-
-    ExecuteFrameGuard efg;
-    if (!cx->stack.pushExecuteFrame(cx, script, thisv, scopeChain, type, evalInFrame, &efg))
-        return false;
-
-    if (!script->ensureRanAnalysis(cx))
-        return false;
-    TypeScript::SetThis(cx, script, efg.fp()->thisValue());
-
-    Probes::startExecution(script);
-    bool ok = RunScript(cx, script, efg.fp());
-    Probes::stopExecution(script);
-
-    /* Propgate the return value out. */
-    if (result)
-        *result = efg.fp()->returnValue();
-    return ok;
-}
-
-bool
-js::Execute(JSContext *cx, HandleScript script, JSObject &scopeChainArg, Value *rval)
-{
-    /* The scope chain could be anything, so innerize just in case. */
-    RootedObject scopeChain(cx, &scopeChainArg);
-    scopeChain = GetInnerObject(cx, scopeChain);
-    if (!scopeChain)
-        return false;
-
-    /* If we were handed a non-native object, complain bitterly. */
-    if (!scopeChain->isNative()) {
-        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NON_NATIVE_SCOPE);
-        return false;
-    }
-    JS_ASSERT(!scopeChain->getOps()->defineProperty);
-
-    /* The VAROBJFIX option makes varObj == globalObj in global code. */
-    if (!cx->hasRunOption(JSOPTION_VAROBJFIX)) {
-        if (!scopeChain->setVarObj(cx))
-            return false;
-    }
-
-    /* Use the scope chain as 'this', modulo outerization. */
-    JSObject *thisObj = JSObject::thisObject(cx, scopeChain);
-    if (!thisObj)
-        return false;
-    Value thisv = ObjectValue(*thisObj);
-
-    return ExecuteKernel(cx, script, *scopeChain, thisv, EXECUTE_GLOBAL,
-                         NULL /* evalInFrame */, rval);
-}
-
-bool
-js::HasInstance(JSContext *cx, HandleObject obj, HandleValue v, JSBool *bp)
-{
-    Class *clasp = obj->getClass();
-    RootedValue local(cx, v);
-    if (clasp->hasInstance)
-        return clasp->hasInstance(cx, obj, &local, bp);
-
-    RootedValue val(cx, ObjectValue(*obj));
-    js_ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS,
-                        JSDVG_SEARCH_STACK, val, NullPtr());
-    return JS_FALSE;
-}
-
-bool
-js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, bool *result)
-{
-#if JS_HAS_XML_SUPPORT
-    if (JS_UNLIKELY(lval.isObject() && lval.toObject().isXML()) ||
-                    (rval.isObject() && rval.toObject().isXML())) {
-        JSBool res;
-        if (!js_TestXMLEquality(cx, lval, rval, &res))
-            return false;
-        *result = !!res;
-        return true;
-    }
-#endif
-
-    if (SameType(lval, rval)) {
-        if (lval.isString()) {
-            JSString *l = lval.toString();
-            JSString *r = rval.toString();
-            return EqualStrings(cx, l, r, result);
-        }
-
-        if (lval.isDouble()) {
-            double l = lval.toDouble(), r = rval.toDouble();
-            *result = (l == r);
-            return true;
-        }
-
-        if (lval.isObject()) {
-            JSObject *l = &lval.toObject();
-            JSObject *r = &rval.toObject();
-
-            if (JSEqualityOp eq = l->getClass()->ext.equality) {
-                JSBool res;
-                RootedObject lobj(cx, l);
-                RootedValue r(cx, rval);
-                if (!eq(cx, lobj, r, &res))
-                    return false;
-                *result = !!res;
-                return true;
-            }
-
-            *result = l == r;
-            return true;
-        }
-
-        *result = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
-        return true;
-    }
-
-    if (lval.isNullOrUndefined()) {
-        *result = rval.isNullOrUndefined();
-        return true;
-    }
-
-    if (rval.isNullOrUndefined()) {
-        *result = false;
-        return true;
-    }
-
-    RootedValue lvalue(cx, lval);
-    RootedValue rvalue(cx, rval);
-
-    if (!ToPrimitive(cx, lvalue.address()))
-        return false;
-    if (!ToPrimitive(cx, rvalue.address()))
-        return false;
-
-    if (lvalue.get().isString() && rvalue.get().isString()) {
-        JSString *l = lvalue.get().toString();
-        JSString *r = rvalue.get().toString();
-        return EqualStrings(cx, l, r, result);
-    }
-
-    double l, r;
-    if (!ToNumber(cx, lvalue, &l) || !ToNumber(cx, rvalue, &r))
-        return false;
-    *result = (l == r);
-    return true;
-}
-
-bool
-js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, bool *equal)
-{
-    Value lval = lref, rval = rref;
-    if (SameType(lval, rval)) {
-        if (lval.isString())
-            return EqualStrings(cx, lval.toString(), rval.toString(), equal);
-        if (lval.isDouble()) {
-            *equal = (lval.toDouble() == rval.toDouble());
-            return true;
-        }
-        if (lval.isObject()) {
-            *equal = lval.toObject() == rval.toObject();
-            return true;
-        }
-        if (lval.isUndefined()) {
-            *equal = true;
-            return true;
-        }
-        *equal = lval.payloadAsRawUint32() == rval.payloadAsRawUint32();
-        return true;
-    }
-
-    if (lval.isDouble() && rval.isInt32()) {
-        double ld = lval.toDouble();
-        double rd = rval.toInt32();
-        *equal = (ld == rd);
-        return true;
-    }
-    if (lval.isInt32() && rval.isDouble()) {
-        double ld = lval.toInt32();
-        double rd = rval.toDouble();
-        *equal = (ld == rd);
-        return true;
-    }
-
-    *equal = false;
-    return true;
-}
-
-static inline bool
-IsNegativeZero(const Value &v)
-{
-    return v.isDouble() && MOZ_DOUBLE_IS_NEGATIVE_ZERO(v.toDouble());
-}
-
-static inline bool
-IsNaN(const Value &v)
-{
-    return v.isDouble() && MOZ_DOUBLE_IS_NaN(v.toDouble());
-}
-
-bool
-js::SameValue(JSContext *cx, const Value &v1, const Value &v2, bool *same)
-{
-    if (IsNegativeZero(v1)) {
-        *same = IsNegativeZero(v2);
-        return true;
-    }
-    if (IsNegativeZero(v2)) {
-        *same = false;
-        return true;
-    }
-    if (IsNaN(v1) && IsNaN(v2)) {
-        *same = true;
-        return true;
-    }
-    return StrictlyEqual(cx, v1, v2, same);
-}
-
-JSType
-js::TypeOfValue(JSContext *cx, const Value &vref)
-{
-    Value v = vref;
-    if (v.isNumber())
-        return JSTYPE_NUMBER;
-    if (v.isString())
-        return JSTYPE_STRING;
-    if (v.isNull())
-        return JSTYPE_OBJECT;
-    if (v.isUndefined())
-        return JSTYPE_VOID;
-    if (v.isObject()) {
-        RootedObject obj(cx, &v.toObject());
-        return JSObject::typeOf(cx, obj);
-    }
-    JS_ASSERT(v.isBoolean());
-    return JSTYPE_BOOLEAN;
-}
-
-/*
- * Enter the new with scope using an object at sp[-1] and associate the depth
- * of the with block with sp + stackIndex.
- */
-static bool
-EnterWith(JSContext *cx, int stackIndex)
-{
-    StackFrame *fp = cx->fp();
-    Value *sp = cx->regs().sp;
-    JS_ASSERT(stackIndex < 0);
-    JS_ASSERT(int(cx->regs().stackDepth()) + stackIndex >= 0);
-
-    RootedObject obj(cx);
-    if (sp[-1].isObject()) {
-        obj = &sp[-1].toObject();
-    } else {
-        obj = js_ValueToNonNullObject(cx, sp[-1]);
-        if (!obj)
-            return false;
-        sp[-1].setObject(*obj);
-    }
-
-    WithObject *withobj = WithObject::create(cx, obj, fp->scopeChain(),
-                                             cx->regs().stackDepth() + stackIndex);
-    if (!withobj)
-        return false;
-
-    fp->pushOnScopeChain(*withobj);
-    return true;
-}
-
-/* Unwind block and scope chains to match the given depth. */
-void
-js::UnwindScope(JSContext *cx, uint32_t stackDepth)
-{
-    StackFrame *fp = cx->fp();
-    JS_ASSERT(stackDepth <= cx->regs().stackDepth());
-
-    for (ScopeIter si(fp, cx); !si.done(); ++si) {
-        switch (si.type()) {
-          case ScopeIter::Block:
-            if (si.staticBlock().stackDepth() < stackDepth)
-                return;
-            fp->popBlock(cx);
-            break;
-          case ScopeIter::With:
-            if (si.scope().asWith().stackDepth() < stackDepth)
-                return;
-            fp->popWith(cx);
-            break;
-          case ScopeIter::Call:
-          case ScopeIter::StrictEvalScope:
-            break;
-        }
-    }
-}
-
-void
-js::UnwindForUncatchableException(JSContext *cx, const FrameRegs &regs)
-{
-    /* c.f. the regular (catchable) TryNoteIter loop in Interpret. */
-    for (TryNoteIter tni(regs); !tni.done(); ++tni) {
-        JSTryNote *tn = *tni;
-        if (tn->kind == JSTRY_ITER) {
-            Value *sp = regs.spForStackDepth(tn->stackDepth);
-            UnwindIteratorForUncatchableException(cx, &sp[-1].toObject());
-        }
-    }
-}
-
-TryNoteIter::TryNoteIter(const FrameRegs &regs)
-  : regs(regs),
-    script(regs.fp()->script().unsafeGet()),
-    pcOffset(regs.pc - script->main())
-{
-    if (script->hasTrynotes()) {
-        tn = script->trynotes()->vector;
-        tnEnd = tn + script->trynotes()->length;
-    } else {
-        tn = tnEnd = NULL;
-    }
-    settle();
-}
-
-void
-TryNoteIter::operator++()
-{
-    ++tn;
-    settle();
-}
-
-bool
-TryNoteIter::done() const
-{
-    return tn == tnEnd;
-}
-
-void
-TryNoteIter::settle()
-{
-    for (; tn != tnEnd; ++tn) {
-        /* If pc is out of range, try the next one. */
-        if (pcOffset - tn->start >= tn->length)
-            continue;
-
-        /*
-         * We have a note that covers the exception pc but we must check
-         * whether the interpreter has already executed the corresponding
-         * handler. This is possible when the executed bytecode implements
-         * break or return from inside a for-in loop.
-         *
-         * In this case the emitter generates additional [enditer] and [gosub]
-         * opcodes to close all outstanding iterators and execute the finally
-         * blocks. If such an [enditer] throws an exception, its pc can still
-         * be inside several nested for-in loops and try-finally statements
-         * even if we have already closed the corresponding iterators and
-         * invoked the finally blocks.
-         *
-         * To address this, we make [enditer] always decrease the stack even
-         * when its implementation throws an exception. Thus already executed
-         * [enditer] and [gosub] opcodes will have try notes with the stack
-         * depth exceeding the current one and this condition is what we use to
-         * filter them out.
-         */
-        if (tn->stackDepth <= regs.stackDepth())
-            break;
-    }
-}
-
-/*
- * Increment/decrement the value 'v'. The resulting value is stored in *slot.
- * The result of the expression (taking into account prefix/postfix) is stored
- * in *expr.
- */
-static bool
-DoIncDec(JSContext *cx, HandleScript script, jsbytecode *pc, const Value &v, Value *slot, Value *expr)
-{
-    const JSCodeSpec &cs = js_CodeSpec[*pc];
-
-    if (v.isInt32()) {
-        int32_t i = v.toInt32();
-        if (i > JSVAL_INT_MIN && i < JSVAL_INT_MAX) {
-            int32_t sum = i + (cs.format & JOF_INC ? 1 : -1);
-            *slot = Int32Value(sum);
-            *expr = (cs.format & JOF_POST) ? Int32Value(i) : *slot;
-            return true;
-        }
-    }
-
-    double d;
-    if (!ToNumber(cx, v, &d))
-        return false;
-
-    double sum = d + (cs.format & JOF_INC ? 1 : -1);
-    *slot = NumberValue(sum);
-    *expr = (cs.format & JOF_POST) ? NumberValue(d) : *slot;
-
-    TypeScript::MonitorOverflow(cx, script, pc);
-    return true;
-}
-
-#define PUSH_COPY(v)             do { *regs.sp++ = v; assertSameCompartment(cx, regs.sp[-1]); } while (0)
-#define PUSH_COPY_SKIP_CHECK(v)  *regs.sp++ = v
-#define PUSH_NULL()              regs.sp++->setNull()
-#define PUSH_UNDEFINED()         regs.sp++->setUndefined()
-#define PUSH_BOOLEAN(b)          regs.sp++->setBoolean(b)
-#define PUSH_DOUBLE(d)           regs.sp++->setDouble(d)
-#define PUSH_INT32(i)            regs.sp++->setInt32(i)
-#define PUSH_STRING(s)           do { regs.sp++->setString(s); assertSameCompartment(cx, regs.sp[-1]); } while (0)
-#define PUSH_OBJECT(obj)         do { regs.sp++->setObject(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
-#define PUSH_OBJECT_OR_NULL(obj) do { regs.sp++->setObjectOrNull(obj); assertSameCompartment(cx, regs.sp[-1]); } while (0)
-#define PUSH_HOLE()              regs.sp++->setMagic(JS_ARRAY_HOLE)
-#define POP_COPY_TO(v)           v = *--regs.sp
-#define POP_RETURN_VALUE()       regs.fp()->setReturnValue(*--regs.sp)
-
-#define FETCH_OBJECT(cx, n, obj)                                              \
-    JS_BEGIN_MACRO                                                            \
-        HandleValue val = HandleValue::fromMarkedLocation(&regs.sp[n]);       \
-        obj = ToObject(cx, (val));                                            \
-        if (!obj)                                                             \
-            goto error;                                                       \
-    JS_END_MACRO
-
-template<typename T>
-class GenericInterruptEnabler : public InterpreterFrames::InterruptEnablerBase {
-  public:
-    GenericInterruptEnabler(T *variable, T value) : variable(variable), value(value) { }
-    void enable() const { *variable = value; }
-
-  private:
-    T *variable;
-    T value;
-};
-
-inline InterpreterFrames::InterpreterFrames(JSContext *cx, FrameRegs *regs,
-                                            const InterruptEnablerBase &enabler)
-  : context(cx), regs(regs), enabler(enabler)
-{
-    older = cx->runtime->interpreterFrames;
-    cx->runtime->interpreterFrames = this;
-}
-
-inline InterpreterFrames::~InterpreterFrames()
-{
-    context->runtime->interpreterFrames = older;
-}
-
-#if defined(DEBUG) && !defined(JS_THREADSAFE) && !defined(JSGC_ROOT_ANALYSIS)
-void
-js::AssertValidPropertyCacheHit(JSContext *cx, JSObject *start_,
-                                JSObject *found, PropertyCacheEntry *entry)
-{
-    jsbytecode *pc;
-    JSScript *script = cx->stack.currentScript(&pc);
-
-    uint64_t sample = cx->runtime->gcNumber;
-    PropertyCacheEntry savedEntry = *entry;
-
-    RootedPropertyName name(cx, GetNameFromBytecode(cx, script, pc, JSOp(*pc)));
-    RootedObject start(cx, start_);
-    RootedObject pobj(cx);
-    RootedShape prop(cx);
-    bool ok = baseops::LookupProperty(cx, start, name, &pobj, &prop);
-    JS_ASSERT(ok);
-
-    if (cx->runtime->gcNumber != sample)
-        cx->propertyCache().restore(&savedEntry);
-    JS_ASSERT(prop);
-    JS_ASSERT(pobj == found);
-    JS_ASSERT(entry->prop == prop);
-}
-#endif /* DEBUG && !JS_THREADSAFE */
-
-/*
- * Ensure that the intrepreter switch can close call-bytecode cases in the
- * same way as non-call bytecodes.
- */
-JS_STATIC_ASSERT(JSOP_NAME_LENGTH == JSOP_CALLNAME_LENGTH);
-JS_STATIC_ASSERT(JSOP_GETARG_LENGTH == JSOP_CALLARG_LENGTH);
-JS_STATIC_ASSERT(JSOP_GETLOCAL_LENGTH == JSOP_CALLLOCAL_LENGTH);
-JS_STATIC_ASSERT(JSOP_XMLNAME_LENGTH == JSOP_CALLXMLNAME_LENGTH);
-
-/*
- * Same for JSOP_SETNAME and JSOP_SETPROP, which differ only slightly but
- * remain distinct for the decompiler.
- */
-JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
-
-/* See TRY_BRANCH_AFTER_COND. */
-JS_STATIC_ASSERT(JSOP_IFNE_LENGTH == JSOP_IFEQ_LENGTH);
-JS_STATIC_ASSERT(JSOP_IFNE == JSOP_IFEQ + 1);
-
-/* For the fastest case inder JSOP_INCNAME, etc. */
-JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_DECNAME_LENGTH);
-JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEINC_LENGTH);
-JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH);
-
-/*
- * Inline fast paths for iteration. js_IteratorMore and js_IteratorNext handle
- * all cases, but we inline the most frequently taken paths here.
- */
-static inline bool
-IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, MutableHandleValue rval)
-{
-    if (iterobj->isPropertyIterator()) {
-        NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
-        if (ni->isKeyIter()) {
-            *cond = (ni->props_cursor < ni->props_end);
-            return true;
-        }
-    }
-    Rooted<JSObject*> iobj(cx, iterobj);
-    if (!js_IteratorMore(cx, iobj, rval))
-        return false;
-    *cond = rval.isTrue();
-    return true;
-}
-
-static inline bool
-IteratorNext(JSContext *cx, HandleObject iterobj, MutableHandleValue rval)
-{
-    if (iterobj->isPropertyIterator()) {
-        NativeIterator *ni = iterobj->asPropertyIterator().getNativeIterator();
-        if (ni->isKeyIter()) {
-            JS_ASSERT(ni->props_cursor < ni->props_end);
-            rval.setString(*ni->current());
-            ni->incCursor();
-            return true;
-        }
-    }
-    return js_IteratorNext(cx, iterobj, rval);
-}
-
-/*
- * For bytecodes which push values and then fall through, make sure the
- * types of the pushed values are consistent with type inference information.
- */
-static inline void
-TypeCheckNextBytecode(JSContext *cx, HandleScript script, unsigned n, const FrameRegs &regs)
-{
-#ifdef DEBUG
-    if (cx->typeInferenceEnabled() && n == GetBytecodeLength(regs.pc))
-        TypeScript::CheckBytecode(cx, script, regs.pc, regs.sp);
-#endif
-}
-
-JS_NEVER_INLINE InterpretStatus
-js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode)
-{
-    JSAutoResolveFlags rf(cx, RESOLVE_INFER);
-
-    if (interpMode == JSINTERP_NORMAL)
-        gc::MaybeVerifyBarriers(cx, true);
-
-    JS_ASSERT(!cx->compartment->activeAnalysis);
-
-#define CHECK_PCCOUNT_INTERRUPTS() JS_ASSERT_IF(script->hasScriptCounts, switchMask == -1)
-
-    register int switchMask = 0;
-    int switchOp;
-    typedef GenericInterruptEnabler<int> InterruptEnabler;
-    InterruptEnabler interrupts(&switchMask, -1);
-
-# define DO_OP()            goto do_op
-# define DO_NEXT_OP(n)      JS_BEGIN_MACRO                                    \
-                                JS_ASSERT((n) == len);                        \
-                                goto advance_pc;                              \
-                            JS_END_MACRO
-
-# define BEGIN_CASE(OP)     case OP:
-# define END_CASE(OP)       END_CASE_LEN(OP##_LENGTH)
-# define END_CASE_LEN(n)    END_CASE_LENX(n)
-# define END_CASE_LENX(n)   END_CASE_LEN##n
-
-/*
- * To share the code for all len == 1 cases we use the specialized label with
- * code that falls through to advance_pc: .
- */
-# define END_CASE_LEN1      goto advance_pc_by_one;
-# define END_CASE_LEN2      len = 2; goto advance_pc;
-# define END_CASE_LEN3      len = 3; goto advance_pc;
-# define END_CASE_LEN4      len = 4; goto advance_pc;
-# define END_CASE_LEN5      len = 5; goto advance_pc;
-# define END_CASE_LEN6      len = 6; goto advance_pc;
-# define END_CASE_LEN7      len = 7; goto advance_pc;
-# define END_CASE_LEN8      len = 8; goto advance_pc;
-# define END_CASE_LEN9      len = 9; goto advance_pc;
-# define END_CASE_LEN10     len = 10; goto advance_pc;
-# define END_CASE_LEN11     len = 11; goto advance_pc;
-# define END_CASE_LEN12     len = 12; goto advance_pc;
-# define END_VARLEN_CASE    goto advance_pc;
-# define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
-# define END_EMPTY_CASES    goto advance_pc_by_one;
-
-#define LOAD_DOUBLE(PCOFF, dbl)                                               \
-    (dbl = script->getConst(GET_UINT32_INDEX(regs.pc + (PCOFF))).toDouble())
-
-#ifdef JS_METHODJIT
-
-#define CHECK_PARTIAL_METHODJIT(status)                                       \
-    JS_BEGIN_MACRO                                                            \
-        switch (status) {                                                     \
-          case mjit::Jaeger_UnfinishedAtTrap:                                 \
-            interpMode = JSINTERP_SKIP_TRAP;                                  \
-            /* FALLTHROUGH */                                                 \
-          case mjit::Jaeger_Unfinished:                                       \
-            op = (JSOp) *regs.pc;                                             \
-            SET_SCRIPT(regs.fp()->script());                                  \
-            if (cx->isExceptionPending())                                     \
-                goto error;                                                   \
-            DO_OP();                                                          \
-          default:;                                                           \
-        }                                                                     \
-    JS_END_MACRO
-#endif
-
-    /*
-     * Prepare to call a user-supplied branch handler, and abort the script
-     * if it returns false.
-     */
-#define CHECK_BRANCH()                                                        \
-    JS_BEGIN_MACRO                                                            \
-        if (cx->runtime->interrupt && !js_HandleExecutionInterrupt(cx))       \
-            goto error;                                                       \
-    JS_END_MACRO
-
-#define BRANCH(n)                                                             \
-    JS_BEGIN_MACRO                                                            \
-        regs.pc += (n);                                                       \
-        op = (JSOp) *regs.pc;                                                 \
-        if ((n) <= 0)                                                         \
-            goto check_backedge;                                              \
-        DO_OP();                                                              \
-    JS_END_MACRO
-
-#define SET_SCRIPT(s)                                                         \
-    JS_BEGIN_MACRO                                                            \
-        EnterAssertNoGCScope();                                               \
-        script = (s);                                                         \
-        if (script->hasAnyBreakpointsOrStepMode() || script->hasScriptCounts) \
-            interrupts.enable();                                              \
-        JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP,                        \
-                     script->hasAnyBreakpointsOrStepMode());                  \
-        LeaveAssertNoGCScope();                                               \
-    JS_END_MACRO
-
-    /* Repoint cx->regs to a local variable for faster access. */
-    FrameRegs regs = cx->regs();
-    PreserveRegsGuard interpGuard(cx, regs);
-
-    /*
-     * Help Debugger find frames running scripts that it has put in
-     * single-step mode.
-     */
-    InterpreterFrames interpreterFrame(cx, &regs, interrupts);
-
-    /* Copy in hot values that change infrequently. */
-    JSRuntime *const rt = cx->runtime;
-    RootedScript script(cx);
-    SET_SCRIPT(regs.fp()->script());
-
-    /* Reset the loop count on the script we're entering. */
-    script->resetLoopCount();
-
-#if JS_TRACE_LOGGING
-    AutoTraceLog logger(TraceLogging::defaultLogger(),
-                        TraceLogging::INTERPRETER_START,
-                        TraceLogging::INTERPRETER_STOP,
-                        script);
-#endif
-
-    /*
-     * Pool of rooters for use in this interpreter frame. References to these
-     * are used for local variables within interpreter cases. This avoids
-     * creating new rooters each time an interpreter case is entered, and also
-     * correctness pitfalls due to incorrect compilation of destructor calls
-     * around computed gotos.
-     */
-    RootedValue rootValue0(cx), rootValue1(cx);
-    RootedString rootString0(cx), rootString1(cx);
-    RootedObject rootObject0(cx), rootObject1(cx), rootObject2(cx);
-    RootedFunction rootFunction0(cx);
-    RootedTypeObject rootType0(cx);
-    RootedPropertyName rootName0(cx);
-    RootedId rootId0(cx);
-    RootedShape rootShape0(cx);
-    DebugOnly<uint32_t> blockDepth;
-
-    if (!entryFrame)
-        entryFrame = regs.fp();
-
-#if JS_HAS_GENERATORS
-    if (JS_UNLIKELY(regs.fp()->isGeneratorFrame())) {
-        JS_ASSERT(size_t(regs.pc - script->code) <= script->length);
-        JS_ASSERT(regs.stackDepth() <= script->nslots);
-
-        /*
-         * To support generator_throw and to catch ignored exceptions,
-         * fail if cx->isExceptionPending() is true.
-         */
-        if (cx->isExceptionPending()) {
-            Probes::enterScript(cx, script, script->function(), regs.fp());
-            goto error;
-        }
-    }
-#endif
-
-    /* State communicated between non-local jumps: */
-    bool interpReturnOK;
-
-    /* Don't call the script prologue if executing between Method and Trace JIT. */
-    if (interpMode == JSINTERP_NORMAL) {
-        StackFrame *fp = regs.fp();
-        if (!fp->isGeneratorFrame()) {
-            if (!fp->prologue(cx, UseNewTypeAtEntry(cx, fp)))
-                goto error;
-        } else {
-            Probes::enterScript(cx, script, script->function(), fp);
-        }
-        if (cx->compartment->debugMode()) {
-            JSTrapStatus status = ScriptDebugPrologue(cx, fp);
-            switch (status) {
-              case JSTRAP_CONTINUE:
-                break;
-              case JSTRAP_RETURN:
-                interpReturnOK = true;
-                goto forced_return;
-              case JSTRAP_THROW:
-              case JSTRAP_ERROR:
-                goto error;
-              default:
-                JS_NOT_REACHED("bad ScriptDebugPrologue status");
-            }
-        }
-    }
-
-    /* The REJOIN mode acts like the normal mode, except the prologue is skipped. */
-    if (interpMode == JSINTERP_REJOIN)
-        interpMode = JSINTERP_NORMAL;
-
-    /*
-     * 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
-     * "op" correctly in all other cases.
-     */
-    JSOp op;
-    int32_t len;
-    len = 0;
-
-    if (rt->profilingScripts || cx->runtime->debugHooks.interruptHook)
-        interrupts.enable();
-
-    DO_NEXT_OP(len);
-
-    for (;;) {
-      advance_pc_by_one:
-        JS_ASSERT(js_CodeSpec[op].length == 1);
-        len = 1;
-      advance_pc:
-        TypeCheckNextBytecode(cx, script, len, regs);
-        js::gc::MaybeVerifyBarriers(cx);
-        regs.pc += len;
-        op = (JSOp) *regs.pc;
-
-      do_op:
-        CHECK_PCCOUNT_INTERRUPTS();
-        switchOp = int(op) | switchMask;
-      do_switch:
-        switch (switchOp) {
-
-  case -1:
-    JS_ASSERT(switchMask == -1);
-    {
-        bool moreInterrupts = false;
-
-        if (cx->runtime->profilingScripts) {
-            if (!script->hasScriptCounts)
-                script->initScriptCounts(cx);
-            moreInterrupts = true;
-        }
-
-        if (script->hasScriptCounts) {
-            PCCounts counts = script->getPCCounts(regs.pc);
-            counts.get(PCCounts::BASE_INTERP)++;
-            moreInterrupts = true;
-        }
-
-        JSInterruptHook hook = cx->runtime->debugHooks.interruptHook;
-        if (hook || script->stepModeEnabled()) {
-            Value rval;
-            JSTrapStatus status = JSTRAP_CONTINUE;
-            if (hook)
-                status = hook(cx, script, regs.pc, &rval, cx->runtime->debugHooks.interruptHookData);
-            if (status == JSTRAP_CONTINUE && script->stepModeEnabled())
-                status = Debugger::onSingleStep(cx, &rval);
-            switch (status) {
-              case JSTRAP_ERROR:
-                goto error;
-              case JSTRAP_CONTINUE:
-                break;
-              case JSTRAP_RETURN:
-                regs.fp()->setReturnValue(rval);
-                interpReturnOK = true;
-                goto forced_return;
-              case JSTRAP_THROW:
-                cx->setPendingException(rval);
-                goto error;
-              default:;
-            }
-            moreInterrupts = true;
-        }
-
-        if (script->hasAnyBreakpointsOrStepMode())
-            moreInterrupts = true;
-
-        if (script->hasBreakpointsAt(regs.pc) && interpMode != JSINTERP_SKIP_TRAP) {
-            Value rval;
-            JSTrapStatus status = Debugger::onTrap(cx, &rval);
-            switch (status) {
-              case JSTRAP_ERROR:
-                goto error;
-              case JSTRAP_RETURN:
-                regs.fp()->setReturnValue(rval);
-                interpReturnOK = true;
-                goto forced_return;
-              case JSTRAP_THROW:
-                cx->setPendingException(rval);
-                goto error;
-              default:
-                break;
-            }
-            JS_ASSERT(status == JSTRAP_CONTINUE);
-            JS_ASSERT(rval.isInt32() && rval.toInt32() == op);
-        }
-
-        interpMode = JSINTERP_NORMAL;
-
-        switchMask = moreInterrupts ? -1 : 0;
-        switchOp = int(op);
-        goto do_switch;
-    }
-
-/* No-ops for ease of decompilation. */
-ADD_EMPTY_CASE(JSOP_NOP)
-ADD_EMPTY_CASE(JSOP_UNUSED1)
-ADD_EMPTY_CASE(JSOP_UNUSED2)
-ADD_EMPTY_CASE(JSOP_UNUSED3)
-ADD_EMPTY_CASE(JSOP_UNUSED10)
-ADD_EMPTY_CASE(JSOP_UNUSED11)
-ADD_EMPTY_CASE(JSOP_UNUSED12)
-ADD_EMPTY_CASE(JSOP_UNUSED13)
-ADD_EMPTY_CASE(JSOP_UNUSED15)
-ADD_EMPTY_CASE(JSOP_UNUSED17)
-ADD_EMPTY_CASE(JSOP_UNUSED18)
-ADD_EMPTY_CASE(JSOP_UNUSED19)
-ADD_EMPTY_CASE(JSOP_UNUSED20)
-ADD_EMPTY_CASE(JSOP_UNUSED21)
-ADD_EMPTY_CASE(JSOP_UNUSED22)
-ADD_EMPTY_CASE(JSOP_UNUSED23)
-ADD_EMPTY_CASE(JSOP_UNUSED24)
-ADD_EMPTY_CASE(JSOP_UNUSED25)
-ADD_EMPTY_CASE(JSOP_UNUSED29)
-ADD_EMPTY_CASE(JSOP_UNUSED30)
-ADD_EMPTY_CASE(JSOP_UNUSED31)
-ADD_EMPTY_CASE(JSOP_CONDSWITCH)
-ADD_EMPTY_CASE(JSOP_TRY)
-#if JS_HAS_XML_SUPPORT
-ADD_EMPTY_CASE(JSOP_STARTXML)
-ADD_EMPTY_CASE(JSOP_STARTXMLEXPR)
-#endif
-END_EMPTY_CASES
-
-BEGIN_CASE(JSOP_LOOPHEAD)
-
-    script->incrLoopCount();
-
-END_CASE(JSOP_LOOPHEAD)
-
-BEGIN_CASE(JSOP_LABEL)
-END_CASE(JSOP_LABEL)
-
-check_backedge:
-{
-    CHECK_BRANCH();
-    if (op != JSOP_LOOPHEAD)
-        DO_OP();
-
-#ifdef JS_METHODJIT
-    // Attempt on-stack replacement with JaegerMonkey code, which is keyed to
-    // the interpreter state at the JSOP_LOOPHEAD at the start of the loop.
-    // Unlike IonMonkey, this requires two different code fragments to perform
-    // hoisting.
-    mjit::CompileStatus status =
-        mjit::CanMethodJIT(cx, script, regs.pc, regs.fp()->isConstructing(),
-                           mjit::CompileRequest_Interpreter, regs.fp());
-    if (status == mjit::Compile_Error)
-        goto error;
-    if (status == mjit::Compile_Okay) {
-        void *ncode =
-            script->nativeCodeForPC(regs.fp()->isConstructing(), regs.pc);
-        JS_ASSERT(ncode);
-        mjit::JaegerStatus status = mjit::JaegerShotAtSafePoint(cx, ncode, true);
-        if (status == mjit::Jaeger_ThrowBeforeEnter)
-            goto error;
-        CHECK_PARTIAL_METHODJIT(status);
-        interpReturnOK = (status == mjit::Jaeger_Returned);
-        if (entryFrame != regs.fp())
-            goto jit_return;
-        regs.fp()->setFinishedInInterpreter();
-        goto leave_on_safe_point;
-    }
-#endif /* JS_METHODJIT */
-
-    DO_OP();
-}
-
-BEGIN_CASE(JSOP_LOOPENTRY)
-
-#ifdef JS_ION
-    // Attempt on-stack replacement with Ion code. IonMonkey OSR takes place at
-    // the point of the initial loop entry, to consolidate hoisted code between
-    // entry points.
-    if (ion::IsEnabled(cx)) {
-        ion::MethodStatus status =
-            ion::CanEnterAtBranch(cx, script, regs.fp(), regs.pc);
-        if (status == ion::Method_Error)
-            goto error;
-        if (status == ion::Method_Compiled) {
-            ion::IonExecStatus maybeOsr = ion::SideCannon(cx, regs.fp(), regs.pc);
-            if (maybeOsr == ion::IonExec_Bailout) {
-                // We hit a deoptimization path in the first Ion frame, so now
-                // we've just replaced the entire Ion activation.
-                SET_SCRIPT(regs.fp()->script());
-                op = JSOp(*regs.pc);
-                DO_OP();
-            }
-
-            interpReturnOK = (maybeOsr == ion::IonExec_Ok);
-
-            if (entryFrame != regs.fp())
-                goto jit_return;
-
-            regs.fp()->setFinishedInInterpreter();
-            goto leave_on_safe_point;
-        }
-    }
-#endif /* JS_ION */
-
-END_CASE(JSOP_LOOPENTRY)
-
-BEGIN_CASE(JSOP_NOTEARG)
-END_CASE(JSOP_NOTEARG)
-
-/* ADD_EMPTY_CASE is not used here as JSOP_LINENO_LENGTH == 3. */
-BEGIN_CASE(JSOP_LINENO)
-END_CASE(JSOP_LINENO)
-
-BEGIN_CASE(JSOP_UNDEFINED)
-    PUSH_UNDEFINED();
-END_CASE(JSOP_UNDEFINED)
-
-BEGIN_CASE(JSOP_POP)
-    regs.sp--;
-END_CASE(JSOP_POP)
-
-BEGIN_CASE(JSOP_POPN)
-    JS_ASSERT(GET_UINT16(regs.pc) <= regs.stackDepth());
-    regs.sp -= GET_UINT16(regs.pc);
-#ifdef DEBUG
-    if (StaticBlockObject *block = regs.fp()->maybeBlockChain())
-        JS_ASSERT(regs.stackDepth() >= block->stackDepth() + block->slotCount());
-#endif
-END_CASE(JSOP_POPN)
-
-BEGIN_CASE(JSOP_SETRVAL)
-BEGIN_CASE(JSOP_POPV)
-    POP_RETURN_VALUE();
-END_CASE(JSOP_POPV)
-
-BEGIN_CASE(JSOP_ENTERWITH)
-    if (!EnterWith(cx, -1))
-        goto error;
-
-    /*
-     * We must ensure that different "with" blocks have different stack depth
-     * associated with them. This allows the try handler search to properly
-     * recover the scope chain. Thus we must keep the stack at least at the
-     * current level.
-     *
-     * We set sp[-1] to the current "with" object to help asserting the
-     * enter/leave balance in [leavewith].
-     */
-    regs.sp[-1].setObject(*regs.fp()->scopeChain());
-END_CASE(JSOP_ENTERWITH)
-
-BEGIN_CASE(JSOP_LEAVEWITH)
-    JS_ASSERT(regs.sp[-1].toObject() == *regs.fp()->scopeChain());
-    regs.fp()->popWith(cx);
-    regs.sp--;
-END_CASE(JSOP_LEAVEWITH)
-
-BEGIN_CASE(JSOP_RETURN)
-    POP_RETURN_VALUE();
-    /* FALL THROUGH */
-
-BEGIN_CASE(JSOP_RETRVAL)    /* fp return value already set */
-BEGIN_CASE(JSOP_STOP)
-{
-    /*
-     * When the inlined frame exits with an exception or an error, ok will be
-     * false after the inline_return label.
-     */
-    CHECK_BRANCH();
-
-    interpReturnOK = true;
-    if (entryFrame != regs.fp())
-  inline_return:
-    {
-        if (cx->compartment->debugMode())
-            interpReturnOK = ScriptDebugEpilogue(cx, regs.fp(), interpReturnOK);
-
-        if (!regs.fp()->isYielding())
-            regs.fp()->epilogue(cx);
-        else
-            Probes::exitScript(cx, script, script->function(), regs.fp());
-
-        /* The JIT inlines the epilogue. */
-#ifdef JS_METHODJIT
-  jit_return:
-#endif
-
-        /* The results of lowered call/apply frames need to be shifted. */
-        bool shiftResult = regs.fp()->loweredCallOrApply();
-
-        cx->stack.popInlineFrame(regs);
-        SET_SCRIPT(regs.fp()->script());
-
-        JS_ASSERT(*regs.pc == JSOP_NEW || *regs.pc == JSOP_CALL ||
-                  *regs.pc == JSOP_FUNCALL || *regs.pc == JSOP_FUNAPPLY);
-
-        /* Resume execution in the calling frame. */
-        if (JS_LIKELY(interpReturnOK)) {
-            TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
-
-            if (shiftResult) {
-                regs.sp[-2] = regs.sp[-1];
-                regs.sp--;
-            }
-
-            len = JSOP_CALL_LENGTH;
-            DO_NEXT_OP(len);
-        }
-
-        /* Increment pc so that |sp - fp->slots == ReconstructStackDepth(pc)|. */
-        regs.pc += JSOP_CALL_LENGTH;
-        goto error;
-    } else {
-        JS_ASSERT(regs.stackDepth() == 0);
-    }
-    interpReturnOK = true;
-    goto exit;
-}
-
-BEGIN_CASE(JSOP_DEFAULT)
-    regs.sp--;
-    /* FALL THROUGH */
-BEGIN_CASE(JSOP_GOTO)
-{
-    len = GET_JUMP_OFFSET(regs.pc);
-    BRANCH(len);
-}
-END_CASE(JSOP_GOTO)
-
-BEGIN_CASE(JSOP_IFEQ)
-{
-    bool cond = ToBoolean(regs.sp[-1]);
-    regs.sp--;
-    if (cond == false) {
-        len = GET_JUMP_OFFSET(regs.pc);
-        BRANCH(len);
-    }
-}
-END_CASE(JSOP_IFEQ)
-
-BEGIN_CASE(JSOP_IFNE)
-{
-    bool cond = ToBoolean(regs.sp[-1]);
-    regs.sp--;
-    if (cond != false) {
-        len = GET_JUMP_OFFSET(regs.pc);
-        BRANCH(len);
-    }
-}
-END_CASE(JSOP_IFNE)
-
-BEGIN_CASE(JSOP_OR)
-{
-    bool cond = ToBoolean(regs.sp[-1]);
-    if (cond == true) {
-        len = GET_JUMP_OFFSET(regs.pc);
-        DO_NEXT_OP(len);
-    }
-}
-END_CASE(JSOP_OR)
-
-BEGIN_CASE(JSOP_AND)
-{
-    bool cond = ToBoolean(regs.sp[-1]);
-    if (cond == false) {
-        len = GET_JUMP_OFFSET(regs.pc);
-        DO_NEXT_OP(len);
-    }
-}
-END_CASE(JSOP_AND)
-
-/*
- * If the index value at sp[n] is not an int that fits in a jsval, it could
- * be an object (an XML QName, AttributeName, or AnyName), but only if we are
- * compiling with JS_HAS_XML_SUPPORT.  Otherwise convert the index value to a
- * string atom id.
- */
-#define FETCH_ELEMENT_ID(obj, n, id)                                          \
-    JS_BEGIN_MACRO                                                            \
-        const Value &idval_ = regs.sp[n];                                     \
-        if (!ValueToId(cx, obj, idval_, id.address()))                        \
-            goto error;                                                       \
-    JS_END_MACRO
-
-#define TRY_BRANCH_AFTER_COND(cond,spdec)                                     \
-    JS_BEGIN_MACRO                                                            \
-        JS_ASSERT(js_CodeSpec[op].length == 1);                               \
-        unsigned diff_ = (unsigned) GET_UINT8(regs.pc) - (unsigned) JSOP_IFEQ;         \
-        if (diff_ <= 1) {                                                     \
-            regs.sp -= spdec;                                                 \
-            if (cond == (diff_ != 0)) {                                       \
-                ++regs.pc;                                                    \
-                len = GET_JUMP_OFFSET(regs.pc);                               \
-                BRANCH(len);                                                  \
-            }                                                                 \
-            len = 1 + JSOP_IFEQ_LENGTH;                                       \
-            DO_NEXT_OP(len);                                                  \
-        }                                                                     \
-    JS_END_MACRO
-
-BEGIN_CASE(JSOP_IN)
-{
-    HandleValue rref = HandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!rref.isObject()) {
-        js_ReportValueError(cx, JSMSG_IN_NOT_OBJECT, -1, rref, NullPtr());
-        goto error;
-    }
-    RootedObject &obj = rootObject0;
-    obj = &rref.toObject();
-    RootedId &id = rootId0;
-    FETCH_ELEMENT_ID(obj, -2, id);
-    RootedObject &obj2 = rootObject1;
-    RootedShape &prop = rootShape0;
-    if (!JSObject::lookupGeneric(cx, obj, id, &obj2, &prop))
-        goto error;
-    bool cond = prop != NULL;
-    TRY_BRANCH_AFTER_COND(cond, 2);
-    regs.sp--;
-    regs.sp[-1].setBoolean(cond);
-}
-END_CASE(JSOP_IN)
-
-BEGIN_CASE(JSOP_ITER)
-{
-    JS_ASSERT(regs.stackDepth() >= 1);
-    uint8_t flags = GET_UINT8(regs.pc);
-    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!ValueToIterator(cx, flags, res))
-        goto error;
-    JS_ASSERT(!res.isPrimitive());
-}
-END_CASE(JSOP_ITER)
-
-BEGIN_CASE(JSOP_MOREITER)
-{
-    JS_ASSERT(regs.stackDepth() >= 1);
-    JS_ASSERT(regs.sp[-1].isObject());
-    PUSH_NULL();
-    bool cond;
-    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!IteratorMore(cx, &regs.sp[-2].toObject(), &cond, res))
-        goto error;
-    regs.sp[-1].setBoolean(cond);
-}
-END_CASE(JSOP_MOREITER)
-
-BEGIN_CASE(JSOP_ITERNEXT)
-{
-    JS_ASSERT(regs.sp[-1].isObject());
-    PUSH_NULL();
-    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-    RootedObject &obj = rootObject0;
-    obj = &regs.sp[-2].toObject();
-    if (!IteratorNext(cx, obj, res))
-        goto error;
-}
-END_CASE(JSOP_ITERNEXT)
-
-BEGIN_CASE(JSOP_ENDITER)
-{
-    JS_ASSERT(regs.stackDepth() >= 1);
-    RootedObject &obj = rootObject0;
-    obj = &regs.sp[-1].toObject();
-    bool ok = CloseIterator(cx, obj);
-    regs.sp--;
-    if (!ok)
-        goto error;
-}
-END_CASE(JSOP_ENDITER)
-
-BEGIN_CASE(JSOP_DUP)
-{
-    JS_ASSERT(regs.stackDepth() >= 1);
-    const Value &rref = regs.sp[-1];
-    PUSH_COPY(rref);
-}
-END_CASE(JSOP_DUP)
-
-BEGIN_CASE(JSOP_DUP2)
-{
-    JS_ASSERT(regs.stackDepth() >= 2);
-    const Value &lref = regs.sp[-2];
-    const Value &rref = regs.sp[-1];
-    PUSH_COPY(lref);
-    PUSH_COPY(rref);
-}
-END_CASE(JSOP_DUP2)
-
-BEGIN_CASE(JSOP_SWAP)
-{
-    JS_ASSERT(regs.stackDepth() >= 2);
-    Value &lref = regs.sp[-2];
-    Value &rref = regs.sp[-1];
-    lref.swap(rref);
-}
-END_CASE(JSOP_SWAP)
-
-BEGIN_CASE(JSOP_PICK)
-{
-    unsigned i = GET_UINT8(regs.pc);
-    JS_ASSERT(regs.stackDepth() >= i + 1);
-    Value lval = regs.sp[-int(i + 1)];
-    memmove(regs.sp - (i + 1), regs.sp - i, sizeof(Value) * i);
-    regs.sp[-1] = lval;
-}
-END_CASE(JSOP_PICK)
-
-BEGIN_CASE(JSOP_SETCONST)
-{
-    RootedPropertyName &name = rootName0;
-    name = script->getName(regs.pc);
-
-    RootedValue &rval = rootValue0;
-    rval = regs.sp[-1];
-
-    RootedObject &obj = rootObject0;
-    obj = &regs.fp()->varObj();
-    if (!JSObject::defineProperty(cx, obj, name, rval,
-                                  JS_PropertyStub, JS_StrictPropertyStub,
-                                  JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
-        goto error;
-    }
-}
-END_CASE(JSOP_SETCONST);
-
-#if JS_HAS_DESTRUCTURING
-BEGIN_CASE(JSOP_ENUMCONSTELEM)
-{
-    RootedValue &rval = rootValue0;
-    rval = regs.sp[-3];
-
-    RootedObject &obj = rootObject0;
-    FETCH_OBJECT(cx, -2, obj);
-    RootedId &id = rootId0;
-    FETCH_ELEMENT_ID(obj, -1, id);
-    if (!JSObject::defineGeneric(cx, obj, id, rval,
-                                 JS_PropertyStub, JS_StrictPropertyStub,
-                                 JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
-        goto error;
-    }
-    regs.sp -= 3;
-}
-END_CASE(JSOP_ENUMCONSTELEM)
-#endif
-
-BEGIN_CASE(JSOP_BINDGNAME)
-    PUSH_OBJECT(regs.fp()->global());
-END_CASE(JSOP_BINDGNAME)
-
-BEGIN_CASE(JSOP_BINDNAME)
-{
-    RootedObject &scopeChain = rootObject0;
-    scopeChain = regs.fp()->scopeChain();
-
-    RootedPropertyName &name = rootName0;
-    name = script->getName(regs.pc);
-
-    /* Assigning to an undeclared name adds a property to the global object. */
-    RootedObject &scope = rootObject1;
-    if (!LookupNameWithGlobalDefault(cx, name, scopeChain, &scope))
-        goto error;
-
-    PUSH_OBJECT(*scope);
-}
-END_CASE(JSOP_BINDNAME)
-
-#define BITWISE_OP(OP)                                                        \
-    JS_BEGIN_MACRO                                                            \
-        int32_t i, j;                                                         \
-        if (!ToInt32(cx, regs.sp[-2], &i))                                    \
-            goto error;                                                       \
-        if (!ToInt32(cx, regs.sp[-1], &j))                                    \
-            goto error;                                                       \
-        i = i OP j;                                                           \
-        regs.sp--;                                                            \
-        regs.sp[-1].setInt32(i);                                              \
-    JS_END_MACRO
-
-BEGIN_CASE(JSOP_BITOR)
-    BITWISE_OP(|);
-END_CASE(JSOP_BITOR)
-
-BEGIN_CASE(JSOP_BITXOR)
-    BITWISE_OP(^);
-END_CASE(JSOP_BITXOR)
-
-BEGIN_CASE(JSOP_BITAND)
-    BITWISE_OP(&);
-END_CASE(JSOP_BITAND)
-
-#undef BITWISE_OP
-
-#define EQUALITY_OP(OP)                                                       \
-    JS_BEGIN_MACRO                                                            \
-        Value rval = regs.sp[-1];                                             \
-        Value lval = regs.sp[-2];                                             \
-        bool cond;                                                            \
-        if (!LooselyEqual(cx, lval, rval, &cond))                             \
-            goto error;                                                       \
-        cond = cond OP JS_TRUE;                                               \
-        TRY_BRANCH_AFTER_COND(cond, 2);                                       \
-        regs.sp--;                                                            \
-        regs.sp[-1].setBoolean(cond);                                         \
-    JS_END_MACRO
-
-BEGIN_CASE(JSOP_EQ)
-    EQUALITY_OP(==);
-END_CASE(JSOP_EQ)
-
-BEGIN_CASE(JSOP_NE)
-    EQUALITY_OP(!=);
-END_CASE(JSOP_NE)
-
-#undef EQUALITY_OP
-
-#define STRICT_EQUALITY_OP(OP, COND)                                          \
-    JS_BEGIN_MACRO                                                            \
-        const Value &rref = regs.sp[-1];                                      \
-        const Value &lref = regs.sp[-2];                                      \
-        bool equal;                                                           \
-        if (!StrictlyEqual(cx, lref, rref, &equal))                           \
-            goto error;                                                       \
-        COND = equal OP JS_TRUE;                                              \
-        regs.sp--;                                                            \
-    JS_END_MACRO
-
-BEGIN_CASE(JSOP_STRICTEQ)
-{
-    bool cond;
-    STRICT_EQUALITY_OP(==, cond);
-    regs.sp[-1].setBoolean(cond);
-}
-END_CASE(JSOP_STRICTEQ)
-
-BEGIN_CASE(JSOP_STRICTNE)
-{
-    bool cond;
-    STRICT_EQUALITY_OP(!=, cond);
-    regs.sp[-1].setBoolean(cond);
-}
-END_CASE(JSOP_STRICTNE)
-
-BEGIN_CASE(JSOP_CASE)
-{
-    bool cond;
-    STRICT_EQUALITY_OP(==, cond);
-    if (cond) {
-        regs.sp--;
-        len = GET_JUMP_OFFSET(regs.pc);
-        BRANCH(len);
-    }
-}
-END_CASE(JSOP_CASE)
-
-#undef STRICT_EQUALITY_OP
-
-BEGIN_CASE(JSOP_LT)
-{
-    bool cond;
-    const Value &lref = regs.sp[-2];
-    const Value &rref = regs.sp[-1];
-    if (!LessThanOperation(cx, lref, rref, &cond))
-        goto error;
-    TRY_BRANCH_AFTER_COND(cond, 2);
-    regs.sp[-2].setBoolean(cond);
-    regs.sp--;
-}
-END_CASE(JSOP_LT)
-
-BEGIN_CASE(JSOP_LE)
-{
-    bool cond;
-    const Value &lref = regs.sp[-2];
-    const Value &rref = regs.sp[-1];
-    if (!LessThanOrEqualOperation(cx, lref, rref, &cond))
-        goto error;
-    TRY_BRANCH_AFTER_COND(cond, 2);
-    regs.sp[-2].setBoolean(cond);
-    regs.sp--;
-}
-END_CASE(JSOP_LE)
-
-BEGIN_CASE(JSOP_GT)
-{
-    bool cond;
-    const Value &lref = regs.sp[-2];
-    const Value &rref = regs.sp[-1];
-    if (!GreaterThanOperation(cx, lref, rref, &cond))
-        goto error;
-    TRY_BRANCH_AFTER_COND(cond, 2);
-    regs.sp[-2].setBoolean(cond);
-    regs.sp--;
-}
-END_CASE(JSOP_GT)
-
-BEGIN_CASE(JSOP_GE)
-{
-    bool cond;
-    const Value &lref = regs.sp[-2];
-    const Value &rref = regs.sp[-1];
-    if (!GreaterThanOrEqualOperation(cx, lref, rref, &cond))
-        goto error;
-    TRY_BRANCH_AFTER_COND(cond, 2);
-    regs.sp[-2].setBoolean(cond);
-    regs.sp--;
-}
-END_CASE(JSOP_GE)
-
-#define SIGNED_SHIFT_OP(OP)                                                   \
-    JS_BEGIN_MACRO                                                            \
-        int32_t i, j;                                                         \
-        if (!ToInt32(cx, regs.sp[-2], &i))                                    \
-            goto error;                                                       \
-        if (!ToInt32(cx, regs.sp[-1], &j))                                    \
-            goto error;                                                       \
-        i = i OP (j & 31);                                                    \
-        regs.sp--;                                                            \
-        regs.sp[-1].setInt32(i);                                              \
-    JS_END_MACRO
-
-BEGIN_CASE(JSOP_LSH)
-    SIGNED_SHIFT_OP(<<);
-END_CASE(JSOP_LSH)
-
-BEGIN_CASE(JSOP_RSH)
-    SIGNED_SHIFT_OP(>>);
-END_CASE(JSOP_RSH)
-
-#undef SIGNED_SHIFT_OP
-
-BEGIN_CASE(JSOP_URSH)
-{
-    HandleValue lval = HandleValue::fromMarkedLocation(&regs.sp[-2]);
-    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!UrshOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
-        goto error;
-    regs.sp--;
-}
-END_CASE(JSOP_URSH)
-
-BEGIN_CASE(JSOP_ADD)
-{
-    Value lval = regs.sp[-2];
-    Value rval = regs.sp[-1];
-    if (!AddOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
-        goto error;
-    regs.sp--;
-}
-END_CASE(JSOP_ADD)
-
-BEGIN_CASE(JSOP_SUB)
-{
-    RootedValue &lval = rootValue0, &rval = rootValue1;
-    lval = regs.sp[-2];
-    rval = regs.sp[-1];
-    if (!SubOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
-        goto error;
-    regs.sp--;
-}
-END_CASE(JSOP_SUB)
-
-BEGIN_CASE(JSOP_MUL)
-{
-    RootedValue &lval = rootValue0, &rval = rootValue1;
-    lval = regs.sp[-2];
-    rval = regs.sp[-1];
-    if (!MulOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
-        goto error;
-    regs.sp--;
-}
-END_CASE(JSOP_MUL)
-
-BEGIN_CASE(JSOP_DIV)
-{
-    RootedValue &lval = rootValue0, &rval = rootValue1;
-    lval = regs.sp[-2];
-    rval = regs.sp[-1];
-    if (!DivOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
-        goto error;
-    regs.sp--;
-}
-END_CASE(JSOP_DIV)
-
-BEGIN_CASE(JSOP_MOD)
-{
-    RootedValue &lval = rootValue0, &rval = rootValue1;
-    lval = regs.sp[-2];
-    rval = regs.sp[-1];
-    if (!ModOperation(cx, script, regs.pc, lval, rval, &regs.sp[-2]))
-        goto error;
-    regs.sp--;
-}
-END_CASE(JSOP_MOD)
-
-BEGIN_CASE(JSOP_NOT)
-{
-    bool cond = ToBoolean(regs.sp[-1]);
-    regs.sp--;
-    PUSH_BOOLEAN(!cond);
-}
-END_CASE(JSOP_NOT)
-
-BEGIN_CASE(JSOP_BITNOT)
-{
-    int32_t i;
-    HandleValue value = HandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!BitNot(cx, value, &i))
-        goto error;
-    regs.sp[-1].setInt32(i);
-}
-END_CASE(JSOP_BITNOT)
-
-BEGIN_CASE(JSOP_NEG)
-{
-    /*
-     * When the operand is int jsval, INT32_FITS_IN_JSVAL(i) implies
-     * INT32_FITS_IN_JSVAL(-i) unless i is 0 or INT32_MIN when the
-     * results, -0.0 or INT32_MAX + 1, are double values.
-     */
-    Value ref = regs.sp[-1];
-    int32_t i;
-    if (ref.isInt32() && (i = ref.toInt32()) != 0 && i != INT32_MIN) {
-        i = -i;
-        regs.sp[-1].setInt32(i);
-    } else {
-        double d;
-        if (!ToNumber(cx, regs.sp[-1], &d))
-            goto error;
-        d = -d;
-        if (!regs.sp[-1].setNumber(d) && !ref.isDouble())
-            TypeScript::MonitorOverflow(cx, script, regs.pc);
-    }
-}
-END_CASE(JSOP_NEG)
-
-BEGIN_CASE(JSOP_POS)
-    if (!ToNumber(cx, &regs.sp[-1]))
-        goto error;
-    if (!regs.sp[-1].isInt32())
-        TypeScript::MonitorOverflow(cx, script, regs.pc);
-END_CASE(JSOP_POS)
-
-BEGIN_CASE(JSOP_DELNAME)
-{
-    RootedPropertyName &name = rootName0;
-    name = script->getName(regs.pc);
-
-    RootedObject &scopeObj = rootObject0;
-    scopeObj = cx->stack.currentScriptedScopeChain();
-
-    RootedObject &scope = rootObject1;
-    RootedObject &pobj = rootObject2;
-    RootedShape &prop = rootShape0;
-    if (!LookupName(cx, name, scopeObj, &scope, &pobj, &prop))
-        goto error;
-
-    /* Strict mode code should never contain JSOP_DELNAME opcodes. */
-    JS_ASSERT(!script->strictModeCode);
-
-    /* ECMA says to return true if name is undefined or inherited. */
-    PUSH_BOOLEAN(true);
-    if (prop) {
-        MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-        if (!JSObject::deleteProperty(cx, scope, name, res, false))
-            goto error;
-    }
-}
-END_CASE(JSOP_DELNAME)
-
-BEGIN_CASE(JSOP_DELPROP)
-{
-    RootedPropertyName &name = rootName0;
-    name = script->getName(regs.pc);
-
-    RootedObject &obj = rootObject0;
-    FETCH_OBJECT(cx, -1, obj);
-
-    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!JSObject::deleteProperty(cx, obj, name, res, script->strictModeCode))
-        goto error;
-}
-END_CASE(JSOP_DELPROP)
-
-BEGIN_CASE(JSOP_DELELEM)
-{
-    /* Fetch the left part and resolve it to a non-null object. */
-    RootedObject &obj = rootObject0;
-    FETCH_OBJECT(cx, -2, obj);
-
-    RootedValue &propval = rootValue0;
-    propval = regs.sp[-1];
-
-    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
-    if (!JSObject::deleteByValue(cx, obj, propval, res, script->strictModeCode))
-        goto error;
-
-    regs.sp--;
-}
-END_CASE(JSOP_DELELEM)
-
-BEGIN_CASE(JSOP_TOID)
-{
-    /*
-     * Increment or decrement requires use to lookup the same property twice, but we need to avoid
-     * the oberservable stringification the second time.
-     * There must be an object value below the id, which will not be popped
-     * but is necessary in interning the id for XML.
-     */
-    RootedValue &objval = rootValue0, &idval = rootValue1;
-    objval = regs.sp[-2];
-    idval = regs.sp[-1];
-
-    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-1]);
-    if (!ToIdOperation(cx, script, regs.pc, objval, idval, res))
-        goto error;
-}
-END_CASE(JSOP_TOID)
-
-BEGIN_CASE(JSOP_TYPEOFEXPR)
-BEGIN_CASE(JSOP_TYPEOF)
-{
-    HandleValue ref = HandleValue::fromMarkedLocation(&regs.sp[-1]);
-    regs.sp[-1].setString(TypeOfOperation(cx, ref));
-}
-END_CASE(JSOP_TYPEOF)
-
-BEGIN_CASE(JSOP_VOID)
-    regs.sp[-1].setUndefined();
-END_CASE(JSOP_VOID)
-
-BEGIN_CASE(JSOP_INCELEM)
-BEGIN_CASE(JSOP_DECELEM)
-BEGIN_CASE(JSOP_ELEMINC)
-BEGIN_CASE(JSOP_ELEMDEC)
-    /* No-op */
-END_CASE(JSOP_INCELEM)
-
-BEGIN_CASE(JSOP_INCPROP)
-BEGIN_CASE(JSOP_DECPROP)
-BEGIN_CASE(JSOP_PROPINC)
-BEGIN_CASE(JSOP_PROPDEC)
-BEGIN_CASE(JSOP_INCNAME)
-BEGIN_CASE(JSOP_DECNAME)
-BEGIN_CASE(JSOP_NAMEINC)
-BEGIN_CASE(JSOP_NAMEDEC)
-BEGIN_CASE(JSOP_INCGNAME)
-BEGIN_CASE(JSOP_DECGNAME)
-BEGIN_CASE(JSOP_GNAMEINC)
-BEGIN_CASE(JSOP_GNAMEDEC)
-    /* No-op */
-END_CASE(JSOP_INCPROP)
-
-BEGIN_CASE(JSOP_DECALIASEDVAR)
-BEGIN_CASE(JSOP_ALIASEDVARDEC)
-BEGIN_CASE(JSOP_INCALIASEDVAR)
-BEGIN_CASE(JSOP_ALIASEDVARINC)
-    /* No-op */
-END_CASE(JSOP_ALIASEDVARINC)
-
-BEGIN_CASE(JSOP_DECARG)
-BEGIN_CASE(JSOP_ARGDEC)
-BEGIN_CASE(JSOP_INCARG)
-BEGIN_CASE(JSOP_ARGINC)
-{
-    unsigned i = GET_ARGNO(regs.pc);
-    if (script->argsObjAliasesFormals()) {
-        const Value &arg = regs.fp()->argsObj().arg(i);
-        Value v;
-        if (!DoIncDec(cx, script, regs.pc, arg, &v, &regs.sp[0]))
-            goto error;
-        regs.fp()->argsObj().setArg(i, v);
-    } else {
-        Value &arg = regs.fp()->unaliasedFormal(i);
-        if (!DoIncDec(cx, script, regs.pc, arg, &arg, &regs.sp[0]))
-            goto error;
-    }
-    regs.sp++;
-}
-END_CASE(JSOP_ARGINC);
-
-BEGIN_CASE(JSOP_DECLOCAL)
-BEGIN_CASE(JSOP_LOCALDEC)
-BEGIN_CASE(JSOP_INCLOCAL)
-BEGIN_CASE(JSOP_LOCALINC)
-{
-    unsigned i = GET_SLOTNO(regs.pc);
-    Value &local = regs.fp()->unaliasedLocal(i);
-    if (!DoIncDec(cx, script, regs.pc, local, &local, &regs.sp[0]))
-        goto error;
-    regs.sp++;
-}
-END_CASE(JSOP_LOCALINC)
-
-BEGIN_CASE(JSOP_THIS)
-    if (!ComputeThis(cx, regs.fp()))
-        goto error;
-    PUSH_COPY(regs.fp()->thisValue());
-END_CASE(JSOP_THIS)
-
-BEGIN_CASE(JSOP_GETPROP)
-BEGIN_CASE(JSOP_GETXPROP)
-BEGIN_CASE(JSOP_LENGTH)
-BEGIN_CASE(JSOP_CALLPROP)
-{
-    RootedValue &lval = rootValue0;
-    lval = regs.sp[-1];
-
-    RootedValue rval(cx);
-    if (!GetPropertyOperation(cx, script, regs.pc, &lval, &rval))
-        goto error;
-
-    TypeScript::Monitor(cx, script, regs.pc, rval);
-
-    regs.sp[-1] = rval;
-    assertSameCompartment(cx, regs.sp[-1]);
-}
-END_CASE(JSOP_GETPROP)
-
-BEGIN_CASE(JSOP_SETGNAME)
-BEGIN_CASE(JSOP_SETNAME)
-{
-    RootedObject &scope = rootObject0;
-    scope = &regs.sp[-2].toObject();
-
-    HandleValue value = HandleValue::fromMarkedLocation(&regs.sp[-1]);
-
-    if (!SetNameOperation(cx, script, regs.pc, scope, value))
-        goto error;
-
-    regs.sp[-2] = regs.sp[-1];
-    regs.sp--;
-}
-END_CASE(JSOP_SETNAME)
-
-BEGIN_CASE(JSOP_SETPROP)
-{
-    HandleValue lval = HandleValue::fromMarkedLocation(&regs.sp[-2]);
-    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
-
-    if (!SetPropertyOperation(cx, regs.pc, lval, rval))
-        goto error;
-
-    regs.sp[-2] = regs.sp[-1];
-    regs.sp--;
-}
-END_CASE(JSOP_SETPROP)
-
-BEGIN_CASE(JSOP_GETELEM)
-BEGIN_CASE(JSOP_CALLELEM)
-{
-    MutableHandleValue lval = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
-    HandleValue rval = HandleValue::fromMarkedLocation(&regs.sp[-1]);
-
-    MutableHandleValue res = MutableHandleValue::fromMarkedLocation(&regs.sp[-2]);
-    if (!GetElementOperation(cx, op, lval, rval, res))
-        goto error;
-    TypeScript::Monitor(cx, script, regs.pc, res);
-    regs.sp--;
-}
-END_CASE(JSOP_GETELEM)
-
-BEGIN_CASE(JSOP_SETELEM)
-{
-    RootedObject &obj = rootObject0;
-    FETCH_OBJECT(cx, -3, obj);
-    RootedId &id = rootId0;
-    FETCH_ELEMENT_ID(obj, -2, id);
-    Value &value = regs.sp[-1];
-    if (!SetObjectElementOperation(cx, obj, id, value, script->strictModeCode))
-        goto error;
-    regs.sp[-3] = value;
-    regs.sp -= 2;
-}
-END_CASE(JSOP_SETELEM)
-
-BEGIN_CASE(JSOP_ENUMELEM)
-{
-    RootedObject &obj = rootObject0;
-    RootedValue &rval = rootValue0;
-
-    /* Funky: the value to set is under the [obj, id] pair. */
-    FETCH_OBJECT(cx, -2, obj);
-    RootedId &id = rootId0;
-    FETCH_ELEMENT_ID(obj, -1, id);
-    rval = regs.sp[-3];
-    if (!JSObject::setGeneric(cx, obj, obj, id, &rval, script->strictModeCode))
-        goto error;
-    regs.sp -= 3;
-}
-END_CASE(JSOP_ENUMELEM)
-
-BEGIN_CASE(JSOP_EVAL)
-{
-    CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
-    if (IsBuiltinEvalForScope(regs.fp()->scopeChain(), args.calleev())) {
-        if (!DirectEval(cx, args))
-            goto error;
-    } else {
-        if (!InvokeKernel(cx, args))
-            goto error;
-    }
-    regs.sp = args.spAfterCall();
-    TypeScript::Monitor(cx, script, regs.pc, regs.sp[-1]);
-}
-END_CASE(JSOP_EVAL)
-
-BEGIN_CASE(JSOP_FUNAPPLY)
-    if (!GuardFunApplyArgumentsOptimization(cx))
-        goto error;
-    /* FALL THROUGH */
-
-BEGIN_CASE(JSOP_NEW)
-BEGIN_CASE(JSOP_CALL)
-BEGIN_CASE(JSOP_FUNCALL)
-{
-    if (regs.fp()->hasPushedSPSFrame())
-        cx->runtime->spsProfiler.updatePC(script, regs.pc);
-    JS_ASSERT(regs.stackDepth() >= 2 + GET_ARGC(regs.pc));
-    CallArgs args = CallArgsFromSp(GET_ARGC(regs.pc), regs.sp);
-
-    bool construct = (*regs.pc == JSOP_NEW);
-
-    RootedFunction &fun = rootFunction0;
-    /* Don't bother trying to fast-path calls to scripted non-constructors. */
-    if (!IsFunctionObject(args.calleev(), fun.address()) || !fun->isInterpretedConstructor()) {
-        if (construct) {
-            if (!InvokeConstructorKernel(cx, args))
-                goto error;
-        } else {
-            if (!InvokeKernel(cx, args))
-                goto error;
-        }
-        Value *newsp = args.spAfterCall();
-        TypeScript::Monitor(cx, script, regs.pc, newsp[-1]);
-        regs.sp = newsp;
-        len = JSOP_CALL_LENGTH;
-        DO_NEXT_OP(len);
-    }
-
-    if (!TypeMonitorCall(cx, args, construct))
-        goto error;
-
-    InitialFrameFlags initial = construct ? INITIAL_CONSTRUCT : INITIAL_NONE;
-    bool newType = cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc);
-    RawScript funScript = fun->script().unsafeGet();
-    if (!cx->stack.pushInlineFrame(cx, regs, args, *fun, funScript, initial))
-        goto error;
-
-    SET_SCRIPT(regs.fp()->script());
-    script->resetLoopCount();
-
-#ifdef JS_ION
-    if (!newType && ion::IsEnabled(cx)) {
-        ion::MethodStatus status = ion::CanEnter(cx, script, regs.fp(), newType);