[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.
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 buffer of bytes.
class Decoder {
@ -189,10 +231,11 @@ class Decoder {
uint8_t consume_u8(const char* name = "uint8_t") {
return consume_little_endian<uint8_t, kTrace>(name);
}
template <class Tracer>
uint8_t consume_u8(const char* name, Tracer& tracer) {
tracer.Bytes(pc_, sizeof(uint8_t));
tracer.Description(name);
uint8_t consume_u8(const char* name, ITracer* tracer) {
if (tracer) {
tracer->Bytes(pc_, sizeof(uint8_t));
tracer->Description(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_}.
template <class Tracer>
uint32_t consume_u32(const char* name, Tracer& tracer) {
tracer.Bytes(pc_, sizeof(uint32_t));
tracer.Description(name);
uint32_t consume_u32(const char* name, ITracer* tracer) {
if (tracer) {
tracer->Bytes(pc_, sizeof(uint32_t));
tracer->Description(name);
}
return consume_little_endian<uint32_t, kNoTrace>(name);
}
@ -217,13 +261,14 @@ class Decoder {
pc_ += length;
return result;
}
template <class Tracer>
uint32_t consume_u32v(const char* name, Tracer& tracer) {
uint32_t consume_u32v(const char* name, ITracer* tracer) {
uint32_t length = 0;
uint32_t result =
read_leb<uint32_t, FullValidationTag, kNoTrace>(pc_, &length, name);
tracer.Bytes(pc_, length);
tracer.Description(name);
if (tracer) {
tracer->Bytes(pc_, length);
tracer->Description(name);
}
pc_ += length;
return result;
}
@ -238,13 +283,14 @@ class Decoder {
}
// Reads a LEB128 variable-length unsigned 64-bit integer and advances {pc_}.
template <class Tracer>
uint64_t consume_u64v(const char* name, Tracer& tracer) {
uint64_t consume_u64v(const char* name, ITracer* tracer) {
uint32_t length = 0;
uint64_t result =
read_leb<uint64_t, FullValidationTag, kNoTrace>(pc_, &length, name);
tracer.Bytes(pc_, length);
tracer.Description(name);
if (tracer) {
tracer->Bytes(pc_, length);
tracer->Description(name);
}
pc_ += length;
return result;
}
@ -268,10 +314,11 @@ class Decoder {
pc_ = end_;
}
}
template <class Tracer>
void consume_bytes(uint32_t size, const char* name, Tracer& tracer) {
tracer.Bytes(pc_, size);
tracer.Description(name);
void consume_bytes(uint32_t size, const char* name, ITracer* tracer) {
if (tracer) {
tracer->Bytes(pc_, size);
tracer->Description(name);
}
consume_bytes(size, nullptr);
}

View File

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

View File

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

View File

@ -566,7 +566,7 @@ uint32_t FunctionBodyDisassembler::PrintImmediatesAndGetLength(
////////////////////////////////////////////////////////////////////////////////
// OffsetsProvider.
class OffsetsProvider {
class OffsetsProvider : public ITracer {
public:
OffsetsProvider() = default;
@ -583,50 +583,58 @@ class OffsetsProvider {
element_offsets_.reserve(module->elem_segments.size());
data_offsets_.reserve(module->data_segments.size());
using OffsetsCollectingDecoder = ModuleDecoderTemplate<OffsetsProvider>;
OffsetsCollectingDecoder decoder{WasmFeatures::All(), wire_bytes,
kWasmOrigin, *this};
ModuleDecoderBase decoder{WasmFeatures::All(), wire_bytes, kWasmOrigin,
this};
constexpr bool kNoVerifyFunctions = false;
decoder.DecodeModule(kNoVerifyFunctions);
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:
void ImportsDone() {}
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 ImportsDone() override {}
void Bytes(const byte* start, uint32_t count) override {}
void Description(const char* desc) override {}
void Description(const char* desc, size_t length) override {}
void Description(uint32_t number) override {}
void Description(ValueType type) override {}
void Description(HeapType type) override {}
void Description(const FunctionSig* sig) override {}
void NextLine() override {}
void NextLineIfFull() override {}
void NextLineIfNonEmpty() override {}
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) {}
ValueType expected_type) override {}
void FunctionBody(const WasmFunction* func, const byte* start) override {}
void FunctionName(uint32_t func_index) override {}
void NameSection(const byte* start, const byte* end,
uint32_t offset) override {}
#define GETTER(name) \
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,
uint32_t offset) override {
Decoder decoder(bytes.begin(), bytes.end());
NoTracer no_tracer;
uint32_t magic_word = decoder.consume_u32("wasm magic", no_tracer);
uint32_t magic_word = decoder.consume_u32("wasm magic", ITracer::NoTrace);
if (decoder.failed() || magic_word != kWasmMagic) {
result_->error = WasmError(0, "expected wasm magic");
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) {
result_->error = WasmError(4, "expected wasm version");
return false;

View File

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