[wasm-gc] Module decoder: Remove template to save binary size

Bug: v8:7748
Change-Id: Ic2eb981b28b6f5af926c7f8889da8bb9a71188ca
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4171636
Reviewed-by: Manos Koukoutos <manoskouk@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85335}
This commit is contained in:
Matthias Liedtke 2023-01-17 11:44:18 +01:00 committed by V8 LUCI CQ
parent b26a55b88f
commit 04f19e973e
6 changed files with 364 additions and 307 deletions

View File

@ -38,6 +38,48 @@ namespace wasm {
// A {DecodeResult} only stores the failure / success status, but no data. // A {DecodeResult} only stores the failure / success status, but no data.
using DecodeResult = VoidResult; using DecodeResult = VoidResult;
struct WasmFunction;
class ITracer {
public:
static constexpr ITracer* NoTrace = nullptr;
// Hooks for extracting byte offsets of things.
virtual void TypeOffset(uint32_t offset) = 0;
virtual void ImportOffset(uint32_t offset) = 0;
virtual void ImportsDone() = 0;
virtual void TableOffset(uint32_t offset) = 0;
virtual void MemoryOffset(uint32_t offset) = 0;
virtual void TagOffset(uint32_t offset) = 0;
virtual void GlobalOffset(uint32_t offset) = 0;
virtual void StartOffset(uint32_t offset) = 0;
virtual void ElementOffset(uint32_t offset) = 0;
virtual void DataOffset(uint32_t offset) = 0;
// Hooks for annotated hex dumps.
virtual void Bytes(const byte* start, uint32_t count) = 0;
virtual void Description(const char* desc) = 0;
virtual void Description(const char* desc, size_t length) = 0;
virtual void Description(uint32_t number) = 0;
virtual void Description(ValueType type) = 0;
virtual void Description(HeapType type) = 0;
virtual void Description(const FunctionSig* sig) = 0;
virtual void NextLine() = 0;
virtual void NextLineIfFull() = 0;
virtual void NextLineIfNonEmpty() = 0;
virtual void InitializerExpression(const byte* start, const byte* end,
ValueType expected_type) = 0;
virtual void FunctionBody(const WasmFunction* func, const byte* start) = 0;
virtual void FunctionName(uint32_t func_index) = 0;
virtual void NameSection(const byte* start, const byte* end,
uint32_t offset) = 0;
virtual ~ITracer() = default;
};
// A helper utility to decode bytes, integers, fields, varints, etc, from // A helper utility to decode bytes, integers, fields, varints, etc, from
// a buffer of bytes. // a buffer of bytes.
class Decoder { class Decoder {
@ -189,10 +231,11 @@ class Decoder {
uint8_t consume_u8(const char* name = "uint8_t") { uint8_t consume_u8(const char* name = "uint8_t") {
return consume_little_endian<uint8_t, kTrace>(name); return consume_little_endian<uint8_t, kTrace>(name);
} }
template <class Tracer> uint8_t consume_u8(const char* name, ITracer* tracer) {
uint8_t consume_u8(const char* name, Tracer& tracer) { if (tracer) {
tracer.Bytes(pc_, sizeof(uint8_t)); tracer->Bytes(pc_, sizeof(uint8_t));
tracer.Description(name); tracer->Description(name);
}
return consume_little_endian<uint8_t, kNoTrace>(name); return consume_little_endian<uint8_t, kNoTrace>(name);
} }
@ -202,10 +245,11 @@ class Decoder {
} }
// Reads a single 32-bit unsigned integer (little endian) and advances {pc_}. // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
template <class Tracer> uint32_t consume_u32(const char* name, ITracer* tracer) {
uint32_t consume_u32(const char* name, Tracer& tracer) { if (tracer) {
tracer.Bytes(pc_, sizeof(uint32_t)); tracer->Bytes(pc_, sizeof(uint32_t));
tracer.Description(name); tracer->Description(name);
}
return consume_little_endian<uint32_t, kNoTrace>(name); return consume_little_endian<uint32_t, kNoTrace>(name);
} }
@ -217,13 +261,14 @@ class Decoder {
pc_ += length; pc_ += length;
return result; return result;
} }
template <class Tracer> uint32_t consume_u32v(const char* name, ITracer* tracer) {
uint32_t consume_u32v(const char* name, Tracer& tracer) {
uint32_t length = 0; uint32_t length = 0;
uint32_t result = uint32_t result =
read_leb<uint32_t, FullValidationTag, kNoTrace>(pc_, &length, name); read_leb<uint32_t, FullValidationTag, kNoTrace>(pc_, &length, name);
tracer.Bytes(pc_, length); if (tracer) {
tracer.Description(name); tracer->Bytes(pc_, length);
tracer->Description(name);
}
pc_ += length; pc_ += length;
return result; return result;
} }
@ -238,13 +283,14 @@ class Decoder {
} }
// Reads a LEB128 variable-length unsigned 64-bit integer and advances {pc_}. // Reads a LEB128 variable-length unsigned 64-bit integer and advances {pc_}.
template <class Tracer> uint64_t consume_u64v(const char* name, ITracer* tracer) {
uint64_t consume_u64v(const char* name, Tracer& tracer) {
uint32_t length = 0; uint32_t length = 0;
uint64_t result = uint64_t result =
read_leb<uint64_t, FullValidationTag, kNoTrace>(pc_, &length, name); read_leb<uint64_t, FullValidationTag, kNoTrace>(pc_, &length, name);
tracer.Bytes(pc_, length); if (tracer) {
tracer.Description(name); tracer->Bytes(pc_, length);
tracer->Description(name);
}
pc_ += length; pc_ += length;
return result; return result;
} }
@ -268,10 +314,11 @@ class Decoder {
pc_ = end_; pc_ = end_;
} }
} }
template <class Tracer> void consume_bytes(uint32_t size, const char* name, ITracer* tracer) {
void consume_bytes(uint32_t size, const char* name, Tracer& tracer) { if (tracer) {
tracer.Bytes(pc_, size); tracer->Bytes(pc_, size);
tracer.Description(name); tracer->Description(name);
}
consume_bytes(size, nullptr); consume_bytes(size, nullptr);
} }

View File

@ -28,41 +28,6 @@ namespace v8::internal::wasm {
if (v8_flags.trace_wasm_decoder) PrintF(__VA_ARGS__); \ if (v8_flags.trace_wasm_decoder) PrintF(__VA_ARGS__); \
} while (false) } while (false)
class NoTracer {
public:
// Hooks for extracting byte offsets of things.
void TypeOffset(uint32_t offset) {}
void ImportOffset(uint32_t offset) {}
void ImportsDone() {}
void TableOffset(uint32_t offset) {}
void MemoryOffset(uint32_t offset) {}
void TagOffset(uint32_t offset) {}
void GlobalOffset(uint32_t offset) {}
void StartOffset(uint32_t offset) {}
void ElementOffset(uint32_t offset) {}
void DataOffset(uint32_t offset) {}
// Hooks for annotated hex dumps.
void Bytes(const byte* start, uint32_t count) {}
void Description(const char* desc) {}
void Description(const char* desc, size_t length) {}
void Description(uint32_t number) {}
void Description(ValueType type) {}
void Description(HeapType type) {}
void Description(const FunctionSig* sig) {}
void NextLine() {}
void NextLineIfFull() {}
void NextLineIfNonEmpty() {}
void InitializerExpression(const byte* start, const byte* end,
ValueType expected_type) {}
void FunctionBody(const WasmFunction* func, const byte* start) {}
void FunctionName(uint32_t func_index) {}
void NameSection(const byte* start, const byte* end, uint32_t offset) {}
};
constexpr char kNameString[] = "name"; constexpr char kNameString[] = "name";
constexpr char kSourceMappingURLString[] = "sourceMappingURL"; constexpr char kSourceMappingURLString[] = "sourceMappingURL";
constexpr char kInstTraceString[] = "metadata.code.trace_inst"; constexpr char kInstTraceString[] = "metadata.code.trace_inst";
@ -95,23 +60,26 @@ inline bool validate_utf8(Decoder* decoder, WireBytesRef string) {
// Reads a length-prefixed string, checking that it is within bounds. Returns // Reads a length-prefixed string, checking that it is within bounds. Returns
// the offset of the string, and the length as an out parameter. // the offset of the string, and the length as an out parameter.
template <class Tracer>
inline WireBytesRef consume_string(Decoder* decoder, inline WireBytesRef consume_string(Decoder* decoder,
unibrow::Utf8Variant grammar, unibrow::Utf8Variant grammar,
const char* name, Tracer& tracer) { const char* name, ITracer* tracer) {
tracer.Description(name); if (tracer) tracer->Description(name);
uint32_t length = decoder->consume_u32v(" length:", tracer); uint32_t length = decoder->consume_u32v(" length:", tracer);
tracer.Description(length); if (tracer) {
tracer.NextLine(); tracer->Description(length);
tracer->NextLine();
}
uint32_t offset = decoder->pc_offset(); uint32_t offset = decoder->pc_offset();
const byte* string_start = decoder->pc(); const byte* string_start = decoder->pc();
// Consume bytes before validation to guarantee that the string is not oob. // Consume bytes before validation to guarantee that the string is not oob.
if (length > 0) { if (length > 0) {
tracer.Bytes(decoder->pc(), length); if (tracer) {
tracer.Description(name); tracer->Bytes(decoder->pc(), length);
tracer.Description(": "); tracer->Description(name);
tracer.Description(reinterpret_cast<const char*>(decoder->pc()), length); tracer->Description(": ");
tracer.NextLine(); tracer->Description(reinterpret_cast<const char*>(decoder->pc()), length);
tracer->NextLine();
}
decoder->consume_bytes(length, name); decoder->consume_bytes(length, name);
if (decoder->ok()) { if (decoder->ok()) {
switch (grammar) { switch (grammar) {
@ -136,19 +104,16 @@ inline WireBytesRef consume_string(Decoder* decoder,
inline WireBytesRef consume_string(Decoder* decoder, inline WireBytesRef consume_string(Decoder* decoder,
unibrow::Utf8Variant grammar, unibrow::Utf8Variant grammar,
const char* name) { const char* name) {
NoTracer no_tracer; return consume_string(decoder, grammar, name, ITracer::NoTrace);
return consume_string(decoder, grammar, name, no_tracer);
} }
template <class Tracer>
inline WireBytesRef consume_utf8_string(Decoder* decoder, const char* name, inline WireBytesRef consume_utf8_string(Decoder* decoder, const char* name,
Tracer& tracer) { ITracer* tracer) {
return consume_string(decoder, unibrow::Utf8Variant::kUtf8, name, tracer); return consume_string(decoder, unibrow::Utf8Variant::kUtf8, name, tracer);
} }
template <class Tracer>
inline SectionCode IdentifyUnknownSectionInternal(Decoder* decoder, inline SectionCode IdentifyUnknownSectionInternal(Decoder* decoder,
Tracer& tracer) { ITracer* tracer) {
WireBytesRef string = consume_utf8_string(decoder, "section name", tracer); WireBytesRef string = consume_utf8_string(decoder, "section name", tracer);
if (decoder->failed()) { if (decoder->failed()) {
return kUnknownSectionCode; return kUnknownSectionCode;
@ -184,10 +149,9 @@ inline SectionCode IdentifyUnknownSectionInternal(Decoder* decoder,
// An iterator over the sections in a wasm binary module. // An iterator over the sections in a wasm binary module.
// Automatically skips all unknown sections. // Automatically skips all unknown sections.
template <class Tracer>
class WasmSectionIterator { class WasmSectionIterator {
public: public:
explicit WasmSectionIterator(Decoder* decoder, Tracer& tracer) explicit WasmSectionIterator(Decoder* decoder, ITracer* tracer)
: decoder_(decoder), : decoder_(decoder),
tracer_(tracer), tracer_(tracer),
section_code_(kUnknownSectionCode), section_code_(kUnknownSectionCode),
@ -238,7 +202,7 @@ class WasmSectionIterator {
private: private:
Decoder* decoder_; Decoder* decoder_;
Tracer& tracer_; ITracer* tracer_;
SectionCode section_code_; SectionCode section_code_;
const byte* section_start_; const byte* section_start_;
const byte* payload_start_; const byte* payload_start_;
@ -252,15 +216,19 @@ class WasmSectionIterator {
return; return;
} }
section_start_ = decoder_->pc(); section_start_ = decoder_->pc();
tracer_.NextLine(); // Empty line before next section. // Empty line before next section.
if (tracer_) tracer_->NextLine();
uint8_t section_code = decoder_->consume_u8("section kind: ", tracer_); uint8_t section_code = decoder_->consume_u8("section kind: ", tracer_);
tracer_.Description(SectionName(static_cast<SectionCode>(section_code))); if (tracer_) {
tracer_.NextLine(); tracer_->Description(SectionName(static_cast<SectionCode>(section_code)));
tracer_->NextLine();
}
// Read and check the section size. // Read and check the section size.
uint32_t section_length = decoder_->consume_u32v("section length", tracer_); uint32_t section_length = decoder_->consume_u32v("section length", tracer_);
tracer_.Description(section_length); if (tracer_) {
tracer_.NextLine(); tracer_->Description(section_length);
tracer_->NextLine();
}
payload_start_ = decoder_->pc(); payload_start_ = decoder_->pc();
section_end_ = payload_start_ + section_length; section_end_ = payload_start_ + section_length;
if (section_length > decoder_->available_bytes()) { if (section_length > decoder_->available_bytes()) {
@ -301,17 +269,12 @@ class WasmSectionIterator {
} }
}; };
// Add an explicit template deduction guide for {WasmSectionIterator}.
template <class T>
WasmSectionIterator(Decoder*, T&) -> WasmSectionIterator<T>;
// The main logic for decoding the bytes of a module. // The main logic for decoding the bytes of a module.
template <class Tracer> class ModuleDecoderBase : public Decoder {
class ModuleDecoderTemplate : public Decoder {
public: public:
ModuleDecoderTemplate(WasmFeatures enabled_features, ModuleDecoderBase(WasmFeatures enabled_features,
base::Vector<const uint8_t> wire_bytes, base::Vector<const uint8_t> wire_bytes, ModuleOrigin origin,
ModuleOrigin origin, Tracer& tracer) ITracer* tracer)
: Decoder(wire_bytes), : Decoder(wire_bytes),
enabled_features_(enabled_features), enabled_features_(enabled_features),
module_(std::make_shared<WasmModule>(origin)), module_(std::make_shared<WasmModule>(origin)),
@ -355,7 +318,7 @@ class ModuleDecoderTemplate : public Decoder {
const byte* pos = pc_; const byte* pos = pc_;
uint32_t magic_word = consume_u32("wasm magic", tracer_); uint32_t magic_word = consume_u32("wasm magic", tracer_);
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
#define BYTES(x) (x & 0xFF), (x >> 8) & 0xFF, (x >> 16) & 0xFF, (x >> 24) & 0xFF #define BYTES(x) (x & 0xFF), (x >> 8) & 0xFF, (x >> 16) & 0xFF, (x >> 24) & 0xFF
if (magic_word != kWasmMagic) { if (magic_word != kWasmMagic) {
errorf(pos, errorf(pos,
@ -367,7 +330,7 @@ class ModuleDecoderTemplate : public Decoder {
pos = pc_; pos = pc_;
{ {
uint32_t magic_version = consume_u32("wasm version", tracer_); uint32_t magic_version = consume_u32("wasm version", tracer_);
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
if (magic_version != kWasmVersion) { if (magic_version != kWasmVersion) {
errorf(pos, errorf(pos,
"expected version %02x %02x %02x %02x, " "expected version %02x %02x %02x %02x, "
@ -577,7 +540,7 @@ class ModuleDecoderTemplate : public Decoder {
TypeDefinition consume_base_type_definition() { TypeDefinition consume_base_type_definition() {
DCHECK(enabled_features_.has_gc()); DCHECK(enabled_features_.has_gc());
uint8_t kind = consume_u8(" kind: ", tracer_); uint8_t kind = consume_u8(" kind: ", tracer_);
tracer_.Description(TypeKindName(kind)); if (tracer_) tracer_->Description(TypeKindName(kind));
switch (kind) { switch (kind) {
case kWasmFunctionTypeCode: { case kWasmFunctionTypeCode: {
const FunctionSig* sig = consume_sig(&module_->signature_zone); const FunctionSig* sig = consume_sig(&module_->signature_zone);
@ -592,7 +555,7 @@ class ModuleDecoderTemplate : public Decoder {
return {type, kNoSuperType, v8_flags.wasm_final_types}; return {type, kNoSuperType, v8_flags.wasm_final_types};
} }
default: default:
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
errorf(pc() - 1, "unknown type form: %d", kind); errorf(pc() - 1, "unknown type form: %d", kind);
return {}; return {};
} }
@ -619,8 +582,10 @@ class ModuleDecoderTemplate : public Decoder {
supertype, kV8MaxWasmTypes); supertype, kV8MaxWasmTypes);
return {}; return {};
} }
tracer_.Description(supertype); if (tracer_) {
tracer_.NextLine(); tracer_->Description(supertype);
tracer_->NextLine();
}
} }
TypeDefinition type = consume_base_type_definition(); TypeDefinition type = consume_base_type_definition();
type.supertype = supertype; type.supertype = supertype;
@ -644,11 +609,13 @@ class ModuleDecoderTemplate : public Decoder {
static_cast<int>(pc_ - start_)); static_cast<int>(pc_ - start_));
uint8_t opcode = uint8_t opcode =
read_u8<FullValidationTag>(pc(), "signature definition"); read_u8<FullValidationTag>(pc(), "signature definition");
tracer_.Bytes(pc_, 1); if (tracer_) {
tracer_.TypeOffset(pc_offset()); tracer_->Bytes(pc_, 1);
tracer_.Description(" kind: "); tracer_->TypeOffset(pc_offset());
tracer_.Description(TypeKindName(opcode)); tracer_->Description(" kind: ");
tracer_.NextLine(); tracer_->Description(TypeKindName(opcode));
tracer_->NextLine();
}
switch (opcode) { switch (opcode) {
case kWasmFunctionTypeCode: { case kWasmFunctionTypeCode: {
consume_bytes(1, "function"); consume_bytes(1, "function");
@ -681,7 +648,7 @@ class ModuleDecoderTemplate : public Decoder {
uint8_t kind = read_u8<Decoder::FullValidationTag>(pc(), "type kind"); uint8_t kind = read_u8<Decoder::FullValidationTag>(pc(), "type kind");
if (kind == kWasmRecursiveTypeGroupCode) { if (kind == kWasmRecursiveTypeGroupCode) {
consume_bytes(1, "rec. group definition", tracer_); consume_bytes(1, "rec. group definition", tracer_);
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
size_t initial_size = module_->types.size(); size_t initial_size = module_->types.size();
uint32_t group_size = uint32_t group_size =
consume_count("recursive group size", kV8MaxWasmTypes); consume_count("recursive group size", kV8MaxWasmTypes);
@ -694,7 +661,7 @@ class ModuleDecoderTemplate : public Decoder {
module_->isorecursive_canonical_type_ids.resize(initial_size + module_->isorecursive_canonical_type_ids.resize(initial_size +
group_size); group_size);
for (uint32_t j = 0; j < group_size; j++) { for (uint32_t j = 0; j < group_size; j++) {
tracer_.TypeOffset(pc_offset()); if (tracer_) tracer_->TypeOffset(pc_offset());
TypeDefinition type = consume_subtype_definition(); TypeDefinition type = consume_subtype_definition();
if (ok()) module_->types[initial_size + j] = type; if (ok()) module_->types[initial_size + j] = type;
} }
@ -703,7 +670,7 @@ class ModuleDecoderTemplate : public Decoder {
static_cast<uint32_t>(initial_size)); static_cast<uint32_t>(initial_size));
} }
} else { } else {
tracer_.TypeOffset(pc_offset()); if (tracer_) tracer_->TypeOffset(pc_offset());
TypeDefinition type = consume_subtype_definition(); TypeDefinition type = consume_subtype_definition();
if (ok()) { if (ok()) {
module_->add_type(type); module_->add_type(type);
@ -751,7 +718,7 @@ class ModuleDecoderTemplate : public Decoder {
for (uint32_t i = 0; ok() && i < import_table_count; ++i) { for (uint32_t i = 0; ok() && i < import_table_count; ++i) {
TRACE("DecodeImportTable[%d] module+%d\n", i, TRACE("DecodeImportTable[%d] module+%d\n", i,
static_cast<int>(pc_ - start_)); static_cast<int>(pc_ - start_));
tracer_.ImportOffset(pc_offset()); if (tracer_) tracer_->ImportOffset(pc_offset());
module_->import_table.push_back({ module_->import_table.push_back({
{0, 0}, // module_name {0, 0}, // module_name
@ -765,7 +732,7 @@ class ModuleDecoderTemplate : public Decoder {
import->field_name = consume_utf8_string(this, "field name", tracer_); import->field_name = consume_utf8_string(this, "field name", tracer_);
import->kind = import->kind =
static_cast<ImportExportKindCode>(consume_u8("kind: ", tracer_)); static_cast<ImportExportKindCode>(consume_u8("kind: ", tracer_));
tracer_.Description(ExternalKindName(import->kind)); if (tracer_) tracer_->Description(ExternalKindName(import->kind));
switch (import->kind) { switch (import->kind) {
case kExternalFunction: { case kExternalFunction: {
// ===== Imported function =========================================== // ===== Imported function ===========================================
@ -830,7 +797,7 @@ class ModuleDecoderTemplate : public Decoder {
if (global->mutability) { if (global->mutability) {
module_->num_imported_mutable_globals++; module_->num_imported_mutable_globals++;
} }
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
break; break;
} }
case kExternalTag: { case kExternalTag: {
@ -849,7 +816,7 @@ class ModuleDecoderTemplate : public Decoder {
} }
} }
UpdateMemorySizes(); UpdateMemorySizes();
tracer_.ImportsDone(); if (tracer_) tracer_->ImportsDone();
} }
void DecodeFunctionSection() { void DecodeFunctionSection() {
@ -876,7 +843,7 @@ class ModuleDecoderTemplate : public Decoder {
func_index < total_function_count; ++func_index) { func_index < total_function_count; ++func_index) {
WasmFunction* function = &module_->functions[func_index]; WasmFunction* function = &module_->functions[func_index];
function->func_index = func_index; function->func_index = func_index;
tracer_.FunctionName(func_index); if (tracer_) tracer_->FunctionName(func_index);
function->sig_index = consume_sig_index(module_.get(), &function->sig); function->sig_index = consume_sig_index(module_.get(), &function->sig);
if (!ok()) return; if (!ok()) return;
} }
@ -886,7 +853,7 @@ class ModuleDecoderTemplate : public Decoder {
uint32_t table_count = consume_count("table count", kV8MaxWasmTables); uint32_t table_count = consume_count("table count", kV8MaxWasmTables);
for (uint32_t i = 0; ok() && i < table_count; i++) { for (uint32_t i = 0; ok() && i < table_count; i++) {
tracer_.TableOffset(pc_offset()); if (tracer_) tracer_->TableOffset(pc_offset());
module_->tables.emplace_back(); module_->tables.emplace_back();
WasmTable* table = &module_->tables.back(); WasmTable* table = &module_->tables.back();
const byte* type_position = pc(); const byte* type_position = pc();
@ -929,7 +896,7 @@ class ModuleDecoderTemplate : public Decoder {
uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories); uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories);
for (uint32_t i = 0; ok() && i < memory_count; i++) { for (uint32_t i = 0; ok() && i < memory_count; i++) {
tracer_.MemoryOffset(pc_offset()); if (tracer_) tracer_->MemoryOffset(pc_offset());
if (!AddMemory(module_.get())) break; if (!AddMemory(module_.get())) break;
consume_memory_flags(&module_->has_shared_memory, &module_->is_memory64, consume_memory_flags(&module_->has_shared_memory, &module_->is_memory64,
&module_->has_maximum_pages); &module_->has_maximum_pages);
@ -964,7 +931,7 @@ class ModuleDecoderTemplate : public Decoder {
module_->globals.reserve(imported_globals + globals_count); module_->globals.reserve(imported_globals + globals_count);
for (uint32_t i = 0; ok() && i < globals_count; ++i) { for (uint32_t i = 0; ok() && i < globals_count; ++i) {
TRACE("DecodeGlobal[%d] module+%d\n", i, static_cast<int>(pc_ - start_)); TRACE("DecodeGlobal[%d] module+%d\n", i, static_cast<int>(pc_ - start_));
tracer_.GlobalOffset(pc_offset()); if (tracer_) tracer_->GlobalOffset(pc_offset());
ValueType type = consume_value_type(); ValueType type = consume_value_type();
bool mutability = consume_mutability(); bool mutability = consume_mutability();
if (failed()) break; if (failed()) break;
@ -980,9 +947,11 @@ class ModuleDecoderTemplate : public Decoder {
for (uint32_t i = 0; ok() && i < export_table_count; ++i) { for (uint32_t i = 0; ok() && i < export_table_count; ++i) {
TRACE("DecodeExportTable[%d] module+%d\n", i, TRACE("DecodeExportTable[%d] module+%d\n", i,
static_cast<int>(pc_ - start_)); static_cast<int>(pc_ - start_));
tracer_.Description("export #"); if (tracer_) {
tracer_.Description(i); tracer_->Description("export #");
tracer_.NextLine(); tracer_->Description(i);
tracer_->NextLine();
}
module_->export_table.push_back({ module_->export_table.push_back({
{0, 0}, // name {0, 0}, // name
@ -996,8 +965,10 @@ class ModuleDecoderTemplate : public Decoder {
const byte* pos = pc(); const byte* pos = pc();
exp->kind = exp->kind =
static_cast<ImportExportKindCode>(consume_u8("kind: ", tracer_)); static_cast<ImportExportKindCode>(consume_u8("kind: ", tracer_));
tracer_.Description(ExternalKindName(exp->kind)); if (tracer_) {
tracer_.Description(" "); tracer_->Description(ExternalKindName(exp->kind));
tracer_->Description(" ");
}
switch (exp->kind) { switch (exp->kind) {
case kExternalFunction: { case kExternalFunction: {
WasmFunction* func = nullptr; WasmFunction* func = nullptr;
@ -1045,7 +1016,7 @@ class ModuleDecoderTemplate : public Decoder {
errorf(pos, "invalid export kind 0x%02x", exp->kind); errorf(pos, "invalid export kind 0x%02x", exp->kind);
break; break;
} }
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
} }
// Check for duplicate exports (except for asm.js). // Check for duplicate exports (except for asm.js).
if (ok() && module_->origin == kWasmOrigin && if (ok() && module_->origin == kWasmOrigin &&
@ -1080,11 +1051,11 @@ class ModuleDecoderTemplate : public Decoder {
} }
void DecodeStartSection() { void DecodeStartSection() {
tracer_.StartOffset(pc_offset()); if (tracer_) tracer_->StartOffset(pc_offset());
WasmFunction* func; WasmFunction* func;
const byte* pos = pc_; const byte* pos = pc_;
module_->start_function_index = consume_func_index(module_.get(), &func); module_->start_function_index = consume_func_index(module_.get(), &func);
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
if (func && if (func &&
(func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) { (func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) {
error(pos, "invalid start function: non-zero parameter or return count"); error(pos, "invalid start function: non-zero parameter or return count");
@ -1096,9 +1067,9 @@ class ModuleDecoderTemplate : public Decoder {
consume_count("segment count", v8_flags.wasm_max_table_size); consume_count("segment count", v8_flags.wasm_max_table_size);
for (uint32_t i = 0; i < segment_count; ++i) { for (uint32_t i = 0; i < segment_count; ++i) {
tracer_.ElementOffset(pc_offset()); if (tracer_) tracer_->ElementOffset(pc_offset());
WasmElemSegment segment = consume_element_segment_header(); WasmElemSegment segment = consume_element_segment_header();
tracer_.NextLineIfNonEmpty(); if (tracer_) tracer_->NextLineIfNonEmpty();
if (failed()) return; if (failed()) return;
DCHECK_NE(segment.type, kWasmBottom); DCHECK_NE(segment.type, kWasmBottom);
@ -1124,8 +1095,10 @@ class ModuleDecoderTemplate : public Decoder {
CalculateGlobalOffsets(module_.get()); CalculateGlobalOffsets(module_.get());
uint32_t code_section_start = pc_offset(); uint32_t code_section_start = pc_offset();
uint32_t functions_count = consume_u32v("functions count", tracer_); uint32_t functions_count = consume_u32v("functions count", tracer_);
tracer_.Description(functions_count); if (tracer_) {
tracer_.NextLine(); tracer_->Description(functions_count);
tracer_->NextLine();
}
CheckFunctionsCount(functions_count, code_section_start); CheckFunctionsCount(functions_count, code_section_start);
auto inst_traces_it = this->inst_traces_.begin(); auto inst_traces_it = this->inst_traces_.begin();
@ -1133,13 +1106,17 @@ class ModuleDecoderTemplate : public Decoder {
for (uint32_t i = 0; ok() && i < functions_count; ++i) { for (uint32_t i = 0; ok() && i < functions_count; ++i) {
int function_index = module_->num_imported_functions + i; int function_index = module_->num_imported_functions + i;
tracer_.Description("function #"); if (tracer_) {
tracer_.FunctionName(function_index); tracer_->Description("function #");
tracer_.NextLine(); tracer_->FunctionName(function_index);
tracer_->NextLine();
}
const byte* pos = pc(); const byte* pos = pc();
uint32_t size = consume_u32v("body size", tracer_); uint32_t size = consume_u32v("body size", tracer_);
tracer_.Description(size); if (tracer_) {
tracer_.NextLine(); tracer_->Description(size);
tracer_->NextLine();
}
if (size > kV8MaxWasmFunctionSize) { if (size > kV8MaxWasmFunctionSize) {
errorf(pos, "size %u > maximum function size %zu", size, errorf(pos, "size %u > maximum function size %zu", size,
kV8MaxWasmFunctionSize); kV8MaxWasmFunctionSize);
@ -1195,7 +1172,9 @@ class ModuleDecoderTemplate : public Decoder {
uint32_t offset) { uint32_t offset) {
WasmFunction* function = &module_->functions[func_index]; WasmFunction* function = &module_->functions[func_index];
function->code = {offset, length}; function->code = {offset, length};
tracer_.FunctionBody(function, pc_ - (pc_offset() - offset)); if (tracer_) {
tracer_->FunctionBody(function, pc_ - (pc_offset() - offset));
}
} }
bool CheckDataSegmentsCount(uint32_t data_segments_count) { bool CheckDataSegmentsCount(uint32_t data_segments_count) {
@ -1218,7 +1197,7 @@ class ModuleDecoderTemplate : public Decoder {
const byte* pos = pc(); const byte* pos = pc();
TRACE("DecodeDataSegment[%d] module+%d\n", i, TRACE("DecodeDataSegment[%d] module+%d\n", i,
static_cast<int>(pc_ - start_)); static_cast<int>(pc_ - start_));
tracer_.DataOffset(pc_offset()); if (tracer_) tracer_->DataOffset(pc_offset());
bool is_active; bool is_active;
uint32_t memory_index; uint32_t memory_index;
@ -1238,8 +1217,10 @@ class ModuleDecoderTemplate : public Decoder {
} }
uint32_t source_length = consume_u32v("source size", tracer_); uint32_t source_length = consume_u32v("source size", tracer_);
tracer_.Description(source_length); if (tracer_) {
tracer_.NextLine(); tracer_->Description(source_length);
tracer_->NextLine();
}
uint32_t source_offset = pc_offset(); uint32_t source_offset = pc_offset();
if (is_active) { if (is_active) {
@ -1250,9 +1231,11 @@ class ModuleDecoderTemplate : public Decoder {
WasmDataSegment* segment = &module_->data_segments.back(); WasmDataSegment* segment = &module_->data_segments.back();
tracer_.Bytes(pc_, source_length); if (tracer_) {
tracer_.Description("segment data"); tracer_->Bytes(pc_, source_length);
tracer_.NextLine(); tracer_->Description("segment data");
tracer_->NextLine();
}
consume_bytes(source_length, "segment data"); consume_bytes(source_length, "segment data");
if (failed()) break; if (failed()) break;
@ -1261,8 +1244,10 @@ class ModuleDecoderTemplate : public Decoder {
} }
void DecodeNameSection() { void DecodeNameSection() {
tracer_.NameSection(pc_, end_, if (tracer_) {
buffer_offset_ + static_cast<uint32_t>(pc_ - start_)); tracer_->NameSection(
pc_, end_, buffer_offset_ + static_cast<uint32_t>(pc_ - start_));
}
// TODO(titzer): find a way to report name errors as warnings. // TODO(titzer): find a way to report name errors as warnings.
// Ignore all but the first occurrence of name section. // Ignore all but the first occurrence of name section.
if (!has_seen_unordered_section(kNameSectionCode)) { if (!has_seen_unordered_section(kNameSectionCode)) {
@ -1282,11 +1267,10 @@ class ModuleDecoderTemplate : public Decoder {
// Decode module name, ignore the rest. // Decode module name, ignore the rest.
// Function and local names will be decoded when needed. // Function and local names will be decoded when needed.
NoTracer tracing_already_done;
if (name_type == NameSectionKindCode::kModuleCode) { if (name_type == NameSectionKindCode::kModuleCode) {
WireBytesRef name = WireBytesRef name =
consume_string(&inner, unibrow::Utf8Variant::kLossyUtf8, consume_string(&inner, unibrow::Utf8Variant::kLossyUtf8,
"module name", tracing_already_done); "module name", ITracer::NoTrace);
if (inner.ok() && validate_utf8(&inner, name)) { if (inner.ok() && validate_utf8(&inner, name)) {
module_->name = name; module_->name = name;
} }
@ -1564,14 +1548,14 @@ class ModuleDecoderTemplate : public Decoder {
void DecodeDataCountSection() { void DecodeDataCountSection() {
module_->num_declared_data_segments = module_->num_declared_data_segments =
consume_count("data segments count", kV8MaxWasmDataSegments); consume_count("data segments count", kV8MaxWasmDataSegments);
tracer_.NextLineIfNonEmpty(); if (tracer_) tracer_->NextLineIfNonEmpty();
} }
void DecodeTagSection() { void DecodeTagSection() {
uint32_t tag_count = consume_count("tag count", kV8MaxWasmTags); uint32_t tag_count = consume_count("tag count", kV8MaxWasmTags);
for (uint32_t i = 0; ok() && i < tag_count; ++i) { for (uint32_t i = 0; ok() && i < tag_count; ++i) {
TRACE("DecodeTag[%d] module+%d\n", i, static_cast<int>(pc_ - start_)); TRACE("DecodeTag[%d] module+%d\n", i, static_cast<int>(pc_ - start_));
tracer_.TagOffset(pc_offset()); if (tracer_) tracer_->TagOffset(pc_offset());
const WasmTagSig* tag_sig = nullptr; const WasmTagSig* tag_sig = nullptr;
consume_exception_attribute(); // Attribute ignored for now. consume_exception_attribute(); // Attribute ignored for now.
uint32_t sig_index = consume_tag_sig_index(module_.get(), &tag_sig); uint32_t sig_index = consume_tag_sig_index(module_.get(), &tag_sig);
@ -1784,7 +1768,7 @@ class ModuleDecoderTemplate : public Decoder {
uint32_t consume_sig_index(WasmModule* module, const FunctionSig** sig) { uint32_t consume_sig_index(WasmModule* module, const FunctionSig** sig) {
const byte* pos = pc_; const byte* pos = pc_;
uint32_t sig_index = consume_u32v("signature index"); uint32_t sig_index = consume_u32v("signature index");
tracer_.Bytes(pos, static_cast<uint32_t>(pc_ - pos)); if (tracer_) tracer_->Bytes(pos, static_cast<uint32_t>(pc_ - pos));
if (!module->has_signature(sig_index)) { if (!module->has_signature(sig_index)) {
errorf(pos, "no signature at index %u (%d %s)", sig_index, errorf(pos, "no signature at index %u (%d %s)", sig_index,
static_cast<int>(module->types.size()), static_cast<int>(module->types.size()),
@ -1793,8 +1777,10 @@ class ModuleDecoderTemplate : public Decoder {
return 0; return 0;
} }
*sig = module->signature(sig_index); *sig = module->signature(sig_index);
tracer_.Description(*sig); if (tracer_) {
tracer_.NextLine(); tracer_->Description(*sig);
tracer_->NextLine();
}
return sig_index; return sig_index;
} }
@ -1812,11 +1798,13 @@ class ModuleDecoderTemplate : public Decoder {
uint32_t consume_count(const char* name, size_t maximum) { uint32_t consume_count(const char* name, size_t maximum) {
const byte* p = pc_; const byte* p = pc_;
uint32_t count = consume_u32v(name, tracer_); uint32_t count = consume_u32v(name, tracer_);
tracer_.Description(count); if (tracer_) {
if (count == 1) { tracer_->Description(count);
tracer_.Description(": "); if (count == 1) {
} else { tracer_->Description(": ");
tracer_.NextLine(); } else {
tracer_->NextLine();
}
} }
if (count > maximum) { if (count > maximum) {
errorf(p, "%s of %u exceeds internal limit of %zu", name, count, maximum); errorf(p, "%s of %u exceeds internal limit of %zu", name, count, maximum);
@ -1845,7 +1833,7 @@ class ModuleDecoderTemplate : public Decoder {
uint32_t consume_index(const char* name, std::vector<T>* vector, T** ptr) { uint32_t consume_index(const char* name, std::vector<T>* vector, T** ptr) {
const byte* pos = pc_; const byte* pos = pc_;
uint32_t index = consume_u32v("index:", tracer_); uint32_t index = consume_u32v("index:", tracer_);
tracer_.Description(index); if (tracer_) tracer_->Description(index);
if (index >= vector->size()) { if (index >= vector->size()) {
errorf(pos, "%s index %u out of bounds (%d entr%s)", name, index, errorf(pos, "%s index %u out of bounds (%d entr%s)", name, index,
static_cast<int>(vector->size()), static_cast<int>(vector->size()),
@ -1858,10 +1846,14 @@ class ModuleDecoderTemplate : public Decoder {
} }
void consume_table_flags(const char* name, bool* has_maximum_out) { void consume_table_flags(const char* name, bool* has_maximum_out) {
tracer_.Bytes(pc_, 1); if (tracer_) tracer_->Bytes(pc_, 1);
uint8_t flags = consume_u8("table limits flags"); uint8_t flags = consume_u8("table limits flags");
tracer_.Description(flags == kNoMaximum ? " no maximum" : " with maximum"); if (tracer_) {
tracer_.NextLine(); tracer_->Description(flags == kNoMaximum ? " no maximum"
: " with maximum");
tracer_->NextLine();
}
static_assert(kNoMaximum == 0 && kWithMaximum == 1); static_assert(kNoMaximum == 0 && kWithMaximum == 1);
*has_maximum_out = flags == kWithMaximum; *has_maximum_out = flags == kWithMaximum;
if (V8_UNLIKELY(flags > kWithMaximum)) { if (V8_UNLIKELY(flags > kWithMaximum)) {
@ -1871,7 +1863,7 @@ class ModuleDecoderTemplate : public Decoder {
void consume_memory_flags(bool* is_shared_out, bool* is_memory64_out, void consume_memory_flags(bool* is_shared_out, bool* is_memory64_out,
bool* has_maximum_out) { bool* has_maximum_out) {
tracer_.Bytes(pc_, 1); if (tracer_) tracer_->Bytes(pc_, 1);
uint8_t flags = consume_u8("memory limits flags"); uint8_t flags = consume_u8("memory limits flags");
// Flags 0..7 are valid (3 bits). // Flags 0..7 are valid (3 bits).
if (flags & ~0x7) { if (flags & ~0x7) {
@ -1899,10 +1891,12 @@ class ModuleDecoderTemplate : public Decoder {
} }
// Tracing. // Tracing.
if (is_shared) tracer_.Description(" shared"); if (tracer_) {
if (is_memory64) tracer_.Description(" mem64"); if (is_shared) tracer_->Description(" shared");
tracer_.Description(has_maximum ? " with maximum" : " no maximum"); if (is_memory64) tracer_->Description(" mem64");
tracer_.NextLine(); tracer_->Description(has_maximum ? " with maximum" : " no maximum");
tracer_->NextLine();
}
} }
enum ResizableLimitsType : bool { k32BitLimits, k64BitLimits }; enum ResizableLimitsType : bool { k32BitLimits, k64BitLimits };
@ -1923,8 +1917,10 @@ class ModuleDecoderTemplate : public Decoder {
name, initial_64, units, max_initial, units); name, initial_64, units, max_initial, units);
} }
*initial = static_cast<uint32_t>(initial_64); *initial = static_cast<uint32_t>(initial_64);
tracer_.Description(*initial); if (tracer_) {
tracer_.NextLine(); tracer_->Description(*initial);
tracer_->NextLine();
}
if (has_maximum) { if (has_maximum) {
pos = pc(); pos = pc();
uint64_t maximum_64 = type == k64BitLimits uint64_t maximum_64 = type == k64BitLimits
@ -1942,8 +1938,10 @@ class ModuleDecoderTemplate : public Decoder {
name, maximum_64, units, *initial, units); name, maximum_64, units, *initial, units);
} }
*maximum = static_cast<uint32_t>(maximum_64); *maximum = static_cast<uint32_t>(maximum_64);
tracer_.Description(*maximum); if (tracer_) {
tracer_.NextLine(); tracer_->Description(*maximum);
tracer_->NextLine();
}
} else { } else {
*maximum = max_initial; *maximum = max_initial;
} }
@ -1972,7 +1970,7 @@ class ModuleDecoderTemplate : public Decoder {
return {}; \ return {}; \
} }
tracer_.NextLineIfNonEmpty(); if (tracer_) tracer_->NextLineIfNonEmpty();
// To avoid initializing a {WasmFullDecoder} for the most common // To avoid initializing a {WasmFullDecoder} for the most common
// expressions, we replicate their decoding and validation here. The // expressions, we replicate their decoding and validation here. The
// manually handled cases correspond to {ConstantExpression}'s kinds. // manually handled cases correspond to {ConstantExpression}'s kinds.
@ -1990,7 +1988,9 @@ class ModuleDecoderTemplate : public Decoder {
if (V8_UNLIKELY(failed())) return {}; if (V8_UNLIKELY(failed())) return {};
if (V8_LIKELY(lookahead(1 + length, kExprEnd))) { if (V8_LIKELY(lookahead(1 + length, kExprEnd))) {
TYPE_CHECK(kWasmI32) TYPE_CHECK(kWasmI32)
tracer_.InitializerExpression(pc_, pc_ + length + 2, kWasmI32); if (tracer_) {
tracer_->InitializerExpression(pc_, pc_ + length + 2, kWasmI32);
}
consume_bytes(length + 2); consume_bytes(length + 2);
return ConstantExpression::I32Const(value); return ConstantExpression::I32Const(value);
} }
@ -2011,7 +2011,9 @@ class ModuleDecoderTemplate : public Decoder {
: kWasmFuncRef; : kWasmFuncRef;
TYPE_CHECK(type) TYPE_CHECK(type)
module_->functions[index].declared = true; module_->functions[index].declared = true;
tracer_.InitializerExpression(pc_, pc_ + length + 2, type); if (tracer_) {
tracer_->InitializerExpression(pc_, pc_ + length + 2, type);
}
consume_bytes(length + 2); consume_bytes(length + 2);
return ConstantExpression::RefFunc(index); return ConstantExpression::RefFunc(index);
} }
@ -2025,8 +2027,10 @@ class ModuleDecoderTemplate : public Decoder {
if (V8_UNLIKELY(failed())) return {}; if (V8_UNLIKELY(failed())) return {};
if (V8_LIKELY(lookahead(1 + length, kExprEnd))) { if (V8_LIKELY(lookahead(1 + length, kExprEnd))) {
TYPE_CHECK(ValueType::RefNull(type)) TYPE_CHECK(ValueType::RefNull(type))
tracer_.InitializerExpression(pc_, pc_ + length + 2, if (tracer_) {
ValueType::RefNull(type)); tracer_->InitializerExpression(pc_, pc_ + length + 2,
ValueType::RefNull(type));
}
consume_bytes(length + 2); consume_bytes(length + 2);
return ConstantExpression::RefNull(type.representation()); return ConstantExpression::RefNull(type.representation());
} }
@ -2049,7 +2053,9 @@ class ModuleDecoderTemplate : public Decoder {
decoder.DecodeFunctionBody(); decoder.DecodeFunctionBody();
tracer_.InitializerExpression(pc_, decoder.end(), expected); if (tracer_) {
tracer_->InitializerExpression(pc_, decoder.end(), expected);
}
this->pc_ = decoder.end(); this->pc_ = decoder.end();
if (decoder.failed()) { if (decoder.failed()) {
@ -2068,11 +2074,13 @@ class ModuleDecoderTemplate : public Decoder {
// Read a mutability flag // Read a mutability flag
bool consume_mutability() { bool consume_mutability() {
tracer_.Bytes(pc_, 1); if (tracer_) tracer_->Bytes(pc_, 1);
byte val = consume_u8("mutability"); byte val = consume_u8("mutability");
tracer_.Description(val == 0 ? " immutable" if (tracer_) {
: val == 1 ? " mutable" tracer_->Description(val == 0 ? " immutable"
: " invalid"); : val == 1 ? " mutable"
: " invalid");
}
if (val > 1) error(pc_ - 1, "invalid mutability"); if (val > 1) error(pc_ - 1, "invalid mutability");
return val != 0; return val != 0;
} }
@ -2085,24 +2093,14 @@ class ModuleDecoderTemplate : public Decoder {
: WasmFeatures::None()); : WasmFeatures::None());
value_type_reader::ValidateValueType<FullValidationTag>( value_type_reader::ValidateValueType<FullValidationTag>(
this, pc_, module_.get(), result); this, pc_, module_.get(), result);
tracer_.Bytes(pc_, type_length); if (tracer_) {
tracer_.Description(result); tracer_->Bytes(pc_, type_length);
tracer_->Description(result);
}
consume_bytes(type_length, "value type"); consume_bytes(type_length, "value type");
return result; return result;
} }
HeapType consume_super_type() {
uint32_t type_length;
HeapType result = value_type_reader::read_heap_type<FullValidationTag>(
this, pc_, &type_length, enabled_features_);
value_type_reader::ValidateValueType<FullValidationTag>(
this, pc_, module_.get(), result);
tracer_.Bytes(pc_, type_length);
tracer_.Description(result);
consume_bytes(type_length, "heap type");
return result;
}
ValueType consume_storage_type() { ValueType consume_storage_type() {
uint8_t opcode = read_u8<FullValidationTag>(this->pc()); uint8_t opcode = read_u8<FullValidationTag>(this->pc());
switch (opcode) { switch (opcode) {
@ -2119,7 +2117,7 @@ class ModuleDecoderTemplate : public Decoder {
} }
const FunctionSig* consume_sig(Zone* zone) { const FunctionSig* consume_sig(Zone* zone) {
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
// Parse parameter types. // Parse parameter types.
uint32_t param_count = uint32_t param_count =
consume_count("param count", kV8MaxWasmFunctionParams); consume_count("param count", kV8MaxWasmFunctionParams);
@ -2127,9 +2125,9 @@ class ModuleDecoderTemplate : public Decoder {
std::vector<ValueType> params; std::vector<ValueType> params;
for (uint32_t i = 0; ok() && i < param_count; ++i) { for (uint32_t i = 0; ok() && i < param_count; ++i) {
params.push_back(consume_value_type()); params.push_back(consume_value_type());
tracer_.NextLineIfFull(); if (tracer_) tracer_->NextLineIfFull();
} }
tracer_.NextLineIfNonEmpty(); if (tracer_) tracer_->NextLineIfNonEmpty();
if (failed()) return nullptr; if (failed()) return nullptr;
// Parse return types. // Parse return types.
@ -2139,9 +2137,9 @@ class ModuleDecoderTemplate : public Decoder {
if (failed()) return nullptr; if (failed()) return nullptr;
for (uint32_t i = 0; ok() && i < return_count; ++i) { for (uint32_t i = 0; ok() && i < return_count; ++i) {
returns.push_back(consume_value_type()); returns.push_back(consume_value_type());
tracer_.NextLineIfFull(); if (tracer_) tracer_->NextLineIfFull();
} }
tracer_.NextLineIfNonEmpty(); if (tracer_) tracer_->NextLineIfNonEmpty();
if (failed()) return nullptr; if (failed()) return nullptr;
// FunctionSig stores the return types first. // FunctionSig stores the return types first.
@ -2162,7 +2160,7 @@ class ModuleDecoderTemplate : public Decoder {
for (uint32_t i = 0; ok() && i < field_count; ++i) { for (uint32_t i = 0; ok() && i < field_count; ++i) {
fields[i] = consume_storage_type(); fields[i] = consume_storage_type();
mutabilities[i] = consume_mutability(); mutabilities[i] = consume_mutability();
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
} }
if (failed()) return nullptr; if (failed()) return nullptr;
uint32_t* offsets = zone->NewArray<uint32_t>(field_count); uint32_t* offsets = zone->NewArray<uint32_t>(field_count);
@ -2175,7 +2173,7 @@ class ModuleDecoderTemplate : public Decoder {
const ArrayType* consume_array(Zone* zone) { const ArrayType* consume_array(Zone* zone) {
ValueType element_type = consume_storage_type(); ValueType element_type = consume_storage_type();
bool mutability = consume_mutability(); bool mutability = consume_mutability();
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
if (failed()) return nullptr; if (failed()) return nullptr;
return zone->New<ArrayType>(element_type, mutability); return zone->New<ArrayType>(element_type, mutability);
} }
@ -2184,7 +2182,7 @@ class ModuleDecoderTemplate : public Decoder {
uint32_t consume_exception_attribute() { uint32_t consume_exception_attribute() {
const byte* pos = pc_; const byte* pos = pc_;
uint32_t attribute = consume_u32v("exception attribute"); uint32_t attribute = consume_u32v("exception attribute");
tracer_.Bytes(pos, static_cast<uint32_t>(pc_ - pos)); if (tracer_) tracer_->Bytes(pos, static_cast<uint32_t>(pc_ - pos));
if (attribute != kExceptionAttribute) { if (attribute != kExceptionAttribute) {
errorf(pos, "exception attribute %u not supported", attribute); errorf(pos, "exception attribute %u not supported", attribute);
return 0; return 0;
@ -2221,11 +2219,12 @@ class ModuleDecoderTemplate : public Decoder {
: WasmElemSegment::kStatusPassive : WasmElemSegment::kStatusPassive
: WasmElemSegment::kStatusActive; : WasmElemSegment::kStatusActive;
const bool is_active = status == WasmElemSegment::kStatusActive; const bool is_active = status == WasmElemSegment::kStatusActive;
// clang-format off if (tracer_) {
tracer_.Description(status == WasmElemSegment::kStatusActive ? "active" : tracer_->Description(status == WasmElemSegment::kStatusActive ? "active"
status == WasmElemSegment::kStatusPassive ? "passive," : : status == WasmElemSegment::kStatusPassive
"declarative,"); ? "passive,"
// clang-format on : "declarative,");
}
WasmElemSegment::ElementType element_type = WasmElemSegment::ElementType element_type =
flag & kExpressionsAsElementsMask flag & kExpressionsAsElementsMask
@ -2237,7 +2236,7 @@ class ModuleDecoderTemplate : public Decoder {
uint32_t table_index = 0; uint32_t table_index = 0;
if (has_table_index) { if (has_table_index) {
table_index = consume_u32v(", table index", tracer_); table_index = consume_u32v(", table index", tracer_);
tracer_.Description(table_index); if (tracer_) tracer_->Description(table_index);
} }
if (V8_UNLIKELY(is_active && table_index >= module_->tables.size())) { if (V8_UNLIKELY(is_active && table_index >= module_->tables.size())) {
errorf(pos, "out of bounds%s table index %u", errorf(pos, "out of bounds%s table index %u",
@ -2249,8 +2248,10 @@ class ModuleDecoderTemplate : public Decoder {
ConstantExpression offset; ConstantExpression offset;
if (is_active) { if (is_active) {
tracer_.Description(", offset:"); if (tracer_) {
tracer_.NextLine(); tracer_->Description(", offset:");
tracer_->NextLine();
}
offset = consume_init_expr(module_.get(), kWasmI32); offset = consume_init_expr(module_.get(), kWasmI32);
// Failed to parse offset initializer, return early. // Failed to parse offset initializer, return early.
if (failed()) return {}; if (failed()) return {};
@ -2264,7 +2265,7 @@ class ModuleDecoderTemplate : public Decoder {
if (backwards_compatible_mode) { if (backwards_compatible_mode) {
type = kWasmFuncRef; type = kWasmFuncRef;
} else { } else {
tracer_.Description(" element type:"); if (tracer_) tracer_->Description(" element type:");
type = consume_value_type(); type = consume_value_type();
if (failed()) return {}; if (failed()) return {};
} }
@ -2323,12 +2324,14 @@ class ModuleDecoderTemplate : public Decoder {
ConstantExpression* offset) { ConstantExpression* offset) {
const byte* pos = pc(); const byte* pos = pc();
uint32_t flag = consume_u32v("flag: ", tracer_); uint32_t flag = consume_u32v("flag: ", tracer_);
tracer_.Description(flag == SegmentFlags::kActiveNoIndex ? "active no index" if (tracer_) {
: flag == SegmentFlags::kPassive ? "passive" tracer_->Description(
: flag == SegmentFlags::kActiveWithIndex flag == SegmentFlags::kActiveNoIndex ? "active no index"
? "active with index" : flag == SegmentFlags::kPassive ? "passive"
: "unknown"); : flag == SegmentFlags::kActiveWithIndex ? "active with index"
tracer_.NextLine(); : "unknown");
tracer_->NextLine();
}
// Some flag values are only valid for specific proposals. // Some flag values are only valid for specific proposals.
if (flag != SegmentFlags::kActiveNoIndex && if (flag != SegmentFlags::kActiveNoIndex &&
@ -2353,7 +2356,7 @@ class ModuleDecoderTemplate : public Decoder {
if (flag == SegmentFlags::kActiveWithIndex) { if (flag == SegmentFlags::kActiveWithIndex) {
*is_active = true; *is_active = true;
*index = consume_u32v("memory index", tracer_); *index = consume_u32v("memory index", tracer_);
tracer_.Description(*index); if (tracer_) tracer_->Description(*index);
*offset = consume_init_expr(module_.get(), expected_type); *offset = consume_init_expr(module_.get(), expected_type);
} }
} }
@ -2362,7 +2365,7 @@ class ModuleDecoderTemplate : public Decoder {
WasmFunction* func = nullptr; WasmFunction* func = nullptr;
const byte* initial_pc = pc(); const byte* initial_pc = pc();
uint32_t index = consume_func_index(module_.get(), &func); uint32_t index = consume_func_index(module_.get(), &func);
tracer_.NextLine(); if (tracer_) tracer_->NextLine();
if (failed()) return index; if (failed()) return index;
DCHECK_NOT_NULL(func); DCHECK_NOT_NULL(func);
DCHECK_EQ(index, func->func_index); DCHECK_EQ(index, func->func_index);
@ -2381,20 +2384,20 @@ class ModuleDecoderTemplate : public Decoder {
const std::shared_ptr<WasmModule> module_; const std::shared_ptr<WasmModule> module_;
const byte* module_start_ = nullptr; const byte* module_start_ = nullptr;
const byte* module_end_ = nullptr; const byte* module_end_ = nullptr;
Tracer& tracer_; ITracer* tracer_;
// The type section is the first section in a module. // The type section is the first section in a module.
uint8_t next_ordered_section_ = kFirstSectionInModule; uint8_t next_ordered_section_ = kFirstSectionInModule;
// We store next_ordered_section_ as uint8_t instead of SectionCode so that // We store next_ordered_section_ as uint8_t instead of SectionCode so that
// we can increment it. This static_assert should make sure that SectionCode // we can increment it. This static_assert should make sure that SectionCode
// does not get bigger than uint8_t accidentally. // does not get bigger than uint8_t accidentally.
static_assert(sizeof(ModuleDecoderTemplate::next_ordered_section_) == static_assert(sizeof(ModuleDecoderBase::next_ordered_section_) ==
sizeof(SectionCode), sizeof(SectionCode),
"type mismatch"); "type mismatch");
uint32_t seen_unordered_sections_ = 0; uint32_t seen_unordered_sections_ = 0;
static_assert( static_assert(kBitsPerByte *
kBitsPerByte * sizeof(ModuleDecoderTemplate::seen_unordered_sections_) > sizeof(ModuleDecoderBase::seen_unordered_sections_) >
kLastKnownModuleSection, kLastKnownModuleSection,
"not enough bits"); "not enough bits");
AccountingAllocator allocator_; AccountingAllocator allocator_;
Zone init_expr_zone_{&allocator_, "constant expr. zone"}; Zone init_expr_zone_{&allocator_, "constant expr. zone"};

View File

@ -69,18 +69,15 @@ const char* SectionName(SectionCode code) {
} }
} }
// Ideally we'd just say: // TODO(mliedtke): Convert ModuleDecoderBase to ModuleDecoder[Impl] and get rid
// using ModuleDecoderImpl = ModuleDecoderTemplate<NoTracer> // of this additional subclass. Then move the implementation from the impl
// but that doesn't work with the forward declaration in the header file. // header to the cc as it isn't a template any more.
class ModuleDecoderImpl : public ModuleDecoderTemplate<NoTracer> { class ModuleDecoderImpl : public ModuleDecoderBase {
public: public:
ModuleDecoderImpl(WasmFeatures enabled_features, ModuleDecoderImpl(WasmFeatures enabled_features,
base::Vector<const uint8_t> wire_bytes, ModuleOrigin origin) base::Vector<const uint8_t> wire_bytes, ModuleOrigin origin)
: ModuleDecoderTemplate<NoTracer>(enabled_features, wire_bytes, origin, : ModuleDecoderBase(enabled_features, wire_bytes, origin,
no_tracer_) {} ITracer::NoTrace) {}
private:
NoTracer no_tracer_;
}; };
ModuleResult DecodeWasmModule( ModuleResult DecodeWasmModule(
@ -187,8 +184,8 @@ size_t ModuleDecoder::IdentifyUnknownSection(ModuleDecoder* decoder,
SectionCode* result) { SectionCode* result) {
if (!decoder->ok()) return 0; if (!decoder->ok()) return 0;
decoder->impl_->Reset(bytes, offset); decoder->impl_->Reset(bytes, offset);
NoTracer no_tracer; *result =
*result = IdentifyUnknownSectionInternal(decoder->impl_.get(), no_tracer); IdentifyUnknownSectionInternal(decoder->impl_.get(), ITracer::NoTrace);
return decoder->impl_->pc() - bytes.begin(); return decoder->impl_->pc() - bytes.begin();
} }
@ -318,8 +315,7 @@ bool FindNameSection(Decoder* decoder) {
static constexpr int kModuleHeaderSize = 8; static constexpr int kModuleHeaderSize = 8;
decoder->consume_bytes(kModuleHeaderSize, "module header"); decoder->consume_bytes(kModuleHeaderSize, "module header");
NoTracer no_tracer; WasmSectionIterator section_iter(decoder, ITracer::NoTrace);
WasmSectionIterator section_iter(decoder, no_tracer);
while (decoder->ok() && section_iter.more() && while (decoder->ok() && section_iter.more() &&
section_iter.section_code() != kNameSectionCode) { section_iter.section_code() != kNameSectionCode) {

View File

@ -566,7 +566,7 @@ uint32_t FunctionBodyDisassembler::PrintImmediatesAndGetLength(
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// OffsetsProvider. // OffsetsProvider.
class OffsetsProvider { class OffsetsProvider : public ITracer {
public: public:
OffsetsProvider() = default; OffsetsProvider() = default;
@ -583,50 +583,58 @@ class OffsetsProvider {
element_offsets_.reserve(module->elem_segments.size()); element_offsets_.reserve(module->elem_segments.size());
data_offsets_.reserve(module->data_segments.size()); data_offsets_.reserve(module->data_segments.size());
using OffsetsCollectingDecoder = ModuleDecoderTemplate<OffsetsProvider>; ModuleDecoderBase decoder{WasmFeatures::All(), wire_bytes, kWasmOrigin,
OffsetsCollectingDecoder decoder{WasmFeatures::All(), wire_bytes, this};
kWasmOrigin, *this};
constexpr bool kNoVerifyFunctions = false; constexpr bool kNoVerifyFunctions = false;
decoder.DecodeModule(kNoVerifyFunctions); decoder.DecodeModule(kNoVerifyFunctions);
enabled_ = true; enabled_ = true;
} }
void TypeOffset(uint32_t offset) { type_offsets_.push_back(offset); } void TypeOffset(uint32_t offset) override { type_offsets_.push_back(offset); }
void ImportOffset(uint32_t offset) { import_offsets_.push_back(offset); } void ImportOffset(uint32_t offset) override {
import_offsets_.push_back(offset);
}
void TableOffset(uint32_t offset) { table_offsets_.push_back(offset); } void TableOffset(uint32_t offset) override {
table_offsets_.push_back(offset);
}
void MemoryOffset(uint32_t offset) { memory_offset_ = offset; } void MemoryOffset(uint32_t offset) override { memory_offset_ = offset; }
void TagOffset(uint32_t offset) { tag_offsets_.push_back(offset); } void TagOffset(uint32_t offset) override { tag_offsets_.push_back(offset); }
void GlobalOffset(uint32_t offset) { global_offsets_.push_back(offset); } void GlobalOffset(uint32_t offset) override {
global_offsets_.push_back(offset);
}
void StartOffset(uint32_t offset) { start_offset_ = offset; } void StartOffset(uint32_t offset) override { start_offset_ = offset; }
void ElementOffset(uint32_t offset) { element_offsets_.push_back(offset); } void ElementOffset(uint32_t offset) override {
element_offsets_.push_back(offset);
}
void DataOffset(uint32_t offset) { data_offsets_.push_back(offset); } void DataOffset(uint32_t offset) override { data_offsets_.push_back(offset); }
// Unused by this tracer: // Unused by this tracer:
void ImportsDone() {} void ImportsDone() override {}
void Bytes(const byte* start, uint32_t count) {} void Bytes(const byte* start, uint32_t count) override {}
void Description(const char* desc) {} void Description(const char* desc) override {}
void Description(const char* desc, size_t length) {} void Description(const char* desc, size_t length) override {}
void Description(uint32_t number) {} void Description(uint32_t number) override {}
void Description(ValueType type) {} void Description(ValueType type) override {}
void Description(HeapType type) {} void Description(HeapType type) override {}
void Description(const FunctionSig* sig) {} void Description(const FunctionSig* sig) override {}
void NextLine() {} void NextLine() override {}
void NextLineIfFull() {} void NextLineIfFull() override {}
void NextLineIfNonEmpty() {} void NextLineIfNonEmpty() override {}
void InitializerExpression(const byte* start, const byte* end, void InitializerExpression(const byte* start, const byte* end,
ValueType expected_type) {} ValueType expected_type) override {}
void FunctionBody(const WasmFunction* func, const byte* start) {} void FunctionBody(const WasmFunction* func, const byte* start) override {}
void FunctionName(uint32_t func_index) {} void FunctionName(uint32_t func_index) override {}
void NameSection(const byte* start, const byte* end, uint32_t offset) {} void NameSection(const byte* start, const byte* end,
uint32_t offset) override {}
#define GETTER(name) \ #define GETTER(name) \
uint32_t name##_offset(uint32_t index) { \ uint32_t name##_offset(uint32_t index) { \

View File

@ -42,13 +42,13 @@ class MockStreamingProcessor : public StreamingProcessor {
bool ProcessModuleHeader(base::Vector<const uint8_t> bytes, bool ProcessModuleHeader(base::Vector<const uint8_t> bytes,
uint32_t offset) override { uint32_t offset) override {
Decoder decoder(bytes.begin(), bytes.end()); Decoder decoder(bytes.begin(), bytes.end());
NoTracer no_tracer; uint32_t magic_word = decoder.consume_u32("wasm magic", ITracer::NoTrace);
uint32_t magic_word = decoder.consume_u32("wasm magic", no_tracer);
if (decoder.failed() || magic_word != kWasmMagic) { if (decoder.failed() || magic_word != kWasmMagic) {
result_->error = WasmError(0, "expected wasm magic"); result_->error = WasmError(0, "expected wasm magic");
return false; return false;
} }
uint32_t magic_version = decoder.consume_u32("wasm version", no_tracer); uint32_t magic_version =
decoder.consume_u32("wasm version", ITracer::NoTrace);
if (decoder.failed() || magic_version != kWasmVersion) { if (decoder.failed() || magic_version != kWasmVersion) {
result_->error = WasmError(4, "expected wasm version"); result_->error = WasmError(4, "expected wasm version");
return false; return false;

View File

@ -149,7 +149,7 @@ class InstructionStatistics {
<< static_cast<double>(total_size) / count; << static_cast<double>(total_size) / count;
out << std::setw(kSpacing) << " "; out << std::setw(kSpacing) << " ";
out << std::fixed << std::setprecision(1) << std::setw(8) out << std::fixed << std::setprecision(1) << std::setw(8)
<< 100.0 * total_size / this->total_code_size_ << "%\n"; << 100.0 * total_size / total_code_size_ << "%\n";
}; };
for (const Entry& e : sorted) { for (const Entry& e : sorted) {
PrintLine(WasmOpcodes::OpcodeName(e.opcode), e.count, e.total_size); PrintLine(WasmOpcodes::OpcodeName(e.opcode), e.count, e.total_size);
@ -358,12 +358,10 @@ class ExtendedFunctionDis : public FunctionBodyDisassembler {
// e.g.: // e.g.:
// 0x01, 0x70, 0x00, // table count 1: funcref no maximum // 0x01, 0x70, 0x00, // table count 1: funcref no maximum
class HexDumpModuleDis; class HexDumpModuleDis;
class DumpingModuleDecoder : public ModuleDecoderTemplate<HexDumpModuleDis> { class DumpingModuleDecoder : public ModuleDecoderBase {
public: public:
DumpingModuleDecoder(ModuleWireBytes wire_bytes, HexDumpModuleDis* module_dis) DumpingModuleDecoder(ModuleWireBytes wire_bytes,
: ModuleDecoderTemplate<HexDumpModuleDis>(WasmFeatures::All(), HexDumpModuleDis* module_dis);
wire_bytes.module_bytes(),
kWasmOrigin, *module_dis) {}
void onFirstError() override { void onFirstError() override {
// Pretend we've reached the end of the section, but contrary to the // Pretend we've reached the end of the section, but contrary to the
@ -372,7 +370,8 @@ class DumpingModuleDecoder : public ModuleDecoderTemplate<HexDumpModuleDis> {
end_ = pc_; end_ = pc_;
} }
}; };
class HexDumpModuleDis {
class HexDumpModuleDis : public ITracer {
public: public:
HexDumpModuleDis(MultiLineStringBuilder& out, const WasmModule* module, HexDumpModuleDis(MultiLineStringBuilder& out, const WasmModule* module,
NamesProvider* names, const ModuleWireBytes wire_bytes, NamesProvider* names, const ModuleWireBytes wire_bytes,
@ -417,7 +416,7 @@ class HexDumpModuleDis {
} }
// Tracer hooks. // Tracer hooks.
void Bytes(const byte* start, uint32_t count) { void Bytes(const byte* start, uint32_t count) override {
if (count > kMaxBytesPerLine) { if (count > kMaxBytesPerLine) {
DCHECK_EQ(queue_, nullptr); DCHECK_EQ(queue_, nullptr);
queue_ = start; queue_ = start;
@ -431,38 +430,38 @@ class HexDumpModuleDis {
total_bytes_ += count; total_bytes_ += count;
} }
void Description(const char* desc) { description_ << desc; } void Description(const char* desc) override { description_ << desc; }
void Description(const char* desc, size_t length) { void Description(const char* desc, size_t length) override {
description_.write(desc, length); description_.write(desc, length);
} }
void Description(uint32_t number) { void Description(uint32_t number) override {
if (description_.length() != 0) description_ << " "; if (description_.length() != 0) description_ << " ";
description_ << number; description_ << number;
} }
void Description(ValueType type) { void Description(ValueType type) override {
if (description_.length() != 0) description_ << " "; if (description_.length() != 0) description_ << " ";
names_->PrintValueType(description_, type); names_->PrintValueType(description_, type);
} }
void Description(HeapType type) { void Description(HeapType type) override {
if (description_.length() != 0) description_ << " "; if (description_.length() != 0) description_ << " ";
names_->PrintHeapType(description_, type); names_->PrintHeapType(description_, type);
} }
void Description(const FunctionSig* sig) { void Description(const FunctionSig* sig) override {
PrintSignatureOneLine(description_, sig, 0 /* ignored */, names_, false); PrintSignatureOneLine(description_, sig, 0 /* ignored */, names_, false);
} }
void FunctionName(uint32_t func_index) { void FunctionName(uint32_t func_index) override {
description_ << func_index << " "; description_ << func_index << " ";
names_->PrintFunctionName(description_, func_index, names_->PrintFunctionName(description_, func_index,
NamesProvider::kDevTools); NamesProvider::kDevTools);
} }
void NextLineIfFull() { void NextLineIfFull() override {
if (queue_ || line_bytes_ >= kPadBytes) NextLine(); if (queue_ || line_bytes_ >= kPadBytes) NextLine();
} }
void NextLineIfNonEmpty() { void NextLineIfNonEmpty() override {
if (queue_ || line_bytes_ > 0) NextLine(); if (queue_ || line_bytes_ > 0) NextLine();
} }
void NextLine() { void NextLine() override {
if (queue_) { if (queue_) {
// Print queued hex bytes first, unless there have also been unqueued // Print queued hex bytes first, unless there have also been unqueued
// bytes. // bytes.
@ -517,45 +516,45 @@ class HexDumpModuleDis {
// We don't care about offsets, but we can use these hooks to provide // We don't care about offsets, but we can use these hooks to provide
// helpful indexing comments in long lists. // helpful indexing comments in long lists.
void TypeOffset(uint32_t offset) { void TypeOffset(uint32_t offset) override {
if (!module_ || module_->types.size() > 3) { if (!module_ || module_->types.size() > 3) {
description_ << "type #" << next_type_index_ << " "; description_ << "type #" << next_type_index_ << " ";
names_->PrintTypeName(description_, next_type_index_); names_->PrintTypeName(description_, next_type_index_);
next_type_index_++; next_type_index_++;
} }
} }
void ImportOffset(uint32_t offset) { void ImportOffset(uint32_t offset) override {
description_ << "import #" << next_import_index_++; description_ << "import #" << next_import_index_++;
NextLine(); NextLine();
} }
void ImportsDone() { void ImportsDone() override {
const WasmModule* module = decoder_->shared_module().get(); const WasmModule* module = decoder_->shared_module().get();
next_table_index_ = static_cast<uint32_t>(module->tables.size()); next_table_index_ = static_cast<uint32_t>(module->tables.size());
next_global_index_ = static_cast<uint32_t>(module->globals.size()); next_global_index_ = static_cast<uint32_t>(module->globals.size());
next_tag_index_ = static_cast<uint32_t>(module->tags.size()); next_tag_index_ = static_cast<uint32_t>(module->tags.size());
} }
void TableOffset(uint32_t offset) { void TableOffset(uint32_t offset) override {
if (!module_ || module_->tables.size() > 3) { if (!module_ || module_->tables.size() > 3) {
description_ << "table #" << next_table_index_++; description_ << "table #" << next_table_index_++;
} }
} }
void MemoryOffset(uint32_t offset) {} void MemoryOffset(uint32_t offset) override {}
void TagOffset(uint32_t offset) { void TagOffset(uint32_t offset) override {
if (!module_ || module_->tags.size() > 3) { if (!module_ || module_->tags.size() > 3) {
description_ << "tag #" << next_tag_index_++ << ":"; description_ << "tag #" << next_tag_index_++ << ":";
} }
} }
void GlobalOffset(uint32_t offset) { void GlobalOffset(uint32_t offset) override {
description_ << "global #" << next_global_index_++ << ":"; description_ << "global #" << next_global_index_++ << ":";
} }
void StartOffset(uint32_t offset) {} void StartOffset(uint32_t offset) override {}
void ElementOffset(uint32_t offset) { void ElementOffset(uint32_t offset) override {
if (!module_ || module_->elem_segments.size() > 3) { if (!module_ || module_->elem_segments.size() > 3) {
description_ << "segment #" << next_segment_index_++; description_ << "segment #" << next_segment_index_++;
NextLine(); NextLine();
} }
} }
void DataOffset(uint32_t offset) { void DataOffset(uint32_t offset) override {
if (!module_ || module_->data_segments.size() > 3) { if (!module_ || module_->data_segments.size() > 3) {
description_ << "data segment #" << next_data_segment_index_++; description_ << "data segment #" << next_data_segment_index_++;
NextLine(); NextLine();
@ -565,7 +564,7 @@ class HexDumpModuleDis {
// The following two hooks give us an opportunity to call the hex-dumping // The following two hooks give us an opportunity to call the hex-dumping
// function body disassembler for initializers and functions. // function body disassembler for initializers and functions.
void InitializerExpression(const byte* start, const byte* end, void InitializerExpression(const byte* start, const byte* end,
ValueType expected_type) { ValueType expected_type) override {
WasmFeatures detected; WasmFeatures detected;
auto sig = FixedSizeSignature<ValueType>::Returns(expected_type); auto sig = FixedSizeSignature<ValueType>::Returns(expected_type);
uint32_t offset = decoder_->pc_offset(); uint32_t offset = decoder_->pc_offset();
@ -577,7 +576,7 @@ class HexDumpModuleDis {
total_bytes_ += static_cast<size_t>(end - start); total_bytes_ += static_cast<size_t>(end - start);
} }
void FunctionBody(const WasmFunction* func, const byte* start) { void FunctionBody(const WasmFunction* func, const byte* start) override {
const byte* end = start + func->code.length(); const byte* end = start + func->code.length();
WasmFeatures detected; WasmFeatures detected;
uint32_t offset = static_cast<uint32_t>(start - decoder_->start()); uint32_t offset = static_cast<uint32_t>(start - decoder_->start());
@ -591,20 +590,21 @@ class HexDumpModuleDis {
// We have to do extra work for the name section here, because the regular // We have to do extra work for the name section here, because the regular
// decoder mostly just skips over it. // decoder mostly just skips over it.
void NameSection(const byte* start, const byte* end, uint32_t offset) { void NameSection(const byte* start, const byte* end,
uint32_t offset) override {
Decoder decoder(start, end, offset); Decoder decoder(start, end, offset);
while (decoder.ok() && decoder.more()) { while (decoder.ok() && decoder.more()) {
uint8_t name_type = decoder.consume_u8("name type: ", *this); uint8_t name_type = decoder.consume_u8("name type: ", this);
Description(NameTypeName(name_type)); Description(NameTypeName(name_type));
NextLine(); NextLine();
uint32_t payload_length = decoder.consume_u32v("payload length:", *this); uint32_t payload_length = decoder.consume_u32v("payload length:", this);
Description(payload_length); Description(payload_length);
NextLine(); NextLine();
if (!decoder.checkAvailable(payload_length)) break; if (!decoder.checkAvailable(payload_length)) break;
switch (name_type) { switch (name_type) {
case kModuleCode: case kModuleCode:
consume_string(&decoder, unibrow::Utf8Variant::kLossyUtf8, consume_string(&decoder, unibrow::Utf8Variant::kLossyUtf8,
"module name", *this); "module name", this);
break; break;
case kFunctionCode: case kFunctionCode:
case kTypeCode: case kTypeCode:
@ -642,34 +642,34 @@ class HexDumpModuleDis {
} }
void DumpNameMap(Decoder& decoder) { void DumpNameMap(Decoder& decoder) {
uint32_t count = decoder.consume_u32v("names count", *this); uint32_t count = decoder.consume_u32v("names count", this);
Description(count); Description(count);
NextLine(); NextLine();
for (uint32_t i = 0; i < count; i++) { for (uint32_t i = 0; i < count; i++) {
uint32_t index = decoder.consume_u32v("index", *this); uint32_t index = decoder.consume_u32v("index", this);
Description(index); Description(index);
Description(" "); Description(" ");
consume_string(&decoder, unibrow::Utf8Variant::kLossyUtf8, "name", *this); consume_string(&decoder, unibrow::Utf8Variant::kLossyUtf8, "name", this);
if (!decoder.ok()) break; if (!decoder.ok()) break;
} }
} }
void DumpIndirectNameMap(Decoder& decoder) { void DumpIndirectNameMap(Decoder& decoder) {
uint32_t outer_count = decoder.consume_u32v("outer count", *this); uint32_t outer_count = decoder.consume_u32v("outer count", this);
Description(outer_count); Description(outer_count);
NextLine(); NextLine();
for (uint32_t i = 0; i < outer_count; i++) { for (uint32_t i = 0; i < outer_count; i++) {
uint32_t outer_index = decoder.consume_u32v("outer index", *this); uint32_t outer_index = decoder.consume_u32v("outer index", this);
Description(outer_index); Description(outer_index);
uint32_t inner_count = decoder.consume_u32v(" inner count", *this); uint32_t inner_count = decoder.consume_u32v(" inner count", this);
Description(inner_count); Description(inner_count);
NextLine(); NextLine();
for (uint32_t j = 0; j < inner_count; j++) { for (uint32_t j = 0; j < inner_count; j++) {
uint32_t inner_index = decoder.consume_u32v("inner index", *this); uint32_t inner_index = decoder.consume_u32v("inner index", this);
Description(inner_index); Description(inner_index);
Description(" "); Description(" ");
consume_string(&decoder, unibrow::Utf8Variant::kLossyUtf8, "name", consume_string(&decoder, unibrow::Utf8Variant::kLossyUtf8, "name",
*this); this);
if (!decoder.ok()) break; if (!decoder.ok()) break;
} }
if (!decoder.ok()) break; if (!decoder.ok()) break;
@ -773,8 +773,7 @@ class FormatConverter {
// 18 = kMinNameLength + strlen(" section: "). // 18 = kMinNameLength + strlen(" section: ").
out_ << std::setw(18) << std::left << "Module size: "; out_ << std::setw(18) << std::left << "Module size: ";
out_ << std::setw(digits) << std::right << module_size << " bytes\n"; out_ << std::setw(digits) << std::right << module_size << " bytes\n";
NoTracer no_tracer; for (WasmSectionIterator it(&decoder, ITracer::NoTrace); it.more();
for (WasmSectionIterator it(&decoder, no_tracer); it.more();
it.advance(true)) { it.advance(true)) {
const char* name = SectionName(it.section_code()); const char* name = SectionName(it.section_code());
size_t name_len = strlen(name); size_t name_len = strlen(name);
@ -796,8 +795,7 @@ class FormatConverter {
Decoder decoder(raw_bytes()); Decoder decoder(raw_bytes());
out_.write(reinterpret_cast<const char*>(decoder.pc()), kModuleHeaderSize); out_.write(reinterpret_cast<const char*>(decoder.pc()), kModuleHeaderSize);
decoder.consume_bytes(kModuleHeaderSize); decoder.consume_bytes(kModuleHeaderSize);
NoTracer no_tracer; for (WasmSectionIterator it(&decoder, ITracer::NoTrace); it.more();
for (WasmSectionIterator it(&decoder, no_tracer); it.more();
it.advance(true)) { it.advance(true)) {
if (it.section_code() == kNameSectionCode) continue; if (it.section_code() == kNameSectionCode) continue;
out_.write(reinterpret_cast<const char*>(it.section_start()), out_.write(reinterpret_cast<const char*>(it.section_start()),
@ -1054,6 +1052,11 @@ class FormatConverter {
std::unique_ptr<NamesProvider> names_provider_; std::unique_ptr<NamesProvider> names_provider_;
}; };
DumpingModuleDecoder::DumpingModuleDecoder(ModuleWireBytes wire_bytes,
HexDumpModuleDis* module_dis)
: ModuleDecoderBase(WasmFeatures::All(), wire_bytes.module_bytes(),
kWasmOrigin, module_dis) {}
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8