Bug 1522837 part 11 - Implement some simple ops in BaselineInterpreterCodeGen. r=djvj

Differential Revision: https://phabricator.services.mozilla.com/D18253

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jan de Mooij 2019-03-10 19:43:26 +00:00
Родитель 036413341f
Коммит e554148a4e
9 изменённых файлов: 194 добавлений и 16 удалений

Просмотреть файл

@ -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>

Просмотреть файл

@ -628,6 +628,7 @@ class BaselineCompiler final : private BaselineCompilerCodeGen {
// Interface used by BaselineCodeGen for BaselineInterpreterGenerator.
class BaselineInterpreterHandler {
InterpreterFrameInfo frame_;
Label interpretOp_;
public:
using FrameInfoT = InterpreterFrameInfo;
@ -636,6 +637,8 @@ class BaselineInterpreterHandler {
InterpreterFrameInfo& frame() { return frame_; }
Label* interpretOpLabel() { return &interpretOp_; }
// Interpreter doesn't know the script and pc statically.
jsbytecode* maybePC() const { return nullptr; }
bool isDefinitelyLastOp() const { return false; }

Просмотреть файл

@ -961,6 +961,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
inline void neg32(Register reg) PER_SHARED_ARCH;
inline void neg64(Register64 reg) DEFINED_ON(x86, x64, arm, mips32, mips64);
inline void negPtr(Register reg) PER_ARCH;
inline void negateFloat(FloatRegister reg) PER_SHARED_ARCH;

Просмотреть файл

@ -498,6 +498,8 @@ void MacroAssembler::neg64(Register64 reg) {
as_rsc(reg.high, reg.high, Imm8(0));
}
void MacroAssembler::negPtr(Register reg) { neg32(reg); }
void MacroAssembler::negateDouble(FloatRegister reg) { ma_vneg(reg, reg); }
void MacroAssembler::negateFloat(FloatRegister reg) { ma_vneg_f32(reg, reg); }

Просмотреть файл

@ -483,6 +483,10 @@ void MacroAssembler::neg32(Register reg) {
Negs(ARMRegister(reg, 32), Operand(ARMRegister(reg, 32)));
}
void MacroAssembler::negPtr(Register reg) {
Negs(ARMRegister(reg, 64), Operand(ARMRegister(reg, 64)));
}
void MacroAssembler::negateFloat(FloatRegister reg) {
fneg(ARMFPRegister(reg, 32), ARMFPRegister(reg, 32));
}

Просмотреть файл

@ -264,6 +264,8 @@ void MacroAssembler::inc64(AbsoluteAddress dest) {
void MacroAssembler::neg64(Register64 reg) { negq(reg.reg); }
void MacroAssembler::negPtr(Register reg) { negq(reg); }
// ===============================================================
// Shift functions

Просмотреть файл

@ -343,6 +343,8 @@ void MacroAssembler::neg64(Register64 reg) {
negl(reg.high);
}
void MacroAssembler::negPtr(Register reg) { negl(reg); }
// ===============================================================
// Shift functions

Просмотреть файл

@ -592,11 +592,13 @@ inline bool IsStrictEvalPC(jsbytecode* pc) {
return op == JSOP_STRICTEVAL || op == JSOP_STRICTSPREADEVAL;
}
inline bool IsConstructorCallPC(jsbytecode* pc) {
JSOp op = JSOp(*pc);
inline bool IsConstructorCallOp(JSOp op) {
return op == JSOP_NEW || op == JSOP_SUPERCALL || op == JSOP_SPREADNEW ||
op == JSOP_SPREADSUPERCALL;
}
inline bool IsConstructorCallPC(const jsbytecode* pc) {
return IsConstructorCallOp(JSOp(*pc));
}
inline bool IsSpreadCallPC(jsbytecode* pc) {
JSOp op = JSOp(*pc);

Просмотреть файл

@ -1979,6 +1979,7 @@
MACRO(JSOP_SETFUNNAME, 182, "setfunname", NULL, 2, 2, 1, JOF_UINT8) \
/*
* Moves the top of the stack value under the nth element of the stack.
* Note: n must NOT be 0.
*
* Category: Operators
* Type: Stack Operations