diff options
author | Yuri Iozzelli <y.iozzelli@gmail.com> | 2022-02-25 16:36:35 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-25 15:36:35 +0000 |
commit | 1f59b65d8befc8512ff9045bb371ea5ec379a78c (patch) | |
tree | 349621c048c7716a746d3361c8ec6219d32f0250 | |
parent | 08cf71aa180674432750a02581f1e214c310042d (diff) | |
download | wabt-1f59b65d8befc8512ff9045bb371ea5ec379a78c.tar.gz wabt-1f59b65d8befc8512ff9045bb371ea5ec379a78c.tar.bz2 wabt-1f59b65d8befc8512ff9045bb371ea5ec379a78c.zip |
Add initial support for code metadata (#1840)
See https://github.com/WebAssembly/tool-conventions/blob/main/CodeMetadata.md for the specification.
In particular this pr implements the following:
- Parsing code metadata sections in BinaryReader, providing appropriate callbacks that a BinaryReaderDelegate can implement:
- BinaryReaderObjdump: show the sections in a human-readable form
- BinaryReaderIr: add code metadata in the IR as expressions
- Parsing code metadata annotations in text format, adding them in the IR like the BinaryReaderIR does
- Writing the code metadata present in the IR in the proper sections when converting IR to binary
- Support in wasm-decompiler for showing code metadata as comments in the pseudo-code
All the features have corresponding tests.
Support for code metadata is gated through the --enable-code-metadata feature. For reading/writing in the text format, --enable-annotations is also required.
Missing features:
Support for function-level code metadata (offset 0)
Extensive validation in validator.cc (like making sure that all metadata instances are at the same code offset of an instruction)
41 files changed, 1032 insertions, 6 deletions
diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index fbb1b091..ff3eafab 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -21,6 +21,7 @@ #include <cstdarg> #include <cstdint> #include <cstdio> +#include <deque> #include <vector> #include "src/binary-reader-nop.h" @@ -43,6 +44,52 @@ struct LabelNode { LabelNode::LabelNode(LabelType label_type, ExprList* exprs, Expr* context) : label_type(label_type), exprs(exprs), context(context) {} +class CodeMetadataExprQueue { + private: + struct Entry { + Func* func; + std::deque<std::unique_ptr<CodeMetadataExpr>> func_queue; + Entry(Func* f) : func(f) {} + }; + std::deque<Entry> entries; + + public: + CodeMetadataExprQueue() {} + void push_func(Func* f) { entries.emplace_back(f); } + void push_metadata(std::unique_ptr<CodeMetadataExpr> meta) { + assert(!entries.empty()); + entries.back().func_queue.push_back(std::move(meta)); + } + + std::unique_ptr<CodeMetadataExpr> pop_match(Func* f, Offset offset) { + std::unique_ptr<CodeMetadataExpr> ret; + if (entries.empty()) { + return ret; + } + + auto& current_entry = entries.front(); + + if (current_entry.func != f) + return ret; + if (current_entry.func_queue.empty()) { + entries.pop_front(); + return ret; + } + + auto& current_metadata = current_entry.func_queue.front(); + if (current_metadata->loc.offset + current_entry.func->loc.offset != + offset) { + return ret; + } + + current_metadata->loc = Location(offset); + ret = std::move(current_metadata); + current_entry.func_queue.pop_front(); + + return ret; + } +}; + class BinaryReaderIR : public BinaryReaderNop { public: BinaryReaderIR(Module* out_module, const char* filename, Errors* errors); @@ -115,6 +162,7 @@ class BinaryReaderIR : public BinaryReaderNop { Result BeginFunctionBody(Index index, Offset size) override; Result OnLocalDecl(Index decl_index, Index count, Type type) override; + Result OnOpcode(Opcode opcode) override; Result OnAtomicLoadExpr(Opcode opcode, Address alignment_log2, Address offset) override; @@ -276,6 +324,12 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnSectionSymbol(Index index, uint32_t flags, Index section_index) override; + /* Code Metadata sections */ + Result BeginCodeMetadataSection(std::string_view name, Offset size) override; + Result OnCodeMetadataFuncCount(Index count) override; + Result OnCodeMetadataCount(Index function_index, Index count) override; + Result OnCodeMetadata(Offset offset, const void* data, Address size) override; + Result OnTagSymbol(Index index, uint32_t flags, std::string_view name, @@ -318,6 +372,9 @@ class BinaryReaderIR : public BinaryReaderNop { Func* current_func_ = nullptr; std::vector<LabelNode> label_stack_; const char* filename_; + + CodeMetadataExprQueue code_metadata_queue_; + std::string_view current_metadata_name_; }; BinaryReaderIR::BinaryReaderIR(Module* out_module, @@ -660,6 +717,7 @@ Result BinaryReaderIR::OnFunctionBodyCount(Index count) { Result BinaryReaderIR::BeginFunctionBody(Index index, Offset size) { current_func_ = module_->funcs[index]; + current_func_->loc = GetLocation(); PushLabel(LabelType::Func, ¤t_func_->exprs); return Result::Ok; } @@ -669,6 +727,15 @@ Result BinaryReaderIR::OnLocalDecl(Index decl_index, Index count, Type type) { return Result::Ok; } +Result BinaryReaderIR::OnOpcode(Opcode opcode) { + std::unique_ptr<CodeMetadataExpr> metadata = + code_metadata_queue_.pop_match(current_func_, GetLocation().offset - 1); + if (metadata) { + return AppendExpr(std::move(metadata)); + } + return Result::Ok; +} + Result BinaryReaderIR::OnAtomicLoadExpr(Opcode opcode, Address alignment_log2, Address offset) { @@ -1447,6 +1514,33 @@ Result BinaryReaderIR::OnLocalNameLocalCount(Index index, Index count) { return Result::Ok; } +Result BinaryReaderIR::BeginCodeMetadataSection(std::string_view name, + Offset size) { + current_metadata_name_ = name; + return Result::Ok; +} + +Result BinaryReaderIR::OnCodeMetadataFuncCount(Index count) { + return Result::Ok; +} + +Result BinaryReaderIR::OnCodeMetadataCount(Index function_index, Index count) { + code_metadata_queue_.push_func(module_->funcs[function_index]); + return Result::Ok; +} + +Result BinaryReaderIR::OnCodeMetadata(Offset offset, + const void* data, + Address size) { + std::vector<uint8_t> data_(static_cast<const uint8_t*>(data), + static_cast<const uint8_t*>(data) + size); + auto meta = + MakeUnique<CodeMetadataExpr>(current_metadata_name_, std::move(data_)); + meta->loc.offset = offset; + code_metadata_queue_.push_metadata(std::move(meta)); + return Result::Ok; +} + Result BinaryReaderIR::OnLocalName(Index func_index, Index local_index, std::string_view name) { diff --git a/src/binary-reader-logging.cc b/src/binary-reader-logging.cc index 2e7cb41c..13c68852 100644 --- a/src/binary-reader-logging.cc +++ b/src/binary-reader-logging.cc @@ -638,6 +638,22 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) { return reader_->OnComdatEntry(kind, index); } +Result BinaryReaderLogging::BeginCodeMetadataSection(std::string_view name, + Offset size) { + LOGF("BeginCodeMetadataSection('" PRIstringview "', size:%" PRIzd ")\n", + WABT_PRINTF_STRING_VIEW_ARG(name), size); + Indent(); + return reader_->BeginCodeMetadataSection(name, size); +} +Result BinaryReaderLogging::OnCodeMetadata(Offset code_offset, + const void* data, + Address size) { + std::string_view content(static_cast<const char*>(data), size); + LOGF("OnCodeMetadata(offset: %" PRIzd ", data: \"" PRIstringview "\")\n", + code_offset, WABT_PRINTF_STRING_VIEW_ARG(content)); + return reader_->OnCodeMetadata(code_offset, data, size); +} + #define DEFINE_BEGIN(name) \ Result BinaryReaderLogging::name(Offset size) { \ LOGF(#name "(%" PRIzd ")\n", size); \ @@ -892,6 +908,10 @@ DEFINE_INDEX(OnTagCount); DEFINE_INDEX_INDEX(OnTagType, "index", "sig_index") DEFINE_END(EndTagSection); +DEFINE_INDEX(OnCodeMetadataFuncCount); +DEFINE_INDEX_INDEX(OnCodeMetadataCount, "func_index", "count"); +DEFINE_END(EndCodeMetadataSection); + // We don't need to log these (the individual opcodes are logged instead), but // we still need to forward the calls. Result BinaryReaderLogging::OnOpcode(Opcode opcode) { diff --git a/src/binary-reader-logging.h b/src/binary-reader-logging.h index 740da63f..51cd5985 100644 --- a/src/binary-reader-logging.h +++ b/src/binary-reader-logging.h @@ -386,6 +386,13 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnTagType(Index index, Index sig_index) override; Result EndTagSection() override; + /* Code Metadata sections */ + Result BeginCodeMetadataSection(std::string_view name, Offset size) override; + Result OnCodeMetadataFuncCount(Index count) override; + Result OnCodeMetadataCount(Index function_index, Index count) override; + Result OnCodeMetadata(Offset offset, const void* data, Address size) override; + Result EndCodeMetadataSection() override; + private: void Indent(); void Dedent(); diff --git a/src/binary-reader-nop.h b/src/binary-reader-nop.h index 4adde26a..ff78aa7f 100644 --- a/src/binary-reader-nop.h +++ b/src/binary-reader-nop.h @@ -462,6 +462,21 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnTagType(Index index, Index sig_index) override { return Result::Ok; } Result EndTagSection() override { return Result::Ok; } + /* Code Metadata sections */ + Result BeginCodeMetadataSection(std::string_view name, Offset size) override { + return Result::Ok; + } + Result OnCodeMetadataFuncCount(Index count) override { return Result::Ok; } + Result OnCodeMetadataCount(Index function_index, Index count) override { + return Result::Ok; + } + Result OnCodeMetadata(Offset offset, + const void* data, + Address size) override { + return Result::Ok; + } + Result EndCodeMetadataSection() override { return Result::Ok; } + /* Dylink section */ Result BeginDylinkSection(Offset size) override { return Result::Ok; } Result OnDylinkInfo(uint32_t mem_size, diff --git a/src/binary-reader-objdump.cc b/src/binary-reader-objdump.cc index deb1167f..cb682698 100644 --- a/src/binary-reader-objdump.cc +++ b/src/binary-reader-objdump.cc @@ -1139,6 +1139,10 @@ class BinaryReaderObjdump : public BinaryReaderObjdumpBase { Result OnF32ConstExpr(uint32_t value) override; Result OnF64ConstExpr(uint64_t value) override; Result OnGlobalGetExpr(Index global_index) override; + Result OnCodeMetadataCount(Index function_index, Index count) override; + Result OnCodeMetadata(Offset code_offset, + const void* data, + Address size) override; private: Result InitExprToConstOffset(const InitExpr& expr, uint64_t* out_offset); @@ -2192,6 +2196,31 @@ Result BinaryReaderObjdump::OnTagType(Index index, Index sig_index) { return Result::Ok; } +Result BinaryReaderObjdump::OnCodeMetadataCount(Index function_index, + Index count) { + if (!ShouldPrintDetails()) { + return Result::Ok; + } + printf(" - func[%" PRIindex "]", function_index); + auto name = GetFunctionName(function_index); + if (!name.empty()) { + printf(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + printf(":\n"); + return Result::Ok; +} +Result BinaryReaderObjdump::OnCodeMetadata(Offset code_offset, + const void* data, + Address size) { + if (!ShouldPrintDetails()) { + return Result::Ok; + } + printf(" - meta[%" PRIzx "]:\n", code_offset); + + out_stream_->WriteMemoryDump(data, size, 0, PrintChars::Yes, " - "); + return Result::Ok; +} + } // end anonymous namespace std::string_view ObjdumpNames::Get(Index index) const { diff --git a/src/binary-reader.cc b/src/binary-reader.cc index 0cef458d..28f47b64 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -140,6 +140,8 @@ class BinaryReader { Result ReadDylink0Section(Offset section_size) WABT_WARN_UNUSED; Result ReadTargetFeaturesSections(Offset section_size) WABT_WARN_UNUSED; Result ReadLinkingSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadCodeMetadataSection(std::string_view name, + Offset section_size) WABT_WARN_UNUSED; Result ReadCustomSection(Index section_index, Offset section_size) WABT_WARN_UNUSED; Result ReadTypeSection(Offset section_size) WABT_WARN_UNUSED; @@ -2258,6 +2260,57 @@ Result BinaryReader::ReadTagSection(Offset section_size) { return Result::Ok; } +Result BinaryReader::ReadCodeMetadataSection(std::string_view name, + Offset section_size) { + CALLBACK(BeginCodeMetadataSection, name, section_size); + + Index num_funcions; + CHECK_RESULT(ReadCount(&num_funcions, "function count")); + CALLBACK(OnCodeMetadataFuncCount, num_funcions); + + Index last_function_index = kInvalidIndex; + for (Index i = 0; i < num_funcions; ++i) { + Index function_index; + CHECK_RESULT(ReadCount(&function_index, "function index")); + ERROR_UNLESS(function_index >= num_func_imports_, + "function import can't have metadata (got %" PRIindex ")", + function_index); + ERROR_UNLESS(function_index < NumTotalFuncs(), + "invalid function index: %" PRIindex, function_index); + ERROR_UNLESS(function_index != last_function_index, + "duplicate function index: %" PRIindex, function_index); + ERROR_UNLESS(last_function_index == kInvalidIndex || + function_index > last_function_index, + "function index out of order: %" PRIindex, function_index); + last_function_index = function_index; + + Index num_metadata; + CHECK_RESULT(ReadCount(&num_metadata, "metadata instances count")); + + CALLBACK(OnCodeMetadataCount, function_index, num_metadata); + + Offset last_code_offset = kInvalidOffset; + for (Index j = 0; j < num_metadata; ++j) { + Offset code_offset; + CHECK_RESULT(ReadOffset(&code_offset, "code offset")); + ERROR_UNLESS(code_offset != last_code_offset, + "duplicate code offset: %" PRIzx, code_offset); + ERROR_UNLESS( + last_code_offset == kInvalidOffset || code_offset > last_code_offset, + "code offset out of order: %" PRIzx, code_offset); + last_code_offset = code_offset; + + Address data_size; + const void* data; + CHECK_RESULT(ReadBytes(&data, &data_size, "instance data")); + CALLBACK(OnCodeMetadata, code_offset, data, data_size); + } + } + + CALLBACK(EndCodeMetadataSection); + return Result::Ok; +} + Result BinaryReader::ReadCustomSection(Index section_index, Offset section_size) { std::string_view section_name; @@ -2280,6 +2333,11 @@ Result BinaryReader::ReadCustomSection(Index section_index, CHECK_RESULT(ReadTargetFeaturesSections(section_size)); } else if (section_name == WABT_BINARY_SECTION_LINKING) { CHECK_RESULT(ReadLinkingSection(section_size)); + } else if (options_.features.code_metadata_enabled() && + section_name.find(WABT_BINARY_SECTION_CODE_METADATA) == 0) { + std::string_view metadata_name = section_name; + metadata_name.remove_prefix(sizeof(WABT_BINARY_SECTION_CODE_METADATA) - 1); + CHECK_RESULT(ReadCodeMetadataSection(metadata_name, section_size)); } else { // This is an unknown custom section, skip it. state_.offset = read_end_; diff --git a/src/binary-reader.h b/src/binary-reader.h index 978ce2f5..4e068ecb 100644 --- a/src/binary-reader.h +++ b/src/binary-reader.h @@ -461,6 +461,16 @@ class BinaryReaderDelegate { virtual Result OnTagType(Index index, Index sig_index) = 0; virtual Result EndTagSection() = 0; + /* Code Metadata sections */ + virtual Result BeginCodeMetadataSection(std::string_view name, + Offset size) = 0; + virtual Result OnCodeMetadataFuncCount(Index count) = 0; + virtual Result OnCodeMetadataCount(Index function_index, Index count) = 0; + virtual Result OnCodeMetadata(Offset offset, + const void* data, + Address size) = 0; + virtual Result EndCodeMetadataSection() = 0; + const State* state = nullptr; }; diff --git a/src/binary-writer.cc b/src/binary-writer.cc index 76d0b765..00beede6 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -29,6 +29,7 @@ #include "src/binary.h" #include "src/cast.h" +#include "src/expr-visitor.h" #include "src/ir.h" #include "src/leb128.h" #include "src/stream.h" @@ -355,6 +356,23 @@ class SymbolTable { } }; +struct CodeMetadata { + Offset offset; + std::vector<uint8_t> data; + CodeMetadata(Offset offset, std::vector<uint8_t> data) + : offset(offset), data(std::move(data)) {} +}; +struct FuncCodeMetadata { + Index func_idx; + std::vector<CodeMetadata> entries; + FuncCodeMetadata(Index func_idx) : func_idx(func_idx) {} +}; +struct CodeMetadataSection { + std::vector<FuncCodeMetadata> entries; +}; +typedef std::unordered_map<std::string_view, CodeMetadataSection> + CodeMetadataSections; + class BinaryWriter { WABT_DISALLOW_COPY_AND_ASSIGN(BinaryWriter); @@ -413,6 +431,7 @@ class BinaryWriter { void WriteLinkingSection(); template <typename T> void WriteNames(const std::vector<T*>& elems, NameSectionSubsection type); + void WriteCodeMetadataSections(); Stream* stream_; const WriteBinaryOptions& options_; @@ -438,6 +457,10 @@ class BinaryWriter { size_t data_count_start_ = 0; size_t data_count_end_ = 0; bool has_data_segment_instruction_ = false; + + CodeMetadataSections code_metadata_sections_; + Offset cur_func_start_offset_; + Index cur_func_index_; }; static uint8_t log2_u32(uint32_t x) { @@ -1105,6 +1128,17 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { case ExprType::Unreachable: WriteOpcode(stream_, Opcode::Unreachable); break; + case ExprType::CodeMetadata: { + auto* meta_expr = cast<CodeMetadataExpr>(expr); + auto& s = code_metadata_sections_[meta_expr->name]; + if (s.entries.empty() || s.entries.back().func_idx != cur_func_index_) { + s.entries.emplace_back(cur_func_index_); + } + auto& a = s.entries.back(); + Offset code_offset = stream_->offset() - cur_func_start_offset_; + a.entries.emplace_back(code_offset, meta_expr->data); + break; + } } } @@ -1575,13 +1609,15 @@ Result BinaryWriter::WriteModule() { WriteU32Leb128(stream_, num_funcs, "num functions"); for (size_t i = 0; i < num_funcs; ++i) { + cur_func_index_ = i + module_->num_func_imports; WriteHeader("function body", i); - const Func* func = module_->funcs[i + module_->num_func_imports]; + const Func* func = module_->funcs[cur_func_index_]; /* TODO(binji): better guess of the size of the function body section */ const Offset leb_size_guess = 1; Offset body_size_offset = WriteU32Leb128Space(leb_size_guess, "func body size (guess)"); + cur_func_start_offset_ = stream_->offset(); WriteFunc(func); auto func_start_offset = body_size_offset - last_section_payload_offset_; auto func_end_offset = stream_->offset() - last_section_payload_offset_; @@ -1610,6 +1646,7 @@ Result BinaryWriter::WriteModule() { assert(data_count_end_ == code_start_); assert(last_section_type_ == BinarySection::Code); stream_->MoveData(data_count_start_, data_count_end_, size); + code_start_ = data_count_start_; } stream_->Truncate(data_count_start_ + size); @@ -1625,6 +1662,8 @@ Result BinaryWriter::WriteModule() { } } + WriteCodeMetadataSections(); + if (module_->data_segments.size()) { BeginKnownSection(BinarySection::Data); WriteU32Leb128(stream_, module_->data_segments.size(), "num data segments"); @@ -1719,6 +1758,53 @@ Result BinaryWriter::WriteModule() { return stream_->result(); } +void BinaryWriter::WriteCodeMetadataSections() { + if (code_metadata_sections_.empty()) + return; + + section_count_ -= 1; + // We have to increment the code section's index; adjust anything + // that might have captured it. + for (RelocSection& section : reloc_sections_) { + if (section.section_index == section_count_) { + assert(last_section_type_ == BinarySection::Code); + section.section_index += code_metadata_sections_.size(); + } + } + + MemoryStream tmp_stream; + Stream* main_stream = stream_; + stream_ = &tmp_stream; + for (auto& s : code_metadata_sections_) { + std::string name = "metadata.code."; + name.append(s.first); + auto& section = s.second; + BeginCustomSection(name.c_str()); + WriteU32Leb128(stream_, section.entries.size(), "function count"); + for (auto& f : section.entries) { + WriteU32Leb128WithReloc(f.func_idx, "function index", + RelocType::FuncIndexLEB); + WriteU32Leb128(stream_, f.entries.size(), "instances count"); + for (auto& a : f.entries) { + WriteU32Leb128(stream_, a.offset, "code offset"); + WriteU32Leb128(stream_, a.data.size(), "data length"); + stream_->WriteData(a.data.data(), a.data.size(), "data", + PrintChars::Yes); + } + } + EndSection(); + } + stream_ = main_stream; + auto buf = tmp_stream.ReleaseOutputBuffer(); + stream_->MoveData(code_start_ + buf->data.size(), code_start_, + stream_->offset() - code_start_); + stream_->WriteDataAt(code_start_, buf->data.data(), buf->data.size()); + stream_->AddOffset(buf->data.size()); + code_start_ += buf->data.size(); + section_count_ += 1; + last_section_type_ = BinarySection::Code; +} + } // end anonymous namespace Result WriteBinaryModule(Stream* stream, diff --git a/src/binary.h b/src/binary.h index bd0a3de7..39e0f201 100644 --- a/src/binary.h +++ b/src/binary.h @@ -34,6 +34,7 @@ #define WABT_BINARY_SECTION_TARGET_FEATURES "target_features" #define WABT_BINARY_SECTION_DYLINK "dylink" #define WABT_BINARY_SECTION_DYLINK0 "dylink.0" +#define WABT_BINARY_SECTION_CODE_METADATA "metadata.code." #define WABT_FOREACH_BINARY_SECTION(V) \ V(Custom, custom, 0) \ diff --git a/src/c-writer.cc b/src/c-writer.cc index c1336671..388d8168 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1498,6 +1498,9 @@ void CWriter::Write(const ExprList& exprs) { break; } + case ExprType::CodeMetadata: + break; + case ExprType::Compare: Write(*cast<CompareExpr>(&expr)); break; diff --git a/src/decompiler.cc b/src/decompiler.cc index 1ddaedc3..91272301 100644 --- a/src/decompiler.cc +++ b/src/decompiler.cc @@ -604,6 +604,12 @@ struct Decompiler { ts += "]("; return WrapChild(args[0], ts, ")", Precedence::Atomic); } + case ExprType::CodeMetadata: { + auto cme = cast<CodeMetadataExpr>(n.e); + std::string c = "// @metadata.code." + cme->name + " "; + c += BinaryToString(cme->data); + return Value{{std::move(c)}, Precedence::None}; + } default: { // Everything that looks like a function call. std::string name; diff --git a/src/expr-visitor.cc b/src/expr-visitor.cc index d346f3b7..e7fee9bf 100644 --- a/src/expr-visitor.cc +++ b/src/expr-visitor.cc @@ -219,6 +219,10 @@ Result ExprVisitor::HandleDefaultState(Expr* expr) { CHECK_RESULT(delegate_->OnCallRefExpr(cast<CallRefExpr>(expr))); break; + case ExprType::CodeMetadata: + CHECK_RESULT(delegate_->OnCodeMetadataExpr(cast<CodeMetadataExpr>(expr))); + break; + case ExprType::Compare: CHECK_RESULT(delegate_->OnCompareExpr(cast<CompareExpr>(expr))); break; diff --git a/src/expr-visitor.h b/src/expr-visitor.h index ab7dc9e4..e00c487d 100644 --- a/src/expr-visitor.h +++ b/src/expr-visitor.h @@ -76,6 +76,7 @@ class ExprVisitor::Delegate { virtual Result OnCallExpr(CallExpr*) = 0; virtual Result OnCallIndirectExpr(CallIndirectExpr*) = 0; virtual Result OnCallRefExpr(CallRefExpr*) = 0; + virtual Result OnCodeMetadataExpr(CodeMetadataExpr*) = 0; virtual Result OnCompareExpr(CompareExpr*) = 0; virtual Result OnConstExpr(ConstExpr*) = 0; virtual Result OnConvertExpr(ConvertExpr*) = 0; @@ -149,6 +150,7 @@ class ExprVisitor::DelegateNop : public ExprVisitor::Delegate { Result OnCallExpr(CallExpr*) override { return Result::Ok; } Result OnCallIndirectExpr(CallIndirectExpr*) override { return Result::Ok; } Result OnCallRefExpr(CallRefExpr*) override { return Result::Ok; } + Result OnCodeMetadataExpr(CodeMetadataExpr*) override { return Result::Ok; } Result OnCompareExpr(CompareExpr*) override { return Result::Ok; } Result OnConstExpr(ConstExpr*) override { return Result::Ok; } Result OnConvertExpr(ConvertExpr*) override { return Result::Ok; } diff --git a/src/feature.def b/src/feature.def index 63f920df..26b1db79 100644 --- a/src/feature.def +++ b/src/feature.def @@ -34,6 +34,7 @@ WABT_FEATURE(tail_call, "tail-call", false, "Tail-call WABT_FEATURE(bulk_memory, "bulk-memory", true, "Bulk-memory operations") WABT_FEATURE(reference_types, "reference-types", true, "Reference types (externref)") WABT_FEATURE(annotations, "annotations", false, "Custom annotation syntax") +WABT_FEATURE(code_metadata, "code-metadata", false, "Code metadata") WABT_FEATURE(gc, "gc", false, "Garbage collection") WABT_FEATURE(memory64, "memory64", false, "64-bit memory") WABT_FEATURE(multi_memory, "multi-memory", false, "Multi-memory") diff --git a/src/ir-util.cc b/src/ir-util.cc index 959f0937..099ee8c3 100644 --- a/src/ir-util.cc +++ b/src/ir-util.cc @@ -165,6 +165,7 @@ ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const { case ExprType::DataDrop: case ExprType::ElemDrop: case ExprType::AtomicFence: + case ExprType::CodeMetadata: return {0, 0}; case ExprType::MemoryInit: @@ -40,6 +40,7 @@ const char* ExprTypeName[] = { "Call", "CallIndirect", "CallRef", + "CodeMetadata", "Compare", "Const", "Convert", @@ -320,6 +320,7 @@ enum class ExprType { Call, CallIndirect, CallRef, + CodeMetadata, Compare, Const, Convert, @@ -631,6 +632,19 @@ class CallIndirectExpr : public ExprMixin<ExprType::CallIndirect> { Var table; }; +class CodeMetadataExpr : public ExprMixin<ExprType::CodeMetadata> { + public: + explicit CodeMetadataExpr(std::string_view name, + std::vector<uint8_t> data, + const Location& loc = Location()) + : ExprMixin<ExprType::CodeMetadata>(loc), + name(std::move(name)), + data(std::move(data)) {} + + std::string_view name; + std::vector<uint8_t> data; +}; + class ReturnCallIndirectExpr : public ExprMixin<ExprType::ReturnCallIndirect> { public: explicit ReturnCallIndirectExpr(const Location& loc = Location()) @@ -846,6 +860,7 @@ struct Func { LocalTypes local_types; BindingHash bindings; ExprList exprs; + Location loc; }; struct Global { diff --git a/src/validator.cc b/src/validator.cc index f662b3b0..b3f231bd 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -94,6 +94,7 @@ class Validator : public ExprVisitor::Delegate { Result OnCallExpr(CallExpr*) override; Result OnCallIndirectExpr(CallIndirectExpr*) override; Result OnCallRefExpr(CallRefExpr*) override; + Result OnCodeMetadataExpr(CodeMetadataExpr*) override; Result OnCompareExpr(CompareExpr*) override; Result OnConstExpr(ConstExpr*) override; Result OnConvertExpr(ConvertExpr*) override; @@ -286,6 +287,10 @@ Result Validator::OnCallRefExpr(CallRefExpr* expr) { return Result::Error; } +Result Validator::OnCodeMetadataExpr(CodeMetadataExpr* expr) { + return Result::Ok; +} + Result Validator::OnCompareExpr(CompareExpr* expr) { result_ |= validator_.OnCompare(expr->loc, expr->opcode); return Result::Ok; diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 99406786..f07ee8b1 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -194,6 +194,10 @@ bool IsInstr(TokenTypePair pair) { return IsPlainOrBlockInstr(pair[0]) || IsExpr(pair); } +bool IsLparAnn(TokenTypePair pair) { + return pair[0] == TokenType::LparAnn; +} + bool IsCatch(TokenType token_type) { return token_type == TokenType::Catch || token_type == TokenType::CatchAll; } @@ -551,12 +555,18 @@ TokenType WastParser::Peek(size_t n) { if (cur.token_type() != TokenType::LparAnn) { tokens_.push_back(cur); } else { - // Custom annotation. For now, discard until matching Rpar. + // Custom annotation. For now, discard until matching Rpar, unless it is + // a code metadata annotation. In that case, we know how to parse it. if (!options_->features.annotations_enabled()) { Error(cur.loc, "annotations not enabled: %s", cur.to_string().c_str()); tokens_.push_back(Token(cur.loc, TokenType::Invalid)); continue; } + if (options_->features.code_metadata_enabled() && + cur.text().find("metadata.code.") == 0) { + tokens_.push_back(cur); + continue; + } int indent = 1; while (indent > 0) { cur = lexer_->GetToken(this); @@ -1826,11 +1836,22 @@ Result WastParser::ParseResultList( Result WastParser::ParseInstrList(ExprList* exprs) { WABT_TRACE(ParseInstrList); ExprList new_exprs; - while (IsInstr(PeekPair())) { - if (Succeeded(ParseInstr(&new_exprs))) { - exprs->splice(exprs->end(), new_exprs); + while (true) { + auto pair = PeekPair(); + if (IsInstr(pair)) { + if (Succeeded(ParseInstr(&new_exprs))) { + exprs->splice(exprs->end(), new_exprs); + } else { + CHECK_RESULT(Synchronize(IsInstr)); + } + } else if (IsLparAnn(pair)) { + if (Succeeded(ParseCodeMetadataAnnotation(&new_exprs))) { + exprs->splice(exprs->end(), new_exprs); + } else { + CHECK_RESULT(Synchronize(IsLparAnn)); + } } else { - CHECK_RESULT(Synchronize(IsInstr)); + break; } } return Result::Ok; @@ -1866,6 +1887,21 @@ Result WastParser::ParseInstr(ExprList* exprs) { } } +Result WastParser::ParseCodeMetadataAnnotation(ExprList* exprs) { + WABT_TRACE(ParseCodeMetadataAnnotation); + Token tk = Consume(); + std::string_view name = tk.text(); + name.remove_prefix(sizeof("metadata.code.") - 1); + std::string data_text; + CHECK_RESULT(ParseQuotedText(&data_text)); + std::vector<uint8_t> data(data_text.begin(), data_text.end()); + exprs->push_back(MakeUnique<CodeMetadataExpr>(name, std::move(data))); + TokenType rpar = Peek(); + assert(rpar == TokenType::Rpar); + Consume(); + return Result::Ok; +} + template <typename T> Result WastParser::ParsePlainInstrVar(Location loc, std::unique_ptr<Expr>* out_expr) { diff --git a/src/wast-parser.h b/src/wast-parser.h index 8c799b7f..b3ac652f 100644 --- a/src/wast-parser.h +++ b/src/wast-parser.h @@ -181,6 +181,7 @@ class WastParser { Result ParseInstrList(ExprList*); Result ParseTerminatingInstrList(ExprList*); Result ParseInstr(ExprList*); + Result ParseCodeMetadataAnnotation(ExprList*); Result ParsePlainInstr(std::unique_ptr<Expr>*); Result ParseF32(Const*, ConstType type); Result ParseF64(Const*, ConstType type); diff --git a/src/wat-writer.cc b/src/wat-writer.cc index fd4a5f43..45350e08 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -557,6 +557,7 @@ class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate { Result OnCallExpr(CallExpr*) override; Result OnCallIndirectExpr(CallIndirectExpr*) override; Result OnCallRefExpr(CallRefExpr*) override; + Result OnCodeMetadataExpr(CodeMetadataExpr*) override; Result OnCompareExpr(CompareExpr*) override; Result OnConstExpr(ConstExpr*) override; Result OnConvertExpr(ConvertExpr*) override; @@ -680,6 +681,16 @@ Result WatWriter::ExprVisitorDelegate::OnCallRefExpr(CallRefExpr* expr) { return Result::Ok; } +Result WatWriter::ExprVisitorDelegate::OnCodeMetadataExpr( + CodeMetadataExpr* expr) { + writer_->WriteOpen("@metadata.code.", NextChar::None); + writer_->WriteDataWithNextChar(expr->name.data(), expr->name.size()); + writer_->WritePutc(' '); + writer_->WriteQuotedData(expr->data.data(), expr->data.size()); + writer_->WriteCloseSpace(); + return Result::Ok; +} + Result WatWriter::ExprVisitorDelegate::OnCompareExpr(CompareExpr* expr) { writer_->WritePutsNewline(expr->opcode.GetName()); return Result::Ok; diff --git a/test/binary/bad-code-metadata-function-count.txt b/test/binary/bad-code-metadata-function-count.txt new file mode 100644 index 00000000..50da843a --- /dev/null +++ b/test/binary/bad-code-metadata-function-count.txt @@ -0,0 +1,65 @@ +;;; TOOL: run-objdump-gen-wasm +;;; ARGS1: -x +magic +version +section(TYPE) { + count[1] + function params[0] results[1] i32 +} +section(FUNCTION) { + count[1] + type[0] +} +section(MEMORY) { + count[1] + has_max[0] + initial[0] +} +section("metadata.code.test") { + function_count[2] + function_index[0] + ann_count[1] + ann_offset[1] + ann_data_size[1] + ann_data[1] +} + +section(CODE) { + count[1] + func { + local_decls[0] + i32.const 1 + return + } +} + +(;; STDERR ;;; +0000033: warning: unable to read u32 leb128: function index +;;; STDERR ;;) +(;; STDOUT ;;; + +bad-code-metadata-function-count.wasm: file format wasm 0x1 + +Section Details: + +Type[1]: + - type[0] () -> i32 +Function[1]: + - func[0] sig=0 +Memory[1]: + - memory[0] pages: initial=0 +Custom: + - name: "metadata.code.test" + - func[0]: + - meta[1]: + - 0000000: 01 . +Code[1]: + - func[0] size=5 + +Code Disassembly: + +000037 func[0]: + 000038: 41 01 | i32.const 1 + 00003a: 0f | return + 00003b: 0b | end +;;; STDOUT ;;) diff --git a/test/binary/bad-code-metadata-function-duplicate.txt b/test/binary/bad-code-metadata-function-duplicate.txt new file mode 100644 index 00000000..4173ece2 --- /dev/null +++ b/test/binary/bad-code-metadata-function-duplicate.txt @@ -0,0 +1,67 @@ +;;; TOOL: run-objdump-gen-wasm +;;; ARGS1: -x +magic +version +section(TYPE) { + count[1] + function params[0] results[1] i32 +} +section(FUNCTION) { + count[1] + type[0] +} +section(MEMORY) { + count[1] + has_max[0] + initial[0] +} +section("metadata.code.test") { + function_count[2] + function_index[0] + ann_count[1] + ann_offset[1] + ann_data_size[1] + ann_data[1] + function_index[0] + ann_count[0] +} + +section(CODE) { + count[1] + func { + local_decls[0] + i32.const 1 + return + } +} + +(;; STDERR ;;; +0000034: warning: duplicate function index: 0 +;;; STDERR ;;) +(;; STDOUT ;;; + +bad-code-metadata-function-duplicate.wasm: file format wasm 0x1 + +Section Details: + +Type[1]: + - type[0] () -> i32 +Function[1]: + - func[0] sig=0 +Memory[1]: + - memory[0] pages: initial=0 +Custom: + - name: "metadata.code.test" + - func[0]: + - meta[1]: + - 0000000: 01 . +Code[1]: + - func[0] size=5 + +Code Disassembly: + +000039 func[0]: + 00003a: 41 01 | i32.const 1 + 00003c: 0f | return + 00003d: 0b | end +;;; STDOUT ;;) diff --git a/test/binary/bad-code-metadata-function-index.txt b/test/binary/bad-code-metadata-function-index.txt new file mode 100644 index 00000000..48bd19c6 --- /dev/null +++ b/test/binary/bad-code-metadata-function-index.txt @@ -0,0 +1,62 @@ +;;; TOOL: run-objdump-gen-wasm +;;; ARGS1: -x +magic +version +section(TYPE) { + count[1] + function params[0] results[1] i32 +} +section(FUNCTION) { + count[1] + type[0] +} +section(MEMORY) { + count[1] + has_max[0] + initial[0] +} +section("metadata.code.test") { + function_count[1] + function_index[2] + ann_count[1] + ann_offset[1] + ann_data_size[1] + ann_data[1] +} + +section(CODE) { + count[1] + func { + local_decls[0] + i32.const 1 + return + } +} + +(;; STDERR ;;; +000002f: warning: invalid function index: 2 +;;; STDERR ;;) +(;; STDOUT ;;; + +bad-code-metadata-function-index.wasm: file format wasm 0x1 + +Section Details: + +Type[1]: + - type[0] () -> i32 +Function[1]: + - func[0] sig=0 +Memory[1]: + - memory[0] pages: initial=0 +Custom: + - name: "metadata.code.test" +Code[1]: + - func[0] size=5 + +Code Disassembly: + +000037 func[0]: + 000038: 41 01 | i32.const 1 + 00003a: 0f | return + 00003b: 0b | end +;;; STDOUT ;;) diff --git a/test/binary/bad-code-metadata-function-out-of-order.txt b/test/binary/bad-code-metadata-function-out-of-order.txt new file mode 100644 index 00000000..b0c05890 --- /dev/null +++ b/test/binary/bad-code-metadata-function-out-of-order.txt @@ -0,0 +1,82 @@ +;;; TOOL: run-objdump-gen-wasm +;;; ARGS1: -x +magic +version +section(TYPE) { + count[1] + function params[0] results[1] i32 +} +section(FUNCTION) { + count[2] + type[0] + type[0] +} +section(MEMORY) { + count[1] + has_max[0] + initial[0] +} +section("metadata.code.test") { + function_count[2] + function_index[1] + ann_count[1] + ann_offset[1] + ann_data_size[1] + ann_data[1] + function_index[0] + ann_count[1] + ann_offset[1] + ann_data_size[1] + ann_data[1] +} + +section(CODE) { + count[2] + func { + local_decls[0] + i32.const 1 + return + } + func { + local_decls[0] + i32.const 1 + return + } +} + +(;; STDERR ;;; +0000035: warning: function index out of order: 0 +;;; STDERR ;;) +(;; STDOUT ;;; + +bad-code-metadata-function-out-of-order.wasm: file format wasm 0x1 + +Section Details: + +Type[1]: + - type[0] () -> i32 +Function[2]: + - func[0] sig=0 + - func[1] sig=0 +Memory[1]: + - memory[0] pages: initial=0 +Custom: + - name: "metadata.code.test" + - func[1]: + - meta[1]: + - 0000000: 01 . +Code[2]: + - func[0] size=5 + - func[1] size=5 + +Code Disassembly: + +00003d func[0]: + 00003e: 41 01 | i32.const 1 + 000040: 0f | return + 000041: 0b | end +000043 func[1]: + 000044: 41 01 | i32.const 1 + 000046: 0f | return + 000047: 0b | end +;;; STDOUT ;;) diff --git a/test/binary/bad-code-metadata-instance-count.txt b/test/binary/bad-code-metadata-instance-count.txt new file mode 100644 index 00000000..c8be5895 --- /dev/null +++ b/test/binary/bad-code-metadata-instance-count.txt @@ -0,0 +1,65 @@ +;;; TOOL: run-objdump-gen-wasm +;;; ARGS1: -x +magic +version +section(TYPE) { + count[1] + function params[0] results[1] i32 +} +section(FUNCTION) { + count[1] + type[0] +} +section(MEMORY) { + count[1] + has_max[0] + initial[0] +} +section("metadata.code.test") { + function_count[1] + function_index[0] + ann_count[2] + ann_offset[1] + ann_data_size[1] + ann_data[1] +} + +section(CODE) { + count[1] + func { + local_decls[0] + i32.const 1 + return + } +} + +(;; STDERR ;;; +0000033: warning: unable to read u32 leb128: code offset +;;; STDERR ;;) +(;; STDOUT ;;; + +bad-code-metadata-instance-count.wasm: file format wasm 0x1 + +Section Details: + +Type[1]: + - type[0] () -> i32 +Function[1]: + - func[0] sig=0 +Memory[1]: + - memory[0] pages: initial=0 +Custom: + - name: "metadata.code.test" + - func[0]: + - meta[1]: + - 0000000: 01 . +Code[1]: + - func[0] size=5 + +Code Disassembly: + +000037 func[0]: + 000038: 41 01 | i32.const 1 + 00003a: 0f | return + 00003b: 0b | end +;;; STDOUT ;;) diff --git a/test/binary/bad-code-metadata-instance-duplicate.txt b/test/binary/bad-code-metadata-instance-duplicate.txt new file mode 100644 index 00000000..95723713 --- /dev/null +++ b/test/binary/bad-code-metadata-instance-duplicate.txt @@ -0,0 +1,68 @@ +;;; TOOL: run-objdump-gen-wasm +;;; ARGS1: -x +magic +version +section(TYPE) { + count[1] + function params[0] results[1] i32 +} +section(FUNCTION) { + count[1] + type[0] +} +section(MEMORY) { + count[1] + has_max[0] + initial[0] +} +section("metadata.code.test") { + function_count[1] + function_index[0] + ann_count[2] + ann_offset[1] + ann_data_size[1] + ann_data[1] + ann_offset[1] + ann_data_size[1] + ann_data[1] +} + +section(CODE) { + count[1] + func { + local_decls[0] + i32.const 1 + return + } +} + +(;; STDERR ;;; +0000034: warning: duplicate code offset: 1 +;;; STDERR ;;) +(;; STDOUT ;;; + +bad-code-metadata-instance-duplicate.wasm: file format wasm 0x1 + +Section Details: + +Type[1]: + - type[0] () -> i32 +Function[1]: + - func[0] sig=0 +Memory[1]: + - memory[0] pages: initial=0 +Custom: + - name: "metadata.code.test" + - func[0]: + - meta[1]: + - 0000000: 01 . +Code[1]: + - func[0] size=5 + +Code Disassembly: + +00003a func[0]: + 00003b: 41 01 | i32.const 1 + 00003d: 0f | return + 00003e: 0b | end +;;; STDOUT ;;) diff --git a/test/binary/bad-code-metadata-instance-out-of-order.txt b/test/binary/bad-code-metadata-instance-out-of-order.txt new file mode 100644 index 00000000..4efb85d8 --- /dev/null +++ b/test/binary/bad-code-metadata-instance-out-of-order.txt @@ -0,0 +1,68 @@ +;;; TOOL: run-objdump-gen-wasm +;;; ARGS1: -x +magic +version +section(TYPE) { + count[1] + function params[0] results[1] i32 +} +section(FUNCTION) { + count[1] + type[0] +} +section(MEMORY) { + count[1] + has_max[0] + initial[0] +} +section("metadata.code.test") { + function_count[1] + function_index[0] + ann_count[2] + ann_offset[3] + ann_data_size[1] + ann_data[1] + ann_offset[1] + ann_data_size[1] + ann_data[1] +} + +section(CODE) { + count[1] + func { + local_decls[0] + i32.const 1 + return + } +} + +(;; STDERR ;;; +0000034: warning: code offset out of order: 1 +;;; STDERR ;;) +(;; STDOUT ;;; + +bad-code-metadata-instance-out-of-order.wasm: file format wasm 0x1 + +Section Details: + +Type[1]: + - type[0] () -> i32 +Function[1]: + - func[0] sig=0 +Memory[1]: + - memory[0] pages: initial=0 +Custom: + - name: "metadata.code.test" + - func[0]: + - meta[3]: + - 0000000: 01 . +Code[1]: + - func[0] size=5 + +Code Disassembly: + +00003a func[0]: + 00003b: 41 01 | i32.const 1 + 00003d: 0f | return + 00003e: 0b | end +;;; STDOUT ;;) diff --git a/test/binary/code-metadata-section.txt b/test/binary/code-metadata-section.txt new file mode 100644 index 00000000..9625f602 --- /dev/null +++ b/test/binary/code-metadata-section.txt @@ -0,0 +1,61 @@ +;;; TOOL: run-objdump-gen-wasm +;;; ARGS: -x +magic +version +section(TYPE) { + count[1] + function params[0] results[1] i32 +} +section(FUNCTION) { + count[1] + type[0] +} +section(MEMORY) { + count[1] + has_max[0] + initial[0] +} +section("metadata.code.test") { + function_count[1] + function_index[0] + ann_count[1] + ann_offset[1] + ann_data_size[1] + ann_data[1] +} + +section(CODE) { + count[1] + func { + local_decls[0] + i32.const 1 + return + } +} +(;; STDOUT ;;; + +code-metadata-section.wasm: file format wasm 0x1 + +Section Details: + +Type[1]: + - type[0] () -> i32 +Function[1]: + - func[0] sig=0 +Memory[1]: + - memory[0] pages: initial=0 +Custom: + - name: "metadata.code.test" + - func[0]: + - meta[1]: + - 0000000: 01 . +Code[1]: + - func[0] size=5 + +Code Disassembly: + +000037 func[0]: + 000038: 41 01 | i32.const 1 + 00003a: 0f | return + 00003b: 0b | end +;;; STDOUT ;;) diff --git a/test/decompile/code-metadata.txt b/test/decompile/code-metadata.txt new file mode 100644 index 00000000..1efd9d65 --- /dev/null +++ b/test/decompile/code-metadata.txt @@ -0,0 +1,17 @@ +;;; TOOL: run-wasm-decompile + +(module + (func $f (param i32) (result i32) + i32.const 1234 + local.get 0 + (@metadata.code.test "aa\01a") i32.add + return)) + +(;; STDOUT ;;; +function f_a(a:int):int { + let t0 = a; + // @metadata.code.test "aa\01a"; + return 1234 + t0; +} + +;;; STDOUT ;;) diff --git a/test/dump/code-metadata.txt b/test/dump/code-metadata.txt new file mode 100644 index 00000000..1b2254d7 --- /dev/null +++ b/test/dump/code-metadata.txt @@ -0,0 +1,43 @@ +;;; TOOL: run-objdump +;;; ARGS0: --enable-annotations --enable-code-metadata +;;; ARGS1: --headers --details +(module + (func $f (param i32) (result i32) + i32.const 1234 + local.get 0 + (@metadata.code.test "aa\01a") i32.add + return)) +(;; STDOUT ;;; + +code-metadata.wasm: file format wasm 0x1 + +Sections: + + Type start=0x0000000a end=0x00000010 (size=0x00000006) count: 1 + Function start=0x00000012 end=0x00000014 (size=0x00000002) count: 1 + Custom start=0x00000016 end=0x00000032 (size=0x0000001c) "metadata.code.test" + Code start=0x00000034 end=0x0000003f (size=0x0000000b) count: 1 + +Section Details: + +Type[1]: + - type[0] (i32) -> i32 +Function[1]: + - func[0] sig=0 +Custom: + - name: "metadata.code.test" + - func[0]: + - meta[6]: + - 0000000: 6161 0161 aa.a +Code[1]: + - func[0] size=9 + +Code Disassembly: + +000036 func[0]: + 000037: 41 d2 09 | i32.const 1234 + 00003a: 20 00 | local.get 0 + 00003c: 6a | i32.add + 00003d: 0f | return + 00003e: 0b | end +;;; STDOUT ;;) diff --git a/test/help/spectest-interp.txt b/test/help/spectest-interp.txt index 225a3938..bbb68061 100644 --- a/test/help/spectest-interp.txt +++ b/test/help/spectest-interp.txt @@ -25,6 +25,7 @@ options: --disable-bulk-memory Disable Bulk-memory operations --disable-reference-types Disable Reference types (externref) --enable-annotations Enable Custom annotation syntax + --enable-code-metadata Enable Code metadata --enable-gc Enable Garbage collection --enable-memory64 Enable 64-bit memory --enable-multi-memory Enable Multi-memory diff --git a/test/help/wasm-interp.txt b/test/help/wasm-interp.txt index efbe0409..f6dc26b7 100644 --- a/test/help/wasm-interp.txt +++ b/test/help/wasm-interp.txt @@ -36,6 +36,7 @@ options: --disable-bulk-memory Disable Bulk-memory operations --disable-reference-types Disable Reference types (externref) --enable-annotations Enable Custom annotation syntax + --enable-code-metadata Enable Code metadata --enable-gc Enable Garbage collection --enable-memory64 Enable 64-bit memory --enable-multi-memory Enable Multi-memory diff --git a/test/help/wasm-opcodecnt.txt b/test/help/wasm-opcodecnt.txt index eff83b99..2a0606b9 100644 --- a/test/help/wasm-opcodecnt.txt +++ b/test/help/wasm-opcodecnt.txt @@ -26,6 +26,7 @@ options: --disable-bulk-memory Disable Bulk-memory operations --disable-reference-types Disable Reference types (externref) --enable-annotations Enable Custom annotation syntax + --enable-code-metadata Enable Code metadata --enable-gc Enable Garbage collection --enable-memory64 Enable 64-bit memory --enable-multi-memory Enable Multi-memory diff --git a/test/help/wasm-validate.txt b/test/help/wasm-validate.txt index 3f76d737..4ceeb329 100644 --- a/test/help/wasm-validate.txt +++ b/test/help/wasm-validate.txt @@ -25,6 +25,7 @@ options: --disable-bulk-memory Disable Bulk-memory operations --disable-reference-types Disable Reference types (externref) --enable-annotations Enable Custom annotation syntax + --enable-code-metadata Enable Code metadata --enable-gc Enable Garbage collection --enable-memory64 Enable 64-bit memory --enable-multi-memory Enable Multi-memory diff --git a/test/help/wasm2wat.txt b/test/help/wasm2wat.txt index 29155532..a2b78d31 100644 --- a/test/help/wasm2wat.txt +++ b/test/help/wasm2wat.txt @@ -31,6 +31,7 @@ options: --disable-bulk-memory Disable Bulk-memory operations --disable-reference-types Disable Reference types (externref) --enable-annotations Enable Custom annotation syntax + --enable-code-metadata Enable Code metadata --enable-gc Enable Garbage collection --enable-memory64 Enable 64-bit memory --enable-multi-memory Enable Multi-memory diff --git a/test/help/wast2json.txt b/test/help/wast2json.txt index 90278883..95fa3a3e 100644 --- a/test/help/wast2json.txt +++ b/test/help/wast2json.txt @@ -28,6 +28,7 @@ options: --disable-bulk-memory Disable Bulk-memory operations --disable-reference-types Disable Reference types (externref) --enable-annotations Enable Custom annotation syntax + --enable-code-metadata Enable Code metadata --enable-gc Enable Garbage collection --enable-memory64 Enable 64-bit memory --enable-multi-memory Enable Multi-memory diff --git a/test/help/wat-desugar.txt b/test/help/wat-desugar.txt index 38f6356c..268fd600 100644 --- a/test/help/wat-desugar.txt +++ b/test/help/wat-desugar.txt @@ -35,6 +35,7 @@ options: --disable-bulk-memory Disable Bulk-memory operations --disable-reference-types Disable Reference types (externref) --enable-annotations Enable Custom annotation syntax + --enable-code-metadata Enable Code metadata --enable-gc Enable Garbage collection --enable-memory64 Enable 64-bit memory --enable-multi-memory Enable Multi-memory diff --git a/test/help/wat2wasm.txt b/test/help/wat2wasm.txt index 71ff482c..2bba6093 100644 --- a/test/help/wat2wasm.txt +++ b/test/help/wat2wasm.txt @@ -35,6 +35,7 @@ options: --disable-bulk-memory Disable Bulk-memory operations --disable-reference-types Disable Reference types (externref) --enable-annotations Enable Custom annotation syntax + --enable-code-metadata Enable Code metadata --enable-gc Enable Garbage collection --enable-memory64 Enable 64-bit memory --enable-multi-memory Enable Multi-memory diff --git a/test/roundtrip/code-metadata.txt b/test/roundtrip/code-metadata.txt new file mode 100644 index 00000000..1526f212 --- /dev/null +++ b/test/roundtrip/code-metadata.txt @@ -0,0 +1,8 @@ +;;; TOOL: run-roundtrip +;;; ARGS: --enable-annotations --enable-code-metadata +(module + (func $f (param i32) (result i32) + i32.const 1234 + local.get 0 + (@metadata.code.test "aa\01a") i32.add + return)) diff --git a/test/run-roundtrip.py b/test/run-roundtrip.py index ee765537..bf7b23cb 100755 --- a/test/run-roundtrip.py +++ b/test/run-roundtrip.py @@ -124,6 +124,8 @@ def main(args): parser.add_argument('--disable-reference-types', action='store_true') parser.add_argument('--enable-memory64', action='store_true') parser.add_argument('--enable-multi-memory', action='store_true') + parser.add_argument('--enable-annotations', action='store_true') + parser.add_argument('--enable-code-metadata', action='store_true') parser.add_argument('--inline-exports', action='store_true') parser.add_argument('--inline-imports', action='store_true') parser.add_argument('--reloc', action='store_true') @@ -146,6 +148,8 @@ def main(args): '--disable-reference-types': options.disable_reference_types, '--enable-memory64': options.enable_memory64, '--enable-multi-memory': options.enable_multi_memory, + '--enable-annotations': options.enable_annotations, + '--enable-code-metadata': options.enable_code_metadata, '--reloc': options.reloc, '--no-check': options.no_check, }) @@ -166,6 +170,8 @@ def main(args): '--enable-threads': options.enable_threads, '--enable-memory64': options.enable_memory64, '--enable-multi-memory': options.enable_multi_memory, + '--enable-annotations': options.enable_annotations, + '--enable-code-metadata': options.enable_code_metadata, '--inline-exports': options.inline_exports, '--inline-imports': options.inline_imports, '--no-debug-names': not options.debug_names, |