[wasm] Refactor decoder tracing

Move more logic into the {TraceLine} class. In release builds, this
class will not do anything. Since there is no code after the switch in
{DecodeOp} any more after this CL, we can apply tail-call optimization
(via explicit returns in C++), which will save an additional call in
some cases.

R=thibaudm@chromium.org

Bug: v8:10576
Change-Id: Ie11ec550ab33d0c03a27375f34576e3a75dcf6ad
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2254021
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68515}
This commit is contained in:
Clemens Backes 2020-06-24 09:54:50 +02:00 committed by Commit Bot
parent 5ce53d3666
commit 98a9c44be9

View File

@ -1989,11 +1989,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
return true;
}
#ifdef DEBUG
class TraceLine {
public:
static constexpr int kMaxLen = 512;
explicit TraceLine(WasmFullDecoder* decoder) : decoder_(decoder) {}
~TraceLine() {
if (!FLAG_trace_wasm_decoder) return;
AppendStackState();
PrintF("%.*s\n", len_, buffer_);
}
@ -2011,9 +2014,87 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
private:
void AppendStackState() {
DCHECK(FLAG_trace_wasm_decoder);
Append(" ");
for (Control& c : decoder_->control_) {
switch (c.kind) {
case kControlIf:
Append("I");
break;
case kControlBlock:
Append("B");
break;
case kControlLoop:
Append("L");
break;
case kControlTry:
Append("T");
break;
case kControlIfElse:
case kControlTryCatch:
case kControlLet: // TODO(7748): Implement
break;
}
if (c.start_merge.arity) Append("%u-", c.start_merge.arity);
Append("%u", c.end_merge.arity);
if (!c.reachable()) Append("%c", c.unreachable() ? '*' : '#');
}
Append(" | ");
for (size_t i = 0; i < decoder_->stack_.size(); ++i) {
Value& val = decoder_->stack_[i];
WasmOpcode val_opcode = static_cast<WasmOpcode>(*val.pc);
if (WasmOpcodes::IsPrefixOpcode(val_opcode)) {
val_opcode =
decoder_->template read_prefixed_opcode<Decoder::kNoValidate>(
val.pc);
}
Append(" %c@%d:%s", val.type.short_name(),
static_cast<int>(val.pc - decoder_->start_),
WasmOpcodes::OpcodeName(val_opcode));
// If the decoder failed, don't try to decode the immediates, as this
// can trigger a DCHECK failure.
if (decoder_->failed()) continue;
switch (val_opcode) {
case kExprI32Const: {
ImmI32Immediate<Decoder::kNoValidate> imm(decoder_, val.pc);
Append("[%d]", imm.value);
break;
}
case kExprLocalGet:
case kExprLocalSet:
case kExprLocalTee: {
LocalIndexImmediate<Decoder::kNoValidate> imm(decoder_, val.pc);
Append("[%u]", imm.index);
break;
}
case kExprGlobalGet:
case kExprGlobalSet: {
GlobalIndexImmediate<Decoder::kNoValidate> imm(decoder_, val.pc);
Append("[%u]", imm.index);
break;
}
default:
break;
}
}
}
static constexpr int kMaxLen = 512;
char buffer_[kMaxLen];
int len_ = 0;
WasmFullDecoder* const decoder_;
};
#else
class TraceLine {
public:
explicit TraceLine(WasmFullDecoder*) {}
PRINTF_FORMAT(2, 3)
void Append(const char* format, ...) {}
};
#endif
// Helper to avoid calling member methods (which are more expensive to call
// indirectly).
@ -2024,16 +2105,11 @@ class WasmFullDecoder : public WasmDecoder<validate> {
template <WasmOpcode opcode>
int DecodeOp() {
#if DEBUG
TraceLine trace_msg;
#define TRACE_PART(...) trace_msg.Append(__VA_ARGS__)
TraceLine trace_msg(this);
if (!WasmOpcodes::IsPrefixOpcode(opcode)) {
TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(opcode));
trace_msg.Append(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(opcode));
}
#else
#define TRACE_PART(...)
#endif
int len = 1;
@ -2283,8 +2359,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
break;
}
// The result of the block is the return value.
TRACE_PART("\n" TRACE_INST_FORMAT, startrel(this->pc_),
"(implicit) return");
trace_msg.Append("\n" TRACE_INST_FORMAT, startrel(this->pc_),
"(implicit) return");
DoReturn();
control_.clear();
break;
@ -2744,8 +2820,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
} else if (full_opcode >= kExprMemoryInit) {
CHECK_PROTOTYPE_OPCODE(bulk_memory);
}
TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(full_opcode));
trace_msg.Append(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(full_opcode));
len += DecodeNumericOpcode(full_opcode);
break;
}
@ -2757,8 +2833,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
if (!VALIDATE(this->ok())) break;
len += length;
TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(full_opcode));
trace_msg.Append(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(full_opcode));
len += DecodeSimdOpcode(full_opcode, length);
break;
}
@ -2769,8 +2845,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
this->template read_u8<validate>(this->pc_ + 1, "atomic index");
WasmOpcode full_opcode =
static_cast<WasmOpcode>(opcode << 8 | atomic_index);
TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(full_opcode));
trace_msg.Append(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(full_opcode));
len += DecodeAtomicOpcode(full_opcode);
break;
}
@ -2780,8 +2856,8 @@ class WasmFullDecoder : public WasmDecoder<validate> {
this->template read_u8<validate>(this->pc_ + 1, "gc index");
WasmOpcode full_opcode =
static_cast<WasmOpcode>(opcode << 8 | gc_index);
TRACE_PART(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(full_opcode));
trace_msg.Append(TRACE_INST_FORMAT, startrel(this->pc_),
WasmOpcodes::OpcodeName(full_opcode));
len = DecodeGCOpcode(full_opcode);
break;
}
@ -2804,71 +2880,6 @@ class WasmFullDecoder : public WasmDecoder<validate> {
}
}
#if DEBUG
if (FLAG_trace_wasm_decoder) {
TRACE_PART(" ");
for (Control& c : control_) {
switch (c.kind) {
case kControlIf:
TRACE_PART("I");
break;
case kControlBlock:
TRACE_PART("B");
break;
case kControlLoop:
TRACE_PART("L");
break;
case kControlTry:
TRACE_PART("T");
break;
case kControlIfElse:
case kControlTryCatch:
case kControlLet: // TODO(7748): Implement
break;
}
if (c.start_merge.arity) TRACE_PART("%u-", c.start_merge.arity);
TRACE_PART("%u", c.end_merge.arity);
if (!c.reachable()) TRACE_PART("%c", c.unreachable() ? '*' : '#');
}
TRACE_PART(" | ");
for (size_t i = 0; i < stack_.size(); ++i) {
Value& val = stack_[i];
WasmOpcode val_opcode = static_cast<WasmOpcode>(*val.pc);
if (WasmOpcodes::IsPrefixOpcode(val_opcode)) {
val_opcode =
this->template read_prefixed_opcode<Decoder::kNoValidate>(val.pc);
}
TRACE_PART(" %c@%d:%s", val.type.short_name(),
static_cast<int>(val.pc - this->start_),
WasmOpcodes::OpcodeName(val_opcode));
// If the decoder failed, don't try to decode the immediates, as this
// can trigger a DCHECK failure.
if (this->failed()) continue;
switch (val_opcode) {
case kExprI32Const: {
ImmI32Immediate<Decoder::kNoValidate> imm(this, val.pc);
TRACE_PART("[%d]", imm.value);
break;
}
case kExprLocalGet:
case kExprLocalSet:
case kExprLocalTee: {
LocalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
TRACE_PART("[%u]", imm.index);
break;
}
case kExprGlobalGet:
case kExprGlobalSet: {
GlobalIndexImmediate<Decoder::kNoValidate> imm(this, val.pc);
TRACE_PART("[%u]", imm.index);
break;
}
default:
break;
}
}
}
#endif
return len;
}