[lld] [clang-tools-extra] [llvm] [clang] [Object][Wasm] Allow parsing of GC types in type and table sections (PR #79235)

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 23 17:19:54 PST 2024


https://github.com/dschuff created https://github.com/llvm/llvm-project/pull/79235

This change allows a WasmObjectFile to be created from a wasm file even if it uses typed funcrefs and GC types.
It does not significantly change how lib/Object models its various internal types (e.g. WasmSignature,
WasmElemSegment), so LLVM does not really "support" or understand such files, but it is sufficient to parse
the type, global and element sections, discarding types that are not understood. This is useful for low-level binary
tools such as nm and objcopy, which use only limited aspects of the binary (such as function definitions) or deal
with sections as opaque blobs.

This is done by allowing `WasmValType` to have a value of `OTHERREF` (representing any unmodeled reference
type), and adding a field to `WasmSignature` indicating it's a placeholder for an unmodeled reference type (since
there is a 1:1 correspondence between WasmSignature objects and types in the type section). 
Then the object file parsers for the type and element sections are expanded to parse encoded reference types and
discard any unmodeled fields.

>From 976c98f631e5ed48bb18accbe59c9babd354a924 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Wed, 3 Jan 2024 09:06:37 -0800
Subject: [PATCH 01/11] parse types

---
 llvm/include/llvm/BinaryFormat/Wasm.h |  8 +++
 llvm/lib/Object/WasmObjectFile.cpp    | 83 +++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index c7658cc7b7432b3..89499a61b76c8c3 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -265,7 +265,13 @@ enum : unsigned {
   WASM_TYPE_V128 = 0x7B,
   WASM_TYPE_FUNCREF = 0x70,
   WASM_TYPE_EXTERNREF = 0x6F,
+  WASM_TYPE_NULLABLE = 0x63,
   WASM_TYPE_FUNC = 0x60,
+  WASM_TYPE_ARRAY = 0x5E, // Composite types, not used for codegen
+  WASM_TYPE_STRUCT = 0x5F,
+  WASM_TYPE_SUB = 0x50,
+  WASM_TYPE_SUB_FINAL = 0x4F,
+  WASM_TYPE_REC = 0x4E,
   WASM_TYPE_NORESULT = 0x40, // for blocks with no result values
 };
 
@@ -431,11 +437,13 @@ enum class ValType {
   V128 = WASM_TYPE_V128,
   FUNCREF = WASM_TYPE_FUNCREF,
   EXTERNREF = WASM_TYPE_EXTERNREF,
+  OTHERREF,
 };
 
 struct WasmSignature {
   SmallVector<ValType, 1> Returns;
   SmallVector<ValType, 4> Params;
+  enum {Function, Other} Kind = Function;
   // Support empty and tombstone instances, needed by DenseMap.
   enum { Plain, Empty, Tombstone } State = Plain;
 
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 94cd96968ff2010..3d2b06342481aa0 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -21,6 +21,7 @@
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
 #include "llvm/Support/LEB128.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/TargetParser/SubtargetFeature.h"
@@ -29,6 +30,7 @@
 #include <cassert>
 #include <cstdint>
 #include <cstring>
+#include <sys/types.h>
 
 #define DEBUG_TYPE "wasm-object"
 
@@ -1104,26 +1106,107 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
 }
 
 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
+  auto parseFieldDef = [&]() {
+    int32_t TypeCode = readVarint32((Ctx));
+    uint32_t Mutability = readVaruint32(Ctx);
+  };
+  auto parseRecType = [&]() {
+    uint8_t Form = readUint8(Ctx);
+    if (Form == wasm::WASM_TYPE_REC) {
+      uint32_t Size = readVaruint32(Ctx);
+      assert(Size > 0); // TODO real errors here and below
+      Form = readVaruint32(Ctx);
+    }
+    if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {
+      uint32_t Supers = readVaruint32(Ctx);
+      if (Supers > 0) {
+        assert(Supers == 1);
+        uint32_t SuperIndex = readVaruint32(Ctx);
+      }
+      Form = readVaruint32(Ctx);
+    }
+    if (Form == wasm::WASM_TYPE_STRUCT) {
+      uint32_t NumFields = readVaruint32(Ctx);
+      for (size_t i = 0; i < NumFields; i++) {
+        parseFieldDef();
+      }
+    } else if (Form == wasm::WASM_TYPE_ARRAY) {
+      parseFieldDef();
+    }
+
+  };
+  auto parseParamType = [&](uint32_t code) -> wasm::ValType {
+    switch(code) {
+      case wasm::WASM_TYPE_I32:
+      case wasm::WASM_TYPE_I64:
+      case wasm::WASM_TYPE_F32:
+      case wasm::WASM_TYPE_F64:
+      case wasm::WASM_TYPE_V128:
+      case wasm::WASM_TYPE_FUNCREF:
+      case wasm::WASM_TYPE_EXTERNREF:
+        return wasm::ValType(code);
+    }
+  };
   uint32_t Count = readVaruint32(Ctx);
   Signatures.reserve(Count);
   while (Count--) {
     wasm::WasmSignature Sig;
     uint8_t Form = readUint8(Ctx);
+    llvm::errs() << llvm::format("Top Count %d form %x", Count, Form) << '\n';
+    if (Form == wasm::WASM_TYPE_REC) {
+      uint32_t Size = readVaruint32(Ctx);
+      assert(Size > 0); // TODO real errors here and below
+      Form = readVaruint32(Ctx);
+      wasm::WasmSignature s; s.Kind = s.Other;
+      Signatures.push_back(s);
+      Count--;
+      llvm::errs() << llvm::format(" Rec size %d form %x", Size, Form) << '\n';
+    }
     if (Form != wasm::WASM_TYPE_FUNC) {
+      wasm::WasmSignature s; s.Kind = s.Other;
+      if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {
+        uint32_t Supers = readVaruint32(Ctx);
+        if (Supers > 0) {
+          assert(Supers == 1);
+          uint32_t SuperIndex = readVaruint32(Ctx);
+        }
+        Form = readVaruint32(Ctx);
+        llvm::errs() << llvm::format(" Sub Supers %d form %x", Supers, Form) << '\n';
+      }
+      if (Form == wasm::WASM_TYPE_STRUCT) {
+        uint32_t NumFields = readVaruint32(Ctx);
+        for (size_t i = 0; i < NumFields; i++) {
+          parseFieldDef();
+        }
+        llvm::errs() << llvm::format(" Struct size %d", NumFields) << '\n';
+      } else if (Form == wasm::WASM_TYPE_ARRAY) {
+        parseFieldDef();
+        llvm::errs() << llvm::format("arr form %x", Form) << '\n';
+      } else {
+        llvm::errs() << llvm::format(" bad form %x", Form) << '\n';
+        return make_error<GenericBinaryError>("bad form", object_error::parse_failed);
+      }
+      Signatures.push_back(s);
+      continue;
       return make_error<GenericBinaryError>("invalid signature type",
                                             object_error::parse_failed);
     }
+
     uint32_t ParamCount = readVaruint32(Ctx);
     Sig.Params.reserve(ParamCount);
+    llvm::errs() << llvm::format("param ct %d ", ParamCount);
     while (ParamCount--) {
       uint32_t ParamType = readUint8(Ctx);
+      if (ParamType == )
       Sig.Params.push_back(wasm::ValType(ParamType));
     }
     uint32_t ReturnCount = readVaruint32(Ctx);
+    llvm::errs() << llvm::format("return ct %d\n", ReturnCount);
     while (ReturnCount--) {
       uint32_t ReturnType = readUint8(Ctx);
       Sig.Returns.push_back(wasm::ValType(ReturnType));
     }
+    
     Signatures.push_back(std::move(Sig));
   }
   if (Ctx.Ptr != Ctx.End)

>From 28273084c7b3f10dbff88ffe418e12d4e7c7c159 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 4 Jan 2024 11:07:38 -0800
Subject: [PATCH 02/11] type section working

---
 llvm/include/llvm/BinaryFormat/Wasm.h | 16 +++++++-
 llvm/lib/Object/WasmObjectFile.cpp    | 59 +++++++++++----------------
 2 files changed, 38 insertions(+), 37 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 89499a61b76c8c3..2cfb69fcf8f8276 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -263,8 +263,18 @@ enum : unsigned {
   WASM_TYPE_F32 = 0x7D,
   WASM_TYPE_F64 = 0x7C,
   WASM_TYPE_V128 = 0x7B,
+  WASM_TYPE_NULLFUNCREF = 0x73,
+  WASM_TYPE_NULLEXTERNREF = 0x72,
+  WASM_TYPE_NULLREF = 0x71,
   WASM_TYPE_FUNCREF = 0x70,
   WASM_TYPE_EXTERNREF = 0x6F,
+  WASM_TYPE_ANYREF = 0x6E,
+  WASM_TYPE_EQREF = 0x6D,
+  WASM_TYPE_I31REF = 0x6C,
+  WASM_TYPE_STRUCTREF = 0x6B,
+  WASM_TYPE_ARRAYREF = 0x6A,
+  WASM_TYPE_EXNREF = 0x69,
+  WASM_TYPE_NONNULLABLE = 0x64,
   WASM_TYPE_NULLABLE = 0x63,
   WASM_TYPE_FUNC = 0x60,
   WASM_TYPE_ARRAY = 0x5E, // Composite types, not used for codegen
@@ -437,13 +447,15 @@ enum class ValType {
   V128 = WASM_TYPE_V128,
   FUNCREF = WASM_TYPE_FUNCREF,
   EXTERNREF = WASM_TYPE_EXTERNREF,
-  OTHERREF,
+  OTHERREF, // Unmodeled value types include ref types with heap types other than funcref or externref
 };
 
+// Represents anything that can be encoded in the type section, but only
+// signatures are actually modeled. TODO: maybe refactor to make this explicit.
 struct WasmSignature {
   SmallVector<ValType, 1> Returns;
   SmallVector<ValType, 4> Params;
-  enum {Function, Other} Kind = Function;
+  enum {Function, Other} Kind = Function; // Recursive, Composite(Array,Struct),  
   // Support empty and tombstone instances, needed by DenseMap.
   enum { Plain, Empty, Tombstone } State = Plain;
 
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 3d2b06342481aa0..639d49b242694c9 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1106,37 +1106,11 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
 }
 
 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
-  auto parseFieldDef = [&]() {
-    int32_t TypeCode = readVarint32((Ctx));
-    uint32_t Mutability = readVaruint32(Ctx);
-  };
-  auto parseRecType = [&]() {
-    uint8_t Form = readUint8(Ctx);
-    if (Form == wasm::WASM_TYPE_REC) {
-      uint32_t Size = readVaruint32(Ctx);
-      assert(Size > 0); // TODO real errors here and below
-      Form = readVaruint32(Ctx);
-    }
-    if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {
-      uint32_t Supers = readVaruint32(Ctx);
-      if (Supers > 0) {
-        assert(Supers == 1);
-        uint32_t SuperIndex = readVaruint32(Ctx);
-      }
-      Form = readVaruint32(Ctx);
-    }
-    if (Form == wasm::WASM_TYPE_STRUCT) {
-      uint32_t NumFields = readVaruint32(Ctx);
-      for (size_t i = 0; i < NumFields; i++) {
-        parseFieldDef();
-      }
-    } else if (Form == wasm::WASM_TYPE_ARRAY) {
-      parseFieldDef();
-    }
 
-  };
-  auto parseParamType = [&](uint32_t code) -> wasm::ValType {
-    switch(code) {
+  auto parseValType = [&](uint32_t Code) -> wasm::ValType {
+    // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern)
+    llvm::errs() << llvm::format(" val type %x ", Code);
+    switch(Code) {
       case wasm::WASM_TYPE_I32:
       case wasm::WASM_TYPE_I64:
       case wasm::WASM_TYPE_F32:
@@ -1144,9 +1118,20 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
       case wasm::WASM_TYPE_V128:
       case wasm::WASM_TYPE_FUNCREF:
       case wasm::WASM_TYPE_EXTERNREF:
-        return wasm::ValType(code);
+        return wasm::ValType(Code);
+    }
+    if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
+      readVarint64(Ctx);
     }
+    return wasm::ValType(wasm::ValType::OTHERREF);
   };
+  auto parseFieldDef = [&]() {
+    uint32_t TypeCode = readVaruint32((Ctx));
+    parseValType(TypeCode);
+    uint32_t Mutability = readVaruint32(Ctx);
+    llvm::errs() << llvm:: format(" mut %d ", Mutability);
+  };
+
   uint32_t Count = readVaruint32(Ctx);
   Signatures.reserve(Count);
   while (Count--) {
@@ -1156,6 +1141,8 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
     if (Form == wasm::WASM_TYPE_REC) {
       uint32_t Size = readVaruint32(Ctx);
       assert(Size > 0); // TODO real errors here and below
+      Signatures.reserve(Signatures.size() + Size);
+      Count += Size;
       Form = readVaruint32(Ctx);
       wasm::WasmSignature s; s.Kind = s.Other;
       Signatures.push_back(s);
@@ -1197,17 +1184,19 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
     llvm::errs() << llvm::format("param ct %d ", ParamCount);
     while (ParamCount--) {
       uint32_t ParamType = readUint8(Ctx);
-      if (ParamType == )
-      Sig.Params.push_back(wasm::ValType(ParamType));
+      Sig.Returns.push_back(parseValType(ParamType));
+      continue;
+      
     }
     uint32_t ReturnCount = readVaruint32(Ctx);
-    llvm::errs() << llvm::format("return ct %d\n", ReturnCount);
+    llvm::errs() << llvm::format("\nreturn ct %d ", ReturnCount);
     while (ReturnCount--) {
       uint32_t ReturnType = readUint8(Ctx);
-      Sig.Returns.push_back(wasm::ValType(ReturnType));
+      Sig.Returns.push_back(parseValType(ReturnType));
     }
     
     Signatures.push_back(std::move(Sig));
+    llvm::errs() << '\n';
   }
   if (Ctx.Ptr != Ctx.End)
     return make_error<GenericBinaryError>("type section ended prematurely",

>From e716a1470836d18af1a1032880ed1afec47f4aa5 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 4 Jan 2024 11:57:02 -0800
Subject: [PATCH 03/11] some cleanup

---
 llvm/lib/Object/WasmObjectFile.cpp | 43 +++++++++++++++---------------
 1 file changed, 21 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 639d49b242694c9..c7916fdebac85a0 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -30,7 +30,6 @@
 #include <cassert>
 #include <cstdint>
 #include <cstring>
-#include <sys/types.h>
 
 #define DEBUG_TYPE "wasm-object"
 
@@ -1106,7 +1105,6 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
 }
 
 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
-
   auto parseValType = [&](uint32_t Code) -> wasm::ValType {
     // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern)
     llvm::errs() << llvm::format(" val type %x ", Code);
@@ -1121,13 +1119,13 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
         return wasm::ValType(Code);
     }
     if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
-      readVarint64(Ctx);
+      /* Discard HeapType */ readVarint64(Ctx);
     }
     return wasm::ValType(wasm::ValType::OTHERREF);
   };
   auto parseFieldDef = [&]() {
     uint32_t TypeCode = readVaruint32((Ctx));
-    parseValType(TypeCode);
+    /* Discard StorageType */ parseValType(TypeCode);
     uint32_t Mutability = readVaruint32(Ctx);
     llvm::errs() << llvm:: format(" mut %d ", Mutability);
   };
@@ -1139,33 +1137,36 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
     uint8_t Form = readUint8(Ctx);
     llvm::errs() << llvm::format("Top Count %d form %x", Count, Form) << '\n';
     if (Form == wasm::WASM_TYPE_REC) {
-      uint32_t Size = readVaruint32(Ctx);
-      assert(Size > 0); // TODO real errors here and below
-      Signatures.reserve(Signatures.size() + Size);
-      Count += Size;
-      Form = readVaruint32(Ctx);
-      wasm::WasmSignature s; s.Kind = s.Other;
-      Signatures.push_back(s);
-      Count--;
-      llvm::errs() << llvm::format(" Rec size %d form %x", Size, Form) << '\n';
+      // Rec groups expand the type index space (beyond what was declared at
+      // the top of the section, and also consume one element in that space.
+      uint32_t RecSize = readVaruint32(Ctx);
+      assert(RecSize > 0); // TODO real errors here and below
+      Signatures.reserve(Signatures.size() + RecSize);
+      Count += RecSize;
+      llvm::errs() << llvm::format(" Rec size %d\n", RecSize);
+      Sig.Kind = wasm::WasmSignature::Other;
+      Signatures.push_back(std::move(Sig));
+      continue;
     }
     if (Form != wasm::WASM_TYPE_FUNC) {
-      wasm::WasmSignature s; s.Kind = s.Other;
+      // Currently LLVM only models function types, and not other composite
+      // types. Here we parse the type declarations just enough to skip past
+      // them in the binary.
       if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {
         uint32_t Supers = readVaruint32(Ctx);
         if (Supers > 0) {
           assert(Supers == 1);
-          uint32_t SuperIndex = readVaruint32(Ctx);
+          /* Discard SuperIndex */ readVaruint32(Ctx);
         }
         Form = readVaruint32(Ctx);
         llvm::errs() << llvm::format(" Sub Supers %d form %x", Supers, Form) << '\n';
       }
       if (Form == wasm::WASM_TYPE_STRUCT) {
-        uint32_t NumFields = readVaruint32(Ctx);
-        for (size_t i = 0; i < NumFields; i++) {
+        uint32_t FieldCount = readVaruint32(Ctx);
+        while (FieldCount--) {
           parseFieldDef();
         }
-        llvm::errs() << llvm::format(" Struct size %d", NumFields) << '\n';
+        llvm::errs() << llvm::format(" Struct size %d", FieldCount) << '\n';
       } else if (Form == wasm::WASM_TYPE_ARRAY) {
         parseFieldDef();
         llvm::errs() << llvm::format("arr form %x", Form) << '\n';
@@ -1173,10 +1174,9 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
         llvm::errs() << llvm::format(" bad form %x", Form) << '\n';
         return make_error<GenericBinaryError>("bad form", object_error::parse_failed);
       }
-      Signatures.push_back(s);
+      Sig.Kind = wasm::WasmSignature::Other;
+      Signatures.push_back(std::move(Sig));
       continue;
-      return make_error<GenericBinaryError>("invalid signature type",
-                                            object_error::parse_failed);
     }
 
     uint32_t ParamCount = readVaruint32(Ctx);
@@ -1186,7 +1186,6 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
       uint32_t ParamType = readUint8(Ctx);
       Sig.Returns.push_back(parseValType(ParamType));
       continue;
-      
     }
     uint32_t ReturnCount = readVaruint32(Ctx);
     llvm::errs() << llvm::format("\nreturn ct %d ", ReturnCount);

>From 2b0b6195883979b19d3d029ee56cc69d1957abaf Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 4 Jan 2024 14:35:20 -0800
Subject: [PATCH 04/11] parses dart global section

---
 llvm/include/llvm/BinaryFormat/Wasm.h |  9 +++
 llvm/lib/Object/WasmObjectFile.cpp    | 80 ++++++++++++++++++---------
 2 files changed, 62 insertions(+), 27 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 2cfb69fcf8f8276..a378b20ded75fd7 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -316,6 +316,15 @@ enum : unsigned {
   WASM_OPCODE_I64_SUB = 0x7d,
   WASM_OPCODE_I64_MUL = 0x7e,
   WASM_OPCODE_REF_NULL = 0xd0,
+  WASM_OPCODE_REF_FUNC = 0xd2,
+  WASM_OPCODE_GC_PREFIX = 0xfb,
+};
+
+// Opcodes in the GC-prefixed space (0xfb)
+enum : unsigned {
+  WASM_OPCODE_STRUCT_NEW = 0x00,
+  WASM_OPCODE_STRUCT_NEW_DEFAULT = 0x01,
+  WASM_OPCODE_ARRAY_NEW_FIXED = 0x08,
 };
 
 // Opcodes used in synthetic functions.
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index c7916fdebac85a0..4d33bf82ec43078 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -30,6 +30,7 @@
 #include <cassert>
 #include <cstdint>
 #include <cstring>
+#include <limits>
 
 #define DEBUG_TYPE "wasm-object"
 
@@ -174,6 +175,25 @@ static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
   return readUint8(Ctx);
 }
 
+static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx, uint32_t Code) {
+    // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern)
+    llvm::errs() << llvm::format(" val type %x ", Code);
+    switch(Code) {
+      case wasm::WASM_TYPE_I32:
+      case wasm::WASM_TYPE_I64:
+      case wasm::WASM_TYPE_F32:
+      case wasm::WASM_TYPE_F64:
+      case wasm::WASM_TYPE_V128:
+      case wasm::WASM_TYPE_FUNCREF:
+      case wasm::WASM_TYPE_EXTERNREF:
+        return wasm::ValType(Code);
+    }
+    if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
+      /* Discard HeapType */ readVarint64(Ctx);
+    }
+    return wasm::ValType(wasm::ValType::OTHERREF);
+}
+
 static Error readInitExpr(wasm::WasmInitExpr &Expr,
                           WasmObjectFile::ReadContext &Ctx) {
   auto Start = Ctx.Ptr;
@@ -197,10 +217,10 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
     Expr.Inst.Value.Global = readULEB128(Ctx);
     break;
   case wasm::WASM_OPCODE_REF_NULL: {
-    wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
-    if (Ty != wasm::ValType::EXTERNREF) {
-      return make_error<GenericBinaryError>("invalid type for ref.null",
-                                            object_error::parse_failed);
+    wasm::ValType Ty = parseValType(Ctx, readVaruint32(Ctx));
+    if (Ty != wasm::ValType::EXTERNREF) { // maybe something special if the type isn't one we understand?
+      //return make_error<GenericBinaryError>("invalid type for ref.null",
+      //                                      object_error::parse_failed);
     }
     break;
   }
@@ -218,14 +238,20 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
     Ctx.Ptr = Start;
     while (true) {
       uint8_t Opcode = readOpcode(Ctx);
+      llvm::errs() << llvm::format(" opcode %x", Opcode);
       switch (Opcode) {
       case wasm::WASM_OPCODE_I32_CONST:
       case wasm::WASM_OPCODE_GLOBAL_GET:
       case wasm::WASM_OPCODE_REF_NULL:
+      case wasm::WASM_OPCODE_REF_FUNC:
       case wasm::WASM_OPCODE_I64_CONST:
+        readULEB128(Ctx);
+        break;
       case wasm::WASM_OPCODE_F32_CONST:
+        readFloat32(Ctx);
+        break;
       case wasm::WASM_OPCODE_F64_CONST:
-        readULEB128(Ctx);
+        readFloat64(Ctx);
         break;
       case wasm::WASM_OPCODE_I32_ADD:
       case wasm::WASM_OPCODE_I32_SUB:
@@ -234,8 +260,22 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
       case wasm::WASM_OPCODE_I64_SUB:
       case wasm::WASM_OPCODE_I64_MUL:
         break;
+      case wasm::WASM_OPCODE_GC_PREFIX:
+        break;
+      // The GC opcodes are in a separate (prefixed space). This flat switch
+      // structure works as long as there is no overlap between the GC and
+      // general opcodes used in init exprs.
+      case wasm::WASM_OPCODE_STRUCT_NEW:
+      case wasm::WASM_OPCODE_STRUCT_NEW_DEFAULT:
+        readULEB128(Ctx); // heap type index
+        break;
+      case wasm::WASM_OPCODE_ARRAY_NEW_FIXED:
+        readULEB128(Ctx); // heap type index
+        readULEB128(Ctx); // array size
+        break;
       case wasm::WASM_OPCODE_END:
         Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);
+        llvm::errs() << "\n";
         return Error::success();
       default:
         return make_error<GenericBinaryError>(
@@ -1105,27 +1145,9 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
 }
 
 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
-  auto parseValType = [&](uint32_t Code) -> wasm::ValType {
-    // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern)
-    llvm::errs() << llvm::format(" val type %x ", Code);
-    switch(Code) {
-      case wasm::WASM_TYPE_I32:
-      case wasm::WASM_TYPE_I64:
-      case wasm::WASM_TYPE_F32:
-      case wasm::WASM_TYPE_F64:
-      case wasm::WASM_TYPE_V128:
-      case wasm::WASM_TYPE_FUNCREF:
-      case wasm::WASM_TYPE_EXTERNREF:
-        return wasm::ValType(Code);
-    }
-    if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
-      /* Discard HeapType */ readVarint64(Ctx);
-    }
-    return wasm::ValType(wasm::ValType::OTHERREF);
-  };
   auto parseFieldDef = [&]() {
     uint32_t TypeCode = readVaruint32((Ctx));
-    /* Discard StorageType */ parseValType(TypeCode);
+    /* Discard StorageType */ parseValType(Ctx, TypeCode);
     uint32_t Mutability = readVaruint32(Ctx);
     llvm::errs() << llvm:: format(" mut %d ", Mutability);
   };
@@ -1184,14 +1206,14 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
     llvm::errs() << llvm::format("param ct %d ", ParamCount);
     while (ParamCount--) {
       uint32_t ParamType = readUint8(Ctx);
-      Sig.Returns.push_back(parseValType(ParamType));
+      Sig.Returns.push_back(parseValType(Ctx, ParamType));
       continue;
     }
     uint32_t ReturnCount = readVaruint32(Ctx);
     llvm::errs() << llvm::format("\nreturn ct %d ", ReturnCount);
     while (ReturnCount--) {
       uint32_t ReturnType = readUint8(Ctx);
-      Sig.Returns.push_back(parseValType(ReturnType));
+      Sig.Returns.push_back(parseValType(Ctx, ReturnType));
     }
     
     Signatures.push_back(std::move(Sig));
@@ -1350,8 +1372,12 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
   while (Count--) {
     wasm::WasmGlobal Global;
     Global.Index = NumImportedGlobals + Globals.size();
-    Global.Type.Type = readUint8(Ctx);
+    auto GlobalOpcode = readVaruint32(Ctx);
+    auto GlobalType = parseValType(Ctx, GlobalOpcode);
+    //assert(GlobalType <= std::numeric_limits<wasm::ValType>::max());
+    Global.Type.Type = (uint8_t)GlobalType;
     Global.Type.Mutable = readVaruint1(Ctx);
+    llvm::errs() << llvm::format("Read global %d index %d, type %x mut %d\n", Globals.capacity() -Count-1, Global.Index, GlobalOpcode, Global.Type.Mutable);
     if (Error Err = readInitExpr(Global.InitExpr, Ctx))
       return Err;
     Globals.push_back(Global);

>From 9a524b5431a49e3103230108573d43e8b2df4bd4 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 4 Jan 2024 14:47:13 -0800
Subject: [PATCH 05/11] fix params

---
 llvm/lib/Object/WasmObjectFile.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 4d33bf82ec43078..13234e0ad2f28f9 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1206,7 +1206,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
     llvm::errs() << llvm::format("param ct %d ", ParamCount);
     while (ParamCount--) {
       uint32_t ParamType = readUint8(Ctx);
-      Sig.Returns.push_back(parseValType(Ctx, ParamType));
+      Sig.Params.push_back(parseValType(Ctx, ParamType));
       continue;
     }
     uint32_t ReturnCount = readVaruint32(Ctx);

>From 2d3c70fd4c45087943d7040164c2c6a4bb181c7b Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Thu, 4 Jan 2024 15:11:20 -0800
Subject: [PATCH 06/11] add GC opcodes not used by dart sample

---
 llvm/include/llvm/BinaryFormat/Wasm.h | 4 ++++
 llvm/lib/Object/WasmObjectFile.cpp    | 4 ++++
 2 files changed, 8 insertions(+)

diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index a378b20ded75fd7..395f0ab6d2465f0 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -324,7 +324,11 @@ enum : unsigned {
 enum : unsigned {
   WASM_OPCODE_STRUCT_NEW = 0x00,
   WASM_OPCODE_STRUCT_NEW_DEFAULT = 0x01,
+  WASM_OPCODE_ARRAY_NEW = 0x06,
+  WASM_OPCODE_ARRAY_NEW_DEFAULT = 0x07,
   WASM_OPCODE_ARRAY_NEW_FIXED = 0x08,
+  WASM_OPCODE_REF_I31 = 0x1c,
+  // any.convert_extern and extern.convert_any don't seem to be supported by Binaryen.
 };
 
 // Opcodes used in synthetic functions.
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 13234e0ad2f28f9..1bd2b8e75b6ba31 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -267,12 +267,16 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
       // general opcodes used in init exprs.
       case wasm::WASM_OPCODE_STRUCT_NEW:
       case wasm::WASM_OPCODE_STRUCT_NEW_DEFAULT:
+      case wasm::WASM_OPCODE_ARRAY_NEW:
+      case wasm::WASM_OPCODE_ARRAY_NEW_DEFAULT:
         readULEB128(Ctx); // heap type index
         break;
       case wasm::WASM_OPCODE_ARRAY_NEW_FIXED:
         readULEB128(Ctx); // heap type index
         readULEB128(Ctx); // array size
         break;
+      case wasm::WASM_OPCODE_REF_I31:
+        break;
       case wasm::WASM_OPCODE_END:
         Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);
         llvm::errs() << "\n";

>From db8bd762f77a7cd3c4ebe45817a89ad9b222c1ad Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Mon, 8 Jan 2024 16:59:47 -0800
Subject: [PATCH 07/11] passes tests, doesn't choke on multi-table.wast

---
 llvm/include/llvm/BinaryFormat/Wasm.h |  7 ++--
 llvm/lib/Object/WasmObjectFile.cpp    | 59 ++++++++++++++++++++-------
 2 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 395f0ab6d2465f0..b48048a38e77f7a 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -81,7 +81,7 @@ struct WasmLimits {
 };
 
 struct WasmTableType {
-  uint8_t ElemType;
+  uint8_t ElemType; // TODO: make this a ValType?
   WasmLimits Limits;
 };
 
@@ -110,7 +110,7 @@ struct WasmInitExpr {
 };
 
 struct WasmGlobalType {
-  uint8_t Type;
+  uint8_t Type; // TODO: make this a ValType?
   bool Mutable;
 };
 
@@ -363,7 +363,8 @@ enum : unsigned {
 
 enum : unsigned {
   WASM_ELEM_SEGMENT_IS_PASSIVE = 0x01,
-  WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02,
+  WASM_ELEM_SEGMENT_IS_DECLARATIVE = 0x02, // if passive == 1
+  WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02, // if passive == 0
   WASM_ELEM_SEGMENT_HAS_INIT_EXPRS = 0x04,
 };
 const unsigned WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND = 0x3;
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 1bd2b8e75b6ba31..e3ffea5f8ce20be 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -303,7 +303,8 @@ static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
 
 static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
   wasm::WasmTableType TableType;
-  TableType.ElemType = readUint8(Ctx);
+  auto ElemType = parseValType(Ctx, readVaruint32(Ctx));
+  TableType.ElemType = (uint8_t)ElemType;
   TableType.Limits = readLimits(Ctx);
   return TableType;
 }
@@ -1617,7 +1618,15 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
       return make_error<GenericBinaryError>(
           "Unsupported flags for element segment", object_error::parse_failed);
 
-    if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
+    bool IsPassive = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) != 0;
+    bool IsDeclarative = IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE);
+    bool HasTableNumber = !IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER);
+    bool HasInitExprs = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
+    bool HasElemKind = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) && !HasInitExprs;
+
+    llvm::errs() << llvm::format("segment %d flags %x, InitExprs %d HasKind %d\n",
+      ElemSegments.capacity() - Count-1, Segment.Flags, HasInitExprs,HasElemKind);
+    if (HasTableNumber)
       Segment.TableNumber = readVaruint32(Ctx);
     else
       Segment.TableNumber = 0;
@@ -1625,41 +1634,61 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
       return make_error<GenericBinaryError>("invalid TableNumber",
                                             object_error::parse_failed);
 
-    if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
+    if (IsDeclarative && false) {
+      // Declarative segments are not used or understood by LLVM
+      /* Discard type/kind */ readVaruint32(Ctx);
+      auto DeclCount = readVaruint32(Ctx);
+      while(DeclCount--) {
+        readVaruint32(Ctx);
+      }
+      // Dummy element?
+
+    }
+    if (IsPassive || IsDeclarative) {
       Segment.Offset.Extended = false;
       Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
       Segment.Offset.Inst.Value.Int32 = 0;
     } else {
       if (Error Err = readInitExpr(Segment.Offset, Ctx))
         return Err;
+      llvm::errs() << llvm::format( " active seg, read initexpr opcode %x\n", Segment.Offset.Inst.Opcode);
     }
 
-    if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
+    if (HasElemKind) {
       Segment.ElemKind = readUint8(Ctx);
       if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
         if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
-            Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF)) {
-          return make_error<GenericBinaryError>("invalid reference type",
+            Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF) &&
+            Segment.ElemKind != uint8_t(wasm::ValType::OTHERREF)) {
+          return make_error<GenericBinaryError>("invalid elem type",
                                                 object_error::parse_failed);
         }
       } else {
         if (Segment.ElemKind != 0)
-          return make_error<GenericBinaryError>("invalid elemtype",
+          return make_error<GenericBinaryError>("invalid elem type",
                                                 object_error::parse_failed);
         Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
       }
+    } else if (HasInitExprs) {
+      auto ElemType = parseValType(Ctx, readVaruint32(Ctx));
+      Segment.ElemKind = uint8_t(ElemType);
     } else {
-      Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
+      Segment.ElemKind = (uint8_t)wasm::ValType::FUNCREF;
     }
 
-    if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS)
-      return make_error<GenericBinaryError>(
-          "elem segment init expressions not yet implemented",
-          object_error::parse_failed);
-
     uint32_t NumElems = readVaruint32(Ctx);
-    while (NumElems--) {
-      Segment.Functions.push_back(readVaruint32(Ctx));
+    llvm::errs() << llvm::format(" num elems %d\n", NumElems);
+
+    if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
+      while(NumElems--) {
+        wasm::WasmInitExpr Expr;
+        if(Error Err = readInitExpr(Expr, Ctx))
+          return Err;
+      }
+    } else {
+      while (NumElems--) {
+        Segment.Functions.push_back(readVaruint32(Ctx));
+      }
     }
     ElemSegments.push_back(Segment);
   }

>From 04e8a530b40b93ebd2ed3f0f6ed6699435aae2ae Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 12 Jan 2024 17:17:40 -0800
Subject: [PATCH 08/11] Make TableType a ValType

---
 lld/wasm/InputFiles.cpp                       |   2 +-
 lld/wasm/SymbolTable.cpp                      |   4 +-
 llvm/include/llvm/BinaryFormat/Wasm.h         | 417 +++++++++---------
 llvm/include/llvm/BinaryFormat/WasmTraits.h   |   4 +-
 llvm/include/llvm/MC/MCSymbolWasm.h           |   4 +-
 llvm/lib/MC/WasmObjectWriter.cpp              |   4 +-
 llvm/lib/Object/WasmObjectFile.cpp            |  29 +-
 llvm/lib/ObjectYAML/WasmYAML.cpp              |   7 +-
 .../AsmParser/WebAssemblyAsmParser.cpp        |   2 +-
 .../WebAssembly/WebAssemblyUtilities.cpp      |   2 +-
 llvm/tools/obj2yaml/wasm2yaml.cpp             |   4 +-
 11 files changed, 244 insertions(+), 235 deletions(-)

diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 5709a5ced584c72..97c88587231ba93 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -320,7 +320,7 @@ void ObjFile::addLegacyIndirectFunctionTableIfNeeded(
   // it has an unexpected name or type, assume that it's not actually the
   // indirect function table.
   if (tableImport->Field != functionTableName ||
-      tableImport->Table.ElemType != uint8_t(ValType::FUNCREF)) {
+      tableImport->Table.ElemType != ValType::FUNCREF) {
     error(toString(this) + ": table import " + Twine(tableImport->Field) +
           " is missing a symbol table entry.");
     return;
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index 76370525c371995..b5c138cd76392d2 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -676,7 +676,7 @@ Symbol *SymbolTable::addUndefinedTag(StringRef name,
 TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
   WasmLimits limits{0, 0, 0}; // Set by the writer.
   WasmTableType *type = make<WasmTableType>();
-  type->ElemType = uint8_t(ValType::FUNCREF);
+  type->ElemType = ValType::FUNCREF;
   type->Limits = limits;
   StringRef module(defaultModule);
   uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
@@ -690,7 +690,7 @@ TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
 TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) {
   const uint32_t invalidIndex = -1;
   WasmLimits limits{0, 0, 0}; // Set by the writer.
-  WasmTableType type{uint8_t(ValType::FUNCREF), limits};
+  WasmTableType type{ValType::FUNCREF, limits};
   WasmTable desc{invalidIndex, type, name};
   InputTable *table = make<InputTable>(desc, nullptr);
   uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN;
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index b48048a38e77f7a..1e7ece3363caa26 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -31,213 +31,6 @@ const uint32_t WasmMetadataVersion = 0x2;
 // Wasm uses a 64k page size
 const uint32_t WasmPageSize = 65536;
 
-struct WasmObjectHeader {
-  StringRef Magic;
-  uint32_t Version;
-};
-
-struct WasmDylinkImportInfo {
-  StringRef Module;
-  StringRef Field;
-  uint32_t Flags;
-};
-
-struct WasmDylinkExportInfo {
-  StringRef Name;
-  uint32_t Flags;
-};
-
-struct WasmDylinkInfo {
-  uint32_t MemorySize; // Memory size in bytes
-  uint32_t MemoryAlignment;  // P2 alignment of memory
-  uint32_t TableSize;  // Table size in elements
-  uint32_t TableAlignment;  // P2 alignment of table
-  std::vector<StringRef> Needed; // Shared library dependencies
-  std::vector<WasmDylinkImportInfo> ImportInfo;
-  std::vector<WasmDylinkExportInfo> ExportInfo;
-};
-
-struct WasmProducerInfo {
-  std::vector<std::pair<std::string, std::string>> Languages;
-  std::vector<std::pair<std::string, std::string>> Tools;
-  std::vector<std::pair<std::string, std::string>> SDKs;
-};
-
-struct WasmFeatureEntry {
-  uint8_t Prefix;
-  std::string Name;
-};
-
-struct WasmExport {
-  StringRef Name;
-  uint8_t Kind;
-  uint32_t Index;
-};
-
-struct WasmLimits {
-  uint8_t Flags;
-  uint64_t Minimum;
-  uint64_t Maximum;
-};
-
-struct WasmTableType {
-  uint8_t ElemType; // TODO: make this a ValType?
-  WasmLimits Limits;
-};
-
-struct WasmTable {
-  uint32_t Index;
-  WasmTableType Type;
-  StringRef SymbolName; // from the "linking" section
-};
-
-struct WasmInitExprMVP {
-  uint8_t Opcode;
-  union {
-    int32_t Int32;
-    int64_t Int64;
-    uint32_t Float32;
-    uint64_t Float64;
-    uint32_t Global;
-  } Value;
-};
-
-struct WasmInitExpr {
-  uint8_t Extended; // Set to non-zero if extended const is used (i.e. more than
-                    // one instruction)
-  WasmInitExprMVP Inst;
-  ArrayRef<uint8_t> Body;
-};
-
-struct WasmGlobalType {
-  uint8_t Type; // TODO: make this a ValType?
-  bool Mutable;
-};
-
-struct WasmGlobal {
-  uint32_t Index;
-  WasmGlobalType Type;
-  WasmInitExpr InitExpr;
-  StringRef SymbolName; // from the "linking" section
-};
-
-struct WasmTag {
-  uint32_t Index;
-  uint32_t SigIndex;
-  StringRef SymbolName; // from the "linking" section
-};
-
-struct WasmImport {
-  StringRef Module;
-  StringRef Field;
-  uint8_t Kind;
-  union {
-    uint32_t SigIndex;
-    WasmGlobalType Global;
-    WasmTableType Table;
-    WasmLimits Memory;
-  };
-};
-
-struct WasmLocalDecl {
-  uint8_t Type;
-  uint32_t Count;
-};
-
-struct WasmFunction {
-  uint32_t Index;
-  uint32_t SigIndex;
-  std::vector<WasmLocalDecl> Locals;
-  ArrayRef<uint8_t> Body;
-  uint32_t CodeSectionOffset;
-  uint32_t Size;
-  uint32_t CodeOffset;  // start of Locals and Body
-  std::optional<StringRef> ExportName; // from the "export" section
-  StringRef SymbolName; // from the "linking" section
-  StringRef DebugName;  // from the "name" section
-  uint32_t Comdat;      // from the "comdat info" section
-};
-
-struct WasmDataSegment {
-  uint32_t InitFlags;
-  // Present if InitFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX.
-  uint32_t MemoryIndex;
-  // Present if InitFlags & WASM_DATA_SEGMENT_IS_PASSIVE == 0.
-  WasmInitExpr Offset;
-
-  ArrayRef<uint8_t> Content;
-  StringRef Name; // from the "segment info" section
-  uint32_t Alignment;
-  uint32_t LinkingFlags;
-  uint32_t Comdat; // from the "comdat info" section
-};
-
-struct WasmElemSegment {
-  uint32_t Flags;
-  uint32_t TableNumber;
-  uint8_t ElemKind;
-  WasmInitExpr Offset;
-  std::vector<uint32_t> Functions;
-};
-
-// Represents the location of a Wasm data symbol within a WasmDataSegment, as
-// the index of the segment, and the offset and size within the segment.
-struct WasmDataReference {
-  uint32_t Segment;
-  uint64_t Offset;
-  uint64_t Size;
-};
-
-struct WasmRelocation {
-  uint8_t Type;    // The type of the relocation.
-  uint32_t Index;  // Index into either symbol or type index space.
-  uint64_t Offset; // Offset from the start of the section.
-  int64_t Addend;  // A value to add to the symbol.
-};
-
-struct WasmInitFunc {
-  uint32_t Priority;
-  uint32_t Symbol;
-};
-
-struct WasmSymbolInfo {
-  StringRef Name;
-  uint8_t Kind;
-  uint32_t Flags;
-  // For undefined symbols the module of the import
-  std::optional<StringRef> ImportModule;
-  // For undefined symbols the name of the import
-  std::optional<StringRef> ImportName;
-  // For symbols to be exported from the final module
-  std::optional<StringRef> ExportName;
-  union {
-    // For function, table, or global symbols, the index in function, table, or
-    // global index space.
-    uint32_t ElementIndex;
-    // For a data symbols, the address of the data relative to segment.
-    WasmDataReference DataRef;
-  };
-};
-
-enum class NameType {
-  FUNCTION,
-  GLOBAL,
-  DATA_SEGMENT,
-};
-
-struct WasmDebugName {
-  NameType Type;
-  uint32_t Index;
-  StringRef Name;
-};
-
-struct WasmLinkingData {
-  uint32_t Version;
-  std::vector<WasmInitFunc> InitFunctions;
-  std::vector<StringRef> Comdats;
-  std::vector<WasmSymbolInfo> SymbolTable;
-};
-
 enum : unsigned {
   WASM_SEC_CUSTOM = 0,     // Custom / User-defined section
   WASM_SEC_TYPE = 1,       // Function signature declarations
@@ -452,6 +245,11 @@ enum : unsigned {
 
 #undef WASM_RELOC
 
+struct WasmObjectHeader {
+  StringRef Magic;
+  uint32_t Version;
+};
+
 // Subset of types that a value can have
 enum class ValType {
   I32 = WASM_TYPE_I32,
@@ -461,7 +259,210 @@ enum class ValType {
   V128 = WASM_TYPE_V128,
   FUNCREF = WASM_TYPE_FUNCREF,
   EXTERNREF = WASM_TYPE_EXTERNREF,
-  OTHERREF, // Unmodeled value types include ref types with heap types other than funcref or externref
+  OTHERREF = 0xff, // Unmodeled value types include ref types with heap types other than funcref or externref
+};
+
+struct WasmDylinkImportInfo {
+  StringRef Module;
+  StringRef Field;
+  uint32_t Flags;
+};
+
+struct WasmDylinkExportInfo {
+  StringRef Name;
+  uint32_t Flags;
+};
+
+struct WasmDylinkInfo {
+  uint32_t MemorySize; // Memory size in bytes
+  uint32_t MemoryAlignment;  // P2 alignment of memory
+  uint32_t TableSize;  // Table size in elements
+  uint32_t TableAlignment;  // P2 alignment of table
+  std::vector<StringRef> Needed; // Shared library dependencies
+  std::vector<WasmDylinkImportInfo> ImportInfo;
+  std::vector<WasmDylinkExportInfo> ExportInfo;
+};
+
+struct WasmProducerInfo {
+  std::vector<std::pair<std::string, std::string>> Languages;
+  std::vector<std::pair<std::string, std::string>> Tools;
+  std::vector<std::pair<std::string, std::string>> SDKs;
+};
+
+struct WasmFeatureEntry {
+  uint8_t Prefix;
+  std::string Name;
+};
+
+struct WasmExport {
+  StringRef Name;
+  uint8_t Kind;
+  uint32_t Index;
+};
+
+struct WasmLimits {
+  uint8_t Flags;
+  uint64_t Minimum;
+  uint64_t Maximum;
+};
+
+
+struct WasmTableType {
+  ValType ElemType;
+  WasmLimits Limits;
+};
+
+struct WasmTable {
+  uint32_t Index;
+  WasmTableType Type;
+  StringRef SymbolName; // from the "linking" section
+};
+
+struct WasmInitExprMVP {
+  uint8_t Opcode;
+  union {
+    int32_t Int32;
+    int64_t Int64;
+    uint32_t Float32;
+    uint64_t Float64;
+    uint32_t Global;
+  } Value;
+};
+
+struct WasmInitExpr {
+  uint8_t Extended; // Set to non-zero if extended const is used (i.e. more than
+                    // one instruction)
+  WasmInitExprMVP Inst;
+  ArrayRef<uint8_t> Body;
+};
+
+struct WasmGlobalType {
+  uint8_t Type; // TODO: make this a ValType?
+  bool Mutable;
+};
+
+struct WasmGlobal {
+  uint32_t Index;
+  WasmGlobalType Type;
+  WasmInitExpr InitExpr;
+  StringRef SymbolName; // from the "linking" section
+};
+
+struct WasmTag {
+  uint32_t Index;
+  uint32_t SigIndex;
+  StringRef SymbolName; // from the "linking" section
+};
+
+struct WasmImport {
+  StringRef Module;
+  StringRef Field;
+  uint8_t Kind;
+  union {
+    uint32_t SigIndex;
+    WasmGlobalType Global;
+    WasmTableType Table;
+    WasmLimits Memory;
+  };
+};
+
+struct WasmLocalDecl {
+  uint8_t Type;
+  uint32_t Count;
+};
+
+struct WasmFunction {
+  uint32_t Index;
+  uint32_t SigIndex;
+  std::vector<WasmLocalDecl> Locals;
+  ArrayRef<uint8_t> Body;
+  uint32_t CodeSectionOffset;
+  uint32_t Size;
+  uint32_t CodeOffset;  // start of Locals and Body
+  std::optional<StringRef> ExportName; // from the "export" section
+  StringRef SymbolName; // from the "linking" section
+  StringRef DebugName;  // from the "name" section
+  uint32_t Comdat;      // from the "comdat info" section
+};
+
+struct WasmDataSegment {
+  uint32_t InitFlags;
+  // Present if InitFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX.
+  uint32_t MemoryIndex;
+  // Present if InitFlags & WASM_DATA_SEGMENT_IS_PASSIVE == 0.
+  WasmInitExpr Offset;
+
+  ArrayRef<uint8_t> Content;
+  StringRef Name; // from the "segment info" section
+  uint32_t Alignment;
+  uint32_t LinkingFlags;
+  uint32_t Comdat; // from the "comdat info" section
+};
+
+struct WasmElemSegment {
+  uint32_t Flags;
+  uint32_t TableNumber;
+  ValType ElemKind;
+  WasmInitExpr Offset;
+  std::vector<uint32_t> Functions;
+};
+
+// Represents the location of a Wasm data symbol within a WasmDataSegment, as
+// the index of the segment, and the offset and size within the segment.
+struct WasmDataReference {
+  uint32_t Segment;
+  uint64_t Offset;
+  uint64_t Size;
+};
+
+struct WasmRelocation {
+  uint8_t Type;    // The type of the relocation.
+  uint32_t Index;  // Index into either symbol or type index space.
+  uint64_t Offset; // Offset from the start of the section.
+  int64_t Addend;  // A value to add to the symbol.
+};
+
+struct WasmInitFunc {
+  uint32_t Priority;
+  uint32_t Symbol;
+};
+
+struct WasmSymbolInfo {
+  StringRef Name;
+  uint8_t Kind;
+  uint32_t Flags;
+  // For undefined symbols the module of the import
+  std::optional<StringRef> ImportModule;
+  // For undefined symbols the name of the import
+  std::optional<StringRef> ImportName;
+  // For symbols to be exported from the final module
+  std::optional<StringRef> ExportName;
+  union {
+    // For function, table, or global symbols, the index in function, table, or
+    // global index space.
+    uint32_t ElementIndex;
+    // For a data symbols, the address of the data relative to segment.
+    WasmDataReference DataRef;
+  };
+};
+
+enum class NameType {
+  FUNCTION,
+  GLOBAL,
+  DATA_SEGMENT,
+};
+
+struct WasmDebugName {
+  NameType Type;
+  uint32_t Index;
+  StringRef Name;
+};
+
+struct WasmLinkingData {
+  uint32_t Version;
+  std::vector<WasmInitFunc> InitFunctions;
+  std::vector<StringRef> Comdats;
+  std::vector<WasmSymbolInfo> SymbolTable;
 };
 
 // Represents anything that can be encoded in the type section, but only
diff --git a/llvm/include/llvm/BinaryFormat/WasmTraits.h b/llvm/include/llvm/BinaryFormat/WasmTraits.h
index bef9dd3291ca76e..a279ce37a791ed9 100644
--- a/llvm/include/llvm/BinaryFormat/WasmTraits.h
+++ b/llvm/include/llvm/BinaryFormat/WasmTraits.h
@@ -87,11 +87,11 @@ template <> struct DenseMapInfo<wasm::WasmLimits, void> {
 template <> struct DenseMapInfo<wasm::WasmTableType, void> {
   static wasm::WasmTableType getEmptyKey() {
     return wasm::WasmTableType{
-        0, DenseMapInfo<wasm::WasmLimits, void>::getEmptyKey()};
+        wasm::ValType(0), DenseMapInfo<wasm::WasmLimits, void>::getEmptyKey()};
   }
   static wasm::WasmTableType getTombstoneKey() {
     return wasm::WasmTableType{
-        1, DenseMapInfo<wasm::WasmLimits, void>::getTombstoneKey()};
+        wasm::ValType(1), DenseMapInfo<wasm::WasmLimits, void>::getTombstoneKey()};
   }
   static unsigned getHashValue(const wasm::WasmTableType &TableType) {
     return hash_combine(
diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h
index c67bd64e7cbdfda..0ce95c72a73f702 100644
--- a/llvm/include/llvm/MC/MCSymbolWasm.h
+++ b/llvm/include/llvm/MC/MCSymbolWasm.h
@@ -112,7 +112,7 @@ class MCSymbolWasm : public MCSymbol {
 
   bool isFunctionTable() const {
     return isTable() && hasTableType() &&
-           getTableType().ElemType == wasm::WASM_TYPE_FUNCREF;
+           getTableType().ElemType == wasm::ValType::FUNCREF;
   }
   void setFunctionTable() {
     setType(wasm::WASM_SYMBOL_TYPE_TABLE);
@@ -144,7 +144,7 @@ class MCSymbolWasm : public MCSymbol {
     // Declare a table with element type VT and no limits (min size 0, no max
     // size).
     wasm::WasmLimits Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0};
-    setTableType({uint8_t(VT), Limits});
+    setTableType({VT, Limits});
   }
 };
 
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index e43f111113b408f..9d8770271163eae 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -972,7 +972,9 @@ void WasmObjectWriter::writeTableSection(ArrayRef<wasm::WasmTable> Tables) {
 
   encodeULEB128(Tables.size(), W->OS);
   for (const wasm::WasmTable &Table : Tables) {
-    encodeULEB128(Table.Type.ElemType, W->OS);
+    llvm::errs() << "Table " << Table.Index << std::string(Table.SymbolName) << " type " << (uint32_t)Table.Type.ElemType << "\n";
+    assert(Table.Type.ElemType != wasm::ValType::OTHERREF && "Cannot encode general ref-typed tables");
+    encodeULEB128((uint32_t)Table.Type.ElemType, W->OS);
     encodeULEB128(Table.Type.Limits.Flags, W->OS);
     encodeULEB128(Table.Type.Limits.Minimum, W->OS);
     if (Table.Type.Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index e3ffea5f8ce20be..b67b815ed2b72d7 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -304,7 +304,7 @@ static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
 static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
   wasm::WasmTableType TableType;
   auto ElemType = parseValType(Ctx, readVaruint32(Ctx));
-  TableType.ElemType = (uint8_t)ElemType;
+  TableType.ElemType = ElemType;
   TableType.Limits = readLimits(Ctx);
   return TableType;
 }
@@ -1261,8 +1261,9 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
       Im.Table = readTableType(Ctx);
       NumImportedTables++;
       auto ElemType = Im.Table.ElemType;
-      if (ElemType != wasm::WASM_TYPE_FUNCREF &&
-          ElemType != wasm::WASM_TYPE_EXTERNREF)
+      if (ElemType != wasm::ValType::FUNCREF &&
+          ElemType != wasm::ValType::EXTERNREF &&
+          ElemType != wasm::ValType::OTHERREF)
         return make_error<GenericBinaryError>("invalid table element type",
                                               object_error::parse_failed);
       break;
@@ -1318,8 +1319,9 @@ Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
     T.Index = NumImportedTables + Tables.size();
     Tables.push_back(T);
     auto ElemType = Tables.back().Type.ElemType;
-    if (ElemType != wasm::WASM_TYPE_FUNCREF &&
-        ElemType != wasm::WASM_TYPE_EXTERNREF) {
+    if (ElemType != wasm::ValType::FUNCREF &&
+        ElemType != wasm::ValType::EXTERNREF &&
+        ElemType != wasm::ValType::OTHERREF) {
       return make_error<GenericBinaryError>("invalid table element type",
                                             object_error::parse_failed);
     }
@@ -1655,25 +1657,26 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
     }
 
     if (HasElemKind) {
-      Segment.ElemKind = readUint8(Ctx);
+      auto ElemKind = readVaruint32(Ctx);
       if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
-        if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
-            Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF) &&
-            Segment.ElemKind != uint8_t(wasm::ValType::OTHERREF)) {
+        Segment.ElemKind = parseValType(Ctx, ElemKind);
+        if (Segment.ElemKind != wasm::ValType::FUNCREF &&
+            Segment.ElemKind != wasm::ValType::EXTERNREF &&
+            Segment.ElemKind != wasm::ValType::OTHERREF) {
           return make_error<GenericBinaryError>("invalid elem type",
                                                 object_error::parse_failed);
         }
       } else {
-        if (Segment.ElemKind != 0)
+        if (ElemKind != 0)
           return make_error<GenericBinaryError>("invalid elem type",
                                                 object_error::parse_failed);
-        Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
+        Segment.ElemKind = wasm::ValType::FUNCREF;
       }
     } else if (HasInitExprs) {
       auto ElemType = parseValType(Ctx, readVaruint32(Ctx));
-      Segment.ElemKind = uint8_t(ElemType);
+      Segment.ElemKind = ElemType;
     } else {
-      Segment.ElemKind = (uint8_t)wasm::ValType::FUNCREF;
+      Segment.ElemKind = wasm::ValType::FUNCREF;
     }
 
     uint32_t NumElems = readVaruint32(Ctx);
diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp
index 9502fe5e4077881..797902e31ac32ff 100644
--- a/llvm/lib/ObjectYAML/WasmYAML.cpp
+++ b/llvm/lib/ObjectYAML/WasmYAML.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm/ObjectYAML/WasmYAML.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/YAMLTraits.h"
@@ -593,7 +594,8 @@ void ScalarEnumerationTraits<WasmYAML::SymbolKind>::enumeration(
 
 void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration(
     IO &IO, WasmYAML::ValueType &Type) {
-#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X);
+#define CONCAT(X) (uint32_t)wasm::ValType::X
+#define ECase(X) IO.enumCase(Type, #X, CONCAT(X));
   ECase(I32);
   ECase(I64);
   ECase(F32);
@@ -601,7 +603,8 @@ void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration(
   ECase(V128);
   ECase(FUNCREF);
   ECase(EXTERNREF);
-  ECase(FUNC);
+  ECase(OTHERREF);
+  //ECase(FUNC);
 #undef ECase
 }
 
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 1b92997f03f11c9..3cc4d50271eb114 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -851,7 +851,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
       // symbol
       auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName));
       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
-      wasm::WasmTableType Type = {uint8_t(*ElemType), Limits};
+      wasm::WasmTableType Type = {*ElemType, Limits};
       WasmSym->setTableType(Type);
       TOut.emitTableType(WasmSym);
       return expect(AsmToken::EndOfStatement, "EOL");
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
index 189111cef7d0a04..ac7cf5b37fcaa49 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
@@ -134,7 +134,7 @@ MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol(
     Sym->setWeak(true);
 
     wasm::WasmLimits Limits = {0, 1, 1};
-    wasm::WasmTableType TableType = {wasm::WASM_TYPE_FUNCREF, Limits};
+    wasm::WasmTableType TableType = {wasm::ValType::FUNCREF, Limits};
     Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
     Sym->setTableType(TableType);
   }
diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp
index 8557a38405193bb..c15d64cef8d65e4 100644
--- a/llvm/tools/obj2yaml/wasm2yaml.cpp
+++ b/llvm/tools/obj2yaml/wasm2yaml.cpp
@@ -44,7 +44,7 @@ static WasmYAML::Table makeTable(uint32_t Index,
                                  const wasm::WasmTableType &Type) {
   WasmYAML::Table T;
   T.Index = Index;
-  T.ElemType = Type.ElemType;
+  T.ElemType = (uint32_t)Type.ElemType;
   T.TableLimits = makeLimits(Type.Limits);
   return T;
 }
@@ -334,7 +334,7 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
         WasmYAML::ElemSegment Seg;
         Seg.Flags = Segment.Flags;
         Seg.TableNumber = Segment.TableNumber;
-        Seg.ElemKind = Segment.ElemKind;
+        Seg.ElemKind = (uint32_t)Segment.ElemKind;
         Seg.Offset.Extended = Segment.Offset.Extended;
         if (Seg.Offset.Extended) {
           Seg.Offset.Body = yaml::BinaryRef(Segment.Offset.Body);

>From 64e0ae785149714ac848833dc4af34ab28e95ef9 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Fri, 19 Jan 2024 16:11:01 -0800
Subject: [PATCH 09/11] obj2yaml dumps elemkind

---
 lld/wasm/WriterUtils.cpp                      |   2 +
 llvm/include/llvm/BinaryFormat/Wasm.h         |   4 +-
 llvm/lib/Object/WasmObjectFile.cpp            |   7 +-
 llvm/lib/ObjectYAML/WasmYAML.cpp              |   5 +-
 .../WebAssembly/WebAssemblyAsmPrinter.cpp     |   3 +-
 llvm/test/Object/Inputs/WASM/multi-table.wasm | Bin 0 -> 185 bytes
 llvm/test/Object/wasm-obj2yaml-tables.test    | 112 ++++++++++++++++++
 7 files changed, 127 insertions(+), 6 deletions(-)
 create mode 100644 llvm/test/Object/Inputs/WASM/multi-table.wasm
 create mode 100644 llvm/test/Object/wasm-obj2yaml-tables.test

diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp
index cc8ed0b1de23712..02c8dd677f635aa 100644
--- a/lld/wasm/WriterUtils.cpp
+++ b/lld/wasm/WriterUtils.cpp
@@ -35,6 +35,8 @@ std::string toString(ValType type) {
     return "funcref";
   case ValType::EXTERNREF:
     return "externref";
+  case ValType::OTHERREF:
+    return "otherref";
   }
   llvm_unreachable("Invalid wasm::ValType");
 }
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 9dbed31c21ffffd..2bcd87039ceb00f 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -259,7 +259,9 @@ enum class ValType {
   V128 = WASM_TYPE_V128,
   FUNCREF = WASM_TYPE_FUNCREF,
   EXTERNREF = WASM_TYPE_EXTERNREF,
-  OTHERREF = 0xff, // Unmodeled value types include ref types with heap types other than funcref or externref
+  // Unmodeled value types include ref types with heap types other than
+  // funcr or extern, and type-specialized funcrefs
+  OTHERREF = 0xff,
 };
 
 struct WasmDylinkImportInfo {
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index b67b815ed2b72d7..6edab3e0502d132 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1626,10 +1626,11 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
     bool HasInitExprs = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
     bool HasElemKind = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) && !HasInitExprs;
 
-    llvm::errs() << llvm::format("segment %d flags %x, InitExprs %d HasKind %d\n",
+    llvm::errs() << llvm::format("\nsegment %d flags %x, InitExprs %d HasKind %d\n",
       ElemSegments.capacity() - Count-1, Segment.Flags, HasInitExprs,HasElemKind);
-    if (HasTableNumber)
+    if (HasTableNumber) {
       Segment.TableNumber = readVaruint32(Ctx);
+      llvm::errs() << " table " << Segment.TableNumber << "\n"; }
     else
       Segment.TableNumber = 0;
     if (!isValidTableNumber(Segment.TableNumber))
@@ -1682,7 +1683,7 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
     uint32_t NumElems = readVaruint32(Ctx);
     llvm::errs() << llvm::format(" num elems %d\n", NumElems);
 
-    if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
+    if (HasInitExprs) {
       while(NumElems--) {
         wasm::WasmInitExpr Expr;
         if(Error Err = readInitExpr(Expr, Ctx))
diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp
index 797902e31ac32ff..908778daa0304eb 100644
--- a/llvm/lib/ObjectYAML/WasmYAML.cpp
+++ b/llvm/lib/ObjectYAML/WasmYAML.cpp
@@ -384,6 +384,7 @@ void MappingTraits<WasmYAML::ElemSegment>::mapping(
   if (!IO.outputting() ||
       Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND)
     IO.mapOptional("ElemKind", Segment.ElemKind);
+  // TODO: Omit "offset" for passive segments? It's neither meaningful nor encoded.
   IO.mapRequired("Offset", Segment.Offset);
   IO.mapRequired("Functions", Segment.Functions);
 }
@@ -634,9 +635,11 @@ void ScalarEnumerationTraits<WasmYAML::Opcode>::enumeration(
 
 void ScalarEnumerationTraits<WasmYAML::TableType>::enumeration(
     IO &IO, WasmYAML::TableType &Type) {
-#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X);
+#define CONCAT(X) (uint32_t)wasm::ValType::X
+#define ECase(X) IO.enumCase(Type, #X, CONCAT(X));
   ECase(FUNCREF);
   ECase(EXTERNREF);
+  ECase(OTHERREF);
 #undef ECase
 }
 
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 908efbb8d32155d..fb949d4b19a3e12 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -125,8 +125,9 @@ static char getInvokeSig(wasm::ValType VT) {
     return 'F';
   case wasm::ValType::EXTERNREF:
     return 'X';
+  default:
+    llvm_unreachable("Unhandled wasm::ValType enum");
   }
-  llvm_unreachable("Unhandled wasm::ValType enum");
 }
 
 // Given the wasm signature, generate the invoke name in the format JS glue code
diff --git a/llvm/test/Object/Inputs/WASM/multi-table.wasm b/llvm/test/Object/Inputs/WASM/multi-table.wasm
new file mode 100644
index 0000000000000000000000000000000000000000..47f5d8311cb74f76485577df85578b62f896361d
GIT binary patch
literal 185
zcmX|(K at P$&3<P&=ClWCd;>xuz=}#z8j}?*n0KSOwBAkLaSfjDmi)G&kfW|u at g<SYx
zBa52G-mccD+GzF!Dwt9}O9eXog&BTY%K#w^;2<3WW|`<sBKY1t%Pd|otaGHJsp;3^
ZoGR=u)2KtX==*($my0HJxw(SJd;l027?A(~

literal 0
HcmV?d00001

diff --git a/llvm/test/Object/wasm-obj2yaml-tables.test b/llvm/test/Object/wasm-obj2yaml-tables.test
new file mode 100644
index 000000000000000..870ffd179a1c25b
--- /dev/null
+++ b/llvm/test/Object/wasm-obj2yaml-tables.test
@@ -0,0 +1,112 @@
+RUN: obj2yaml %p/Inputs/WASM/multi-table.wasm | FileCheck %s
+
+
+# CHECK:  - Type:            TABLE
+# CHECK:    Tables:
+# CHECK:      - Index:           1
+# CHECK:        ElemType:        FUNCREF
+# CHECK:        Limits:
+# CHECK:          Flags:           [ HAS_MAX ]
+# CHECK:          Minimum:         0x3
+# CHECK:          Maximum:         0x3
+# CHECK:      - Index:           2
+# CHECK:        ElemType:        FUNCREF
+# CHECK:        Limits:
+# CHECK:          Flags:           [ HAS_MAX ]
+# CHECK:          Minimum:         0x4
+# CHECK:          Maximum:         0x4
+# CHECK:      - Index:           3
+# CHECK:        ElemType:        EXTERNREF
+# CHECK:        Limits:
+# CHECK:          Minimum:         0x0
+# CHECK:      - Index:           4
+# CHECK:        ElemType:        OTHERREF
+# CHECK:        Limits:
+# CHECK:          Flags:           [ HAS_MAX ]
+# CHECK:          Minimum:         0x5
+# CHECK:          Maximum:         0x5
+# CHECK:  - Type:            GLOBAL
+# CHECK:    Globals:
+# CHECK:      - Index:           0
+# CHECK:        Type:            OTHERREF
+# CHECK:        Mutable:         false
+# CHECK:        InitExpr:
+# CHECK:          Extended:        true
+# CHECK:          Body:            D2000B
+# CHECK:      - Index:           1
+# CHECK:        Type:            I32
+# CHECK:        Mutable:         false
+# CHECK:        InitExpr:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           0
+# CHECK:  - Type:            ELEM
+# CHECK:    Segments:
+# CHECK:      - Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           0
+# CHECK:        Functions:       [ 0 ]
+# CHECK:      - Flags:           2
+# CHECK:        TableNumber:     1
+# CHECK:        ElemKind:        FUNCREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           0
+# CHECK:        Functions:       [ 0 ]
+# CHECK:      - Flags:           2
+# CHECK:        TableNumber:     1
+# CHECK:        ElemKind:        FUNCREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           1
+# CHECK:        Functions:       [ 0, 1 ]
+# CHECK:      - Flags:           6
+# CHECK:        TableNumber:     2
+# CHECK:        ElemKind:        FUNCREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          GLOBAL_GET
+# CHECK:          Index:           1
+# There are 2 funcions encoded with initexprs in this segment
+# but initexprs in tables are unmodeled.
+# CHECK:        Functions:       [  ]
+# CHECK:      - Flags:           6
+# CHECK:        TableNumber:     2
+# This elemkind is OTHERREF because it's encoded as a typed funcref
+# CHECK:        ElemKind:        OTHERREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           2
+# CHECK:        Functions:       [  ]
+# CHECK:      - Flags:           1
+# CHECK:        ElemKind:        FUNCREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           0
+# CHECK:        Functions:       [ 0, 1 ]
+# CHECK:      - Flags:           5
+# CHECK:        ElemKind:        FUNCREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           0
+# Empty function list, encoded with initexprs
+# CHECK:        Functions:       [  ]
+# CHECK:      - Flags:           5
+# CHECK:        ElemKind:        OTHERREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           0
+# Function list encoded with initexprs
+# CHECK:        Functions:       [  ]
+# CHECK:      - Flags:           1
+# CHECK:        ElemKind:        FUNCREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           0
+# CHECK:        Functions:       [  ]
+# CHECK:      - Flags:           6
+# CHECK:        TableNumber:     4
+# CHECK:        ElemKind:        OTHERREF
+# CHECK:        Offset:
+# CHECK:          Opcode:          I32_CONST
+# CHECK:          Value:           0
+# Function list encoded with initexprs
+# CHECK:        Functions:       [  ]

>From 8d0e4528e2d3fdbed1e951e41a728d62b93513b9 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Tue, 23 Jan 2024 16:36:30 -0800
Subject: [PATCH 10/11] update signature kinds, clang-format

---
 lld/wasm/InputChunks.h                |  5 ++++-
 lld/wasm/InputElement.h               |  4 +++-
 llvm/include/llvm/BinaryFormat/Wasm.h | 12 +++++++++---
 llvm/include/llvm/Object/Wasm.h       |  4 +++-
 llvm/lib/Object/WasmObjectFile.cpp    | 13 +++++++++----
 5 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index 1e430832fb84c72..ad1d45e335eac90 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -259,10 +259,13 @@ class InputFunction : public InputChunk {
         file->codeSection->Content.slice(inputSectionOffset, function->Size);
     debugName = function->DebugName;
     comdat = function->Comdat;
+    assert(s.Kind != WasmSignature::Placeholder);
   }
 
   InputFunction(StringRef name, const WasmSignature &s)
-      : InputChunk(nullptr, InputChunk::Function, name), signature(s) {}
+      : InputChunk(nullptr, InputChunk::Function, name), signature(s) {
+    assert(s.Kind == WasmSignature::Function);
+  }
 
   static bool classof(const InputChunk *c) {
     return c->kind() == InputChunk::Function ||
diff --git a/lld/wasm/InputElement.h b/lld/wasm/InputElement.h
index 46e21d7c7dfd800..10dc2a3e4a826a9 100644
--- a/lld/wasm/InputElement.h
+++ b/lld/wasm/InputElement.h
@@ -76,7 +76,9 @@ class InputGlobal : public InputElement {
 class InputTag : public InputElement {
 public:
   InputTag(const WasmSignature &s, const WasmTag &t, ObjFile *f)
-      : InputElement(t.SymbolName, f), signature(s) {}
+      : InputElement(t.SymbolName, f), signature(s) {
+    assert(s.Kind == WasmSignature::Tag);
+  }
 
   const WasmSignature &signature;
 };
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 2bcd87039ceb00f..9f13cf4e36a855e 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -400,6 +400,11 @@ struct WasmDataSegment {
   uint32_t Comdat; // from the "comdat info" section
 };
 
+// Represents a Wasm element segment, with some limitations compared the spec:
+// 1) Does not model passive or declarative segments (Segment will end up with
+// an Offset field of i32.const 0)
+// 2) Does not model init exprs (Segment will get an empty Functions list)
+// 2) Does not model types other than basic funcref/externref (see ValType)
 struct WasmElemSegment {
   uint32_t Flags;
   uint32_t TableNumber;
@@ -466,12 +471,13 @@ struct WasmLinkingData {
   std::vector<WasmSymbolInfo> SymbolTable;
 };
 
-// Represents anything that can be encoded in the type section, but only
-// signatures are actually modeled. TODO: maybe refactor to make this explicit.
 struct WasmSignature {
   SmallVector<ValType, 1> Returns;
   SmallVector<ValType, 4> Params;
-  enum {Function, Other} Kind = Function; // Recursive, Composite(Array,Struct),  
+  // LLVM can parse types other than functions encoded in the type section,
+  // but does not actually model them. Instead a placeholder signature is
+  // created in the Object's signature list.
+  enum { Function, Tag, Placeholder } Kind = Function;
   // Support empty and tombstone instances, needed by DenseMap.
   enum { Plain, Empty, Tombstone } State = Plain;
 
diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h
index 6b8edb90e144b58..737a6eb9355c64b 100644
--- a/llvm/include/llvm/Object/Wasm.h
+++ b/llvm/include/llvm/Object/Wasm.h
@@ -39,7 +39,9 @@ class WasmSymbol {
              const wasm::WasmTableType *TableType,
              const wasm::WasmSignature *Signature)
       : Info(Info), GlobalType(GlobalType), TableType(TableType),
-        Signature(Signature) {}
+        Signature(Signature) {
+    assert(!Signature || Signature->Kind != wasm::WasmSignature::Placeholder);
+  }
 
   const wasm::WasmSymbolInfo &Info;
   const wasm::WasmGlobalType *GlobalType;
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 6edab3e0502d132..48e351f34057204 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1167,11 +1167,13 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
       // Rec groups expand the type index space (beyond what was declared at
       // the top of the section, and also consume one element in that space.
       uint32_t RecSize = readVaruint32(Ctx);
-      assert(RecSize > 0); // TODO real errors here and below
+      if (RecSize == 0)
+        return make_error<GenericBinaryError>("Rec group size cannot be 0",
+                                              object_error::parse_failed);
       Signatures.reserve(Signatures.size() + RecSize);
       Count += RecSize;
       llvm::errs() << llvm::format(" Rec size %d\n", RecSize);
-      Sig.Kind = wasm::WasmSignature::Other;
+      Sig.Kind = wasm::WasmSignature::Placeholder;
       Signatures.push_back(std::move(Sig));
       continue;
     }
@@ -1182,7 +1184,9 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
       if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {
         uint32_t Supers = readVaruint32(Ctx);
         if (Supers > 0) {
-          assert(Supers == 1);
+          if (Supers != 1)
+            return make_error<GenericBinaryError>(
+                "Invalid number of supertypes", object_error::parse_failed);
           /* Discard SuperIndex */ readVaruint32(Ctx);
         }
         Form = readVaruint32(Ctx);
@@ -1201,7 +1205,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
         llvm::errs() << llvm::format(" bad form %x", Form) << '\n';
         return make_error<GenericBinaryError>("bad form", object_error::parse_failed);
       }
-      Sig.Kind = wasm::WasmSignature::Other;
+      Sig.Kind = wasm::WasmSignature::Placeholder;
       Signatures.push_back(std::move(Sig));
       continue;
     }
@@ -1363,6 +1367,7 @@ Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
     wasm::WasmTag Tag;
     Tag.Index = NumImportedTags + Tags.size();
     Tag.SigIndex = Type;
+    Signatures[Type].Kind = wasm::WasmSignature::Tag;
     Tags.push_back(Tag);
   }
 

>From 1cb58ca7602fc604f0d146fcc06fe5abeca6c240 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Tue, 23 Jan 2024 17:02:57 -0800
Subject: [PATCH 11/11] clean up, remove printfs, clang-format

---
 llvm/include/llvm/BinaryFormat/Wasm.h |  11 ++-
 llvm/lib/MC/WasmObjectWriter.cpp      |   4 +-
 llvm/lib/Object/WasmObjectFile.cpp    | 101 ++++++++++----------------
 llvm/lib/ObjectYAML/WasmYAML.cpp      |   8 +-
 4 files changed, 52 insertions(+), 72 deletions(-)

diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 9f13cf4e36a855e..cd13b7014bfe265 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -70,7 +70,7 @@ enum : unsigned {
   WASM_TYPE_NONNULLABLE = 0x64,
   WASM_TYPE_NULLABLE = 0x63,
   WASM_TYPE_FUNC = 0x60,
-  WASM_TYPE_ARRAY = 0x5E, // Composite types, not used for codegen
+  WASM_TYPE_ARRAY = 0x5E,
   WASM_TYPE_STRUCT = 0x5F,
   WASM_TYPE_SUB = 0x50,
   WASM_TYPE_SUB_FINAL = 0x4F,
@@ -121,7 +121,8 @@ enum : unsigned {
   WASM_OPCODE_ARRAY_NEW_DEFAULT = 0x07,
   WASM_OPCODE_ARRAY_NEW_FIXED = 0x08,
   WASM_OPCODE_REF_I31 = 0x1c,
-  // any.convert_extern and extern.convert_any don't seem to be supported by Binaryen.
+  // any.convert_extern and extern.convert_any don't seem to be supported by
+  // Binaryen.
 };
 
 // Opcodes used in synthetic functions.
@@ -156,7 +157,7 @@ enum : unsigned {
 
 enum : unsigned {
   WASM_ELEM_SEGMENT_IS_PASSIVE = 0x01,
-  WASM_ELEM_SEGMENT_IS_DECLARATIVE = 0x02, // if passive == 1
+  WASM_ELEM_SEGMENT_IS_DECLARATIVE = 0x02,   // if passive == 1
   WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02, // if passive == 0
   WASM_ELEM_SEGMENT_HAS_INIT_EXPRS = 0x04,
 };
@@ -260,7 +261,7 @@ enum class ValType {
   FUNCREF = WASM_TYPE_FUNCREF,
   EXTERNREF = WASM_TYPE_EXTERNREF,
   // Unmodeled value types include ref types with heap types other than
-  // funcr or extern, and type-specialized funcrefs
+  // func or extern, and type-specialized funcrefs
   OTHERREF = 0xff,
 };
 
@@ -330,6 +331,8 @@ struct WasmInitExprMVP {
   } Value;
 };
 
+// Extended-const init exprs and exprs with GC types are not explicitly
+// modeled, but the raw body of the expr is attached.
 struct WasmInitExpr {
   uint8_t Extended; // Set to non-zero if extended const is used (i.e. more than
                     // one instruction)
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 9d8770271163eae..985f9351f4a3085 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -972,8 +972,8 @@ void WasmObjectWriter::writeTableSection(ArrayRef<wasm::WasmTable> Tables) {
 
   encodeULEB128(Tables.size(), W->OS);
   for (const wasm::WasmTable &Table : Tables) {
-    llvm::errs() << "Table " << Table.Index << std::string(Table.SymbolName) << " type " << (uint32_t)Table.Type.ElemType << "\n";
-    assert(Table.Type.ElemType != wasm::ValType::OTHERREF && "Cannot encode general ref-typed tables");
+    assert(Table.Type.ElemType != wasm::ValType::OTHERREF &&
+           "Cannot encode general ref-typed tables");
     encodeULEB128((uint32_t)Table.Type.ElemType, W->OS);
     encodeULEB128(Table.Type.Limits.Flags, W->OS);
     encodeULEB128(Table.Type.Limits.Minimum, W->OS);
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 48e351f34057204..e7006473449bc7a 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -175,23 +175,24 @@ static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
   return readUint8(Ctx);
 }
 
-static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx, uint32_t Code) {
-    // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern)
-    llvm::errs() << llvm::format(" val type %x ", Code);
-    switch(Code) {
-      case wasm::WASM_TYPE_I32:
-      case wasm::WASM_TYPE_I64:
-      case wasm::WASM_TYPE_F32:
-      case wasm::WASM_TYPE_F64:
-      case wasm::WASM_TYPE_V128:
-      case wasm::WASM_TYPE_FUNCREF:
-      case wasm::WASM_TYPE_EXTERNREF:
-        return wasm::ValType(Code);
-    }
-    if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
-      /* Discard HeapType */ readVarint64(Ctx);
-    }
-    return wasm::ValType(wasm::ValType::OTHERREF);
+static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx,
+                                  uint32_t Code) {
+  // only directly encoded FUNCREF/EXTERNREF are supported
+  // (not ref null func or ref null extern)
+  switch (Code) {
+  case wasm::WASM_TYPE_I32:
+  case wasm::WASM_TYPE_I64:
+  case wasm::WASM_TYPE_F32:
+  case wasm::WASM_TYPE_F64:
+  case wasm::WASM_TYPE_V128:
+  case wasm::WASM_TYPE_FUNCREF:
+  case wasm::WASM_TYPE_EXTERNREF:
+    return wasm::ValType(Code);
+  }
+  if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
+    /* Discard HeapType */ readVarint64(Ctx);
+  }
+  return wasm::ValType(wasm::ValType::OTHERREF);
 }
 
 static Error readInitExpr(wasm::WasmInitExpr &Expr,
@@ -217,11 +218,7 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
     Expr.Inst.Value.Global = readULEB128(Ctx);
     break;
   case wasm::WASM_OPCODE_REF_NULL: {
-    wasm::ValType Ty = parseValType(Ctx, readVaruint32(Ctx));
-    if (Ty != wasm::ValType::EXTERNREF) { // maybe something special if the type isn't one we understand?
-      //return make_error<GenericBinaryError>("invalid type for ref.null",
-      //                                      object_error::parse_failed);
-    }
+    /* Discard type */ parseValType(Ctx, readVaruint32(Ctx));
     break;
   }
   default:
@@ -238,7 +235,6 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
     Ctx.Ptr = Start;
     while (true) {
       uint8_t Opcode = readOpcode(Ctx);
-      llvm::errs() << llvm::format(" opcode %x", Opcode);
       switch (Opcode) {
       case wasm::WASM_OPCODE_I32_CONST:
       case wasm::WASM_OPCODE_GLOBAL_GET:
@@ -279,7 +275,6 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
         break;
       case wasm::WASM_OPCODE_END:
         Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);
-        llvm::errs() << "\n";
         return Error::success();
       default:
         return make_error<GenericBinaryError>(
@@ -1153,8 +1148,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
   auto parseFieldDef = [&]() {
     uint32_t TypeCode = readVaruint32((Ctx));
     /* Discard StorageType */ parseValType(Ctx, TypeCode);
-    uint32_t Mutability = readVaruint32(Ctx);
-    llvm::errs() << llvm:: format(" mut %d ", Mutability);
+    /* Discard Mutability */ readVaruint32(Ctx);
   };
 
   uint32_t Count = readVaruint32(Ctx);
@@ -1162,7 +1156,6 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
   while (Count--) {
     wasm::WasmSignature Sig;
     uint8_t Form = readUint8(Ctx);
-    llvm::errs() << llvm::format("Top Count %d form %x", Count, Form) << '\n';
     if (Form == wasm::WASM_TYPE_REC) {
       // Rec groups expand the type index space (beyond what was declared at
       // the top of the section, and also consume one element in that space.
@@ -1172,7 +1165,6 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
                                               object_error::parse_failed);
       Signatures.reserve(Signatures.size() + RecSize);
       Count += RecSize;
-      llvm::errs() << llvm::format(" Rec size %d\n", RecSize);
       Sig.Kind = wasm::WasmSignature::Placeholder;
       Signatures.push_back(std::move(Sig));
       continue;
@@ -1190,20 +1182,17 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
           /* Discard SuperIndex */ readVaruint32(Ctx);
         }
         Form = readVaruint32(Ctx);
-        llvm::errs() << llvm::format(" Sub Supers %d form %x", Supers, Form) << '\n';
       }
       if (Form == wasm::WASM_TYPE_STRUCT) {
         uint32_t FieldCount = readVaruint32(Ctx);
         while (FieldCount--) {
           parseFieldDef();
         }
-        llvm::errs() << llvm::format(" Struct size %d", FieldCount) << '\n';
       } else if (Form == wasm::WASM_TYPE_ARRAY) {
         parseFieldDef();
-        llvm::errs() << llvm::format("arr form %x", Form) << '\n';
       } else {
-        llvm::errs() << llvm::format(" bad form %x", Form) << '\n';
-        return make_error<GenericBinaryError>("bad form", object_error::parse_failed);
+        return make_error<GenericBinaryError>("bad form",
+                                              object_error::parse_failed);
       }
       Sig.Kind = wasm::WasmSignature::Placeholder;
       Signatures.push_back(std::move(Sig));
@@ -1212,21 +1201,18 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
 
     uint32_t ParamCount = readVaruint32(Ctx);
     Sig.Params.reserve(ParamCount);
-    llvm::errs() << llvm::format("param ct %d ", ParamCount);
     while (ParamCount--) {
       uint32_t ParamType = readUint8(Ctx);
       Sig.Params.push_back(parseValType(Ctx, ParamType));
       continue;
     }
     uint32_t ReturnCount = readVaruint32(Ctx);
-    llvm::errs() << llvm::format("\nreturn ct %d ", ReturnCount);
     while (ReturnCount--) {
       uint32_t ReturnType = readUint8(Ctx);
       Sig.Returns.push_back(parseValType(Ctx, ReturnType));
     }
-    
+
     Signatures.push_back(std::move(Sig));
-    llvm::errs() << '\n';
   }
   if (Ctx.Ptr != Ctx.End)
     return make_error<GenericBinaryError>("type section ended prematurely",
@@ -1386,10 +1372,9 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
     Global.Index = NumImportedGlobals + Globals.size();
     auto GlobalOpcode = readVaruint32(Ctx);
     auto GlobalType = parseValType(Ctx, GlobalOpcode);
-    //assert(GlobalType <= std::numeric_limits<wasm::ValType>::max());
+    // assert(GlobalType <= std::numeric_limits<wasm::ValType>::max());
     Global.Type.Type = (uint8_t)GlobalType;
     Global.Type.Mutable = readVaruint1(Ctx);
-    llvm::errs() << llvm::format("Read global %d index %d, type %x mut %d\n", Globals.capacity() -Count-1, Global.Index, GlobalOpcode, Global.Type.Mutable);
     if (Error Err = readInitExpr(Global.InitExpr, Ctx))
       return Err;
     Globals.push_back(Global);
@@ -1626,32 +1611,26 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
           "Unsupported flags for element segment", object_error::parse_failed);
 
     bool IsPassive = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) != 0;
-    bool IsDeclarative = IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE);
-    bool HasTableNumber = !IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER);
-    bool HasInitExprs = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
-    bool HasElemKind = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) && !HasInitExprs;
-
-    llvm::errs() << llvm::format("\nsegment %d flags %x, InitExprs %d HasKind %d\n",
-      ElemSegments.capacity() - Count-1, Segment.Flags, HasInitExprs,HasElemKind);
-    if (HasTableNumber) {
+    bool IsDeclarative =
+        IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE);
+    bool HasTableNumber =
+        !IsPassive &&
+        (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER);
+    bool HasInitExprs =
+        (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
+    bool HasElemKind =
+        (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) &&
+        !HasInitExprs;
+
+    if (HasTableNumber)
       Segment.TableNumber = readVaruint32(Ctx);
-      llvm::errs() << " table " << Segment.TableNumber << "\n"; }
     else
       Segment.TableNumber = 0;
+
     if (!isValidTableNumber(Segment.TableNumber))
       return make_error<GenericBinaryError>("invalid TableNumber",
                                             object_error::parse_failed);
 
-    if (IsDeclarative && false) {
-      // Declarative segments are not used or understood by LLVM
-      /* Discard type/kind */ readVaruint32(Ctx);
-      auto DeclCount = readVaruint32(Ctx);
-      while(DeclCount--) {
-        readVaruint32(Ctx);
-      }
-      // Dummy element?
-
-    }
     if (IsPassive || IsDeclarative) {
       Segment.Offset.Extended = false;
       Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
@@ -1659,7 +1638,6 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
     } else {
       if (Error Err = readInitExpr(Segment.Offset, Ctx))
         return Err;
-      llvm::errs() << llvm::format( " active seg, read initexpr opcode %x\n", Segment.Offset.Inst.Opcode);
     }
 
     if (HasElemKind) {
@@ -1686,12 +1664,11 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
     }
 
     uint32_t NumElems = readVaruint32(Ctx);
-    llvm::errs() << llvm::format(" num elems %d\n", NumElems);
 
     if (HasInitExprs) {
-      while(NumElems--) {
+      while (NumElems--) {
         wasm::WasmInitExpr Expr;
-        if(Error Err = readInitExpr(Expr, Ctx))
+        if (Error Err = readInitExpr(Expr, Ctx))
           return Err;
       }
     } else {
diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp
index 908778daa0304eb..3b53788eddbabcc 100644
--- a/llvm/lib/ObjectYAML/WasmYAML.cpp
+++ b/llvm/lib/ObjectYAML/WasmYAML.cpp
@@ -384,7 +384,8 @@ void MappingTraits<WasmYAML::ElemSegment>::mapping(
   if (!IO.outputting() ||
       Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND)
     IO.mapOptional("ElemKind", Segment.ElemKind);
-  // TODO: Omit "offset" for passive segments? It's neither meaningful nor encoded.
+  // TODO: Omit "offset" for passive segments? It's neither meaningful nor
+  // encoded.
   IO.mapRequired("Offset", Segment.Offset);
   IO.mapRequired("Functions", Segment.Functions);
 }
@@ -595,7 +596,7 @@ void ScalarEnumerationTraits<WasmYAML::SymbolKind>::enumeration(
 
 void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration(
     IO &IO, WasmYAML::ValueType &Type) {
-#define CONCAT(X) (uint32_t)wasm::ValType::X
+#define CONCAT(X) (uint32_t) wasm::ValType::X
 #define ECase(X) IO.enumCase(Type, #X, CONCAT(X));
   ECase(I32);
   ECase(I64);
@@ -605,7 +606,6 @@ void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration(
   ECase(FUNCREF);
   ECase(EXTERNREF);
   ECase(OTHERREF);
-  //ECase(FUNC);
 #undef ECase
 }
 
@@ -635,7 +635,7 @@ void ScalarEnumerationTraits<WasmYAML::Opcode>::enumeration(
 
 void ScalarEnumerationTraits<WasmYAML::TableType>::enumeration(
     IO &IO, WasmYAML::TableType &Type) {
-#define CONCAT(X) (uint32_t)wasm::ValType::X
+#define CONCAT(X) (uint32_t) wasm::ValType::X
 #define ECase(X) IO.enumCase(Type, #X, CONCAT(X));
   ECase(FUNCREF);
   ECase(EXTERNREF);



More information about the llvm-commits mailing list