Bug 1519880 part 1 - Stop exposing StackValue* to BaselineCodeGen. r=djvj
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 17 Jan 2019 12:18:35 +0000
changeset 514250 f24ec43206d74a563fbd401faf3761dde41707f8
parent 514249 cb3ca443d8c3f635764d2cc77f42aff6c3daecda
child 514251 d11bb3bd81951e0e5a66bc9e3ae80ca22d2ad13f
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdjvj
bugs1519880
milestone66.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1519880 part 1 - Stop exposing StackValue* to BaselineCodeGen. r=djvj The interpreter won't use the virtual stack and StackValue, so we need to refactor things a bit so we don't call frame.peek(x) outside the FrameInfo class. StackValue will be just an implementation detail of CompilerFrameInfo in the next patch. Differential Revision: https://phabricator.services.mozilla.com/D16479
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineCompiler.h
js/src/jit/BaselineFrameInfo.cpp
js/src/jit/BaselineFrameInfo.h
js/src/jit/BaselineJIT.cpp
js/src/jit/BaselineJIT.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1160,17 +1160,17 @@ template <>
 bool BaselineCompilerCodeGen::emit_JSOP_DUPAT() {
   frame.syncStack(0);
 
   // DUPAT takes a value on the stack and re-pushes it on top.  It's like
   // GETLOCAL but it addresses from the top of the stack instead of from the
   // stack frame.
 
   int depth = -(GET_UINT24(handler.pc()) + 1);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(depth)), R0);
+  masm.loadValue(frame.addressOfStackValue(depth), R0);
   frame.push(R0);
   return true;
 }
 
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_DUPAT() {
   MOZ_CRASH("NYI: interpreter JSOP_DUPAT");
 }
@@ -1188,18 +1188,18 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   frame.push(R0);
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_DUP2() {
   frame.syncStack(0);
 
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
+  masm.loadValue(frame.addressOfStackValue(-2), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R1);
 
   frame.push(R0);
   frame.push(R1);
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_SWAP() {
@@ -1217,23 +1217,23 @@ bool BaselineCompilerCodeGen::emit_JSOP_
 
   // Pick takes a value on the stack and moves it to the top.
   // For instance, pick 2:
   //     before: A B C D E
   //     after : A B D E C
 
   // First, move value at -(amount + 1) into R0.
   int32_t depth = -(GET_INT8(handler.pc()) + 1);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(depth)), R0);
+  masm.loadValue(frame.addressOfStackValue(depth), R0);
 
   // Move the other values down.
   depth++;
   for (; depth < 0; depth++) {
-    Address source = frame.addressOfStackValue(frame.peek(depth));
-    Address dest = frame.addressOfStackValue(frame.peek(depth - 1));
+    Address source = frame.addressOfStackValue(depth);
+    Address dest = frame.addressOfStackValue(depth - 1);
     masm.loadValue(source, R1);
     masm.storeValue(R1, dest);
   }
 
   // Push R0.
   frame.pop();
   frame.push(R0);
   return true;
@@ -1249,29 +1249,29 @@ bool BaselineCompilerCodeGen::emit_JSOP_
   frame.syncStack(0);
 
   // Pick takes the top of the stack value and moves it under the nth value.
   // For instance, unpick 2:
   //     before: A B C D E
   //     after : A B E C D
 
   // First, move value at -1 into R0.
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   // Move the other values up.
   int32_t depth = -(GET_INT8(handler.pc()) + 1);
   for (int32_t i = -1; i > depth; i--) {
-    Address source = frame.addressOfStackValue(frame.peek(i - 1));
-    Address dest = frame.addressOfStackValue(frame.peek(i));
+    Address source = frame.addressOfStackValue(i - 1);
+    Address dest = frame.addressOfStackValue(i);
     masm.loadValue(source, R1);
     masm.storeValue(R1, dest);
   }
 
   // Store R0 under the nth value.
-  Address dest = frame.addressOfStackValue(frame.peek(depth));
+  Address dest = frame.addressOfStackValue(depth);
   masm.storeValue(R0, dest);
   return true;
 }
 
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_UNPICK() {
   MOZ_CRASH("NYI: interpreter JSOP_UNPICK");
 }
@@ -1330,17 +1330,17 @@ bool BaselineCodeGen<Handler>::emitToBoo
   }
 
   masm.bind(&skipIC);
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitTest(bool branchIfTrue) {
-  bool knownBoolean = frame.peek(-1)->isKnownBoolean();
+  bool knownBoolean = frame.stackValueHasKnownType(-1, JSVAL_TYPE_BOOLEAN);
 
   // Keep top stack value in R0.
   frame.popRegsAndSync(1);
 
   if (!knownBoolean && !emitToBoolean()) {
     return false;
   }
 
@@ -1356,22 +1356,22 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_IFNE() {
   return emitTest(true);
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitAndOr(bool branchIfTrue) {
-  bool knownBoolean = frame.peek(-1)->isKnownBoolean();
+  bool knownBoolean = frame.stackValueHasKnownType(-1, JSVAL_TYPE_BOOLEAN);
 
   // AND and OR leave the original value on the stack.
   frame.syncStack(0);
 
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
   if (!knownBoolean && !emitToBoolean()) {
     return false;
   }
 
   emitTestBooleanTruthy(branchIfTrue, R0);
   return true;
 }
 
@@ -1382,17 +1382,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_OR() {
   return emitAndOr(true);
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_NOT() {
-  bool knownBoolean = frame.peek(-1)->isKnownBoolean();
+  bool knownBoolean = frame.stackValueHasKnownType(-1, JSVAL_TYPE_BOOLEAN);
 
   // Keep top stack value in R0.
   frame.popRegsAndSync(1);
 
   if (!knownBoolean && !emitToBoolean()) {
     return false;
   }
 
@@ -1474,17 +1474,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 typedef bool (*ThrowCheckIsObjectFn)(JSContext*, CheckIsObjectKind);
 static const VMFunction ThrowCheckIsObjectInfo =
     FunctionInfo<ThrowCheckIsObjectFn>(ThrowCheckIsObject,
                                        "ThrowCheckIsObject");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CHECKISOBJ() {
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   Label ok;
   masm.branchTestObject(Assembler::Equal, R0, &ok);
 
   prepareVMCall();
 
   pushUint8BytecodeOperandArg();
   if (!callVM(ThrowCheckIsObjectInfo)) {
@@ -1497,17 +1497,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
 typedef bool (*CheckIsCallableFn)(JSContext*, HandleValue, CheckIsCallableKind);
 static const VMFunction CheckIsCallableInfo =
     FunctionInfo<CheckIsCallableFn>(CheckIsCallable, "CheckIsCallable");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CHECKISCALLABLE() {
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
 
   pushUint8BytecodeOperandArg();
   pushArg(R0);
   if (!callVM(CheckIsCallableInfo)) {
     return false;
   }
@@ -1523,25 +1523,25 @@ static const VMFunction ThrowUninitializ
 typedef bool (*ThrowInitializedThisFn)(JSContext*);
 static const VMFunction ThrowInitializedThisInfo =
     FunctionInfo<ThrowInitializedThisFn>(BaselineThrowInitializedThis,
                                          "BaselineThrowInitializedThis");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CHECKTHIS() {
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   return emitCheckThis(R0);
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CHECKTHISREINIT() {
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   return emitCheckThis(R0, /* reinit = */ true);
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitCheckThis(ValueOperand val, bool reinit) {
   Label thisOK;
   if (reinit) {
@@ -1930,53 +1930,16 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
   pushUint8BytecodeOperandArg();
   pushArg(R1);
   pushArg(R0.scratchReg());
   return callVM(SetFunNameInfo);
 }
 
 template <typename Handler>
-void BaselineCodeGen<Handler>::storeValue(const StackValue* source,
-                                          const Address& dest,
-                                          const ValueOperand& scratch) {
-  switch (source->kind()) {
-    case StackValue::Constant:
-      masm.storeValue(source->constant(), dest);
-      break;
-    case StackValue::Register:
-      masm.storeValue(source->reg(), dest);
-      break;
-    case StackValue::LocalSlot:
-      masm.loadValue(frame.addressOfLocal(source->localSlot()), scratch);
-      masm.storeValue(scratch, dest);
-      break;
-    case StackValue::ArgSlot:
-      masm.loadValue(frame.addressOfArg(source->argSlot()), scratch);
-      masm.storeValue(scratch, dest);
-      break;
-    case StackValue::ThisSlot:
-      masm.loadValue(frame.addressOfThis(), scratch);
-      masm.storeValue(scratch, dest);
-      break;
-    case StackValue::EvalNewTargetSlot:
-      MOZ_ASSERT(script->isForEval());
-      masm.loadValue(frame.addressOfEvalNewTarget(), scratch);
-      masm.storeValue(scratch, dest);
-      break;
-    case StackValue::Stack:
-      masm.loadValue(frame.addressOfStackValue(source), scratch);
-      masm.storeValue(scratch, dest);
-      break;
-    default:
-      MOZ_CRASH("Invalid kind");
-  }
-}
-
-template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_BITOR() {
   return emitBinaryArith();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_BITXOR() {
   return emitBinaryArith();
 }
@@ -2219,17 +2182,17 @@ bool BaselineInterpreterCodeGen::emit_JS
 }
 
 template <>
 bool BaselineCompilerCodeGen::emit_JSOP_INITELEM_ARRAY() {
   // Keep the object and rhs on the stack.
   frame.syncStack(0);
 
   // Load object in R0, index in R1.
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
+  masm.loadValue(frame.addressOfStackValue(-2), R0);
   uint32_t index = GET_UINT32(handler.pc());
   MOZ_ASSERT(index <= INT32_MAX,
              "the bytecode emitter must fail to compile code that would "
              "produce JSOP_INITELEM_ARRAY with a length exceeding "
              "int32_t range");
   masm.moveValue(Int32Value(AssertedCast<int32_t>(index)), R1);
 
   // Call IC.
@@ -2269,17 +2232,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
   frame.push(R0);
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_INITELEM() {
   // Store RHS in the scratch slot.
-  storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
+  frame.storeStackValue(-1, frame.addressOfScratchValue(), R2);
   frame.pop();
 
   // Keep object and index in R0 and R1.
   frame.popRegsAndSync(2);
 
   // Push the object to store the result of the IC.
   frame.push(R0);
   frame.syncStack(0);
@@ -2307,18 +2270,18 @@ typedef bool (*MutateProtoFn)(JSContext*
 static const VMFunction MutateProtoInfo =
     FunctionInfo<MutateProtoFn>(MutatePrototype, "MutatePrototype");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_MUTATEPROTO() {
   // Keep values on the stack for the decompiler.
   frame.syncStack(0);
 
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-2)), R0.scratchReg());
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
+  masm.unboxObject(frame.addressOfStackValue(-2), R0.scratchReg());
+  masm.loadValue(frame.addressOfStackValue(-1), R1);
 
   prepareVMCall();
 
   pushArg(R1);
   pushArg(R0.scratchReg());
 
   if (!callVM(MutateProtoInfo)) {
     return false;
@@ -2327,18 +2290,18 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   frame.pop();
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_INITPROP() {
   // Load lhs in R0, rhs in R1.
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
+  masm.loadValue(frame.addressOfStackValue(-2), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R1);
 
   // Call IC.
   if (!emitNextIC()) {
     return false;
   }
 
   // Leave the object on the stack.
   frame.pop();
@@ -2368,17 +2331,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
   // Mark R0 as pushed stack value.
   frame.push(R0);
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_GETELEM_SUPER() {
   // Store obj in the scratch slot.
-  storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
+  frame.storeStackValue(-1, frame.addressOfScratchValue(), R2);
   frame.pop();
 
   // Keep receiver and index in R0 and R1.
   frame.popRegsAndSync(2);
 
   // Keep obj on the stack.
   frame.pushScratchValue();
 
@@ -2394,17 +2357,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CALLELEM() {
   return emit_JSOP_GETELEM();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_SETELEM() {
   // Store RHS in the scratch slot.
-  storeValue(frame.peek(-1), frame.addressOfScratchValue(), R2);
+  frame.storeStackValue(-1, frame.addressOfScratchValue(), R2);
   frame.pop();
 
   // Keep object and index in R0 and R1.
   frame.popRegsAndSync(2);
 
   // Keep RHS on the stack.
   frame.pushScratchValue();
 
@@ -2423,27 +2386,27 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitSetElemSuper(bool strict) {
   // Incoming stack is |receiver, propval, obj, rval|. We need to shuffle
   // stack to leave rval when operation is complete.
 
   // Pop rval into R0, then load receiver into R1 and replace with rval.
   frame.popRegsAndSync(1);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-3)), R1);
-  masm.storeValue(R0, frame.addressOfStackValue(frame.peek(-3)));
+  masm.loadValue(frame.addressOfStackValue(-3), R1);
+  masm.storeValue(R0, frame.addressOfStackValue(-3));
 
   prepareVMCall();
 
   pushArg(Imm32(strict));
   pushArg(R1);  // receiver
   pushArg(R0);  // rval
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
+  masm.loadValue(frame.addressOfStackValue(-2), R0);
   pushArg(R0);  // propval
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
+  masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
   pushArg(R0.scratchReg());  // obj
 
   if (!callVM(SetObjectElementInfo)) {
     return false;
   }
 
   frame.popn(2);
   return true;
@@ -2465,18 +2428,18 @@ static const VMFunction DeleteElementStr
 static const VMFunction DeleteElementNonStrictInfo =
     FunctionInfo<DeleteElementFn>(DeleteElementJit<false>,
                                   "DeleteElementNonStrict");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitDelElem(bool strict) {
   // Keep values on the stack for the decompiler.
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
+  masm.loadValue(frame.addressOfStackValue(-2), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R1);
 
   prepareVMCall();
 
   pushArg(R1);
   pushArg(R0);
   if (!callVM(strict ? DeleteElementStrictInfo : DeleteElementNonStrictInfo)) {
     return false;
   }
@@ -2692,26 +2655,26 @@ static const VMFunction SetPropertySuper
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitSetPropSuper(bool strict) {
   // Incoming stack is |receiver, obj, rval|. We need to shuffle stack to
   // leave rval when operation is complete.
 
   // Pop rval into R0, then load receiver into R1 and replace with rval.
   frame.popRegsAndSync(1);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
-  masm.storeValue(R0, frame.addressOfStackValue(frame.peek(-2)));
+  masm.loadValue(frame.addressOfStackValue(-2), R1);
+  masm.storeValue(R0, frame.addressOfStackValue(-2));
 
   prepareVMCall();
 
   pushArg(Imm32(strict));
   pushArg(R0);  // rval
   pushScriptNameArg();
   pushArg(R1);  // receiver
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
+  masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
   pushArg(R0.scratchReg());  // obj
 
   if (!callVM(SetPropertySuperInfo)) {
     return false;
   }
 
   frame.pop();
   return true;
@@ -2756,17 +2719,17 @@ template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_GETBOUNDNAME() {
   return emit_JSOP_GETPROP();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_GETPROP_SUPER() {
   // Receiver -> R1, Object -> R0
   frame.popRegsAndSync(1);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
+  masm.loadValue(frame.addressOfStackValue(-1), R1);
   frame.pop();
 
   if (!emitNextIC()) {
     return false;
   }
 
   frame.push(R0);
   return true;
@@ -2780,17 +2743,17 @@ static const VMFunction DeletePropertySt
 static const VMFunction DeletePropertyNonStrictInfo =
     FunctionInfo<DeletePropertyFn>(DeletePropertyJit<false>,
                                    "DeletePropertyNonStrict");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitDelProp(bool strict) {
   // Keep value on the stack for the decompiler.
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
 
   pushScriptNameArg();
   pushArg(R0);
 
   if (!callVM(strict ? DeletePropertyStrictInfo
                      : DeletePropertyNonStrictInfo)) {
@@ -2879,17 +2842,17 @@ bool BaselineCompilerCodeGen::emit_JSOP_
   jsbytecode* pc = handler.pc();
   JSScript* outerScript = EnvironmentCoordinateFunctionScript(script, pc);
   if (outerScript && outerScript->treatAsRunOnce()) {
     // Type updates for this operation might need to be tracked, so treat
     // this as a SETPROP.
 
     // Load rhs into R1.
     frame.syncStack(0);
-    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
+    masm.loadValue(frame.addressOfStackValue(-1), R1);
 
     // Load and box lhs into R0.
     getEnvironmentCoordinateObject(R2.scratchReg());
     masm.tagValue(JSVAL_TYPE_OBJECT, R2.scratchReg(), R0);
 
     // Call SETPROP IC.
     if (!emitNextIC()) {
       return false;
@@ -3137,18 +3100,18 @@ static const VMFunction InitPropGetterSe
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitInitPropGetterSetter() {
   // Keep values on the stack for the decompiler.
   frame.syncStack(0);
 
   prepareVMCall();
 
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-2)), R1.scratchReg());
+  masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
+  masm.unboxObject(frame.addressOfStackValue(-2), R1.scratchReg());
 
   pushArg(R0.scratchReg());
   pushScriptNameArg();
   pushArg(R1.scratchReg());
   pushBytecodePCArg();
 
   if (!callVM(InitPropGetterSetterInfo)) {
     return false;
@@ -3184,24 +3147,24 @@ static const VMFunction InitElemGetterSe
     FunctionInfo<InitElemGetterSetterFn>(InitGetterSetterOperation,
                                          "InitElemGetterSetterOperation");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitInitElemGetterSetter() {
   // Load index and value in R0 and R1, but keep values on the stack for the
   // decompiler.
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R0);
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R1.scratchReg());
+  masm.loadValue(frame.addressOfStackValue(-2), R0);
+  masm.unboxObject(frame.addressOfStackValue(-1), R1.scratchReg());
 
   prepareVMCall();
 
   pushArg(R1.scratchReg());
   pushArg(R0);
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-3)), R0.scratchReg());
+  masm.unboxObject(frame.addressOfStackValue(-3), R0.scratchReg());
   pushArg(R0.scratchReg());
   pushBytecodePCArg();
 
   if (!callVM(InitElemGetterSetterInfo)) {
     return false;
   }
 
   frame.popn(2);
@@ -3229,29 +3192,29 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_INITELEM_INC() {
   // Keep the object and rhs on the stack.
   frame.syncStack(0);
 
   // Load object in R0, index in R1.
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-3)), R0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-2)), R1);
+  masm.loadValue(frame.addressOfStackValue(-3), R0);
+  masm.loadValue(frame.addressOfStackValue(-2), R1);
 
   // Call IC.
   if (!emitNextIC()) {
     return false;
   }
 
   // Pop the rhs
   frame.pop();
 
   // Increment index
-  Address indexAddr = frame.addressOfStackValue(frame.peek(-1));
+  Address indexAddr = frame.addressOfStackValue(-1);
 #ifdef DEBUG
   Label isInt32;
   masm.branchTestInt32(Assembler::Equal, indexAddr, &isInt32);
   masm.assumeUnreachable("INITELEM_INC index must be Int32");
   masm.bind(&isInt32);
 #endif
   masm.incrementInt32Value(indexAddr);
   return true;
@@ -3270,17 +3233,17 @@ bool BaselineInterpreterCodeGen::emit_JS
 
 template <>
 bool BaselineCompilerCodeGen::emit_JSOP_SETLOCAL() {
   // Ensure no other StackValue refers to the old value, for instance i + (i =
   // 3). This also allows us to use R0 as scratch below.
   frame.syncStack(1);
 
   uint32_t local = GET_LOCALNO(handler.pc());
-  storeValue(frame.peek(-1), frame.addressOfLocal(local), R0);
+  frame.storeStackValue(-1, frame.addressOfLocal(local), R0);
   return true;
 }
 
 template <>
 bool BaselineInterpreterCodeGen::emit_JSOP_SETLOCAL() {
   MOZ_CRASH("NYI: interpreter JSOP_SETLOCAL");
 }
 
@@ -3293,17 +3256,17 @@ bool BaselineCompilerCodeGen::emitFormal
   // Fast path: the script does not use |arguments| or formals don't
   // alias the arguments object.
   if (!script->argumentsAliasesFormals()) {
     if (op == JSOP_GETARG) {
       frame.pushArg(arg);
     } else {
       // See the comment in emit_JSOP_SETLOCAL.
       frame.syncStack(1);
-      storeValue(frame.peek(-1), frame.addressOfArg(arg), R0);
+      frame.storeStackValue(-1, frame.addressOfArg(arg), R0);
     }
 
     return true;
   }
 
   // Sync so that we can use R0.
   frame.syncStack(0);
 
@@ -3313,17 +3276,17 @@ bool BaselineCompilerCodeGen::emitFormal
   Label done;
   if (!script->needsArgsObj()) {
     Label hasArgsObj;
     masm.branchTest32(Assembler::NonZero, frame.addressOfFlags(),
                       Imm32(BaselineFrame::HAS_ARGS_OBJ), &hasArgsObj);
     if (op == JSOP_GETARG) {
       masm.loadValue(frame.addressOfArg(arg), R0);
     } else {
-      storeValue(frame.peek(-1), frame.addressOfArg(arg), R0);
+      frame.storeStackValue(-1, frame.addressOfArg(arg), R0);
     }
     masm.jump(&done);
     masm.bind(&hasArgsObj);
   }
 
   // Load the arguments object data vector.
   Register reg = R2.scratchReg();
   masm.loadPtr(
@@ -3332,17 +3295,17 @@ bool BaselineCompilerCodeGen::emitFormal
 
   // Load/store the argument.
   Address argAddr(reg, ArgumentsData::offsetOfArgs() + arg * sizeof(Value));
   if (op == JSOP_GETARG) {
     masm.loadValue(argAddr, R0);
     frame.push(R0);
   } else {
     masm.guardedCallPreBarrier(argAddr, MIRType::Value);
-    masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+    masm.loadValue(frame.addressOfStackValue(-1), R0);
     masm.storeValue(R0, argAddr);
 
     MOZ_ASSERT(frame.numUnsyncedSlots() == 0);
 
     Register temp = R1.scratchReg();
 
     // Reload the arguments object
     Register reg = R2.scratchReg();
@@ -3654,17 +3617,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 typedef bool (*OptimizeSpreadCallFn)(JSContext*, HandleValue, bool*);
 static const VMFunction OptimizeSpreadCallInfo =
     FunctionInfo<OptimizeSpreadCallFn>(OptimizeSpreadCall,
                                        "OptimizeSpreadCall");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_OPTIMIZE_SPREADCALL() {
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
 
   if (!callVM(OptimizeSpreadCallInfo)) {
     return false;
   }
 
@@ -4195,17 +4158,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 typedef bool (*ToIdFn)(JSContext*, HandleValue, MutableHandleValue);
 static const VMFunction ToIdInfo =
     FunctionInfo<ToIdFn>(js::ToIdOperation, "ToIdOperation");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TOID() {
   // Load index in R0, but keep values on the stack for the decompiler.
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   // No-op if the index is trivally convertable to an id.
   Label done;
   masm.branchTestInt32(Assembler::Equal, R0, &done);
   masm.branchTestString(Assembler::Equal, R0, &done);
   masm.branchTestSymbol(Assembler::Equal, R0, &done);
 
   prepareVMCall();
@@ -4224,17 +4187,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
 typedef JSObject* (*ToAsyncFn)(JSContext*, HandleFunction);
 static const VMFunction ToAsyncInfo =
     FunctionInfo<ToAsyncFn>(js::WrapAsyncFunction, "ToAsync");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TOASYNC() {
   frame.syncStack(0);
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
+  masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
 
   prepareVMCall();
   pushArg(R0.scratchReg());
 
   if (!callVM(ToAsyncInfo)) {
     return false;
   }
 
@@ -4246,17 +4209,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
 typedef JSObject* (*ToAsyncGenFn)(JSContext*, HandleFunction);
 static const VMFunction ToAsyncGenInfo =
     FunctionInfo<ToAsyncGenFn>(js::WrapAsyncGenerator, "ToAsyncGen");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TOASYNCGEN() {
   frame.syncStack(0);
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), R0.scratchReg());
+  masm.unboxObject(frame.addressOfStackValue(-1), R0.scratchReg());
 
   prepareVMCall();
   pushArg(R0.scratchReg());
 
   if (!callVM(ToAsyncGenInfo)) {
     return false;
   }
 
@@ -4268,18 +4231,18 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
 typedef JSObject* (*ToAsyncIterFn)(JSContext*, HandleObject, HandleValue);
 static const VMFunction ToAsyncIterInfo =
     FunctionInfo<ToAsyncIterFn>(js::CreateAsyncFromSyncIterator, "ToAsyncIter");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TOASYNCITER() {
   frame.syncStack(0);
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-2)), R0.scratchReg());
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
+  masm.unboxObject(frame.addressOfStackValue(-2), R0.scratchReg());
+  masm.loadValue(frame.addressOfStackValue(-1), R1);
 
   prepareVMCall();
   pushArg(R1);
   pushArg(R0.scratchReg());
 
   if (!callVM(ToAsyncIterInfo)) {
     return false;
   }
@@ -4292,33 +4255,33 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
 typedef bool (*TrySkipAwaitFn)(JSContext*, HandleValue, MutableHandleValue);
 static const VMFunction TrySkipAwaitInfo =
     FunctionInfo<TrySkipAwaitFn>(jit::TrySkipAwait, "TrySkipAwait");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_TRYSKIPAWAIT() {
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
 
   if (!callVM(TrySkipAwaitInfo)) {
     return false;
   }
 
   Label cannotSkip, done;
   masm.branchTestMagicValue(Assembler::Equal, R0, JS_CANNOT_SKIP_AWAIT,
                             &cannotSkip);
   masm.moveValue(BooleanValue(true), R1);
   masm.jump(&done);
 
   masm.bind(&cannotSkip);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
   masm.moveValue(BooleanValue(false), R1);
 
   masm.bind(&done);
 
   frame.pop();
   frame.push(R0);
   frame.push(R1);
   return true;
@@ -4327,17 +4290,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 typedef bool (*ThrowObjectCoercibleFn)(JSContext*, HandleValue);
 static const VMFunction ThrowObjectCoercibleInfo =
     FunctionInfo<ThrowObjectCoercibleFn>(ThrowObjectCoercible,
                                          "ThrowObjectCoercible");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CHECKOBJCOERCIBLE() {
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   Label fail, done;
 
   masm.branchTestUndefined(Assembler::Equal, R0, &fail);
   masm.branchTestNull(Assembler::NotEqual, R0, &done);
 
   masm.bind(&fail);
   prepareVMCall();
@@ -4465,33 +4428,33 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
   frame.push(R0);
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_MOREITER() {
   frame.syncStack(0);
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   if (!emitNextIC()) {
     return false;
   }
 
   frame.push(R0);
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emitIsMagicValue() {
   frame.syncStack(0);
 
   Label isMagic, done;
-  masm.branchTestMagic(Assembler::Equal,
-                       frame.addressOfStackValue(frame.peek(-1)), &isMagic);
+  masm.branchTestMagic(Assembler::Equal, frame.addressOfStackValue(-1),
+                       &isMagic);
   masm.moveValue(BooleanValue(false), R0);
   masm.jump(&done);
 
   masm.bind(&isMagic);
   masm.moveValue(BooleanValue(true), R0);
 
   masm.bind(&done);
   frame.push(R0, JSVAL_TYPE_BOOLEAN);
@@ -4530,17 +4493,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 
   frame.push(R0);
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_SETRVAL() {
   // Store to the frame's return value slot.
-  storeValue(frame.peek(-1), frame.addressOfReturnValue(), R2);
+  frame.storeStackValue(-1, frame.addressOfReturnValue(), R2);
   masm.or32(Imm32(BaselineFrame::HAS_RVAL), frame.addressOfFlags());
   frame.pop();
   return true;
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CALLEE() {
   MOZ_ASSERT(function());
@@ -4768,17 +4731,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_INITIALYIELD() {
   frame.syncStack(0);
   MOZ_ASSERT(frame.stackDepth() == 1);
 
   Register genObj = R2.scratchReg();
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), genObj);
+  masm.unboxObject(frame.addressOfStackValue(-1), genObj);
 
   MOZ_ASSERT_IF(handler.maybePC(), GET_RESUMEINDEX(handler.maybePC()) == 0);
   masm.storeValue(Int32Value(0),
                   Address(genObj, GeneratorObject::offsetOfResumeIndexSlot()));
 
   Register envObj = R0.scratchReg();
   Address envChainSlot(genObj, GeneratorObject::offsetOfEnvironmentChainSlot());
   masm.loadPtr(frame.addressOfEnvironmentChain(), envObj);
@@ -4845,17 +4808,17 @@ bool BaselineCodeGen<Handler>::emit_JSOP
     pushArg(R1.scratchReg());
     pushArg(genObj);
 
     if (!callVM(NormalSuspendInfo)) {
       return false;
     }
   }
 
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), JSReturnOperand);
+  masm.loadValue(frame.addressOfStackValue(-1), JSReturnOperand);
   return emitReturn();
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_AWAIT() {
   return emit_JSOP_YIELD();
 }
 
@@ -4932,17 +4895,17 @@ bool BaselineCompilerCodeGen::emit_JSOP_
   frame.syncStack(0);
   masm.assertStackAlignment(sizeof(Value), 0);
 
   AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
   regs.take(BaselineFrameReg);
 
   // Load generator object.
   Register genObj = regs.takeAny();
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-2)), genObj);
+  masm.unboxObject(frame.addressOfStackValue(-2), genObj);
 
   // Load callee.
   Register callee = regs.takeAny();
   masm.unboxObject(Address(genObj, GeneratorObject::offsetOfCalleeSlot()),
                    callee);
 
   // Load the script. Note that we don't relazify generator scripts, so it's
   // guaranteed to be non-lazy.
@@ -4989,17 +4952,17 @@ bool BaselineCompilerCodeGen::emit_JSOP_
   masm.Push(Imm32(0));  // actual argc
   masm.PushCalleeToken(callee, /* constructing = */ false);
   masm.Push(scratch2);  // frame descriptor
 
   regs.add(callee);
 
   // Load the return value.
   ValueOperand retVal = regs.takeAnyValue();
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), retVal);
+  masm.loadValue(frame.addressOfStackValue(-1), retVal);
 
   // Push a fake return address on the stack. We will resume here when the
   // generator returns.
   Label genStart, returnTarget;
 #ifdef JS_USE_LINK_REGISTER
   masm.call(&genStart);
 #else
   masm.callAndPushReturnAddress(&genStart);
@@ -5163,28 +5126,28 @@ bool BaselineCompilerCodeGen::emit_JSOP_
     pushArg(ImmGCPtr(cx->names().next));
   } else if (resumeKind == GeneratorObject::THROW) {
     pushArg(ImmGCPtr(cx->names().throw_));
   } else {
     MOZ_ASSERT(resumeKind == GeneratorObject::RETURN);
     pushArg(ImmGCPtr(cx->names().return_));
   }
 
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), retVal);
+  masm.loadValue(frame.addressOfStackValue(-1), retVal);
   pushArg(retVal);
   pushArg(genObj);
 
   if (!callVM(InterpretResumeInfo)) {
     return false;
   }
 
   // After the generator returns, we restore the stack pointer, switch back to
   // the current realm, push the return value, and we're done.
   masm.bind(&returnTarget);
-  masm.computeEffectiveAddress(frame.addressOfStackValue(frame.peek(-1)),
+  masm.computeEffectiveAddress(frame.addressOfStackValue(-1),
                                masm.getStackPointer());
   masm.switchToRealm(script->realm(), R2.scratchReg());
   frame.popn(2);
   frame.push(R0);
   return true;
 }
 
 template <>
@@ -5196,17 +5159,17 @@ typedef bool (*CheckSelfHostedFn)(JSCont
 static const VMFunction CheckSelfHostedInfo = FunctionInfo<CheckSelfHostedFn>(
     js::Debug_CheckSelfHosted, "Debug_CheckSelfHosted");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_DEBUGCHECKSELFHOSTED() {
 #ifdef DEBUG
   frame.syncStack(0);
 
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
   if (!callVM(CheckSelfHostedInfo)) {
     return false;
   }
 #endif
   return true;
@@ -5239,31 +5202,31 @@ static const VMFunction CheckClassHerita
     FunctionInfo<CheckClassHeritageOperationFn>(js::CheckClassHeritageOperation,
                                                 "CheckClassHeritageOperation");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_CHECKCLASSHERITAGE() {
   frame.syncStack(0);
 
   // Leave the heritage value on the stack.
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
   return callVM(CheckClassHeritageOperationInfo);
 }
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_INITHOMEOBJECT() {
   // Load HomeObject in R0.
   frame.popRegsAndSync(1);
 
   // Load function off stack
   Register func = R2.scratchReg();
-  masm.unboxObject(frame.addressOfStackValue(frame.peek(-1)), func);
+  masm.unboxObject(frame.addressOfStackValue(-1), func);
 
   // Set HOMEOBJECT_SLOT
   Address addr(func, FunctionExtended::offsetOfMethodHomeObjectSlot());
   masm.guardedCallPreBarrier(addr, MIRType::Value);
   masm.storeValue(R0, addr);
 
   Register temp = R1.scratchReg();
   Label skipBarrier;
@@ -5298,17 +5261,17 @@ static const VMFunction ObjectWithProtoO
     FunctionInfo<ObjectWithProtoOperationFn>(js::ObjectWithProtoOperation,
                                              "ObjectWithProtoOperationInfo");
 
 template <typename Handler>
 bool BaselineCodeGen<Handler>::emit_JSOP_OBJWITHPROTO() {
   frame.syncStack(0);
 
   // Leave the proto value on the stack for the decompiler
-  masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0);
+  masm.loadValue(frame.addressOfStackValue(-1), R0);
 
   prepareVMCall();
   pushArg(R0);
   if (!callVM(ObjectWithProtoOperationInfo)) {
     return false;
   }
 
   masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, R0);
--- a/js/src/jit/BaselineCompiler.h
+++ b/js/src/jit/BaselineCompiler.h
@@ -348,19 +348,16 @@ class BaselineCodeGen {
   void emitLoadReturnValue(ValueOperand val);
 
   MOZ_MUST_USE bool emitNextIC();
   MOZ_MUST_USE bool emitInterruptCheck();
   MOZ_MUST_USE bool emitWarmUpCounterIncrement();
   MOZ_MUST_USE bool emitTraceLoggerResume(Register script,
                                           AllocatableGeneralRegisterSet& regs);
 
-  void storeValue(const StackValue* source, const Address& dest,
-                  const ValueOperand& scratch);
-
 #define EMIT_OP(op) bool emit_##op();
   OPCODE_LIST(EMIT_OP)
 #undef EMIT_OP
 
   // JSOP_NEG, JSOP_BITNOT
   MOZ_MUST_USE bool emitUnaryArith();
 
   // JSOP_BITXOR, JSOP_LSH, JSOP_ADD etc.
@@ -522,24 +519,26 @@ class BaselineCompiler final : private B
   }
 
  private:
   PCMappingSlotInfo getStackTopSlotInfo() {
     MOZ_ASSERT(frame.numUnsyncedSlots() <= 2);
     switch (frame.numUnsyncedSlots()) {
       case 0:
         return PCMappingSlotInfo::MakeSlotInfo();
-      case 1:
-        return PCMappingSlotInfo::MakeSlotInfo(
-            PCMappingSlotInfo::ToSlotLocation(frame.peek(-1)));
+      case 1: {
+        PCMappingSlotInfo::SlotLocation loc = frame.stackValueSlotLocation(-1);
+        return PCMappingSlotInfo::MakeSlotInfo(loc);
+      }
       case 2:
-      default:
-        return PCMappingSlotInfo::MakeSlotInfo(
-            PCMappingSlotInfo::ToSlotLocation(frame.peek(-1)),
-            PCMappingSlotInfo::ToSlotLocation(frame.peek(-2)));
+      default: {
+        PCMappingSlotInfo::SlotLocation loc1 = frame.stackValueSlotLocation(-1);
+        PCMappingSlotInfo::SlotLocation loc2 = frame.stackValueSlotLocation(-2);
+        return PCMappingSlotInfo::MakeSlotInfo(loc1, loc2);
+      }
     }
   }
 
   BytecodeAnalysis& analysis() { return analysis_; }
 
   MethodStatus emitBody();
 
   void emitInitializeLocals();
--- a/js/src/jit/BaselineFrameInfo.cpp
+++ b/js/src/jit/BaselineFrameInfo.cpp
@@ -141,16 +141,52 @@ void FrameInfo::popRegsAndSync(uint32_t 
       popValue(R0);
       break;
     }
     default:
       MOZ_CRASH("Invalid uses");
   }
 }
 
+void FrameInfo::storeStackValue(int32_t depth, const Address& dest,
+                                const ValueOperand& scratch) {
+  const StackValue* source = peek(depth);
+  switch (source->kind()) {
+    case StackValue::Constant:
+      masm.storeValue(source->constant(), dest);
+      break;
+    case StackValue::Register:
+      masm.storeValue(source->reg(), dest);
+      break;
+    case StackValue::LocalSlot:
+      masm.loadValue(addressOfLocal(source->localSlot()), scratch);
+      masm.storeValue(scratch, dest);
+      break;
+    case StackValue::ArgSlot:
+      masm.loadValue(addressOfArg(source->argSlot()), scratch);
+      masm.storeValue(scratch, dest);
+      break;
+    case StackValue::ThisSlot:
+      masm.loadValue(addressOfThis(), scratch);
+      masm.storeValue(scratch, dest);
+      break;
+    case StackValue::EvalNewTargetSlot:
+      MOZ_ASSERT(script->isForEval());
+      masm.loadValue(addressOfEvalNewTarget(), scratch);
+      masm.storeValue(scratch, dest);
+      break;
+    case StackValue::Stack:
+      masm.loadValue(addressOfStackValue(depth), scratch);
+      masm.storeValue(scratch, dest);
+      break;
+    default:
+      MOZ_CRASH("Invalid kind");
+  }
+}
+
 #ifdef DEBUG
 void FrameInfo::assertValidState(const BytecodeInfo& info) {
   // Check stack depth.
   MOZ_ASSERT(stackDepth() == info.stackDepth);
 
   // Start at the bottom, find the first value that's not synced.
   uint32_t i = 0;
   for (; i < stackDepth(); i++) {
@@ -180,8 +216,24 @@ void FrameInfo::assertValidState(const B
         usedR1 = true;
       } else {
         MOZ_CRASH("Invalid register");
       }
     }
   }
 }
 #endif
+
+PCMappingSlotInfo::SlotLocation FrameInfo::stackValueSlotLocation(
+    int32_t depth) {
+  const StackValue* stackVal = peek(depth);
+
+  if (stackVal->kind() == StackValue::Register) {
+    if (stackVal->reg() == R0) {
+      return PCMappingSlotInfo::SlotInR0;
+    }
+    MOZ_ASSERT(stackVal->reg() == R1);
+    return PCMappingSlotInfo::SlotInR1;
+  }
+
+  MOZ_ASSERT(stackVal->kind() != StackValue::Stack);
+  return PCMappingSlotInfo::SlotIgnore;
+}
--- a/js/src/jit/BaselineFrameInfo.h
+++ b/js/src/jit/BaselineFrameInfo.h
@@ -7,16 +7,17 @@
 #ifndef jit_BaselineFrameInfo_h
 #define jit_BaselineFrameInfo_h
 
 #include "mozilla/Attributes.h"
 
 #include <new>
 
 #include "jit/BaselineFrame.h"
+#include "jit/BaselineJIT.h"
 #include "jit/FixedList.h"
 #include "jit/MacroAssembler.h"
 #include "jit/SharedICRegisters.h"
 
 namespace js {
 namespace jit {
 
 struct BytecodeInfo;
@@ -88,17 +89,16 @@ class StackValue {
   StackValue() { reset(); }
 
   Kind kind() const { return kind_; }
   bool hasKnownType() const { return knownType_ != JSVAL_TYPE_UNKNOWN; }
   bool hasKnownType(JSValueType type) const {
     MOZ_ASSERT(type != JSVAL_TYPE_UNKNOWN);
     return knownType_ == type;
   }
-  bool isKnownBoolean() const { return hasKnownType(JSVAL_TYPE_BOOLEAN); }
   JSValueType knownType() const {
     MOZ_ASSERT(hasKnownType());
     return knownType_;
   }
   void reset() {
 #ifdef DEBUG
     kind_ = Uninitialized;
     knownType_ = JSVAL_TYPE_UNKNOWN;
@@ -176,35 +176,36 @@ class FrameInfo {
 
  private:
   inline StackValue* rawPush() {
     StackValue* val = &stack[spIndex++];
     val->reset();
     return val;
   }
 
+  inline StackValue* peek(int32_t index) const {
+    MOZ_ASSERT(index < 0);
+    return const_cast<StackValue*>(&stack[spIndex + index]);
+  }
+
  public:
   inline size_t stackDepth() const { return spIndex; }
   inline void setStackDepth(uint32_t newDepth) {
     if (newDepth <= stackDepth()) {
       spIndex = newDepth;
     } else {
       uint32_t diff = newDepth - stackDepth();
       for (uint32_t i = 0; i < diff; i++) {
         StackValue* val = rawPush();
         val->setStack();
       }
 
       MOZ_ASSERT(spIndex == newDepth);
     }
   }
-  inline StackValue* peek(int32_t index) const {
-    MOZ_ASSERT(index < 0);
-    return const_cast<StackValue*>(&stack[spIndex + index]);
-  }
 
   inline void pop(StackAdjustment adjust = AdjustStack);
   inline void popn(uint32_t n, StackAdjustment adjust = AdjustStack);
   inline void push(const Value& val) {
     StackValue* sv = rawPush();
     sv->setConstant(val);
   }
   inline void push(const ValueOperand& val,
@@ -263,17 +264,18 @@ class FrameInfo {
   }
   Address addressOfReturnValue() const {
     return Address(BaselineFrameReg,
                    BaselineFrame::reverseOffsetOfReturnValue());
   }
   Address addressOfArgsObj() const {
     return Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj());
   }
-  Address addressOfStackValue(const StackValue* value) const {
+  Address addressOfStackValue(int32_t depth) const {
+    const StackValue* value = peek(depth);
     MOZ_ASSERT(value->kind() == StackValue::Stack);
     size_t slot = value - &stack[0];
     MOZ_ASSERT(slot < stackDepth());
     return Address(BaselineFrameReg,
                    BaselineFrame::reverseOffsetOfLocal(nlocals() + slot));
   }
   Address addressOfScratchValue() const {
     return Address(BaselineFrameReg,
@@ -286,16 +288,25 @@ class FrameInfo {
   void syncStack(uint32_t uses);
   uint32_t numUnsyncedSlots();
   void popRegsAndSync(uint32_t uses);
 
   inline void assertSyncedStack() const {
     MOZ_ASSERT_IF(stackDepth() > 0, peek(-1)->kind() == StackValue::Stack);
   }
 
+  bool stackValueHasKnownType(int32_t depth, JSValueType type) const {
+    return peek(depth)->hasKnownType(type);
+  }
+
+  void storeStackValue(int32_t depth, const Address& dest,
+                       const ValueOperand& scratch);
+
+  PCMappingSlotInfo::SlotLocation stackValueSlotLocation(int32_t depth);
+
 #ifdef DEBUG
   // Assert the state is valid before excuting "pc".
   void assertValidState(const BytecodeInfo& info);
 #else
   inline void assertValidState(const BytecodeInfo& info) {}
 #endif
 };
 
--- a/js/src/jit/BaselineJIT.cpp
+++ b/js/src/jit/BaselineJIT.cpp
@@ -33,29 +33,16 @@
 #include "vm/Stack-inl.h"
 
 using mozilla::BinarySearchIf;
 using mozilla::DebugOnly;
 
 using namespace js;
 using namespace js::jit;
 
-/* static */ PCMappingSlotInfo::SlotLocation PCMappingSlotInfo::ToSlotLocation(
-    const StackValue* stackVal) {
-  if (stackVal->kind() == StackValue::Register) {
-    if (stackVal->reg() == R0) {
-      return SlotInR0;
-    }
-    MOZ_ASSERT(stackVal->reg() == R1);
-    return SlotInR1;
-  }
-  MOZ_ASSERT(stackVal->kind() != StackValue::Stack);
-  return SlotIgnore;
-}
-
 void ICStubSpace::freeAllAfterMinorGC(Zone* zone) {
   if (zone->isAtomsZone()) {
     MOZ_ASSERT(allocator_.isEmpty());
   } else {
     JSRuntime* rt = zone->runtimeFromMainThread();
     rt->gc.queueAllLifoBlocksForFreeAfterMinorGC(&allocator_);
   }
 }
--- a/js/src/jit/BaselineJIT.h
+++ b/js/src/jit/BaselineJIT.h
@@ -16,17 +16,16 @@
 #include "vm/EnvironmentObject.h"
 #include "vm/JSContext.h"
 #include "vm/Realm.h"
 #include "vm/TraceLogging.h"
 
 namespace js {
 namespace jit {
 
-class StackValue;
 class ICEntry;
 class ICStub;
 class ControlFlowGraph;
 class ReturnAddressEntry;
 
 class PCMappingSlotInfo {
   uint8_t slotInfo_;
 
@@ -42,18 +41,16 @@ class PCMappingSlotInfo {
   PCMappingSlotInfo() : slotInfo_(0) {}
 
   explicit PCMappingSlotInfo(uint8_t slotInfo) : slotInfo_(slotInfo) {}
 
   static inline bool ValidSlotLocation(SlotLocation loc) {
     return (loc == SlotInR0) || (loc == SlotInR1) || (loc == SlotIgnore);
   }
 
-  static SlotLocation ToSlotLocation(const StackValue* stackVal);
-
   inline static PCMappingSlotInfo MakeSlotInfo() {
     return PCMappingSlotInfo(0);
   }
 
   inline static PCMappingSlotInfo MakeSlotInfo(SlotLocation topSlotLoc) {
     MOZ_ASSERT(ValidSlotLocation(topSlotLoc));
     return PCMappingSlotInfo(1 | (topSlotLoc << 2));
   }