#include "jit/BaselineFrameInfo.h"
#ifdef DEBUG
# include "jit/BytecodeAnalysis.h"
#endif
#include "jit/BaselineFrameInfo-inl.h"
#include "jit/MacroAssembler-inl.h"
using namespace js;
using namespace js::jit;
bool CompilerFrameInfo::init(TempAllocator& alloc) {
size_t extra = script->isGlobalCode() ? 1 : 0;
size_t nstack =
Max(script->nslots() - script->nfixed(), size_t(MinJITStackSize)) + extra;
if (!stack.init(alloc, nstack)) {
return false;
}
return true;
}
void CompilerFrameInfo::sync(StackValue* val) {
switch (val->kind()) {
case StackValue::Stack:
break;
case StackValue::LocalSlot:
masm.pushValue(addressOfLocal(val->localSlot()));
break;
case StackValue::ArgSlot:
masm.pushValue(addressOfArg(val->argSlot()));
break;
case StackValue::ThisSlot:
masm.pushValue(addressOfThis());
break;
case StackValue::EvalNewTargetSlot:
MOZ_ASSERT(script->isForEval());
masm.pushValue(addressOfEvalNewTarget());
break;
case StackValue::Register:
masm.pushValue(val->reg());
break;
case StackValue::Constant:
masm.pushValue(val->constant());
break;
default:
MOZ_CRASH("Invalid kind");
}
val->setStack();
}
void CompilerFrameInfo::syncStack(uint32_t uses) {
MOZ_ASSERT(uses <= stackDepth());
uint32_t depth = stackDepth() - uses;
for (uint32_t i = 0; i < depth; i++) {
StackValue* current = &stack[i];
sync(current);
}
}
uint32_t CompilerFrameInfo::numUnsyncedSlots() {
uint32_t i = 0;
for (; i < stackDepth(); i++) {
if (peek(-int32_t(i + 1))->kind() == StackValue::Stack) {
break;
}
}
return i;
}
void CompilerFrameInfo::popValue(ValueOperand dest) {
StackValue* val = peek(-1);
switch (val->kind()) {
case StackValue::Constant:
masm.moveValue(val->constant(), dest);
break;
case StackValue::LocalSlot:
masm.loadValue(addressOfLocal(val->localSlot()), dest);
break;
case StackValue::ArgSlot:
masm.loadValue(addressOfArg(val->argSlot()), dest);
break;
case StackValue::ThisSlot:
masm.loadValue(addressOfThis(), dest);
break;
case StackValue::EvalNewTargetSlot:
masm.loadValue(addressOfEvalNewTarget(), dest);
break;
case StackValue::Stack:
masm.popValue(dest);
break;
case StackValue::Register:
masm.moveValue(val->reg(), dest);
break;
default:
MOZ_CRASH("Invalid kind");
}
pop(DontAdjustStack);
}
void CompilerFrameInfo::popRegsAndSync(uint32_t uses) {
MOZ_ASSERT(uses > 0);
MOZ_ASSERT(uses <= 2);
MOZ_ASSERT(uses <= stackDepth());
syncStack(uses);
switch (uses) {
case 1:
popValue(R0);
break;
case 2: {
StackValue* val = peek(-2);
if (val->kind() == StackValue::Register && val->reg() == R1) {
masm.moveValue(R1, ValueOperand(R2));
val->setRegister(R2);
}
popValue(R1);
popValue(R0);
break;
}
default:
MOZ_CRASH("Invalid uses");
}
}
void InterpreterFrameInfo::popRegsAndSync(uint32_t uses) {
switch (uses) {
case 1:
popValue(R0);
break;
case 2: {
popValue(R1);
popValue(R0);
break;
}
default:
MOZ_CRASH("Invalid uses");
}
}
void CompilerFrameInfo::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 CompilerFrameInfo::assertValidState(const BytecodeInfo& info) {
MOZ_ASSERT(stackDepth() == info.stackDepth);
uint32_t i = 0;
for (; i < stackDepth(); i++) {
if (stack[i].kind() != StackValue::Stack) {
break;
}
}
for (; i < stackDepth(); i++) {
MOZ_ASSERT(stack[i].kind() != StackValue::Stack);
}
bool usedR0 = false, usedR1 = false;
for (i = 0; i < stackDepth(); i++) {
if (stack[i].kind() == StackValue::Register) {
ValueOperand reg = stack[i].reg();
if (reg == R0) {
MOZ_ASSERT(!usedR0);
usedR0 = true;
} else if (reg == R1) {
MOZ_ASSERT(!usedR1);
usedR1 = true;
} else {
MOZ_CRASH("Invalid register");
}
}
}
}
#endif
PCMappingSlotInfo::SlotLocation CompilerFrameInfo::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;
}