|
|
|
@ -46,6 +46,13 @@ using mozilla::Maybe;
|
|
|
|
|
namespace js {
|
|
|
|
|
namespace jit {
|
|
|
|
|
|
|
|
|
|
// When generating the Baseline Interpreter, this register is guaranteed to hold
|
|
|
|
|
// the bytecode pc at the start of a bytecode instruction. Instructions are free
|
|
|
|
|
// to clobber this register: the frame's interpreterPC is the canonical
|
|
|
|
|
// location for the pc. This register is useful to avoid loading the pc when
|
|
|
|
|
// compiling simple ops like JSOP_INT8 or JSOP_GETLOCAL.
|
|
|
|
|
static constexpr Register PCRegAtStart = R2.scratchReg();
|
|
|
|
|
|
|
|
|
|
BaselineCompilerHandler::BaselineCompilerHandler(JSContext* cx,
|
|
|
|
|
MacroAssembler& masm,
|
|
|
|
|
TempAllocator& alloc,
|
|
|
|
@ -371,6 +378,35 @@ MethodStatus BaselineCompiler::compile() {
|
|
|
|
|
return Method_Compiled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LoadInt8Operand(MacroAssembler& masm, Register pc, Register dest) {
|
|
|
|
|
masm.load8SignExtend(Address(pc, sizeof(jsbytecode)), dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LoadUint8Operand(MacroAssembler& masm, Register pc, Register dest) {
|
|
|
|
|
masm.load8ZeroExtend(Address(pc, sizeof(jsbytecode)), dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LoadUint16Operand(MacroAssembler& masm, Register pc,
|
|
|
|
|
Register dest) {
|
|
|
|
|
masm.load16ZeroExtend(Address(pc, sizeof(jsbytecode)), dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LoadInt32Operand(MacroAssembler& masm, Register pc, Register dest) {
|
|
|
|
|
masm.load32(Address(pc, sizeof(jsbytecode)), dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LoadInt32OperandSignExtendToPtr(MacroAssembler& masm, Register pc,
|
|
|
|
|
Register dest) {
|
|
|
|
|
masm.load32SignExtendToPtr(Address(pc, sizeof(jsbytecode)), dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void LoadUint24Operand(MacroAssembler& masm, Register pc, size_t offset,
|
|
|
|
|
Register dest) {
|
|
|
|
|
// Load the opcode and operand, then left shift to discard the opcode.
|
|
|
|
|
masm.load32(Address(pc, offset), dest);
|
|
|
|
|
masm.rshift32(Imm32(8), dest);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
void BaselineCompilerCodeGen::loadScript(Register dest) {
|
|
|
|
|
masm.movePtr(ImmGCPtr(handler.script()), dest);
|
|
|
|
@ -1309,7 +1345,9 @@ bool BaselineCompilerCodeGen::emit_JSOP_POPN() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_POPN() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_POPN");
|
|
|
|
|
LoadUint16Operand(masm, PCRegAtStart, R0.scratchReg());
|
|
|
|
|
frame.popn(R0.scratchReg());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -1328,7 +1366,10 @@ bool BaselineCompilerCodeGen::emit_JSOP_DUPAT() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_DUPAT() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_DUPAT");
|
|
|
|
|
LoadUint24Operand(masm, PCRegAtStart, 0, R0.scratchReg());
|
|
|
|
|
masm.loadValue(frame.addressOfStackValue(R0.scratchReg()), R0);
|
|
|
|
|
frame.push(R0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename Handler>
|
|
|
|
@ -1397,7 +1438,26 @@ bool BaselineCompilerCodeGen::emit_JSOP_PICK() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_PICK() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_PICK");
|
|
|
|
|
// First, move the value to move up into R0.
|
|
|
|
|
LoadUint8Operand(masm, PCRegAtStart, PCRegAtStart);
|
|
|
|
|
masm.loadValue(frame.addressOfStackValue(PCRegAtStart), R0);
|
|
|
|
|
|
|
|
|
|
// Move the other values down.
|
|
|
|
|
Label top, done;
|
|
|
|
|
masm.bind(&top);
|
|
|
|
|
masm.sub32(Imm32(1), PCRegAtStart);
|
|
|
|
|
masm.branchTest32(Assembler::Signed, PCRegAtStart, PCRegAtStart, &done);
|
|
|
|
|
{
|
|
|
|
|
masm.loadValue(frame.addressOfStackValue(PCRegAtStart), R1);
|
|
|
|
|
masm.storeValue(R1, frame.addressOfStackValue(PCRegAtStart, sizeof(Value)));
|
|
|
|
|
masm.jump(&top);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
masm.bind(&done);
|
|
|
|
|
|
|
|
|
|
// Replace value on top of the stack with R0.
|
|
|
|
|
masm.storeValue(R0, frame.addressOfStackValue(-1));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -1412,6 +1472,9 @@ bool BaselineCompilerCodeGen::emit_JSOP_UNPICK() {
|
|
|
|
|
// First, move value at -1 into R0.
|
|
|
|
|
masm.loadValue(frame.addressOfStackValue(-1), R0);
|
|
|
|
|
|
|
|
|
|
MOZ_ASSERT(GET_INT8(handler.pc()) > 0,
|
|
|
|
|
"Interpreter code assumes JSOP_UNPICK operand > 0");
|
|
|
|
|
|
|
|
|
|
// Move the other values up.
|
|
|
|
|
int32_t depth = -(GET_INT8(handler.pc()) + 1);
|
|
|
|
|
for (int32_t i = -1; i > depth; i--) {
|
|
|
|
@ -1429,7 +1492,49 @@ bool BaselineCompilerCodeGen::emit_JSOP_UNPICK() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_UNPICK() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_UNPICK");
|
|
|
|
|
LoadUint8Operand(masm, PCRegAtStart, PCRegAtStart);
|
|
|
|
|
|
|
|
|
|
// Move the top value into R0.
|
|
|
|
|
masm.loadValue(frame.addressOfStackValue(-1), R0);
|
|
|
|
|
|
|
|
|
|
// Overwrite the nth stack value with R0 but first save the old value in R1.
|
|
|
|
|
masm.loadValue(frame.addressOfStackValue(PCRegAtStart), R1);
|
|
|
|
|
masm.storeValue(R0, frame.addressOfStackValue(PCRegAtStart));
|
|
|
|
|
|
|
|
|
|
// Now for each slot x in [n-1, 1] do the following:
|
|
|
|
|
//
|
|
|
|
|
// * Store the value in slot x in R0.
|
|
|
|
|
// * Store the value in the previous slot (now in R1) in slot x.
|
|
|
|
|
// * Move R0 to R1.
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
// Assert the operand > 0 so the sub32 below doesn't "underflow" to negative
|
|
|
|
|
// values.
|
|
|
|
|
{
|
|
|
|
|
Label ok;
|
|
|
|
|
masm.branch32(Assembler::GreaterThan, PCRegAtStart, Imm32(0), &ok);
|
|
|
|
|
masm.assumeUnreachable("JSOP_UNPICK with operand <= 0?");
|
|
|
|
|
masm.bind(&ok);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
Label top, done;
|
|
|
|
|
masm.bind(&top);
|
|
|
|
|
masm.sub32(Imm32(1), PCRegAtStart);
|
|
|
|
|
masm.branchTest32(Assembler::Zero, PCRegAtStart, PCRegAtStart, &done);
|
|
|
|
|
{
|
|
|
|
|
// Overwrite stack slot x with slot x + 1, saving the old value in R1.
|
|
|
|
|
masm.loadValue(frame.addressOfStackValue(PCRegAtStart), R0);
|
|
|
|
|
masm.storeValue(R1, frame.addressOfStackValue(PCRegAtStart));
|
|
|
|
|
masm.moveValue(R0, R1);
|
|
|
|
|
masm.jump(&top);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Finally, replace the value on top of the stack (slot 0) with R1. This is
|
|
|
|
|
// the value that used to be in slot 1.
|
|
|
|
|
masm.bind(&done);
|
|
|
|
|
masm.storeValue(R1, frame.addressOfStackValue(-1));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -1444,8 +1549,15 @@ void BaselineCompilerCodeGen::emitJump() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
void BaselineInterpreterCodeGen::emitJump() {
|
|
|
|
|
// We have to add the current pc's jump offset to the frame's pc.
|
|
|
|
|
MOZ_CRASH("NYI: interpreter emitJump");
|
|
|
|
|
// We have to add the current pc's jump offset to the frame's pc. We can use
|
|
|
|
|
// R0 as scratch because we jump to the "next op" label and that assumes a
|
|
|
|
|
// synced stack.
|
|
|
|
|
Register scratch = R0.scratchReg();
|
|
|
|
|
masm.loadPtr(frame.addressOfInterpreterPC(), scratch);
|
|
|
|
|
LoadInt32OperandSignExtendToPtr(masm, scratch, scratch);
|
|
|
|
|
masm.addPtr(frame.addressOfInterpreterPC(), scratch);
|
|
|
|
|
masm.storePtr(scratch, frame.addressOfInterpreterPC());
|
|
|
|
|
masm.jump(handler.interpretOpLabel());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -1965,7 +2077,10 @@ bool BaselineCompilerCodeGen::emit_JSOP_INT8() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_INT8() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_INT8");
|
|
|
|
|
LoadInt8Operand(masm, PCRegAtStart, R0.scratchReg());
|
|
|
|
|
masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
|
|
|
|
|
frame.push(R0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -1976,7 +2091,10 @@ bool BaselineCompilerCodeGen::emit_JSOP_INT32() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_INT32() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_INT32");
|
|
|
|
|
LoadInt32Operand(masm, PCRegAtStart, R0.scratchReg());
|
|
|
|
|
masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
|
|
|
|
|
frame.push(R0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -1987,7 +2105,10 @@ bool BaselineCompilerCodeGen::emit_JSOP_UINT16() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_UINT16() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_UINT16");
|
|
|
|
|
LoadUint16Operand(masm, PCRegAtStart, R0.scratchReg());
|
|
|
|
|
masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
|
|
|
|
|
frame.push(R0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -1998,7 +2119,10 @@ bool BaselineCompilerCodeGen::emit_JSOP_UINT24() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_UINT24() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_UINT24");
|
|
|
|
|
LoadUint24Operand(masm, PCRegAtStart, 0, R0.scratchReg());
|
|
|
|
|
masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
|
|
|
|
|
frame.push(R0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename Handler>
|
|
|
|
@ -3505,9 +3629,23 @@ bool BaselineCompilerCodeGen::emit_JSOP_GETLOCAL() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static BaseValueIndex ComputeAddressOfLocal(MacroAssembler& masm,
|
|
|
|
|
Register indexScratch) {
|
|
|
|
|
// Locals are stored in memory at a negative offset from the frame pointer. We
|
|
|
|
|
// negate the index first to effectively subtract it.
|
|
|
|
|
masm.negPtr(indexScratch);
|
|
|
|
|
return BaseValueIndex(BaselineFrameReg, indexScratch,
|
|
|
|
|
BaselineFrame::reverseOffsetOfLocal(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_GETLOCAL() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_GETLOCAL");
|
|
|
|
|
Register scratch = R0.scratchReg();
|
|
|
|
|
LoadUint24Operand(masm, PCRegAtStart, 0, scratch);
|
|
|
|
|
BaseValueIndex addr = ComputeAddressOfLocal(masm, scratch);
|
|
|
|
|
masm.loadValue(addr, R0);
|
|
|
|
|
frame.push(R0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -3523,7 +3661,12 @@ bool BaselineCompilerCodeGen::emit_JSOP_SETLOCAL() {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emit_JSOP_SETLOCAL() {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter JSOP_SETLOCAL");
|
|
|
|
|
Register scratch = R0.scratchReg();
|
|
|
|
|
LoadUint24Operand(masm, PCRegAtStart, 0, scratch);
|
|
|
|
|
BaseValueIndex addr = ComputeAddressOfLocal(masm, scratch);
|
|
|
|
|
masm.loadValue(frame.addressOfStackValue(-1), R1);
|
|
|
|
|
masm.storeValue(R1, addr);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
@ -3797,7 +3940,7 @@ bool BaselineCompilerCodeGen::emitCall(JSOp op) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update FrameInfo.
|
|
|
|
|
bool construct = op == JSOP_NEW || op == JSOP_SUPERCALL;
|
|
|
|
|
bool construct = IsConstructorCallOp(op);
|
|
|
|
|
frame.popn(2 + argc + construct);
|
|
|
|
|
frame.push(R0);
|
|
|
|
|
return true;
|
|
|
|
@ -3805,7 +3948,25 @@ bool BaselineCompilerCodeGen::emitCall(JSOp op) {
|
|
|
|
|
|
|
|
|
|
template <>
|
|
|
|
|
bool BaselineInterpreterCodeGen::emitCall(JSOp op) {
|
|
|
|
|
MOZ_CRASH("NYI: interpreter emitCall");
|
|
|
|
|
MOZ_ASSERT(IsCallOp(op));
|
|
|
|
|
|
|
|
|
|
// The IC expects argc in R0.
|
|
|
|
|
LoadUint16Operand(masm, PCRegAtStart, R0.scratchReg());
|
|
|
|
|
if (!emitNextIC()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Pop the arguments. We have to reload pc/argc because the IC clobbers them.
|
|
|
|
|
// The return value is in R0 so we can't use that.
|
|
|
|
|
Register scratch = R1.scratchReg();
|
|
|
|
|
uint32_t extraValuesToPop = IsConstructorCallOp(op) ? 3 : 2;
|
|
|
|
|
Register spReg = AsRegister(masm.getStackPointer());
|
|
|
|
|
masm.loadPtr(frame.addressOfInterpreterPC(), scratch);
|
|
|
|
|
LoadUint16Operand(masm, scratch, scratch);
|
|
|
|
|
masm.computeEffectiveAddress(
|
|
|
|
|
BaseValueIndex(spReg, scratch, extraValuesToPop * sizeof(Value)), spReg);
|
|
|
|
|
frame.push(R0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename Handler>
|
|
|
|
|