[Liftoff] Fill registers as the right type
When spilling a value to the stack, make sure to fill it as the same type later. Otherwise, we might load garbage from the stack and violate the assumption that the upper 32 bits of a 64 bit register are zero if it currently holds a 32 bit value. R=titzer@chromium.org Bug: v8:7353, v8:6600 Change-Id: I7f2b1b31b7f3c13aa152c682cb59400fb5a3ebf0 Reviewed-on: https://chromium-review.googlesource.com/880682 Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#50797}
This commit is contained in:
parent
daff6e7a0d
commit
ecb3afcaed
@ -46,7 +46,8 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index) {
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -58,7 +59,8 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg) {
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -66,7 +68,8 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index) {
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,8 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index) {
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -58,7 +59,8 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg) {
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -66,7 +68,8 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index) {
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
@ -176,12 +176,13 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index) {
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
|
||||
ValueType type) {
|
||||
DCHECK_NE(dst_index, src_index);
|
||||
if (cache_state_.has_unused_register(kGpReg)) {
|
||||
LiftoffRegister reg = GetUnusedRegister(kGpReg);
|
||||
Fill(reg, src_index);
|
||||
Spill(dst_index, reg);
|
||||
Fill(reg, src_index, type);
|
||||
Spill(dst_index, reg, type);
|
||||
} else {
|
||||
push(liftoff::GetStackSlot(src_index));
|
||||
pop(liftoff::GetStackSlot(dst_index));
|
||||
@ -210,13 +211,21 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src) {
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg) {
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
Operand dst = liftoff::GetStackSlot(index);
|
||||
// TODO(clemensh): Handle different sizes here.
|
||||
if (reg.is_gp()) {
|
||||
mov(dst, reg.gp());
|
||||
} else {
|
||||
movsd(dst, reg.fp());
|
||||
switch (type) {
|
||||
case kWasmI32:
|
||||
mov(dst, reg.gp());
|
||||
break;
|
||||
case kWasmF32:
|
||||
movss(dst, reg.fp());
|
||||
break;
|
||||
case kWasmF64:
|
||||
movsd(dst, reg.fp());
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@ -234,13 +243,21 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index) {
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
|
||||
ValueType type) {
|
||||
Operand src = liftoff::GetStackSlot(index);
|
||||
// TODO(clemensh): Handle different sizes here.
|
||||
if (reg.is_gp()) {
|
||||
mov(reg.gp(), src);
|
||||
} else {
|
||||
movsd(reg.fp(), src);
|
||||
switch (type) {
|
||||
case kWasmI32:
|
||||
mov(reg.gp(), src);
|
||||
break;
|
||||
case kWasmF32:
|
||||
movss(reg.fp(), src);
|
||||
break;
|
||||
case kWasmF64:
|
||||
movsd(reg.fp(), src);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,20 +31,23 @@ class StackTransferRecipe {
|
||||
struct RegisterMove {
|
||||
LiftoffRegister dst;
|
||||
LiftoffRegister src;
|
||||
constexpr RegisterMove(LiftoffRegister dst, LiftoffRegister src)
|
||||
: dst(dst), src(src) {}
|
||||
ValueType type;
|
||||
constexpr RegisterMove(LiftoffRegister dst, LiftoffRegister src,
|
||||
ValueType type)
|
||||
: dst(dst), src(src), type(type) {}
|
||||
};
|
||||
struct RegisterLoad {
|
||||
LiftoffRegister dst;
|
||||
bool is_constant_load; // otherwise load it from the stack.
|
||||
union {
|
||||
uint32_t stack_slot;
|
||||
WasmValue constant;
|
||||
};
|
||||
ValueType type;
|
||||
uint32_t value; // i32 constant if {is_constant_load}, else stack slot.
|
||||
RegisterLoad(LiftoffRegister dst, WasmValue constant)
|
||||
: dst(dst), is_constant_load(true), constant(constant) {}
|
||||
RegisterLoad(LiftoffRegister dst, uint32_t stack_slot)
|
||||
: dst(dst), is_constant_load(false), stack_slot(stack_slot) {}
|
||||
: dst(dst),
|
||||
is_constant_load(true),
|
||||
type(kWasmI32),
|
||||
value(constant.to_i32()) {}
|
||||
RegisterLoad(LiftoffRegister dst, uint32_t stack_slot, ValueType type)
|
||||
: dst(dst), is_constant_load(false), type(type), value(stack_slot) {}
|
||||
};
|
||||
|
||||
public:
|
||||
@ -89,10 +92,11 @@ class StackTransferRecipe {
|
||||
if (executed_moves == 0) {
|
||||
// There is a cycle. Spill one register, then continue.
|
||||
// TODO(clemensh): Use an unused register if available.
|
||||
LiftoffRegister spill_reg = register_moves_.back().src;
|
||||
asm_->Spill(next_spill_slot, spill_reg);
|
||||
RegisterMove& rm = register_moves_.back();
|
||||
LiftoffRegister spill_reg = rm.src;
|
||||
asm_->Spill(next_spill_slot, spill_reg, rm.type);
|
||||
// Remember to reload into the destination register later.
|
||||
LoadStackSlot(register_moves_.back().dst, next_spill_slot);
|
||||
LoadStackSlot(register_moves_.back().dst, next_spill_slot, rm.type);
|
||||
DCHECK_EQ(1, src_reg_use_count[spill_reg.liftoff_code()]);
|
||||
src_reg_use_count[spill_reg.liftoff_code()] = 0;
|
||||
++next_spill_slot;
|
||||
@ -105,9 +109,9 @@ class StackTransferRecipe {
|
||||
|
||||
for (RegisterLoad& rl : register_loads_) {
|
||||
if (rl.is_constant_load) {
|
||||
asm_->LoadConstant(rl.dst, rl.constant);
|
||||
asm_->LoadConstant(rl.dst, WasmValue(rl.value));
|
||||
} else {
|
||||
asm_->Fill(rl.dst, rl.stack_slot);
|
||||
asm_->Fill(rl.dst, rl.value, rl.type);
|
||||
}
|
||||
}
|
||||
register_loads_.clear();
|
||||
@ -117,15 +121,16 @@ class StackTransferRecipe {
|
||||
uint32_t dst_index, uint32_t src_index) {
|
||||
const VarState& dst = dst_state.stack_state[dst_index];
|
||||
const VarState& src = __ cache_state()->stack_state[src_index];
|
||||
DCHECK_EQ(dst.type(), src.type());
|
||||
switch (dst.loc()) {
|
||||
case VarState::kStack:
|
||||
switch (src.loc()) {
|
||||
case VarState::kStack:
|
||||
if (src_index == dst_index) break;
|
||||
asm_->MoveStackValue(dst_index, src_index);
|
||||
asm_->MoveStackValue(dst_index, src_index, src.type());
|
||||
break;
|
||||
case VarState::kRegister:
|
||||
asm_->Spill(dst_index, src.reg());
|
||||
asm_->Spill(dst_index, src.reg(), src.type());
|
||||
break;
|
||||
case VarState::kI32Const:
|
||||
asm_->Spill(dst_index, WasmValue(src.i32_const()));
|
||||
@ -146,11 +151,11 @@ class StackTransferRecipe {
|
||||
uint32_t src_index) {
|
||||
switch (src.loc()) {
|
||||
case VarState::kStack:
|
||||
LoadStackSlot(dst, src_index);
|
||||
LoadStackSlot(dst, src_index, src.type());
|
||||
break;
|
||||
case VarState::kRegister:
|
||||
DCHECK_EQ(dst.reg_class(), src.reg_class());
|
||||
if (dst != src.reg()) MoveRegister(dst, src.reg());
|
||||
if (dst != src.reg()) MoveRegister(dst, src.reg(), src.type());
|
||||
break;
|
||||
case VarState::kI32Const:
|
||||
LoadConstant(dst, WasmValue(src.i32_const()));
|
||||
@ -158,20 +163,23 @@ class StackTransferRecipe {
|
||||
}
|
||||
}
|
||||
|
||||
void MoveRegister(LiftoffRegister dst, LiftoffRegister src) {
|
||||
void MoveRegister(LiftoffRegister dst, LiftoffRegister src, ValueType type) {
|
||||
DCHECK_NE(dst, src);
|
||||
DCHECK_EQ(dst.reg_class(), src.reg_class());
|
||||
DCHECK_EQ(reg_class_for(type), src.reg_class());
|
||||
DCHECK(!move_dst_regs_.has(dst));
|
||||
move_dst_regs_.set(dst);
|
||||
move_src_regs_.set(src);
|
||||
register_moves_.emplace_back(dst, src);
|
||||
register_moves_.emplace_back(dst, src, type);
|
||||
}
|
||||
|
||||
void LoadConstant(LiftoffRegister dst, WasmValue value) {
|
||||
register_loads_.emplace_back(dst, value);
|
||||
}
|
||||
|
||||
void LoadStackSlot(LiftoffRegister dst, uint32_t stack_index) {
|
||||
register_loads_.emplace_back(dst, stack_index);
|
||||
void LoadStackSlot(LiftoffRegister dst, uint32_t stack_index,
|
||||
ValueType type) {
|
||||
register_loads_.emplace_back(dst, stack_index, type);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -183,6 +191,9 @@ class StackTransferRecipe {
|
||||
LiftoffAssembler* const asm_;
|
||||
};
|
||||
|
||||
static constexpr ValueType kWasmIntPtr =
|
||||
kPointerSize == 8 ? kWasmI64 : kWasmI32;
|
||||
|
||||
} // namespace
|
||||
|
||||
// TODO(clemensh): Don't copy the full parent state (this makes us N^2).
|
||||
@ -301,7 +312,7 @@ LiftoffRegister LiftoffAssembler::PopToRegister(RegClass rc,
|
||||
switch (slot.loc()) {
|
||||
case VarState::kStack: {
|
||||
LiftoffRegister reg = GetUnusedRegister(rc, pinned);
|
||||
Fill(reg, cache_state_.stack_height());
|
||||
Fill(reg, cache_state_.stack_height(), slot.type());
|
||||
return reg;
|
||||
}
|
||||
case VarState::kRegister:
|
||||
@ -352,7 +363,7 @@ void LiftoffAssembler::Spill(uint32_t index) {
|
||||
case VarState::kStack:
|
||||
return;
|
||||
case VarState::kRegister:
|
||||
Spill(index, slot.reg());
|
||||
Spill(index, slot.reg(), slot.type());
|
||||
cache_state_.dec_used(slot.reg());
|
||||
break;
|
||||
case VarState::kI32Const:
|
||||
@ -372,7 +383,7 @@ void LiftoffAssembler::SpillAllRegisters() {
|
||||
for (uint32_t i = 0, e = cache_state_.stack_height(); i < e; ++i) {
|
||||
auto& slot = cache_state_.stack_state[i];
|
||||
if (!slot.is_reg()) continue;
|
||||
Spill(i, slot.reg());
|
||||
Spill(i, slot.reg(), slot.type());
|
||||
slot.MakeStack();
|
||||
}
|
||||
cache_state_.reset_used_registers();
|
||||
@ -395,7 +406,7 @@ void LiftoffAssembler::PrepareCall(wasm::FunctionSig* sig,
|
||||
idx < end; ++idx) {
|
||||
VarState& slot = cache_state_.stack_state[idx];
|
||||
if (!slot.is_reg()) continue;
|
||||
Spill(idx, slot.reg());
|
||||
Spill(idx, slot.reg(), slot.type());
|
||||
slot.MakeStack();
|
||||
}
|
||||
|
||||
@ -439,7 +450,8 @@ void LiftoffAssembler::PrepareCall(wasm::FunctionSig* sig,
|
||||
LiftoffRegList free_regs = kGpCacheRegList.MaskOut(param_regs);
|
||||
if (!free_regs.is_empty()) {
|
||||
LiftoffRegister new_target = free_regs.GetFirstRegSet();
|
||||
stack_transfers.MoveRegister(new_target, LiftoffRegister(*target));
|
||||
stack_transfers.MoveRegister(new_target, LiftoffRegister(*target),
|
||||
kWasmIntPtr);
|
||||
*target = new_target.gp();
|
||||
} else {
|
||||
PushCallerFrameSlot(LiftoffRegister(*target));
|
||||
@ -488,7 +500,7 @@ void LiftoffAssembler::SpillRegister(LiftoffRegister reg) {
|
||||
DCHECK_GT(cache_state_.stack_height(), idx);
|
||||
auto* slot = &cache_state_.stack_state[idx];
|
||||
if (!slot->is_reg() || slot->reg() != reg) continue;
|
||||
Spill(idx, reg);
|
||||
Spill(idx, reg, slot->type());
|
||||
slot->MakeStack();
|
||||
if (--remaining_uses == 0) break;
|
||||
}
|
||||
|
@ -294,15 +294,15 @@ class LiftoffAssembler : public TurboAssembler {
|
||||
LiftoffRegister src, StoreType type, LiftoffRegList pinned,
|
||||
uint32_t* protected_store_pc = nullptr);
|
||||
inline void LoadCallerFrameSlot(LiftoffRegister, uint32_t caller_slot_idx);
|
||||
inline void MoveStackValue(uint32_t dst_index, uint32_t src_index);
|
||||
inline void MoveStackValue(uint32_t dst_index, uint32_t src_index, ValueType);
|
||||
|
||||
inline void MoveToReturnRegister(LiftoffRegister);
|
||||
// TODO(clemensh): Pass the type to {Move}, to emit more efficient code.
|
||||
inline void Move(LiftoffRegister dst, LiftoffRegister src);
|
||||
|
||||
inline void Spill(uint32_t index, LiftoffRegister);
|
||||
inline void Spill(uint32_t index, LiftoffRegister, ValueType);
|
||||
inline void Spill(uint32_t index, WasmValue);
|
||||
inline void Fill(LiftoffRegister, uint32_t index);
|
||||
inline void Fill(LiftoffRegister, uint32_t index, ValueType);
|
||||
|
||||
// i32 binops.
|
||||
inline void emit_i32_add(Register dst, Register lhs, Register rhs);
|
||||
|
@ -141,6 +141,17 @@ class LiftoffCompiler {
|
||||
BindUnboundLabels(decoder);
|
||||
}
|
||||
|
||||
bool CheckSupportedType(Decoder* decoder, ValueType type,
|
||||
const char* context) {
|
||||
char buffer[128];
|
||||
// Check supported types.
|
||||
if (type == kWasmI32 || type == kWasmF32) return true;
|
||||
SNPrintF(ArrayVector(buffer), "%s %s", WasmOpcodes::TypeName(type),
|
||||
context);
|
||||
unsupported(decoder, buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetSafepointTableOffset() const {
|
||||
return safepoint_table_builder_.GetCodeOffset();
|
||||
}
|
||||
@ -235,21 +246,7 @@ class LiftoffCompiler {
|
||||
uint32_t num_params =
|
||||
static_cast<uint32_t>(call_desc_->ParameterCount()) - 1;
|
||||
for (uint32_t i = 0; i < __ num_locals(); ++i) {
|
||||
switch (__ local_type(i)) {
|
||||
case kWasmI32:
|
||||
case kWasmF32:
|
||||
// supported.
|
||||
break;
|
||||
case kWasmI64:
|
||||
unsupported(decoder, "i64 param/local");
|
||||
return;
|
||||
case kWasmF64:
|
||||
unsupported(decoder, "f64 param/local");
|
||||
return;
|
||||
default:
|
||||
unsupported(decoder, "exotic param/local");
|
||||
return;
|
||||
}
|
||||
if (!CheckSupportedType(decoder, __ local_type(i), "param")) return;
|
||||
}
|
||||
// Input 0 is the call target, the context is at 1.
|
||||
constexpr int kContextParameterIndex = 1;
|
||||
@ -638,7 +635,7 @@ class LiftoffCompiler {
|
||||
case kStack: {
|
||||
auto rc = reg_class_for(operand.type);
|
||||
LiftoffRegister reg = __ GetUnusedRegister(rc);
|
||||
__ Fill(reg, operand.index);
|
||||
__ Fill(reg, operand.index, operand.type);
|
||||
__ PushRegister(slot.type(), reg);
|
||||
break;
|
||||
}
|
||||
@ -649,19 +646,19 @@ class LiftoffCompiler {
|
||||
void SetLocalFromStackSlot(LiftoffAssembler::VarState& dst_slot,
|
||||
uint32_t local_index) {
|
||||
auto& state = *__ cache_state();
|
||||
ValueType type = dst_slot.type();
|
||||
if (dst_slot.is_reg()) {
|
||||
LiftoffRegister slot_reg = dst_slot.reg();
|
||||
if (state.get_use_count(slot_reg) == 1) {
|
||||
__ Fill(dst_slot.reg(), state.stack_height() - 1);
|
||||
__ Fill(dst_slot.reg(), state.stack_height() - 1, type);
|
||||
return;
|
||||
}
|
||||
state.dec_used(slot_reg);
|
||||
}
|
||||
ValueType type = dst_slot.type();
|
||||
DCHECK_EQ(type, __ local_type(local_index));
|
||||
RegClass rc = reg_class_for(type);
|
||||
LiftoffRegister dst_reg = __ GetUnusedRegister(rc);
|
||||
__ Fill(dst_reg, __ cache_state()->stack_height() - 1);
|
||||
__ Fill(dst_reg, __ cache_state()->stack_height() - 1, type);
|
||||
dst_slot = LiftoffAssembler::VarState(type, dst_reg);
|
||||
__ cache_state()->inc_used(dst_reg);
|
||||
}
|
||||
@ -889,8 +886,7 @@ class LiftoffCompiler {
|
||||
const MemoryAccessOperand<validate>& operand,
|
||||
const Value& index_val, Value* result) {
|
||||
ValueType value_type = type.value_type();
|
||||
if (value_type != kWasmI32 && value_type != kWasmF32)
|
||||
return unsupported(decoder, "unsupported load type");
|
||||
if (!CheckSupportedType(decoder, value_type, "load")) return;
|
||||
LiftoffRegList pinned;
|
||||
Register index = pinned.set(__ PopToRegister(kGpReg)).gp();
|
||||
if (!env_->use_trap_handler) {
|
||||
@ -923,8 +919,7 @@ class LiftoffCompiler {
|
||||
const MemoryAccessOperand<validate>& operand,
|
||||
const Value& index_val, const Value& value_val) {
|
||||
ValueType value_type = type.value_type();
|
||||
if (value_type != kWasmI32 && value_type != kWasmF32)
|
||||
return unsupported(decoder, "unsupported store type");
|
||||
if (!CheckSupportedType(decoder, value_type, "store")) return;
|
||||
RegClass rc = reg_class_for(value_type);
|
||||
LiftoffRegList pinned;
|
||||
LiftoffRegister value = pinned.set(__ PopToRegister(rc));
|
||||
@ -962,6 +957,9 @@ class LiftoffCompiler {
|
||||
const Value args[], Value returns[]) {
|
||||
if (operand.sig->return_count() > 1)
|
||||
return unsupported(decoder, "multi-return");
|
||||
if (operand.sig->return_count() == 1 &&
|
||||
!CheckSupportedType(decoder, operand.sig->GetReturn(0), "return"))
|
||||
return;
|
||||
|
||||
compiler::CallDescriptor* call_desc =
|
||||
compiler::GetWasmCallDescriptor(compilation_zone_, operand.sig);
|
||||
|
@ -46,7 +46,8 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index) {
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -58,7 +59,8 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg) {
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -66,7 +68,8 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index) {
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,8 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index) {
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -58,7 +59,8 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg) {
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -66,7 +68,8 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index) {
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,8 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index) {
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -58,7 +59,8 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg) {
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -66,7 +68,8 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index) {
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,8 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index) {
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -58,7 +59,8 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg) {
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
@ -66,7 +68,8 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index) {
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
|
||||
ValueType type) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
@ -178,12 +178,13 @@ void LiftoffAssembler::LoadCallerFrameSlot(LiftoffRegister dst,
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index) {
|
||||
void LiftoffAssembler::MoveStackValue(uint32_t dst_index, uint32_t src_index,
|
||||
ValueType type) {
|
||||
DCHECK_NE(dst_index, src_index);
|
||||
if (cache_state_.has_unused_register(kGpReg)) {
|
||||
LiftoffRegister reg = GetUnusedRegister(kGpReg);
|
||||
Fill(reg, src_index);
|
||||
Spill(dst_index, reg);
|
||||
Fill(reg, src_index, type);
|
||||
Spill(dst_index, reg, type);
|
||||
} else {
|
||||
pushq(liftoff::GetStackSlot(src_index));
|
||||
popq(liftoff::GetStackSlot(dst_index));
|
||||
@ -212,13 +213,24 @@ void LiftoffAssembler::Move(LiftoffRegister dst, LiftoffRegister src) {
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg) {
|
||||
void LiftoffAssembler::Spill(uint32_t index, LiftoffRegister reg,
|
||||
ValueType type) {
|
||||
Operand dst = liftoff::GetStackSlot(index);
|
||||
// TODO(clemensh): Handle different sizes here.
|
||||
if (reg.is_gp()) {
|
||||
movq(dst, reg.gp());
|
||||
} else {
|
||||
Movsd(dst, reg.fp());
|
||||
switch (type) {
|
||||
case kWasmI32:
|
||||
movl(dst, reg.gp());
|
||||
break;
|
||||
case kWasmI64:
|
||||
movq(dst, reg.gp());
|
||||
break;
|
||||
case kWasmF32:
|
||||
Movss(dst, reg.fp());
|
||||
break;
|
||||
case kWasmF64:
|
||||
Movsd(dst, reg.fp());
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,13 +248,24 @@ void LiftoffAssembler::Spill(uint32_t index, WasmValue value) {
|
||||
}
|
||||
}
|
||||
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index) {
|
||||
void LiftoffAssembler::Fill(LiftoffRegister reg, uint32_t index,
|
||||
ValueType type) {
|
||||
Operand src = liftoff::GetStackSlot(index);
|
||||
// TODO(clemensh): Handle different sizes here.
|
||||
if (reg.is_gp()) {
|
||||
movq(reg.gp(), src);
|
||||
} else {
|
||||
Movsd(reg.fp(), src);
|
||||
switch (type) {
|
||||
case kWasmI32:
|
||||
movl(reg.gp(), src);
|
||||
break;
|
||||
case kWasmI64:
|
||||
movq(reg.gp(), src);
|
||||
break;
|
||||
case kWasmF32:
|
||||
Movss(reg.fp(), src);
|
||||
break;
|
||||
case kWasmF64:
|
||||
Movsd(reg.fp(), src);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
29
test/mjsunit/regress/wasm/regress-7353.js
Normal file
29
test/mjsunit/regress/wasm/regress-7353.js
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --wasm-lazy-compilation
|
||||
|
||||
load('test/mjsunit/wasm/wasm-constants.js');
|
||||
load('test/mjsunit/wasm/wasm-module-builder.js');
|
||||
|
||||
const builder = new WasmModuleBuilder();
|
||||
builder.addMemory(16, 32);
|
||||
builder.addFunction('grow', kSig_i_i).addBody([
|
||||
kExprGetLocal, 0,
|
||||
kExprGrowMemory, 0,
|
||||
]).exportFunc();
|
||||
builder.addFunction('main', kSig_i_i).addBody([
|
||||
...wasmI32Const(0x41),
|
||||
kExprSetLocal, 0,
|
||||
// Enter loop, such that values are spilled to the stack.
|
||||
kExprLoop, kWasmStmt,
|
||||
kExprEnd,
|
||||
// Reload value. This must be loaded as 32 bit value.
|
||||
kExprGetLocal, 0,
|
||||
kExprI32LoadMem, 0, 0,
|
||||
]).exportFunc();
|
||||
const instance = builder.instantiate();
|
||||
// Execute grow, such that the stack contains garbage data afterwards.
|
||||
instance.exports.grow(1);
|
||||
instance.exports.main();
|
Loading…
Reference in New Issue
Block a user