diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/binary-reader-ir.cc | 94 | ||||
-rw-r--r-- | src/binary-reader-logging.cc | 20 | ||||
-rw-r--r-- | src/binary-reader-logging.h | 7 | ||||
-rw-r--r-- | src/binary-reader-nop.h | 15 | ||||
-rw-r--r-- | src/binary-reader-objdump.cc | 29 | ||||
-rw-r--r-- | src/binary-reader.cc | 58 | ||||
-rw-r--r-- | src/binary-reader.h | 10 | ||||
-rw-r--r-- | src/binary-writer.cc | 88 | ||||
-rw-r--r-- | src/binary.h | 1 | ||||
-rw-r--r-- | src/c-writer.cc | 3 | ||||
-rw-r--r-- | src/decompiler.cc | 6 | ||||
-rw-r--r-- | src/expr-visitor.cc | 4 | ||||
-rw-r--r-- | src/expr-visitor.h | 2 | ||||
-rw-r--r-- | src/feature.def | 1 | ||||
-rw-r--r-- | src/ir-util.cc | 1 | ||||
-rw-r--r-- | src/ir.cc | 1 | ||||
-rw-r--r-- | src/ir.h | 15 | ||||
-rw-r--r-- | src/validator.cc | 5 | ||||
-rw-r--r-- | src/wast-parser.cc | 46 | ||||
-rw-r--r-- | src/wast-parser.h | 1 | ||||
-rw-r--r-- | src/wat-writer.cc | 11 |
21 files changed, 412 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; |