Commit 2c8ca0c8 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[Liftoff] Add tracing of cache state

This helps to debug issues with maintaining the cache state, and also
understanding errors in the generated code.

Unfortunately, it requires buffering the trace output in the decoder,
since the interface is called in between, and the output would be
messed up otherwise.

R=titzer@chromium.org

Bug: v8:6600
Change-Id: Ie8af8f7f619f3909ea52268241b883a4d4de79fa
Reviewed-on: https://chromium-review.googlesource.com/813972
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49989}
parent 95ca3e8b
...@@ -235,6 +235,8 @@ class LiftoffCompiler { ...@@ -235,6 +235,8 @@ class LiftoffCompiler {
// Note: This is called for blocks and loops. // Note: This is called for blocks and loops.
DCHECK_EQ(new_block, decoder->control_at(0)); DCHECK_EQ(new_block, decoder->control_at(0));
TraceCacheState(decoder);
new_block->label_state.stack_base = __ cache_state()->stack_height(); new_block->label_state.stack_base = __ cache_state()->stack_height();
if (new_block->is_loop()) { if (new_block->is_loop()) {
...@@ -261,6 +263,7 @@ class LiftoffCompiler { ...@@ -261,6 +263,7 @@ class LiftoffCompiler {
} }
void FallThruTo(Decoder* decoder, Control* c) { void FallThruTo(Decoder* decoder, Control* c) {
TraceCacheState(decoder);
if (c->end_merge.reached) { if (c->end_merge.reached) {
__ MergeFullStackWith(c->label_state); __ MergeFullStackWith(c->label_state);
} else { } else {
...@@ -311,6 +314,7 @@ class LiftoffCompiler { ...@@ -311,6 +314,7 @@ class LiftoffCompiler {
void BinOp(Decoder* decoder, WasmOpcode opcode, FunctionSig*, void BinOp(Decoder* decoder, WasmOpcode opcode, FunctionSig*,
const Value& lhs, const Value& rhs, Value* result) { const Value& lhs, const Value& rhs, Value* result) {
TraceCacheState(decoder);
#define CASE_BINOP(opcode, type, fn) \ #define CASE_BINOP(opcode, type, fn) \
case WasmOpcode::kExpr##opcode: \ case WasmOpcode::kExpr##opcode: \
return type##BinOp(&LiftoffAssembler::emit_##fn); return type##BinOp(&LiftoffAssembler::emit_##fn);
...@@ -331,6 +335,7 @@ class LiftoffCompiler { ...@@ -331,6 +335,7 @@ class LiftoffCompiler {
} }
void I32Const(Decoder* decoder, Value* result, int32_t value) { void I32Const(Decoder* decoder, Value* result, int32_t value) {
TraceCacheState(decoder);
__ cache_state()->stack_state.emplace_back(kWasmI32, value); __ cache_state()->stack_state.emplace_back(kWasmI32, value);
CheckStackSizeLimit(decoder); CheckStackSizeLimit(decoder);
} }
...@@ -351,6 +356,7 @@ class LiftoffCompiler { ...@@ -351,6 +356,7 @@ class LiftoffCompiler {
} }
void Drop(Decoder* decoder, const Value& value) { void Drop(Decoder* decoder, const Value& value) {
TraceCacheState(decoder);
__ DropStackSlot(&__ cache_state()->stack_state.back()); __ DropStackSlot(&__ cache_state()->stack_state.back());
__ cache_state()->stack_state.pop_back(); __ cache_state()->stack_state.pop_back();
} }
...@@ -486,7 +492,7 @@ class LiftoffCompiler { ...@@ -486,7 +492,7 @@ class LiftoffCompiler {
unsupported(decoder, "select"); unsupported(decoder, "select");
} }
void Br(Decoder* decoder, Control* target) { void Br(Control* target) {
if (!target->br_merge()->reached) { if (!target->br_merge()->reached) {
target->label_state.InitMerge(*__ cache_state(), __ num_locals(), target->label_state.InitMerge(*__ cache_state(), __ num_locals(),
target->br_merge()->arity); target->br_merge()->arity);
...@@ -495,12 +501,18 @@ class LiftoffCompiler { ...@@ -495,12 +501,18 @@ class LiftoffCompiler {
__ jmp(target->label.get()); __ jmp(target->label.get());
} }
void Br(Decoder* decoder, Control* target) {
TraceCacheState(decoder);
Br(target);
}
void BrIf(Decoder* decoder, const Value& cond, Control* target) { void BrIf(Decoder* decoder, const Value& cond, Control* target) {
TraceCacheState(decoder);
Label cont_false; Label cont_false;
Register value = __ PopToRegister(kGpReg).gp(); Register value = __ PopToRegister(kGpReg).gp();
__ JumpIfZero(value, &cont_false); __ JumpIfZero(value, &cont_false);
Br(decoder, target); Br(target);
__ bind(&cont_false); __ bind(&cont_false);
} }
...@@ -581,6 +593,41 @@ class LiftoffCompiler { ...@@ -581,6 +593,41 @@ class LiftoffCompiler {
// LiftoffCompiler after compilation. // LiftoffCompiler after compilation.
Zone compilation_zone_; Zone compilation_zone_;
SafepointTableBuilder safepoint_table_builder_; SafepointTableBuilder safepoint_table_builder_;
void TraceCacheState(Decoder* decoder) const {
#ifdef DEBUG
if (!FLAG_trace_liftoff) return;
for (int control_depth = decoder->control_depth() - 1; control_depth >= -1;
--control_depth) {
LiftoffAssembler::CacheState* cache_state =
control_depth == -1
? asm_->cache_state()
: &decoder->control_at(control_depth)->label_state;
int idx = 0;
for (LiftoffAssembler::VarState& slot : cache_state->stack_state) {
if (idx++) PrintF("-");
PrintF("%s:", WasmOpcodes::TypeName(slot.type()));
switch (slot.loc()) {
case kStack:
PrintF("s");
break;
case kRegister:
if (slot.reg().is_gp()) {
PrintF("gp%d", slot.reg().gp().code());
} else {
PrintF("fp%d", slot.reg().fp().code());
}
break;
case kConstant:
PrintF("c");
break;
}
}
if (control_depth != -1) PrintF("; ");
}
PrintF("\n");
#endif
}
}; };
} // namespace } // namespace
......
...@@ -1281,6 +1281,32 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1281,6 +1281,32 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return true; return true;
} }
class TraceLine {
public:
static constexpr int kMaxLen = 512;
~TraceLine() {
if (!FLAG_trace_wasm_decoder) return;
PrintF("%.*s\n", len_, buffer_);
}
// Appends a formatted string.
PRINTF_FORMAT(2, 3)
void Append(const char* format, ...) {
if (!FLAG_trace_wasm_decoder) return;
va_list va_args;
va_start(va_args, format);
size_t remaining_len = kMaxLen - len_;
Vector<char> remaining_msg_space(buffer_ + len_, remaining_len);
int len = VSNPrintF(remaining_msg_space, format, va_args);
va_end(va_args);
len_ += len < 0 ? remaining_len : len;
}
private:
char buffer_[kMaxLen];
int len_ = 0;
};
// Decodes the body of a function. // Decodes the body of a function.
void DecodeFunctionBody() { void DecodeFunctionBody() {
TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n", TRACE("wasm-decode %p...%p (module+%u, %d bytes)\n",
...@@ -1303,10 +1329,14 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1303,10 +1329,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
unsigned len = 1; unsigned len = 1;
WasmOpcode opcode = static_cast<WasmOpcode>(*this->pc_); WasmOpcode opcode = static_cast<WasmOpcode>(*this->pc_);
#if DEBUG #if DEBUG
if (FLAG_trace_wasm_decoder && !WasmOpcodes::IsPrefixOpcode(opcode)) { TraceLine trace_msg;
TRACE(" @%-8d #%-20s|", startrel(this->pc_), #define TRACE_PART(...) trace_msg.Append(__VA_ARGS__)
WasmOpcodes::OpcodeName(opcode)); if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
TRACE_PART(" @%-8d #%-20s|", startrel(this->pc_),
WasmOpcodes::OpcodeName(opcode));
} }
#else
#define TRACE_PART(...)
#endif #endif
FunctionSig* sig = WasmOpcodes::Signature(opcode); FunctionSig* sig = WasmOpcodes::Signature(opcode);
...@@ -1475,10 +1505,9 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1475,10 +1505,9 @@ class WasmFullDecoder : public WasmDecoder<validate> {
} }
last_end_found_ = true; last_end_found_ = true;
// The result of the block is the return value. // The result of the block is the return value.
TRACE(" @%-8d #xx:%-20s|", startrel(this->pc_), TRACE_PART("\n @%-8d #%-20s|", startrel(this->pc_),
"(implicit) return"); "(implicit) return");
DoReturn(c, true); DoReturn(c, true);
TRACE("\n");
} }
PopControl(c); PopControl(c);
...@@ -1756,8 +1785,8 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1756,8 +1785,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
byte simd_index = byte simd_index =
this->template read_u8<validate>(this->pc_ + 1, "simd index"); this->template read_u8<validate>(this->pc_ + 1, "simd index");
opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index); opcode = static_cast<WasmOpcode>(opcode << 8 | simd_index);
TRACE(" @%-4d #%-20s|", startrel(this->pc_), TRACE_PART(" @%-4d #%-20s|", startrel(this->pc_),
WasmOpcodes::OpcodeName(opcode)); WasmOpcodes::OpcodeName(opcode));
len += DecodeSimdOpcode(opcode); len += DecodeSimdOpcode(opcode);
break; break;
} }
...@@ -1768,8 +1797,8 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1768,8 +1797,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
byte atomic_index = byte atomic_index =
this->template read_u8<validate>(this->pc_ + 1, "atomic index"); this->template read_u8<validate>(this->pc_ + 1, "atomic index");
opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_index); opcode = static_cast<WasmOpcode>(opcode << 8 | atomic_index);
TRACE(" @%-4d #%-20s|", startrel(this->pc_), TRACE_PART(" @%-4d #%-20s|", startrel(this->pc_),
WasmOpcodes::OpcodeName(opcode)); WasmOpcodes::OpcodeName(opcode));
len += DecodeAtomicOpcode(opcode); len += DecodeAtomicOpcode(opcode);
break; break;
} }
...@@ -1790,62 +1819,61 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1790,62 +1819,61 @@ class WasmFullDecoder : public WasmDecoder<validate> {
#if DEBUG #if DEBUG
if (FLAG_trace_wasm_decoder) { if (FLAG_trace_wasm_decoder) {
PrintF(" "); TRACE_PART(" ");
for (Control& c : control_) { for (Control& c : control_) {
switch (c.kind) { switch (c.kind) {
case kControlIf: case kControlIf:
PrintF("I"); TRACE_PART("I");
break; break;
case kControlBlock: case kControlBlock:
PrintF("B"); TRACE_PART("B");
break; break;
case kControlLoop: case kControlLoop:
PrintF("L"); TRACE_PART("L");
break; break;
case kControlTry: case kControlTry:
PrintF("T"); TRACE_PART("T");
break; break;
default: default:
break; break;
} }
if (c.start_merge.arity) PrintF("%u-", c.start_merge.arity); if (c.start_merge.arity) TRACE_PART("%u-", c.start_merge.arity);
PrintF("%u", c.end_merge.arity); TRACE_PART("%u", c.end_merge.arity);
if (!c.reachable()) PrintF("%c", c.unreachable() ? '*' : '#'); if (!c.reachable()) TRACE_PART("%c", c.unreachable() ? '*' : '#');
} }
PrintF(" | "); TRACE_PART(" | ");
for (size_t i = 0; i < stack_.size(); ++i) { for (size_t i = 0; i < stack_.size(); ++i) {
auto& val = stack_[i]; auto& val = stack_[i];
WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc); WasmOpcode opcode = static_cast<WasmOpcode>(*val.pc);
if (WasmOpcodes::IsPrefixOpcode(opcode)) { if (WasmOpcodes::IsPrefixOpcode(opcode)) {
opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1)); opcode = static_cast<WasmOpcode>(opcode << 8 | *(val.pc + 1));
} }
PrintF(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type), TRACE_PART(" %c@%d:%s", WasmOpcodes::ShortNameOf(val.type),
static_cast<int>(val.pc - this->start_), static_cast<int>(val.pc - this->start_),
WasmOpcodes::OpcodeName(opcode)); WasmOpcodes::OpcodeName(opcode));
switch (opcode) { switch (opcode) {
case kExprI32Const: { case kExprI32Const: {
ImmI32Operand<validate> operand(this, val.pc); ImmI32Operand<validate> operand(this, val.pc);
PrintF("[%d]", operand.value); TRACE_PART("[%d]", operand.value);
break; break;
} }
case kExprGetLocal: case kExprGetLocal:
case kExprSetLocal: case kExprSetLocal:
case kExprTeeLocal: { case kExprTeeLocal: {
LocalIndexOperand<Decoder::kValidate> operand(this, val.pc); LocalIndexOperand<Decoder::kValidate> operand(this, val.pc);
PrintF("[%u]", operand.index); TRACE_PART("[%u]", operand.index);
break; break;
} }
case kExprGetGlobal: case kExprGetGlobal:
case kExprSetGlobal: { case kExprSetGlobal: {
GlobalIndexOperand<validate> operand(this, val.pc); GlobalIndexOperand<validate> operand(this, val.pc);
PrintF("[%u]", operand.index); TRACE_PART("[%u]", operand.index);
break; break;
} }
default: default:
break; break;
} }
} }
PrintF("\n");
} }
#endif #endif
this->pc_ += len; this->pc_ += len;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment